{"data":{"alternate_greetings":["※※C\n해가 기울 무렵, 옛 왕국의 가도는 군데군데 돌이 빠진 채 언덕 너머로 이어진다. 길섶에는 부서진 이정석이 반쯤 흙에 묻혀 있고, 거기 새겨진 왕도의 이름은 이끼에 덮여 읽을 수 없다.\n\n언덕을 넘자 아래로 골짜기가 트인다. 무너진 성벽 한쪽에 새로 박은 목책이 둘러쳐져 있고, 그 안에서 저녁 짓는 연기 몇 줄이 피어오른다. 개척 마을 애시턴이다. 성벽 너머 북쪽 능선에는 탑 하나가 부러진 이빨처럼 솟아 있다.\n\n이정석 옆 그루터기에 앉아 쉬던 늙은 짐꾼이 등짐을 고쳐 메며 고개를 든다. 손등이 갈라지고 눈가에 먼지가 앉은 사내다.\n\n\"애시턴 가는 길이면 같이 가세. 해 떨어지면 이 길도 마냥 안전하진 않으니까.\" 그는 지팡이로 마을 쪽을 가리킨다. \"요즘 저기 일거리가 넘친다더군. 우물 밑에서 소리가 난다느니, 탑 근처에서 양이 없어졌다느니. 칼 쓰는 사람이든 책 읽는 사람이든 다 반기는 모양이야.\"\n\n짐꾼은 걸음을 옮기다 말고 당신을 위아래로 훑어본다.\n\n\"그래서, 자네는 뭘로 먹고사는 사람인가?\"\n"],"assets":[{"ext":"png","name":"main","type":"icon","uri":"ccdefault:"}],"character_book":{"entries":[{"case_sensitive":false,"comment":"규칙 · 몬스터","constant":false,"content":"","enabled":true,"extensions":{},"insertion_order":60,"keys":["folder:bac446a9-35e2-480d-a61f-6a2880801e37"],"mode":"folder","name":"규칙 · 몬스터","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Aboleth","constant":false,"content":"## Aboleth (monster stat block, SRD 5.2.1)\nLarge Aberration, Lawful Evil. AC 17, HP 150 (20d10+40), Initiative +7, Speed 10 ft., Swim 40 ft..\nAbilities: Str 21 (save +5), Dex 9 (save +3), Con 15 (save +6), Int 18 (save +8), Wis 15 (save +6), Cha 18 (save +4).\nCR 10 (XP 5900, PB +4).\nSkills History +12, Perception +10\nSenses Darkvision 120 ft.; Passive Perception 20\nLanguages Deep Speech; telepathy 120 ft.\n### Traits\n- Amphibious. The aboleth can breathe air and water.\n- Eldritch Restoration. If destroyed, the aboleth gains a new body in 5d10 days, reviving with all its Hit Points in the Far Realm or another location chosen by the GM.\n- Legendary Resistance (3/Day, or 4/Day in Lair). If the aboleth fails a saving throw, it can choose to succeed instead.\n- Mucus Cloud. While underwater, the aboleth is surrounded by mucus. Constitution Saving Throw: DC 14, each creature in a 5-foot Emanation originating from the aboleth at the end of the aboleth's turn. Failure: The target is cursed. Until the curse ends, the target's skin becomes slimy, the target can breathe air and water, and it can't regain Hit Points unless it is underwater. While the cursed creature is outside a body of water, the creature takes 6 (1d12) Acid damage at the end of every 10 minutes unless moisture is applied to its skin before those minutes have passed.\n- Probing Telepathy. If a creature the aboleth can see communicates telepathically with the aboleth, the aboleth learns the creature's greatest desires.\n### Actions\n- Multiattack. The aboleth makes two Tentacle attacks and uses either Consume Memories or Dominate Mind if available.\n- Tentacle. Melee Attack Roll: +9, reach 15 ft. Hit: 12 (2d6 + 5) Bludgeoning damage. If the target is a Large or smaller creature, it has the Grappled condition (escape DC 14) from one of four tentacles.\n- Consume Memories. Intelligence Saving Throw: DC 16, one creature within 30 feet that is Charmed or Grappled by the aboleth. Failure: 10 (3d6) Psychic damage. Success: Half damage. Failure or Success: The aboleth gains the target's memories if the target is a Humanoid and is reduced to 0 Hit Points by this action.\n- Dominate Mind (2/Day). Wisdom Saving Throw: DC 16, one creature the aboleth can see within 30 feet. Failure: The target has the Charmed condition until the aboleth dies or is on a different plane of existence from the target. While Charmed, the target acts as an ally to the aboleth and is under its control while within 60 feet of it. In addition, the aboleth and the target can communicate telepathically with each other over any distance. The target repeats the save whenever it takes damage as well as after every 24 hours it spends at least 1 mile away from the aboleth, ending the effect on itself on a success.\n### Legendary Actions\n- Legendary Action Uses: 3 (4 in Lair). Immediately after another creature's turn, the aboleth can expend a use to take one of the following actions. The aboleth regains all expended uses at the start of each of its turns.\n- Lash. The aboleth makes one Tentacle attack.\n- Psychic Drain. If the aboleth has at least one creature Charmed or Grappled, it uses Consume Memories and regains 5 (1d10) Hit Points.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Aboleth","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Air Elemental","constant":false,"content":"## Air Elemental (monster stat block, SRD 5.2.1)\nLarge Elemental, Neutral. AC 15, HP 90 (12d10+24), Initiative +5, Speed 10 ft., Fly 90 ft. (hover).\nAbilities: Str 14 (save +2), Dex 20 (save +5), Con 14 (save +2), Int 6 (save -2), Wis 10 (save +0), Cha 6 (save -2).\nCR 5 (XP 1800, PB +3).\nResistances Bludgeoning, Lightning, Piercing, Slashing\nImmunities Poison, Thunder; Exhaustion, Grappled, Paralyzed, Petrified, Poisoned, Prone, Restrained, Unconscious\nSenses Darkvision 60 ft.; Passive Perception 10\nLanguages Primordial (Auran)\n### Traits\n- Air Form. The elemental can enter a creature's space and stop there. It can move through a space as narrow as 1 inch without expending extra movement to do so.\n### Actions\n- Multiattack. The elemental makes two Thunderous Slam attacks.\n- Thunderous Slam. Melee Attack Roll: +8, reach 10 ft. Hit: 14 (2d8 + 5) Thunder damage.\n- Whirlwind (Recharge 4–6). Strength Saving Throw: DC 13, one Medium or smaller creature in the elemental's space. Failure: 24 (4d10 + 2) Thunder damage, and the target is pushed up to 20 feet straight away from the elemental and has the Prone condition. Success: Half damage only.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Air Elemental","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Animated Armor","constant":false,"content":"## Animated Armor (monster stat block, SRD 5.2.1)\nMedium Construct, Unaligned. AC 18, HP 33 (6d8+6), Initiative +2, Speed 25 ft..\nAbilities: Str 14 (save +2), Dex 11 (save +0), Con 13 (save +1), Int 1 (save -5), Wis 3 (save -4), Cha 1 (save -5).\nCR 1 (XP 200, PB +2).\nImmunities Poison, Psychic; Charmed, Deafened, Exhaustion, Frightened, Paralyzed, Petrified, Poisoned\nSenses Blindsight 60 ft.; Passive Perception 6\nLanguages None\n### Actions\n- Multiattack. The armor makes two Slam attacks.\n- Slam. Melee Attack Roll: +4, reach 5 ft. Hit: 5 (1d6 + 2) Bludgeoning damage.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Animated Armor","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Animated Flying Sword","constant":false,"content":"## Animated Flying Sword (monster stat block, SRD 5.2.1)\nSmall Construct, Unaligned. AC 17, HP 14 (4d6), Initiative +4, Speed 5 ft., Fly 50 ft. (hover).\nAbilities: Str 12 (save +1), Dex 15 (save +4), Con 11 (save +0), Int 1 (save -5), Wis 5 (save -3), Cha 1 (save -5).\nCR 1/4 (XP 50, PB +2).\nImmunities Poison, Psychic; Charmed, Deafened, Exhaustion, Frightened, Paralyzed, Petrified, Poisoned\nSenses Blindsight 60 ft.; Passive Perception 7\nLanguages None\n### Actions\n- Slash. Melee Attack Roll: +4, reach 5 ft. Hit: 6 (1d8 + 2) Slashing damage.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Animated Flying Sword","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Animated Rug of Smothering","constant":false,"content":"## Animated Rug of Smothering (monster stat block, SRD 5.2.1)\nLarge Construct, Unaligned. AC 12, HP 27 (5d10), Initiative +4, Speed 10 ft..\nAbilities: Str 17 (save +3), Dex 14 (save +2), Con 10 (save +0), Int 1 (save -5), Wis 3 (save -4), Cha 1 (save -5).\nCR 2 (XP 450, PB +2).\nImmunities Poison, Psychic; Charmed, Deafened, Exhaustion, Frightened, Paralyzed, Petrified, Poisoned\nSenses Blindsight 60 ft.; Passive Perception 6\nLanguages None\n### Actions\n- Smother. Melee Attack Roll: +5, reach 5 ft. Hit: 10 (2d6 + 3) Bludgeoning damage. If the target is a Medium or smaller creature, the rug can give it the Grappled condition (escape DC 13) instead of dealing damage. Until the grapple ends, the target has the Blinded and Restrained conditions, is suffocating, and takes 10 (2d6 + 3) Bludgeoning damage at the start of each of its turns.\n- The rug can smother only one creature at a time. While grappling the target, the rug can't take this action, the rug halves the damage it takes (round down), and the target takes the same amount of damage.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Animated Rug of Smothering","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Ankheg","constant":false,"content":"## Ankheg (monster stat block, SRD 5.2.1)\nLarge Monstrosity, Unaligned. AC 14, HP 45 (6d10+12), Initiative +0, Speed 30 ft., Burrow 10 ft..\nAbilities: Str 17 (save +3), Dex 11 (save +0), Con 14 (save +2), Int 1 (save -5), Wis 13 (save +1), Cha 6 (save -2).\nCR 2 (XP 450, PB +2).\nSenses Darkvision 60 ft., Tremorsense 60 ft.; Passive Perception 11\nLanguages None\n### Traits\n- Tunneler. The ankheg can burrow through solid rock at half its Burrow Speed and leaves a 10-foot-diameter tunnel in its wake.\n### Actions\n- Bite. Melee Attack Roll: +5 (with Advantage if the target is Grappled by the ankheg), reach 5 ft. Hit: 10 (2d6 + 3) Slashing damage plus 3 (1d6) Acid damage. If the target is a Large or smaller creature, it has the Grappled condition (escape DC 13).\n- Acid Spray (Recharge 6). Dexterity Saving Throw: DC 12, each creature in a 30-foot-long, 5-foot-wide Line. Failure: 14 (4d6) Acid damage. Success: Half damage.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Ankheg","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Assassin","constant":false,"content":"## Assassin (monster stat block, SRD 5.2.1)\nMedium or Small Humanoid, Neutral. AC 16, HP 97 (15d8+30), Initiative +10, Speed 30 ft..\nAbilities: Str 11 (save +0), Dex 18 (save +7), Con 14 (save +2), Int 16 (save +6), Wis 11 (save +0), Cha 10 (save +0).\nCR 8 (XP 3900, PB +3).\nSkills Acrobatics +7, Perception +6, Stealth +10\nResistances Poison\nGear Light Crossbow, Shortsword, Studded Leather Armor\nSenses Passive Perception 16\nLanguages Common, Thieves' Cant\n### Traits\n- Evasion. If the assassin is subjected to an effect that allows it to make a Dexterity saving throw to take only half damage, the assassin instead takes no damage if it succeeds on the save and only half damage if it fails. It can't use this trait if it has the Incapacitated condition.\n### Actions\n- Multiattack. The assassin makes three attacks, using Shortsword or Light Crossbow in any combination.\n- Shortsword. Melee Attack Roll: +7, reach 5 ft. Hit: 7 (1d6 + 4) Piercing damage plus 17 (5d6) Poison damage, and the target has the Poisoned condition until the start of the assassin's next turn.\n- Light Crossbow. Ranged Attack Roll: +7, range 80/320 ft. Hit: 8 (1d8 + 4) Piercing damage plus 21 (6d6) Poison damage.\n### Bonus Actions\n- Cunning Action. The assassin takes the Dash, Disengage, or Hide action.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Assassin","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Awakened Shrub","constant":false,"content":"## Awakened Shrub (monster stat block, SRD 5.2.1)\nSmall Plant, Neutral. AC 9, HP 10 (3d6), Initiative -1, Speed 20 ft..\nAbilities: Str 3 (save -4), Dex 8 (save -1), Con 11 (save +0), Int 10 (save +0), Wis 10 (save +0), Cha 6 (save -2).\nCR 0 (XP 10, PB +2).\nVulnerabilities Fire\nResistances Piercing\nSenses Passive Perception 10\nLanguages Common plus one other language\n### Actions\n- Rake. Melee Attack Roll: +1, reach 5 ft. Hit: 1 Slashing damage.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Awakened Shrub","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Awakened Tree","constant":false,"content":"## Awakened Tree (monster stat block, SRD 5.2.1)\nHuge Plant, Neutral. AC 13, HP 59 (7d12+14), Initiative -2, Speed 20 ft..\nAbilities: Str 19 (save +4), Dex 6 (save -2), Con 15 (save +2), Int 10 (save +0), Wis 10 (save +0), Cha 7 (save -2).\nCR 2 (XP 450, PB +2).\nVulnerabilities Fire\nResistances Bludgeoning, Piercing\nSenses Passive Perception 10\nLanguages Common plus one other language\n### Actions\n- Slam. Melee Attack Roll: +6, reach 10 ft. Hit: 14 (3d6 + 4) Bludgeoning damage.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Awakened Tree","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Axe Beak","constant":false,"content":"## Axe Beak (monster stat block, SRD 5.2.1)\nLarge Monstrosity, Unaligned. AC 11, HP 19 (3d10+3), Initiative +1, Speed 50 ft..\nAbilities: Str 14 (save +2), Dex 12 (save +1), Con 12 (save +1), Int 2 (save -4), Wis 10 (save +0), Cha 5 (save -3).\nCR 1/4 (XP 50, PB +2).\nSenses Passive Perception 10\nLanguages None\n### Actions\n- Beak. Melee Attack Roll: +4, reach 5 ft. Hit: 6 (1d8 + 2) Slashing damage.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Axe Beak","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Azer Sentinel","constant":false,"content":"## Azer Sentinel (monster stat block, SRD 5.2.1)\nMedium Elemental, Lawful Neutral. AC 17, HP 39 (6d8+12), Initiative +1, Speed 30 ft..\nAbilities: Str 17 (save +3), Dex 12 (save +1), Con 15 (save +4), Int 12 (save +1), Wis 13 (save +1), Cha 10 (save +0).\nCR 2 (XP 450, PB +2).\nImmunities Fire, Poison; Poisoned\nSenses Passive Perception 11\nLanguages Primordial (Ignan)\n### Traits\n- Fire Aura. At the end of each of the azer's turns, each creature of the azer's choice in a 5-foot Emanation originating from the azer takes 5 (1d10) Fire damage unless the azer has the Incapacitated condition.\n- Illumination. The azer sheds Bright Light in a 10-foot radius and Dim Light for an additional 10 feet.\n### Actions\n- Burning Hammer. Melee Attack Roll: +5, reach 5 ft. Hit: 8 (1d10 + 3) Bludgeoning damage plus 3 (1d6) Fire damage.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Azer Sentinel","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Balor","constant":false,"content":"## Balor (monster stat block, SRD 5.2.1)\nHuge Fiend (Demon), Chaotic Evil. AC 19, HP 287 (23d12+138), Initiative +14, Speed 40 ft., Fly 80 ft..\nAbilities: Str 26 (save +8), Dex 15 (save +2), Con 22 (save +12), Int 20 (save +5), Wis 16 (save +9), Cha 22 (save +6).\nCR 19 (XP 22000, PB +6).\nSkills Perception +9\nResistances Cold, Lightning\nImmunities Fire, Poison; Charmed, Frightened, Poisoned\nSenses Truesight 120 ft.; Passive Perception 19\nLanguages Abyssal; telepathy 120 ft.\n### Traits\n- Death Throes. The balor explodes when it dies. Dexterity Saving Throw: DC 20, each creature in a 30-foot Emanation originating from the balor. Failure: 31 (9d6) Fire damage plus 31 (9d6) Force damage. Success: Half damage. Failure or Success: If the balor dies outside the Abyss, it gains a new body instantly, reviving with all its Hit Points somewhere in the Abyss.\n- Fire Aura. At the end of each of the balor's turns, each creature in a 5-foot Emanation originating from the balor takes 13 (3d8) Fire damage.\n- Legendary Resistance (3/Day). If the balor fails a saving throw, it can choose to succeed instead.\n- Magic Resistance. The balor has Advantage on saving throws against spells and other magical effects.\n### Actions\n- Multiattack. The balor makes one Flame Whip attack and one Lightning Blade attack.\n- Flame Whip. Melee Attack Roll: +14, reach 30 ft. Hit: 18 (3d6 + 8) Force damage plus 17 (5d6) Fire damage. If the target is a Huge or smaller creature, the balor pulls the target up to 25 feet straight toward itself, and the target has the Prone condition.\n- Lightning Blade. Melee Attack Roll: +14, reach 10 ft. Hit: 21 (3d8 + 8) Force damage plus 22 (4d10) Lightning damage, and the target can't take Reactions until the start of the balor's next turn.\n### Bonus Actions\n- Teleport. The balor teleports itself or a willing demon within 10 feet of itself up to 60 feet to an unoccupied space the balor can see.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Balor","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Bandit","constant":false,"content":"## Bandit (monster stat block, SRD 5.2.1)\nMedium or Small Humanoid, Neutral. AC 12, HP 11 (2d8+2), Initiative +1, Speed 30 ft..\nAbilities: Str 11 (save +0), Dex 12 (save +1), Con 12 (save +1), Int 10 (save +0), Wis 10 (save +0), Cha 10 (save +0).\nCR 1/8 (XP 25, PB +2).\nGear Leather Armor, Light Crossbow, Scimitar\nSenses Passive Perception 10\nLanguages Common, Thieves' Cant\n### Actions\n- Scimitar. Melee Attack Roll: +3, reach 5 ft. Hit: 4 (1d6 + 1) Slashing damage.\n- Light Crossbow. Ranged Attack Roll: +3, range 80/320 ft. Hit: 5 (1d8 + 1) Piercing damage.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Bandit","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Bandit Captain","constant":false,"content":"## Bandit Captain (monster stat block, SRD 5.2.1)\nMedium or Small Humanoid, Neutral. AC 15, HP 52 (8d8+16), Initiative +3, Speed 30 ft..\nAbilities: Str 15 (save +4), Dex 16 (save +5), Con 14 (save +2), Int 14 (save +2), Wis 11 (save +2), Cha 14 (save +2).\nCR 2 (XP 450, PB +2).\nSkills Athletics +4, Deception +4\nGear Pistol, Scimitar, Studded Leather Armor\nSenses Passive Perception 10\nLanguages Common, Thieves' Cant\n### Actions\n- Multiattack. The bandit makes two attacks, using Scimitar and Pistol in any combination.\n- Scimitar. Melee Attack Roll: +5, reach 5 ft. Hit: 6 (1d6 + 3) Slashing damage.\n- Pistol. Ranged Attack Roll: +5, range 30/90 ft. Hit: 8 (1d10 + 3) Piercing damage.\n### Reactions\n- Parry. Trigger: The bandit is hit by a melee attack roll while holding a weapon. Response: The bandit adds 2 to its AC against that attack, possibly causing it to miss.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Bandit Captain","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Barbed Devil","constant":false,"content":"## Barbed Devil (monster stat block, SRD 5.2.1)\nMedium Fiend (Devil), Lawful Evil. AC 15, HP 110 (13d8+52), Initiative +3, Speed 30 ft., Climb 30 ft..\nAbilities: Str 16 (save +6), Dex 17 (save +3), Con 18 (save +7), Int 12 (save +1), Wis 14 (save +5), Cha 14 (save +5).\nCR 5 (XP 1800, PB +3).\nSkills Deception +5, Insight +5, Perception +8\nResistances Cold\nImmunities Fire, Poison; Poisoned\nSenses Darkvision 120 ft. (unimpeded by magical Darkness); Passive Perception 18\nLanguages Infernal; telepathy 120 ft.\n### Traits\n- Barbed Hide. At the start of each of its turns, the devil deals 5 (1d10) Piercing damage to any creature it is grappling or any creature grappling it.\n- Diabolical Restoration. If the devil dies outside the Nine Hells, its body disappears in sulfurous smoke, and it gains a new body instantly, reviving with all its Hit Points somewhere in the Nine Hells.\n- Magic Resistance. The devil has Advantage on saving throws against spells and other magical effects.\n### Actions\n- Multiattack. The devil makes one Claws attack and one Tail attack, or it makes two Hurl Flame attacks.\n- Claws. Melee Attack Roll: +6, reach 5 ft. Hit: 10 (2d6 + 3) Piercing damage. If the target is a Large or smaller creature, it has the Grappled condition (escape DC 13) from both claws.\n- Tail. Melee Attack Roll: +6, reach 10 ft. Hit: 14 (2d10 + 3) Slashing damage.\n- Hurl Flame. Ranged Attack Roll: +5, range 150 ft. Hit: 17 (5d6) Fire damage. If the target is a flammable object that isn't being worn or carried, it starts burning.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Barbed Devil","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Basilisk","constant":false,"content":"## Basilisk (monster stat block, SRD 5.2.1)\nMedium Monstrosity, Unaligned. AC 15, HP 52 (8d8+16), Initiative -1, Speed 20 ft..\nAbilities: Str 16 (save +3), Dex 8 (save -1), Con 15 (save +2), Int 2 (save -4), Wis 8 (save -1), Cha 7 (save -2).\nCR 3 (XP 700, PB +2).\nSenses Darkvision 60 ft.; Passive Perception 9\nLanguages None\n### Actions\n- Bite. Melee Attack Roll: +5, reach 5 ft. Hit: 10 (2d6 + 3) Piercing damage plus 7 (2d6) Poison damage.\n### Bonus Actions\n- Petrifying Gaze (Recharge 4–6). Constitution Saving Throw: DC 12, each creature in a 30-foot Cone. If the basilisk sees its reflection in the Cone, the basilisk must make this save. First Failure: The target has the Restrained condition and repeats the save at the end of its next turn if it is still Restrained, ending the effect on itself on a success. Second Failure: The target has the Petrified condition instead of the Restrained condition.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Basilisk","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Bearded Devil","constant":false,"content":"## Bearded Devil (monster stat block, SRD 5.2.1)\nMedium Fiend (Devil), Lawful Evil. AC 13, HP 58 (9d8+18), Initiative +2, Speed 30 ft..\nAbilities: Str 16 (save +5), Dex 15 (save +2), Con 15 (save +4), Int 9 (save -1), Wis 11 (save +0), Cha 14 (save +4).\nCR 3 (XP 700, PB +2).\nResistances Cold\nImmunities Fire, Poison; Frightened, Poisoned\nSenses Darkvision 120 ft. (unimpeded by magical Darkness); Passive Perception 10\nLanguages Infernal; telepathy 120 ft.\n### Traits\n- Magic Resistance. The devil has Advantage on saving throws against spells and other magical effects.\n### Actions\n- Multiattack. The devil makes one Beard attack and one Infernal Glaive attack.\n- Beard. Melee Attack Roll: +5, reach 5 ft. Hit: 7 (1d8 + 3) Piercing damage, and the target has the Poisoned condition until the start of the devil's next turn. Until this poison ends, the target can't regain Hit Points.\n- Infernal Glaive. Melee Attack Roll: +5, reach 10 ft. Hit: 8 (1d10 + 3) Slashing damage. If the target is a creature and doesn't already have an infernal wound, it is subjected to the following effect. Constitution Saving Throw: DC 12. Failure: The target receives an infernal wound. While wounded, the target loses 5 (1d10) Hit Points at the start of each of its turns. The wound closes after 1 minute, after a spell restores Hit Points to the target, or after the target or a creature within 5 feet of it takes an action to stanch the wound, doing so by succeeding on a DC 12 Wisdom (Medicine) check.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Bearded Devil","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Behir","constant":false,"content":"## Behir (monster stat block, SRD 5.2.1)\nHuge Monstrosity, Neutral Evil. AC 17, HP 168 (16d12+64), Initiative +3, Speed 50 ft., Climb 50 ft..\nAbilities: Str 23 (save +6), Dex 16 (save +3), Con 18 (save +4), Int 7 (save -2), Wis 14 (save +2), Cha 12 (save +1).\nCR 11 (XP 7200, PB +4).\nSkills Perception +6, Stealth +7\nImmunities Lightning\nSenses Darkvision 90 ft.; Passive Perception 16\nLanguages Draconic\n### Actions\n- Multiattack. The behir makes one Bite attack and uses Constrict.\n- Bite. Melee Attack Roll: +10, reach 10 ft. Hit: 19 (2d12 + 6) Piercing damage plus 11 (2d10) Lightning damage.\n- Constrict. Strength Saving Throw: DC 18, one Large or smaller creature the behir can see within 5 feet. Failure: 28 (5d8 + 6) Bludgeoning damage. The target has the Grappled condition (escape DC 16), and it has the Restrained condition until the grapple ends.\n- Lightning Breath (Recharge 5–6). Dexterity Saving Throw: DC 16, each creature in a 90-foot-long, 5-footwide Line. Failure: 66 (12d10) Lightning damage. Success: Half damage.\n### Bonus Actions\n- Swallow. Dexterity Saving Throw: DC 18, one Large or smaller creature Grappled by the behir (the behir can have only one creature swallowed at a time). Failure: The behir swallows the target, which is no longer Grappled. While swallowed, a creature has the Blinded and Restrained conditions, has Total Cover against attacks and other effects outside the behir, and takes 21 (6d6) Acid damage at the start of each of the behir's turns. If the behir takes 30 damage or more on a single turn from the swallowed creature, the behir must succeed on a DC 14 Constitution saving throw at the end of that turn or regurgitate the creature, which falls in a space within 10 feet of the behir and has the Prone condition. If the behir dies, a swallowed creature is no longer Restrained and can escape from the corpse by using 15 feet of movement, exiting Prone.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Behir","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Berserker","constant":false,"content":"## Berserker (monster stat block, SRD 5.2.1)\nMedium or Small Humanoid, Neutral. AC 13, HP 67 (9d8+27), Initiative +1, Speed 30 ft..\nAbilities: Str 16 (save +3), Dex 12 (save +1), Con 17 (save +3), Int 9 (save -1), Wis 11 (save +0), Cha 9 (save -1).\nCR 2 (XP 450, PB +2).\nGear Greataxe, Hide Armor\nSenses Passive Perception 10\nLanguages Common\n### Traits\n- Bloodied Frenzy. While Bloodied, the berserker has Advantage on attack rolls and saving throws.\n### Actions\n- Greataxe. Melee Attack Roll: +5, reach 5 ft. Hit: 9 (1d12 + 3) Slashing damage.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Berserker","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Black Dragon Wyrmling","constant":false,"content":"## Black Dragon Wyrmling (monster stat block, SRD 5.2.1)\nMedium Dragon (Chromatic), Chaotic Evil. AC 17, HP 33 (6d8+6), Initiative +4, Speed 30 ft., Fly 60 ft., Swim 30 ft..\nAbilities: Str 15 (save +2), Dex 14 (save +4), Con 13 (save +1), Int 10 (save +0), Wis 11 (save +2), Cha 13 (save +1).\nCR 2 (XP 450, PB +2).\nSkills Perception +4, Stealth +4\nImmunities Acid\nSenses Blindsight 10 ft., Darkvision 60 ft.; Passive Perception 14\nLanguages Draconic\n### Traits\n- Amphibious. The dragon can breathe air and water.\n### Actions\n- Multiattack. The dragon makes two Rend attacks.\n- Rend. Melee Attack Roll: +4, reach 5 ft. Hit: 5 (1d6 + 2) Slashing damage plus 2 (1d4) Acid damage.\n- Acid Breath (Recharge 5–6). Dexterity Saving Throw: DC 11, each creature in a 15-foot-long, 5-footwide Line. Failure: 22 (5d8) Acid damage. Success: Half damage.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Black Dragon Wyrmling","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Young Black Dragon","constant":false,"content":"## Young Black Dragon (monster stat block, SRD 5.2.1)\nLarge Dragon (Chromatic), Chaotic Evil. AC 18, HP 127 (15d10+45), Initiative +5, Speed 40 ft., Fly 80 ft., Swim 40 ft..\nAbilities: Str 19 (save +4), Dex 14 (save +5), Con 17 (save +3), Int 12 (save +1), Wis 11 (save +3), Cha 15 (save +2).\nCR 7 (XP 2900, PB +3).\nSkills Perception +6, Stealth +5\nImmunities Acid\nSenses Blindsight 30 ft., Darkvision 120 ft.; Passive Perception 16\nLanguages Common, Draconic\n### Traits\n- Amphibious. The dragon can breathe air and water.\n### Actions\n- Multiattack. The dragon makes three Rend attacks.\n- Rend. Melee Attack Roll: +7, reach 10 ft. Hit: 9 (2d4 + 4) Slashing damage plus 3 (1d6) Acid damage.\n- Acid Breath (Recharge 5–6). Dexterity Saving Throw: DC 14, each creature in a 30-foot-long, 5-footwide Line. Failure: 49 (14d6) Acid damage. Success: Half damage.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Young Black Dragon","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Adult Black Dragon","constant":false,"content":"## Adult Black Dragon (monster stat block, SRD 5.2.1)\nHuge Dragon (Chromatic), Chaotic Evil. AC 19, HP 195 (17d12+85), Initiative +12, Speed 40 ft., Fly 80 ft., Swim 40 ft..\nAbilities: Str 23 (save +6), Dex 14 (save +7), Con 21 (save +5), Int 14 (save +2), Wis 13 (save +6), Cha 19 (save +4).\nCR 14 (XP 11500, PB +5).\nSkills Perception +11, Stealth +7\nImmunities Acid\nSenses Blindsight 60 ft., Darkvision 120 ft.; Passive Perception 21\nLanguages Common, Draconic\n### Traits\n- Amphibious. The dragon can breathe air and water.\n- Legendary Resistance (3/Day, or 4/Day in Lair). If the dragon fails a saving throw, it can choose to succeed instead.\n### Actions\n- Multiattack. The dragon makes three Rend attacks. It can replace one attack with a use of Spellcasting to cast Acid Arrow (level 3 version).\n- Rend. Melee Attack Roll: +11, reach 10 ft. Hit: 13 (2d6 + 6) Slashing damage plus 4 (1d8) Acid damage.\n- Acid Breath (Recharge 5–6). Dexterity Saving Throw: DC 18, each creature in a 60-foot-long, 5-footwide Line. Failure: 54 (12d8) Acid damage. Success: Half damage.\n- Spellcasting. The dragon casts one of the following spells, requiring no Material components and using Charisma as the spellcasting ability (spell save DC 17, +9 to hit with spell attacks): At Will: Acid Arrow (level 3 version), Detect Magic, Fear 1/Day Each: Speak with Dead, Vitriolic Sphere\n### Legendary Actions\n- Legendary Action Uses: 3 (4 in Lair). Immediately after another creature's turn, the dragon can expend a use to take one of the following actions. The dragon regains all expended uses at the start of each of its turns.\n- Cloud of Insects. Dexterity Saving Throw: DC 17, one creature the dragon can see within 120 feet. Failure: 22 (4d10) Poison damage, and the target has Disadvantage on saving throws to maintain Concentration until the end of its next turn. Failure or Success: The dragon can't take this action again until the start of its next turn.\n- Frightful Presence. The dragon uses Spellcasting to cast Fear. The dragon can't take this action again until the start of its next turn.\n- Pounce. The dragon moves up to half its Speed, and it makes one Rend attack.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Adult Black Dragon","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Ancient Black Dragon","constant":false,"content":"## Ancient Black Dragon (monster stat block, SRD 5.2.1)\nGargantuan Dragon (Chromatic), Chaotic Evil. AC 22, HP 367 (21d20+147), Initiative +16, Speed 40 ft., Fly 80 ft., Swim 40 ft..\nAbilities: Str 27 (save +8), Dex 14 (save +9), Con 25 (save +7), Int 16 (save +3), Wis 15 (save +9), Cha 22 (save +6).\nCR 21 (XP 33000, PB +7).\nSkills Perception +16, Stealth +9\nImmunities Acid\nSenses Blindsight 60 ft., Darkvision 120 ft.; Passive Perception 26\nLanguages Common, Draconic\n### Traits\n- Amphibious. The dragon can breathe air and water.\n- Legendary Resistance (4/Day, or 5/Day in Lair). If the dragon fails a saving throw, it can choose to succeed instead.\n### Actions\n- Multiattack. The dragon makes three Rend attacks. It can replace one attack with a use of Spellcasting to cast Acid Arrow (level 4 version).\n- Rend. Melee Attack Roll: +15, reach 15 ft. Hit: 17 (2d8 + 8) Slashing damage plus 9 (2d8) Acid damage.\n- Acid Breath (Recharge 5–6). Dexterity Saving Throw: DC 22, each creature in a 90-foot-long, 10-footwide Line. Failure: 67 (15d8) Acid damage. Success: Half damage.\n- Spellcasting. The dragon casts one of the following spells, requiring no Material components and using Charisma as the spellcasting ability (spell save DC 21, +13 to hit with spell attacks): At Will: Acid Arrow (level 4 version), Detect Magic, Fear 1/Day Each: Create Undead, Speak with Dead, Vitriolic Sphere (level 5 version)\n### Legendary Actions\n- Legendary Action Uses: 3 (4 in Lair). Immediately after another creature's turn, the dragon can expend a use to take one of the following actions. The dragon regains all expended uses at the start of each of its turns.\n- Cloud of Insects. Dexterity Saving Throw: DC 21, one creature the dragon can see within 120 feet. Failure: 33 (6d10) Poison damage, and the target has Disadvantage on saving throws to maintain Concentration until the end of its next turn. Failure or Success: The dragon can't take this action again until the start of its next turn.\n- Frightful Presence. The dragon uses Spellcasting to cast Fear. The dragon can't take this action again until the start of its next turn.\n- Pounce. The dragon moves up to half its Speed, and it makes one Rend attack.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Ancient Black Dragon","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Black Pudding","constant":false,"content":"## Black Pudding (monster stat block, SRD 5.2.1)\nLarge Ooze, Unaligned. AC 7, HP 68 (8d10+24), Initiative -3, Speed 20 ft., Climb 20 ft..\nAbilities: Str 16 (save +3), Dex 5 (save -3), Con 16 (save +3), Int 1 (save -5), Wis 6 (save -2), Cha 1 (save -5).\nCR 4 (XP 1100, PB +2).\nImmunities Acid, Cold, Lightning, Slashing; Charmed, Deafened, Exhaustion, Frightened, Grappled, Prone, Restrained\nSenses Blindsight 60 ft.; Passive Perception 8\nLanguages None\n### Traits\n- Amorphous. The pudding can move through a space as narrow as 1 inch without expending extra movement to do so.\n- Corrosive Form. A creature that hits the pudding with a melee attack roll takes 4 (1d8) Acid damage. Nonmagical ammunition is destroyed immediately after hitting the pudding and dealing any damage. Any nonmagical weapon takes a cumulative -1 penalty to attack rolls immediately after dealing damage to the pudding and coming into contact with it. The weapon is destroyed if the penalty reaches -5. The penalty can be removed by casting the Mending spell on the weapon. In 1 minute, the pudding can eat through 2 feet of nonmagical wood or metal.\n- Spider Climb. The pudding can climb difficult surfaces, including along ceilings, without needing to make an ability check.\n### Actions\n- Dissolving Pseudopod. Melee Attack Roll: +5, reach 10 ft. Hit: 17 (4d6 + 3) Acid damage. Nonmagical armor worn by the target takes a -1 penalty to the AC it offers. The armor is destroyed if the penalty reduces its AC to 10. The penalty can be removed by casting the Mending spell on the armor.\n### Reactions\n- Split. Trigger: While the pudding is Large or Medium and has 10+ Hit Points, it becomes Bloodied or is subjected to Lightning or Slashing damage. Response: The pudding splits into two new Black Puddings. Each new pudding is one size smaller than the original pudding and acts on its Initiative. The original pudding's Hit Points are divided evenly between the new puddings (round down).","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Black Pudding","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Blink Dog","constant":false,"content":"## Blink Dog (monster stat block, SRD 5.2.1)\nMedium Fey, Lawful Good. AC 13, HP 22 (4d8+4), Initiative +3, Speed 40 ft..\nAbilities: Str 12 (save +1), Dex 17 (save +3), Con 12 (save +1), Int 10 (save +0), Wis 13 (save +1), Cha 11 (save +0).\nCR 1/4 (XP 50, PB +2).\nSkills Perception +5, Stealth +5\nSenses Darkvision 60 ft.; Passive Perception 15\nLanguages Blink Dog; understands Elvish and Sylvan but can't speak them\n### Actions\n- Bite. Melee Attack Roll: +5, reach 5 ft. Hit: 5 (1d4 + 3) Piercing damage.\n### Bonus Actions\n- Teleport (Recharge 4–6). The dog teleports up to 40 feet to an unoccupied space it can see.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Blink Dog","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Blue Dragon Wyrmling","constant":false,"content":"## Blue Dragon Wyrmling (monster stat block, SRD 5.2.1)\nMedium Dragon (Chromatic), Lawful Evil. AC 17, HP 65 (10d8+20), Initiative +2, Speed 30 ft., Burrow 15 ft., Fly 60 ft..\nAbilities: Str 17 (save +3), Dex 10 (save +2), Con 15 (save +2), Int 12 (save +1), Wis 11 (save +2), Cha 15 (save +2).\nCR 3 (XP 700, PB +2).\nSkills Perception +4, Stealth +2\nImmunities Lightning\nSenses Blindsight 10 ft., Darkvision 60 ft.; Passive Perception 14\nLanguages Draconic\n### Actions\n- Multiattack. The dragon makes two Rend attacks.\n- Rend. Melee Attack Roll: +5, reach 5 ft. Hit: 8 (1d10 + 3) Slashing damage plus 3 (1d6) Lightning damage.\n- Lightning Breath (Recharge 5–6). Dexterity Saving Throw: DC 12, each creature in a 30-foot-long, 5-footwide Line. Failure: 21 (6d6) Lightning damage. Success: Half damage.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Blue Dragon Wyrmling","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Young Blue Dragon","constant":false,"content":"## Young Blue Dragon (monster stat block, SRD 5.2.1)\nLarge Dragon (Chromatic), Lawful Evil. AC 18, HP 152 (16d10+64), Initiative +4, Speed 40 ft., Burrow 20 ft., Fly 80 ft..\nAbilities: Str 21 (save +5), Dex 10 (save +4), Con 19 (save +4), Int 14 (save +2), Wis 13 (save +5), Cha 17 (save +3).\nCR 9 (XP 5000, PB +4).\nSkills Perception +9, Stealth +4\nImmunities Lightning\nSenses Blindsight 30 ft., Darkvision 120 ft.; Passive Perception 19\nLanguages Common, Draconic\n### Actions\n- Multiattack. The dragon makes three Rend attacks.\n- Rend. Melee Attack Roll: +9, reach 10 ft. Hit: 12 (2d6 + 5) Slashing damage plus 5 (1d10) Lightning damage.\n- Lightning Breath (Recharge 5–6). Dexterity Saving Throw: DC 16, each creature in a 60-foot-long, 5-footwide Line. Failure: 55 (10d10) Lightning damage. Success: Half damage.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Young Blue Dragon","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Adult Blue Dragon","constant":false,"content":"## Adult Blue Dragon (monster stat block, SRD 5.2.1)\nHuge Dragon (Chromatic), Lawful Evil. AC 19, HP 212 (17d12+102), Initiative +10, Speed 40 ft., Burrow 30 ft., Fly 80 ft..\nAbilities: Str 25 (save +7), Dex 10 (save +5), Con 23 (save +6), Int 16 (save +3), Wis 15 (save +7), Cha 20 (save +5).\nCR 16 (XP 15000, PB +5).\nSkills Perception +12, Stealth +5\nImmunities Lightning\nSenses Blindsight 60 ft., Darkvision 120 ft.; Passive Perception 22\nLanguages Common, Draconic\n### Traits\n- Legendary Resistance (3/Day, or 4/Day in Lair). If the dragon fails a saving throw, it can choose to succeed instead.\n### Actions\n- Multiattack. The dragon makes three Rend attacks. It can replace one attack with a use of Spellcasting to cast Shatter.\n- Rend. Melee Attack Roll: +12, reach 10 ft. Hit: 16 (2d8 + 7) Slashing damage plus 5 (1d10) Lightning damage.\n- Lightning Breath (Recharge 5–6). Dexterity Saving Throw: DC 19, each creature in a 90-foot-long, 5-footwide Line. Failure: 60 (11d10) Lightning damage. Success: Half damage.\n- Spellcasting. The dragon casts one of the following spells, requiring no Material components and using Charisma as the spellcasting ability (spell save DC 18): At Will: Detect Magic, Invisibility, Mage Hand, Shatter 1/Day Each: Scrying, Sending\n### Legendary Actions\n- Legendary Action Uses: 3 (4 in Lair). Immediately after another creature's turn, the dragon can expend a use to take one of the following actions. The dragon regains all expended uses at the start of each of its turns.\n- Cloaked Flight. The dragon uses Spellcasting to cast Invisibility on itself, and it can fly up to half its Fly Speed. The dragon can't take this action again until the start of its next turn.\n- Sonic Boom. The dragon uses Spellcasting to cast Shatter. The dragon can't take this action again until the start of its next turn.\n- Tail Swipe. The dragon makes one Rend attack.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Adult Blue Dragon","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Ancient Blue Dragon","constant":false,"content":"## Ancient Blue Dragon (monster stat block, SRD 5.2.1)\nGargantuan Dragon (Chromatic), Lawful Evil. AC 22, HP 481 (26d20+208), Initiative +14, Speed 40 ft., Burrow 40 ft., Fly 80 ft..\nAbilities: Str 29 (save +9), Dex 10 (save +7), Con 27 (save +8), Int 18 (save +4), Wis 17 (save +10), Cha 25 (save +7).\nCR 23 (XP 50000, PB +7).\nSkills Perception +17, Stealth +7\nImmunities Lightning\nSenses Blindsight 60 ft., Darkvision 120 ft.; Passive Perception 27\nLanguages Common, Draconic\n### Traits\n- Legendary Resistance (4/Day, or 5/Day in Lair). If the dragon fails a saving throw, it can choose to succeed instead.\n### Actions\n- Multiattack. The dragon makes three Rend attacks. It can replace one attack with a use of Spellcasting to cast Shatter (level 3 version).\n- Rend. Melee Attack Roll: +16, reach 15 ft. Hit: 18 (2d8 + 9) Slashing damage plus 11 (2d10) Lightning damage.\n- Lightning Breath (Recharge 5–6). Dexterity Saving Throw: DC 23, each creature in a 120-foot-long, 10-foot-wide Line. Failure: 88 (16d10) Lightning damage. Success: Half damage.\n- Spellcasting. The dragon casts one of the following spells, requiring no Material components and using Charisma as the spellcasting ability (spell save DC 22): At Will: Detect Magic, Invisibility, Mage Hand, Shatter (level 3 version) 1/Day Each: Scrying, Sending\n### Legendary Actions\n- Legendary Action Uses: 3 (4 in Lair). Immediately after another creature's turn, the dragon can expend a use to take one of the following actions. The dragon regains all expended uses at the start of each of its turns.\n- Cloaked Flight. The dragon uses Spellcasting to cast Invisibility on itself, and it can fly up to half its Fly Speed. The dragon can't take this action again until the start of its next turn.\n- Sonic Boom. The dragon uses Spellcasting to cast Shatter (level 3 version). The dragon can't take this action again until the start of its next turn.\n- Tail Swipe. The dragon makes one Rend attack.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Ancient Blue Dragon","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Bone Devil","constant":false,"content":"## Bone Devil (monster stat block, SRD 5.2.1)\nLarge Fiend (Devil), Lawful Evil. AC 16, HP 161 (17d10+68), Initiative +7, Speed 40 ft., Fly 40 ft..\nAbilities: Str 18 (save +8), Dex 16 (save +3), Con 18 (save +4), Int 13 (save +5), Wis 14 (save +6), Cha 16 (save +7).\nCR 9 (XP 5000, PB +4).\nSkills Deception +7, Insight +6\nResistances Cold\nImmunities Fire, Poison; Poisoned\nSenses Darkvision 120 ft. (unimpeded by magical Darkness); Passive Perception 12\nLanguages Infernal; telepathy 120 ft.\n### Traits\n- Diabolical Restoration. If the devil dies outside the Nine Hells, its body disappears in sulfurous smoke, and it gains a new body instantly, reviving with all its Hit Points somewhere in the Nine Hells.\n- Magic Resistance. The devil has Advantage on saving throws against spells and other magical effects.\n### Actions\n- Multiattack. The devil makes two Claw attacks and one Infernal Sting attack.\n- Claw. Melee Attack Roll: +8, reach 10 ft. Hit: 13 (2d8 + 4) Slashing damage.\n- Infernal Sting. Melee Attack Roll: +8, reach 10 ft. Hit: 15 (2d10 + 4) Piercing damage plus 18 (4d8) Poison damage, and the target has the Poisoned condition until the start of the devil's next turn. While Poisoned, the target can't regain Hit Points.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Bone Devil","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Brass Dragon Wyrmling","constant":false,"content":"## Brass Dragon Wyrmling (monster stat block, SRD 5.2.1)\nMedium Dragon (Metallic), Chaotic Good. AC 15, HP 22 (4d8+4), Initiative +2, Speed 30 ft., Burrow 15 ft., Fly 60 ft..\nAbilities: Str 15 (save +2), Dex 10 (save +2), Con 13 (save +1), Int 10 (save +0), Wis 11 (save +2), Cha 13 (save +1).\nCR 1 (XP 200, PB +2).\nSkills Perception +4, Stealth +2\nImmunities Fire\nSenses Blindsight 10 ft., Darkvision 60 ft.; Passive Perception 14\nLanguages Draconic\n### Actions\n- Rend. Melee Attack Roll: +4, reach 5 ft. Hit: 7 (1d10 + 2) Slashing damage.\n- Fire Breath (Recharge 5–6). Dexterity Saving Throw: DC 11, each creature in a 20-foot-long, 5-footwide Line. Failure: 14 (4d6) Fire damage. Success: Half damage.\n- Sleep Breath. Constitution Saving Throw: DC 11, each creature in a 15-foot Cone. Failure: The target has the Incapacitated condition until the end of its next turn, at which point it repeats the save. Second Failure: The target has the Unconscious condition for 1 minute. This effect ends for the target if it takes damage or a creature within 5 feet of it takes an action to wake it.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Brass Dragon Wyrmling","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Young Brass Dragon","constant":false,"content":"## Young Brass Dragon (monster stat block, SRD 5.2.1)\nLarge Dragon (Metallic), Chaotic Good. AC 17, HP 110 (13d10+39), Initiative +3, Speed 40 ft., Burrow 20 ft., Fly 80 ft..\nAbilities: Str 19 (save +4), Dex 10 (save +3), Con 17 (save +3), Int 12 (save +1), Wis 11 (save +3), Cha 15 (save +2).\nCR 6 (XP 2300, PB +3).\nSkills Perception +6, Persuasion +5, Stealth +3\nImmunities Fire\nSenses Blindsight 30 ft., Darkvision 120 ft.; Passive Perception 16\nLanguages Common, Draconic\n### Actions\n- Multiattack. The dragon makes three Rend attacks. It can replace two attacks with a use of Sleep Breath.\n- Rend. Melee Attack Roll: +7, reach 10 ft. Hit: 15 (2d10 + 4) Slashing damage.\n- Fire Breath (Recharge 5–6). Dexterity Saving Throw: DC 14, each creature in a 40-foot-long, 5-footwide Line. Failure: 38 (11d6) Fire damage. Success: Half damage.\n- Sleep Breath. Constitution Saving Throw: DC 14, each creature in a 30-foot Cone. Failure: The target has the Incapacitated condition until the end of its next turn, at which point it repeats the save. Second Failure: The target has the Unconscious condition for 1 minute. This effect ends for the target if it takes damage or a creature within 5 feet of it takes an action to wake it.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Young Brass Dragon","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Adult Brass Dragon","constant":false,"content":"## Adult Brass Dragon (monster stat block, SRD 5.2.1)\nHuge Dragon (Metallic), Chaotic Good. AC 18, HP 172 (15d12+75), Initiative +10, Speed 40 ft., Burrow 30 ft., Fly 80 ft..\nAbilities: Str 23 (save +6), Dex 10 (save +5), Con 21 (save +5), Int 14 (save +2), Wis 13 (save +6), Cha 17 (save +3).\nCR 13 (XP 10000, PB +5).\nSkills History +7, Perception +11, Persuasion +8, Stealth +5\nImmunities Fire\nSenses Blindsight 60 ft., Darkvision 120 ft.; Passive Perception 21\nLanguages Common, Draconic\n### Traits\n- Legendary Resistance (3/Day, or 4/Day in Lair). If the dragon fails a saving throw, it can choose to succeed instead.\n### Actions\n- Multiattack. The dragon makes three Rend attacks. It can replace one attack with a use of (A) Sleep Breath or (B) Spellcasting to cast Scorching Ray.\n- Rend. Melee Attack Roll: +11, reach 10 ft. Hit: 17 (2d10 + 6) Slashing damage plus 4 (1d8) Fire damage.\n- Fire Breath (Recharge 5–6). Dexterity Saving Throw: DC 18, each creature in a 60-foot-long, 5-footwide Line. Failure: 45 (10d8) Fire damage. Success: Half damage.\n- Sleep Breath. Constitution Saving Throw: DC 18, each creature in a 60-foot Cone. Failure: The target has the Incapacitated condition until the end of its next turn, at which point it repeats the save. Second Failure: The target has the Unconscious condition for 10 minutes. This effect ends for the target if it takes damage or a creature within 5 feet of it takes an action to wake it.\n- Spellcasting. The dragon casts one of the following spells, requiring no Material components and using Charisma as the spellcasting ability (spell save DC 16): At Will: Detect Magic, Minor Illusion, Scorching Ray, Shapechange (Beast or Humanoid form only, no Temporary Hit Points gained from the spell, and no Concentration or Temporary Hit Points required to maintain the spell), Speak with Animals 1/Day Each: Detect Thoughts, Control Weather\n### Legendary Actions\n- Legendary Action Uses: 3 (4 in Lair). Immediately after another creature's turn, the dragon can expend a use to take one of the following actions. The dragon regains all expended uses at the start of each of its turns.\n- Blazing Light. The dragon uses Spellcasting to cast Scorching Ray.\n- Pounce. The dragon moves up to half its Speed, and it makes one Rend attack.\n- Scorching Sands. Dexterity Saving Throw: DC 16, one creature the dragon can see within 120 feet. Failure: 27 (6d8) Fire damage, and the target's Speed is halved until the end of its next turn. Failure or Success: The dragon can't take this action again until the start of its next turn.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Adult Brass Dragon","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Ancient Brass Dragon","constant":false,"content":"## Ancient Brass Dragon (monster stat block, SRD 5.2.1)\nGargantuan Dragon (Metallic), Chaotic Good. AC 20, HP 332 (19d20+133), Initiative +12, Speed 40 ft., Burrow 40 ft., Fly 80 ft..\nAbilities: Str 27 (save +8), Dex 10 (save +6), Con 25 (save +7), Int 16 (save +3), Wis 15 (save +8), Cha 22 (save +6).\nCR 20 (XP 25000, PB +6).\nSkills History +9, Perception +14, Persuasion +12, Stealth +6\nImmunities Fire\nSenses Blindsight 60 ft., Darkvision 120 ft.; Passive Perception 24\nLanguages Common, Draconic\n### Traits\n- Legendary Resistance (4/Day, or 5/Day in Lair). If the dragon fails a saving throw, it can choose to succeed instead.\n### Actions\n- Multiattack. The dragon makes three Rend attacks. It can replace one attack with a use of (A) Sleep Breath or (B) Spellcasting to cast Scorching Ray (level 3 version).\n- Rend. Melee Attack Roll: +14, reach 15 ft. Hit: 19 (2d10 + 8) Slashing damage plus 7 (2d6) Fire damage.\n- Fire Breath (Recharge 5–6). Dexterity Saving Throw: DC 21, each creature in a 90-foot-long, 5-footwide Line. Failure: 58 (13d8) Fire damage. Success: Half damage.\n- Sleep Breath. Constitution Saving Throw: DC 21, each creature in a 90-foot Cone. Failure: The target has the Incapacitated condition until the end of its next turn, at which point it repeats the save. Second Failure: The target has the Unconscious condition for 10 minutes. This effect ends for the target if it takes damage or a creature within 5 feet of it takes an action to wake it.\n- Spellcasting. The dragon casts one of the following spells, requiring no Material components and using Charisma as the spellcasting ability (spell save DC 20): At Will: Detect Magic, Minor Illusion, Scorching Ray (level 3 version), Shapechange (Beast or Humanoid form only, no Temporary Hit Points gained from the spell, and no Concentration or Temporary Hit Points required to maintain the spell), Speak with Animals 1/Day Each: Control Weather, Detect Thoughts\n### Legendary Actions\n- Legendary Action Uses: 3 (4 in Lair). Immediately after another creature's turn, the dragon can expend a use to take one of the following actions. The dragon regains all expended uses at the start of each of its turns.\n- Blazing Light. The dragon uses Spellcasting to cast Scorching Ray (level 3 version).\n- Pounce. The dragon moves up to half its Speed, and it makes one Rend attack.\n- Scorching Sands. Dexterity Saving Throw: DC 20, one creature the dragon can see within 120 feet. Failure: 36 (8d8) Fire damage, and the target's Speed is halved until the end of its next turn. Failure or Success: The dragon can't take this action again until the start of its next turn.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Ancient Brass Dragon","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Bronze Dragon Wyrmling","constant":false,"content":"## Bronze Dragon Wyrmling (monster stat block, SRD 5.2.1)\nMedium Dragon (Metallic), Lawful Good. AC 15, HP 39 (6d8+12), Initiative +2, Speed 30 ft., Fly 60 ft., Swim 30 ft..\nAbilities: Str 17 (save +3), Dex 10 (save +2), Con 15 (save +2), Int 12 (save +1), Wis 11 (save +2), Cha 15 (save +2).\nCR 2 (XP 450, PB +2).\nSkills Perception +4, Stealth +2\nImmunities Lightning\nSenses Blindsight 10 ft., Darkvision 60 ft.; Passive Perception 14\nLanguages Draconic\n### Traits\n- Amphibious. The dragon can breathe air and water.\n### Actions\n- Multiattack. The dragon makes two Rend attacks.\n- Rend. Melee Attack Roll: +5, reach 5 ft. Hit: 8 (1d10 + 3) Slashing damage.\n- Lightning Breath (Recharge 5–6). Dexterity Saving Throw: DC 12, each creature in a 40-foot-long, 5-footwide Line. Failure: 16 (3d10) Lightning damage. Success: Half damage.\n- Repulsion Breath. Strength Saving Throw: DC 12, each creature in a 30-foot Cone. Failure: The target is pushed up to 30 feet straight away from the dragon and has the Prone condition.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Bronze Dragon Wyrmling","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Young Bronze Dragon","constant":false,"content":"## Young Bronze Dragon (monster stat block, SRD 5.2.1)\nLarge Dragon (Metallic), Lawful Good. AC 17, HP 142 (15d10+60), Initiative +3, Speed 40 ft., Fly 80 ft., Swim 40 ft..\nAbilities: Str 21 (save +5), Dex 10 (save +3), Con 19 (save +4), Int 14 (save +2), Wis 13 (save +4), Cha 17 (save +3).\nCR 8 (XP 3900, PB +3).\nSkills Insight +4, Perception +7, Stealth +3\nImmunities Lightning\nSenses Blindsight 30 ft., Darkvision 120 ft.; Passive Perception 17\nLanguages Common, Draconic\n### Traits\n- Amphibious. The dragon can breathe air and water.\n### Actions\n- Multiattack. The dragon makes three Rend attacks. It can replace one attack with a use of Repulsion Breath.\n- Rend. Melee Attack Roll: +8, reach 10 ft. Hit: 16 (2d10 + 5) Slashing damage.\n- Lightning Breath (Recharge 5–6). Dexterity Saving Throw: DC 15, each creature in a 60-foot-long, 5-footwide Line. Failure: 49 (9d10) Lightning damage. Success: Half damage.\n- Repulsion Breath. Strength Saving Throw: DC 15, each creature in a 30-foot Cone. Failure: The target is pushed up to 40 feet straight away from the dragon and has the Prone condition.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Young Bronze Dragon","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Adult Bronze Dragon","constant":false,"content":"## Adult Bronze Dragon (monster stat block, SRD 5.2.1)\nHuge Dragon (Metallic), Lawful Good. AC 18, HP 212 (17d12+102), Initiative +10, Speed 40 ft., Fly 80 ft., Swim 40 ft..\nAbilities: Str 25 (save +7), Dex 10 (save +5), Con 23 (save +6), Int 16 (save +3), Wis 15 (save +7), Cha 20 (save +5).\nCR 15 (XP 13000, PB +5).\nSkills Insight +7, Perception +12, Stealth +5\nImmunities Lightning\nSenses Blindsight 60 ft., Darkvision 120 ft.; Passive Perception 22\nLanguages Common, Draconic\n### Traits\n- Amphibious. The dragon can breathe air and water.\n- Legendary Resistance (3/Day, or 4/Day in Lair). If the dragon fails a saving throw, it can choose to succeed instead.\n### Actions\n- Multiattack. The dragon makes three Rend attacks. It can replace one attack with a use of (A) Repulsion Breath or (B) Spellcasting to cast Guiding Bolt (level 2 version).\n- Rend. Melee Attack Roll: +12, reach 10 ft. Hit: 16 (2d8 + 7) Slashing damage plus 5 (1d10) Lightning damage.\n- Lightning Breath (Recharge 5–6). Dexterity Saving Throw: DC 19, each creature in a 90-foot-long, 5-footwide Line. Failure: 55 (10d10) Lightning damage. Success: Half damage.\n- Repulsion Breath. Strength Saving Throw: DC 19, each creature in a 30-foot Cone. Failure: The target is pushed up to 60 feet straight away from the dragon and has the Prone condition.\n- Spellcasting. The dragon casts one of the following spells, requiring no Material components and using Charisma as the spellcasting ability (spell save DC 17, +10 to hit with spell attacks): At Will: Detect Magic, Guiding Bolt (level 2 version), Shapechange (Beast or Humanoid form only, no Temporary Hit Points gained from the spell, and no Concentration or Temporary Hit Points required to maintain the spell), Speak with Animals, Thaumaturgy 1/Day Each: Detect Thoughts, Water Breathing\n### Legendary Actions\n- Legendary Action Uses: 3 (4 in Lair). Immediately after another creature's turn, the dragon can expend a use to take one of the following actions. The dragon regains all expended uses at the start of each of its turns.\n- Guiding Light. The dragon uses Spellcasting to cast Guiding Bolt (level 2 version).\n- Pounce. The dragon moves up to half its Speed, and it makes one Rend attack.\n- Thunderclap. Constitution Saving Throw: DC 17, each creature in a 20-foot-radius Sphere centered on a point the dragon can see within 90 feet. Failure: 10 (3d6) Thunder damage, and the target has the Deafened condition until the end of its next turn.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Adult Bronze Dragon","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Ancient Bronze Dragon","constant":false,"content":"## Ancient Bronze Dragon (monster stat block, SRD 5.2.1)\nGargantuan Dragon (Metallic), Lawful Good. AC 22, HP 444 (24d20+192), Initiative +14, Speed 40 ft., Fly 80 ft., Swim 40 ft..\nAbilities: Str 29 (save +9), Dex 10 (save +7), Con 27 (save +8), Int 18 (save +4), Wis 17 (save +10), Cha 25 (save +7).\nCR 22 (XP 41000, PB +7).\nSkills Insight +10, Perception +17, Stealth +7\nImmunities Lightning\nSenses Blindsight 60 ft., Darkvision 120 ft.; Passive Perception 27\nLanguages Common, Draconic\n### Traits\n- Amphibious. The dragon can breathe air and water.\n- Legendary Resistance (4/Day, or 5/Day in Lair). If the dragon fails a saving throw, it can choose to succeed instead.\n### Actions\n- Multiattack. The dragon makes three Rend attacks. It can replace one attack with a use of (A) Repulsion Breath or (B) Spellcasting to cast Guiding Bolt (level 2 version).\n- Rend. Melee Attack Roll: +16, reach 15 ft. Hit: 18 (2d8 + 9) Slashing damage plus 9 (2d8) Lightning damage.\n- Lightning Breath (Recharge 5–6). Dexterity Saving Throw: DC 23, each creature in a 120-foot-long, 10-foot-wide Line. Failure: 82 (15d10) Lightning damage. Success: Half damage.\n- Repulsion Breath. Strength Saving Throw: DC 23, each creature in a 30-foot Cone. Failure: The target is pushed up to 60 feet straight away from the dragon and has the Prone condition.\n- Spellcasting. The dragon casts one of the following spells, requiring no Material components and using Charisma as the spellcasting ability (spell save DC 22, +14 to hit with spell attacks): At Will: Detect Magic, Guiding Bolt (level 2 version), Shapechange (Beast or Humanoid form only, no Temporary Hit Points gained from the spell, and no Concentration or Temporary Hit Points required to maintain the spell), Speak with Animals, Thaumaturgy 1/Day Each: Detect Thoughts, Control Water, Scrying, Water Breathing\n### Legendary Actions\n- Legendary Action Uses: 3 (4 in Lair). Immediately after another creature's turn, the dragon can expend a use to take one of the following actions. The dragon regains all expended uses at the start of each of its turns.\n- Guiding Light. The dragon uses Spellcasting to cast Guiding Bolt (level 2 version).\n- Pounce. The dragon moves up to half its Speed, and it makes one Rend attack.\n- Thunderclap. Constitution Saving Throw: DC 22, each creature in a 20-foot-radius Sphere centered on a point the dragon can see within 120 feet. Failure: 13 (3d8) Thunder damage, and the target has the Deafened condition until the end of its next turn.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Ancient Bronze Dragon","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Bugbear Stalker","constant":false,"content":"## Bugbear Stalker (monster stat block, SRD 5.2.1)\nMedium Fey (Goblinoid), Chaotic Evil. AC 15, HP 65 (10d8+20), Initiative +2, Speed 30 ft..\nAbilities: Str 17 (save +3), Dex 14 (save +2), Con 14 (save +4), Int 11 (save +0), Wis 12 (save +3), Cha 11 (save +0).\nCR 3 (XP 700, PB +2).\nSkills Stealth +6, Survival +3\nGear Chain Shirt, Javelins (6), Morningstar\nSenses Darkvision 60 ft.; Passive Perception 11\nLanguages Common, Goblin\n### Traits\n- Abduct. The bugbear needn't spend extra movement to move a creature it is grappling.\n### Actions\n- Multiattack. The bugbear makes two Javelin or Morningstar attacks.\n- Javelin. Melee or Ranged Attack Roll: +5, reach 10 ft. or range 30/120 ft. Hit: 13 (3d6 + 3) Piercing damage.\n- Morningstar. Melee Attack Roll: +5 (with Advantage if the target is Grappled by the bugbear), reach 10 ft. Hit: 12 (2d8 + 3) Piercing damage.\n### Bonus Actions\n- Quick Grapple. Dexterity Saving Throw: DC 13, one Medium or smaller creature the bugbear can see within 10 feet. Failure: The target has the Grappled condition (escape DC 13).","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Bugbear Stalker","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Bugbear Warrior","constant":false,"content":"## Bugbear Warrior (monster stat block, SRD 5.2.1)\nMedium Fey (Goblinoid), Chaotic Evil. AC 14, HP 33 (6d8+6), Initiative +2, Speed 30 ft..\nAbilities: Str 15 (save +2), Dex 14 (save +2), Con 13 (save +1), Int 8 (save -1), Wis 11 (save +0), Cha 9 (save -1).\nCR 1 (XP 200, PB +2).\nSkills Stealth +6, Survival +2\nGear Hide Armor, Light Hammers (3)\nSenses Darkvision 60 ft.; Passive Perception 10\nLanguages Common, Goblin\n### Traits\n- Abduct. The bugbear needn't spend extra movement to move a creature it is grappling.\n### Actions\n- Grab. Melee Attack Roll: +4, reach 10 ft. Hit: 9 (2d6 + 2) Bludgeoning damage. If the target is a Medium or smaller creature, it has the Grappled condition (escape DC 12).\n- Light Hammer. Melee or Ranged Attack Roll: +4 (with Advantage if the target is Grappled by the bugbear), reach 10 ft. or range 20/60 ft. Hit: 9 (3d4 + 2) Bludgeoning damage.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Bugbear Warrior","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Bulette","constant":false,"content":"## Bulette (monster stat block, SRD 5.2.1)\nLarge Monstrosity, Unaligned. AC 17, HP 94 (9d10+45), Initiative +0, Speed 40 ft., Burrow 40 ft..\nAbilities: Str 19 (save +4), Dex 11 (save +0), Con 21 (save +5), Int 2 (save -4), Wis 10 (save +0), Cha 5 (save -3).\nCR 5 (XP 1800, PB +3).\nSkills Perception +6\nSenses Darkvision 60 ft., Tremorsense 120 ft.; Passive Perception 16\nLanguages None\n### Actions\n- Multiattack. The bulette makes two Bite attacks.\n- Bite. Melee Attack Roll: +7, reach 5 ft. Hit: 17 (2d12 + 4) Piercing damage.\n- Deadly Leap. The bulette spends 5 feet of movement to jump to a space within 15 feet that contains one or more Large or smaller creatures. Dexterity Saving Throw: DC 15, each creature in the bulette's destination space. Failure: 19 (3d12) Bludgeoning damage, and the target has the Prone condition. Success: Half damage, and the target is pushed 5 feet straight away from the bulette.\n### Bonus Actions\n- Leap. The bulette jumps up to 30 feet by spending 10 feet of movement.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Bulette","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Centaur Trooper","constant":false,"content":"## Centaur Trooper (monster stat block, SRD 5.2.1)\nLarge Fey, Neutral Good. AC 16, HP 45 (6d10+12), Initiative +2, Speed 50 ft..\nAbilities: Str 18 (save +4), Dex 14 (save +2), Con 14 (save +2), Int 9 (save -1), Wis 13 (save +1), Cha 11 (save +0).\nCR 2 (XP 450, PB +2).\nSkills Athletics +6, Perception +3\nGear Breastplate, Longbow, Pike\nSenses Passive Perception 13\nLanguages Elvish, Sylvan\n### Actions\n- Multiattack. The centaur makes two attacks, using Pike or Longbow in any combination.\n- Pike. Melee Attack Roll: +6, reach 10 ft. Hit: 9 (1d10 + 4) Piercing damage.\n- Longbow. Ranged Attack Roll: +4, range 150/600 ft. Hit: 6 (1d8 + 2) Piercing damage.\n### Bonus Actions\n- Trampling Charge (Recharge 5–6). The centaur moves up to its Speed without provoking Opportunity Attacks and can move through the spaces of Medium or smaller creatures. Each creature whose space the centaur enters is targeted once by the following effect. Strength Saving Throw: DC 14. Failure: 7 (1d6 + 4) Bludgeoning damage, and the target has the Prone condition.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Centaur Trooper","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Chain Devil","constant":false,"content":"## Chain Devil (monster stat block, SRD 5.2.1)\nMedium Fiend (Devil), Lawful Evil. AC 15, HP 85 (10d8+40), Initiative +5, Speed 30 ft..\nAbilities: Str 18 (save +4), Dex 15 (save +2), Con 18 (save +7), Int 11 (save +0), Wis 12 (save +4), Cha 14 (save +2).\nCR 8 (XP 3900, PB +3).\nResistances Bludgeoning, Cold, Piercing, Slashing\nImmunities Fire, Poison; Poisoned\nSenses Darkvision 120 ft. (unimpeded by magical Darkness); Passive Perception 11\nLanguages Infernal; telepathy 120 ft.\n### Traits\n- Diabolical Restoration. If the devil dies outside the Nine Hells, its body disappears in sulfurous smoke, and it gains a new body instantly, reviving with all its Hit Points somewhere in the Nine Hells.\n- Magic Resistance. The devil has Advantage on saving throws against spells and other magical effects.\n### Actions\n- Multiattack. The devil makes two Chain attacks and uses Conjure Infernal Chain.\n- Chain. Melee Attack Roll: +7, reach 10 ft. Hit: 11 (2d6 + 4) Slashing damage. If the target is a Large or smaller creature, it has the Grappled condition (escape DC 14) from one of two chains, and it has the Restrained condition until the grapple ends.\n- Conjure Infernal Chain. The devil conjures a fiery chain to bind a creature. Dexterity Saving Throw: DC 15, one creature the devil can see within 60 feet. Failure: 9 (2d4 + 4) Fire damage, and the target has the Restrained condition until the end of the devil's next turn, at which point the chain disappears. If the target is Large or smaller, the devil moves the target up to 30 feet straight toward itself. Success: The chain disappears.\n### Reactions\n- Unnerving Gaze. Trigger: A creature the devil can see starts its turn within 30 feet of the devil and can see the devil. Response—Wisdom Saving Throw: DC 15, the triggering creature. Failure: The target has the Frightened condition until the end of its turn. Success: The target is immune to this devil's Unnerving Gaze for 24 hours.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Chain Devil","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Chimera","constant":false,"content":"## Chimera (monster stat block, SRD 5.2.1)\nLarge Monstrosity, Chaotic Evil. AC 14, HP 114 (12d10+48), Initiative +0, Speed 30 ft., Fly 60 ft..\nAbilities: Str 19 (save +4), Dex 11 (save +0), Con 19 (save +4), Int 3 (save -4), Wis 14 (save +2), Cha 10 (save +0).\nCR 6 (XP 2300, PB +3).\nSkills Perception +8\nSenses Darkvision 60 ft.; Passive Perception 18\nLanguages Understands Draconic but can't speak\n### Actions\n- Multiattack. The chimera makes one Ram attack, one Bite attack, and one Claw attack. It can replace the Claw attack with a use of Fire Breath if available.\n- Bite. Melee Attack Roll: +7, reach 5 ft. Hit: 11 (2d6 + 4) Piercing damage, or 18 (4d6 + 4) Piercing damage if the chimera had Advantage on the attack roll.\n- Claw. Melee Attack Roll: +7, reach 5 ft. Hit: 7 (1d6 + 4) Slashing damage.\n- Ram. Melee Attack Roll: +7, reach 5 ft. Hit: 10 (1d12 + 4) Bludgeoning damage. If the target is a Medium or smaller creature, it has the Prone condition.\n- Fire Breath (Recharge 5–6). Dexterity Saving Throw: DC 15, each creature in a 15-foot Cone. Failure: 31 (7d8) Fire damage. Success: Half damage.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Chimera","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Chuul","constant":false,"content":"## Chuul (monster stat block, SRD 5.2.1)\nLarge Aberration, Chaotic Evil. AC 16, HP 76 (9d10+27), Initiative +0, Speed 30 ft., Swim 30 ft..\nAbilities: Str 19 (save +4), Dex 10 (save +0), Con 16 (save +3), Int 5 (save -3), Wis 11 (save +0), Cha 5 (save -3).\nCR 4 (XP 1100, PB +2).\nSkills Perception +4\nImmunities Poison; Poisoned\nSenses Darkvision 60 ft.; Passive Perception 14\nLanguages Understands Deep Speech but can't speak\n### Traits\n- Amphibious. The chuul can breathe air and water.\n- Sense Magic. The chuul senses magic within 120 feet of itself. This trait otherwise works like the Detect Magic spell but isn't itself magical.\n### Actions\n- Multiattack. The chuul makes two Pincer attacks and uses Paralyzing Tentacles.\n- Pincer. Melee Attack Roll: +6, reach 10 ft. Hit: 9 (1d10 + 4) Bludgeoning damage. If the target is a Large or smaller creature, it has the Grappled condition (escape DC 14) from one of two pincers.\n- Paralyzing Tentacles. Constitution Saving Throw: DC 13, one creature Grappled by the chuul. Failure: The target has the Poisoned condition and repeats the save at the end of each of its turns, ending the effect on itself on a success. After 1 minute, it succeeds automatically.\n- While Poisoned, the target has the Paralyzed condition.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Chuul","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Clay Golem","constant":false,"content":"## Clay Golem (monster stat block, SRD 5.2.1)\nLarge Construct, Unaligned. AC 14, HP 123 (13d10+52), Initiative +3, Speed 30 ft..\nAbilities: Str 20 (save +5), Dex 9 (save -1), Con 18 (save +4), Int 3 (save -4), Wis 8 (save -1), Cha 1 (save -5).\nCR 9 (XP 5000, PB +4).\nResistances Bludgeoning, Piercing, Slashing\nImmunities Acid, Poison, Psychic; Charmed, Exhaustion, Frightened, Paralyzed, Petrified, Poisoned\nSenses Darkvision 60 ft.; Passive Perception 9\nLanguages Common plus one other language\n### Traits\n- Acid Absorption. Whenever the golem is subjected to Acid damage, it takes no damage and instead regains a number of Hit Points equal to the Acid damage dealt.\n- Berserk. Whenever the golem starts its turn Bloodied, roll 1d6. On a 6, the golem goes berserk. On each of its turns while berserk, the golem attacks the nearest creature it can see. If no creature is near enough to move to and attack, the golem attacks an object. Once the golem goes berserk, it continues to be berserk until it is destroyed or it is no longer Bloodied.\n- Immutable Form. The golem can't shape-shift.\n- Magic Resistance. The golem has Advantage on saving throws against spells and other magical effects.\n### Actions\n- Multiattack. The golem makes two Slam attacks, or it makes three Slam attacks if it used Hasten this turn.\n- Slam. Melee Attack Roll: +9, reach 5 ft. Hit: 10 (1d10 + 5) Bludgeoning damage plus 6 (1d12) Acid damage, and the target's Hit Point maximum decreases by an amount equal to the Acid damage taken.\n### Bonus Actions\n- Hasten (Recharge 5–6). The golem takes the Dash and Disengage actions.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Clay Golem","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Cloaker","constant":false,"content":"## Cloaker (monster stat block, SRD 5.2.1)\nLarge Aberration, Chaotic Neutral. AC 14, HP 91 (14d10+14), Initiative +5, Speed 10 ft., Fly 40 ft..\nAbilities: Str 17 (save +3), Dex 15 (save +2), Con 12 (save +1), Int 13 (save +1), Wis 14 (save +2), Cha 7 (save -2).\nCR 8 (XP 3900, PB +3).\nSkills Stealth +5\nImmunities Frightened\nSenses Darkvision 120 ft.; Passive Perception 12\nLanguages Deep Speech, Undercommon\n### Traits\n- Light Sensitivity. While in Bright Light, the cloaker has Disadvantage on attack rolls.\n### Actions\n- Multiattack. The cloaker makes one Attach attack and two Tail attacks.\n- Attach. Melee Attack Roll: +6, reach 5 ft. Hit: 13 (3d6 + 3) Piercing damage. If the target is a Large or smaller creature, the cloaker attaches to it. While the cloaker is attached, the target has the Blinded condition, and the cloaker can't make Attach attacks against other targets. In addition, the cloaker halves the damage it takes (round down), and the target takes the same amount of damage. The cloaker can detach itself by spending 5 feet of movement. The target or a creature within 5 feet of it can take an action to try to detach the cloaker, doing so by succeeding on a DC 14 Strength (Athletics) check.\n- Tail. Melee Attack Roll: +6, reach 10 ft. Hit: 8 (1d10 + 3) Slashing damage.\n### Bonus Actions\n- Moan. Wisdom Saving Throw: DC 13, each creature in a 60-foot Emanation originating from the cloaker. Failure: The target has the Frightened condition until the end of the cloaker's next turn. Success: The target is immune to this cloaker's Moan for the next 24 hours.\n- Phantasms (Recharge after a Short or Long Rest). The cloaker casts the Mirror Image spell, requiring no spell components and using Wisdom as the spellcasting ability. The spell ends early if the cloaker starts or ends its turn in Bright Light.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Cloaker","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Cloud Giant","constant":false,"content":"## Cloud Giant (monster stat block, SRD 5.2.1)\nHuge Giant, Neutral. AC 14, HP 200 (16d12+96), Initiative +4, Speed 40 ft., Fly 20 ft. (hover).\nAbilities: Str 27 (save +8), Dex 10 (save +0), Con 22 (save +10), Int 12 (save +1), Wis 16 (save +7), Cha 16 (save +3).\nCR 9 (XP 5000, PB +4).\nSkills Insight +7, Perception +11\nSenses Passive Perception 21\nLanguages Common, Giant\n### Actions\n- Multiattack. The giant makes two attacks, using Thunderous Mace or Thundercloud in any combination. It can replace one attack with a use of Spellcasting to cast Fog Cloud.\n- Thunderous Mace. Melee Attack Roll: +12, reach 10 ft. Hit: 21 (3d8 + 8) Bludgeoning damage plus 7 (2d6) Thunder damage.\n- Thundercloud. Ranged Attack Roll: +12, range 240 ft. Hit: 18 (3d6 + 8) Thunder damage, and the target has the Incapacitated condition until the end of its next turn.\n- Spellcasting. The giant casts one of the following spells, requiring no Material components and using Charisma as the spellcasting ability (spell save DC 15): At Will: Detect Magic, Fog Cloud, Light 1/Day Each: Control Weather, Gaseous Form, Telekinesis\n### Bonus Actions\n- Misty Step. The giant casts the Misty Step spell, using the same spellcasting ability as Spellcasting.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Cloud Giant","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Cockatrice","constant":false,"content":"## Cockatrice (monster stat block, SRD 5.2.1)\nSmall Monstrosity, Unaligned. AC 11, HP 22 (5d6+5), Initiative +1, Speed 20 ft., Fly 40 ft..\nAbilities: Str 6 (save -2), Dex 12 (save +1), Con 12 (save +1), Int 2 (save -4), Wis 13 (save +1), Cha 5 (save -3).\nCR 1/2 (XP 100, PB +2).\nImmunities Petrified\nSenses Darkvision 60 ft.; Passive Perception 11\nLanguages None\n### Actions\n- Petrifying Bite. Melee Attack Roll: +3, reach 5 ft. Hit: 3 (1d4 + 1) Piercing damage. If the target is a creature, it is subjected to the following effect. Constitution Saving Throw: DC 11. First Failure: The target has the Restrained condition. The target repeats the save at the end of its next turn if it is still Restrained, ending the effect on itself on a success. Second Failure: The target has the Petrified condition, instead of the Restrained condition, for 24 hours.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Cockatrice","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Commoner","constant":false,"content":"## Commoner (monster stat block, SRD 5.2.1)\nMedium or Small Humanoid, Neutral. AC 10, HP 4 (1d8), Initiative +0, Speed 30 ft..\nAbilities: Str 10 (save +0), Dex 10 (save +0), Con 10 (save +0), Int 10 (save +0), Wis 10 (save +0), Cha 10 (save +0).\nCR 0 (XP 10, PB +2).\nGear Club\nSenses Passive Perception 10\nLanguages Common\n### Traits\n- Training. The commoner has proficiency in one skill of the GM's choice and has Advantage whenever it makes an ability check using that skill.\n### Actions\n- Club. Melee Attack Roll: +2, reach 5 ft. Hit: 2 (1d4) Bludgeoning damage.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Commoner","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Copper Dragon Wyrmling","constant":false,"content":"## Copper Dragon Wyrmling (monster stat block, SRD 5.2.1)\nMedium Dragon (Metallic), Chaotic Good. AC 16, HP 22 (4d8+4), Initiative +3, Speed 30 ft., Climb 30 ft., Fly 60 ft..\nAbilities: Str 15 (save +2), Dex 12 (save +3), Con 13 (save +1), Int 14 (save +2), Wis 11 (save +2), Cha 13 (save +1).\nCR 1 (XP 200, PB +2).\nSkills Perception +4, Stealth +3\nImmunities Acid\nSenses Blindsight 10 ft., Darkvision 60 ft.; Passive Perception 14\nLanguages Draconic\n### Actions\n- Rend. Melee Attack Roll: +4, reach 5 ft. Hit: 7 (1d10 + 2) Slashing damage.\n- Acid Breath (Recharge 5–6). Dexterity Saving Throw: DC 11, each creature in a 20-foot-long, 5-footwide Line. Failure: 18 (4d8) Acid damage. Success: Half damage.\n- Slowing Breath. Constitution Saving Throw: DC 11, each creature in a 15-foot Cone. Failure: The target can't take Reactions; its Speed is halved; and it can take either an action or a Bonus Action on its turn, not both.\n- This effect lasts until the end of its next turn.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Copper Dragon Wyrmling","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Young Copper Dragon","constant":false,"content":"## Young Copper Dragon (monster stat block, SRD 5.2.1)\nLarge Dragon (Metallic), Chaotic Good. AC 17, HP 119 (14d10+42), Initiative +4, Speed 40 ft., Climb 40 ft., Fly 80 ft..\nAbilities: Str 19 (save +4), Dex 12 (save +4), Con 17 (save +3), Int 16 (save +3), Wis 13 (save +4), Cha 15 (save +2).\nCR 7 (XP 2900, PB +3).\nSkills Deception +5, Perception +7, Stealth +4\nImmunities Acid\nSenses Blindsight 30 ft., Darkvision 120 ft.; Passive Perception 17\nLanguages Common, Draconic\n### Actions\n- Multiattack. The dragon makes three Rend attacks. It can replace one attack with a use of Slowing Breath.\n- Rend. Melee Attack Roll: +7, reach 10 ft. Hit: 15 (2d10 + 4) Slashing damage.\n- Acid Breath (Recharge 5–6). Dexterity Saving Throw: DC 14, each creature in a 40-foot-long, 5-footwide Line. Failure: 40 (9d8) Acid damage. Success: Half damage.\n- Slowing Breath. Constitution Saving Throw: DC 14, each creature in a 30-foot Cone. Failure: The target can't take Reactions; its Speed is halved; and it can take either an action or a Bonus Action on its turn, not both.\n- This effect lasts until the end of its next turn.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Young Copper Dragon","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Adult Copper Dragon","constant":false,"content":"## Adult Copper Dragon (monster stat block, SRD 5.2.1)\nHuge Dragon (Metallic), Chaotic Good. AC 18, HP 184 (16d12+80), Initiative +11, Speed 40 ft., Climb 40 ft., Fly 80 ft..\nAbilities: Str 23 (save +6), Dex 12 (save +6), Con 21 (save +5), Int 18 (save +4), Wis 15 (save +7), Cha 18 (save +4).\nCR 14 (XP 11500, PB +5).\nSkills Deception +9, Perception +12, Stealth +6\nImmunities Acid\nSenses Blindsight 60 ft., Darkvision 120 ft.; Passive Perception 22\nLanguages Common, Draconic\n### Traits\n- Legendary Resistance (3/Day, or 4/Day in Lair). If the dragon fails a saving throw, it can choose to succeed instead.\n### Actions\n- Multiattack. The dragon makes three Rend attacks. It can replace one attack with a use of (A) Slowing Breath or (B) Spellcasting to cast Mind Spike (level 4 version).\n- Rend. Melee Attack Roll: +11, reach 10 ft. Hit: 17 (2d10 + 6) Slashing damage plus 4 (1d8) Acid damage.\n- Acid Breath (Recharge 5–6). Dexterity Saving Throw: DC 18, each creature in an 60-foot-long, 5-footwide Line. Failure: 54 (12d8) Acid damage. Success: Half damage.\n- Slowing Breath. Constitution Saving Throw: DC 18, each creature in a 60-foot Cone. Failure: The target can't take Reactions; its Speed is halved; and it can take either an action or a Bonus Action on its turn, not both.\n- This effect lasts until the end of its next turn.\n- Spellcasting. The dragon casts one of the following spells, requiring no Material components and using Charisma as the spellcasting ability (spell save DC 17): At Will: Detect Magic, Mind Spike (level 4 version), Minor Illusion, Shapechange (Beast or Humanoid form only, no Temporary Hit Points gained from the spell, and no Concentration or Temporary Hit Points required to maintain the spell) 1/Day Each: Greater Restoration, Major Image\n### Legendary Actions\n- Legendary Action Uses: 3 (4 in Lair). Immediately after another creature's turn, the dragon can expend a use to take one of the following actions. The dragon regains all expended uses at the start of each of its turns.\n- Giggling Magic. Charisma Saving Throw: DC 17, one creature the dragon can see within 90 feet. Failure: 24 (7d6) Psychic damage. Until the end of its next turn, the target rolls 1d6 whenever it makes an ability check or attack roll and subtracts the number rolled from the D20 Test. Failure or Success: The dragon can't take this action again until the start of its next turn.\n- Mind Jolt. The dragon uses Spellcasting to cast Mind Spike (level 4 version). The dragon can't take this action again until the start of its next turn.\n- Pounce. The dragon moves up to half its Speed, and it makes one Rend attack.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Adult Copper Dragon","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Ancient Copper Dragon","constant":false,"content":"## Ancient Copper Dragon (monster stat block, SRD 5.2.1)\nGargantuan Dragon (Metallic), Chaotic Good. AC 21, HP 367 (21d20+147), Initiative +15, Speed 40 ft., Climb 40 ft., Fly 80 ft..\nAbilities: Str 27 (save +8), Dex 12 (save +8), Con 25 (save +7), Int 20 (save +5), Wis 17 (save +10), Cha 22 (save +6).\nCR 21 (XP 33000, PB +7).\nSkills Deception +13, Perception +17, Stealth +8\nImmunities Acid\nSenses Blindsight 60 ft., Darkvision 120 ft.; Passive Perception 27\nLanguages Common, Draconic\n### Traits\n- Legendary Resistance (4/Day, or 5/Day in Lair). If the dragon fails a saving throw, it can choose to succeed instead.\n### Actions\n- Multiattack. The dragon makes three Rend attacks. It can replace one attack with a use of (A) Slowing Breath or (B) Spellcasting to cast Mind Spike (level 5 version).\n- Rend. Melee Attack Roll: +15, reach 15 ft. Hit: 19 (2d10 + 8) Slashing damage plus 9 (2d8) Acid damage.\n- Acid Breath (Recharge 5–6). Dexterity Saving Throw: DC 22, each creature in an 90-foot-long, 10-footwide Line. Failure: 63 (14d8) Acid damage. Success: Half damage.\n- Slowing Breath. Constitution Saving Throw: DC 22, each creature in a 90-foot Cone. Failure: The target can't take Reactions; its Speed is halved; and it can take either an action or a Bonus Action on its turn, not both.\n- This effect lasts until the end of its next turn.\n- Spellcasting. The dragon casts one of the following spells, requiring no Material components and using Charisma as the spellcasting ability (spell save DC 21): At Will: Detect Magic, Mind Spike (level 5 version), Minor Illusion, Shapechange (Beast or Humanoid form only, no Temporary Hit Points gained from the spell, and no Concentration or Temporary Hit Points required to maintain the spell) 1/Day Each: Greater Restoration, Major Image, Project Image\n### Legendary Actions\n- Legendary Action Uses: 3 (4 in Lair). Immediately after another creature's turn, the dragon can expend a use to take one of the following actions. The dragon regains all expended uses at the start of each of its turns.\n- Giggling Magic. Charisma Saving Throw: DC 21, one creature the dragon can see within 120 feet. Failure: 31 (9d6) Psychic damage. Until the end of its next turn, the target rolls 1d8 whenever it makes an ability check or attack roll and subtracts the number rolled from the D20 Test. Failure or Success: The dragon can't take this action again until the start of its next turn.\n- Mind Jolt. The dragon uses Spellcasting to cast Mind Spike (level 5 version). The dragon can't take this action again until the start of its next turn.\n- Pounce. The dragon moves up to half its Speed, and it makes one Rend attack.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Ancient Copper Dragon","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Couatl","constant":false,"content":"## Couatl (monster stat block, SRD 5.2.1)\nMedium Celestial, Lawful Good. AC 19, HP 60 (8d8+24), Initiative +5, Speed 30 ft., Fly 90 ft..\nAbilities: Str 16 (save +3), Dex 20 (save +5), Con 17 (save +5), Int 18 (save +4), Wis 20 (save +7), Cha 18 (save +4).\nCR 4 (XP 1100, PB +2).\nResistances Bludgeoning, Piercing, Slashing\nImmunities Psychic, Radiant\nSenses Truesight 120 ft.; Passive Perception 15\nLanguages All; telepathy 120 ft.\n### Traits\n- Shielded Mind. The couatl's thoughts can't be read by any means, and other creatures can communicate with it telepathically only if it allows them.\n### Actions\n- Bite. Melee Attack Roll: +7, reach 5 ft. Hit: 11 (1d12 + 5) Piercing damage, and the target has the Poisoned condition until the end of the couatl's next turn.\n- Constrict. Strength Saving Throw: DC 15, one Medium or smaller creature the couatl can see within 5 feet. Failure: 8 (1d6 + 5) Bludgeoning damage. The target has the Grappled condition (escape DC 13), and it has the Restrained condition until the grapple ends.\n- Spellcasting. The couatl casts one of the following spells, requiring no spell components and using Wisdom as the spellcasting ability (spell save DC 15): At Will: Detect Evil and Good, Detect Magic, Detect Thoughts, Shapechange (Beast or Humanoid form only, no Temporary Hit Points gained from the spell, and no Concentration or Temporary Hit Points required to maintain the spell) 1/Day Each: Create Food and Water, Dream, Greater Restoration, Scrying, Sleep\n### Bonus Actions\n- Divine Aid (2/Day). The couatl casts Bless, Lesser Restoration, or Sanctuary, requiring no spell components and using the same spellcasting ability as Spellcasting.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Couatl","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Swarm of Crawling Claws","constant":false,"content":"## Swarm of Crawling Claws (monster stat block, SRD 5.2.1)\nMedium Swarm of Tiny Undead, Neutral Evil. AC 12, HP 49 (11d8), Initiative +2, Speed 30 ft., Climb 30 ft..\nAbilities: Str 14 (save +2), Dex 14 (save +2), Con 11 (save +0), Int 5 (save -3), Wis 10 (save +0), Cha 4 (save -3).\nCR 3 (XP 700, PB +2).\nResistances Bludgeoning, Piercing, Slashing\nImmunities Necrotic, Poison; Charmed, Exhaustion, Frightened, Grappled, Incapacitated, Paralyzed, Petrified, Poisoned, Prone, Restrained, Stunned\nSenses Blindsight 30 ft.; Passive Perception 10\nLanguages Understands Common but can't speak\n### Traits\n- Swarm. The swarm can occupy another creature's space and vice versa, and the swarm can move through any opening large enough for a Tiny creature. The swarm can't regain Hit Points or gain Temporary Hit Points.\n### Actions\n- Swarm of Grasping Hands. Melee Attack Roll: +4, reach 5 ft. Hit: 20 (4d8 + 2) Necrotic damage, or 11 (2d8 + 2) Necrotic damage if the swarm is Bloodied. If the target is a Medium or smaller creature, it has the Prone condition.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Swarm of Crawling Claws","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Cultist","constant":false,"content":"## Cultist (monster stat block, SRD 5.2.1)\nMedium or Small Humanoid, Neutral. AC 12, HP 9 (2d8), Initiative +1, Speed 30 ft..\nAbilities: Str 11 (save +0), Dex 12 (save +1), Con 10 (save +0), Int 10 (save +0), Wis 11 (save +2), Cha 10 (save +0).\nCR 1/8 (XP 25, PB +2).\nSkills Deception +2, Religion +2\nGear Leather Armor, Sickle\nSenses Passive Perception 10\nLanguages Common\n### Actions\n- Ritual Sickle. Melee Attack Roll: +3, reach 5 ft. Hit: 3 (1d4 + 1) Slashing damage plus 1 Necrotic damage.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Cultist","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Cultist Fanatic","constant":false,"content":"## Cultist Fanatic (monster stat block, SRD 5.2.1)\nMedium or Small Humanoid, Neutral. AC 13, HP 44 (8d8+8), Initiative +2, Speed 30 ft..\nAbilities: Str 11 (save +0), Dex 14 (save +2), Con 12 (save +1), Int 10 (save +0), Wis 14 (save +4), Cha 13 (save +1).\nCR 2 (XP 450, PB +2).\nSkills Deception +3, Persuasion +3, Religion +2\nGear Holy Symbol, Leather Armor\nSenses Passive Perception 12\nLanguages Common\n### Actions\n- Pact Blade. Melee Attack Roll: +4, reach 5 ft. Hit: 6 (1d8 + 2) Slashing damage plus 7 (2d6) Necrotic damage.\n- Spellcasting. The cultist casts one of the following spells, using Wisdom as the spellcasting ability (spell save DC 12, +4 to hit with spell attacks): At Will: Light, Thaumaturgy 2/Day: Command 1/Day: Hold Person\n### Bonus Actions\n- Spiritual Weapon (2/Day). The cultist casts the Spiritual Weapon spell, using the same spellcasting ability as Spellcasting.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Cultist Fanatic","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Darkmantle","constant":false,"content":"## Darkmantle (monster stat block, SRD 5.2.1)\nSmall Aberration, Unaligned. AC 11, HP 22 (5d6+5), Initiative +3, Speed 10 ft., Fly 30 ft..\nAbilities: Str 16 (save +3), Dex 12 (save +1), Con 13 (save +1), Int 2 (save -4), Wis 10 (save +0), Cha 5 (save -3).\nCR 1/2 (XP 100, PB +2).\nSkills Stealth +3\nSenses Blindsight 60 ft.; Passive Perception 10\nLanguages None\n### Actions\n- Crush. Melee Attack Roll: +5, reach 5 ft. Hit: 6 (1d6 + 3) Bludgeoning damage, and the darkmantle attaches to the target. If the target is a Medium or smaller creature and the darkmantle had Advantage on the attack roll, it covers the target, which has the Blinded condition and is suffocating while the darkmantle is attached in this way. While attached to a target, the darkmantle can attack only the target but has Advantage on its attack rolls. Its Speed becomes 0, it can't benefit from any bonus to its Speed, and it moves with the target. A creature can take an action to try to detach the darkmantle from itself, doing so with a successful DC 13 Strength (Athletics) check. On its turn, the darkmantle can detach itself by using 5 feet of movement.\n- Darkness Aura (1/Day). Magical Darkness fills a 15-foot Emanation originating from the darkmantle. This effect lasts while the darkmantle maintains Concentration on it, up to 10 minutes. Darkvision can't penetrate this area, and no light can illuminate it.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Darkmantle","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Death Dog","constant":false,"content":"## Death Dog (monster stat block, SRD 5.2.1)\nMedium Monstrosity, Neutral Evil. AC 12, HP 39 (6d8+12), Initiative +2, Speed 40 ft..\nAbilities: Str 15 (save +2), Dex 14 (save +2), Con 14 (save +2), Int 3 (save -4), Wis 13 (save +1), Cha 6 (save -2).\nCR 1 (XP 200, PB +2).\nSkills Perception +5, Stealth +4\nImmunities Blinded, Charmed, Deafened, Frightened, Stunned, Unconscious\nSenses Darkvision 120 ft.; Passive Perception 15\nLanguages None\n### Actions\n- Multiattack. The death dog makes two Bite attacks.\n- Bite. Melee Attack Roll: +4, reach 5 ft. Hit: 4 (1d4 + 2) Piercing damage. If the target is a creature, it is subjected to the following effect. Constitution Saving Throw: DC 12. First Failure: The target has the Poisoned condition. While Poisoned, the target's Hit Point maximum doesn't return to normal when finishing a Long Rest, and it repeats the save every 24 hours that elapse, ending the effect on itself on a success. Subsequent Failures: The Poisoned target's Hit Point maximum decreases by 5 (1d10).","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Death Dog","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Deva","constant":false,"content":"## Deva (monster stat block, SRD 5.2.1)\nMedium Celestial (Angel), Lawful Good. AC 17, HP 229 (27d8+108), Initiative +4, Speed 30 ft., Fly 90 ft. (hover).\nAbilities: Str 18 (save +4), Dex 18 (save +4), Con 18 (save +4), Int 17 (save +3), Wis 20 (save +9), Cha 20 (save +9).\nCR 10 (XP 5900, PB +4).\nSkills Insight +9, Perception +9\nResistances Radiant\nImmunities Charmed, Exhaustion, Frightened\nSenses Darkvision 120 ft.; Passive Perception 19\nLanguages All; telepathy 120 ft.\n### Traits\n- Exalted Restoration. If the deva dies outside Mount Celestia, its body disappears, and it gains a new body instantly, reviving with all its Hit Points somewhere in Mount Celestia.\n- Magic Resistance. The deva has Advantage on saving throws against spells and other magical effects.\n### Actions\n- Multiattack. The deva makes two Holy Mace attacks.\n- Holy Mace. Melee Attack Roll: +8, reach 5 ft. Hit: 7 (1d6 + 4) Bludgeoning damage plus 18 (4d8) Radiant damage.\n- Spellcasting. The deva casts one of the following spells, requiring no Material components and using Charisma as the spellcasting ability (spell save DC 17): At Will: Detect Evil and Good, Shapechange (Beast or Humanoid form only, no Temporary Hit Points gained from the spell, and no Concentration or Temporary Hit Points required to maintain the spell) 1/Day Each: Commune, Raise Dead\n### Bonus Actions\n- Divine Aid (2/Day). The deva casts Cure Wounds, Lesser Restoration, or Remove Curse, using the same spellcasting ability as Spellcasting.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Deva","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Djinni","constant":false,"content":"## Djinni (monster stat block, SRD 5.2.1)\nLarge Elemental (Genie), Neutral. AC 17, HP 218 (19d10+114), Initiative +2, Speed 30 ft., Fly 90 ft. (hover).\nAbilities: Str 21 (save +5), Dex 15 (save +6), Con 22 (save +6), Int 15 (save +2), Wis 16 (save +7), Cha 20 (save +5).\nCR 11 (XP 7200, PB +4).\nImmunities Lightning, Thunder\nSenses Darkvision 120 ft.; Passive Perception 13\nLanguages Primordial (Auran)\n### Traits\n- Elemental Restoration. If the djinni dies outside the Elemental Plane of Air, its body dissolves into mist, and it gains a new body in 1d4 days, reviving with all its Hit Points somewhere on the Plane of Air.\n- Magic Resistance. The djinni has Advantage on saving throws against spells and other magical effects.\n- Wishes. The djinni has a 30 percent chance of knowing the Wish spell. If the djinni knows it, the djinni can cast it only on behalf of a non-genie creature who communicates a wish in a way the djinni can understand. If the djinni casts the spell for the creature, the djinni suffers none of the spell's stress. Once the djinni has cast it three times, the djinni can't do so again for 365 days.\n### Actions\n- Multiattack. The djinni makes three attacks, using Storm Blade or Storm Bolt in any combination.\n- Storm Blade. Melee Attack Roll: +9, reach 5 feet. Hit: 12 (2d6 + 5) Slashing damage plus 7 (2d6) Lightning damage.\n- Storm Bolt. Ranged Attack Roll: +9, range 120 feet. Hit: 13 (3d8) Thunder damage. If the target is a Large or smaller creature, it has the Prone condition.\n- Create Whirlwind. The djinni conjures a whirlwind at a point it can see within 120 feet. The whirlwind fills a 20-foot-radius, 60-foot-high Cylinder centered on that point. The whirlwind lasts until the djinni's Concentration on it ends. The djinni can move the whirlwind up to 20 feet at the start of each of its turns. Whenever the whirlwind enters a creature's space or a creature enters the whirlwind, that creature is subjected to the following effect. Strength Saving Throw: DC 17 (a creature makes this save only once per turn, and the djinni is unaffected). Failure: While in the whirlwind, the target has the Restrained condition and moves with the whirlwind. At the start of each of its turns, the Restrained target takes 21 (6d6) Thunder damage. At the end of each of its turns, the target repeats the save, ending the effect on itself on a success.\n- Spellcasting. The djinni casts one of the following spells, requiring no Material components and using Charisma as the spellcasting ability (spell save DC 17): At Will: Detect Evil and Good, Detect Magic 2/Day Each: Create Food and Water (can create wine instead of water), Tongues, Wind Walk 1/Day Each: Creation, Gaseous Form, Invisibility, Major Image, Plane Shift","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Djinni","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Doppelganger","constant":false,"content":"## Doppelganger (monster stat block, SRD 5.2.1)\nMedium Monstrosity, Neutral. AC 14, HP 52 (8d8+16), Initiative +4, Speed 30 ft..\nAbilities: Str 11 (save +0), Dex 18 (save +4), Con 14 (save +2), Int 11 (save +0), Wis 12 (save +1), Cha 14 (save +2).\nCR 3 (XP 700, PB +2).\nSkills Deception +6, Insight +3\nImmunities Charmed\nSenses Darkvision 60 ft.; Passive Perception 11\nLanguages Common plus three other languages\n### Actions\n- Multiattack. The doppelganger makes two Slam attacks and uses Unsettling Visage if available.\n- Slam. Melee Attack Roll: +6 (with Advantage during the first round of each combat), reach 5 ft. Hit: 11 (2d6 + 4) Bludgeoning damage.\n- Read Thoughts. The doppelganger casts Detect Thoughts, requiring no spell components and using Charisma as the spellcasting ability (spell save DC 12).\n- Unsettling Visage (Recharge 6). Wisdom Saving Throw: DC 12, each creature in a 15-foot Emanation originating from the doppelganger that can see the doppelganger. Failure: The target has the Frightened condition and repeats the save at the end of each of its turns, ending the effect on itself on a success. After 1 minute, it succeeds automatically.\n### Bonus Actions\n- Shape-Shift. The doppelganger shape-shifts into a Medium or Small Humanoid, or it returns to its true form. Its game statistics, other than its size, are the same in each form. Any equipment it is wearing or carrying isn't transformed.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Doppelganger","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Dragon Turtle","constant":false,"content":"## Dragon Turtle (monster stat block, SRD 5.2.1)\nGargantuan Dragon, Neutral. AC 20, HP 356 (23d20+115), Initiative +6, Speed 20 ft., Swim 50 ft..\nAbilities: Str 25 (save +7), Dex 10 (save +0), Con 20 (save +11), Int 10 (save +0), Wis 12 (save +7), Cha 12 (save +1).\nCR 17 (XP 18000, PB +6).\nResistances Fire\nSenses Darkvision 120 ft.; Passive Perception 11\nLanguages Draconic, Primordial (Aquan)\n### Traits\n- Amphibious. The dragon can breathe air and water.\n### Actions\n- Multiattack. The dragon makes three Bite attacks. It can replace one attack with a Tail attack.\n- Bite. Melee Attack Roll: +13, reach 15 ft. Hit: 23 (3d10 + 7) Piercing damage plus 7 (2d6) Fire damage. Being underwater doesn't grant Resistance to this Fire damage.\n- Tail. Melee Attack Roll: +13, reach 15 ft. Hit: 18 (2d10 + 7) Bludgeoning damage. If the target is a Huge or smaller creature, it has the Prone condition.\n- Steam Breath (Recharge 5–6). Constitution Saving Throw: DC 19, each creature in a 60-foot Cone. Failure: 56 (16d6) Fire damage. Success: Half damage. Failure or Success: Being underwater doesn't grant Resistance to this Fire damage.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Dragon Turtle","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Dretch","constant":false,"content":"## Dretch (monster stat block, SRD 5.2.1)\nSmall Fiend (Demon), Chaotic Evil. AC 11, HP 18 (4d6+4), Initiative +0, Speed 20 ft..\nAbilities: Str 12 (save +1), Dex 11 (save +0), Con 12 (save +1), Int 5 (save -3), Wis 8 (save -1), Cha 3 (save -4).\nCR 1/4 (XP 50, PB +2).\nResistances Cold, Fire, Lightning\nImmunities Poison; Poisoned\nSenses Darkvision 60 ft.; Passive Perception 9\nLanguages Abyssal; telepathy 60 ft. (works only with creatures that understand Abyssal)\n### Actions\n- Rend. Melee Attack Roll: +3, reach 5 ft. Hit: 4 (1d6 + 1) Slashing damage.\n- Fetid Cloud (1/Day). Constitution Saving Throw: DC 11, each creature in a 10-foot Emanation originating from the dretch. Failure: The target has the Poisoned condition until the end of its next turn. While Poisoned, the creature can take either an action or a Bonus Action on its turn, not both, and it can't take Reactions.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Dretch","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Drider","constant":false,"content":"## Drider (monster stat block, SRD 5.2.1)\nLarge Monstrosity, Chaotic Evil. AC 19, HP 123 (13d10+52), Initiative +4, Speed 30 ft., Climb 30 ft..\nAbilities: Str 16 (save +3), Dex 19 (save +4), Con 18 (save +4), Int 13 (save +1), Wis 16 (save +3), Cha 12 (save +1).\nCR 6 (XP 2300, PB +3).\nSkills Perception +6, Stealth +10\nSenses Darkvision 120 ft.; Passive Perception 16\nLanguages Elvish, Undercommon\n### Traits\n- Spider Climb. The drider can climb difficult surfaces, including along ceilings, without needing to make an ability check.\n- Sunlight Sensitivity. While in sunlight, the drider has Disadvantage on ability checks and attack rolls.\n- Web Walker. The drider ignores movement restrictions caused by webs, and the drider knows the location of any other creature in contact with the same web.\n### Actions\n- Multiattack. The drider makes three attacks, using Foreleg or Poison Burst in any combination.\n- Foreleg. Melee Attack Roll: +7, reach 10 ft. Hit: 13 (2d8 + 4) Piercing damage.\n- Poison Burst. Ranged Attack Roll: +6, range 120 ft. Hit: 13 (3d6 + 3) Poison damage.\n### Bonus Actions\n- Magic of the Spider Queen (Recharge 5–6). The drider casts Darkness, Faerie Fire, or Web, requiring no Material components and using Wisdom as the spellcasting ability (spell save DC 14).","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Drider","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Druid","constant":false,"content":"## Druid (monster stat block, SRD 5.2.1)\nMedium or Small Humanoid (Druid), Neutral. AC 13, HP 44 (8d8+8), Initiative +1, Speed 30 ft..\nAbilities: Str 10 (save +0), Dex 12 (save +1), Con 13 (save +1), Int 12 (save +1), Wis 16 (save +3), Cha 11 (save +0).\nCR 2 (XP 450, PB +2).\nSkills Medicine +5, Nature +3, Perception +5\nGear Studded Leather Armor\nSenses Passive Perception 15\nLanguages Common, Druidic, Sylvan\n### Actions\n- Multiattack. The druid makes two attacks, using Vine Staff or Verdant Wisp in any combination.\n- Vine Staff. Melee Attack Roll: +5, reach 5 ft. Hit: 7 (1d8 + 3) Bludgeoning damage plus 2 (1d4) Poison damage.\n- Verdant Wisp. Ranged Attack Roll: +5, range 90 ft. Hit: 10 (3d6) Radiant damage.\n- Spellcasting. The druid casts one of the following spells, using Wisdom as the spellcasting ability (spell save DC 13): At Will: Druidcraft, Speak with Animals 2/Day Each: Entangle, Thunderwave 1/Day Each: Animal Messenger, Longstrider, Moonbeam","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Druid","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Dryad","constant":false,"content":"## Dryad (monster stat block, SRD 5.2.1)\nMedium Fey, Neutral. AC 16, HP 22 (5d8), Initiative +1, Speed 30 ft..\nAbilities: Str 10 (save +0), Dex 12 (save +1), Con 11 (save +0), Int 14 (save +2), Wis 15 (save +2), Cha 18 (save +4).\nCR 1 (XP 200, PB +2).\nSkills Perception +4, Stealth +5\nSenses Darkvision 60 ft.; Passive Perception 14\nLanguages Elvish, Sylvan\n### Traits\n- Magic Resistance. The dryad has Advantage on saving throws against spells and other magical effects.\n- Speak with Beasts and Plants. The dryad can communicate with Beasts and Plants as if they shared a language.\n### Actions\n- Multiattack. The dryad makes one Vine Lash or Thorn Burst attack, and it can use Spellcasting to cast Charm Monster.\n- Vine Lash. Melee Attack Roll: +6, reach 10 ft. Hit: 8 (1d8 + 4) Slashing damage.\n- Thorn Burst. Ranged Attack Roll: +6, range 60 ft. Hit: 7 (1d6 + 4) Piercing damage.\n- Spellcasting. The dryad casts one of the following spells, requiring no Material components and using Charisma as the spellcasting ability (spell save DC 14): At Will: Animal Friendship, Charm Monster (lasts 24 hours; ends early if the dryad casts the spell again), Druidcraft 1/Day Each: Entangle, Pass without Trace\n### Bonus Actions\n- Tree Stride. If within 5 feet of a Large or bigger tree, the dryad teleports to an unoccupied space within 5 feet of a second Large or bigger tree that is within 60 feet of the previous tree.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Dryad","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Earth Elemental","constant":false,"content":"## Earth Elemental (monster stat block, SRD 5.2.1)\nLarge Elemental, Neutral. AC 17, HP 147 (14d10+70), Initiative -1, Speed 30 ft., Burrow 30 ft..\nAbilities: Str 20 (save +5), Dex 8 (save -1), Con 20 (save +5), Int 5 (save -3), Wis 10 (save +0), Cha 5 (save -3).\nCR 5 (XP 1800, PB +3).\nVulnerabilities Thunder\nImmunities Poison; Exhaustion, Paralyzed, Petrified, Poisoned, Unconscious\nSenses Darkvision 60 ft., Tremorsense 60 ft.; Passive Perception 10\nLanguages Primordial (Terran)\n### Traits\n- Earth Glide. The elemental can burrow through nonmagical, unworked earth and stone. While doing so, the elemental doesn't disturb the material it moves through.\n- Siege Monster. The elemental deals double damage to objects and structures.\n### Actions\n- Multiattack. The elemental makes two attacks, using Slam or Rock Launch in any combination.\n- Slam. Melee Attack Roll: +8, reach 10 ft. Hit: 14 (2d8 + 5) Bludgeoning damage.\n- Rock Launch. Ranged Attack Roll: +8, range 60 ft. Hit: 8 (1d6 + 5) Bludgeoning damage. If the target is a Large or smaller creature, it has the Prone condition.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Earth Elemental","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Efreeti","constant":false,"content":"## Efreeti (monster stat block, SRD 5.2.1)\nLarge Elemental (Genie), Neutral. AC 17, HP 212 (17d10+119), Initiative +1, Speed 40 ft., Fly 60 ft. (hover).\nAbilities: Str 22 (save +6), Dex 12 (save +1), Con 24 (save +7), Int 16 (save +3), Wis 15 (save +6), Cha 19 (save +8).\nCR 11 (XP 7200, PB +4).\nImmunities Fire\nSenses Darkvision 120 ft.; Passive Perception 12\nLanguages Primordial (Ignan)\n### Traits\n- Elemental Restoration. If the efreeti dies outside the Elemental Plane of Fire, its body dissolves into ash, and it gains a new body in 1d4 days, reviving with all its Hit Points somewhere on the Plane of Fire.\n- Magic Resistance. The efreeti has Advantage on saving throws against spells and other magical effects.\n- Wishes. The efreeti has a 30 percent chance of knowing the Wish spell. If the efreeti knows it, the efreeti can cast it only on behalf of a non-genie creature who communicates a wish in a way the efreeti can understand. If the efreeti casts the spell for the creature, the efreeti suffers none of the spell's stress. Once the efreeti has cast it three times, the efreeti can't do so again for 365 days.\n### Actions\n- Multiattack. The efreeti makes three attacks, using Heated Blade or Hurl Flame in any combination.\n- Heated Blade. Melee Attack Roll: +10, reach 5 ft. Hit: 13 (2d6 + 6) Slashing damage plus 13 (2d12) Fire damage.\n- Hurl Flame. Ranged Attack Roll: +8, range 120 ft. Hit: 24 (7d6) Fire damage.\n- Spellcasting. The efreeti casts one of the following spells, requiring no Material components and using Charisma as the spellcasting ability (spell save DC 16): At Will: Detect Magic, Elementalism 1/Day Each: Gaseous Form, Invisibility, Major Image, Plane Shift, Tongues, Wall of Fire (level 7 version)","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Efreeti","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Erinyes","constant":false,"content":"## Erinyes (monster stat block, SRD 5.2.1)\nMedium Fiend (Devil), Lawful Evil. AC 18, HP 178 (21d8+84), Initiative +7, Speed 30 ft., Fly 60 ft..\nAbilities: Str 18 (save +4), Dex 16 (save +7), Con 18 (save +8), Int 14 (save +2), Wis 14 (save +2), Cha 18 (save +8).\nCR 12 (XP 8400, PB +4).\nSkills Perception +6, Persuasion +8\nResistances Cold\nImmunities Fire, Poison; Poisoned\nSenses Truesight 120 ft.; Passive Perception 16\nLanguages Infernal; telepathy 120 ft.\n### Traits\n- Diabolical Restoration. If the erinyes dies outside the Nine Hells, its body disappears in sulfurous smoke, and it gains a new body instantly, reviving with all its Hit Points somewhere in the Nine Hells.\n- Magic Resistance. The erinyes has Advantage on saving throws against spells and other magical effects.\n- Magic Rope. The erinyes has a magic rope. While bearing it, the erinyes can use the Entangling Rope action. The rope has AC 20, HP 90, and Immunity to Poison and Psychic damage. The rope turns to dust if reduced to 0 Hit Points, if it is 5+ feet away from the erinyes for 1 hour or more, or if the erinyes dies. If the rope is damaged or destroyed, the erinyes can fully restore it when finishing a Short or Long Rest.\n### Actions\n- Multiattack. The erinyes makes three Withering Sword attacks and can use Entangling Rope.\n- Withering Sword. Melee Attack Roll: +8, reach 5 ft. Hit: 13 (2d8 + 4) Slashing damage plus 11 (2d10) Necrotic damage.\n- Entangling Rope (Requires Magic Rope). Strength Saving Throw: DC 16, one creature the erinyes can see within 120 feet. Failure: 14 (4d6) Force damage, and the target has the Restrained condition until the rope is destroyed, the erinyes uses a Bonus Action to release the target, or the erinyes uses Entangling Rope again.\n### Reactions\n- Parry. Trigger: The erinyes is hit by a melee attack roll while holding a weapon. Response: The erinyes adds 4 to its AC against that attack, possibly causing it to miss.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Erinyes","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Ettercap","constant":false,"content":"## Ettercap (monster stat block, SRD 5.2.1)\nMedium Monstrosity, Neutral Evil. AC 13, HP 44 (8d8+8), Initiative +2, Speed 30 ft., Climb 30 ft..\nAbilities: Str 14 (save +2), Dex 15 (save +2), Con 13 (save +1), Int 7 (save -2), Wis 12 (save +1), Cha 8 (save -1).\nCR 2 (XP 450, PB +2).\nSkills Perception +3, Stealth +4, Survival +3\nSenses Darkvision 60 ft.; Passive Perception 13\nLanguages None\n### Traits\n- Spider Climb. The ettercap can climb difficult surfaces, including along ceilings, without needing to make an ability check.\n- Web Walker. The ettercap ignores movement restrictions caused by webs, and the ettercap knows the location of any other creature in contact with the same web.\n### Actions\n- Multiattack. The ettercap makes one Bite attack and one Claw attack.\n- Bite. Melee Attack Roll: +4, reach 5 ft. Hit: 5 (1d6 + 2) Piercing damage plus 2 (1d4) Poison damage, and the target has the Poisoned condition until the start of the ettercap's next turn.\n- Claw. Melee Attack Roll: +4, reach 5 ft. Hit: 7 (2d4 + 2) Slashing damage.\n- Web Strand (Recharge 5–6). Dexterity Saving Throw: DC 12, one Large or smaller creature the ettercap can see within 30 feet. Failure: The target has the Restrained condition until the web is destroyed (AC 10; HP 5; Vulnerability to Fire damage; Immunity to Bludgeoning, Poison, and Psychic damage).\n### Bonus Actions\n- Reel. The ettercap pulls one creature within 30 feet of itself that is Restrained by its Web Strand up to 25 feet straight toward itself.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Ettercap","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Ettin","constant":false,"content":"## Ettin (monster stat block, SRD 5.2.1)\nLarge Giant, Chaotic Evil. AC 12, HP 85 (10d10+30), Initiative -1, Speed 40 ft..\nAbilities: Str 21 (save +5), Dex 8 (save -1), Con 17 (save +3), Int 6 (save -2), Wis 10 (save +0), Cha 8 (save -1).\nCR 4 (XP 1100, PB +2).\nSkills Perception +4\nImmunities Blinded, Charmed, Deafened, Frightened, Stunned, Unconscious\nGear Battleaxe, Morningstar\nSenses Darkvision 60 ft.; Passive Perception 14\nLanguages Giant\n### Actions\n- Multiattack. The ettin makes one Battleaxe attack and one Morningstar attack.\n- Battleaxe. Melee Attack Roll: +7, reach 5 ft. Hit: 14 (2d8 + 5) Slashing damage. If the target is a Large or smaller creature, it has the Prone condition.\n- Morningstar. Melee Attack Roll: +7, reach 5 ft. Hit: 14 (2d8 + 5) Piercing damage, and the target has Disadvantage on the next attack roll it makes before the end of its next turn.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Ettin","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Fire Elemental","constant":false,"content":"## Fire Elemental (monster stat block, SRD 5.2.1)\nLarge Elemental, Neutral. AC 13, HP 93 (11d10+33), Initiative +3, Speed 50 ft..\nAbilities: Str 10 (save +0), Dex 17 (save +3), Con 16 (save +3), Int 6 (save -2), Wis 10 (save +0), Cha 7 (save -2).\nCR 5 (XP 1800, PB +3).\nResistances Bludgeoning, Piercing, Slashing\nImmunities Fire, Poison; Exhaustion, Grappled, Paralyzed, Petrified, Poisoned, Prone, Restrained, Unconscious\nSenses Darkvision 60 ft.; Passive Perception 10\nLanguages Primordial (Ignan)\n### Traits\n- Fire Aura. At the end of each of the elemental's turns, each creature in a 10-foot Emanation originating from the elemental takes 5 (1d10) Fire damage. Creatures and flammable objects in the Emanation start burning.\n- Fire Form. The elemental can move through a space as narrow as 1 inch without expending extra movement to do so, and it can enter a creature's space and stop there. The first time it enters a creature's space on a turn, that creature takes 5 (1d10) Fire damage.\n- Illumination. The elemental sheds Bright Light in a 30foot radius and Dim Light for an additional 30 feet.\n- Water Susceptibility. The elemental takes 3 (1d6) Cold damage for every 5 feet the elemental moves in water or for every gallon of water splashed on it.\n### Actions\n- Multiattack. The elemental makes two Burn attacks.\n- Burn. Melee Attack Roll: +6, reach 5 ft. Hit: 10 (2d6 + 3) Fire damage. If the target is a creature or a flammable object, it starts burning.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Fire Elemental","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Fire Giant","constant":false,"content":"## Fire Giant (monster stat block, SRD 5.2.1)\nHuge Giant, Lawful Evil. AC 18, HP 162 (13d12+78), Initiative +3, Speed 30 ft..\nAbilities: Str 25 (save +7), Dex 9 (save +3), Con 23 (save +10), Int 10 (save +0), Wis 14 (save +2), Cha 13 (save +5).\nCR 9 (XP 5000, PB +4).\nSkills Athletics +11, Perception +6\nImmunities Fire\nSenses Passive Perception 16\nLanguages Giant\n### Actions\n- Multiattack. The giant makes two attacks, using Flame Sword or Hammer Throw in any combination.\n- Flame Sword. Melee Attack Roll: +11, reach 10 ft. Hit: 21 (4d6 + 7) Slashing damage plus 10 (3d6) Fire damage.\n- Hammer Throw. Ranged Attack Roll: +11, range 60/240 ft. Hit: 23 (3d10 + 7) Bludgeoning damage plus 4 (1d8) Fire damage, and the target is pushed up to 15 feet straight away from the giant and has Disadvantage on the next attack roll it makes before the end of its next turn.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Fire Giant","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Flesh Golem","constant":false,"content":"## Flesh Golem (monster stat block, SRD 5.2.1)\nMedium Construct, Neutral. AC 9, HP 127 (15d8+60), Initiative -1, Speed 30 ft..\nAbilities: Str 19 (save +4), Dex 9 (save -1), Con 18 (save +4), Int 6 (save -2), Wis 10 (save +0), Cha 5 (save -3).\nCR 5 (XP 1800, PB +3).\nImmunities Lightning, Poison; Charmed, Exhaustion, Frightened, Paralyzed, Petrified, Poisoned\nSenses Darkvision 60 ft.; Passive Perception 10\nLanguages Understands Common plus one other language but can't speak\n### Traits\n- Aversion to Fire. If the golem takes Fire damage, it has Disadvantage on attack rolls and ability checks until the end of its next turn.\n- Berserk. Whenever the golem starts its turn Bloodied, roll 1d6. On a 6, the golem goes berserk. On each of its turns while berserk, the golem attacks the nearest creature it can see. If no creature is near enough to move to and attack, the golem attacks an object. Once the golem goes berserk, it remains so until it is destroyed or it is no longer Bloodied. The golem's creator, if within 60 feet of the berserk golem, can try to calm it by taking an action to make a DC 15 Charisma (Persuasion) check; the golem must be able to hear its creator. If this check succeeds, the golem ceases being berserk until the start of its next turn, at which point it resumes rolling for the Berserk trait again if it is still Bloodied.\n- Immutable Form. The golem can't shape-shift.\n- Lightning Absorption. Whenever the golem is subjected to Lightning damage, it regains a number of Hit Points equal to the Lightning damage dealt.\n- Magic Resistance. The golem has Advantage on saving throws against spells and other magical effects.\n### Actions\n- Multiattack. The golem makes two Slam attacks.\n- Slam. Melee Attack Roll: +7, reach 5 ft. Hit: 13 (2d8 + 4) Bludgeoning damage plus 4 (1d8) Lightning damage.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Flesh Golem","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Frost Giant","constant":false,"content":"## Frost Giant (monster stat block, SRD 5.2.1)\nHuge Giant, Neutral Evil. AC 15, HP 149 (13d12+65), Initiative +2, Speed 40 ft..\nAbilities: Str 23 (save +6), Dex 9 (save -1), Con 21 (save +8), Int 9 (save -1), Wis 10 (save +3), Cha 12 (save +4).\nCR 8 (XP 3900, PB +3).\nSkills Athletics +9, Perception +3\nImmunities Cold\nSenses Passive Perception 13\nLanguages Giant\n### Actions\n- Multiattack. The giant makes two attacks, using Frost Axe or Great Bow in any combination.\n- Frost Axe. Melee Attack Roll: +9, reach 10 ft. Hit: 19 (2d12 + 6) Slashing damage plus 9 (2d8) Cold damage.\n- Great Bow. Ranged Attack Roll: +9, range 150/600 ft. Hit: 17 (2d10 + 6) Piercing damage plus 7 (2d6) Cold damage, and the target's Speed decreases by 10 feet until the end of its next turn.\n### Bonus Actions\n- War Cry (Recharge 5–6). The giant or one creature of its choice that can see or hear it gains 16 (2d10 + 5) Temporary Hit Points and has Advantage on attack rolls until the start of the giant's next turn.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Frost Giant","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Shrieker Fungus","constant":false,"content":"## Shrieker Fungus (monster stat block, SRD 5.2.1)\nMedium Plant, Unaligned. AC 5, HP 13 (3d8), Initiative -5, Speed 5 ft..\nAbilities: Str 1 (save -5), Dex 1 (save -5), Con 10 (save +0), Int 1 (save -5), Wis 3 (save -4), Cha 1 (save -5).\nCR 0 (XP 0, PB +2).\nImmunities Blinded, Charmed, Deafened, Frightened\nSenses Blindsight 30 ft.; Passive Perception 6\nLanguages None\n### Reactions\n- Shriek. Trigger: A creature or a source of Bright Light moves within 30 feet of the shrieker. Response: The shrieker emits a shriek audible within 300 feet of itself for 1 minute or until the shrieker dies.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Shrieker Fungus","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Violet Fungus","constant":false,"content":"## Violet Fungus (monster stat block, SRD 5.2.1)\nMedium Plant, Unaligned. AC 5, HP 18 (4d8), Initiative -5, Speed 5 ft..\nAbilities: Str 3 (save -4), Dex 1 (save -5), Con 10 (save +0), Int 1 (save -5), Wis 3 (save -4), Cha 1 (save -5).\nCR 1/4 (XP 50, PB +2).\nImmunities Blinded, Charmed, Deafened, Frightened\nSenses Blindsight 30 ft.; Passive Perception 6\nLanguages None\n### Actions\n- Multiattack. The fungus makes two Rotting Touch attacks.\n- Rotting Touch. Melee Attack Roll: +2, reach 10 ft. Hit: 4 (1d8) Necrotic damage.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Violet Fungus","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Gargoyle","constant":false,"content":"## Gargoyle (monster stat block, SRD 5.2.1)\nMedium Elemental, Chaotic Evil. AC 15, HP 67 (9d8+27), Initiative +2, Speed 30 ft., Fly 60 ft..\nAbilities: Str 15 (save +2), Dex 11 (save +0), Con 16 (save +3), Int 6 (save -2), Wis 11 (save +0), Cha 7 (save -2).\nCR 2 (XP 450, PB +2).\nSkills Stealth +4\nImmunities Poison; Exhaustion, Petrified, Poisoned\nSenses Darkvision 60 ft.; Passive Perception 10\nLanguages Primordial (Terran)\n### Traits\n- Flyby. The gargoyle doesn't provoke an Opportunity Attack when it flies out of an enemy's reach.\n### Actions\n- Multiattack. The gargoyle makes two Claw attacks.\n- Claw. Melee Attack Roll: +4, reach 5 ft. Hit: 7 (2d4 + 2) Slashing damage.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Gargoyle","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Gelatinous Cube","constant":false,"content":"## Gelatinous Cube (monster stat block, SRD 5.2.1)\nLarge Ooze, Unaligned. AC 6, HP 63 (6d10+30), Initiative -4, Speed 15 ft..\nAbilities: Str 14 (save +2), Dex 3 (save -4), Con 20 (save +5), Int 1 (save -5), Wis 6 (save -2), Cha 1 (save -5).\nCR 2 (XP 450, PB +2).\nImmunities Acid; Blinded, Charmed, Deafened, Exhaustion, Frightened, Prone\nSenses Blindsight 60 ft.; Passive Perception 8\nLanguages None\n### Traits\n- Ooze Cube. The cube fills its entire space and is transparent. Other creatures can enter that space, but a creature that does so is subjected to the cube's Engulf and has Disadvantage on the saving throw. Creatures inside the cube have Total Cover, and the cube can hold one Large creature or up to four Medium or Small creatures inside itself at a time. As an action, a creature within 5 feet of the cube can pull a creature or an object out of the cube by succeeding on a DC 12 Strength (Athletics) check, and the puller takes 10 (3d6) Acid damage.\n- Transparent. Even when the cube is in plain sight, a creature must succeed on a DC 15 Wisdom (Perception) check to notice the cube if the creature hasn't witnessed the cube move or otherwise act.\n### Actions\n- Pseudopod. Melee Attack Roll: +4, reach 5 ft. Hit: 12 (3d6 + 2) Acid damage.\n- Engulf. The cube moves up to its Speed without provoking Opportunity Attacks. The cube can move through the spaces of Large or smaller creatures if it has room inside itself to contain them (see the Ooze Cube trait). Dexterity Saving Throw: DC 12, each creature whose space the cube enters for the first time during this move. Failure: 10 (3d6) Acid damage, and the target is engulfed. An engulfed target is suffocating, can't cast spells with a Verbal component, has the Restrained condition, and takes 10 (3d6) Acid damage at the start of each of the cube's turns. When the cube moves, the engulfed target moves with it. An engulfed target can try to escape by taking an action to make a DC 12 Strength (Athletics) check. On a successful check, the target escapes and enters the nearest unoccupied space. Success: Half damage, and the target moves to an unoccupied space within 5 feet of the cube. If there is no unoccupied space, the target fails the save instead.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Gelatinous Cube","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Ghast","constant":false,"content":"## Ghast (monster stat block, SRD 5.2.1)\nMedium Undead, Chaotic Evil. AC 13, HP 36 (8d8), Initiative +3, Speed 30 ft..\nAbilities: Str 16 (save +3), Dex 17 (save +3), Con 10 (save +0), Int 11 (save +0), Wis 10 (save +2), Cha 8 (save -1).\nCR 2 (XP 450, PB +2).\nResistances Necrotic\nImmunities Poison; Charmed, Exhaustion, Poisoned\nSenses Darkvision 60 ft.; Passive Perception 10\nLanguages Common\n### Traits\n- Stench. Constitution Saving Throw: DC 10, any creature that starts its turn in a 5-foot Emanation originating from the ghast. Failure: The target has the Poisoned condition until the start of its next turn. Success: The target is immune to this ghast's Stench for 24 hours.\n### Actions\n- Bite. Melee Attack Roll: +5, reach 5 ft. Hit: 7 (1d8 + 3) Piercing damage plus 9 (2d8) Necrotic damage.\n- Claw. Melee Attack Roll: +5, reach 5 ft. Hit: 10 (2d6 + 3) Slashing damage. If the target is a non-Undead creature, it is subjected to the following effect. Constitution Saving Throw: DC 10. Failure: The target has the Paralyzed condition until the end of its next turn.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Ghast","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Ghost","constant":false,"content":"## Ghost (monster stat block, SRD 5.2.1)\nMedium Undead, Neutral. AC 11, HP 45 (10d8), Initiative +1, Speed 5 ft., Fly 40 ft. (hover).\nAbilities: Str 7 (save -2), Dex 13 (save +1), Con 10 (save +0), Int 10 (save +0), Wis 12 (save +1), Cha 17 (save +3).\nCR 4 (XP 1100, PB +2).\nResistances Acid, Bludgeoning, Cold, Fire, Lightning, Piercing, Slashing, Thunder\nImmunities Necrotic, Poison; Charmed, Exhaustion, Frightened, Grappled, Paralyzed, Petrified, Poisoned, Prone, Restrained\nSenses Darkvision 60 ft.; Passive Perception 11\nLanguages Common plus one other language\n### Traits\n- Ethereal Sight. The ghost can see 60 feet into the Ethereal Plane when it is on the Material Plane.\n- Incorporeal Movement. The ghost can move through other creatures and objects as if they were Difficult Terrain. It takes 5 (1d10) Force damage if it ends its turn inside an object.\n### Actions\n- Multiattack. The ghost makes two Withering Touch attacks.\n- Withering Touch. Melee Attack Roll: +5, reach 5 ft. Hit: 19 (3d10 + 3) Necrotic damage.\n- Etherealness. The ghost casts the Etherealness spell, requiring no spell components and using Charisma as the spellcasting ability. The ghost is visible on the Material Plane while on the Border Ethereal and vice versa, but it can't affect or be affected by anything on the other plane.\n- Horrific Visage. Wisdom Saving Throw: DC 13, each creature in a 60-foot Cone that can see the ghost and isn't an Undead. Failure: 10 (2d6 + 3) Psychic damage, and the target has the Frightened condition until the start of the ghost's next turn. Success: The target is immune to this ghost's Horrific Visage for 24 hours.\n- Possession (Recharge 6). Charisma Saving Throw: DC 13, one Humanoid the ghost can see within 5 feet. Failure: The target is possessed by the ghost; the ghost disappears, and the target has the Incapacitated condition and loses control of its body. The ghost now controls the body, but the target retains awareness. The ghost can't be targeted by any attack, spell, or other effect, except ones that specifically target Undead. The ghost's game statistics are the same, except it uses the possessed target's Speed, as well as the target's Strength, Dexterity, and Constitution modifiers. The possession lasts until the body drops to 0 Hit Points or the ghost leaves as a Bonus Action. When the possession ends, the ghost appears in an unoccupied space within 5 feet of the target, and the target is immune to this ghost's Possession for 24 hours. Success: The target is immune to this ghost's Possession for 24 hours.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Ghost","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Ghoul","constant":false,"content":"## Ghoul (monster stat block, SRD 5.2.1)\nMedium Undead, Chaotic Evil. AC 12, HP 22 (5d8), Initiative +2, Speed 30 ft..\nAbilities: Str 13 (save +1), Dex 15 (save +2), Con 10 (save +0), Int 7 (save -2), Wis 10 (save +0), Cha 6 (save -2).\nCR 1 (XP 200, PB +2).\nImmunities Poison; Charmed, Exhaustion, Poisoned\nSenses Darkvision 60 ft.; Passive Perception 10\nLanguages Common\n### Actions\n- Multiattack. The ghoul makes two Bite attacks.\n- Bite. Melee Attack Roll: +4, reach 5 ft. Hit: 5 (1d6 + 2) Piercing damage plus 3 (1d6) Necrotic damage.\n- Claw. Melee Attack Roll: +4, reach 5 ft. Hit: 4 (1d4 + 2) Slashing damage. If the target is a creature that isn't an Undead or elf, it is subjected to the following effect. Constitution Saving Throw: DC 10. Failure: The target has the Paralyzed condition until the end of its next turn.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Ghoul","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Gibbering Mouther","constant":false,"content":"## Gibbering Mouther (monster stat block, SRD 5.2.1)\nMedium Aberration, Chaotic Neutral. AC 9, HP 52 (7d8+21), Initiative -1, Speed 20 ft., Swim 20 ft..\nAbilities: Str 10 (save +0), Dex 8 (save -1), Con 16 (save +3), Int 3 (save -4), Wis 10 (save +0), Cha 6 (save -2).\nCR 2 (XP 450, PB +2).\nImmunities Prone\nSenses Darkvision 60 ft.; Passive Perception 10\nLanguages None\n### Traits\n- Aberrant Ground. The ground in a 10-foot Emanation originating from the mouther is Difficult Terrain.\n- Gibbering. The mouther babbles incoherently while it doesn't have the Incapacitated condition. Wisdom Saving Throw: DC 10, any creature that starts its turn within 20 feet of the mouther while it is babbling. Failure: The target rolls 1d8 to determine what it does during the current turn: 1–4. The target does nothing. 5–6. The target takes no action or Bonus Action and uses all its movement to move in a random direction. 7–8. The target makes a melee attack against a randomly determined creature within its reach or does nothing if it can't make such an attack.\n### Actions\n- Bite. Melee Attack Roll: +2, reach 5 ft. Hit: 7 (2d6) Piercing damage. If the target is a Medium or smaller creature, it has the Prone condition. The target dies if it is reduced to 0 Hit Points by this attack. Its body is then absorbed into the mouther, leaving only equipment behind.\n- Blinding Spittle (Recharge 5–6). Dexterity Saving Throw: DC 10, each creature in a 10-foot-radius Sphere centered on a point within 30 feet. Failure: 7 (2d6) Radiant damage, and the target has the Blinded condition until the end of the mouther's next turn.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Gibbering Mouther","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Glabrezu","constant":false,"content":"## Glabrezu (monster stat block, SRD 5.2.1)\nLarge Fiend (Demon), Chaotic Evil. AC 17, HP 189 (18d10+90), Initiative +6, Speed 40 ft..\nAbilities: Str 20 (save +9), Dex 15 (save +2), Con 21 (save +9), Int 19 (save +4), Wis 17 (save +7), Cha 16 (save +7).\nCR 9 (XP 5000, PB +4).\nSkills Deception +7, Perception +7\nResistances Cold, Fire, Lightning\nImmunities Poison; Poisoned\nSenses Truesight 120 ft.; Passive Perception 17\nLanguages Abyssal; telepathy 120 ft.\n### Traits\n- Demonic Restoration. If the glabrezu dies outside the Abyss, its body dissolves into ichor, and it gains a new body instantly, reviving with all its Hit Points somewhere in the Abyss.\n- Magic Resistance. The glabrezu has Advantage on saving throws against spells and other magical effects.\n### Actions\n- Multiattack. The glabrezu makes two Pincer attacks and uses Pummel or Spellcasting.\n- Pincer. Melee Attack Roll: +9, reach 10 ft. Hit: 16 (2d10 + 5) Slashing damage. If the target is a Medium or smaller creature, it has the Grappled condition (escape DC 15) from one of two pincers.\n- Pummel. Dexterity Saving Throw: DC 17, one creature Grappled by the glabrezu. Failure: 15 (3d6 + 5) Bludgeoning damage. Success: Half damage.\n- Spellcasting. The glabrezu casts one of the following spells, requiring no Material components and using Intelligence as the spellcasting ability (spell save DC 16): At Will: Darkness, Detect Magic, Dispel Magic 1/Day Each: Confusion, Fly, Power Word Stun","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Glabrezu","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Gladiator","constant":false,"content":"## Gladiator (monster stat block, SRD 5.2.1)\nMedium or Small Humanoid, Neutral. AC 16, HP 112 (15d8+45), Initiative +5, Speed 30 ft..\nAbilities: Str 18 (save +7), Dex 15 (save +5), Con 16 (save +6), Int 10 (save +0), Wis 12 (save +4), Cha 15 (save +2).\nCR 5 (XP 1800, PB +3).\nSkills Athletics +10, Performance +5\nGear Shield, Spears (3), Studded Leather Armor\nSenses Passive Perception 11\nLanguages Common\n### Actions\n- Multiattack. The gladiator makes three Spear attacks. It can replace one attack with a use of Shield Bash.\n- Spear. Melee or Ranged Attack Roll: +7, reach 5 ft. or range 20/60 ft. Hit: 11 (2d6 + 4) Piercing damage.\n- Shield Bash. Strength Saving Throw: DC 15, one creature within 5 feet that the gladiator can see. Failure: 9 (2d4 + 4) Bludgeoning damage. If the target is a Medium or smaller creature, it has the Prone condition.\n### Reactions\n- Parry. Trigger: The gladiator is hit by a melee attack roll while holding a weapon. Response: The gladiator adds 3 to its AC against that attack, possibly causing it to miss.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Gladiator","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Gnoll Warrior","constant":false,"content":"## Gnoll Warrior (monster stat block, SRD 5.2.1)\nMedium Fiend, Chaotic Evil. AC 15, HP 27 (6d8), Initiative +1, Speed 30 ft..\nAbilities: Str 14 (save +2), Dex 12 (save +1), Con 11 (save +0), Int 6 (save -2), Wis 10 (save +0), Cha 7 (save -2).\nCR 1/2 (XP 100, PB +2).\nSenses Darkvision 60 ft.; Passive Perception 10\nLanguages Gnoll\n### Actions\n- Rend. Melee Attack Roll: +4, reach 5 ft. Hit: 5 (1d6 + 2) Piercing damage.\n- Bone Bow. Ranged Attack Roll: +3, range 150/600 ft. Hit: 6 (1d10 + 1) Piercing damage.\n### Bonus Actions\n- Rampage (1/Day). Immediately after dealing damage to a creature that is already Bloodied, the gnoll moves up to half its Speed, and it makes one Rend attack.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Gnoll Warrior","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Goblin Minion","constant":false,"content":"## Goblin Minion (monster stat block, SRD 5.2.1)\nSmall Fey (Goblinoid), Chaotic Neutral. AC 12, HP 7 (2d6), Initiative +2, Speed 30 ft..\nAbilities: Str 8 (save -1), Dex 15 (save +2), Con 10 (save +0), Int 10 (save +0), Wis 8 (save -1), Cha 8 (save -1).\nCR 1/8 (XP 25, PB +2).\nSkills Stealth +6\nGear Daggers (3)\nSenses Darkvision 60 ft.; Passive Perception 9\nLanguages Common, Goblin\n### Actions\n- Dagger. Melee or Ranged Attack Roll: +4, reach 5 ft. or range 20/60 ft. Hit: 4 (1d4 + 2) Piercing damage.\n### Bonus Actions\n- Nimble Escape. The goblin takes the Disengage or Hide action.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Goblin Minion","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Goblin Warrior","constant":false,"content":"## Goblin Warrior (monster stat block, SRD 5.2.1)\nSmall Fey (Goblinoid), Chaotic Neutral. AC 15, HP 10 (3d6), Initiative +2, Speed 30 ft..\nAbilities: Str 8 (save -1), Dex 15 (save +2), Con 10 (save +0), Int 10 (save +0), Wis 8 (save -1), Cha 8 (save -1).\nCR 1/4 (XP 50, PB +2).\nSkills Stealth +6\nGear Leather Armor, Scimitar, Shield, Shortbow\nSenses Darkvision 60 ft.; Passive Perception 9\nLanguages Common, Goblin\n### Actions\n- Scimitar. Melee Attack Roll: +4, reach 5 ft. Hit: 5 (1d6 + 2) Slashing damage, plus 2 (1d4) Slashing damage if the attack roll had Advantage.\n- Shortbow. Ranged Attack Roll: +4, range 80/320 ft. Hit: 5 (1d6 + 2) Piercing damage, plus 2 (1d4) Piercing damage if the attack roll had Advantage.\n### Bonus Actions\n- Nimble Escape. The goblin takes the Disengage or Hide action.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Goblin Warrior","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Goblin Boss","constant":false,"content":"## Goblin Boss (monster stat block, SRD 5.2.1)\nSmall Fey (Goblinoid), Chaotic Neutral. AC 17, HP 21 (6d6), Initiative +2, Speed 30 ft..\nAbilities: Str 10 (save +0), Dex 15 (save +2), Con 10 (save +0), Int 10 (save +0), Wis 8 (save -1), Cha 10 (save +0).\nCR 1 (XP 200, PB +2).\nSkills Stealth +6\nGear Chain Shirt, Scimitar, Shield, Shortbow\nSenses Darkvision 60 ft.; Passive Perception 9\nLanguages Common, Goblin\n### Actions\n- Multiattack. The goblin makes two attacks, using Scimitar or Shortbow in any combination.\n- Scimitar. Melee Attack Roll: +4, reach 5 ft. Hit: 5 (1d6 + 2) Slashing damage, plus 2 (1d4) Slashing damage if the attack roll had Advantage.\n- Shortbow. Ranged Attack Roll: +4, range 80/320 ft. Hit: 5 (1d6 + 2) Piercing damage, plus 2 (1d4) Piercing damage if the attack roll had Advantage.\n### Bonus Actions\n- Nimble Escape. The goblin takes the Disengage or Hide action.\n### Reactions\n- Redirect Attack. Trigger: A creature the goblin can see makes an attack roll against it. Response: The goblin chooses a Small or Medium ally within 5 feet of itself. The goblin and that ally swap places, and the ally becomes the target of the attack instead.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Goblin Boss","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Gold Dragon Wyrmling","constant":false,"content":"## Gold Dragon Wyrmling (monster stat block, SRD 5.2.1)\nMedium Dragon (Metallic), Lawful Good. AC 17, HP 60 (8d8+24), Initiative +4, Speed 30 ft., Fly 60 ft., Swim 30 ft..\nAbilities: Str 19 (save +4), Dex 14 (save +4), Con 17 (save +3), Int 14 (save +2), Wis 11 (save +2), Cha 16 (save +3).\nCR 3 (XP 700, PB +2).\nSkills Perception +4, Stealth +4\nImmunities Fire\nSenses Blindsight 10 ft., Darkvision 60 ft.; Passive Perception 14\nLanguages Draconic\n### Traits\n- Amphibious. The dragon can breathe air and water.\n### Actions\n- Multiattack. The dragon makes two Rend attacks.\n- Rend. Melee Attack Roll: +6, reach 5 ft. Hit: 9 (1d10 + 4) Slashing damage.\n- Fire Breath (Recharge 5–6). Dexterity Saving Throw: DC 13, each creature in a 15-foot Cone. Failure: 22 (4d10) Fire damage. Success: Half damage.\n- Weakening Breath. Strength Saving Throw: DC 13, each creature that isn't currently affected by this breath in a 15-foot Cone. Failure: The target has Disadvantage on Strength-based D20 Tests and subtracts 2 (1d4) from its damage rolls. It repeats the save at the end of each of its turns, ending the effect on itself on a success. After 1 minute, it succeeds automatically.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Gold Dragon Wyrmling","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Young Gold Dragon","constant":false,"content":"## Young Gold Dragon (monster stat block, SRD 5.2.1)\nLarge Dragon (Metallic), Lawful Good. AC 18, HP 178 (17d10+85), Initiative +6, Speed 40 ft., Fly 80 ft., Swim 40 ft..\nAbilities: Str 23 (save +6), Dex 14 (save +6), Con 21 (save +5), Int 16 (save +3), Wis 13 (save +5), Cha 20 (save +5).\nCR 10 (XP 5900, PB +4).\nSkills Insight +5, Perception +9, Persuasion +9, Stealth +6\nImmunities Fire\nSenses Blindsight 30 ft., Darkvision 120 ft.; Passive Perception 19\nLanguages Common, Draconic\n### Traits\n- Amphibious. The dragon can breathe air and water.\n### Actions\n- Multiattack. The dragon makes three Rend attacks. It can replace one attack with a use of Weakening Breath.\n- Rend. Melee Attack Roll: +10, reach 10 ft. Hit: 17 (2d10 + 6) Slashing damage.\n- Fire Breath (Recharge 5–6). Dexterity Saving Throw: DC 17, each creature in a 30-foot Cone. Failure: 55 (10d10) Fire damage. Success: Half damage.\n- Weakening Breath. Strength Saving Throw: DC 17, each creature that isn't currently affected by this breath in a 30-foot Cone. Failure: The target has Disadvantage on Strength-based D20 Tests and subtracts 3 (1d6) from its damage rolls. It repeats the save at the end of each of its turns, ending the effect on itself on a success. After 1 minute, it succeeds automatically.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Young Gold Dragon","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Adult Gold Dragon","constant":false,"content":"## Adult Gold Dragon (monster stat block, SRD 5.2.1)\nHuge Dragon (Metallic), Lawful Good. AC 19, HP 243 (18d12+126), Initiative +14, Speed 40 ft., Fly 80 ft., Swim 40 ft..\nAbilities: Str 27 (save +8), Dex 14 (save +8), Con 25 (save +7), Int 16 (save +3), Wis 15 (save +8), Cha 24 (save +7).\nCR 17 (XP 18000, PB +6).\nSkills Insight +8, Perception +14, Persuasion +13, Stealth +8\nImmunities Fire\nSenses Blindsight 60 ft., Darkvision 120 ft.; Passive Perception 24\nLanguages Common, Draconic\n### Traits\n- Amphibious. The dragon can breathe air and water.\n- Legendary Resistance (3/Day, or 4/Day in Lair). If the dragon fails a saving throw, it can choose to succeed instead.\n### Actions\n- Multiattack. The dragon makes three Rend attacks. It can replace one attack with a use of (A) Spellcasting to cast Guiding Bolt (level 2 version) or (B) Weakening Breath.\n- Rend. Melee Attack Roll: +14, reach 10 ft. Hit: 17 (2d8 + 8) Slashing damage plus 4 (1d8) Fire damage.\n- Fire Breath (Recharge 5–6). Dexterity Saving Throw: DC 21, each creature in a 60-foot Cone. Failure: 66 (12d10) Fire damage. Success: Half damage.\n- Spellcasting. The dragon casts one of the following spells, requiring no Material components and using Charisma as the spellcasting ability (spell save DC 21, +13 to hit with spell attacks): At Will: Detect Magic, Guiding Bolt (level 2 version), Shapechange (Beast or Humanoid form only, no Temporary Hit Points gained from the spell, and no Concentration or Temporary Hit Points required to maintain the spell) 1/Day Each: Flame Strike, Zone of Truth\n- Weakening Breath. Strength Saving Throw: DC 21, each creature that isn't currently affected by this breath in a 60-foot Cone. Failure: The target has Disadvantage on Strength-based D20 Tests and subtracts 3 (1d6) from its damage rolls. It repeats the save at the end of each of its turns, ending the effect on itself on a success. After 1 minute, it succeeds automatically.\n### Legendary Actions\n- Legendary Action Uses: 3 (4 in Lair). Immediately after another creature's turn, the dragon can expend a use to take one of the following actions. The dragon regains all expended uses at the start of each of its turns.\n- Banish. Charisma Saving Throw: DC 21, one creature the dragon can see within 120 feet. Failure: 10 (3d6) Force damage, and the target has the Incapacitated condition and is transported to a harmless demiplane until the start of the dragon's next turn, at which point it re­ appears in an unoccupied space of the dragon's choice within 120 feet of the dragon. Failure or Success: The dragon can't take this action again until the start of its next turn.\n- Guiding Light. The dragon uses Spellcasting to cast Guiding Bolt (level 2 version).\n- Pounce. The dragon moves up to half its Speed, and it makes one Rend attack.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Adult Gold Dragon","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Ancient Gold Dragon","constant":false,"content":"## Ancient Gold Dragon (monster stat block, SRD 5.2.1)\nGargantuan Dragon (Metallic), Lawful Good. AC 22, HP 546 (28d20+252), Initiative +16, Speed 40 ft., Fly 80 ft., Swim 40 ft..\nAbilities: Str 30 (save +10), Dex 14 (save +9), Con 29 (save +9), Int 18 (save +4), Wis 17 (save +10), Cha 28 (save +9).\nCR 24 (XP 62000, PB +7).\nSkills Insight +10, Perception +17, Persuasion +16, Stealth +9\nImmunities Fire\nSenses Blindsight 60 ft., Darkvision 120 ft.; Passive Perception 27\nLanguages Common, Draconic\n### Traits\n- Amphibious. The dragon can breathe air and water.\n- Legendary Resistance (4/Day, or 5/Day in Lair). If the dragon fails a saving throw, it can choose to succeed instead.\n### Actions\n- Multiattack. The dragon makes three Rend attacks. It can replace one attack with a use of (A) Spellcasting to cast Guiding Bolt (level 4 version) or (B) Weakening Breath.\n- Rend. Melee Attack Roll: +17 to hit, reach 15 ft. Hit: 19 (2d8 + 10) Slashing damage plus 9 (2d8) Fire damage.\n- Fire Breath (Recharge 5–6). Dexterity Saving Throw: DC 24, each creature in a 90-foot Cone. Failure: 71 (13d10) Fire damage. Success: Half damage.\n- Spellcasting. The dragon casts one of the following spells, requiring no Material components and using Charisma as the spellcasting ability (spell save DC 24, +16 to hit with spell attacks): At Will: Detect Magic, Guiding Bolt (level 4 version), Shapechange (Beast or Humanoid form only, no Temporary Hit Points gained from the spell, and no Concentration or Temporary Hit Points required to maintain the spell) 1/Day Each: Flame Strike (level 6 version), Word of Recall, Zone of Truth\n- Weakening Breath. Strength Saving Throw: DC 24, each creature that isn't currently affected by this breath in a 90-foot Cone. Failure: The target has Disadvantage on Strength-based D20 Tests and subtracts 5 (1d10) from its damage rolls. It repeats the save at the end of each of its turns, ending the effect on itself on a success. After 1 minute, it succeeds automatically.\n### Legendary Actions\n- Legendary Action Uses: 3 (4 in Lair). Immediately after another creature's turn, the dragon can expend a use to take one of the following actions. The dragon regains all expended uses at the start of each of its turns.\n- Banish. Charisma Saving Throw: DC 24, one creature the dragon can see within 120 feet. Failure: 24 (7d6) Force damage, and the target has the Incapacitated condition and is transported to a harmless demiplane until the start of the dragon's next turn, at which point it reappears in an unoccupied space of the dragon's choice within 120 feet of the dragon. Failure or Success: The dragon can't take this action again until the start of its next turn.\n- Guiding Light. The dragon uses Spellcasting to cast Guiding Bolt (level 4 version).\n- Pounce. The dragon moves up to half its Speed, and it makes one Rend attack.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Ancient Gold Dragon","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Gorgon","constant":false,"content":"## Gorgon (monster stat block, SRD 5.2.1)\nLarge Construct, Unaligned. AC 19, HP 114 (12d10+48), Initiative +0, Speed 40 ft..\nAbilities: Str 20 (save +5), Dex 11 (save +0), Con 18 (save +4), Int 2 (save -4), Wis 12 (save +1), Cha 7 (save -2).\nCR 5 (XP 1800, PB +3).\nSkills Perception +7\nImmunities Exhaustion, Petrified\nSenses Darkvision 60 ft.; Passive Perception 17\nLanguages None\n### Actions\n- Gore. Melee Attack Roll: +8, reach 5 ft. Hit: 18 (2d12 + 5) Piercing damage. If the target is a Large or smaller creature and the gorgon moved 20+ feet straight toward it immediately before the hit, the target has the Prone condition.\n- Petrifying Breath (Recharge 5–6). Constitution Saving Throw: DC 15, each creature in a 30-foot Cone. First Failure: The target has the Restrained condition and repeats the save at the end of its next turn if it is still Restrained, ending the effect on itself on a success. Second Failure: The target has the Petrified condition instead of the Restrained condition.\n### Bonus Actions\n- Trample. Dexterity Saving Throw: DC 16, one creature within 5 feet that has the Prone condition. Failure: 16 (2d10 + 5) Bludgeoning damage. Success: Half damage.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Gorgon","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Gray Ooze","constant":false,"content":"## Gray Ooze (monster stat block, SRD 5.2.1)\nMedium Ooze, Unaligned. AC 9, HP 22 (3d8+9), Initiative -2, Speed 10 ft., Climb 10 ft..\nAbilities: Str 12 (save +1), Dex 6 (save -2), Con 16 (save +3), Int 1 (save -5), Wis 6 (save -2), Cha 2 (save -4).\nCR 1/2 (XP 100, PB +2).\nSkills Stealth +2\nResistances Acid, Cold, Fire\nImmunities Blinded, Charmed, Deafened, Exhaustion, Frightened, Grappled, Prone, Restrained\nSenses Blindsight 60 ft.; Passive Perception 8\nLanguages None\n### Traits\n- Amorphous. The ooze can move through a space as narrow as 1 inch without expending extra movement to do so.\n- Corrosive Form. Nonmagical ammunition is destroyed immediately after hitting the ooze and dealing any damage. Any nonmagical weapon takes a cumulative -1 penalty to attack rolls immediately after dealing damage to the ooze and coming into contact with it.\n- The weapon is destroyed if the penalty reaches -5. The penalty can be removed by casting the Mending spell on the weapon. The ooze can eat through 2-inch-thick, nonmagical metal or wood in 1 round.\n### Actions\n- Pseudopod. Melee Attack Roll: +3, reach 5 ft. Hit: 10 (2d8 + 1) Acid damage. Nonmagical armor worn by the target takes a -1 penalty to the AC it offers. The armor is destroyed if the penalty reduces its AC to 10. The penalty can be removed by casting the Mending spell on the armor.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Gray Ooze","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Green Dragon Wyrmling","constant":false,"content":"## Green Dragon Wyrmling (monster stat block, SRD 5.2.1)\nMedium Dragon (Chromatic), Lawful Evil. AC 17, HP 38 (7d8+7), Initiative +3, Speed 30 ft., Fly 60 ft., Swim 30 ft..\nAbilities: Str 15 (save +2), Dex 12 (save +3), Con 13 (save +1), Int 14 (save +2), Wis 11 (save +2), Cha 13 (save +1).\nCR 2 (XP 450, PB +2).\nSkills Perception +4, Stealth +3\nImmunities Poison; Poisoned\nSenses Blindsight 10 ft., Darkvision 60 ft.; Passive Perception 14\nLanguages Draconic\n### Traits\n- Amphibious. The dragon can breathe air and water.\n### Actions\n- Multiattack. The dragon makes two Rend attacks.\n- Rend. Melee Attack Roll: +4, reach 5 ft. Hit: 7 (1d10 + 2) Slashing damage plus 3 (1d6) Poison damage.\n- Poison Breath (Recharge 5–6). Constitution Saving Throw: DC 11, each creature in a 15-foot Cone. Failure: 21 (6d6) Poison damage. Success: Half damage.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Green Dragon Wyrmling","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Young Green Dragon","constant":false,"content":"## Young Green Dragon (monster stat block, SRD 5.2.1)\nLarge Dragon (Chromatic), Lawful Evil. AC 18, HP 136 (16d10+48), Initiative +4, Speed 40 ft., Fly 80 ft., Swim 40 ft..\nAbilities: Str 19 (save +4), Dex 12 (save +4), Con 17 (save +3), Int 16 (save +3), Wis 13 (save +4), Cha 15 (save +2).\nCR 8 (XP 3900, PB +3).\nSkills Deception +5, Perception +7, Stealth +4\nImmunities Poison; Poisoned\nSenses Blindsight 30 ft., Darkvision 120 ft.; Passive Perception 17\nLanguages Common, Draconic\n### Traits\n- Amphibious. The dragon can breathe air and water.\n### Actions\n- Multiattack. The dragon makes three Rend attacks.\n- Rend. Melee Attack Roll: +7, reach 10 ft. Hit: 11 (2d6 + 4) Slashing damage plus 7 (2d6) Poison damage.\n- Poison Breath (Recharge 5–6). Constitution Saving Throw: DC 14, each creature in a 30-foot Cone. Failure: 42 (12d6) Poison damage. Success: Half damage.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Young Green Dragon","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Adult Green Dragon","constant":false,"content":"## Adult Green Dragon (monster stat block, SRD 5.2.1)\nHuge Dragon (Chromatic), Lawful Evil. AC 19, HP 207 (18d12+90), Initiative +11, Speed 40 ft., Fly 80 ft., Swim 40 ft..\nAbilities: Str 23 (save +6), Dex 12 (save +6), Con 21 (save +5), Int 18 (save +4), Wis 15 (save +7), Cha 18 (save +4).\nCR 15 (XP 13000, PB +5).\nSkills Deception +9, Perception +12, Persuasion +9, Stealth +6\nImmunities Poison; Poisoned\nSenses Blindsight 60 ft., Darkvision 120 ft.; Passive Perception 22\nLanguages Common, Draconic\n### Traits\n- Amphibious. The dragon can breathe air and water.\n- Legendary Resistance (3/Day, or 4/Day in Lair). If the dragon fails a saving throw, it can choose to succeed instead.\n### Actions\n- Multiattack. The dragon makes three Rend attacks. It can replace one attack with a use of Spellcasting to cast Mind Spike (level 3 version).\n- Rend. Melee Attack Roll: +11, reach 10 ft. Hit: 15 (2d8 + 6) Slashing damage plus 7 (2d6) Poison damage.\n- Poison Breath (Recharge 5–6). Constitution Saving Throw: DC 18, each creature in a 60-foot Cone. Failure: 56 (16d6) Poison damage. Success: Half damage.\n- Spellcasting. The dragon casts one of the following spells, requiring no Material components and using Charisma as the spellcasting ability (spell save DC 17): At Will: Detect Magic, Mind Spike (level 3 version) 1/Day: Geas\n### Legendary Actions\n- Legendary Action Uses: 3 (4 in Lair). Immediately after another creature's turn, the dragon can expend a use to take one of the following actions. The dragon regains all expended uses at the start of each of its turns.\n- Mind Invasion. The dragon uses Spellcasting to cast Mind Spike (level 3 version).\n- Noxious Miasma. Constitution Saving Throw: DC 17, each creature in a 20-foot-radius Sphere centered on a point the dragon can see within 90 feet. Failure: 7 (2d6) Poison damage, and the target takes a -2 penalty to AC until the end of its next turn. Failure or Success: The dragon can't take this action again until the start of its next turn.\n- Pounce. The dragon moves up to half its Speed, and it makes one Rend attack.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Adult Green Dragon","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Ancient Green Dragon","constant":false,"content":"## Ancient Green Dragon (monster stat block, SRD 5.2.1)\nGargantuan Dragon (Chromatic), Lawful Evil. AC 21, HP 402 (23d20+161), Initiative +15, Speed 40 ft., Fly 80 ft., Swim 40 ft..\nAbilities: Str 27 (save +8), Dex 12 (save +8), Con 25 (save +7), Int 20 (save +5), Wis 17 (save +10), Cha 22 (save +6).\nCR 22 (XP 41000, PB +7).\nSkills Deception +13, Perception +17, Persuasion +13, Stealth +8\nImmunities Poison; Poisoned\nSenses Blindsight 60 ft., Darkvision 120 ft.; Passive Perception 27\nLanguages Common, Draconic\n### Traits\n- Amphibious. The dragon can breathe air and water.\n- Legendary Resistance (4/Day, or 5/Day in Lair). If the dragon fails a saving throw, it can choose to succeed instead.\n### Actions\n- Multiattack. The dragon makes three Rend attacks. It can replace one attack with a use of Spellcasting to cast Mind Spike (level 5 version).\n- Rend. Melee Attack Roll: +15, reach 15 ft. Hit: 17 (2d8 + 8) Slashing damage plus 10 (3d6) Poison damage.\n- Poison Breath (Recharge 5–6). Constitution Saving Throw: DC 22, each creature in a 90-foot Cone. Failure: 77 (22d6) Poison damage. Success: Half damage.\n- Spellcasting. The dragon casts one of the following spells, requiring no Material components and using Charisma as the spellcasting ability (spell save DC 21): At Will: Detect Magic, Mind Spike (level 5 version) 1/Day Each: Geas, Modify Memory\n### Legendary Actions\n- Legendary Action Uses: 3 (4 in Lair). Immediately after another creature's turn, the dragon can expend a use to take one of the following actions. The dragon regains all expended uses at the start of each of its turns.\n- Mind Invasion. The dragon uses Spellcasting to cast Mind Spike (level 5 version).\n- Noxious Miasma. Constitution Saving Throw: DC 21, each creature in a 30-foot-radius Sphere centered on a point the dragon can see within 90 feet. Failure: 17 (5d6) Poison damage, and the target takes a -2 penalty to AC until the end of its next turn. Failure or Success: The dragon can't take this action again until the start of its next turn.\n- Pounce. The dragon moves up to half its Speed, and it makes one Rend attack.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Ancient Green Dragon","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Green Hag","constant":false,"content":"## Green Hag (monster stat block, SRD 5.2.1)\nMedium Fey, Neutral Evil. AC 17, HP 82 (11d8+33), Initiative +1, Speed 30 ft., Swim 30 ft..\nAbilities: Str 18 (save +4), Dex 12 (save +1), Con 16 (save +3), Int 13 (save +1), Wis 14 (save +2), Cha 14 (save +2).\nCR 3 (XP 700, PB +2).\nSkills Arcana +5, Deception +4, Perception +4, Stealth +3\nSenses Darkvision 60 ft.; Passive Perception 14\nLanguages Common, Elvish, Sylvan\n### Traits\n- Amphibious. The hag can breathe air and water.\n- Coven Magic. While within 30 feet of at least two hag allies, the hag can cast one of the following spells, requiring no Material components, using the spell's normal casting time, and using Intelligence as the spellcasting ability (spell save DC 11): Augury, Find Familiar, Identify, Locate Object, Scrying, or Unseen Servant. The hag must finish a Long Rest before using this trait to cast that spell again.\n- Mimicry. The hag can mimic animal sounds and humanoid voices. A creature that hears the sounds can tell they are imitations only with a successful DC 14 Wisdom (Insight) check.\n### Actions\n- Multiattack. The hag makes two Claw attacks.\n- Claw. Melee Attack Roll: +6, reach 5 ft. Hit: 8 (1d8 + 4) Slashing damage plus 3 (1d6) Poison damage.\n- Spellcasting. The hag casts one of the following spells, requiring no Material components and using Wisdom as the spellcasting ability (spell save DC 12, +4 to hit with spell attacks): At Will: Dancing Lights, Disguise Self (24-hour duration), Invisibility (self only, and the hag leaves no tracks while Invisible), Minor Illusion, Ray of Sickness (level 3 version)","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Green Hag","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Grick","constant":false,"content":"## Grick (monster stat block, SRD 5.2.1)\nMedium Aberration, Unaligned. AC 14, HP 54 (12d8), Initiative +2, Speed 30 ft., Climb 30 ft..\nAbilities: Str 14 (save +2), Dex 14 (save +2), Con 11 (save +0), Int 3 (save -4), Wis 14 (save +2), Cha 5 (save -3).\nCR 2 (XP 450, PB +2).\nSkills Stealth +4\nSenses Darkvision 60 ft.; Passive Perception 12\nLanguages None\n### Actions\n- Multiattack. The grick makes one Beak attack and one Tentacles attack.\n- Beak. Melee Attack Roll: +4, reach 5 ft. Hit: 9 (2d6 + 2) Piercing damage.\n- Tentacles. Melee Attack Roll: +4, reach 5 ft. Hit: 7 (1d10 + 2) Slashing damage. If the target is a Medium or smaller creature, it has the Grappled condition (escape DC 12) from all four tentacles.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Grick","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Griffon","constant":false,"content":"## Griffon (monster stat block, SRD 5.2.1)\nLarge Monstrosity, Unaligned. AC 12, HP 59 (7d10+21), Initiative +2, Speed 30 ft., Fly 80 ft..\nAbilities: Str 18 (save +4), Dex 15 (save +2), Con 16 (save +3), Int 2 (save -4), Wis 13 (save +1), Cha 8 (save -1).\nCR 2 (XP 450, PB +2).\nSkills Perception +5\nSenses Darkvision 60 ft.; Passive Perception 15\nLanguages None\n### Actions\n- Multiattack. The griffon makes two Rend attacks.\n- Rend. Melee Attack Roll: +6, reach 5 ft. Hit: 8 (1d8 + 4) Piercing damage. If the target is a Medium or smaller creature, it has the Grappled condition (escape DC 14) from both of the griffon's front claws.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Griffon","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Grimlock","constant":false,"content":"## Grimlock (monster stat block, SRD 5.2.1)\nMedium Aberration, Neutral Evil. AC 11, HP 11 (2d8+2), Initiative +1, Speed 30 ft., Climb 30 ft..\nAbilities: Str 16 (save +3), Dex 12 (save +1), Con 12 (save +1), Int 9 (save -1), Wis 8 (save -1), Cha 6 (save -2).\nCR 1/4 (XP 50, PB +2).\nSkills Athletics +5, Perception +3, Stealth +5\nSenses Blindsight 30 ft.; Passive Perception 13\nLanguages None\n### Actions\n- Bone Cudgel. Melee Attack Roll: +5, reach 5 ft. Hit: 6 (1d6 + 3) Bludgeoning damage plus 2 (1d4) Psychic damage.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Grimlock","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Guardian Naga","constant":false,"content":"## Guardian Naga (monster stat block, SRD 5.2.1)\nLarge Celestial, Lawful Good. AC 18, HP 136 (16d10+48), Initiative +4, Speed 40 ft., Climb 40 ft., Swim 40 ft..\nAbilities: Str 19 (save +4), Dex 18 (save +8), Con 16 (save +7), Int 16 (save +7), Wis 19 (save +8), Cha 18 (save +8).\nCR 10 (XP 5900, PB +4).\nSkills Arcana +11, History +11, Religion +11\nImmunities Poison; Charmed, Paralyzed, Poisoned, Restrained\nSenses Darkvision 60 ft.; Passive Perception 14\nLanguages Celestial, Common\n### Traits\n- Celestial Restoration. If the naga dies, it returns to life in 1d6 days and regains all its Hit Points unless Dispel Evil and Good is cast on its remains.\n### Actions\n- Multiattack. The naga makes two Bite attacks. It can replace any attack with a use of Poisonous Spittle.\n- Bite. Melee Attack Roll: +8, reach 10 ft. Hit: 17 (2d12 + 4) Piercing damage plus 22 (4d10) Poison damage.\n- Poisonous Spittle. Constitution Saving Throw: DC 16, one creature the naga can see within 60 feet. Failure: 31 (7d8) Poison damage, and the target has the Blinded condition until the start of the naga's next turn. Success: Half damage only.\n- Spellcasting. The naga casts one of the following spells, requiring no Somatic or Material components and using Wisdom as the spellcasting ability (spell save DC 16): At Will: Thaumaturgy 1/Day Each: Clairvoyance, Cure Wounds (level 6 version), Flame Strike (level 6 version), Geas, True Seeing","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Guardian Naga","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Guard","constant":false,"content":"## Guard (monster stat block, SRD 5.2.1)\nMedium or Small Humanoid, Neutral. AC 16, HP 11 (2d8+2), Initiative +1, Speed 30 ft..\nAbilities: Str 13 (save +1), Dex 12 (save +1), Con 12 (save +1), Int 10 (save +0), Wis 11 (save +0), Cha 10 (save +0).\nCR 1/8 (XP 25, PB +2).\nSkills Perception +2\nGear Chain Shirt, Shield, Spear\nSenses Passive Perception 12\nLanguages Common\n### Actions\n- Spear. Melee or Ranged Attack Roll: +3, reach 5 ft. or range 20/60 ft. Hit: 4 (1d6 + 1) Piercing damage.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Guard","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Guard Captain","constant":false,"content":"## Guard Captain (monster stat block, SRD 5.2.1)\nMedium or Small Humanoid, Neutral. AC 18, HP 75 (10d8+30), Initiative +4, Speed 30 ft..\nAbilities: Str 18 (save +4), Dex 14 (save +2), Con 16 (save +3), Int 12 (save +1), Wis 14 (save +2), Cha 13 (save +1).\nCR 4 (XP 1100, PB +2).\nSkills Athletics +6, Perception +4\nGear Breastplate, Javelins (6), Longsword, Shield\nSenses Passive Perception 14\nLanguages Common\n### Actions\n- Multiattack. The guard makes two attacks, using Javelin or Longsword in any combination.\n- Javelin. Melee or Ranged Attack Roll: +6, reach 5 ft. or range 30/120 ft. Hit: 14 (3d6 + 4) Piercing damage.\n- Longsword. Melee Attack Roll: +6, reach 5 ft. Hit: 15 (2d10 + 4) Slashing damage.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Guard Captain","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Half-Dragon","constant":false,"content":"## Half-Dragon (monster stat block, SRD 5.2.1)\nMedium Dragon, Neutral. AC 18, HP 105 (14d8+42), Initiative +5, Speed 40 ft..\nAbilities: Str 19 (save +4), Dex 14 (save +5), Con 16 (save +3), Int 10 (save +0), Wis 15 (save +5), Cha 14 (save +2).\nCR 5 (XP 1800, PB +3).\nSkills Athletics +7, Perception +5, Stealth +5\nResistances Damage type chosen for the Draconic Origin trait below\nSenses Blindsight 10 ft., Darkvision 60 ft.; Passive Perception 15\nLanguages Common, Draconic\n### Traits\n- Draconic Origin. The half-dragon is related to a type of dragon associated with one of the following damage types (GM's choice): Acid, Cold, Fire, Lightning, or Poison. This choice affects other aspects of the stat block.\n### Actions\n- Multiattack. The half-dragon makes two Claw attacks.\n- Claw. Melee Attack Roll: +7, reach 10 ft. Hit: 6 (1d4 + 4) Slashing damage plus 7 (2d6) damage of the type chosen for the Draconic Origin trait.\n- Dragon's Breath (Recharge 5–6). Dexterity Saving Throw: DC 14, each creature in a 30-foot Cone. Failure: 28 (8d6) damage of the type chosen for the Draconic Origin trait. Success: Half damage.\n### Bonus Actions\n- Leap. The half-dragon jumps up to 30 feet by spending 10 feet of movement.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Half-Dragon","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Harpy","constant":false,"content":"## Harpy (monster stat block, SRD 5.2.1)\nMedium Monstrosity, Chaotic Evil. AC 11, HP 38 (7d8+7), Initiative +1, Speed 20 ft., Fly 40 ft..\nAbilities: Str 12 (save +1), Dex 13 (save +1), Con 12 (save +1), Int 7 (save -2), Wis 10 (save +0), Cha 13 (save +1).\nCR 1 (XP 200, PB +2).\nSenses Passive Perception 10\nLanguages Common\n### Actions\n- Claw. Melee Attack Roll: +3, reach 5 ft. Hit: 6 (2d4 + 1) Slashing damage.\n- Luring Song. The harpy sings a magical melody, which lasts until the harpy's Concentration ends on it. Wisdom Saving Throw: DC 11, each Humanoid and Giant in a 300-foot Emanation originating from the harpy when the song starts. Failure: The target has the Charmed condition until the song ends and repeats the save at the end of each of its turns. While Charmed, the target has the Incapacitated condition and ignores the Luring Song of other harpies. If the target is more than 5 feet from the harpy, the target moves on its turn toward the harpy by the most direct route, trying to get within 5 feet of the harpy. It doesn't avoid Opportunity Attacks; however, before moving into damaging terrain (such as lava or a pit) and whenever it takes damage from a source other than the harpy, the target repeats the save. Success: The target is immune to this harpy's Luring Song for 24 hours.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Harpy","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Hell Hound","constant":false,"content":"## Hell Hound (monster stat block, SRD 5.2.1)\nMedium Fiend, Lawful Evil. AC 15, HP 58 (9d8+18), Initiative +1, Speed 50 ft..\nAbilities: Str 17 (save +3), Dex 12 (save +1), Con 14 (save +2), Int 6 (save -2), Wis 13 (save +1), Cha 6 (save -2).\nCR 3 (XP 700, PB +2).\nSkills Perception +5\nImmunities Fire\nSenses Darkvision 60 ft.; Passive Perception 15\nLanguages Understands Infernal but can't speak\n### Traits\n- Pack Tactics. The hound has Advantage on an attack roll against a creature if at least one of the hound's allies is within 5 feet of the creature and the ally doesn't have the Incapacitated condition.\n### Actions\n- Multiattack. The hound makes two Bite attacks.\n- Bite. Melee Attack Roll: +5, reach 5 ft. Hit: 7 (1d8 + 3) Piercing damage plus 3 (1d6) Fire damage.\n- Fire Breath (Recharge 5–6). Dexterity Saving Throw: DC 12, each creature in a 15-foot Cone. Failure: 17 (5d6) Fire damage. Success: Half damage.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Hell Hound","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Hezrou","constant":false,"content":"## Hezrou (monster stat block, SRD 5.2.1)\nLarge Fiend (Demon), Chaotic Evil. AC 18, HP 157 (15d10+75), Initiative +6, Speed 30 ft..\nAbilities: Str 19 (save +7), Dex 17 (save +3), Con 20 (save +8), Int 5 (save -3), Wis 12 (save +4), Cha 13 (save +1).\nCR 8 (XP 3900, PB +3).\nResistances Cold, Fire, Lightning\nImmunities Poison; Poisoned\nSenses Darkvision 120 ft.; Passive Perception 11\nLanguages Abyssal; telepathy 120 ft.\n### Traits\n- Demonic Restoration. If the hezrou dies outside the Abyss, its body dissolves into ichor, and it gains a new body instantly, reviving with all its Hit Points somewhere in the Abyss.\n- Magic Resistance. The hezrou has Advantage on saving throws against spells and other magical effects.\n- Stench. Constitution Saving Throw: DC 16, any creature that starts its turn in a 10-foot Emanation originating from the hezrou. Failure: The target has the Poisoned condition until the start of its next turn.\n### Actions\n- Multiattack. The hezrou makes three Rend attacks.\n- Rend. Melee Attack Roll: +7, reach 5 ft. Hit: 6 (1d4 + 4) Slashing damage plus 9 (2d8) Poison damage.\n### Bonus Actions\n- Leap. The hezrou jumps up to 30 feet by spending 10 feet of movement.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Hezrou","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Hill Giant","constant":false,"content":"## Hill Giant (monster stat block, SRD 5.2.1)\nHuge Giant, Chaotic Evil. AC 13, HP 105 (10d12+40), Initiative +2, Speed 40 ft..\nAbilities: Str 21 (save +5), Dex 8 (save -1), Con 19 (save +4), Int 5 (save -3), Wis 9 (save -1), Cha 6 (save -2).\nCR 5 (XP 1800, PB +3).\nSkills Perception +2\nSenses Passive Perception 12\nLanguages Giant\n### Actions\n- Multiattack. The giant makes two attacks, using Tree Club or Trash Lob in any combination.\n- Tree Club. Melee Attack Roll: +8, reach 10 ft. Hit: 18 (3d8 + 5) Bludgeoning damage. If the target is a Large or smaller creature, it has the Prone condition.\n- Trash Lob. Ranged Attack Roll: +8, range 60/240 ft. Hit: 16 (2d10 + 5) Bludgeoning damage, and the target has the Poisoned condition until the end of its next turn.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Hill Giant","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Hippogriff","constant":false,"content":"## Hippogriff (monster stat block, SRD 5.2.1)\nLarge Monstrosity, Unaligned. AC 11, HP 26 (4d10+4), Initiative +1, Speed 40 ft., Fly 60 ft..\nAbilities: Str 17 (save +3), Dex 13 (save +1), Con 13 (save +1), Int 2 (save -4), Wis 12 (save +1), Cha 8 (save -1).\nCR 1 (XP 200, PB +2).\nSkills Perception +5\nSenses Passive Perception 15\nLanguages None\n### Traits\n- Flyby. The hippogriff doesn't provoke an Opportunity Attack when it flies out of an enemy's reach.\n### Actions\n- Multiattack. The hippogriff makes two Rend attacks.\n- Rend. Melee Attack Roll: +5, reach 5 ft. Hit: 7 (1d8 + 3) Slashing damage.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Hippogriff","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Hobgoblin Warrior","constant":false,"content":"## Hobgoblin Warrior (monster stat block, SRD 5.2.1)\nMedium Fey (Goblinoid), Lawful Evil. AC 18, HP 11 (2d8+2), Initiative +3, Speed 30 ft..\nAbilities: Str 13 (save +1), Dex 12 (save +1), Con 12 (save +1), Int 10 (save +0), Wis 10 (save +0), Cha 9 (save -1).\nCR 1/2 (XP 100, PB +2).\nGear Half Plate Armor, Longbow, Longsword, Shield\nSenses Darkvision 60 ft.; Passive Perception 10\nLanguages Common, Goblin\n### Traits\n- Pack Tactics. The hobgoblin has Advantage on an attack roll against a creature if at least one of the hobgoblin's allies is within 5 feet of the creature and the ally doesn't have the Incapacitated condition.\n### Actions\n- Longsword. Melee Attack Roll: +3, reach 5 ft. Hit: 12 (2d10 + 1) Slashing damage.\n- Longbow. Ranged Attack Roll: +3, range 150/600 ft. Hit: 5 (1d8 + 1) Piercing damage plus 7 (3d4) Poison damage.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Hobgoblin Warrior","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Hobgoblin Captain","constant":false,"content":"## Hobgoblin Captain (monster stat block, SRD 5.2.1)\nMedium Fey (Goblinoid), Lawful Evil. AC 17, HP 58 (9d8+18), Initiative +4, Speed 30 ft..\nAbilities: Str 15 (save +2), Dex 14 (save +2), Con 14 (save +2), Int 12 (save +1), Wis 10 (save +0), Cha 13 (save +1).\nCR 3 (XP 700, PB +2).\nGear Greatsword, Half Plate Armor, Longbow\nSenses Darkvision 60 ft.; Passive Perception 10\nLanguages Common, Goblin\n### Traits\n- Aura of Authority. While in a 10-foot Emanation originating from the hobgoblin, the hobgoblin and its allies have Advantage on attack rolls and saving throws, provided the hobgoblin doesn't have the Incapacitated condition.\n### Actions\n- Multiattack. The hobgoblin makes two attacks, using Greatsword or Longbow in any combination.\n- Greatsword. Melee Attack Roll: +4, reach 5 ft. Hit: 9 (2d6 + 2) Slashing damage plus 3 (1d6) Poison damage.\n- Longbow. Ranged Attack Roll: +4, range 150/600 ft. Hit: 6 (1d8 + 2) Piercing damage plus 5 (2d4) Poison damage.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Hobgoblin Captain","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Homunculus","constant":false,"content":"## Homunculus (monster stat block, SRD 5.2.1)\nTiny Construct, Neutral. AC 13, HP 4 (1d4+2), Initiative +2, Speed 20 ft., Fly 40 ft..\nAbilities: Str 4 (save -3), Dex 15 (save +2), Con 14 (save +2), Int 10 (save +0), Wis 10 (save +2), Cha 7 (save +0).\nCR 0 (XP 10, PB +2).\nImmunities Poison; Charmed, Poisoned\nSenses Darkvision 60 ft.; Passive Perception 10\nLanguages Understands Common plus one other language but can't speak\n### Traits\n- Telepathic Bond. While the homunculus is on the same plane of existence as its master, the two of them can communicate telepathically with each other.\n### Actions\n- Bite. Melee Attack Roll: +4, reach 5 ft. Hit: 1 Piercing damage, and the target is subjected to the following effect. Constitution Saving Throw: DC 12. Failure: The target has the Poisoned condition until the end of the homunculus's next turn. Failure by 5 or More: The target has the Poisoned condition for 1 minute. While Poisoned, the target has the Unconscious condition, which ends early if the target takes any damage.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Homunculus","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Horned Devil","constant":false,"content":"## Horned Devil (monster stat block, SRD 5.2.1)\nLarge Fiend (Devil), Lawful Evil. AC 18, HP 199 (19d10+95), Initiative +7, Speed 30 ft., Fly 60 ft..\nAbilities: Str 22 (save +10), Dex 17 (save +7), Con 21 (save +5), Int 12 (save +1), Wis 16 (save +7), Cha 18 (save +8).\nCR 11 (XP 7200, PB +4).\nResistances Cold\nImmunities Fire, Poison; Poisoned\nSenses Darkvision 150 ft. (unimpeded by magical Darkness); Passive Perception 13\nLanguages Infernal; telepathy 120 ft.\n### Traits\n- Diabolical Restoration. If the devil dies outside the Nine Hells, its body disappears in sulfurous smoke, and it gains a new body instantly, reviving with all its Hit Points somewhere in the Nine Hells.\n- Magic Resistance. The devil has Advantage on saving throws against spells and other magical effects.\n### Actions\n- Multiattack. The devil makes three attacks, using Searing Fork or Hurl Flame in any combination. It can replace one attack with a use of Infernal Tail.\n- Searing Fork. Melee Attack Roll: +10, reach 10 ft. Hit: 15 (2d8 + 6) Piercing damage plus 9 (2d8) Fire damage.\n- Hurl Flame. Ranged Attack Roll: +8, range 150 ft. Hit: 26 (5d8 + 4) Fire damage. If the target is a flammable object that isn't being worn or carried, it starts burning.\n- Infernal Tail. Dexterity Saving Throw: DC 17, one creature the devil can see within 10 feet. Failure: 10 (1d8 + 6) Necrotic damage, and the target receives an infernal wound if it doesn't have one. While wounded, the target loses 10 (3d6) Hit Points at the start of each of its turns. The wound closes after 1 minute, after a spell restores Hit Points to the target, or after the target or a creature within 5 feet of it takes an action to stanch the wound, doing so by succeeding on a DC 17 Wisdom (Medicine) check.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Horned Devil","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Hydra","constant":false,"content":"## Hydra (monster stat block, SRD 5.2.1)\nHuge Monstrosity, Unaligned. AC 15, HP 184 (16d12+80), Initiative +4, Speed 40 ft., Swim 40 ft..\nAbilities: Str 20 (save +5), Dex 12 (save +1), Con 20 (save +5), Int 2 (save -4), Wis 10 (save +0), Cha 7 (save -2).\nCR 8 (XP 3900, PB +3).\nSkills Perception +6\nImmunities Blinded, Charmed, Deafened, Frightened, Stunned, Unconscious\nSenses Darkvision 60 ft.; Passive Perception 16\nLanguages None\n### Traits\n- Hold Breath. The hydra can hold its breath for 1 hour.\n- Multiple Heads. The hydra has five heads. Whenever the hydra takes 25 damage or more on a single turn, one of its heads dies. The hydra dies if all its heads are dead. At the end of each of its turns when it has at least one living head, the hydra grows two heads for each of its heads that died since its last turn, unless it has taken Fire damage since its last turn. The hydra regains 20 Hit Points when it grows new heads.\n- Reactive Heads. For each head the hydra has beyond one, it gets an extra Reaction that can be used only for Opportunity Attacks.\n### Actions\n- Multiattack. The hydra makes as many Bite attacks as it has heads.\n- Bite. Melee Attack Roll: +8, reach 10 ft. Hit: 10 (1d10 + 5) Piercing damage.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Hydra","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Ice Devil","constant":false,"content":"## Ice Devil (monster stat block, SRD 5.2.1)\nLarge Fiend (Devil), Lawful Evil. AC 18, HP 228 (24d10+96), Initiative +7, Speed 40 ft..\nAbilities: Str 21 (save +5), Dex 14 (save +7), Con 18 (save +9), Int 18 (save +4), Wis 15 (save +7), Cha 18 (save +9).\nCR 14 (XP 11500, PB +5).\nSkills Insight +7, Perception +7, Persuasion +9\nImmunities Cold, Fire, Poison; Poisoned\nSenses Blindsight 120 ft.; Passive Perception 17\nLanguages Infernal; telepathy 120 ft.\n### Traits\n- Diabolical Restoration. If the devil dies outside the Nine Hells, its body disappears in sulfurous smoke, and it gains a new body instantly, reviving with all its Hit Points somewhere in the Nine Hells.\n- Magic Resistance. The devil has Advantage on saving throws against spells and other magical effects.\n### Actions\n- Multiattack. The devil makes three Ice Spear attacks. It can replace one attack with a Tail attack.\n- Ice Spear. Melee or Ranged Attack Roll: +10, reach 5 ft. or range 30/120 ft. Hit: 14 (2d8 + 5) Piercing damage plus 10 (3d6) Cold damage. Until the end of its next turn, the target can't take a Bonus Action or Reaction, its Speed decreases by 10 feet, and it can move or take one action on its turn, not both. Hit or Miss: The spear magically returns to the devil's hand immediately after a ranged attack.\n- Tail. Melee Attack Roll: +10, reach 10 ft. Hit: 15 (3d6 + 5) Bludgeoning damage plus 18 (4d8) Cold damage.\n- Ice Wall (Recharge 6). The devil casts Wall of Ice (level 8 version), requiring no spell components and using Intelligence as the spellcasting ability (spell save DC 17).","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Ice Devil","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Imp","constant":false,"content":"## Imp (monster stat block, SRD 5.2.1)\nTiny Fiend (Devil), Lawful Evil. AC 13, HP 21 (6d4+6), Initiative +3, Speed 20 ft., Fly 40 ft..\nAbilities: Str 6 (save -2), Dex 17 (save +3), Con 13 (save +1), Int 11 (save +0), Wis 12 (save +1), Cha 14 (save +2).\nCR 1 (XP 200, PB +2).\nSkills Deception +4, Insight +3, Stealth +5\nResistances Cold\nImmunities Fire, Poison; Poisoned\nSenses Darkvision 120 ft. (unimpeded by magical Darkness); Passive Perception 11\nLanguages Common, Infernal\n### Traits\n- Magic Resistance. The imp has Advantage on saving throws against spells and other magical effects.\n### Actions\n- Sting. Melee Attack Roll: +5, reach 5 ft. Hit: 6 (1d6 + 3) Piercing damage plus 7 (2d6) Poison damage.\n- Invisibility. The imp casts Invisibility on itself, requiring no spell components and using Charisma as the spellcasting ability.\n- Shape-Shift. The imp shape-shifts to resemble a rat (Speed 20 ft.), a raven (20 ft., Fly 60 ft.), or a spider (20 ft., Climb 20 ft.), or it returns to its true form. Its game statistics are the same in each form, except for its Speed. Any equipment it is wearing or carrying isn't transformed.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Imp","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Incubus","constant":false,"content":"## Incubus (monster stat block, SRD 5.2.1)\nMedium Fiend, Neutral Evil. AC 15, HP 66 (12d8+12), Initiative +3, Speed 30 ft., Fly 60 ft..\nAbilities: Str 8 (save -1), Dex 17 (save +3), Con 13 (save +1), Int 15 (save +2), Wis 12 (save +1), Cha 20 (save +5).\nCR 4 (XP 1100, PB +2).\nSkills Deception +9, Insight +5, Perception +5, Persuasion +9, Stealth +7\nResistances Cold, Fire, Poison, Psychic\nSenses Darkvision 60 ft.; Passive Perception 15\nLanguages Abyssal, Common, Infernal; telepathy 60 ft.\n### Traits\n- Succubus Form. When the incubus finishes a Long Rest, it can shape-shift into a Succubus, using that stat block instead of this one. Any equipment it is wearing or carrying isn't transformed.\n### Actions\n- Multiattack. The incubus makes two Restless Touch attacks.\n- Restless Touch. Melee Attack Roll: +7, reach 5 ft. Hit: 15 (3d6 + 5) Psychic damage, and the target is cursed for 24 hours or until the incubus dies. Until the curse ends, the target gains no benefit from finishing Short Rests.\n- Spellcasting. The incubus casts one of the following spells, requiring no Material components and using Charisma as the spellcasting ability (spell save DC 15): At Will: Disguise Self, Etherealness 1/Day Each: Dream, Hypnotic Pattern\n### Bonus Actions\n- Nightmare (Recharge 6). Wisdom Saving Throw: DC 15, one creature the incubus can see within 60 feet. Failure: If the target has 20 Hit Points or fewer, it has the Unconscious condition for 1 hour, until it takes damage, or until a creature within 5 feet of it takes an action to wake it. Otherwise, the target takes 18 (4d8) Psychic damage.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Incubus","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Invisible Stalker","constant":false,"content":"## Invisible Stalker (monster stat block, SRD 5.2.1)\nLarge Elemental, Neutral. AC 14, HP 97 (13d10+26), Initiative +7, Speed 50 ft., Fly 50 ft. (hover).\nAbilities: Str 16 (save +3), Dex 19 (save +4), Con 14 (save +2), Int 10 (save +0), Wis 15 (save +2), Cha 11 (save +0).\nCR 6 (XP 2300, PB +3).\nSkills Perception +8, Stealth +10\nResistances Bludgeoning, Piercing, Slashing\nImmunities Poison; Exhaustion, Grappled, Paralyzed, Petrified, Poisoned, Prone, Restrained, Unconscious\nSenses Darkvision 60 ft.; Passive Perception 18\nLanguages Common, Primordial (Auran)\n### Traits\n- Air Form. The stalker can enter an enemy's space and stop there. It can move through a space as narrow as 1 inch without expending extra movement to do so.\n- Invisibility. The stalker has the Invisible condition.\n### Actions\n- Multiattack. The stalker makes three Wind Swipe attacks. It can replace one attack with a use of Vortex.\n- Wind Swipe. Melee Attack Roll: +7, reach 5 ft. Hit: 11 (2d6 + 4) Force damage.\n- Vortex. Constitution Saving Throw: DC 14, one Large or smaller creature in the stalker's space. Failure: 7 (1d8 + 3) Thunder damage, and the target has the Grappled condition (escape DC 13). Until the grapple ends, the target can't cast spells with a Verbal component and takes 7 (2d6) Thunder damage at the start of each of the stalker's turns.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Invisible Stalker","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Iron Golem","constant":false,"content":"## Iron Golem (monster stat block, SRD 5.2.1)\nLarge Construct, Unaligned. AC 20, HP 252 (24d10+120), Initiative +9, Speed 30 ft..\nAbilities: Str 24 (save +7), Dex 9 (save -1), Con 20 (save +5), Int 3 (save -4), Wis 11 (save +0), Cha 1 (save -5).\nCR 16 (XP 15000, PB +5).\nImmunities Fire, Poison, Psychic; Charmed, Exhaustion, Frightened, Paralyzed, Petrified, Poisoned\nSenses Darkvision 120 ft.; Passive Perception 10\nLanguages Understands Common plus two other languages but can't speak\n### Traits\n- Fire Absorption. Whenever the golem is subjected to Fire damage, it regains a number of Hit Points equal to the Fire damage dealt.\n- Immutable Form. The golem can't shape-shift.\n- Magic Resistance. The golem has Advantage on saving throws against spells and other magical effects.\n### Actions\n- Multiattack. The golem makes two attacks, using Bladed Arm or Fiery Bolt in any combination.\n- Bladed Arm. Melee Attack Roll: +12, reach 10 ft. Hit: 20 (3d8 + 7) Slashing damage plus 10 (3d6) Fire damage.\n- Fiery Bolt. Ranged Attack Roll: +10, range 120 ft. Hit: 36 (8d8) Fire damage.\n- Poison Breath (Recharge 6). Constitution Saving Throw: DC 18, each creature in a 60-foot Cone. Failure: 55 (10d10) Poison damage. Success: Half damage.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Iron Golem","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Knight","constant":false,"content":"## Knight (monster stat block, SRD 5.2.1)\nMedium or Small Humanoid, Neutral. AC 18, HP 52 (8d8+16), Initiative +0, Speed 30 ft..\nAbilities: Str 16 (save +3), Dex 11 (save +0), Con 14 (save +4), Int 11 (save +0), Wis 11 (save +2), Cha 15 (save +2).\nCR 3 (XP 700, PB +2).\nImmunities Frightened\nGear Greatsword, Heavy Crossbow, Plate Armor\nSenses Passive Perception 10\nLanguages Common plus one other language\n### Actions\n- Multiattack. The knight makes two attacks, using Greatsword or Heavy Crossbow in any combination.\n- Greatsword. Melee Attack Roll: +5, reach 5 ft. Hit: 10 (2d6 + 3) Slashing damage plus 4 (1d8) Radiant damage.\n- Heavy Crossbow. Ranged Attack Roll: +2, range 100/400 ft. Hit: 11 (2d10) Piercing damage plus 4 (1d8) Radiant damage.\n### Reactions\n- Parry. Trigger: The knight is hit by a melee attack roll while holding a weapon. Response: The knight adds 2 to its AC against that attack, possibly causing it to miss.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Knight","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Kobold Warrior","constant":false,"content":"## Kobold Warrior (monster stat block, SRD 5.2.1)\nSmall Dragon, Neutral. AC 14, HP 7 (3d6-3), Initiative +2, Speed 30 ft..\nAbilities: Str 7 (save -2), Dex 15 (save +2), Con 9 (save -1), Int 8 (save -1), Wis 7 (save -2), Cha 8 (save -1).\nCR 1/8 (XP 25, PB +2).\nGear Daggers (3)\nSenses Darkvision 60 ft.; Passive Perception 8\nLanguages Common, Draconic\n### Traits\n- Pack Tactics. The kobold has Advantage on an attack roll against a creature if at least one of the kobold's allies is within 5 feet of the creature and the ally doesn't have the Incapacitated condition.\n- Sunlight Sensitivity. While in sunlight, the kobold has Disadvantage on ability checks and attack rolls.\n### Actions\n- Dagger. Melee or Ranged Attack Roll: +4, reach 5 ft. or range 20/60 ft. Hit: 4 (1d4 + 2) Piercing damage.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Kobold Warrior","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Kraken","constant":false,"content":"## Kraken (monster stat block, SRD 5.2.1)\nGargantuan Monstrosity (Titan), Chaotic Evil. AC 18, HP 481 (26d20+208), Initiative +14, Speed 30 ft., Swim 120 ft..\nAbilities: Str 30 (save +17), Dex 11 (save +7), Con 26 (save +15), Int 22 (save +6), Wis 18 (save +11), Cha 20 (save +5).\nCR 23 (XP 50000, PB +7).\nSkills History +13, Perception +11\nImmunities Cold, Lightning; Frightened, Grappled, Paralyzed, Restrained\nSenses Truesight 120 ft.; Passive Perception 21\nLanguages Understands Abyssal, Celestial, Infernal, and Primordial but can't speak; telepathy 120 ft.\n### Traits\n- Amphibious. The kraken can breathe air and water.\n- Legendary Resistance (4/Day, or 5/Day in Lair). If the kraken fails a saving throw, it can choose to succeed instead.\n- Siege Monster. The kraken deals double damage to objects and structures.\n### Actions\n- Multiattack. The kraken makes two Tentacle attacks and uses Fling, Lightning Strike, or Swallow.\n- Tentacle. Melee Attack Roll: +17, reach 30 ft. Hit: 24 (4d6 + 10) Bludgeoning damage. The target has the Grappled condition (escape DC 20) from one of ten tentacles, and it has the Restrained condition until the grapple ends.\n- Fling. The kraken throws a Large or smaller creature Grappled by it to a space it can see within 60 feet of itself that isn't in the air. Dexterity Saving Throw: DC 25, the creature thrown and each creature in the destination space. Failure: 18 (4d8) Bludgeoning damage, and the target has the Prone condition. Success: Half damage only.\n- Lightning Strike. Dexterity Saving Throw: DC 23, one creature the kraken can see within 120 feet. Failure: 33 (6d10) Lightning damage. Success: Half damage.\n- Swallow. Dexterity Saving Throw: DC 25, one creature Grappled by the kraken (it can have up to four creatures swallowed at a time). Failure: 23 (3d8 + 10) Piercing damage. If the target is Large or smaller, it is swallowed and no longer Grappled. A swallowed creature has the Restrained condition, has Total Cover against attacks and other effects outside the kraken, and takes 24 (7d6) Acid damage at the start of each of its turns. If the kraken takes 50 damage or more on a single turn from a creature inside it, the kraken must succeed on a DC 25 Constitution saving throw at the end of that turn or regurgitate all swallowed creatures, each of which falls in a space within 10 feet of the kraken with the Prone condition. If the kraken dies, any swallowed creature no longer has the Restrained condition and can escape from the corpse using 15 feet of movement, exiting Prone.\n### Legendary Actions\n- Legendary Action Uses: 3 (4 in Lair). Immediately after another creature's turn, the kraken can expend a use to take one of the following actions. The kraken regains all expended uses at the start of each of its turns.\n- Storm Bolt. The kraken uses Lightning Strike.\n- Toxic Ink. Constitution Saving Throw: DC 23, each creature in a 15-foot Emanation originating from the kraken while it is underwater. Failure: The target has the Blinded and Poisoned conditions until the end of the kraken's next turn. The kraken then moves up to its Speed. Failure or Success: The kraken can't take this action again until the start of its next turn.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Kraken","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Lamia","constant":false,"content":"## Lamia (monster stat block, SRD 5.2.1)\nLarge Fiend, Chaotic Evil. AC 13, HP 97 (13d10+26), Initiative +1, Speed 40 ft..\nAbilities: Str 16 (save +3), Dex 13 (save +1), Con 15 (save +2), Int 14 (save +2), Wis 15 (save +2), Cha 16 (save +3).\nCR 4 (XP 1100, PB +2).\nSkills Deception +7, Insight +4, Stealth +5\nSenses Darkvision 60 ft.; Passive Perception 12\nLanguages Abyssal, Common\n### Actions\n- Multiattack. The lamia makes two Claw attacks. It can replace one attack with a use of Corrupting Touch.\n- Claw. Melee Attack Roll: +5, reach 5 ft. Hit: 7 (1d8 + 3) Slashing damage plus 7 (2d6) Psychic damage.\n- Corrupting Touch. Wisdom Saving Throw: DC 13, one creature the lamia can see within 5 feet. Failure: 13 (3d8) Psychic damage, and the target is cursed for 1 hour. Until the curse ends, the target has the Charmed and Poisoned conditions.\n- Spellcasting. The lamia casts one of the following spells, requiring no Material components and using Charisma as the spellcasting ability (spell save DC 13): At Will: Disguise Self (can appear as a Large or Medium biped), Minor Illusion 1/Day Each: Geas, Major Image, Scrying\n### Bonus Actions\n- Leap. The lamia jumps up to 30 feet by spending 10 feet of movement.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Lamia","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Lemure","constant":false,"content":"## Lemure (monster stat block, SRD 5.2.1)\nMedium Fiend (Devil), Lawful Evil. AC 9, HP 9 (2d8), Initiative -3, Speed 20 ft..\nAbilities: Str 10 (save +0), Dex 5 (save -3), Con 11 (save +0), Int 1 (save -5), Wis 11 (save +0), Cha 3 (save -4).\nCR 0 (XP 10, PB +2).\nResistances Cold\nImmunities Fire, Poison; Charmed, Frightened, Poisoned\nSenses Darkvision 120 ft. (unimpeded by magical Darkness); Passive Perception 10\nLanguages Understands Infernal but can't speak\n### Traits\n- Hellish Restoration. If the lemure dies in the Nine Hells, it revives with all its Hit Points in 1d10 days unless it is killed by a creature under the effects of a Bless spell or its remains are sprinkled with Holy Water.\n### Actions\n- Vile Slime. Melee Attack Roll: +2, reach 5 ft. Hit: 2 (1d4) Poison damage.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Lemure","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Lich","constant":false,"content":"## Lich (monster stat block, SRD 5.2.1)\nMedium Undead (Wizard), Neutral Evil. AC 20, HP 315 (42d8+126), Initiative +17, Speed 30 ft..\nAbilities: Str 11 (save +0), Dex 16 (save +10), Con 16 (save +10), Int 21 (save +12), Wis 14 (save +9), Cha 16 (save +3).\nCR 21 (XP 33000, PB +7).\nSkills Arcana +19, History +12, Insight +9, Perception +9\nResistances Cold, Lightning\nImmunities Necrotic, Poison; Charmed, Exhaustion, Frightened, Paralyzed, Poisoned\nGear Component Pouch\nSenses Truesight 120 ft.; Passive Perception 19\nLanguages All\n### Traits\n- Legendary Resistance (4/Day, or 5/Day in Lair). If the lich fails a saving throw, it can choose to succeed instead.\n- Spirit Jar. If destroyed, the lich reforms in 1d10 days if it has a spirit jar, reviving with all its Hit Points. The new body appears in an unoccupied space within the lich's lair.\n### Actions\n- Multiattack. The lich makes three attacks, using Eldritch Burst or Paralyzing Touch in any combination.\n- Eldritch Burst. Melee or Ranged Attack Roll: +12, reach 5 ft. or range 120 ft. Hit: 31 (4d12 + 5) Force damage.\n- Paralyzing Touch. Melee Attack Roll: +12, reach 5 ft. Hit: 15 (3d6 + 5) Cold damage, and the target has the Paralyzed condition until the start of the lich's next turn.\n- Spellcasting. The lich casts one of the following spells, using Intelligence as the spellcasting ability (spell save DC 20): At Will: Detect Magic, Detect Thoughts, Dispel Magic, Fireball (level 5 version), Invisibility, Lightning Bolt (level 5 version), Mage Hand, Prestidigitation 2/Day Each: Animate Dead, Dimension Door, Plane Shift 1/Day Each: Chain Lightning, Finger of Death, Power Word Kill, Scrying\n### Reactions\n- Protective Magic. The lich casts Counterspell or Shield in response to the spell's trigger, using the same spellcasting ability as Spellcasting.\n### Legendary Actions\n- Legendary Action Uses: 3 (4 in Lair). Immediately after another creature's turn, the lich can expend a use to take one of the following actions. The lich regains all expended uses at the start of each of its turns.\n- Deathly Teleport. The lich teleports up to 60 feet to an unoccupied space it can see, and each creature within 10 feet of the space it left takes 11 (2d10) Necrotic damage.\n- Disrupt Life. Constitution Saving Throw: DC 20, each creature that isn't an Undead in a 20-foot Emanation originating from the lich. Failure: 31 (9d6) Necrotic damage. Success: Half damage. Failure or Success: The lich can't take this action again until the start of its next turn.\n- Frightening Gaze. The lich casts Fear, using the same spellcasting ability as Spellcasting. The lich can't take this action again until the start of its next turn.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Lich","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Mage","constant":false,"content":"## Mage (monster stat block, SRD 5.2.1)\nMedium or Small Humanoid (Wizard), Neutral. AC 15, HP 81 (18d8), Initiative +2, Speed 30 ft..\nAbilities: Str 9 (save -1), Dex 14 (save +2), Con 11 (save +0), Int 17 (save +6), Wis 12 (save +4), Cha 11 (save +0).\nCR 6 (XP 2300, PB +3).\nSkills Arcana +6, History +6, Perception +4\nGear Wand\nSenses Passive Perception 14\nLanguages Common plus three other languages\n### Actions\n- Multiattack. The mage makes three Arcane Burst attacks.\n- Arcane Burst. Melee or Ranged Attack Roll: +6, reach 5 ft. or range 120 ft. Hit: 16 (3d8 + 3) Force damage.\n- Spellcasting. The mage casts one of the following spells, using Intelligence as the spellcasting ability (spell save DC 14): At Will: Detect Magic, Light, Mage Armor (included in AC), Mage Hand, Prestidigitation 2/Day Each: Fireball (level 4 version), Invisibility 1/Day Each: Cone of Cold, Fly\n### Bonus Actions\n- Misty Step (3/Day). The mage casts Misty Step, using the same spellcasting ability as Spellcasting.\n### Reactions\n- Protective Magic (3/Day). The mage casts Counterspell or Shield in response to the spell's trigger, using the same spellcasting ability as Spellcasting.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Mage","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Archmage","constant":false,"content":"## Archmage (monster stat block, SRD 5.2.1)\nMedium or Small Humanoid (Wizard), Neutral. AC 17, HP 170 (31d8+31), Initiative +7, Speed 30 ft..\nAbilities: Str 10 (save +0), Dex 14 (save +2), Con 12 (save +1), Int 20 (save +9), Wis 15 (save +6), Cha 16 (save +3).\nCR 12 (XP 8000, PB +4).\nSkills Arcana +13, History +9, Perception +6\nImmunities Psychic; Charmed (with Mind Blank)\nGear Wand\nSenses Passive Perception 16\nLanguages Common plus five other languages\n### Traits\n- Magic Resistance. The archmage has Advantage on saving throws against spells and other magical effects.\n### Actions\n- Multiattack. The archmage makes four Arcane Burst attacks.\n- Arcane Burst. Melee or Ranged Attack Roll: +9, reach 5 ft. or range 150 ft. Hit: 27 (4d10 + 5) Force damage.\n- Spellcasting. The archmage casts one of the following spells, using Intelligence as the spellcasting ability (spell save DC 17): At Will: Detect Magic, Detect Thoughts, Disguise Self, Invisibility, Light, Mage Armor (included in AC), Mage Hand, Prestidigitation 2/Day Each: Fly, Lightning Bolt (level 7 version) 1/Day Each: Cone of Cold (level 9 version), Mind Blank (cast before combat), Scrying, Teleport\n### Bonus Actions\n- Misty Step (3/Day). The mage casts Misty Step, using the same spellcasting ability as Spellcasting.\n### Reactions\n- Protective Magic (3/Day). The archmage casts Counterspell or Shield in response to the spell's trigger, using the same spellcasting ability as Spellcasting.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Archmage","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Magmin","constant":false,"content":"## Magmin (monster stat block, SRD 5.2.1)\nSmall Elemental, Chaotic Neutral. AC 14, HP 13 (3d6+3), Initiative +2, Speed 30 ft..\nAbilities: Str 7 (save -2), Dex 15 (save +2), Con 12 (save +1), Int 8 (save -1), Wis 11 (save +0), Cha 10 (save +0).\nCR 1/2 (XP 100, PB +2).\nImmunities Fire\nSenses Darkvision 60 ft.; Passive Perception 10\nLanguages Primordial (Ignan)\n### Traits\n- Death Burst. The magmin explodes when it dies. Dexterity Saving Throw: DC 11, each creature in a 10-foot Emanation originating from the magmin. Failure: 7 (2d6) Fire damage. Success: Half damage.\n### Actions\n- Touch. Melee Attack Roll: +4, reach 5 ft. Hit: 7 (2d4 + 2) Fire damage. If the target is a creature or a flammable object that isn't being worn or carried, it starts burning.\n### Bonus Actions\n- Ignited Illumination. The magmin sets itself ablaze or extinguishes its flames. While ablaze, the magmin sheds Bright Light in a 10-foot radius and Dim Light for an additional 10 feet.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Magmin","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Manticore","constant":false,"content":"## Manticore (monster stat block, SRD 5.2.1)\nLarge Monstrosity, Lawful Evil. AC 14, HP 68 (8d10+24), Initiative +3, Speed 30 ft., Fly 50 ft..\nAbilities: Str 17 (save +3), Dex 16 (save +3), Con 17 (save +3), Int 7 (save -2), Wis 12 (save +1), Cha 8 (save -1).\nCR 3 (XP 700, PB +2).\nSenses Darkvision 60 ft.; Passive Perception 11\nLanguages Common\n### Actions\n- Multiattack. The manticore makes three attacks, using Rend or Tail Spike in any combination.\n- Rend. Melee Attack Roll: +5, reach 5 ft. Hit: 7 (1d8 + 3) Slashing damage.\n- Tail Spike. Ranged Attack Roll: +5, range 100/200 ft. Hit: 7 (1d8 + 3) Piercing damage.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Manticore","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Marilith","constant":false,"content":"## Marilith (monster stat block, SRD 5.2.1)\nLarge Fiend (Demon), Chaotic Evil. AC 16, HP 220 (21d10+105), Initiative +10, Speed 40 ft., Climb 40 ft..\nAbilities: Str 18 (save +9), Dex 20 (save +5), Con 20 (save +10), Int 18 (save +4), Wis 16 (save +8), Cha 20 (save +10).\nCR 16 (XP 15000, PB +5).\nSkills Perception +8\nResistances Cold, Fire, Lightning\nImmunities Poison; Poisoned\nSenses Truesight 120 ft.; Passive Perception 18\nLanguages Abyssal; telepathy 120 ft.\n### Traits\n- Demonic Restoration. If the marilith dies outside the Abyss, its body dissolves into ichor, and it gains a new body instantly, reviving with all its Hit Points somewhere in the Abyss.\n- Magic Resistance. The marilith has Advantage on saving throws against spells and other magical effects.\n- Reactive. The marilith can take one Reaction on every turn of combat.\n### Actions\n- Multiattack. The marilith makes six Pact Blade attacks and uses Constrict.\n- Pact Blade. Melee Attack Roll: +10, reach 5 ft. Hit: 10 (1d10 + 5) Slashing damage plus 7 (2d6) Necrotic damage.\n- Constrict. Strength Saving Throw: DC 17, one Medium or smaller creature the marilith can see within 5 feet. Failure: 15 (2d10 + 4) Bludgeoning damage. The target has the Grappled condition (escape DC 14), and it has the Restrained condition until the grapple ends.\n### Bonus Actions\n- Teleport (Recharge 5–6). The marilith teleports up to 120 feet to an unoccupied space it can see.\n### Reactions\n- Parry. Trigger: The marilith is hit by a melee attack roll while holding a weapon. Response: The marilith adds 5 to its AC against that attack, possibly causing it to miss.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Marilith","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Medusa","constant":false,"content":"## Medusa (monster stat block, SRD 5.2.1)\nMedium Monstrosity, Lawful Evil. AC 15, HP 127 (17d8+51), Initiative +6, Speed 30 ft..\nAbilities: Str 10 (save +0), Dex 17 (save +3), Con 16 (save +3), Int 12 (save +1), Wis 13 (save +4), Cha 15 (save +2).\nCR 6 (XP 2300, PB +3).\nSkills Deception +5, Perception +4, Stealth +6\nSenses Darkvision 150 ft.; Passive Perception 14\nLanguages Common plus one other language\n### Actions\n- Multiattack. The medusa makes two Claw attacks and one Snake Hair attack, or it makes three Poison Ray attacks.\n- Claw. Melee Attack Roll: +6, reach 5 ft. Hit: 10 (2d6 + 3) Slashing damage.\n- Snake Hair. Melee Attack Roll: +6, reach 5 ft. Hit: 5 (1d4 + 3) Piercing damage plus 14 (4d6) Poison damage.\n- Poison Ray. Ranged Attack Roll: +5, range 150 ft. Hit: 11 (2d8 + 2) Poison damage.\n### Bonus Actions\n- Petrifying Gaze (Recharge 5–6). Constitution Saving Throw: DC 13, each creature in a 30-foot Cone. If the medusa sees its reflection in the Cone, the medusa must make this save. First Failure: The target has the Restrained condition and repeats the save at the end of its next turn if it is still Restrained, ending the effect on itself on a success. Second Failure: The target has the Petrified condition instead of the Restrained condition.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Medusa","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Dust Mephit","constant":false,"content":"## Dust Mephit (monster stat block, SRD 5.2.1)\nSmall Elemental, Neutral Evil. AC 12, HP 17 (5d6), Initiative +2, Speed 30 ft., Fly 30 ft..\nAbilities: Str 5 (save -3), Dex 14 (save +2), Con 10 (save +0), Int 9 (save -1), Wis 11 (save +0), Cha 10 (save +0).\nCR 1/2 (XP 100, PB +2).\nSkills Perception +2, Stealth +4\nVulnerabilities Fire\nImmunities Poison; Exhaustion, Poisoned\nSenses Darkvision 60 ft.; Passive Perception 12\nLanguages Primordial (Auran, Terran)\n### Traits\n- Death Burst. The mephit explodes when it dies. Dexterity Saving Throw: DC 10, each creature in a 5-foot Emanation originating from the mephit. Failure: 5 (2d4) Bludgeoning damage. Success: Half damage.\n### Actions\n- Claw. Melee Attack Roll: +4, reach 5 ft. Hit: 4 (1d4 + 2) Slashing damage.\n- Blinding Breath (Recharge 6). Dexterity Saving Throw: DC 10, each creature in a 15-foot Cone. Failure: The target has the Blinded condition until the end of the mephit's next turn.\n- Sleep (1/Day). The mephit casts the Sleep spell, requiring no spell components and using Charisma as the spellcasting ability (spell save DC 10).","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Dust Mephit","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Ice Mephit","constant":false,"content":"## Ice Mephit (monster stat block, SRD 5.2.1)\nSmall Elemental, Neutral Evil. AC 11, HP 21 (6d6), Initiative +1, Speed 30 ft., Fly 30 ft..\nAbilities: Str 7 (save -2), Dex 13 (save +1), Con 10 (save +0), Int 9 (save -1), Wis 11 (save +0), Cha 12 (save +1).\nCR 1/2 (XP 100, PB +2).\nSkills Perception +2, Stealth +3\nVulnerabilities Fire\nImmunities Cold, Poison; Exhaustion, Poisoned\nSenses Darkvision 60 ft.; Passive Perception 12\nLanguages Primordial (Aquan, Auran)\n### Traits\n- Death Burst. The mephit explodes when it dies. Constitution Saving Throw: DC 10, each creature in a 5-foot Emanation originating from the mephit. Failure: 5 (2d4) Cold damage. Success: Half damage.\n### Actions\n- Claw. Melee Attack Roll: +3, reach 5 ft. Hit: 3 (1d4 + 1) Slashing damage plus 2 (1d4) Cold damage.\n- Fog Cloud (1/Day). The mephit casts Fog Cloud, requiring no spell components and using Charisma as the spellcasting ability.\n- Frost Breath (Recharge 6). Constitution Saving Throw: DC 10, each creature in a 15-foot Cone. Failure: 7 (3d4) Cold damage. Success: Half damage.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Ice Mephit","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Magma Mephit","constant":false,"content":"## Magma Mephit (monster stat block, SRD 5.2.1)\nSmall Elemental, Neutral Evil. AC 11, HP 18 (4d6+4), Initiative +1, Speed 30 ft., Fly 30 ft..\nAbilities: Str 8 (save -1), Dex 12 (save +1), Con 12 (save +1), Int 7 (save -2), Wis 10 (save +0), Cha 10 (save +0).\nCR 1/2 (XP 100, PB +2).\nSkills Stealth +3\nVulnerabilities Cold\nImmunities Fire, Poison; Exhaustion, Poisoned\nSenses Darkvision 60 ft.; Passive Perception 10\nLanguages Primordial (Ignan, Terran)\n### Traits\n- Death Burst. The mephit explodes when it dies. Dexterity Saving Throw: DC 11, each creature in a 5-foot Emanation originating from the mephit. Failure: 7 (2d6) Fire damage. Success: Half damage.\n### Actions\n- Claw. Melee Attack Roll: +3, reach 5 ft. Hit: 3 (1d4 + 1) Slashing damage plus 3 (1d6) Fire damage.\n- Fire Breath (Recharge 6). Dexterity Saving Throw: DC 11, each creature in a 15-foot Cone. Failure: 7 (2d6) Fire damage. Success: Half damage.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Magma Mephit","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Steam Mephit","constant":false,"content":"## Steam Mephit (monster stat block, SRD 5.2.1)\nSmall Elemental, Neutral Evil. AC 10, HP 17 (5d6), Initiative +0, Speed 30 ft., Fly 30 ft..\nAbilities: Str 5 (save -3), Dex 11 (save +0), Con 10 (save +0), Int 11 (save +0), Wis 10 (save +0), Cha 12 (save +1).\nCR 1/4 (XP 50, PB +2).\nSkills Stealth +2\nImmunities Fire, Poison; Exhaustion, Poisoned\nSenses Darkvision 60 ft.; Passive Perception 10\nLanguages Primordial (Aquan, Ignan)\n### Traits\n- Blurred Form. Attack rolls against the mephit are made with Disadvantage unless the mephit has the Incapacitated condition.\n- Death Burst. The mephit explodes when it dies. Dexterity Saving Throw: DC 10, each creature in a 5-foot Emanation originating from the mephit. Failure: 5 (2d4) Fire damage. Success: Half damage.\n### Actions\n- Claw. Melee Attack Roll: +2, reach 5 ft. Hit: 2 (1d4) Slashing damage plus 2 (1d4) Fire damage.\n- Steam Breath (Recharge 6). Constitution Saving Throw: DC 10, each creature in a 15-foot Cone. Failure: 5 (2d4) Fire damage, and the target's Speed decreases by 10 feet until the end of the mephit's next turn. Success: Half damage only. Failure or Success: Being underwater doesn't grant Resistance to this Fire damage.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Steam Mephit","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Merfolk Skirmisher","constant":false,"content":"## Merfolk Skirmisher (monster stat block, SRD 5.2.1)\nMedium Elemental, Neutral. AC 11, HP 11 (2d8+2), Initiative +1, Speed 10 ft., Swim 40 ft..\nAbilities: Str 10 (save +0), Dex 13 (save +1), Con 12 (save +1), Int 11 (save +0), Wis 14 (save +2), Cha 12 (save +1).\nCR 1/8 (XP 25, PB +2).\nSenses Passive Perception 12\nLanguages Common, Primordial (Aquan)\n### Traits\n- Amphibious. The merfolk can breathe air and water.\n### Actions\n- Ocean Spear. Melee or Ranged Attack Roll: +2, reach 5 ft. or range 20/60 ft. Hit: 3 (1d6) Piercing damage plus 2 (1d4) Cold damage. If the target is a creature, its Speed decreases by 10 feet until the end of its next turn. Hit or Miss: The spear magically returns to the merfolk's hand immediately after a ranged attack.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Merfolk Skirmisher","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Merrow","constant":false,"content":"## Merrow (monster stat block, SRD 5.2.1)\nLarge Monstrosity, Chaotic Evil. AC 13, HP 45 (6d10+12), Initiative +2, Speed 10 ft., Swim 40 ft..\nAbilities: Str 18 (save +4), Dex 15 (save +2), Con 15 (save +2), Int 8 (save -1), Wis 10 (save +0), Cha 9 (save -1).\nCR 2 (XP 450, PB +2).\nSenses Darkvision 60 ft.; Passive Perception 10\nLanguages Abyssal, Primordial (Aquan)\n### Traits\n- Amphibious. The merrow can breathe air and water.\n### Actions\n- Multiattack. The merrow makes two attacks, using Bite, Claw, or Harpoon in any combination.\n- Bite. Melee Attack Roll: +6, reach 5 ft. Hit: 6 (1d4 + 4) Piercing damage, and the target has the Poisoned condition until the end of the merrow's next turn.\n- Claw. Melee Attack Roll: +6, reach 5 ft. Hit: 9 (2d4 + 4) Slashing damage.\n- Harpoon. Melee or Ranged Attack Roll: +6, reach 5 ft. or range 20/60 ft. Hit: 11 (2d6 + 4) Piercing damage. If the target is a Large or smaller creature, the merrow pulls the target up to 15 feet straight toward itself.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Merrow","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Mimic","constant":false,"content":"## Mimic (monster stat block, SRD 5.2.1)\nMedium Monstrosity, Neutral. AC 12, HP 58 (9d8+18), Initiative +3, Speed 20 ft..\nAbilities: Str 17 (save +3), Dex 12 (save +1), Con 15 (save +2), Int 5 (save -3), Wis 13 (save +1), Cha 8 (save -1).\nCR 2 (XP 450, PB +2).\nSkills Stealth +5\nImmunities Acid; Prone\nSenses Darkvision 60 ft.; Passive Perception 11\nLanguages None\n### Traits\n- Adhesive (Object Form Only). The mimic adheres to anything that touches it. A Huge or smaller creature adhered to the mimic has the Grappled condition (escape DC 13). Ability checks made to escape this grapple have Disadvantage.\n### Actions\n- Bite. Melee Attack Roll: +5 (with Advantage if the target is Grappled by the mimic), reach 5 ft. Hit: 7 (1d8 + 3) Piercing damage—or 12 (2d8 + 3) Piercing damage if the target is Grappled by the mimic—plus 4 (1d8) Acid damage.\n- Pseudopod. Melee Attack Roll: +5, reach 5 ft. Hit: 7 (1d8 + 3) Bludgeoning damage plus 4 (1d8) Acid damage. If the target is a Large or smaller creature, it has the Grappled condition (escape DC 13). Ability checks made to escape this grapple have Disadvantage.\n### Bonus Actions\n- Shape-Shift. The mimic shape-shifts to resemble a Medium or Small object while retaining its game statistics, or it returns to its true blob form. Any equipment it is wearing or carrying isn't transformed.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Mimic","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Minotaur of Baphomet","constant":false,"content":"## Minotaur of Baphomet (monster stat block, SRD 5.2.1)\nLarge Monstrosity, Chaotic Evil. AC 14, HP 85 (10d10+30), Initiative +0, Speed 40 ft..\nAbilities: Str 18 (save +4), Dex 11 (save +0), Con 16 (save +3), Int 6 (save -2), Wis 16 (save +3), Cha 9 (save -1).\nCR 3 (XP 700, PB +2).\nSkills Perception +7, Survival +7\nSenses Darkvision 60 ft.; Passive Perception 17\nLanguages Abyssal\n### Actions\n- Abyssal Glaive. Melee Attack Roll: +6, reach 10 ft. Hit: 10 (1d12 + 4) Slashing damage plus 10 (3d6) Necrotic damage.\n- Gore (Recharge 5–6). Melee Attack Roll: +6, reach 5 ft. Hit: 18 (4d6 + 4) Piercing damage. If the target is a Large or smaller creature and the minotaur moved 10+ feet straight toward it immediately before the hit, the target takes an extra 10 (3d6) Piercing damage and has the Prone condition.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Minotaur of Baphomet","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Mummy","constant":false,"content":"## Mummy (monster stat block, SRD 5.2.1)\nMedium or Small Undead, Lawful Evil. AC 11, HP 58 (9d8+18), Initiative -1, Speed 20 ft..\nAbilities: Str 16 (save +3), Dex 8 (save -1), Con 15 (save +2), Int 6 (save -2), Wis 12 (save +3), Cha 12 (save +1).\nCR 3 (XP 700, PB +2).\nVulnerabilities Fire\nImmunities Necrotic, Poison; Charmed, Exhaustion, Frightened, Paralyzed, Poisoned\nSenses Darkvision 60 ft.; Passive Perception 11\nLanguages Common plus two other languages\n### Actions\n- Multiattack. The mummy makes two Rotting Fist attacks and uses Dreadful Glare.\n- Rotting Fist. Melee Attack Roll: +5, reach 5 ft. Hit: 8 (1d10 + 3) Bludgeoning damage plus 10 (3d6) Necrotic damage. If the target is a creature, it is cursed. While cursed, the target can't regain Hit Points, its Hit Point maximum doesn't return to normal when finishing a Long Rest, and its Hit Point maximum decreases by 10 (3d6) every 24 hours that elapse. A creature dies and turns to dust if reduced to 0 Hit Points by this attack.\n- Dreadful Glare. Wisdom Saving Throw: DC 11, one creature the mummy can see within 60 feet. Failure: The target has the Frightened condition until the end of the mummy's next turn. Success: The target is immune to this mummy's Dreadful Glare for 24 hours.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Mummy","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Mummy Lord","constant":false,"content":"## Mummy Lord (monster stat block, SRD 5.2.1)\nMedium or Small Undead (Cleric), Lawful Evil. AC 17, HP 187 (25d8+75), Initiative +10, Speed 30 ft..\nAbilities: Str 18 (save +4), Dex 10 (save +0), Con 17 (save +3), Int 11 (save +5), Wis 19 (save +9), Cha 16 (save +3).\nCR 15 (XP 13000, PB +5).\nSkills History +5, Perception +9, Religion +5\nVulnerabilities Fire\nImmunities Necrotic, Poison; Charmed, Exhaustion, Frightened, Paralyzed, Poisoned\nSenses Truesight 60 ft.; Passive Perception 19\nLanguages Common plus three other languages\n### Traits\n- Legendary Resistance (3/Day, or 4/Day in Lair). If the mummy fails a saving throw, it can choose to succeed instead.\n- Magic Resistance. The mummy has Advantage on saving throws against spells and other magical effects.\n- Undead Restoration. If destroyed, the mummy gains a new body in 24 hours if its heart is intact, reviving with all its Hit Points. The new body appears in an unoccupied space within the mummy's lair. The heart is a Tiny object that has AC 17, HP 10, and Immunity to all damage except Fire.\n### Actions\n- Multiattack. The mummy makes one Rotting Fist or Channel Negative Energy attack, and it uses Dreadful Glare.\n- Rotting Fist. Melee Attack Roll: +9, reach 5 ft. Hit: 15 (2d10 + 4) Bludgeoning damage plus 10 (3d6) Necrotic damage. If the target is a creature, it is cursed. While cursed, the target can't regain Hit Points, it gains no benefit from finishing a Long Rest, and its Hit Point maximum decreases by 10 (3d6) every 24 hours that elapse. A creature dies and turns to dust if reduced to 0 Hit Points by this attack.\n- Channel Negative Energy. Ranged Attack Roll: +9, range 60 ft. Hit: 25 (6d6 + 4) Necrotic damage.\n- Dreadful Glare. Wisdom Saving Throw: DC 17, one creature the mummy can see within 60 feet. Failure: 25 (6d6 + 4) Psychic damage, and the target has the Paralyzed condition until the end of the mummy's next turn.\n- Spellcasting. The mummy casts one of the following spells, requiring no Material components and using Wisdom as the spellcasting ability (spell save DC 17, +9 to hit with spell attacks): At Will: Dispel Magic, Thaumaturgy 1/Day Each: Animate Dead, Harm, Insect Plague (level 7 version)\n### Reactions\n- Whirlwind of Sand. Trigger: The mummy is hit by an attack roll. Response: The mummy adds 2 to its AC against the attack, possibly causing the attack to miss, and the mummy teleports up to 60 feet to an unoccupied space it can see. Each creature of its choice that it can see within 5 feet of its destination space has the Blinded condition until the end of the mummy's next turn.\n### Legendary Actions\n- Legendary Action Uses: 3 (4 in Lair). Immediately after another creature's turn, the mummy can expend a use to take one of the following actions. The mummy regains all expended uses at the start of each of its turns.\n- Dread Command. The mummy casts Command (level 2 version), using the same spellcasting ability as Spellcasting. The mummy can't take this action again until the start of its next turn.\n- Glare. The mummy uses Dreadful Glare. The mummy can't take this action again until the start of its next turn.\n- Necrotic Strike. The mummy makes one Rotting Fist or Channel Negative Energy attack.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Mummy Lord","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Nalfeshnee","constant":false,"content":"## Nalfeshnee (monster stat block, SRD 5.2.1)\nLarge Fiend (Demon), Chaotic Evil. AC 18, HP 184 (16d10+96), Initiative +5, Speed 20 ft., Fly 30 ft..\nAbilities: Str 21 (save +5), Dex 10 (save +0), Con 22 (save +11), Int 19 (save +9), Wis 12 (save +6), Cha 15 (save +7).\nCR 13 (XP 10000, PB +5).\nResistances Cold, Fire, Lightning\nImmunities Poison; Frightened, Poisoned\nSenses Truesight 120 ft.; Passive Perception 11\nLanguages Abyssal; telepathy 120 ft.\n### Traits\n- Demonic Restoration. If the nalfeshnee dies outside the Abyss, its body dissolves into ichor, and it gains a new body instantly, reviving with all its Hit Points somewhere in the Abyss.\n- Magic Resistance. The nalfeshnee has Advantage on saving throws against spells and other magical effects.\n### Actions\n- Multiattack. The nalfeshnee makes three Rend attacks.\n- Rend. Melee Attack Roll: +10, reach 10 ft. Hit: 16 (2d10 + 5) Slashing damage plus 11 (2d10) Force damage.\n- Teleport. The nalfeshnee teleports up to 120 feet to an unoccupied space it can see.\n### Bonus Actions\n- Horror Nimbus (Recharge 5–6). Wisdom Saving Throw: DC 15, each creature in a 15-foot Emanation originating from the nalfeshnee. Failure: 28 (8d6) Psychic damage, and the target has the Frightened condition for 1 minute, until it takes damage, or until it ends its turn with the nalfeshnee out of line of sight. Success: The target is immune to this nalfeshnee's Horror Nimbus for 24 hours.\n### Reactions\n- Pursuit. Trigger: Another creature the nalfeshnee can see ends its move within 120 feet of the nalfeshnee. Response: The nalfeshnee uses Teleport, but its destination space must be within 10 feet of the triggering creature.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Nalfeshnee","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Night Hag","constant":false,"content":"## Night Hag (monster stat block, SRD 5.2.1)\nMedium Fiend, Neutral Evil. AC 17, HP 112 (15d8+45), Initiative +5, Speed 30 ft..\nAbilities: Str 18 (save +4), Dex 15 (save +2), Con 16 (save +3), Int 16 (save +3), Wis 14 (save +2), Cha 16 (save +3).\nCR 5 (XP 1800, PB +3).\nSkills Deception +6, Insight +5, Perception +5, Stealth +5\nResistances Cold, Fire\nImmunities Charmed\nSenses Darkvision 120 ft.; Passive Perception 15\nLanguages Abyssal, Common, Infernal, Primordial\n### Traits\n- Coven Magic. While within 30 feet of at least two hag allies, the hag can cast one of the following spells, requiring no Material components, using the spell's normal casting time, and using Intelligence as the spellcasting ability (spell save DC 14): Augury, Find Familiar, Identify, Locate Object, Scrying, or Unseen Servant. The hag must finish a Long Rest before using this trait to cast that spell again.\n- Magic Resistance. The hag has Advantage on saving throws against spells and other magical effects.\n- Soul Bag. The hag has a soul bag. While holding or carrying the bag, the hag can use its Nightmare Haunting action. The bag has AC 15, HP 20, and Resistance to all damage. The bag turns to dust if reduced to 0 Hit Points. If the bag is destroyed, any souls the bag is holding are released. The hag can create a new bag after 7 days.\n### Actions\n- Multiattack. The hag makes two Claw attacks.\n- Claw. Melee Attack Roll: +7, reach 5 ft. Hit: 13 (2d8 + 4) Slashing damage.\n- Nightmare Haunting (1/Day; Requires Soul Bag). While on the Ethereal Plane, the hag casts Dream, using the same spellcasting ability as Spellcasting. Only the hag can serve as the spell's messenger, and the target must be a creature the hag can see on the Material Plane. The spell fails and is wasted if the target is under the effect of the Protection from Evil and Good spell or within a Magic Circle spell. If the target takes damage from the Dream spell, the target's Hit Point maximum decreases by an amount equal to that damage. If the spell kills the target, its soul is trapped in the hag's soul bag, and the target can't be raised from the dead until its soul is released.\n- Spellcasting. The hag casts one of the following spells, requiring no Material components and using Intelligence as the spellcasting ability (spell save DC 14): At Will: Detect Magic, Etherealness, Magic Missile (level 4 version) 2/Day Each: Phantasmal Killer, Plane Shift (self only)\n### Bonus Actions\n- Shape-Shift. The hag shape-shifts into a Small or Medium Humanoid, or it returns to its true form. Other than its size, its game statistics are the same in each form. Any equipment it is wearing or carrying isn't transformed.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Night Hag","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Nightmare","constant":false,"content":"## Nightmare (monster stat block, SRD 5.2.1)\nLarge Fiend, Neutral Evil. AC 13, HP 68 (8d10+24), Initiative +2, Speed 60 ft., Fly 90 ft. (hover).\nAbilities: Str 18 (save +4), Dex 15 (save +2), Con 16 (save +3), Int 10 (save +0), Wis 13 (save +1), Cha 15 (save +2).\nCR 3 (XP 700, PB +2).\nImmunities Fire\nSenses Passive Perception 11\nLanguages Understands Abyssal, Common, and Infernal but can't speak\n### Traits\n- Confer Fire Resistance. The nightmare can grant Resistance to Fire damage to a rider while it is on the nightmare.\n- Illumination. The nightmare sheds Bright Light in a 10foot radius and Dim Light for an additional 10 feet.\n### Actions\n- Hooves. Melee Attack Roll: +6, reach 5 ft. Hit: 13 (2d8 + 4) Bludgeoning damage plus 10 (3d6) Fire damage.\n- Ethereal Stride. The nightmare and up to three willing creatures within 5 feet of it teleport to the Ethereal Plane from the Material Plane or vice versa.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Nightmare","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Noble","constant":false,"content":"## Noble (monster stat block, SRD 5.2.1)\nMedium or Small Humanoid, Neutral. AC 15, HP 9 (2d8), Initiative +1, Speed 30 ft..\nAbilities: Str 11 (save +0), Dex 12 (save +1), Con 11 (save +0), Int 12 (save +1), Wis 14 (save +2), Cha 16 (save +3).\nCR 1/8 (XP 25, PB +2).\nSkills Deception +5, Insight +4, Persuasion +5\nGear Breastplate, Rapier\nSenses Passive Perception 12\nLanguages Common plus two other languages\n### Actions\n- Rapier. Melee Attack Roll: +3, reach 5 ft. Hit: 5 (1d8 + 1) Piercing damage.\n### Reactions\n- Parry. Trigger: The noble is hit by a melee attack roll while holding a weapon. Response: The noble adds 2 to its AC against that attack, possibly causing it to miss.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Noble","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Ochre Jelly","constant":false,"content":"## Ochre Jelly (monster stat block, SRD 5.2.1)\nLarge Ooze, Unaligned. AC 8, HP 52 (7d10+14), Initiative -2, Speed 20 ft., Climb 20 ft..\nAbilities: Str 15 (save +2), Dex 6 (save -2), Con 14 (save +2), Int 2 (save -4), Wis 6 (save -2), Cha 1 (save -5).\nCR 2 (XP 450, PB +2).\nResistances Acid\nImmunities Lightning, Slashing; Charmed, Deafened, Exhaustion, Frightened, Grappled, Prone, Restrained\nSenses Blindsight 60 ft.; Passive Perception 8\nLanguages None\n### Traits\n- Amorphous. The jelly can move through a space as narrow as 1 inch without expending extra movement to do so.\n- Spider Climb. The jelly can climb difficult surfaces, including along ceilings, without needing to make an ability check.\n### Actions\n- Pseudopod. Melee Attack Roll: +4, reach 5 ft. Hit: 12 (3d6 + 2) Acid damage.\n### Reactions\n- Split. Trigger: While the jelly is Large or Medium and has 10+ Hit Points, it becomes Bloodied or is subjected to Lightning or Slashing damage. Response: The jelly splits into two new Ochre Jellies. Each new jelly is one size smaller than the original jelly and acts on its Initiative. The original jelly's Hit Points are divided evenly between the new jellies (round down).","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Ochre Jelly","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Ogre","constant":false,"content":"## Ogre (monster stat block, SRD 5.2.1)\nLarge Giant, Chaotic Evil. AC 11, HP 68 (8d10+24), Initiative -1, Speed 40 ft..\nAbilities: Str 19 (save +4), Dex 8 (save -1), Con 16 (save +3), Int 5 (save -3), Wis 7 (save -2), Cha 7 (save -2).\nCR 2 (XP 450, PB +2).\nGear Greatclub, Javelins (3)\nSenses Darkvision 60 ft.; Passive Perception 8\nLanguages Common, Giant\n### Actions\n- Greatclub. Melee Attack Roll: +6, reach 5 ft. Hit: 13 (2d8 + 4) Bludgeoning damage.\n- Javelin. Melee or Ranged Attack Roll: +6, reach 5 ft. or range 30/120 ft. Hit: 11 (2d6 + 4) Piercing damage.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Ogre","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Oni","constant":false,"content":"## Oni (monster stat block, SRD 5.2.1)\nLarge Fiend, Lawful Evil. AC 17, HP 119 (14d10+42), Initiative +0, Speed 30 ft., Fly 30 ft. (hover).\nAbilities: Str 19 (save +4), Dex 11 (save +3), Con 16 (save +6), Int 14 (save +2), Wis 12 (save +4), Cha 15 (save +5).\nCR 7 (XP 2900, PB +3).\nSkills Arcana +5, Deception +8, Perception +4\nResistances Cold\nSenses Darkvision 60 ft.; Passive Perception 14\nLanguages Common, Giant\n### Traits\n- Regeneration. The oni regains 10 Hit Points at the start of each of its turns if it has at least 1 Hit Point.\n### Actions\n- Multiattack. The oni makes two Claw or Nightmare Ray attacks. It can replace one attack with a use of Spellcasting.\n- Claw. Melee Attack Roll: +7, reach 10 ft. Hit: 10 (1d12 + 4) Slashing damage plus 9 (2d8) Necrotic damage.\n- Nightmare Ray. Ranged Attack Roll: +5, range 60 ft. Hit: 9 (2d6 + 2) Psychic damage, and the target has the Frightened condition until the start of the oni's next turn.\n- Shape-Shift. The oni shape-shifts into a Small or Medium Humanoid or a Large Giant, or it returns to its true form. Other than its size, its game statistics are the same in each form. Any equipment it is wearing or carrying isn't transformed.\n- Spellcasting. The oni casts one of the following spells, requiring no Material components and using Charisma as the spellcasting ability (spell save DC 13): 1/Day Each: Charm Person (level 2 version), Darkness, Gaseous Form, Sleep\n### Bonus Actions\n- Invisibility. The oni casts Invisibility on itself, requiring no spell components and using the same spellcasting ability as Spellcasting.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Oni","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Otyugh","constant":false,"content":"## Otyugh (monster stat block, SRD 5.2.1)\nLarge Aberration, Neutral. AC 14, HP 104 (11d10+44), Initiative +0, Speed 30 ft..\nAbilities: Str 16 (save +3), Dex 11 (save +0), Con 19 (save +7), Int 6 (save -2), Wis 13 (save +1), Cha 6 (save -2).\nCR 5 (XP 1800, PB +3).\nSenses Darkvision 120 ft.; Passive Perception 11\nLanguages Otyugh; telepathy 120 ft. (doesn't allow the receiving creature to respond telepathically)\n### Actions\n- Multiattack. The otyugh makes one Bite attack and two Tentacle attacks.\n- Bite. Melee Attack Roll: +6, reach 5 ft. Hit: 12 (2d8 + 3) Piercing damage, and the target has the Poisoned condition. Whenever the Poisoned target finishes a Long Rest, it is subjected to the following effect. Constitution Saving Throw: DC 15. Failure: The target's Hit Point maximum decreases by 5 (1d10) and doesn't return to normal until the Poisoned condition ends on the target. Success: The Poisoned condition ends.\n- Tentacle. Melee Attack Roll: +6, reach 10 ft. Hit: 12 (2d8 + 3) Piercing damage. If the target is a Medium or smaller creature, it has the Grappled condition (escape DC 13) from one of two tentacles.\n- Tentacle Slam. Constitution Saving Throw: DC 14, each creature Grappled by the otyugh. Failure: 16 (3d8 + 3) Bludgeoning damage, and the target has the Stunned condition until the start of the otyugh's next turn. Success: Half damage only.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Otyugh","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Owlbear","constant":false,"content":"## Owlbear (monster stat block, SRD 5.2.1)\nLarge Monstrosity, Unaligned. AC 13, HP 59 (7d10+21), Initiative +1, Speed 40 ft., Climb 40 ft..\nAbilities: Str 20 (save +5), Dex 12 (save +1), Con 17 (save +3), Int 3 (save -4), Wis 12 (save +1), Cha 7 (save -2).\nCR 3 (XP 700, PB +2).\nSkills Perception +5\nSenses Darkvision 60 ft.; Passive Perception 15\nLanguages None\n### Actions\n- Multiattack. The owlbear makes two Rend attacks.\n- Rend. Melee Attack Roll: +7, reach 5 ft. Hit: 14 (2d8 + 5) Slashing damage.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Owlbear","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Pegasus","constant":false,"content":"## Pegasus (monster stat block, SRD 5.2.1)\nLarge Celestial, Chaotic Good. AC 12, HP 59 (7d10+21), Initiative +2, Speed 60 ft., Fly 90 ft..\nAbilities: Str 18 (save +4), Dex 15 (save +4), Con 16 (save +5), Int 10 (save +0), Wis 15 (save +4), Cha 13 (save +3).\nCR 2 (XP 450, PB +2).\nSkills Perception +6\nSenses Passive Perception 16\nLanguages Understands Celestial, Common, Elvish, and Sylvan but can't speak\n### Actions\n- Hooves. Melee Attack Roll: +6, reach 5 ft. Hit: 7 (1d6 + 4) Bludgeoning damage plus 5 (2d4) Radiant damage.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Pegasus","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Phase Spider","constant":false,"content":"## Phase Spider (monster stat block, SRD 5.2.1)\nLarge Monstrosity, Unaligned. AC 14, HP 45 (7d10+7), Initiative +3, Speed 30 ft., Climb 30 ft..\nAbilities: Str 15 (save +2), Dex 16 (save +3), Con 12 (save +1), Int 6 (save -2), Wis 10 (save +0), Cha 6 (save -2).\nCR 3 (XP 700, PB +2).\nSkills Stealth +7\nSenses Darkvision 60 ft.; Passive Perception 10\nLanguages None\n### Traits\n- Ethereal Sight. The spider can see 60 feet into the Ethereal Plane while on the Material Plane and vice versa.\n- Spider Climb. The spider can climb difficult surfaces, including along ceilings, without needing to make an ability check.\n- Web Walker. The spider ignores movement restrictions caused by webs, and the spider knows the location of any other creature in contact with the same web.\n### Actions\n- Multiattack. The spider makes two Bite attacks.\n- Bite. Melee Attack Roll: +5, reach 5 ft. Hit: 8 (1d10 + 3) Piercing damage plus 9 (2d8) Poison damage. If this damage reduces the target to 0 Hit Points, the target becomes Stable, and it has the Poisoned condition for 1 hour. While Poisoned, the target also has the Paralyzed condition.\n### Bonus Actions\n- Ethereal Jaunt. The spider teleports from the Material Plane to the Ethereal Plane or vice versa.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Phase Spider","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Pirate","constant":false,"content":"## Pirate (monster stat block, SRD 5.2.1)\nMedium or Small Humanoid, Neutral. AC 14, HP 33 (6d8+6), Initiative +5, Speed 30 ft..\nAbilities: Str 10 (save +0), Dex 16 (save +5), Con 12 (save +1), Int 8 (save -1), Wis 12 (save +1), Cha 14 (save +4).\nCR 1 (XP 200, PB +2).\nGear Daggers (6), Leather Armor\nSenses Passive Perception 11\nLanguages Common plus one other language\n### Actions\n- Multiattack. The pirate makes two Dagger attacks. It can replace one attack with a use of Enthralling Panache.\n- Dagger. Melee or Ranged Attack Roll: +5, reach 5 ft. or range 20/60 ft. Hit: 5 (1d4 + 3) Piercing damage.\n- Enthralling Panache. Wisdom Saving Throw: DC 12, one creature the pirate can see within 30 feet. Failure: The target has the Charmed condition until the start of the pirate's next turn.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Pirate","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Pirate Captain","constant":false,"content":"## Pirate Captain (monster stat block, SRD 5.2.1)\nMedium or Small Humanoid, Neutral. AC 17, HP 84 (13d8+26), Initiative +7, Speed 30 ft..\nAbilities: Str 10 (save +3), Dex 18 (save +7), Con 14 (save +2), Int 10 (save +0), Wis 14 (save +5), Cha 17 (save +6).\nCR 6 (XP 2300, PB +3).\nSkills Acrobatics +7, Perception +5\nGear Pistol, Rapier\nSenses Passive Perception 15\nLanguages Common plus one other language\n### Actions\n- Multiattack. The pirate makes three attacks, using Rapier or Pistol in any combination.\n- Rapier. Melee Attack Roll: +7, reach 5 ft. Hit: 13 (2d8 + 4) Piercing damage, and the pirate has Advantage on the next attack roll it makes before the end of this turn.\n- Pistol. Ranged Attack Roll: +7, range 30/90 ft. Hit: 15 (2d10 + 4) Piercing damage.\n### Bonus Actions\n- Captain's Charm. Wisdom Saving Throw: DC 14, one creature the pirate can see within 30 feet. Failure: The target has the Charmed condition until the start of the pirate's next turn.\n### Reactions\n- Riposte. Trigger: The pirate is hit by a melee attack roll while holding a weapon. Response: The pirate adds 3 to its AC against that attack, possibly causing it to miss. On a miss, the pirate makes one Rapier attack against the triggering creature if within range.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Pirate Captain","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Pit Fiend","constant":false,"content":"## Pit Fiend (monster stat block, SRD 5.2.1)\nLarge Fiend (Devil), Lawful Evil. AC 21, HP 337 (27d10+189), Initiative +14, Speed 30 ft., Fly 60 ft..\nAbilities: Str 26 (save +8), Dex 14 (save +8), Con 24 (save +7), Int 22 (save +6), Wis 18 (save +10), Cha 24 (save +7).\nCR 20 (XP 25000, PB +6).\nSkills Perception +10, Persuasion +19\nResistances Cold\nImmunities Fire, Poison; Poisoned\nSenses Truesight 120 ft.; Passive Perception 20\nLanguages Infernal; telepathy 120 ft.\n### Traits\n- Diabolical Restoration. If the pit fiend dies outside the Nine Hells, its body disappears in sulfurous smoke, and it gains a new body instantly, reviving with all its Hit Points somewhere in the Nine Hells.\n- Fear Aura. The pit fiend emanates an aura in a 20foot Emanation while it doesn't have the Incapacitated condition. Wisdom Saving Throw: DC 21, any enemy that starts its turn in the aura. Failure: The target has the Frightened condition until the start of its next turn. Success: The target is immune to this pit fiend's aura for 24 hours.\n- Legendary Resistance (4/Day). If the pit fiend fails a saving throw, it can choose to succeed instead.\n- Magic Resistance. The pit fiend has Advantage on saving throws against spells and other magical effects.\n### Actions\n- Multiattack. The pit fiend makes one Bite attack, two Devilish Claw attacks, and one Fiery Mace attack.\n- Bite. Melee Attack Roll: +14, reach 10 ft. Hit: 18 (3d6 + 8) Piercing damage. If the target is a creature, it must make the following saving throw. Constitution Saving Throw: DC 21. Failure: The target has the Poisoned condition. While Poisoned, the target can't regain Hit Points and takes 21 (6d6) Poison damage at the start of each of its turns, and it repeats the save at the end of each of its turns, ending the effect on itself on a success. After 1 minute, it succeeds automatically.\n- Devilish Claw. Melee Attack Roll: +14, reach 10 ft. Hit: 26 (4d8 + 8) Necrotic damage.\n- Fiery Mace. Melee Attack Roll: +14, reach 10 ft. Hit: 22 (4d6 + 8) Force damage plus 21 (6d6) Fire damage.\n- Hellfire Spellcasting (Recharge 4–6). The pit fiend casts Fireball (level 5 version) twice, requiring no Material components and using Charisma as the spellcasting ability (spell save DC 21). It can replace one Fireball with Hold Monster (level 7 version) or Wall of Fire.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Pit Fiend","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Planetar","constant":false,"content":"## Planetar (monster stat block, SRD 5.2.1)\nLarge Celestial (Angel), Lawful Good. AC 19, HP 262 (21d10+147), Initiative +10, Speed 40 ft., Fly 120 ft. (hover).\nAbilities: Str 24 (save +12), Dex 20 (save +5), Con 24 (save +12), Int 19 (save +4), Wis 22 (save +11), Cha 25 (save +12).\nCR 16 (XP 15000, PB +5).\nSkills Perception +11\nResistances Radiant\nImmunities Charmed, Exhaustion, Frightened\nSenses Truesight 120 ft.; Passive Perception 21\nLanguages All; telepathy 120 ft.\n### Traits\n- Divine Awareness. The planetar knows if it hears a lie.\n- Exalted Restoration. If the planetar dies outside Mount Celestia, its body disappears, and it gains a new body instantly, reviving with all its Hit Points somewhere in Mount Celestia.\n- Magic Resistance. The planetar has Advantage on saving throws against spells and other magical effects.\n### Actions\n- Multiattack. The planetar makes three Radiant Sword attacks or uses Holy Burst twice.\n- Radiant Sword. Melee Attack Roll: +12, reach 10 ft. Hit: 14 (2d6 + 7) Slashing damage plus 18 (4d8) Radiant damage.\n- Holy Burst. Dexterity Saving Throw: DC 20, each enemy in a 20-foot-radius Sphere centered on a point the planetar can see within 120 feet. Failure: 24 (7d6) Radiant damage. Success: Half damage.\n- Spellcasting. The planetar casts one of the following spells, requiring no Material components and using Charisma as spellcasting ability (spell save DC 20): At Will: Detect Evil and Good 1/Day Each: Commune, Control Weather, Dispel Evil and Good, Raise Dead\n### Bonus Actions\n- Divine Aid (2/Day). The planetar casts Cure Wounds, Invisibility, Lesser Restoration, or Remove Curse, using the same spellcasting ability as Spellcasting.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Planetar","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Priest Acolyte","constant":false,"content":"## Priest Acolyte (monster stat block, SRD 5.2.1)\nMedium or Small Humanoid (Cleric), Neutral. AC 13, HP 11 (2d8+2), Initiative +0, Speed 30 ft..\nAbilities: Str 14 (save +2), Dex 10 (save +0), Con 12 (save +1), Int 10 (save +0), Wis 14 (save +2), Cha 11 (save +0).\nCR 1/4 (XP 50, PB +2).\nSkills Medicine +4, Religion +2\nGear Chain Shirt, Holy Symbol, Mace\nSenses Passive Perception 12\nLanguages Common\n### Actions\n- Mace. Melee Attack Roll: +4, reach 5 ft. Hit: 5 (1d6 + 2) Bludgeoning damage plus 2 (1d4) Radiant damage.\n- Radiant Flame. Ranged Attack Roll: +4, range 60 ft. Hit: 7 (2d6) Radiant damage.\n- Spellcasting. The priest casts one of the following spells, using Wisdom as the spellcasting ability: At Will: Light, Thaumaturgy\n### Bonus Actions\n- Divine Aid (1/Day). The priest casts Bless, Healing Word, or Sanctuary, using the same spellcasting ability as Spellcasting.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Priest Acolyte","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Priest","constant":false,"content":"## Priest (monster stat block, SRD 5.2.1)\nMedium or Small Humanoid (Cleric), Neutral. AC 13, HP 38 (7d8+7), Initiative +0, Speed 30 ft..\nAbilities: Str 16 (save +3), Dex 10 (save +0), Con 12 (save +1), Int 13 (save +1), Wis 16 (save +3), Cha 13 (save +1).\nCR 2 (XP 450, PB +2).\nSkills Medicine +7, Perception +5, Religion +5\nGear Chain Shirt, Holy Symbol, Mace\nSenses Passive Perception 15\nLanguages Common plus one other language\n### Actions\n- Multiattack. The priest makes two attacks, using Mace or Radiant Flame in any combination.\n- Mace. Melee Attack Roll: +5, reach 5 ft. Hit: 6 (1d6 + 3) Bludgeoning damage plus 5 (2d4) Radiant damage.\n- Radiant Flame. Ranged Attack Roll: +5, range 60 ft. Hit: 11 (2d10) Radiant damage.\n- Spellcasting. The priest casts one of the following spells, using Wisdom as the spellcasting ability (spell save DC 13): At Will: Light, Thaumaturgy 1/Day: Spirit Guardians\n### Bonus Actions\n- Divine Aid (3/Day). The priest casts Bless, Dispel Magic, Healing Word, or Lesser Restoration, using the same spellcasting ability as Spellcasting.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Priest","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Pseudodragon","constant":false,"content":"## Pseudodragon (monster stat block, SRD 5.2.1)\nTiny Dragon, Neutral Good. AC 14, HP 10 (3d4+3), Initiative +2, Speed 15 ft., Fly 60 ft..\nAbilities: Str 6 (save -2), Dex 15 (save +2), Con 13 (save +1), Int 10 (save +0), Wis 12 (save +1), Cha 10 (save +0).\nCR 1/4 (XP 50, PB +2).\nSkills Perception +5, Stealth +4\nSenses Blindsight 10 ft., Darkvision 60 ft.; Passive Perception 15\nLanguages Understands Common and Draconic but can't speak\n### Traits\n- Magic Resistance. The pseudodragon has Advantage on saving throws against spells and other magical effects.\n### Actions\n- Multiattack. The pseudodragon makes two Bite attacks.\n- Bite. Melee Attack Roll: +4, reach 5 ft. Hit: 4 (1d4 + 2) Piercing damage.\n- Sting. Constitution Saving Throw: DC 12, one creature the pseudodragon can see within 5 feet. Failure: 5 (2d4) Poison damage, and the target has the Poisoned condition for 1 hour. Failure by 5 or More: While Poisoned, the target also has the Unconscious condition, which ends early if the target takes damage or a creature within 5 feet of it takes an action to wake it.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Pseudodragon","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Purple Worm","constant":false,"content":"## Purple Worm (monster stat block, SRD 5.2.1)\nGargantuan Monstrosity, Unaligned. AC 18, HP 247 (15d20+90), Initiative +3, Speed 50 ft., Burrow 50 ft..\nAbilities: Str 28 (save +9), Dex 7 (save -2), Con 22 (save +11), Int 1 (save -5), Wis 8 (save +4), Cha 4 (save -3).\nCR 15 (XP 13000, PB +5).\nSenses Blindsight 30 ft., Tremorsense 60 ft.; Passive Perception 9\nLanguages None\n### Traits\n- Tunneler. The worm can burrow through solid rock at half its Burrow Speed and leaves a 10-foot-diameter tunnel in its wake.\n### Actions\n- Multiattack. The worm makes one Bite attack and one Tail Stinger attack.\n- Bite. Melee Attack Roll: +14, reach 10 ft. Hit: 22 (3d8 + 9) Piercing damage. If the target is a Large or smaller creature, it has the Grappled condition (escape DC 19), and it has the Restrained condition until the grapple ends.\n- Tail Stinger. Melee Attack Roll: +14, reach 10 ft. Hit: 16 (2d6 + 9) Piercing damage plus 35 (10d6) Poison damage.\n### Bonus Actions\n- Swallow. Strength Saving Throw: DC 19, one Large or smaller creature Grappled by the worm (it can have up to three creatures swallowed at a time). Failure: The target is swallowed by the worm, and the Grappled condition ends. A swallowed creature has the Blinded and Restrained conditions, has Total Cover against attacks and other effects outside the worm, and takes 17 (5d6) Acid damage at the start of each of the worm's turns. If the worm takes 30 damage or more on a single turn from a creature inside it, the worm must succeed on a DC 21 Constitution saving throw at the end of that turn or regurgitate all swallowed creatures, each of which falls in a space within 5 feet of the worm and has the Prone condition. If the worm dies, any swallowed creature no longer has the Restrained condition and can escape from the corpse using 20 feet of movement, exiting Prone.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Purple Worm","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Quasit","constant":false,"content":"## Quasit (monster stat block, SRD 5.2.1)\nTiny Fiend (Demon), Chaotic Evil. AC 13, HP 25 (10d4), Initiative +3, Speed 40 ft..\nAbilities: Str 5 (save -3), Dex 17 (save +3), Con 10 (save +0), Int 7 (save -2), Wis 10 (save +0), Cha 10 (save +0).\nCR 1 (XP 200, PB +2).\nSkills Stealth +5\nResistances Cold, Fire, Lightning\nImmunities Poison; Poisoned\nSenses Darkvision 120 ft.; Passive Perception 10\nLanguages Abyssal, Common\n### Traits\n- Magic Resistance. The quasit has Advantage on saving throws against spells and other magical effects.\n### Actions\n- Rend. Melee Attack Roll: +5, reach 5 ft. Hit: 5 (1d4 + 3) Slashing damage, and the target has the Poisoned condition until the start of the quasit's next turn.\n- Invisibility. The quasit casts Invisibility on itself, requiring no spell components and using Charisma as the spellcasting ability.\n- Scare (1/Day). Wisdom Saving Throw: DC 10, one creature within 20 feet. Failure: The target has the Frightened condition. At the end of each of its turns, the target repeats the save, ending the effect on itself on a success. After 1 minute, it succeeds automatically.\n- Shape-Shift. The quasit shape-shifts to resemble a bat (Speed 10 ft., Fly 40 ft.), a centipede (40 ft., Climb 40 ft.), or a toad (40 ft., Swim 40 ft.), or it returns to its true form. Its game statistics are the same in each form, except for its Speed. Any equipment it is wearing or carrying isn't transformed.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Quasit","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Rakshasa","constant":false,"content":"## Rakshasa (monster stat block, SRD 5.2.1)\nMedium Fiend, Lawful Evil. AC 17, HP 221 (26d8+104), Initiative +8, Speed 40 ft..\nAbilities: Str 14 (save +2), Dex 17 (save +3), Con 18 (save +4), Int 13 (save +1), Wis 16 (save +3), Cha 20 (save +5).\nCR 13 (XP 10000, PB +5).\nSkills Deception +10, Insight +8, Perception +8\nVulnerabilities Piercing damage from weapons wielded by creatures under the effect of a Bless spell\nImmunities Charmed, Frightened\nSenses Truesight 60 ft.; Passive Perception 18\nLanguages Common, Infernal\n### Traits\n- Greater Magic Resistance. The rakshasa automatically succeeds on saving throws against spells and other magical effects, and the attack rolls of spells automatically miss it. Without the rakshasa's permission, no spell can observe the rakshasa remotely or detect its thoughts, creature type, or alignment.\n- Fiendish Restoration. If the rakshasa dies outside the Nine Hells, its body turns to ichor, and it gains a new body instantly, reviving with all its Hit Points somewhere in the Nine Hells.\n### Actions\n- Multiattack. The rakshasa makes three Cursed Touch attacks.\n- Cursed Touch. Melee Attack Roll: +10, reach 5 ft. Hit: 12 (2d6 + 5) Slashing damage plus 19 (3d12) Necrotic damage. If the target is a creature, it is cursed. While cursed, the target gains no benefit from finishing a Short or Long Rest.\n- Baleful Command (Recharge 5–6). Wisdom Saving Throw: DC 18, each enemy in a 30-foot Emanation originating from the rakshasa. Failure: 28 (8d6) Psychic damage, and the target has the Frightened and Incapacitated conditions until the start of the rakshasa's next turn.\n- Spellcasting. The rakshasa casts one of the following spells, requiring no Material components and using Charisma as the spellcasting ability (spell save DC 18): At Will: Detect Magic, Detect Thoughts, Disguise Self, Mage Hand, Minor Illusion 1/Day Each: Fly, Invisibility, Major Image, Plane Shift","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Rakshasa","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Red Dragon Wyrmling","constant":false,"content":"## Red Dragon Wyrmling (monster stat block, SRD 5.2.1)\nMedium Dragon (Chromatic), Chaotic Evil. AC 17, HP 75 (10d8+30), Initiative +2, Speed 30 ft., Climb 30 ft., Fly 60 ft..\nAbilities: Str 19 (save +4), Dex 10 (save +2), Con 17 (save +3), Int 12 (save +1), Wis 11 (save +2), Cha 15 (save +2).\nCR 4 (XP 1100, PB +2).\nSkills Perception +4, Stealth +2\nImmunities Fire\nSenses Blindsight 10 ft., Darkvision 60 ft.; Passive Perception 14\nLanguages Draconic\n### Actions\n- Multiattack. The dragon makes two Rend attacks.\n- Rend. Melee Attack Roll: +6, reach 5 ft. Hit: 9 (1d10 + 4) Slashing damage plus 3 (1d6) Fire damage.\n- Fire Breath (Recharge 5–6). Dexterity Saving Throw: DC 13, each creature in a 15-foot Cone. Failure: 24 (7d6) Fire damage. Success: Half damage.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Red Dragon Wyrmling","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Young Red Dragon","constant":false,"content":"## Young Red Dragon (monster stat block, SRD 5.2.1)\nLarge Dragon (Chromatic), Chaotic Evil. AC 18, HP 178 (17d10+85), Initiative +4, Speed 40 ft., Climb 40 ft., Fly 80 ft..\nAbilities: Str 23 (save +6), Dex 10 (save +4), Con 21 (save +5), Int 14 (save +2), Wis 11 (save +4), Cha 19 (save +4).\nCR 10 (XP 5900, PB +4).\nSkills Perception +8, Stealth +4\nImmunities Fire\nSenses Blindsight 30 ft., Darkvision 120 ft.; Passive Perception 18\nLanguages Common, Draconic\n### Actions\n- Multiattack. The dragon makes three Rend attacks.\n- Rend. Melee Attack Roll: +10, reach 10 ft. Hit: 13 (2d6 + 6) Slashing damage plus 3 (1d6) Fire damage.\n- Fire Breath (Recharge 5–6). Dexterity Saving Throw: DC 17, each creature in a 30-foot Cone. Failure: 56 (16d6) Fire damage. Success: Half damage.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Young Red Dragon","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Adult Red Dragon","constant":false,"content":"## Adult Red Dragon (monster stat block, SRD 5.2.1)\nHuge Dragon (Chromatic), Chaotic Evil. AC 19, HP 256 (19d12+133), Initiative +12, Speed 40 ft., Climb 40 ft., Fly 80 ft..\nAbilities: Str 27 (save +8), Dex 10 (save +6), Con 25 (save +7), Int 16 (save +3), Wis 13 (save +7), Cha 23 (save +6).\nCR 17 (XP 18000, PB +6).\nSkills Perception +13, Stealth +6\nImmunities Fire\nSenses Blindsight 60 ft., Darkvision 120 ft.; Passive Perception 23\nLanguages Common, Draconic\n### Traits\n- Legendary Resistance (3/Day, or 4/Day in Lair). If the dragon fails a saving throw, it can choose to succeed instead.\n### Actions\n- Multiattack. The dragon makes three Rend attacks. It can replace one attack with a use of Spellcasting to cast Scorching Ray.\n- Rend. Melee Attack Roll: +14, reach 10 ft. Hit: 13 (1d10 + 8) Slashing damage plus 5 (2d4) Fire damage.\n- Fire Breath (Recharge 5–6). Dexterity Saving Throw: DC 21, each creature in a 60-foot Cone. Failure: 59 (17d6) Fire damage. Success: Half damage.\n- Spellcasting. The dragon casts one of the following spells, requiring no Material components and using Charisma as the spellcasting ability (spell save DC 20, +12 to hit with spell attacks): At Will: Command (level 2 version), Detect Magic, Scorching Ray 1/Day: Fireball\n### Legendary Actions\n- Legendary Action Uses: 3 (4 in Lair). Immediately after another creature's turn, the dragon can expend a use to take one of the following actions. The dragon regains all expended uses at the start of each of its turns.\n- Commanding Presence. The dragon uses Spellcasting to cast Command (level 2 version). The dragon can't take this action again until the start of its next turn.\n- Fiery Rays. The dragon uses Spellcasting to cast Scorching Ray. The dragon can't take this action again until the start of its next turn.\n- Pounce. The dragon moves up to half its Speed, and it makes one Rend attack.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Adult Red Dragon","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Ancient Red Dragon","constant":false,"content":"## Ancient Red Dragon (monster stat block, SRD 5.2.1)\nGargantuan Dragon (Chromatic), Chaotic Evil. AC 22, HP 507 (26d20+234), Initiative +14, Speed 40 ft., Climb 40 ft., Fly 80 ft..\nAbilities: Str 30 (save +10), Dex 10 (save +7), Con 29 (save +9), Int 18 (save +4), Wis 15 (save +9), Cha 27 (save +8).\nCR 24 (XP 62000, PB +7).\nSkills Perception +16, Stealth +7\nImmunities Fire\nSenses Blindsight 60 ft., Darkvision 120 ft.; Passive Perception 26\nLanguages Common, Draconic\n### Traits\n- Legendary Resistance (4/Day, or 5/Day in Lair). If the dragon fails a saving throw, it can choose to succeed instead.\n### Actions\n- Multiattack. The dragon makes three Rend attacks. It can replace one attack with a use of Spellcasting to cast Scorching Ray (level 3 version).\n- Rend. Melee Attack Roll: +17, reach 15 ft. Hit: 19 (2d8 + 10) Slashing damage plus 10 (3d6) Fire damage.\n- Fire Breath (Recharge 5–6). Dexterity Saving Throw: DC 24, each creature in a 90-foot Cone. Failure: 91 (26d6) Fire damage. Success: Half damage.\n- Spellcasting. The dragon casts one of the following spells, requiring no Material components and using Charisma as the spellcasting ability (spell save DC 23, +15 to hit with spell attacks): At Will: Command (level 2 version), Detect Magic, Scorching Ray (level 3 version) 1/Day Each: Fireball (level 6 version), Scrying\n### Legendary Actions\n- Legendary Action Uses: 3 (4 in Lair). Immediately after another creature's turn, the dragon can expend a use to take one of the following actions. The dragon regains all expended uses at the start of each of its turns.\n- Commanding Presence. The dragon uses Spellcasting to cast Command (level 2 version). The dragon can't take this action again until the start of its next turn.\n- Fiery Rays. The dragon uses Spellcasting to cast Scorching Ray (level 3 version). The dragon can't take this action again until the start of its next turn.\n- Pounce. The dragon moves up to half its Speed, and it makes one Rend attack.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Ancient Red Dragon","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Remorhaz","constant":false,"content":"## Remorhaz (monster stat block, SRD 5.2.1)\nHuge Monstrosity, Unaligned. AC 17, HP 195 (17d12+85), Initiative +5, Speed 40 ft., Burrow 30 ft..\nAbilities: Str 24 (save +7), Dex 13 (save +1), Con 21 (save +5), Int 4 (save -3), Wis 10 (save +0), Cha 5 (save -3).\nCR 11 (XP 7200, PB +4).\nImmunities Cold, Fire\nSenses Darkvision 60 ft., Tremorsense 60 ft.; Passive Perception 10\nLanguages None\n### Traits\n- Heat Aura. At the end of each of the remorhaz's turns, each creature in a 5-foot Emanation originating from the remorhaz takes 16 (3d10) Fire damage.\n### Actions\n- Bite. Melee Attack Roll: +11, reach 10 ft. Hit: 18 (2d10 + 7) Piercing damage plus 14 (4d6) Fire damage. If the target is a Large or smaller creature, it has the Grappled condition (escape DC 17), and it has the Restrained condition until the grapple ends.\n### Bonus Actions\n- Swallow. Strength Saving Throw: DC 19, one Large or smaller creature Grappled by the remorhaz (it can have up to two creatures swallowed at a time). Failure: The target is swallowed by the remorhaz, and the Grappled condition ends. A swallowed creature has the Blinded and Restrained conditions, it has Total Cover against attacks and other effects outside the remorhaz, and it takes 10 (3d6) Acid damage plus 10 (3d6) Fire damage at the start of each of the remorhaz's turns. If the remorhaz takes 30 damage or more on a single turn from a creature inside it, the remorhaz must succeed on a DC 15 Constitution saving throw at the end of that turn or regurgitate all swallowed creatures, each of which falls in a space within 5 feet of the remorhaz and has the Prone condition. If the remorhaz dies, any swallowed creature no longer has the Restrained condition and can escape from the corpse by using 15 feet of movement, exiting Prone.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Remorhaz","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Roc","constant":false,"content":"## Roc (monster stat block, SRD 5.2.1)\nGargantuan Monstrosity, Unaligned. AC 15, HP 248 (16d20+80), Initiative +8, Speed 20 ft., Fly 120 ft..\nAbilities: Str 28 (save +9), Dex 10 (save +4), Con 20 (save +5), Int 3 (save -4), Wis 10 (save +4), Cha 9 (save -1).\nCR 11 (XP 7200, PB +4).\nSkills Perception +8\nSenses Passive Perception 18\nLanguages None\n### Actions\n- Multiattack. The roc makes two Beak attacks. It can replace one attack with a Talons attack.\n- Beak. Melee Attack Roll: +13, reach 10 ft. Hit: 28 (3d12 + 9) Piercing damage.\n- Talons. Melee Attack Roll: +13, reach 5 ft. Hit: 23 (4d6 + 9) Slashing damage. If the target is a Huge or smaller creature, it has the Grappled condition (escape DC 19) from both talons, and it has the Restrained condition until the grapple ends.\n### Bonus Actions\n- Swoop (Recharge 5–6). If the roc has a creature Grappled, the roc flies up to half its Fly Speed without provoking Opportunity Attacks and drops that creature.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Roc","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Roper","constant":false,"content":"## Roper (monster stat block, SRD 5.2.1)\nLarge Aberration, Neutral Evil. AC 20, HP 93 (11d10+33), Initiative +5, Speed 10 ft., Climb 20 ft..\nAbilities: Str 18 (save +4), Dex 8 (save -1), Con 17 (save +3), Int 7 (save -2), Wis 16 (save +3), Cha 6 (save -2).\nCR 5 (XP 1800, PB +3).\nSkills Perception +6, Stealth +5\nSenses Darkvision 60 ft.; Passive Perception 16\nLanguages None\n### Traits\n- Spider Climb. The roper can climb difficult surfaces, including along ceilings, without needing to make an ability check.\n### Actions\n- Multiattack. The roper makes two Tentacle attacks, uses Reel, and makes two Bite attacks.\n- Bite. Melee Attack Roll: +7, reach 5 ft. Hit: 17 (3d8 + 4) Piercing damage.\n- Tentacle. Melee Attack Roll: +7, reach 60 ft. Hit: The target has the Grappled condition (escape DC 14) from one of six tentacles, and the target has the Poisoned condition until the grapple ends. The tentacle can be damaged, freeing a creature it has Grappled when destroyed (AC 20, HP 10, Immunity to Poison and Psychic damage). Damaging the tentacle deals no damage to the roper, and a destroyed tentacle regrows at the start of the roper's next turn.\n- Reel. The roper pulls each creature Grappled by it up to 30 feet straight toward it.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Roper","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Rust Monster","constant":false,"content":"## Rust Monster (monster stat block, SRD 5.2.1)\nMedium Monstrosity, Unaligned. AC 14, HP 33 (6d8+6), Initiative +1, Speed 40 ft..\nAbilities: Str 13 (save +1), Dex 12 (save +1), Con 13 (save +1), Int 2 (save -4), Wis 13 (save +1), Cha 6 (save -2).\nCR 1/2 (XP 100, PB +2).\nSenses Darkvision 60 ft.; Passive Perception 11\nLanguages None\n### Traits\n- Iron Scent. The rust monster can pinpoint the location of ferrous metal within 30 feet of itself.\n### Actions\n- Multiattack. The rust monster makes one Bite attack and uses Antennae twice.\n- Bite. Melee Attack Roll: +3, reach 5 ft. Hit: 5 (1d8 + 1) Piercing damage.\n- Antennae. The rust monster targets one nonmagical metal object—armor or a weapon—worn or carried by a creature within 5 feet of itself. Dexterity Saving Throw: DC 11, the creature with the object. Failure: The object takes a -1 penalty to the AC it offers (armor) or to its attack rolls (weapon). Armor is destroyed if the penalty reduces its AC to 10, and a weapon is destroyed if its penalty reaches -5. The penalty can be removed by casting the Mending spell on the armor or weapon.\n- Destroy Metal. The rust monster touches a nonmagical metal object within 5 feet of itself that isn't being worn or carried. The touch destroys a 1-foot Cube of the object.\n### Reactions\n- Reflexive Antennae. Trigger: An attack roll hits the rust monster. Response: The rust monster uses Antennae.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Rust Monster","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Sahuagin Warrior","constant":false,"content":"## Sahuagin Warrior (monster stat block, SRD 5.2.1)\nMedium Fiend, Lawful Evil. AC 12, HP 22 (4d8+4), Initiative +0, Speed 30 ft., Swim 40 ft..\nAbilities: Str 13 (save +1), Dex 11 (save +0), Con 12 (save +1), Int 12 (save +1), Wis 13 (save +1), Cha 9 (save -1).\nCR 1/2 (XP 100, PB +2).\nSkills Perception +5\nResistances Acid, Cold\nSenses Darkvision 120 ft.; Passive Perception 15\nLanguages Sahuagin\n### Traits\n- Blood Frenzy. The sahuagin has Advantage on attack rolls against any creature that doesn't have all its Hit Points.\n- Limited Amphibiousness. The sahuagin can breathe air and water, but it must be submerged at least once every 4 hours to avoid suffocating outside water.\n- Shark Telepathy. The sahuagin can magically control sharks within 120 feet of itself, using a special telepathy.\n### Actions\n- Multiattack. The sahuagin makes two Claw attacks.\n- Claw. Melee Attack Roll: +3, reach 5 ft. Hit: 4 (1d6 + 1) Slashing damage.\n### Bonus Actions\n- Aquatic Charge. The sahuagin swims up to its Swim Speed straight toward an enemy it can see.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Sahuagin Warrior","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Salamander","constant":false,"content":"## Salamander (monster stat block, SRD 5.2.1)\nLarge Elemental, Neutral Evil. AC 15, HP 90 (12d10+24), Initiative +2, Speed 30 ft., Climb 30 ft..\nAbilities: Str 18 (save +4), Dex 14 (save +2), Con 15 (save +2), Int 11 (save +0), Wis 10 (save +0), Cha 12 (save +1).\nCR 5 (XP 1800, PB +3).\nVulnerabilities Cold\nImmunities Fire\nSenses Darkvision 60 ft.; Passive Perception 10\nLanguages Primordial (Ignan)\n### Traits\n- Fire Aura. At the end of each of the salamander's turns, each creature of the salamander's choice in a 5-foot Emanation originating from the salamander takes 7 (2d6) Fire damage.\n### Actions\n- Multiattack. The salamander makes two Flame Spear attacks. It can replace one attack with a use of Constrict.\n- Flame Spear. Melee or Ranged Attack Roll: +7, reach 5 ft. or range 20/60 ft. Hit: 13 (2d8 + 4) Piercing damage plus 7 (2d6) Fire damage. Hit or Miss: The spear magically returns to the salamander's hand immediately after a ranged attack.\n- Constrict. Strength Saving Throw: DC 15, one Large or smaller creature the salamander can see within 10 feet. Failure: 11 (2d6 + 4) Bludgeoning damage plus 7 (2d6) Fire damage. The target has the Grappled condition (escape DC 14), and it has the Restrained condition until the grapple ends.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Salamander","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Satyr","constant":false,"content":"## Satyr (monster stat block, SRD 5.2.1)\nMedium Fey, Chaotic Neutral. AC 13, HP 31 (7d8), Initiative +3, Speed 40 ft..\nAbilities: Str 12 (save +1), Dex 16 (save +3), Con 11 (save +0), Int 12 (save +1), Wis 10 (save +0), Cha 14 (save +2).\nCR 1/2 (XP 100, PB +2).\nSkills Perception +2, Performance +6, Stealth +5\nSenses Passive Perception 12\nLanguages Common, Elvish, Sylvan\n### Traits\n- Magic Resistance. The satyr has Advantage on saving throws against spells and other magical effects.\n### Actions\n- Hooves. Melee Attack Roll: +5, reach 5 ft. Hit: 5 (1d4 + 3) Bludgeoning damage. If the target is a Medium or smaller creature, the satyr pushes the target up to 10 feet straight away from itself.\n- Mockery. Wisdom Saving Throw: DC 12, one creature the satyr can see within 90 feet. Failure: 5 (1d6 + 2) Psychic damage.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Satyr","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Scout","constant":false,"content":"## Scout (monster stat block, SRD 5.2.1)\nMedium or Small Humanoid, Neutral. AC 13, HP 16 (3d8+3), Initiative +2, Speed 30 ft..\nAbilities: Str 11 (save +0), Dex 14 (save +2), Con 12 (save +1), Int 11 (save +0), Wis 13 (save +1), Cha 11 (save +0).\nCR 1/2 (XP 100, PB +2).\nSkills Nature +4, Perception +5, Stealth +6, Survival +5\nGear Leather Armor, Longbow, Shortsword\nSenses Passive Perception 15\nLanguages Common plus one other language\n### Actions\n- Multiattack. The scout makes two attacks, using Shortsword and Longbow in any combination.\n- Shortsword. Melee Attack Roll: +4, reach 5 ft. Hit: 5 (1d6 + 2) Piercing damage.\n- Longbow. Ranged Attack Roll: +4, range 150/600 ft. Hit: 6 (1d8 + 2) Piercing damage.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Scout","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Sea Hag","constant":false,"content":"## Sea Hag (monster stat block, SRD 5.2.1)\nMedium Fey, Chaotic Evil. AC 14, HP 52 (7d8+21), Initiative +1, Speed 30 ft., Swim 40 ft..\nAbilities: Str 16 (save +3), Dex 13 (save +1), Con 16 (save +3), Int 12 (save +1), Wis 12 (save +1), Cha 13 (save +1).\nCR 2 (XP 450, PB +2).\nSenses Darkvision 60 ft.; Passive Perception 11\nLanguages Common, Giant, Primordial (Aquan)\n### Traits\n- Amphibious. The hag can breathe air and water.\n- Coven Magic. While within 30 feet of at least two hag allies, the hag can cast one of the following spells, requiring no Material components, using the spell's normal casting time, and using Intelligence as the spellcasting ability (spell save DC 11): Augury, Find Familiar, Identify, Locate Object, Scrying, or Unseen Servant. The hag must finish a Long Rest before using this trait to cast that spell again.\n- Vile Appearance. Wisdom Saving Throw: DC 11, any Beast or Humanoid that starts its turn within 30 feet of the hag and can see the hag's true form. Failure: The target has the Frightened condition until the start of its next turn. Success: The target is immune to this hag's Vile Appearance for 24 hours.\n### Actions\n- Claw. Melee Attack Roll: +5, reach 5 ft. Hit: 10 (2d6 + 3) Slashing damage.\n- Death Glare (Recharge 5–6). Wisdom Saving Throw: DC 11, one Frightened creature the hag can see within 30 feet. Failure: If the target has 20 Hit Points or fewer, it drops to 0 Hit Points. Otherwise, the target takes 13 (3d8) Psychic damage.\n- Illusory Appearance. The hag casts Disguise Self, using Constitution as the spellcasting ability (spell save DC 13). The spell's duration is 24 hours.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Sea Hag","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Shadow","constant":false,"content":"## Shadow (monster stat block, SRD 5.2.1)\nMedium Undead, Chaotic Evil. AC 12, HP 27 (5d8+5), Initiative +2, Speed 40 ft..\nAbilities: Str 6 (save -2), Dex 14 (save +2), Con 13 (save +1), Int 6 (save -2), Wis 10 (save +0), Cha 8 (save -1).\nCR 1/2 (XP 100, PB +2).\nSkills Stealth +6\nVulnerabilities Radiant\nResistances Acid, Cold, Fire, Lightning, Thunder\nImmunities Necrotic, Poison; Exhaustion, Frightened, Grappled, Paralyzed, Petrified, Poisoned, Prone, Restrained, Unconscious\nSenses Darkvision 60 ft.; Passive Perception 10\nLanguages None\n### Traits\n- Amorphous. The shadow can move through a space as narrow as 1 inch without expending extra movement to do so.\n- Sunlight Weakness. While in sunlight, the shadow has Disadvantage on D20 Tests.\n### Actions\n- Draining Swipe. Melee Attack Roll: +4, reach 5 ft. Hit: 5 (1d6 + 2) Necrotic damage, and the target's Strength score decreases by 1d4. The target dies if this reduces that score to 0. If a Humanoid is slain by this attack, a Shadow rises from the corpse 1d4 hours later.\n### Bonus Actions\n- Shadow Stealth. While in Dim Light or Darkness, the shadow takes the Hide action.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Shadow","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Shambling Mound","constant":false,"content":"## Shambling Mound (monster stat block, SRD 5.2.1)\nLarge Plant, Unaligned. AC 15, HP 110 (13d10+39), Initiative -1, Speed 30 ft., Swim 20 ft..\nAbilities: Str 18 (save +4), Dex 8 (save -1), Con 16 (save +3), Int 5 (save -3), Wis 10 (save +0), Cha 5 (save -3).\nCR 5 (XP 1800, PB +3).\nSkills Stealth +3\nResistances Cold, Fire\nImmunities Lightning; Deafened, Exhaustion\nSenses Blindsight 60 ft.; Passive Perception 10\nLanguages None\n### Traits\n- Lightning Absorption. Whenever the shambling mound is subjected to Lightning damage, it regains a number of Hit Points equal to the Lightning damage dealt.\n### Actions\n- Multiattack. The shambling mound makes three Charged Tendril attacks. It can replace one attack with a use of Engulf.\n- Charged Tendril. Melee Attack Roll: +7, reach 10 ft. Hit: 7 (1d6 + 4) Bludgeoning damage plus 5 (2d4) Lightning damage. If the target is a Medium or smaller creature, the shambling mound pulls the target 5 feet straight toward itself.\n- Engulf. Strength Saving Throw: DC 15, one Medium or smaller creature within 5 feet. Failure: The target is pulled into the shambling mound's space and has the Grappled condition (escape DC 14). Until the grapple ends, the target has the Blinded and Restrained conditions, and it takes 10 (3d6) Lightning damage at the start of each of its turns. When the shambling mound moves, the Grappled target moves with it, costing it no extra movement. The shambling mound can have only one creature Grappled by this action at a time.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Shambling Mound","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Shield Guardian","constant":false,"content":"## Shield Guardian (monster stat block, SRD 5.2.1)\nLarge Construct, Unaligned. AC 17, HP 142 (15d10+60), Initiative -1, Speed 30 ft..\nAbilities: Str 18 (save +4), Dex 8 (save -1), Con 18 (save +4), Int 7 (save -2), Wis 10 (save +0), Cha 3 (save -4).\nCR 7 (XP 2900, PB +3).\nImmunities Poison; Charmed, Exhaustion, Frightened, Paralyzed, Petrified, Poisoned\nSenses Blindsight 10 ft., Darkvision 60 ft.; Passive Perception 10\nLanguages Understands commands given in any language but can't speak\n### Traits\n- Bound. The guardian is magically bound to an amulet. While the guardian and its amulet are on the same plane of existence, the amulet's wearer can telepathically call the guardian to travel to it, and the guardian knows the distance and direction to the amulet. If the guardian is within 60 feet of the amulet's wearer, half of any damage the wearer takes (round up) is transferred to the guardian.\n- Regeneration. The guardian regains 10 Hit Points at the start of each of its turns if it has at least 1 Hit Point.\n- Spell Storing. A spellcaster who wears the guardian's amulet can cause the guardian to store one spell of level 4 or lower. To do so, the wearer must cast the spell on the guardian while within 5 feet of it. The spell has no effect but is stored within the guardian. Any previously stored spell is lost when a new spell is stored. The guardian can cast the spell stored with any parameters set by the original caster, requiring no spell components and using the caster's spellcasting ability.\n- The stored spell is then lost.\n### Actions\n- Multiattack. The guardian makes two Fist attacks.\n- Fist. Melee Attack Roll: +7, reach 10 ft. Hit: 11 (2d6 + 4) Bludgeoning damage plus 7 (2d6) Force damage.\n### Reactions\n- Protection. Trigger: An attack roll hits the wearer of the guardian's amulet while the wearer is within 5 feet of the guardian. Response: The wearer gains a +5 bonus to AC, including against the triggering attack and possibly causing it to miss, until the start of the guardian's next turn.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Shield Guardian","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Silver Dragon Wyrmling","constant":false,"content":"## Silver Dragon Wyrmling (monster stat block, SRD 5.2.1)\nMedium Dragon (Metallic), Lawful Good. AC 17, HP 45 (6d8+18), Initiative +2, Speed 30 ft., Fly 60 ft..\nAbilities: Str 19 (save +4), Dex 10 (save +2), Con 17 (save +3), Int 12 (save +1), Wis 11 (save +2), Cha 15 (save +2).\nCR 2 (XP 450, PB +2).\nSkills Perception +4, Stealth +2\nImmunities Cold\nSenses Blindsight 10 ft., Darkvision 60 ft.; Passive Perception 14\nLanguages Draconic\n### Actions\n- Multiattack. The dragon makes two Rend attacks.\n- Rend. Melee Attack Roll: +6, reach 5 ft. Hit: 9 (1d10 + 4) Piercing damage.\n- Cold Breath (Recharge 5–6). Constitution Saving Throw: DC 13, each creature in a 15-foot Cone. Failure: 18 (4d8) Cold damage. Success: Half damage.\n- Paralyzing Breath. Constitution Saving Throw: DC 13, each creature in a 15-foot Cone. First Failure: The target has the Incapacitated condition until the end of its next turn, when it repeats the save. Second Failure: The target has the Paralyzed condition, and it repeats the save at the end of each of its turns, ending the effect on itself on a success. After 1 minute, it succeeds automatically.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Silver Dragon Wyrmling","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Young Silver Dragon","constant":false,"content":"## Young Silver Dragon (monster stat block, SRD 5.2.1)\nLarge Dragon (Metallic), Lawful Good. AC 18, HP 168 (16d10+80), Initiative +4, Speed 40 ft., Fly 80 ft..\nAbilities: Str 23 (save +6), Dex 10 (save +4), Con 21 (save +5), Int 14 (save +2), Wis 11 (save +4), Cha 19 (save +4).\nCR 9 (XP 5000, PB +4).\nSkills History +6, Perception +8, Stealth +4\nImmunities Cold\nSenses Blindsight 30 ft., Darkvision 120 ft.; Passive Perception 18\nLanguages Common, Draconic\n### Actions\n- Multiattack. The dragon makes three Rend attacks. It can replace one attack with a use of Paralyzing Breath.\n- Rend. Melee Attack Roll: +10, reach 10 ft. Hit: 15 (2d8 + 6) Slashing damage.\n- Cold Breath (Recharge 5–6). Constitution Saving Throw: DC 17, each creature in a 30-foot Cone. Failure: 49 (11d8) Cold damage. Success: Half damage.\n- Paralyzing Breath. Constitution Saving Throw: DC 17, each creature in a 30-foot Cone. First Failure: The target has the Incapacitated condition until the end of its next turn, when it repeats the save. Second Failure: The target has the Paralyzed condition, and it repeats the save at the end of each of its turns, ending the effect on itself on a success. After 1 minute, it succeeds automatically.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Young Silver Dragon","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Adult Silver Dragon","constant":false,"content":"## Adult Silver Dragon (monster stat block, SRD 5.2.1)\nHuge Dragon (Metallic), Lawful Good. AC 19, HP 216 (16d12+112), Initiative +10, Speed 40 ft., Fly 80 ft..\nAbilities: Str 27 (save +8), Dex 10 (save +5), Con 25 (save +7), Int 16 (save +3), Wis 13 (save +6), Cha 22 (save +6).\nCR 16 (XP 15000, PB +5).\nSkills History +8, Perception +11, Stealth +5\nImmunities Cold\nSenses Blindsight 60 ft., Darkvision 120 ft.; Passive Perception 21\nLanguages Common, Draconic\n### Traits\n- Legendary Resistance (3/Day, or 4/Day in Lair). If the dragon fails a saving throw, it can choose to succeed instead.\n### Actions\n- Multiattack. The dragon makes three Rend attacks. It can replace one attack with a use of (A) Paralyzing Breath or (B) Spellcasting to cast Ice Knife.\n- Rend. Melee Attack Roll: +13, reach 10 ft. Hit: 17 (2d8 + 8) Slashing damage plus 4 (1d8) Cold damage.\n- Cold Breath (Recharge 5–6). Constitution Saving Throw: DC 20, each creature in a 60-foot Cone. Failure: 54 (12d8) Cold damage. Success: Half damage.\n- Paralyzing Breath. Constitution Saving Throw: DC 20, each creature in a 60-foot Cone. First Failure: The target has the Incapacitated condition until the end of its next turn, when it repeats the save. Second Failure: The target has the Paralyzed condition, and it repeats the save at the end of each of its turns, ending the effect on itself on a success. After 1 minute, it succeeds automatically.\n- Spellcasting. The dragon casts one of the following spells, requiring no Material components and using Charisma as the spellcasting ability (spell save DC 19, +11 to hit with spell attacks): At Will: Detect Magic, Hold Monster, Ice Knife, Shapechange (Beast or Humanoid form only, no Temporary Hit Points gained from the spell, and no Concentration or Temporary Hit Points required to maintain the spell) 1/Day Each: Ice Storm (level 5 version), Zone of Truth\n### Legendary Actions\n- Legendary Action Uses: 3 (4 in Lair). Immediately after another creature's turn, the dragon can expend a use to take one of the following actions. The dragon regains all expended uses at the start of each of its turns.\n- Chill. The dragon uses Spellcasting to cast Hold Monster. The dragon can't take this action again until the start of its next turn.\n- Cold Gale. Dexterity Saving Throw: DC 19, each creature in a 60-foot-long, 10-foot-wide Line. Failure: 14 (4d6) Cold damage, and the target is pushed up to 30 feet straight away from the dragon. Success: Half damage only. Failure or Success: The dragon can't take this action again until the start of its next turn.\n- Pounce. The dragon moves up to half its Speed, and it makes one Rend attack.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Adult Silver Dragon","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Ancient Silver Dragon","constant":false,"content":"## Ancient Silver Dragon (monster stat block, SRD 5.2.1)\nGargantuan Dragon (Metallic), Lawful Good. AC 22, HP 468 (24d20+216), Initiative +14, Speed 40 ft., Fly 80 ft..\nAbilities: Str 30 (save +10), Dex 10 (save +7), Con 29 (save +9), Int 18 (save +4), Wis 15 (save +9), Cha 26 (save +8).\nCR 23 (XP 50000, PB +7).\nSkills History +11, Perception +16, Stealth +7\nImmunities Cold\nSenses Blindsight 60 ft., Darkvision 120 ft.; Passive Perception 26\nLanguages Common, Draconic\n### Traits\n- Legendary Resistance (4/Day, or 5/Day in Lair). If the dragon fails a saving throw, it can choose to succeed instead.\n### Actions\n- Multiattack. The dragon makes three Rend attacks. It can replace one attack with a use of (A) Paralyzing Breath or (B) Spellcasting to cast Ice Knife (level 2 version).\n- Rend. Melee Attack Roll: +17, reach 15 ft. Hit: 19 (2d8 + 10) Slashing damage plus 9 (2d8) Cold damage.\n- Cold Breath (Recharge 5–6). Constitution Saving Throw: DC 24, each creature in a 90-foot Cone. Failure: 67 (15d8) Cold damage. Success: Half damage.\n- Paralyzing Breath. Constitution Saving Throw: DC 24, each creature in a 90-foot Cone. First Failure: The target has the Incapacitated condition until the end of its next turn, when it repeats the save. Second Failure: The target has the Paralyzed condition, and it repeats the save at the end of each of its turns, ending the effect on itself on a success. After 1 minute, it succeeds automatically.\n- Spellcasting. The dragon casts one of the following spells, requiring no Material components and using Charisma as the spellcasting ability (spell save DC 23, +15 to hit with spell attacks): At Will: Detect Magic, Hold Monster, Ice Knife (level 2 version), Shapechange (Beast or Humanoid form only, no Temporary Hit Points gained from the spell, and no Concentration or Temporary Hit Points required to maintain the spell) 1/Day Each: Control Weather, Ice Storm (level 7 version), Teleport, Zone of Truth\n### Legendary Actions\n- Legendary Action Uses: 3 (4 in Lair). Immediately after another creature's turn, the dragon can expend a use to take one of the following actions. The dragon regains all expended uses at the start of each of its turns.\n- Chill. The dragon uses Spellcasting to cast Hold Monster. The dragon can't take this action again until the start of its next turn.\n- Cold Gale. Dexterity Saving Throw: DC 23, each creature in a 60-foot-long, 10-foot-wide Line. Failure: 14 (4d6) Cold damage, and the target is pushed up to 30 feet straight away from the dragon. Success: Half damage only. Failure or Success: The dragon can't take this action again until the start of its next turn.\n- Pounce. The dragon moves up to half its Speed, and it makes one Rend attack.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Ancient Silver Dragon","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Skeleton","constant":false,"content":"## Skeleton (monster stat block, SRD 5.2.1)\nMedium Undead, Lawful Evil. AC 14, HP 13 (2d8+4), Initiative +3, Speed 30 ft..\nAbilities: Str 10 (save +0), Dex 16 (save +3), Con 15 (save +2), Int 6 (save -2), Wis 8 (save -1), Cha 5 (save -3).\nCR 1/4 (XP 50, PB +2).\nVulnerabilities Bludgeoning\nImmunities Poison; Exhaustion, Poisoned\nGear Shortbow, Shortsword\nSenses Darkvision 60 ft.; Passive Perception 9\nLanguages Understands Common plus one other language but can't speak\n### Actions\n- Shortsword. Melee Attack Roll: +5, reach 5 ft. Hit: 6 (1d6 + 3) Piercing damage.\n- Shortbow. Ranged Attack Roll: +5, range 80/320 ft. Hit: 6 (1d6 + 3) Piercing damage.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Skeleton","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Warhorse Skeleton","constant":false,"content":"## Warhorse Skeleton (monster stat block, SRD 5.2.1)\nLarge Undead, Lawful Evil. AC 13, HP 22 (3d10+6), Initiative +1, Speed 60 ft..\nAbilities: Str 18 (save +4), Dex 12 (save +1), Con 15 (save +2), Int 2 (save -4), Wis 8 (save -1), Cha 5 (save -3).\nCR 1/2 (XP 100, PB +2).\nVulnerabilities Bludgeoning\nImmunities Poison; Exhaustion, Poisoned\nSenses Darkvision 60 ft.; Passive Perception 9\nLanguages None\n### Actions\n- Hooves. Melee Attack Roll: +6, reach 5 ft. Hit: 7 (1d6 + 4) Bludgeoning damage. If the target is a Large or smaller creature and the skeleton moved 20+ feet straight toward it immediately before the hit, the target has the Prone condition.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Warhorse Skeleton","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Minotaur Skeleton","constant":false,"content":"## Minotaur Skeleton (monster stat block, SRD 5.2.1)\nLarge Undead, Lawful Evil. AC 12, HP 45 (6d10+12), Initiative +0, Speed 40 ft..\nAbilities: Str 18 (save +4), Dex 11 (save +0), Con 15 (save +2), Int 6 (save -2), Wis 8 (save -1), Cha 5 (save -3).\nCR 2 (XP 450, PB +2).\nVulnerabilities Bludgeoning\nImmunities Poison; Exhaustion, Poisoned\nSenses Darkvision 60 ft.; Passive Perception 9\nLanguages Understands Abyssal but can't speak\n### Actions\n- Gore. Melee Attack Roll: +6, reach 5 ft. Hit: 11 (2d6 + 4) Piercing damage. If the target is a Large or smaller creature and the skeleton moved 20+ feet straight toward it immediately before the hit, the target takes an extra 9 (2d8) Piercing damage and has the Prone condition.\n- Slam. Melee Attack Roll: +6, reach 5 ft. Hit: 15 (2d10 + 4) Bludgeoning damage.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Minotaur Skeleton","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Solar","constant":false,"content":"## Solar (monster stat block, SRD 5.2.1)\nLarge Celestial (Angel), Lawful Good. AC 21, HP 297 (22d10+176), Initiative +20, Speed 50 ft., Fly 150 ft. (hover).\nAbilities: Str 26 (save +8), Dex 22 (save +6), Con 26 (save +8), Int 25 (save +7), Wis 25 (save +7), Cha 30 (save +10).\nCR 21 (XP 33000, PB +7).\nSkills Perception +14\nImmunities Poison, Radiant; Charmed, Exhaustion, Frightened, Poisoned\nSenses Truesight 120 ft.; Passive Perception 24\nLanguages All; telepathy 120 ft.\n### Traits\n- Divine Awareness. The solar knows if it hears a lie.\n- Exalted Restoration. If the solar dies outside Mount Celestia, its body disappears, and it gains a new body instantly, reviving with all its Hit Points somewhere in Mount Celestia.\n- Legendary Resistance (4/Day). If the solar fails a saving throw, it can choose to succeed instead.\n- Magic Resistance. The solar has Advantage on saving throws against spells and other magical effects.\n### Actions\n- Multiattack. The solar makes two Flying Sword attacks.\n- It can replace one attack with a use of Slaying Bow.\n- Flying Sword. Melee or Ranged Attack Roll: +15, reach 10 ft. or range 120 ft. Hit: 22 (4d6 + 8) Slashing damage plus 36 (8d8) Radiant damage. Hit or Miss: The sword magically returns to the solar's hand or hovers within 5 feet of the solar immediately after a ranged attack.\n- Slaying Bow. Dexterity Saving Throw: DC 21, one creature the solar can see within 600 feet. Failure: If the creature has 100 Hit Points or fewer, it dies. It otherwise takes 24 (4d8 + 6) Piercing damage plus 36 (8d8) Radiant damage.\n- Spellcasting. The solar casts one of the following spells, requiring no Material components and using Charisma as the spellcasting ability (spell save DC 25): At Will: Detect Evil and Good 1/Day Each: Commune, Control Weather, Dispel Evil and Good, Resurrection\n### Bonus Actions\n- Divine Aid (3/Day). The solar casts Cure Wounds (level 2 version), Lesser Restoration, or Remove Curse, using the same spellcasting ability as Spellcasting.\n### Legendary Actions\n- Legendary Action Uses: 3. Immediately after another creature's turn, the solar can expend a use to take one of the following actions. The solar regains all expended uses at the start of each of its turns.\n- Blinding Gaze. Constitution Saving Throw: DC 25, one creature the solar can see within 120 feet. Failure: The target has the Blinded condition for 1 minute. Failure or Success: The solar can't take this action again until the start of its next turn.\n- Radiant Teleport. The solar teleports up to 60 feet to an unoccupied space it can see. Dexterity Saving Throw: DC 25, each creature in a 10-foot Emanation originating from the solar at its destination space. Failure: 11 (2d10) Radiant damage. Success: Half damage.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Solar","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Specter","constant":false,"content":"## Specter (monster stat block, SRD 5.2.1)\nMedium Undead, Chaotic Evil. AC 12, HP 22 (5d8), Initiative +2, Speed 30 ft., Fly 50 ft. (hover).\nAbilities: Str 1 (save -5), Dex 14 (save +2), Con 11 (save +0), Int 10 (save +0), Wis 10 (save +0), Cha 11 (save +0).\nCR 1 (XP 200, PB +2).\nResistances Acid, Bludgeoning, Cold, Fire, Lightning, Piercing, Slashing, Thunder\nImmunities Necrotic, Poison; Charmed, Exhaustion, Grappled, Paralyzed, Petrified, Poisoned, Prone, Restrained, Unconscious\nSenses Darkvision 60 ft.; Passive Perception 10\nLanguages Understands Common plus one other language but can't speak\n### Traits\n- Incorporeal Movement. The specter can move through other creatures and objects as if they were Difficult Terrain. It takes 5 (1d10) Force damage if it ends its turn inside an object.\n- Sunlight Sensitivity. While in sunlight, the specter has Disadvantage on ability checks and attack rolls.\n### Actions\n- Life Drain. Melee Attack Roll: +4, reach 5 ft. Hit: 7 (2d6) Necrotic damage. If the target is a creature, its Hit Point maximum decreases by an amount equal to the damage taken.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Specter","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Sphinx of Wonder","constant":false,"content":"## Sphinx of Wonder (monster stat block, SRD 5.2.1)\nTiny Celestial, Lawful Good. AC 13, HP 24 (7d4+7), Initiative +3, Speed 20 ft., Fly 40 ft..\nAbilities: Str 6 (save -2), Dex 17 (save +3), Con 13 (save +1), Int 15 (save +2), Wis 12 (save +1), Cha 11 (save +0).\nCR 1 (XP 200, PB +2).\nSkills Arcana +4, Religion +4, Stealth +5\nResistances Necrotic, Psychic, Radiant\nSenses Darkvision 60 ft.; Passive Perception 11\nLanguages Celestial, Common\n### Traits\n- Magic Resistance. The sphinx has Advantage on saving throws against spells and other magical effects.\n### Actions\n- Rend. Melee Attack Roll: +5, reach 5 ft. Hit: 5 (1d4 + 3) Slashing damage plus 7 (2d6) Radiant damage.\n### Reactions\n- Burst of Ingenuity (2/Day). Trigger: The sphinx or another creature within 30 feet makes an ability check or a saving throw. Response: The sphinx adds 2 to the roll.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Sphinx of Wonder","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Sphinx of Lore","constant":false,"content":"## Sphinx of Lore (monster stat block, SRD 5.2.1)\nLarge Celestial, Lawful Neutral. AC 17, HP 170 (20d10+60), Initiative +10, Speed 40 ft., Fly 60 ft..\nAbilities: Str 18 (save +4), Dex 15 (save +2), Con 16 (save +3), Int 18 (save +4), Wis 18 (save +4), Cha 18 (save +4).\nCR 11 (XP 7200, PB +4).\nSkills Arcana +12, History +12, Perception +8, Religion +12\nResistances Necrotic, Radiant\nImmunities Psychic; Charmed, Frightened\nSenses Truesight 120 ft.; Passive Perception 18\nLanguages Celestial, Common\n### Traits\n- Inscrutable. No magic can observe the sphinx remotely or detect its thoughts without its permission. Wisdom (Insight) checks made to ascertain its intentions or sincerity are made with Disadvantage.\n- Legendary Resistance (3/Day, or 4/Day in Lair). If the sphinx fails a saving throw, it can choose to succeed instead.\n### Actions\n- Multiattack. The sphinx makes three Claw attacks.\n- Claw. Melee Attack Roll: +8, reach 5 ft. Hit: 14 (3d6 + 4) Slashing damage.\n- Mind-Rending Roar (Recharge 5–6). Wisdom Saving Throw: DC 16, each enemy in a 300-foot Emanation originating from the sphinx. Failure: 35 (10d6) Psychic damage, and the target has the Incapacitated condition until the start of the sphinx's next turn.\n- Spellcasting. The sphinx casts one of the following spells, requiring no Material components and using Intelligence as the spellcasting ability (spell save DC 16): At Will: Detect Magic, Identify, Mage Hand, Minor Illusion, Prestidigitation 1/Day Each: Dispel Magic, Legend Lore, Locate Object, Plane Shift, Remove Curse, Tongues\n### Legendary Actions\n- Legendary Action Uses: 3 (4 in Lair). Immediately after another creature's turn, the sphinx can expend a use to take one of the following actions. The sphinx regains all expended uses at the start of each of its turns.\n- Arcane Prowl. The sphinx can teleport up to 30 feet to an unoccupied space it can see, and it makes one Claw attack.\n- Weight of Years. Constitution Saving Throw: DC 16, one creature the sphinx can see within 120 feet. Failure: The target gains 1 Exhaustion level. While the target has any Exhaustion levels, it appears 3d10 years older. Failure or Success: The sphinx can't take this action again until the start of its next turn.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Sphinx of Lore","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Sphinx of Valor","constant":false,"content":"## Sphinx of Valor (monster stat block, SRD 5.2.1)\nLarge Celestial, Lawful Neutral. AC 17, HP 199 (19d10+95), Initiative +12, Speed 40 ft., Fly 60 ft..\nAbilities: Str 22 (save +6), Dex 10 (save +6), Con 20 (save +11), Int 16 (save +9), Wis 23 (save +12), Cha 18 (save +4).\nCR 17 (XP 18000, PB +6).\nSkills Arcana +9, Perception +12, Religion +15\nResistances Necrotic, Radiant\nImmunities Psychic; Charmed, Frightened\nSenses Truesight 120 ft.; Passive Perception 22\nLanguages Celestial, Common\n### Traits\n- Inscrutable. No magic can observe the sphinx remotely or detect its thoughts without its permission. Wisdom (Insight) checks made to ascertain its intentions or sincerity are made with Disadvantage.\n- Legendary Resistance (3/Day, or 4/Day in Lair). If the sphinx fails a saving throw, it can choose to succeed instead.\n### Actions\n- Multiattack. The sphinx makes two Claw attacks and uses Roar.\n- Claw. Melee Attack Roll: +12, reach 5 ft. Hit: 20 (4d6 + 6) Slashing damage.\n- Roar (3/Day). The sphinx emits a magical roar. Whenever it roars, the roar has a different effect, as detailed below (the sequence resets when it takes a Long Rest): First Roar. Wisdom Saving Throw: DC 20, each enemy in a 500-foot Emanation originating from the sphinx. Failure: The target has the Frightened condition for 1 minute.\n- Second Roar. Wisdom Saving Throw: DC 20, each enemy in a 500-foot Emanation originating from the sphinx. Failure: The target has the Paralyzed condition, and it repeats the save at the end of each of its turns, ending the effect on itself on a success. After 1 minute, it succeeds automatically.\n- Third Roar. Constitution Saving Throw: DC 20, each enemy in a 500-foot Emanation originating from the sphinx. Failure: 44 (8d10) Thunder damage, and the target has the Prone condition. Success: Half damage only.\n- Spellcasting. The sphinx casts one of the following spells, requiring no Material components and using Wisdom as the spellcasting ability (spell save DC 20): At Will: Detect Evil and Good, Thaumaturgy 1/Day Each: Detect Magic, Dispel Magic, Greater Restoration, Heroes' Feast, Zone of Truth\n### Legendary Actions\n- Legendary Action Uses: 3 (4 in Lair). Immediately after another creature's turn, the sphinx can expend a use to take one of the following actions. The sphinx regains all expended uses at the start of each of its turns.\n- Arcane Prowl. The sphinx can teleport up to 30 feet to an unoccupied space it can see, and it makes one Claw attack.\n- Weight of Years. Constitution Saving Throw: DC 16, one creature the sphinx can see within 120 feet. Failure: The target gains 1 Exhaustion level. While the target has any Exhaustion levels, it appears 3d10 years older. Failure or Success: The sphinx can't take this action again until the start of its next turn.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Sphinx of Valor","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Spirit Naga","constant":false,"content":"## Spirit Naga (monster stat block, SRD 5.2.1)\nLarge Fiend, Chaotic Evil. AC 17, HP 135 (18d10+36), Initiative +3, Speed 40 ft..\nAbilities: Str 18 (save +4), Dex 17 (save +6), Con 14 (save +5), Int 16 (save +3), Wis 15 (save +5), Cha 16 (save +6).\nCR 8 (XP 3900, PB +3).\nImmunities Poison; Charmed, Poisoned\nSenses Darkvision 60 ft.; Passive Perception 12\nLanguages Abyssal, Common\n### Traits\n- Fiendish Restoration. If it dies, the naga returns to life in 1d6 days and regains all its Hit Points. Only a Wish spell can prevent this trait from functioning.\n### Actions\n- Multiattack. The naga makes three attacks, using Bite or Necrotic Ray in any combination.\n- Bite. Melee Attack Roll: +7, reach 10 ft. Hit: 7 (1d6 + 4) Piercing damage plus 14 (4d6) Poison damage.\n- Necrotic Ray. Ranged Attack Roll: +6, range 60 ft. Hit: 21 (6d6) Necrotic damage.\n- Spellcasting. The naga casts one of the following spells, requiring no Somatic or Material components and using Intelligence as the spellcasting ability (spell save DC 14): At Will: Detect Magic, Mage Hand, Minor Illusion, Water Breathing 2/Day Each: Detect Thoughts, Dimension Door, Hold Person (level 3 version), Lightning Bolt (level 4 version)","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Spirit Naga","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Sprite","constant":false,"content":"## Sprite (monster stat block, SRD 5.2.1)\nTiny Fey, Neutral Good. AC 15, HP 10 (4d4), Initiative +4, Speed 10 ft., Fly 40 ft..\nAbilities: Str 3 (save -4), Dex 18 (save +4), Con 10 (save +0), Int 14 (save +2), Wis 13 (save +1), Cha 11 (save +0).\nCR 1/4 (XP 50, PB +2).\nSkills Perception +3, Stealth +8\nSenses Passive Perception 13\nLanguages Common, Elvish, Sylvan\n### Actions\n- Needle Sword. Melee Attack Roll: +6, reach 5 ft. Hit: 6 (1d4 + 4) Piercing damage.\n- Enchanting Bow. Ranged Attack Roll: +6, range 40/160 ft. Hit: 1 Piercing damage, and the target has the Charmed condition until the start of the sprite's next turn.\n- Heart Sight. Charisma Saving Throw: DC 10, one creature within 5 feet the sprite can see (Celestials, Fiends, and Undead automatically fail the save). Failure: The sprite knows the target's emotions and alignment.\n- Invisibility. The sprite casts Invisibility on itself, requiring no spell components and using Charisma as the spellcasting ability.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Sprite","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Spy","constant":false,"content":"## Spy (monster stat block, SRD 5.2.1)\nMedium or Small Humanoid, Neutral. AC 12, HP 27 (6d8), Initiative +4, Speed 30 ft., Climb 30 ft..\nAbilities: Str 10 (save +0), Dex 15 (save +2), Con 10 (save +0), Int 12 (save +1), Wis 14 (save +2), Cha 16 (save +3).\nCR 1 (XP 200, PB +2).\nSkills Deception +5, Insight +4, Investigation +5, Perception +6, Sleight of Hand +4, Stealth +6\nGear Hand Crossbow, Shortsword, Thieves' Tools\nSenses Passive Perception 16\nLanguages Common plus one other language\n### Actions\n- Shortsword. Melee Attack Roll: +4, reach 5 ft. Hit: 5 (1d6 + 2) Piercing damage plus 7 (2d6) Poison damage.\n- Hand Crossbow. Ranged Attack Roll: +4, range 30/120 ft. Hit: 5 (1d6 + 2) Piercing damage plus 7 (2d6) Poison damage.\n### Bonus Actions\n- Cunning Action. The spy takes the Dash, Disengage, or Hide action.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Spy","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Stirge","constant":false,"content":"## Stirge (monster stat block, SRD 5.2.1)\nTiny Monstrosity, Unaligned. AC 13, HP 5 (2d4), Initiative +3, Speed 10 ft., Fly 40 ft..\nAbilities: Str 4 (save -3), Dex 16 (save +3), Con 11 (save +0), Int 2 (save -4), Wis 8 (save -1), Cha 6 (save -2).\nCR 1/8 (XP 25, PB +2).\nSenses Darkvision 60 ft.; Passive Perception 9\nLanguages None\n### Actions\n- Proboscis. Melee Attack Roll: +5, reach 5 ft. Hit: 6 (1d6 + 3) Piercing damage, and the stirge attaches to the target. While attached, the stirge can't make Proboscis attacks, and the target takes 5 (2d4) Necrotic damage at the start of each of the stirge's turns. The stirge can detach itself by spending 5 feet of its movement. The target or a creature within 5 feet of it can detach the stirge as an action.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Stirge","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Stone Giant","constant":false,"content":"## Stone Giant (monster stat block, SRD 5.2.1)\nHuge Giant, Neutral. AC 17, HP 126 (11d12+55), Initiative +5, Speed 40 ft..\nAbilities: Str 23 (save +6), Dex 15 (save +5), Con 20 (save +8), Int 10 (save +0), Wis 12 (save +4), Cha 9 (save -1).\nCR 7 (XP 2900, PB +3).\nSkills Athletics +12, Perception +4, Stealth +5\nSenses Darkvision 60 ft.; Passive Perception 14\nLanguages Giant\n### Actions\n- Multiattack. The giant makes two attacks, using Stone Club or Boulder in any combination.\n- Stone Club. Melee Attack Roll: +9, reach 15 ft. Hit: 22 (3d10 + 6) Bludgeoning damage.\n- Boulder. Ranged Attack Roll: +9, range 60/240 ft. Hit: 15 (2d8 + 6) Bludgeoning damage. If the target is a Large or smaller creature, it has the Prone condition.\n### Reactions\n- Deflect Missile (Recharge 5–6). Trigger: The giant is hit by a ranged attack roll and takes Bludgeoning, Piercing, or Slashing damage from it. Response: The giant reduces the damage it takes from the attack by 11 (1d10 + 6), and if that damage is reduced to 0, the giant can redirect some of the attack's force. Dexterity Saving Throw: DC 17, one creature the giant can see within 60 feet. Failure: 11 (1d10 + 6) Force damage.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Stone Giant","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Stone Golem","constant":false,"content":"## Stone Golem (monster stat block, SRD 5.2.1)\nLarge Construct, Unaligned. AC 18, HP 220 (21d10+105), Initiative +3, Speed 30 ft..\nAbilities: Str 22 (save +6), Dex 9 (save -1), Con 20 (save +5), Int 3 (save -4), Wis 11 (save +0), Cha 1 (save -5).\nCR 10 (XP 5900, PB +4).\nImmunities Poison, Psychic; Charmed, Exhaustion, Frightened, Paralyzed, Petrified, Poisoned\nSenses Darkvision 120 ft.; Passive Perception 10\nLanguages Understands Common plus two other languages but can't speak\n### Traits\n- Immutable Form. The golem can't shape-shift.\n- Magic Resistance. The golem has Advantage on saving throws against spells and other magical effects.\n### Actions\n- Multiattack. The golem makes two attacks, using Slam or Force Bolt in any combination.\n- Slam. Melee Attack Roll: +10, reach 5 ft. Hit: 15 (2d8 + 6) Bludgeoning damage plus 9 (2d8) Force damage.\n- Force Bolt. Ranged Attack Roll: +9, range 120 ft. Hit: 22 (4d10) Force damage.\n### Bonus Actions\n- Slow (Recharge 5–6). The golem casts the Slow spell, requiring no spell components and using Constitution as the spellcasting ability (spell save DC 17).","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Stone Golem","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Storm Giant","constant":false,"content":"## Storm Giant (monster stat block, SRD 5.2.1)\nHuge Giant, Chaotic Good. AC 16, HP 230 (20d12+100), Initiative +7, Speed 50 ft., Fly 25 ft. (hover), Swim 50 ft..\nAbilities: Str 29 (save +14), Dex 14 (save +2), Con 20 (save +10), Int 16 (save +3), Wis 20 (save +10), Cha 18 (save +9).\nCR 13 (XP 10000, PB +5).\nSkills Arcana +8, Athletics +14, History +8, Perception +10\nResistances Cold\nImmunities Lightning, Thunder\nSenses Darkvision 120 ft., Truesight 30 ft.; Passive Perception 20\nLanguages Common, Giant\n### Traits\n- Amphibious. The giant can breathe air and water.\n### Actions\n- Multiattack. The giant makes two attacks, using Storm Sword or Thunderbolt in any combination.\n- Storm Sword. Melee Attack Roll: +14, reach 10 ft. Hit: 23 (4d6 + 9) Slashing damage plus 13 (3d8) Lightning damage.\n- Thunderbolt. Ranged Attack Roll: +14, range 500 ft. Hit: 22 (2d12 + 9) Lightning damage, and the target has the Blinded and Deafened conditions until the start of the giant's next turn.\n- Lightning Storm (Recharge 5–6). Dexterity Saving Throw: DC 18, each creature in a 10-foot-radius, 40-foot-high Cylinder originating from a point the giant can see within 500 feet. Failure: 55 (10d10) Lightning damage. Success: Half damage.\n- Spellcasting. The giant casts one of the following spells, requiring no Material components and using Wisdom as the spellcasting ability (spell save DC 18): At Will: Detect Magic, Light 1/Day: Control Weather","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Storm Giant","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Succubus","constant":false,"content":"## Succubus (monster stat block, SRD 5.2.1)\nMedium Fiend, Neutral Evil. AC 15, HP 71 (13d8+13), Initiative +3, Speed 30 ft., Fly 60 ft..\nAbilities: Str 8 (save -1), Dex 17 (save +3), Con 13 (save +1), Int 15 (save +2), Wis 12 (save +1), Cha 20 (save +5).\nCR 4 (XP 1100, PB +2).\nSkills Deception +9, Insight +5, Perception +5, Persuasion +9, Stealth +7\nResistances Cold, Fire, Poison, Psychic\nSenses Darkvision 60 ft.; Passive Perception 15\nLanguages Abyssal, Common, Infernal; telepathy 60 ft.\n### Traits\n- Incubus Form. When the succubus finishes a Long Rest, it can shape-shift into an Incubus, using that stat block instead of this one.\n### Actions\n- Multiattack. The succubus makes one Fiendish Touch attack and uses Charm or Draining Kiss.\n- Fiendish Touch. Melee Attack Roll: +7, reach 5 ft. Hit: 16 (2d10 + 5) Psychic damage.\n- Charm. The succubus casts Dominate Person (level 8 version), requiring no spell components and using Charisma as the spellcasting ability (spell save DC 15).\n- Draining Kiss. Constitution Saving Throw: DC 15, one creature Charmed by the succubus within 5 feet. Failure: 13 (3d8) Psychic damage. Success: Half damage. Failure or Success: The target's Hit Point maximum decreases by an amount equal to the damage taken.\n### Bonus Actions\n- Shape-Shift. The succubus shape-shifts into a Medium or Small Humanoid, or it returns to its true form. Its game statistics are the same in each form, except its Fly Speed is available only in its true form. Any equipment it is wearing or carrying isn't transformed.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Succubus","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Tarrasque","constant":false,"content":"## Tarrasque (monster stat block, SRD 5.2.1)\nGargantuan Monstrosity (Titan), Unaligned. AC 25, HP 697 (34d20+340), Initiative +18, Speed 60 ft., Burrow 40 ft., Climb 60 ft..\nAbilities: Str 30 (save +10), Dex 11 (save +9), Con 30 (save +10), Int 3 (save +5), Wis 11 (save +9), Cha 11 (save +9).\nCR 30 (XP 155000, PB +9).\nSkills Perception +9\nResistances Bludgeoning, Piercing, Slashing\nImmunities Fire, Poison; Charmed, Deafened, Frightened, Paralyzed, Poisoned\nSenses Blindsight 120 ft.; Passive Perception 19\nLanguages None\n### Traits\n- Legendary Resistance (6/Day). If the tarrasque fails a saving throw, it can choose to succeed instead.\n- Magic Resistance. The tarrasque has Advantage on saving throws against spells and other magical effects.\n- Reflective Carapace. If the tarrasque is targeted by a Magic Missile spell or a spell that requires a ranged attack roll, roll 1d6. On a 1–5, the tarrasque is unaffected. On a 6, the tarrasque is unaffected and reflects the spell, turning the caster into the target.\n- Siege Monster. The tarrasque deals double damage to objects and structures.\n### Actions\n- Multiattack. The tarrasque makes one Bite attack and three other attacks, using Claw or Tail in any combination.\n- Bite. Melee Attack Roll: +19, reach 15 ft. Hit: 36 (4d12 + 10) Piercing damage, and the target has the Grappled condition (escape DC 20). Until the grapple ends, the target has the Restrained condition and can't teleport.\n- Claw. Melee Attack Roll: +19, reach 15 ft. Hit: 28 (4d8 + 10) Slashing damage.\n- Tail. Melee Attack Roll: +19, reach 30 ft. Hit: 23 (3d8 + 10) Bludgeoning damage. If the target is a Huge or smaller creature, it has the Prone condition.\n- Thunderous Bellow (Recharge 5–6). Constitution Saving Throw: DC 27, each creature and each object that isn't being worn or carried in a 150-foot Cone. Failure: 78 (12d12) Thunder damage, and the target has the Deafened and Frightened conditions until the end of its next turn. Success: Half damage only.\n### Bonus Actions\n- Swallow. Strength Saving Throw: DC 27, one Large or smaller creature Grappled by the tarrasque (it can have up to six creatures swallowed at a time). Failure: The target is swallowed, and the Grappled condition ends. A swallowed creature has the Blinded and Restrained conditions and can't teleport, it has Total Cover against attacks and other effects outside the tarrasque, and it takes 56 (16d6) Acid damage at the start of each of the tarrasque's turns. If the tarrasque takes 60 damage or more on a single turn from a creature inside it, the tarrasque must succeed on a DC 20 Constitution saving throw at the end of that turn or regurgitate all swallowed creatures, each of which falls in a space within 10 feet of the tarrasque and has the Prone condition. If the tarrasque dies, any swallowed creature no longer has the Restrained condition and can escape from the corpse using 20 feet of movement, exiting Prone.\n### Legendary Actions\n- Legendary Action Uses: 3. Immediately after another creature's turn, the tarrasque can expend a use to take one of the following actions. The tarrasque regains all expended uses at the start of each of its turns.\n- Onslaught. The tarrasque moves up to half its Speed, and it makes one Claw or Tail attack.\n- World-Shaking Movement. The tarrasque moves up to its Speed. At the end of this movement, the tarrasque creates an instantaneous shock wave in a 60-foot Emanation originating from itself. Creatures in that area lose Concentration and, if Medium or smaller, have the Prone condition. The tarrasque can't take this action again until the start of its next turn.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Tarrasque","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Tough","constant":false,"content":"## Tough (monster stat block, SRD 5.2.1)\nMedium or Small Humanoid, Neutral. AC 12, HP 32 (5d8+10), Initiative +1, Speed 30 ft..\nAbilities: Str 15 (save +2), Dex 12 (save +1), Con 14 (save +2), Int 10 (save +0), Wis 10 (save +0), Cha 11 (save +0).\nCR 1/2 (XP 100, PB +2).\nGear Heavy Crossbow, Leather Armor, Mace\nSenses Passive Perception 10\nLanguages Common\n### Traits\n- Pack Tactics. The tough has Advantage on an attack roll against a creature if at least one of the tough's allies is within 5 feet of the creature and the ally doesn't have the Incapacitated condition.\n### Actions\n- Mace. Melee Attack Roll: +4, reach 5 ft. Hit: 5 (1d6 + 2) Bludgeoning damage.\n- Heavy Crossbow. Ranged Attack Roll: +3, range 100/400 ft. Hit: 6 (1d10 + 1) Piercing damage.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Tough","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Tough Boss","constant":false,"content":"## Tough Boss (monster stat block, SRD 5.2.1)\nMedium or Small Humanoid, Neutral. AC 16, HP 82 (11d8+33), Initiative +2, Speed 30 ft..\nAbilities: Str 17 (save +5), Dex 14 (save +2), Con 16 (save +5), Int 11 (save +0), Wis 10 (save +0), Cha 11 (save +2).\nCR 4 (XP 1100, PB +2).\nGear Chain Mail, Heavy Crossbow, Warhammer\nSenses Passive Perception 10\nLanguages Common plus one other language\n### Traits\n- Pack Tactics. The tough has Advantage on an attack roll against a creature if at least one of the tough's allies is within 5 feet of the creature and the ally doesn't have the Incapacitated condition.\n### Actions\n- Multiattack. The tough makes two attacks, using Warhammer or Heavy Crossbow in any combination.\n- Warhammer. Melee Attack Roll: +5, reach 5 ft. Hit: 12 (2d8 + 3) Bludgeoning damage. If the target is a Large or smaller creature, the tough pushes the target up to 10 feet straight away from itself.\n- Heavy Crossbow. Ranged Attack Roll: +4, range 100/400 ft. Hit: 13 (2d10 + 2) Piercing damage.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Tough Boss","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Treant","constant":false,"content":"## Treant (monster stat block, SRD 5.2.1)\nHuge Plant, Chaotic Good. AC 16, HP 138 (12d12+60), Initiative +3, Speed 30 ft..\nAbilities: Str 23 (save +6), Dex 8 (save -1), Con 21 (save +5), Int 12 (save +1), Wis 16 (save +3), Cha 12 (save +1).\nCR 9 (XP 5000, PB +4).\nVulnerabilities Fire\nResistances Bludgeoning, Piercing\nSenses Passive Perception 13\nLanguages Common, Druidic, Elvish, Sylvan\n### Traits\n- Siege Monster. The treant deals double damage to objects and structures.\n### Actions\n- Multiattack. The treant makes two Slam attacks.\n- Slam. Melee Attack Roll: +10, reach 5 ft. Hit: 16 (3d6 + 6) Bludgeoning damage.\n- Hail of Bark. Ranged Attack Roll: +10, range 180 ft. Hit: 28 (4d10 + 6) Piercing damage.\n- Animate Trees (1/Day). The treant magically animates up to two trees it can see within 60 feet of itself. Each tree uses the Treant stat block, except it has Intelligence and Charisma scores of 1, it can't speak, and it lacks this action. The tree takes its turn immediately after the treant on the same Initiative count, and it obeys the treant. A tree remains animate for 1 day or until it dies, the treant dies, or it is more than 120 feet from the treant.\n- The tree then takes root if possible.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Treant","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Troll","constant":false,"content":"## Troll (monster stat block, SRD 5.2.1)\nLarge Giant, Chaotic Evil. AC 15, HP 94 (9d10+45), Initiative +1, Speed 30 ft..\nAbilities: Str 18 (save +4), Dex 13 (save +1), Con 20 (save +5), Int 7 (save -2), Wis 9 (save -1), Cha 7 (save -2).\nCR 5 (XP 1800, PB +3).\nSkills Perception +5\nSenses Darkvision 60 ft.; Passive Perception 15\nLanguages Giant\n### Traits\n- Loathsome Limbs (4/Day). If the troll ends any turn Bloodied and took 15+ Slashing damage during that turn, one of the troll's limbs is severed, falls into the troll's space, and becomes a Troll Limb. The limb acts immediately after the troll's turn. The troll has 1 Exhaustion level for each missing limb, and it grows replacement limbs the next time it regains Hit Points.\n- Regeneration. The troll regains 15 Hit Points at the start of each of its turns. If the troll takes Acid or Fire damage, this trait doesn't function on the troll's next turn. The troll dies only if it starts its turn with 0 Hit Points and doesn't regenerate.\n### Actions\n- Multiattack. The troll makes three Rend attacks.\n- Rend. Melee Attack Roll: +7, reach 10 ft. Hit: 11 (2d6 + 4) Slashing damage.\n### Bonus Actions\n- Charge. The troll moves up to half its Speed straight toward an enemy it can see.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Troll","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Troll Limb","constant":false,"content":"## Troll Limb (monster stat block, SRD 5.2.1)\nSmall Giant, Chaotic Evil. AC 13, HP 14 (4d6), Initiative +1, Speed 20 ft..\nAbilities: Str 18 (save +4), Dex 12 (save +1), Con 10 (save +0), Int 1 (save -5), Wis 9 (save -1), Cha 1 (save -5).\nCR 1/2 (XP 100, PB +2).\nSenses Darkvision 60 ft.; Passive Perception 9\nLanguages None\n### Traits\n- Regeneration. The limb regains 5 Hit Points at the start of each of its turns. If the limb takes Acid or Fire damage, this trait doesn't function on the limb's next turn. The limb dies only if it starts its turn with 0 Hit Points and doesn't regenerate.\n- Troll Spawn. The limb uncannily has the same senses as a whole troll. If the limb isn't destroyed within 24 hours, roll 1d12. On a 12, the limb turns into a Troll.\n- Otherwise, the limb withers away.\n### Actions\n- Rend. Melee Attack Roll: +6, reach 5 ft. Hit: 9 (2d4 + 4) Slashing damage.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Troll Limb","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Unicorn","constant":false,"content":"## Unicorn (monster stat block, SRD 5.2.1)\nLarge Celestial, Lawful Good. AC 12, HP 97 (13d10+26), Initiative +8, Speed 50 ft..\nAbilities: Str 18 (save +4), Dex 14 (save +2), Con 15 (save +2), Int 11 (save +0), Wis 17 (save +3), Cha 16 (save +3).\nCR 5 (XP 1800, PB +3).\nImmunities Poison; Charmed, Paralyzed, Poisoned\nSenses Darkvision 60 ft.; Passive Perception 13\nLanguages Celestial, Elvish, Sylvan; telepathy 120 ft.\n### Traits\n- Legendary Resistance (3/Day). If the unicorn fails a saving throw, it can choose to succeed instead.\n- Magic Resistance. The unicorn has Advantage on saving throws against spells and other magical effects.\n### Actions\n- Multiattack. The unicorn makes one Hooves attack and one Radiant Horn attack.\n- Hooves. Melee Attack Roll: +7, reach 5 ft. Hit: 11 (2d6 + 4) Bludgeoning damage.\n- Radiant Horn. Melee Attack Roll: +7, reach 5 ft. Hit: 9 (1d10 + 4) Radiant damage.\n- Spellcasting. The unicorn casts one of the following spells, requiring no spell components and using Charisma as the spellcasting ability (spell save DC 14): At Will: Detect Evil and Good, Druidcraft 1/Day Each: Calm Emotions, Dispel Evil and Good, Entangle, Pass without Trace, Word of Recall\n### Bonus Actions\n- Unicorn's Blessing (3/Day). The unicorn touches another creature with its horn and casts Cure Wounds or Lesser Restoration on that creature, using the same spellcasting ability as Spellcasting.\n### Legendary Actions\n- Legendary Action Uses: 3. Immediately after another creature's turn, the unicorn can expend a use to take one of the following actions. The unicorn regains all expended uses at the start of each of its turns.\n- Charging Horn. The unicorn moves up to half its Speed without provoking Opportunity Attacks, and it makes one Radiant Horn attack.\n- Shimmering Shield. The unicorn targets itself or one creature it can see within 60 feet of itself. The target gains 10 (3d6) Temporary Hit Points, and its AC increases by 2 until the end of the unicorn's next turn. The unicorn can't take this action again until the start of its next turn.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Unicorn","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Vampire Familiar","constant":false,"content":"## Vampire Familiar (monster stat block, SRD 5.2.1)\nMedium or Small Humanoid, Neutral Evil. AC 15, HP 65 (10d8+20), Initiative +5, Speed 30 ft., Climb 30 ft..\nAbilities: Str 17 (save +3), Dex 16 (save +5), Con 15 (save +2), Int 10 (save +0), Wis 10 (save +2), Cha 14 (save +2).\nCR 3 (XP 700, PB +2).\nSkills Perception +4, Persuasion +4, Stealth +7\nResistances Necrotic\nImmunities Charmed (except from its vampire master)\nGear Daggers (10)\nSenses Darkvision 60 ft.; Passive Perception 14\nLanguages Common plus one other language\n### Traits\n- Vampiric Connection. While the familiar and its vampire master are on the same plane of existence, the vampire can communicate with the familiar telepathically, and the vampire can perceive through the familiar's senses.\n### Actions\n- Multiattack. The familiar makes two Umbral Dagger attacks.\n- Umbral Dagger. Melee or Ranged Attack Roll: +5, reach 5 ft. or range 20/60 ft. Hit: 5 (1d4 + 3) Piercing damage plus 7 (3d4) Necrotic damage. If the target is reduced to 0 Hit Points by this attack, the target becomes Stable but has the Poisoned condition for 1 hour. While it has the Poisoned condition, the target has the Paralyzed condition.\n### Bonus Actions\n- Deathless Agility. The familiar takes the Dash or Disengage action.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Vampire Familiar","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Vampire Spawn","constant":false,"content":"## Vampire Spawn (monster stat block, SRD 5.2.1)\nMedium or Small Undead, Neutral Evil. AC 16, HP 90 (12d8+36), Initiative +3, Speed 30 ft..\nAbilities: Str 16 (save +3), Dex 16 (save +6), Con 16 (save +3), Int 11 (save +0), Wis 10 (save +3), Cha 12 (save +1).\nCR 5 (XP 1800, PB +3).\nSkills Perception +3, Stealth +6\nResistances Necrotic\nSenses Darkvision 60 ft.; Passive Perception 13\nLanguages Common plus one other language\n### Traits\n- Spider Climb. The vampire can climb difficult surfaces, including along ceilings, without needing to make an ability check.\n- Vampire Weakness. The vampire has these weaknesses: Forbiddance. The vampire can't enter a residence without an invitation from an occupant.\n- Running Water. The vampire takes 20 Acid damage if it ends its turn in running water.\n- Stake to the Heart. The vampire is destroyed if a weapon that deals Piercing damage is driven into the vampire's heart while the vampire has the Incapacitated condition.\n- Sunlight. The vampire takes 20 Radiant damage if it starts its turn in sunlight. While in sunlight, it has Disadvantage on attack rolls and ability checks.\n### Actions\n- Multiattack. The vampire makes two Claw attacks and uses Bite.\n- Claw. Melee Attack Roll: +6, reach 5 ft. Hit: 8 (2d4 + 3) Slashing damage. If the target is a Medium or smaller creature, it has the Grappled condition (escape DC 13) from one of two claws.\n- Bite. Constitution Saving Throw: DC 14, one creature within 5 feet that is willing or that has the Grappled, Incapacitated, or Restrained condition. Failure: 5 (1d4 + 3) Piercing damage plus 10 (3d6) Necrotic damage. The target's Hit Point maximum decreases by an amount equal to the Necrotic damage taken, and the vampire regains Hit Points equal to that amount.\n### Bonus Actions\n- Deathless Agility. The vampire takes the Dash or Disengage action.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Vampire Spawn","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Vampire","constant":false,"content":"## Vampire (monster stat block, SRD 5.2.1)\nMedium or Small Undead, Lawful Evil. AC 16, HP 195 (23d8+92), Initiative +14, Speed 40 ft., Climb 40 ft..\nAbilities: Str 18 (save +4), Dex 18 (save +9), Con 18 (save +9), Int 17 (save +3), Wis 15 (save +7), Cha 18 (save +9).\nCR 13 (XP 10000, PB +5).\nSkills Perception +7, Stealth +9\nResistances Necrotic\nSenses Darkvision 120 ft.; Passive Perception 17\nLanguages Common plus two other languages\n### Traits\n- Legendary Resistance (3/Day, or 4/Day in Lair). If the vampire fails a saving throw, it can choose to succeed instead.\n- Misty Escape. If the vampire drops to 0 Hit Points outside its resting place, the vampire uses Shape-Shift to become mist (no action required). If it can't use Shape- Shift, it is destroyed. While it has 0 Hit Points in mist form, it can't return to its vampire form, and it must reach its resting place within 2 hours or be destroyed. Once in its resting place, it returns to its vampire form and has the Paralyzed condition until it regains any Hit Points, and it regains 1 Hit Point after spending 1 hour there.\n- Spider Climb. The vampire can climb difficult surfaces, including along ceilings, without needing to make an ability check.\n- Vampire Weakness. The vampire has these weaknesses: Forbiddance. The vampire can't enter a residence without an invitation from an occupant.\n- Running Water. The vampire takes 20 Acid damage if it ends its turn in running water.\n- Stake to the Heart. If a weapon that deals Piercing damage is driven into the vampire's heart while the vampire has the Incapacitated condition in its resting place, the vampire has the Paralyzed condition until the weapon is removed.\n- Sunlight. The vampire takes 20 Radiant damage if it starts its turn in sunlight. While in sunlight, it has Disadvantage on attack rolls and ability checks.\n### Actions\n- Multiattack (Vampire Form Only). The vampire makes two Grave Strike attacks and uses Bite.\n- Grave Strike (Vampire Form Only). Melee Attack Roll: +9, reach 5 ft. Hit: 8 (1d8 + 4) Bludgeoning damage plus 7 (2d6) Necrotic damage. If the target is a Large or smaller creature, it has the Grappled condition (escape DC 14) from one of two hands.\n- Bite (Bat or Vampire Form Only). Constitution Saving Throw: DC 17, one creature within 5 feet that is willing or that has the Grappled, Incapacitated, or Restrained condition. Failure: 6 (1d4 + 4) Piercing damage plus 13 (3d8) Necrotic damage. The target's Hit Point maximum decreases by an amount equal to the Necrotic damage taken, and the vampire regains Hit Points equal to that amount. A Humanoid reduced to 0 Hit Points by this damage and then buried rises the following sunset as a Vampire Spawn under the vampire's control.\n### Bonus Actions\n- Charm (Recharge 5–6). The vampire casts Charm Person, requiring no spell components and using Charisma as the spellcasting ability (spell save DC 17), and the duration is 24 hours. The Charmed target is a willing recipient of the vampire's Bite, the damage of which doesn't end the spell. When the spell ends, the target is unaware it was Charmed by the vampire.\n- Shape-Shift. If the vampire isn't in sunlight or running water, it shape-shifts into a Tiny bat (Speed 5 ft., Fly Speed 30 ft.) or a Medium cloud of mist (Speed 5 ft., Fly Speed 20 ft. [hover]), or it returns to its vampire form. Anything it is wearing transforms with it.\n- While in bat form, the vampire can't speak. Its game statistics, other than its size and Speed, are unchanged. While in mist form, the vampire can't take any actions, speak, or manipulate objects. It is weightless and can enter an enemy's space and stop there. If air can pass through a space, the mist can do so, but it can't pass through liquid. It has Resistance to all damage, except the damage it takes from sunlight.\n### Legendary Actions\n- Legendary Action Uses: 3 (4 in Lair). Immediately after another creature's turn, the vampire can expend a use to take one of the following actions. The vampire regains all expended uses at the start of each of its turns.\n- Beguile. The vampire casts Command, requiring no spell components and using Charisma as the spellcasting ability (spell save DC 17). The vampire can't take this action again until the start of its next turn.\n- Deathless Strike. The vampire moves up to half its Speed, and it makes one Grave Strike attack.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Vampire","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Vrock","constant":false,"content":"## Vrock (monster stat block, SRD 5.2.1)\nLarge Fiend (Demon), Chaotic Evil. AC 15, HP 152 (16d10+64), Initiative +2, Speed 40 ft., Fly 60 ft..\nAbilities: Str 17 (save +3), Dex 15 (save +5), Con 18 (save +4), Int 8 (save -1), Wis 13 (save +4), Cha 8 (save +2).\nCR 6 (XP 2300, PB +3).\nResistances Cold, Fire, Lightning\nImmunities Poison; Poisoned\nSenses Darkvision 120 ft.; Passive Perception 11\nLanguages Abyssal; telepathy 120 ft.\n### Traits\n- Demonic Restoration. If the vrock dies outside the Abyss, its body dissolves into ichor, and it gains a new body instantly, reviving with all its Hit Points somewhere in the Abyss.\n- Magic Resistance. The vrock has Advantage on saving throws against spells and other magical effects.\n### Actions\n- Multiattack. The vrock makes two Shred attacks.\n- Shred. Melee Attack Roll: +6, reach 5 ft. Hit: 10 (2d6 + 3) Piercing damage plus 10 (3d6) Poison damage.\n- Spores (Recharge 6). Constitution Saving Throw: DC 15, each creature in a 20-foot Emanation originating from the vrock. Failure: The target has the Poisoned condition and repeats the save at the end of each of its turns, ending the effect on itself on a success. While Poisoned, the target takes 5 (1d10) Poison damage at the start of each of its turns. Emptying a flask of Holy Water on the target ends the effect early.\n- Stunning Screech (1/Day). Constitution Saving Throw: DC 15, each creature in a 20-foot Emanation originating from the vrock (demons succeed automatically). Failure: 10 (3d6) Thunder damage, and the target has the Stunned condition until the end of the vrock's next turn.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Vrock","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Warrior Infantry","constant":false,"content":"## Warrior Infantry (monster stat block, SRD 5.2.1)\nMedium or Small Humanoid, Neutral. AC 13, HP 9 (2d8), Initiative +0, Speed 30 ft..\nAbilities: Str 13 (save +1), Dex 11 (save +0), Con 11 (save +0), Int 8 (save -1), Wis 11 (save +0), Cha 8 (save -1).\nCR 1/8 (XP 25, PB +2).\nGear Chain Shirt, Spear\nSenses Passive Perception 10\nLanguages Common\n### Traits\n- Pack Tactics. The warrior has Advantage on an attack roll against a creature if at least one of the warrior's allies is within 5 feet of the creature and the ally doesn't have the Incapacitated condition.\n### Actions\n- Spear. Melee or Ranged Attack Roll: +3, reach 5 ft. or range 20/60 ft. Hit: 4 (1d6 + 1) Piercing damage.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Warrior Infantry","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Warrior Veteran","constant":false,"content":"## Warrior Veteran (monster stat block, SRD 5.2.1)\nMedium or Small Humanoid, Neutral. AC 17, HP 65 (10d8+20), Initiative +3, Speed 30 ft..\nAbilities: Str 16 (save +3), Dex 13 (save +1), Con 14 (save +2), Int 10 (save +0), Wis 11 (save +0), Cha 10 (save +0).\nCR 3 (XP 700, PB +2).\nSkills Athletics +5, Perception +2\nGear Greatsword, Heavy Crossbow, Splint Armor\nSenses Passive Perception 12\nLanguages Common plus one other language\n### Actions\n- Multiattack. The warrior makes two Greatsword or Heavy Crossbow attacks.\n- Greatsword. Melee Attack Roll: +5, reach 5 ft. Hit: 10 (2d6 + 3) Slashing damage.\n- Heavy Crossbow. Ranged Attack Roll: +3, range 100/400 ft. Hit: 12 (2d10 + 1) Piercing damage.\n### Reactions\n- Parry. Trigger: The warrior is hit by a melee attack roll while holding a weapon. Response: The warrior adds 2 to its AC against that attack, possibly causing it to miss.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Warrior Veteran","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Water Elemental","constant":false,"content":"## Water Elemental (monster stat block, SRD 5.2.1)\nLarge Elemental, Neutral. AC 14, HP 114 (12d10+48), Initiative +2, Speed 30 ft., Swim 90 ft..\nAbilities: Str 18 (save +4), Dex 14 (save +2), Con 18 (save +4), Int 5 (save -3), Wis 10 (save +0), Cha 8 (save -1).\nCR 5 (XP 1800, PB +3).\nResistances Acid, Fire\nImmunities Poison; Exhaustion, Grappled, Paralyzed, Petrified, Poisoned, Prone, Restrained, Unconscious\nSenses Darkvision 60 ft.; Passive Perception 10\nLanguages Primordial (Aquan)\n### Traits\n- Freeze. If the elemental takes Cold damage, its Speed decreases by 20 feet until the end of its next turn.\n- Water Form. The elemental can enter an enemy's space and stop there. It can move through a space as narrow as 1 inch without expending extra movement to do so.\n### Actions\n- Multiattack. The elemental makes two Slam attacks.\n- Slam. Melee Attack Roll: +7, reach 5 ft. Hit: 13 (2d8 + 4) Bludgeoning damage. If the target is a Medium or smaller creature, it has the Prone condition.\n- Whelm (Recharge 4–6). Strength Saving Throw: DC 15, each creature in the elemental's space. Failure: 22 (4d8 + 4) Bludgeoning damage. If the target is a Large or smaller creature, it has the Grappled condition (escape DC 14). Until the grapple ends, the target has the Restrained condition, is suffocating unless it can breathe water, and takes 9 (2d8) Bludgeoning damage at the start of each of the elemental's turns. The elemental can grapple one Large creature or up to two Medium or smaller creatures at a time with Whelm. As an action, a creature within 5 feet of the elemental can pull a creature out of it by succeeding on a DC 14 Strength (Athletics) check. Success: Half damage only.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Water Elemental","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Werebear","constant":false,"content":"## Werebear (monster stat block, SRD 5.2.1)\nMedium or Small Monstrosity (Lycanthrope), Neutral Good. AC 15, HP 135 (18d8+54), Initiative +3, Speed 30 ft., 40 ft. (bear form only), Climb 30 ft. (bear.\nAbilities: Str 19 (save +4), Dex 10 (save +0), Con 17 (save +3), Int 11 (save +0), Wis 12 (save +1), Cha 12 (save +1).\nCR 5 (XP 1800, PB +3).\nSkills Perception +7\nGear Handaxes (4)\nSenses Darkvision 60 ft.; Passive Perception 17\nLanguages Common (can't speak in bear form)\n### Actions\n- Multiattack. The werebear makes two attacks, using Handaxe or Rend in any combination. It can replace one attack with a Bite attack.\n- Bite (Bear or Hybrid Form Only). Melee Attack Roll: +7, reach 5 ft. Hit: 17 (2d12 + 4) Piercing damage. If the target is a Humanoid, it is subjected to the following effect. Constitution Saving Throw: DC 14. Failure: The target is cursed. If the cursed target drops to 0 Hit Points, it instead becomes a Werebear under the GM's control and has 10 Hit Points. Success: The target is immune to this werebear's curse for 24 hours.\n- Handaxe (Humanoid or Hybrid Form Only). Melee or Ranged Attack Roll: +7, reach 5 ft or range 20/60 ft. Hit: 14 (3d6 + 4) Slashing damage.\n- Rend (Bear or Hybrid Form Only). Melee Attack Roll: +7, reach 5 ft. Hit: 13 (2d8 + 4) Slashing damage.\n### Bonus Actions\n- Shape-Shift. The werebear shape-shifts into a Large bear-humanoid hybrid form or a Large bear, or it returns to its true humanoid form. Its game statistics, other than its size, are the same in each form. Any equipment it is wearing or carrying isn't transformed.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Werebear","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Wereboar","constant":false,"content":"## Wereboar (monster stat block, SRD 5.2.1)\nMedium or Small Monstrosity (Lycanthrope), Neutral Evil. AC 15, HP 97 (15d8+30), Initiative +2, Speed 30 ft., 40 ft. (boar form only).\nAbilities: Str 17 (save +3), Dex 10 (save +0), Con 15 (save +2), Int 10 (save +0), Wis 11 (save +0), Cha 8 (save -1).\nCR 4 (XP 1100, PB +2).\nSkills Perception +2\nGear Javelins (6)\nSenses Passive Perception 12\nLanguages Common (can't speak in boar form)\n### Actions\n- Multiattack. The wereboar makes two attacks, using Javelin or Tusk in any combination. It can replace one attack with a Gore attack.\n- Gore (Boar or Hybrid Form Only). Melee Attack Roll: +5, reach 5 ft. Hit: 12 (2d8 + 3) Piercing damage. If the target is a Humanoid, it is subjected to the following effect. Constitution Saving Throw: DC 12. Failure: The target is cursed. If the cursed target drops to 0 Hit Points, it instead becomes a Wereboar under the GM's control and has 10 Hit Points. Success: The target is immune to this wereboar's curse for 24 hours.\n- Javelin (Humanoid or Hybrid Form Only). Melee or Ranged Attack Roll: +5, reach 5 ft. or range 30/120 ft. Hit: 13 (3d6 + 3) Piercing damage.\n- Tusk (Boar or Hybrid Form Only). Melee Attack Roll: +5, reach 5 ft. Hit: 10 (2d6 + 3) Piercing damage. If the target is a Medium or smaller creature and the wereboar moved 20+ feet straight toward it immediately before the hit, the target takes an extra 7 (2d6) Piercing damage and has the Prone condition.\n### Bonus Actions\n- Shape-Shift. The wereboar shape-shifts into a Medium boar-humanoid hybrid or a Small boar, or it returns to its true humanoid form. Its game statistics, other than its size, are the same in each form. Any equipment it is wearing or carrying isn't transformed.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Wereboar","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Wererat","constant":false,"content":"## Wererat (monster stat block, SRD 5.2.1)\nMedium or Small Monstrosity (Lycanthrope), Lawful Evil. AC 13, HP 60 (11d8+11), Initiative +3, Speed 30 ft., Climb 30 ft..\nAbilities: Str 10 (save +0), Dex 16 (save +3), Con 12 (save +1), Int 11 (save +0), Wis 10 (save +0), Cha 8 (save -1).\nCR 2 (XP 450, PB +2).\nSkills Perception +4, Stealth +5\nGear Hand Crossbow\nSenses Darkvision 60 ft.; Passive Perception 14\nLanguages Common (can't speak in rat form)\n### Actions\n- Multiattack. The wererat makes two attacks, using Scratch or Hand Crossbow in any combination. It can replace one attack with a Bite attack.\n- Bite (Rat or Hybrid Form Only). Melee Attack Roll: +5, reach 5 ft. Hit: 8 (2d4 + 3) Piercing damage. If the target is a Humanoid, it is subjected to the following effect. Constitution Saving Throw: DC 11. Failure: The target is cursed. If the cursed target drops to 0 Hit Points, it instead becomes a Wererat under the GM's control and has 10 Hit Points. Success: The target is immune to this wererat's curse for 24 hours.\n- Scratch. Melee Attack Roll: +5, reach 5 ft. Hit: 6 (1d6 + 3) Slashing damage.\n- Hand Crossbow (Humanoid or Hybrid Form Only).\n- Ranged Attack Roll: +5, range 30/120 ft. Hit: 6 (1d6 + 3) Piercing damage.\n### Bonus Actions\n- Shape-Shift. The wererat shape-shifts into a Medium rat-humanoid hybrid or a Small rat, or it returns to its true humanoid form. Its game statistics, other than its size, are the same in each form. Any equipment it is wearing or carrying isn't transformed.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Wererat","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Weretiger","constant":false,"content":"## Weretiger (monster stat block, SRD 5.2.1)\nMedium or Small Monstrosity (Lycanthrope), Neutral. AC 12, HP 120 (16d8+48), Initiative +2, Speed 30 ft., 40 ft. (tiger form only).\nAbilities: Str 17 (save +3), Dex 15 (save +2), Con 16 (save +3), Int 10 (save +0), Wis 13 (save +1), Cha 11 (save +0).\nCR 4 (XP 1100, PB +2).\nSkills Perception +5, Stealth +4\nGear Longbow\nSenses Darkvision 60 ft.; Passive Perception 15\nLanguages Common (can't speak in tiger form)\n### Actions\n- Multiattack. The weretiger makes two attacks, using Scratch or Longbow in any combination. It can replace one attack with a Bite attack.\n- Bite (Tiger or Hybrid Form Only). Melee Attack Roll: +5, reach 5 ft. Hit: 12 (2d8 + 3) Piercing damage. If the target is a Humanoid, it is subjected to the following effect. Constitution Saving Throw: DC 13. Failure: The target is cursed. If the cursed target drops to 0 Hit Points, it instead becomes a Weretiger under the GM's control and has 10 Hit Points. Success: The target is immune to this weretiger's curse for 24 hours.\n- Scratch. Melee Attack Roll: +5, reach 5 ft. Hit: 10 (2d6 + 3) Slashing damage.\n- Longbow (Humanoid or Hybrid Form Only). Ranged Attack Roll: +4, range 150/600 ft. Hit: 11 (2d8 + 2) Piercing damage.\n### Bonus Actions\n- Prowl (Tiger or Hybrid Form Only). The weretiger moves up to its Speed without provoking Opportunity Attacks. At the end of this movement, the weretiger can take the Hide action.\n- Shape-Shift. The weretiger shape-shifts into a Large tiger-humanoid hybrid or a Large tiger, or it returns to its true humanoid form. Its game statistics, other than its size, are the same in each form. Any equipment it is wearing or carrying isn't transformed.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Weretiger","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Werewolf","constant":false,"content":"## Werewolf (monster stat block, SRD 5.2.1)\nMedium or Small Monstrosity (Lycanthrope), Chaotic Evil. AC 15, HP 71 (11d8+22), Initiative +4, Speed 30 ft., 40 ft. (wolf form only).\nAbilities: Str 16 (save +3), Dex 14 (save +2), Con 14 (save +2), Int 10 (save +0), Wis 11 (save +0), Cha 10 (save +0).\nCR 3 (XP 700, PB +2).\nSkills Perception +4, Stealth +4\nGear Longbow\nSenses Darkvision 60 ft.; Passive Perception 14\nLanguages Common (can't speak in wolf form)\n### Traits\n- Pack Tactics. The werewolf has Advantage on an attack roll against a creature if at least one of the werewolf's allies is within 5 feet of the creature and the ally doesn't have the Incapacitated condition.\n### Actions\n- Multiattack. The werewolf makes two attacks, using Scratch or Longbow in any combination. It can replace one attack with a Bite attack.\n- Bite (Wolf or Hybrid Form Only). Melee Attack Roll: +5, reach 5 ft. Hit: 12 (2d8 + 3) Piercing damage. If the target is a Humanoid, it is subjected to the following effect. Constitution Saving Throw: DC 12. Failure: The target is cursed. If the cursed target drops to 0 Hit Points, it instead becomes a Werewolf under the GM's control and has 10 Hit Points. Success: The target is immune to this werewolf's curse for 24 hours.\n- Scratch. Melee Attack Roll: +5, reach 5 ft. Hit: 10 (2d6 + 3) Slashing damage.\n- Longbow (Humanoid or Hybrid Form Only). Ranged Attack Roll: +4, range 150/600 ft. Hit: 11 (2d8 + 2) Piercing damage.\n### Bonus Actions\n- Shape-Shift. The werewolf shape-shifts into a Large wolf-humanoid hybrid or a Medium wolf, or it returns to its true humanoid form. Its game statistics, other than its size, are the same in each form. Any equipment it is wearing or carrying isn't transformed.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Werewolf","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: White Dragon Wyrmling","constant":false,"content":"## White Dragon Wyrmling (monster stat block, SRD 5.2.1)\nMedium Dragon (Chromatic), Chaotic Evil. AC 16, HP 32 (5d8+10), Initiative +2, Speed 30 ft., Burrow 15 ft., Fly 60 ft., Swim 30 ft..\nAbilities: Str 14 (save +2), Dex 10 (save +2), Con 14 (save +2), Int 5 (save -3), Wis 10 (save +2), Cha 11 (save +0).\nCR 2 (XP 450, PB +2).\nSkills Perception +4, Stealth +2\nImmunities Cold\nSenses Blindsight 10 ft., Darkvision 60 ft.; Passive Perception 14\nLanguages Draconic\n### Traits\n- Ice Walk. The dragon can move across and climb icy surfaces without needing to make an ability check. Additionally, Difficult Terrain composed of ice or snow doesn't cost it extra movement.\n### Actions\n- Multiattack. The dragon makes two Rend attacks.\n- Rend. Melee Attack Roll: +4, reach 5 ft. Hit: 6 (1d8 + 2) Slashing damage plus 2 (1d4) Cold damage.\n- Cold Breath (Recharge 5–6). Constitution Saving Throw: DC 12, each creature in a 15-foot Cone. Failure: 22 (5d8) Cold damage. Success: Half damage.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: White Dragon Wyrmling","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Young White Dragon","constant":false,"content":"## Young White Dragon (monster stat block, SRD 5.2.1)\nLarge Dragon (Chromatic), Chaotic Evil. AC 17, HP 123 (13d10+52), Initiative +3, Speed 40 ft., Burrow 20 ft., Fly 80 ft., Swim 40 ft..\nAbilities: Str 18 (save +4), Dex 10 (save +3), Con 18 (save +4), Int 6 (save -2), Wis 11 (save +3), Cha 12 (save +1).\nCR 6 (XP 2300, PB +3).\nSkills Perception +6, Stealth +3\nImmunities Cold\nSenses Blindsight 30 ft., Darkvision 120 ft.; Passive Perception 16\nLanguages Common, Draconic\n### Traits\n- Ice Walk. The dragon can move across and climb icy surfaces without needing to make an ability check. Additionally, Difficult Terrain composed of ice or snow doesn't cost it extra movement.\n### Actions\n- Multiattack. The dragon makes three Rend attacks.\n- Rend. Melee Attack Roll: +7, reach 10 ft. Hit: 9 (2d4 + 4) Slashing damage plus 2 (1d4) Cold damage.\n- Cold Breath (Recharge 5–6). Constitution Saving Throw: DC 15, each creature in a 30-foot Cone. Failure: 40 (9d8) Cold damage. Success: Half damage.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Young White Dragon","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Adult White Dragon","constant":false,"content":"## Adult White Dragon (monster stat block, SRD 5.2.1)\nHuge Dragon (Chromatic), Chaotic Evil. AC 18, HP 200 (16d12+96), Initiative +10, Speed 40 ft., Burrow 30 ft., Fly 80 ft., Swim 40 ft..\nAbilities: Str 22 (save +6), Dex 10 (save +5), Con 22 (save +6), Int 8 (save -1), Wis 12 (save +6), Cha 12 (save +1).\nCR 13 (XP 10000, PB +5).\nSkills Perception +11, Stealth +5\nImmunities Cold\nSenses Blindsight 60 ft., Darkvision 120 ft.; Passive Perception 21\nLanguages Common, Draconic\n### Traits\n- Ice Walk. The dragon can move across and climb icy surfaces without needing to make an ability check. Additionally, Difficult Terrain composed of ice or snow doesn't cost it extra movement.\n- Legendary Resistance (3/Day, or 4/Day in Lair). If the dragon fails a saving throw, it can choose to succeed instead.\n### Actions\n- Multiattack. The dragon makes three Rend attacks.\n- Rend. Melee Attack Roll: +11, reach 10 ft. Hit: 13 (2d6 + 6) Slashing damage plus 4 (1d8) Cold damage.\n- Cold Breath (Recharge 5–6). Constitution Saving Throw: DC 19, each creature in a 60-foot Cone. Failure: 54 (12d8) Cold damage. Success: Half damage.\n### Legendary Actions\n- Legendary Action Uses: 3 (4 in Lair). Immediately after another creature's turn, the dragon can expend a use to take one of the following actions. The dragon regains all expended uses at the start of each of its turns.\n- Freezing Burst. Constitution Saving Throw: DC 14, each creature in a 30-foot-radius Sphere centered on a point the dragon can see within 120 feet. Failure: 7 (2d6) Cold damage, and the target's Speed is 0 until the end of the target's next turn. Failure or Success: The dragon can't take this action again until the start of its next turn.\n- Frightful Presence. The dragon casts Fear, requiring no Material components and using Charisma as the spellcasting ability (spell save DC 14). The dragon can't take this action again until the start of its next turn.\n- Pounce. The dragon moves up to half its Speed, and it makes one Rend attack.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Adult White Dragon","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Ancient White Dragon","constant":false,"content":"## Ancient White Dragon (monster stat block, SRD 5.2.1)\nGargantuan Dragon (Chromatic), Chaotic Evil. AC 20, HP 333 (18d20+144), Initiative +12, Speed 40 ft., Burrow 40 ft., Fly 80 ft., Swim 40 ft..\nAbilities: Str 26 (save +8), Dex 10 (save +6), Con 26 (save +8), Int 10 (save +0), Wis 13 (save +7), Cha 18 (save +4).\nCR 20 (XP 25000, PB +6).\nSkills Perception +13, Stealth +6\nImmunities Cold\nSenses Blindsight 60 ft., Darkvision 120 ft.; Passive Perception 23\nLanguages Common, Draconic\n### Traits\n- Ice Walk. The dragon can move across and climb icy surfaces without needing to make an ability check. Additionally, Difficult Terrain composed of ice or snow doesn't cost it extra movement.\n- Legendary Resistance (4/Day, or 5/Day in Lair). If the dragon fails a saving throw, it can choose to succeed instead.\n### Actions\n- Multiattack. The dragon makes three Rend attacks.\n- Rend. Melee Attack Roll: +14, reach 15 ft. Hit: 17 (2d8 + 8) Slashing damage plus 7 (2d6) Cold damage.\n- Cold Breath (Recharge 5–6). Constitution Saving Throw: DC 22, each creature in a 90-foot Cone. Failure: 63 (14d8) Cold damage. Success: Half damage.\n### Legendary Actions\n- Legendary Action Uses: 3 (4 in Lair). Immediately after another creature's turn, the dragon can expend a use to take one of the following actions. The dragon regains all expended uses at the start of each of its turns.\n- Freezing Burst. Constitution Saving Throw: DC 20, each creature in a 30-foot-radius Sphere centered on a point the dragon can see within 120 feet. Failure: 14 (4d6) Cold damage, and the target's Speed is 0 until the end of the target's next turn. Failure or Success: The dragon can't take this action again until the start of its next turn.\n- Frightful Presence. The dragon casts Fear, requiring no Material components and using Charisma as the spellcasting ability (spell save DC 18). The dragon can't take this action again until the start of its next turn.\n- Pounce. The dragon moves up to half its Speed, and it makes one Rend attack.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Ancient White Dragon","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Wight","constant":false,"content":"## Wight (monster stat block, SRD 5.2.1)\nMedium Undead, Neutral Evil. AC 14, HP 82 (11d8+33), Initiative +4, Speed 30 ft..\nAbilities: Str 15 (save +2), Dex 14 (save +2), Con 16 (save +3), Int 10 (save +0), Wis 13 (save +1), Cha 15 (save +2).\nCR 3 (XP 700, PB +2).\nSkills Perception +3, Stealth +4\nResistances Necrotic\nImmunities Poison; Exhaustion, Poisoned\nGear Studded Leather Armor\nSenses Darkvision 60 ft.; Passive Perception 13\nLanguages Common plus one other language\n### Traits\n- Sunlight Sensitivity. While in sunlight, the wight has Disadvantage on ability checks and attack rolls.\n### Actions\n- Multiattack. The wight makes two attacks, using Necrotic Sword or Necrotic Bow in any combination. It can replace one attack with a use of Life Drain.\n- Necrotic Sword. Melee Attack Roll: +4, reach 5 ft. Hit: 6 (1d8 + 2) Slashing damage plus 4 (1d8) Necrotic damage.\n- Necrotic Bow. Ranged Attack Roll: +4, range 150/600 ft. Hit: 6 (1d8 + 2) Piercing damage plus 4 (1d8) Necrotic damage.\n- Life Drain. Constitution Saving Throw: DC 13, one creature within 5 feet. Failure: 6 (1d8 + 2) Necrotic damage, and the target's Hit Point maximum decreases by an amount equal to the damage taken. A Humanoid slain by this attack rises 24 hours later as a Zombie under the wight's control, unless the Humanoid is restored to life or its body is destroyed. The wight can have no more than twelve zombies under its control at a time.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Wight","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Will-o'-Wisp","constant":false,"content":"## Will-o'-Wisp (monster stat block, SRD 5.2.1)\nTiny Undead, Chaotic Evil. AC 19, HP 27 (11d4), Initiative +9, Speed 5 ft., Fly 50 ft. (hover).\nAbilities: Str 1 (save -5), Dex 28 (save +9), Con 10 (save +0), Int 13 (save +1), Wis 14 (save +2), Cha 11 (save +0).\nCR 2 (XP 450, PB +2).\nResistances Acid, Bludgeoning, Cold, Fire, Necrotic, Piercing, Slashing\nImmunities Lightning, Poison; Exhaustion, Grappled, Paralyzed, Petrified, Poisoned, Prone, Restrained, Unconscious\nSenses Darkvision 120 ft.; Passive Perception 12\nLanguages Common plus one other language\n### Traits\n- Ephemeral. The wisp can't wear or carry anything.\n- Illumination. The wisp sheds Bright Light in a 20-foot radius and Dim Light for an additional 20 feet.\n- Incorporeal Movement. The wisp can move through other creatures and objects as if they were Difficult Terrain. It takes 5 (1d10) Force damage if it ends its turn inside an object.\n### Actions\n- Shock. Melee Attack Roll: +4, reach 5 ft. Hit: 11 (2d8 + 2) Lightning damage.\n### Bonus Actions\n- Consume Life. Constitution Saving Throw: DC 10, one living creature the wisp can see within 5 feet that has 0 Hit Points. Failure: The target dies, and the wisp regains 10 (3d6) Hit Points.\n- Vanish. The wisp and its light have the Invisible condition until the wisp's Concentration ends on this effect, which ends early immediately after the wisp makes an attack roll or uses Consume Life.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Will-o'-Wisp","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Winter Wolf","constant":false,"content":"## Winter Wolf (monster stat block, SRD 5.2.1)\nLarge Monstrosity, Neutral Evil. AC 13, HP 75 (10d10+20), Initiative +1, Speed 50 ft..\nAbilities: Str 18 (save +4), Dex 13 (save +1), Con 14 (save +2), Int 7 (save -2), Wis 12 (save +1), Cha 8 (save -1).\nCR 3 (XP 700, PB +2).\nSkills Perception +5, Stealth +5\nImmunities Cold\nSenses Passive Perception 15\nLanguages Common, Giant\n### Traits\n- Pack Tactics. The wolf has Advantage on an attack roll against a creature if at least one of the wolf's allies is within 5 feet of the creature and the ally doesn't have the Incapacitated condition.\n### Actions\n- Bite. Melee Attack Roll: +6, reach 5 ft. Hit: 11 (2d6 + 4) Piercing damage. If the target is a Large or smaller creature, it has the Prone condition.\n- Cold Breath (Recharge 5–6). Constitution Saving Throw: DC 12, each creature in a 15-foot Cone. Failure: 18 (4d8) Cold damage. Success: Half damage.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Winter Wolf","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Worg","constant":false,"content":"## Worg (monster stat block, SRD 5.2.1)\nLarge Fey, Neutral Evil. AC 13, HP 26 (4d10+4), Initiative +1, Speed 50 ft..\nAbilities: Str 16 (save +3), Dex 13 (save +1), Con 13 (save +1), Int 7 (save -2), Wis 11 (save +0), Cha 8 (save -1).\nCR 1/2 (XP 100, PB +2).\nSkills Perception +4\nSenses Darkvision 60 ft.; Passive Perception 14\nLanguages Goblin, Worg\n### Actions\n- Bite. Melee Attack Roll: +5, reach 5 ft. Hit: 7 (1d8 + 3) Piercing damage, and the next attack roll made against the target before the start of the worg's next turn has Advantage.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Worg","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Wraith","constant":false,"content":"## Wraith (monster stat block, SRD 5.2.1)\nMedium or Small Undead, Neutral Evil. AC 13, HP 67 (9d8+27), Initiative +3, Speed 5 ft., Fly 60 ft. (hover).\nAbilities: Str 6 (save -2), Dex 16 (save +3), Con 16 (save +3), Int 12 (save +1), Wis 14 (save +2), Cha 15 (save +2).\nCR 5 (XP 1800, PB +3).\nResistances Acid, Bludgeoning, Cold, Fire, Piercing, Slashing\nImmunities Necrotic, Poison; Charmed, Exhaustion, Grappled, Paralyzed, Petrified, Poisoned, Prone, Restrained, Unconscious\nSenses Darkvision 60 ft.; Passive Perception 12\nLanguages Common plus two other languages\n### Traits\n- Incorporeal Movement. The wraith can move through other creatures and objects as if they were Difficult Terrain. It takes 5 (1d10) Force damage if it ends its turn inside an object.\n- Sunlight Sensitivity. While in sunlight, the wraith has Disadvantage on ability checks and attack rolls.\n### Actions\n- Life Drain. Melee Attack Roll: +6, reach 5 ft. Hit: 21 (4d8 + 3) Necrotic damage. If the target is a creature, its Hit Point maximum decreases by an amount equal to the damage taken.\n- Create Specter. The wraith targets a Humanoid corpse within 10 feet of itself that has been dead for no longer than 1 minute. The target's spirit rises as a Specter in the space of its corpse or in the nearest unoccupied space. The specter is under the wraith's control. The wraith can have no more than seven specters under its control at a time.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Wraith","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Wyvern","constant":false,"content":"## Wyvern (monster stat block, SRD 5.2.1)\nLarge Dragon, Unaligned. AC 14, HP 127 (15d10+45), Initiative +0, Speed 30 ft., Fly 80 ft..\nAbilities: Str 19 (save +4), Dex 10 (save +0), Con 16 (save +3), Int 5 (save -3), Wis 12 (save +1), Cha 6 (save -2).\nCR 6 (XP 2300, PB +3).\nSkills Perception +4\nSenses Darkvision 120 ft.; Passive Perception 14\nLanguages None\n### Actions\n- Multiattack. The wyvern makes one Bite attack and one Sting attack.\n- Bite. Melee Attack Roll: +7, reach 5 ft. Hit: 13 (2d8 + 4) Piercing damage.\n- Sting. Melee Attack Roll: +7, reach 10 ft. Hit: 11 (2d6 + 4) Piercing damage plus 24 (7d6) Poison damage, and the target has the Poisoned condition until the start of the wyvern's next turn.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Wyvern","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Xorn","constant":false,"content":"## Xorn (monster stat block, SRD 5.2.1)\nMedium Elemental, Neutral. AC 19, HP 84 (8d8+48), Initiative +0, Speed 20 ft., Burrow 20 ft..\nAbilities: Str 17 (save +3), Dex 10 (save +0), Con 22 (save +6), Int 11 (save +0), Wis 10 (save +0), Cha 11 (save +0).\nCR 5 (XP 1800, PB +3).\nSkills Perception +6, Stealth +6\nImmunities Poison; Paralyzed, Petrified, Poisoned\nSenses Darkvision 60 ft., Tremorsense 60 ft.; Passive Perception 16\nLanguages Primordial (Terran)\n### Traits\n- Earth Glide. The xorn can burrow through nonmagical, unworked earth and stone. While doing so, the xorn doesn't disturb the material it moves through.\n- Treasure Sense. The xorn can pinpoint the location of precious metals and stones within 60 feet of itself.\n### Actions\n- Multiattack. The xorn makes one Bite attack and three Claw attacks.\n- Bite. Melee Attack Roll: +6, reach 5 ft. Hit: 17 (4d6 + 3) Piercing damage.\n- Claw. Melee Attack Roll: +6, reach 5 ft. Hit: 8 (1d10 + 3) Slashing damage.\n### Bonus Actions\n- Charge. The xorn moves up to its Speed or Burrow Speed straight toward an enemy it can sense.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Xorn","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Zombie","constant":false,"content":"## Zombie (monster stat block, SRD 5.2.1)\nMedium Undead, Neutral Evil. AC 8, HP 15 (2d8+6), Initiative -2, Speed 20 ft..\nAbilities: Str 13 (save +1), Dex 6 (save -2), Con 16 (save +3), Int 3 (save -4), Wis 6 (save +0), Cha 5 (save -3).\nCR 1/4 (XP 50, PB +2).\nImmunities Poison; Exhaustion, Poisoned\nSenses Darkvision 60 ft.; Passive Perception 8\nLanguages Understands Common plus one other language but can't speak\n### Traits\n- Undead Fortitude. If damage reduces the zombie to 0 Hit Points, it makes a Constitution saving throw (DC 5 plus the damage taken) unless the damage is Radiant or from a Critical Hit. On a successful save, the zombie drops to 1 Hit Point instead.\n### Actions\n- Slam. Melee Attack Roll: +3, reach 5 ft. Hit: 5 (1d8 + 1) Bludgeoning damage.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Zombie","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Ogre Zombie","constant":false,"content":"## Ogre Zombie (monster stat block, SRD 5.2.1)\nLarge Undead, Neutral Evil. AC 8, HP 85 (9d10+36), Initiative -2, Speed 30 ft..\nAbilities: Str 19 (save +4), Dex 6 (save -2), Con 18 (save +4), Int 3 (save -4), Wis 6 (save +0), Cha 5 (save -3).\nCR 2 (XP 450, PB +2).\nImmunities Poison; Exhaustion, Poisoned\nSenses Darkvision 60 ft.; Passive Perception 8\nLanguages Understands Common and Giant but can't speak\n### Traits\n- Undead Fortitude. If damage reduces the zombie to 0 Hit Points, it makes a Constitution saving throw (DC 5 plus the damage taken) unless the damage is Radiant or from a Critical Hit. On a successful save, the zombie drops to 1 Hit Point instead.\n### Actions\n- Slam. Melee Attack Roll: +6, reach 5 ft. Hit: 13 (2d8 + 4) Bludgeoning damage.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Ogre Zombie","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Allosaurus","constant":false,"content":"## Allosaurus (monster stat block, SRD 5.2.1)\nLarge Beast (Dinosaur), Unaligned. AC 13, HP 51 (6d10+18), Initiative +1, Speed 60 ft..\nAbilities: Str 19 (save +4), Dex 13 (save +1), Con 17 (save +3), Int 2 (save -4), Wis 12 (save +1), Cha 5 (save -3).\nCR 2 (XP 450, PB +2).\nSkills Perception +5\nSenses Passive Perception 15\nLanguages None\n### Actions\n- Bite. Melee Attack Roll: +6, reach 5 ft. Hit: 15 (2d10 + 4) Piercing damage.\n- Claws. Melee Attack Roll: +6, reach 5 ft. Hit: 8 (1d8 + 4) Slashing damage. If the target is a Large or smaller creature and the allosaurus moved 30+ feet straight toward it immediately before the hit, the target has the Prone condition, and the allosaurus can make one Bite attack against it.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Allosaurus","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Ankylosaurus","constant":false,"content":"## Ankylosaurus (monster stat block, SRD 5.2.1)\nHuge Beast (Dinosaur), Unaligned. AC 15, HP 68 (8d12+16), Initiative +0, Speed 30 ft..\nAbilities: Str 19 (save +6), Dex 11 (save +0), Con 15 (save +2), Int 2 (save -4), Wis 12 (save +1), Cha 5 (save -3).\nCR 3 (XP 700, PB +2).\nSenses Passive Perception 11\nLanguages None\n### Actions\n- Multiattack. The ankylosaurus makes two Tail attacks.\n- Tail. Melee Attack Roll: +6, reach 10 ft. Hit: 9 (1d10 + 4) Bludgeoning damage. If the target is a Huge or smaller creature, it has the Prone condition.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Ankylosaurus","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Ape","constant":false,"content":"## Ape (monster stat block, SRD 5.2.1)\nMedium Beast, Unaligned. AC 12, HP 19 (3d8+6), Initiative +2, Speed 30 ft., Climb 30 ft..\nAbilities: Str 16 (save +3), Dex 14 (save +2), Con 14 (save +2), Int 6 (save -2), Wis 12 (save +1), Cha 7 (save -2).\nCR 1/2 (XP 100, PB +2).\nSkills Athletics +5, Perception +3\nSenses Passive Perception 13\nLanguages None\n### Actions\n- Multiattack. The ape makes two Fist attacks.\n- Fist. Melee Attack Roll: +5, reach 5 ft. Hit: 5 (1d4 + 3) Bludgeoning damage.\n- Rock (Recharge 6). Ranged Attack Roll: +5, range 25/50 ft. Hit: 10 (2d6 + 3) Bludgeoning damage.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Ape","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Archelon","constant":false,"content":"## Archelon (monster stat block, SRD 5.2.1)\nHuge Beast (Dinosaur), Unaligned. AC 17, HP 90 (12d12+12), Initiative +3, Speed 20 ft., Swim 80 ft..\nAbilities: Str 18 (save +4), Dex 16 (save +3), Con 13 (save +1), Int 4 (save -3), Wis 14 (save +2), Cha 6 (save -2).\nCR 4 (XP 1100, PB +2).\nSkills Stealth +5\nSenses Passive Perception 12\nLanguages None\n### Traits\n- Amphibious. The archelon can breathe air and water.\n### Actions\n- Multiattack. The archelon makes two Bite attacks.\n- Bite. Melee Attack Roll: +6, reach 5 ft. Hit: 14 (3d6 + 4) Piercing damage.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Archelon","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Baboon","constant":false,"content":"## Baboon (monster stat block, SRD 5.2.1)\nSmall Beast, Unaligned. AC 12, HP 3 (1d6), Initiative +2, Speed 30 ft., Climb 30 ft..\nAbilities: Str 8 (save -1), Dex 14 (save +2), Con 11 (save +0), Int 4 (save -3), Wis 12 (save +1), Cha 6 (save -2).\nCR 0 (XP 10, PB +2).\nSenses Passive Perception 11\nLanguages None\n### Traits\n- Pack Tactics. The baboon has Advantage on an attack roll against a creature if at least one of the baboon's allies is within 5 feet of the creature and the ally doesn't have the Incapacitated condition.\n### Actions\n- Bite. Melee Attack Roll: +1, reach 5 ft. Hit: 1 (1d4 - 1) Piercing damage.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Baboon","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Badger","constant":false,"content":"## Badger (monster stat block, SRD 5.2.1)\nTiny Beast, Unaligned. AC 11, HP 5 (1d4+3), Initiative +0, Speed 20 ft., Burrow 5 ft..\nAbilities: Str 10 (save +0), Dex 11 (save +0), Con 16 (save +3), Int 2 (save -4), Wis 12 (save +1), Cha 5 (save -3).\nCR 0 (XP 10, PB +2).\nSkills Perception +3\nResistances Poison\nSenses Darkvision 30 ft.; Passive Perception 13\nLanguages None\n### Actions\n- Bite. Melee Attack Roll: +2, reach 5 ft. Hit: 1 Piercing damage.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Badger","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Bat","constant":false,"content":"## Bat (monster stat block, SRD 5.2.1)\nTiny Beast, Unaligned. AC 12, HP 1 (1d4-1), Initiative +2, Speed 5 ft., Fly 30 ft..\nAbilities: Str 2 (save -4), Dex 15 (save +2), Con 8 (save -1), Int 2 (save -4), Wis 12 (save +1), Cha 4 (save -3).\nCR 0 (XP 10, PB +2).\nSenses Blindsight 60 ft.; Passive Perception 11\nLanguages None\n### Actions\n- Bite. Melee Attack Roll: +4, reach 5 ft. Hit: 1 Piercing damage.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Bat","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Black Bear","constant":false,"content":"## Black Bear (monster stat block, SRD 5.2.1)\nMedium Beast, Unaligned. AC 11, HP 19 (3d8+6), Initiative +1, Speed 30 ft., Climb 30 ft., Swim 30 ft..\nAbilities: Str 15 (save +2), Dex 12 (save +1), Con 14 (save +2), Int 2 (save -4), Wis 12 (save +1), Cha 7 (save -2).\nCR 1/2 (XP 100, PB +2).\nSkills Perception +5\nSenses Darkvision 60 ft.; Passive Perception 15\nLanguages None\n### Actions\n- Multiattack. The bear makes two Rend attacks.\n- Rend. Melee Attack Roll: +4, reach 5 ft. Hit: 5 (1d6 + 2) Slashing damage.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Black Bear","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Blood Hawk","constant":false,"content":"## Blood Hawk (monster stat block, SRD 5.2.1)\nSmall Beast, Unaligned. AC 12, HP 7 (2d6), Initiative +2, Speed 10 ft., Fly 60 ft..\nAbilities: Str 6 (save -2), Dex 14 (save +2), Con 10 (save +0), Int 3 (save -4), Wis 14 (save +2), Cha 5 (save -3).\nCR 1/8 (XP 25, PB +2).\nSkills Perception +6\nSenses Passive Perception 16\nLanguages None\n### Traits\n- Pack Tactics. The hawk has Advantage on an attack roll against a creature if at least one of the hawk's allies is within 5 feet of the creature and the ally doesn't have the Incapacitated condition.\n### Actions\n- Beak. Melee Attack Roll: +4, reach 5 ft. Hit: 4 (1d4 + 2) Piercing damage, or 6 (1d8 + 2) Piercing damage if the target is Bloodied.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Blood Hawk","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Boar","constant":false,"content":"## Boar (monster stat block, SRD 5.2.1)\nMedium Beast, Unaligned. AC 11, HP 13 (2d8+4), Initiative +0, Speed 40 ft..\nAbilities: Str 13 (save +1), Dex 11 (save +0), Con 14 (save +2), Int 2 (save -4), Wis 9 (save -1), Cha 5 (save -3).\nCR 1/4 (XP 50, PB +2).\nSenses Passive Perception 9\nLanguages None\n### Traits\n- Bloodied Fury. While Bloodied, the boar has Advantage on attack rolls.\n### Actions\n- Gore. Melee Attack Roll: +3, reach 5 ft. Hit: 4 (1d6 + 1) Piercing damage. If the target is a Medium or smaller creature and the boar moved 20+ feet straight toward it immediately before the hit, the target takes an extra 3 (1d6) Piercing damage and has the Prone condition.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Boar","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Brown Bear","constant":false,"content":"## Brown Bear (monster stat block, SRD 5.2.1)\nLarge Beast, Unaligned. AC 11, HP 22 (3d10+6), Initiative +1, Speed 40 ft., Climb 30 ft..\nAbilities: Str 17 (save +3), Dex 12 (save +1), Con 15 (save +2), Int 2 (save -4), Wis 13 (save +1), Cha 7 (save -2).\nCR 1 (XP 200, PB +2).\nSkills Perception +3\nSenses Darkvision 60 ft.; Passive Perception 13\nLanguages None\n### Actions\n- Multiattack. The bear makes one Bite attack and one Claw attack.\n- Bite. Melee Attack Roll: +5, reach 5 ft. Hit: 7 (1d8 + 3) Piercing damage.\n- Claw. Melee Attack Roll: +5, reach 5 ft. Hit: 5 (1d4 + 3) Slashing damage. If the target is a Large or smaller creature, it has the Prone condition.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Brown Bear","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Camel","constant":false,"content":"## Camel (monster stat block, SRD 5.2.1)\nLarge Beast, Unaligned. AC 10, HP 17 (2d10+6), Initiative -1, Speed 50 ft..\nAbilities: Str 15 (save +2), Dex 8 (save -1), Con 17 (save +5), Int 2 (save -4), Wis 11 (save +0), Cha 5 (save -3).\nCR 1/8 (XP 25, PB +2).\nSenses Darkvision 60 ft.; Passive Perception 10\nLanguages None\n### Actions\n- Bite. Melee Attack Roll: +4, reach 5 ft. Hit: 4 (1d4 + 2) Bludgeoning damage.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Camel","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Cat","constant":false,"content":"## Cat (monster stat block, SRD 5.2.1)\nTiny Beast, Unaligned. AC 12, HP 2 (1d4), Initiative +2, Speed 40 ft., Climb 40 ft..\nAbilities: Str 3 (save -4), Dex 15 (save +4), Con 10 (save +0), Int 3 (save -4), Wis 12 (save +1), Cha 7 (save -2).\nCR 0 (XP 10, PB +2).\nSkills Perception +3, Stealth +4\nSenses Darkvision 60 ft.; Passive Perception 13\nLanguages None\n### Traits\n- Jumper. The cat's jump distance is determined using its Dexterity rather than its Strength.\n### Actions\n- Scratch. Melee Attack Roll: +4, reach 5 ft. Hit: 1 Slashing damage.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Cat","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Constrictor Snake","constant":false,"content":"## Constrictor Snake (monster stat block, SRD 5.2.1)\nLarge Beast, Unaligned. AC 13, HP 13 (2d10+2), Initiative +2, Speed 30 ft., Swim 30 ft..\nAbilities: Str 15 (save +2), Dex 14 (save +2), Con 12 (save +1), Int 1 (save -5), Wis 10 (save +0), Cha 3 (save -4).\nCR 1/4 (XP 50, PB +2).\nSkills Perception +2, Stealth +4\nSenses Blindsight 10 ft.; Passive Perception 12\nLanguages None\n### Actions\n- Bite. Melee Attack Roll: +4, reach 5 ft. Hit: 6 (1d8 + 2) Piercing damage.\n- Constrict. Strength Saving Throw: DC 12, one Medium or smaller creature the snake can see within 5 feet. Failure: 7 (3d4) Bludgeoning damage, and the target has the Grappled condition (escape DC 12).","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Constrictor Snake","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Crab","constant":false,"content":"## Crab (monster stat block, SRD 5.2.1)\nTiny Beast, Unaligned. AC 11, HP 3 (1d4+1), Initiative +0, Speed 20 ft., Swim 20 ft..\nAbilities: Str 6 (save -2), Dex 11 (save +0), Con 12 (save +1), Int 1 (save -5), Wis 8 (save -1), Cha 2 (save -4).\nCR 0 (XP 10, PB +2).\nSkills Stealth +2\nSenses Blindsight 30 ft.; Passive Perception 9\nLanguages None\n### Traits\n- Amphibious. The crab can breathe air and water.\n### Actions\n- Claw. Melee Attack Roll: +2, reach 5 ft. Hit: 1 Bludgeoning damage.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Crab","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Crocodile","constant":false,"content":"## Crocodile (monster stat block, SRD 5.2.1)\nLarge Beast, Unaligned. AC 12, HP 13 (2d10+2), Initiative +0, Speed 20 ft., Swim 30 ft..\nAbilities: Str 15 (save +2), Dex 10 (save +0), Con 13 (save +3), Int 2 (save -4), Wis 10 (save +0), Cha 5 (save -3).\nCR 1/2 (XP 100, PB +2).\nSkills Stealth +2\nSenses Passive Perception 10\nLanguages None\n### Traits\n- Hold Breath. The crocodile can hold its breath for 1 hour.\n### Actions\n- Bite. Melee Attack Roll: +4, reach 5 ft. Hit: 6 (1d8 + 2) Piercing damage. If the target is a Medium or smaller creature, it has the Grappled condition (escape DC 12). While Grappled, the target has the Restrained condition.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Crocodile","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Deer","constant":false,"content":"## Deer (monster stat block, SRD 5.2.1)\nMedium Beast, Unaligned. AC 13, HP 4 (1d8), Initiative +3, Speed 50 ft..\nAbilities: Str 11 (save +0), Dex 16 (save +3), Con 11 (save +0), Int 2 (save -4), Wis 14 (save +2), Cha 5 (save -3).\nCR 0 (XP 10, PB +2).\nSkills Perception +4\nSenses Darkvision 60 ft.; Passive Perception 14\nLanguages None\n### Traits\n- Agile. The deer doesn't provoke an Opportunity Attack when it moves out of an enemy's reach.\n### Actions\n- Ram. Melee Attack Roll: +2, reach 5 ft. Hit: 2 (1d4) Bludgeoning damage.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Deer","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Dire Wolf","constant":false,"content":"## Dire Wolf (monster stat block, SRD 5.2.1)\nLarge Beast, Unaligned. AC 14, HP 22 (3d10+6), Initiative +2, Speed 50 ft..\nAbilities: Str 17 (save +3), Dex 15 (save +2), Con 15 (save +2), Int 3 (save -4), Wis 12 (save +1), Cha 7 (save -2).\nCR 1 (XP 200, PB +2).\nSkills Perception +5, Stealth +4\nSenses Darkvision 60 ft.; Passive Perception 15\nLanguages None\n### Traits\n- Pack Tactics. The wolf has Advantage on an attack roll against a creature if at least one of the wolf's allies is within 5 feet of the creature and the ally doesn't have the Incapacitated condition.\n### Actions\n- Bite. Melee Attack Roll: +5, reach 5 ft. Hit: 8 (1d10 + 3) Piercing damage. If the target is a Large or smaller creature, it has the Prone condition.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Dire Wolf","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Draft Horse","constant":false,"content":"## Draft Horse (monster stat block, SRD 5.2.1)\nLarge Beast, Unaligned. AC 10, HP 15 (2d10+4), Initiative +0, Speed 40 ft..\nAbilities: Str 18 (save +4), Dex 10 (save +0), Con 15 (save +2), Int 2 (save -4), Wis 11 (save +0), Cha 7 (save -2).\nCR 1/4 (XP 50, PB +2).\nSenses Passive Perception 10\nLanguages None\n### Actions\n- Hooves. Melee Attack Roll: +6, reach 5 ft. Hit: 6 (1d4 + 4) Bludgeoning damage.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Draft Horse","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Eagle","constant":false,"content":"## Eagle (monster stat block, SRD 5.2.1)\nSmall Beast, Unaligned. AC 12, HP 4 (1d6+1), Initiative +2, Speed 10 ft., Fly 60 ft..\nAbilities: Str 6 (save -2), Dex 15 (save +2), Con 12 (save +1), Int 2 (save -4), Wis 14 (save +2), Cha 7 (save -2).\nCR 0 (XP 10, PB +2).\nSkills Perception +6\nSenses Passive Perception 16\nLanguages None\n### Actions\n- Talons. Melee Attack Roll: +4, reach 5 feet. Hit: 4 (1d4 + 2) Slashing damage.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Eagle","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Elephant","constant":false,"content":"## Elephant (monster stat block, SRD 5.2.1)\nHuge Beast, Unaligned. AC 12, HP 76 (8d12+24), Initiative -1, Speed 40 ft..\nAbilities: Str 22 (save +6), Dex 9 (save -1), Con 17 (save +3), Int 3 (save -4), Wis 11 (save +0), Cha 6 (save -2).\nCR 4 (XP 1100, PB +2).\nSenses Passive Perception 10\nLanguages None\n### Actions\n- Multiattack. The elephant makes two Gore attacks.\n- Gore. Melee Attack Roll: +8, reach 5 ft. Hit: 15 (2d8 + 6) Piercing damage. If the target is a Huge or smaller creature and the elephant moved 20+ feet straight toward it immediately before the hit, the target has the Prone condition.\n### Bonus Actions\n- Trample. Dexterity Saving Throw: DC 16, one creature within 5 feet that has the Prone condition. Failure: 17 (2d10 + 6) Bludgeoning damage. Success: Half damage.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Elephant","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Elk","constant":false,"content":"## Elk (monster stat block, SRD 5.2.1)\nLarge Beast, Unaligned. AC 10, HP 11 (2d10), Initiative +0, Speed 50 ft..\nAbilities: Str 16 (save +3), Dex 10 (save +0), Con 11 (save +0), Int 2 (save -4), Wis 10 (save +0), Cha 6 (save -2).\nCR 1/4 (XP 50, PB +2).\nSkills Perception +2\nSenses Darkvision 60 ft.; Passive Perception 12\nLanguages None\n### Actions\n- Ram. Melee Attack Roll: +5, reach 5 ft. Hit: 6 (1d6 + 3) Bludgeoning damage. If the target is a Large or smaller creature and the elk moved 20+ feet straight toward it immediately before the hit, the target takes an extra 3 (1d6) Bludgeoning damage and has the Prone condition.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Elk","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Flying Snake","constant":false,"content":"## Flying Snake (monster stat block, SRD 5.2.1)\nTiny Monstrosity, Unaligned. AC 14, HP 5 (2d4), Initiative +2, Speed 30 ft., Fly 60 ft., Swim 30 ft..\nAbilities: Str 4 (save -3), Dex 15 (save +2), Con 11 (save +0), Int 2 (save -4), Wis 12 (save +1), Cha 5 (save -3).\nCR 1/8 (XP 25, PB +2).\nSenses Blindsight 10 ft.; Passive Perception 11\nLanguages None\n### Traits\n- Flyby. The snake doesn't provoke an Opportunity Attack when it flies out of an enemy's reach.\n### Actions\n- Bite. Melee Attack Roll: +4, reach 5 ft. Hit: 1 Piercing damage plus 5 (2d4) Poison damage.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Flying Snake","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Frog","constant":false,"content":"## Frog (monster stat block, SRD 5.2.1)\nTiny Beast, Unaligned. AC 11, HP 1 (1d4-1), Initiative +1, Speed 20 ft., Swim 20 ft..\nAbilities: Str 1 (save -5), Dex 13 (save +1), Con 8 (save -1), Int 1 (save -5), Wis 8 (save -1), Cha 3 (save -4).\nCR 0 (XP 10, PB +2).\nSkills Perception +1, Stealth +3\nSenses Darkvision 30 ft.; Passive Perception 11\nLanguages None\n### Traits\n- Amphibious. The frog can breathe air and water.\n- Standing Leap. The frog's Long Jump is up to 10 feet and its High Jump is up to 5 feet with or without a running start.\n### Actions\n- Bite. Melee Attack Roll: +3, reach 5 ft. Hit: 1 Piercing damage.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Frog","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Giant Ape","constant":false,"content":"## Giant Ape (monster stat block, SRD 5.2.1)\nHuge Beast, Unaligned. AC 12, HP 168 (16d12+64), Initiative +5, Speed 40 ft., Climb 40 ft..\nAbilities: Str 23 (save +6), Dex 14 (save +2), Con 18 (save +4), Int 5 (save -3), Wis 12 (save +1), Cha 7 (save -2).\nCR 7 (XP 2900, PB +3).\nSkills Athletics +9, Perception +4, Survival +4\nSenses Passive Perception 14\nLanguages None\n### Actions\n- Multiattack. The ape makes two Fist attacks.\n- Fist. Melee Attack Roll: +9, reach 10 ft. Hit: 22 (3d10 + 6) Bludgeoning damage.\n- Boulder Toss (Recharge 6). The ape hurls a boulder at a point it can see within 90 feet. Dexterity Saving Throw: DC 17, each creature in a 5-foot-radius Sphere centered on that point. Failure: 24 (7d6) Bludgeoning damage. If the target is a Large or smaller creature, it has the Prone condition. Success: Half damage only.\n### Bonus Actions\n- Leap. The ape jumps up to 30 feet by spending 10 feet of movement.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Giant Ape","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Giant Badger","constant":false,"content":"## Giant Badger (monster stat block, SRD 5.2.1)\nMedium Beast, Unaligned. AC 13, HP 15 (2d8+6), Initiative +0, Speed 30 ft., Burrow 10 ft..\nAbilities: Str 13 (save +1), Dex 10 (save +0), Con 17 (save +3), Int 2 (save -4), Wis 12 (save +1), Cha 5 (save -3).\nCR 1/4 (XP 50, PB +2).\nSkills Perception +3\nResistances Poison\nSenses Darkvision 60 ft.; Passive Perception 13\nLanguages None\n### Actions\n- Bite. Melee Attack Roll: +3, reach 5 ft. Hit: 6 (2d4 + 1) Piercing damage.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Giant Badger","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Giant Bat","constant":false,"content":"## Giant Bat (monster stat block, SRD 5.2.1)\nLarge Beast, Unaligned. AC 13, HP 22 (4d10), Initiative +3, Speed 10 ft., Fly 60 ft..\nAbilities: Str 15 (save +2), Dex 16 (save +3), Con 11 (save +0), Int 2 (save -4), Wis 12 (save +1), Cha 6 (save -2).\nCR 1/4 (XP 50, PB +2).\nSenses Blindsight 120 ft.; Passive Perception 11\nLanguages None\n### Actions\n- Bite. Melee Attack Roll: +5, reach 5 ft. Hit: 6 (1d6 + 3) Piercing damage.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Giant Bat","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Giant Boar","constant":false,"content":"## Giant Boar (monster stat block, SRD 5.2.1)\nLarge Beast, Unaligned. AC 13, HP 42 (5d10+15), Initiative +0, Speed 40 ft..\nAbilities: Str 17 (save +5), Dex 10 (save +0), Con 16 (save +3), Int 2 (save -4), Wis 7 (save -2), Cha 5 (save -3).\nCR 2 (XP 450, PB +2).\nSenses Passive Perception 8\nLanguages None\n### Traits\n- Bloodied Fury. The boar has Advantage on melee attack rolls while it is Bloodied.\n### Actions\n- Gore. Melee Attack Roll: +5, reach 5 ft. Hit: 10 (2d6 + 3) Piercing damage. If the target is a Large or smaller creature and the boar moved 20+ feet straight toward it immediately before the hit, the target takes an extra 7 (2d6) Piercing damage and has the Prone condition.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Giant Boar","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Giant Centipede","constant":false,"content":"## Giant Centipede (monster stat block, SRD 5.2.1)\nSmall Beast, Unaligned. AC 14, HP 9 (2d6+2), Initiative +2, Speed 30 ft., Climb 30 ft..\nAbilities: Str 5 (save -3), Dex 14 (save +2), Con 12 (save +1), Int 1 (save -5), Wis 7 (save -2), Cha 3 (save -4).\nCR 1/4 (XP 50, PB +2).\nSenses Blindsight 30 ft.; Passive Perception 8\nLanguages None\n### Actions\n- Bite. Melee Attack Roll: +4, reach 5 ft. Hit: 4 (1d4 + 2) Piercing damage, and the target has the Poisoned condition until the start of the centipede's next turn.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Giant Centipede","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Giant Constrictor Snake","constant":false,"content":"## Giant Constrictor Snake (monster stat block, SRD 5.2.1)\nHuge Beast, Unaligned. AC 12, HP 60 (8d12+8), Initiative +2, Speed 30 ft., Swim 30 ft..\nAbilities: Str 19 (save +4), Dex 14 (save +2), Con 12 (save +1), Int 1 (save -5), Wis 10 (save +0), Cha 3 (save -4).\nCR 2 (XP 450, PB +2).\nSkills Perception +2\nSenses Blindsight 10 ft.; Passive Perception 12\nLanguages None\n### Actions\n- Multiattack. The snake makes one Bite attack and uses Constrict.\n- Bite. Melee Attack Roll: +6, reach 10 ft. Hit: 11 (2d6 + 4) Piercing damage.\n- Constrict. Strength Saving Throw: DC 14, one Large or smaller creature the snake can see within 10 feet. Failure: 13 (2d8 + 4) Bludgeoning damage, and the target has the Grappled condition (escape DC 14).","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Giant Constrictor Snake","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Giant Crab","constant":false,"content":"## Giant Crab (monster stat block, SRD 5.2.1)\nMedium Beast, Unaligned. AC 15, HP 13 (3d8), Initiative +1, Speed 30 ft., Swim 30 ft..\nAbilities: Str 13 (save +1), Dex 13 (save +1), Con 11 (save +0), Int 1 (save -5), Wis 9 (save -1), Cha 3 (save -4).\nCR 1/8 (XP 25, PB +2).\nSkills Stealth +3\nSenses Blindsight 30 ft.; Passive Perception 9\nLanguages None\n### Traits\n- Amphibious. The crab can breathe air and water.\n### Actions\n- Claw. Melee Attack Roll: +3, reach 5 ft. Hit: 4 (1d6 + 1) Bludgeoning damage. If the target is a Medium or smaller creature, it has the Grappled condition (escape DC 11) from one of two claws.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Giant Crab","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Giant Crocodile","constant":false,"content":"## Giant Crocodile (monster stat block, SRD 5.2.1)\nHuge Beast, Unaligned. AC 14, HP 85 (9d12+27), Initiative -1, Speed 30 ft., Swim 50 ft..\nAbilities: Str 21 (save +5), Dex 9 (save -1), Con 17 (save +3), Int 2 (save -4), Wis 10 (save +0), Cha 7 (save -2).\nCR 5 (XP 1800, PB +3).\nSkills Stealth +5\nSenses Passive Perception 10\nLanguages None\n### Traits\n- Hold Breath. The crocodile can hold its breath for 1 hour.\n### Actions\n- Multiattack. The crocodile makes one Bite attack and one Tail attack.\n- Bite. Melee Attack Roll: +8, reach 5 ft. Hit: 21 (3d10 + 5) Piercing damage. If the target is a Large or smaller creature, it has the Grappled condition (escape DC 15). While Grappled, the target has the Restrained condition and can't be targeted by the crocodile's Tail.\n- Tail. Melee Attack Roll: +8, reach 10 ft. Hit: 18 (3d8 + 5) Bludgeoning damage. If the target is a Large or smaller creature, it has the Prone condition.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Giant Crocodile","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Giant Eagle","constant":false,"content":"## Giant Eagle (monster stat block, SRD 5.2.1)\nLarge Celestial, Neutral Good. AC 13, HP 26 (4d10+4), Initiative +3, Speed 10 ft., Fly 80 ft..\nAbilities: Str 16 (save +3), Dex 17 (save +3), Con 13 (save +1), Int 8 (save -1), Wis 14 (save +2), Cha 10 (save +0).\nCR 1 (XP 200, PB +2).\nSkills Perception +6\nResistances Necrotic, Radiant\nSenses Passive Perception 16\nLanguages Celestial; understands Common and Primordial (Auran) but can't speak them\n### Actions\n- Multiattack. The eagle makes two Rend attacks.\n- Rend. Melee Attack Roll: +5, reach 5 ft. Hit: 5 (1d4 + 3) Slashing damage plus 3 (1d6) Radiant damage.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Giant Eagle","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Giant Elk","constant":false,"content":"## Giant Elk (monster stat block, SRD 5.2.1)\nHuge Celestial, Neutral Good. AC 14, HP 42 (5d12+10), Initiative +6, Speed 60 ft..\nAbilities: Str 19 (save +6), Dex 18 (save +6), Con 14 (save +2), Int 7 (save -2), Wis 14 (save +2), Cha 10 (save +0).\nCR 2 (XP 450, PB +2).\nSkills Perception +4\nResistances Necrotic, Radiant\nSenses Darkvision 90 ft.; Passive Perception 14\nLanguages Celestial; understands Common, Elvish, and Sylvan but can't speak them\n### Actions\n- Ram. Melee Attack Roll: +6, reach 10 ft. Hit: 11 (2d6 + 4) Bludgeoning damage plus 5 (2d4) Radiant damage. If the target is a Huge or smaller creature and the elk moved 20+ feet straight toward it immediately before the hit, the target takes an extra 5 (2d4) Bludgeoning damage and has the Prone condition.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Giant Elk","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Giant Fire Beetle","constant":false,"content":"## Giant Fire Beetle (monster stat block, SRD 5.2.1)\nSmall Beast, Unaligned. AC 13, HP 4 (1d6+1), Initiative +0, Speed 30 ft., Climb 30 ft..\nAbilities: Str 8 (save -1), Dex 10 (save +0), Con 12 (save +1), Int 1 (save -5), Wis 7 (save -2), Cha 3 (save -4).\nCR 0 (XP 10, PB +2).\nResistances Fire\nSenses Blindsight 30 ft.; Passive Perception 8\nLanguages None\n### Traits\n- Illumination. The beetle sheds Bright Light in a 10-foot radius and Dim Light for an additional 10 feet.\n### Actions\n- Bite. Melee Attack Roll: +1, reach 5 ft. Hit: 1 Fire damage.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Giant Fire Beetle","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Giant Frog","constant":false,"content":"## Giant Frog (monster stat block, SRD 5.2.1)\nMedium Beast, Unaligned. AC 11, HP 18 (4d8), Initiative +1, Speed 30 ft., Swim 30 ft..\nAbilities: Str 12 (save +1), Dex 13 (save +1), Con 11 (save +0), Int 2 (save -4), Wis 10 (save +0), Cha 3 (save -4).\nCR 1/4 (XP 50, PB +2).\nSkills Perception +2, Stealth +4\nSenses Darkvision 30 ft.; Passive Perception 12\nLanguages None\n### Traits\n- Amphibious. The frog can breathe air and water.\n- Standing Leap. The frog's Long Jump is up to 20 feet and its High Jump is up to 10 feet with or without a running start.\n### Actions\n- Bite. Melee Attack Roll: +3, reach 5 ft. Hit: 5 (1d6 + 2) Piercing damage. If the target is a Medium or smaller creature, it has the Grappled condition (escape DC 11).\n- Swallow. The frog swallows a Small or smaller target it is grappling. While swallowed, the target isn't Grappled but has the Blinded and Restrained conditions, and it has Total Cover against attacks and other effects outside the frog. While swallowing the target, the frog can't use Bite, and if the frog dies, the swallowed target is no longer Restrained and can escape from the corpse using 5 feet of movement, exiting with the Prone condition. At the end of the frog's next turn, the swallowed target takes 5 (2d4) Acid damage. If that damage doesn't kill it, the frog disgorges it, causing it to exit Prone.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Giant Frog","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Giant Goat","constant":false,"content":"## Giant Goat (monster stat block, SRD 5.2.1)\nLarge Beast, Unaligned. AC 11, HP 19 (3d10+3), Initiative +1, Speed 40 ft., Climb 30 ft..\nAbilities: Str 17 (save +5), Dex 13 (save +1), Con 12 (save +1), Int 3 (save -4), Wis 12 (save +1), Cha 6 (save -2).\nCR 1/2 (XP 100, PB +2).\nSkills Perception +3\nSenses Darkvision 60 ft.; Passive Perception 13\nLanguages None\n### Actions\n- Ram. Melee Attack Roll: +5, reach 5 ft. Hit: 6 (1d6 + 3) Bludgeoning damage. If the target is a Large or smaller creature and the goat moved 20+ feet straight toward it immediately before the hit, the target takes an extra 5 (2d4) Bludgeoning damage and has the Prone condition.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Giant Goat","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Giant Hyena","constant":false,"content":"## Giant Hyena (monster stat block, SRD 5.2.1)\nLarge Beast, Unaligned. AC 12, HP 45 (6d10+12), Initiative +2, Speed 50 ft..\nAbilities: Str 16 (save +3), Dex 14 (save +2), Con 14 (save +2), Int 2 (save -4), Wis 12 (save +1), Cha 7 (save -2).\nCR 1 (XP 200, PB +2).\nSkills Perception +3\nSenses Darkvision 60 ft.; Passive Perception 13\nLanguages None\n### Actions\n- Bite. Melee Attack Roll: +5, reach 5 ft. Hit: 10 (2d6 + 3) Piercing damage.\n### Bonus Actions\n- Rampage (1/Day). Immediately after dealing damage to a creature that was already Bloodied, the hyena can move up to half its Speed, and it makes one Bite attack.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Giant Hyena","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Giant Lizard","constant":false,"content":"## Giant Lizard (monster stat block, SRD 5.2.1)\nLarge Beast, Unaligned. AC 12, HP 19 (3d10+3), Initiative +1, Speed 40 ft., Climb 40 ft..\nAbilities: Str 15 (save +2), Dex 12 (save +3), Con 13 (save +1), Int 2 (save -4), Wis 10 (save +0), Cha 5 (save -3).\nCR 1/4 (XP 50, PB +2).\nSenses Darkvision 60 ft.; Passive Perception 10\nLanguages None\n### Traits\n- Spider Climb. The lizard can climb difficult surfaces, including along ceilings, without needing to make an ability check.\n### Actions\n- Bite. Melee Attack Roll: +4, reach 5 ft. Hit: 6 (1d8 + 2) Piercing damage.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Giant Lizard","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Giant Octopus","constant":false,"content":"## Giant Octopus (monster stat block, SRD 5.2.1)\nLarge Beast, Unaligned. AC 11, HP 45 (7d10+7), Initiative +1, Speed 10 ft., Swim 60 ft..\nAbilities: Str 17 (save +3), Dex 13 (save +1), Con 13 (save +1), Int 5 (save -3), Wis 10 (save +0), Cha 4 (save -3).\nCR 1 (XP 200, PB +2).\nSkills Perception +4, Stealth +5\nSenses Darkvision 60 ft.; Passive Perception 14\nLanguages None\n### Traits\n- Water Breathing. The octopus can breathe only underwater. It can hold its breath for 1 hour outside water.\n### Actions\n- Tentacles. Melee Attack Roll: +5, reach 10 ft. Hit: 10 (2d6 + 3) Bludgeoning damage. If the target is a Medium or smaller creature, it has the Grappled condition (escape DC 13) from all eight tentacles. While Grappled, the target has the Restrained condition.\n### Reactions\n- Ink Cloud (1/Day). Trigger: The octopus takes damage while underwater. Response: The octopus releases ink that fills a 10-foot Cube centered on itself, and the octopus moves up to its Swim Speed. The Cube is Heavily Obscured for 1 minute or until a strong current or similar effect disperses the ink.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Giant Octopus","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Giant Owl","constant":false,"content":"## Giant Owl (monster stat block, SRD 5.2.1)\nLarge Celestial, Neutral. AC 12, HP 19 (3d10+3), Initiative +2, Speed 5 ft., Fly 60 ft..\nAbilities: Str 13 (save +1), Dex 15 (save +2), Con 12 (save +1), Int 10 (save +0), Wis 14 (save +4), Cha 10 (save +0).\nCR 1/4 (XP 50, PB +2).\nSkills Perception +6, Stealth +6\nResistances Necrotic, Radiant\nSenses Darkvision 120 ft.; Passive Perception 16\nLanguages Celestial; understands Common, Elvish, and Sylvan but can't speak them\n### Traits\n- Flyby. The owl doesn't provoke an Opportunity Attack when it flies out of an enemy's reach.\n### Actions\n- Talons. Melee Attack Roll: +4, reach 5 ft. Hit: 7 (1d10 + 2) Slashing damage.\n- Spellcasting. The owl casts one of the following spells, requiring no spell components and using Wisdom as the spellcasting ability: At Will: Detect Evil and Good, Detect Magic 1/Day: Clairvoyance","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Giant Owl","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Giant Rat","constant":false,"content":"## Giant Rat (monster stat block, SRD 5.2.1)\nSmall Beast, Unaligned. AC 13, HP 7 (2d6), Initiative +3, Speed 30 ft., Climb 30 ft..\nAbilities: Str 7 (save -2), Dex 16 (save +5), Con 11 (save +0), Int 2 (save -4), Wis 10 (save +0), Cha 4 (save -3).\nCR 1/8 (XP 25, PB +2).\nSkills Perception +2\nSenses Darkvision 60 ft.; Passive Perception 12\nLanguages None\n### Traits\n- Pack Tactics. The rat has Advantage on an attack roll against a creature if at least one of the rat's allies is within 5 feet of the creature and the ally doesn't have the Incapacitated condition.\n### Actions\n- Bite. Melee Attack Roll: +5, reach 5 feet. Hit: 5 (1d4 + 3) Piercing damage.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Giant Rat","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Giant Scorpion","constant":false,"content":"## Giant Scorpion (monster stat block, SRD 5.2.1)\nLarge Beast, Unaligned. AC 15, HP 52 (7d10+14), Initiative +1, Speed 40 ft..\nAbilities: Str 16 (save +3), Dex 13 (save +1), Con 15 (save +2), Int 1 (save -5), Wis 9 (save -1), Cha 3 (save -4).\nCR 3 (XP 700, PB +2).\nSenses Blindsight 60 ft.; Passive Perception 9\nLanguages None\n### Actions\n- Multiattack. The scorpion makes two Claw attacks and one Sting attack.\n- Claw. Melee Attack Roll: +5, reach 5 ft. Hit: 6 (1d6 + 3) Bludgeoning damage. If the target is a Large or smaller creature, it has the Grappled condition (escape DC 13) from one of two claws.\n- Sting. Melee Attack Roll: +5, reach 5 ft. Hit: 7 (1d8 + 3) Piercing damage plus 11 (2d10) Poison damage.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Giant Scorpion","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Giant Seahorse","constant":false,"content":"## Giant Seahorse (monster stat block, SRD 5.2.1)\nLarge Beast, Unaligned. AC 14, HP 16 (3d10), Initiative +1, Speed 5 ft., Swim 40 ft..\nAbilities: Str 15 (save +2), Dex 12 (save +1), Con 11 (save +0), Int 2 (save -4), Wis 12 (save +1), Cha 5 (save -3).\nCR 1/2 (XP 100, PB +2).\nSenses Passive Perception 11\nLanguages None\n### Traits\n- Water Breathing. The seahorse can breathe only underwater.\n### Actions\n- Ram. Melee Attack Roll: +4, reach 5 ft. Hit: 9 (2d6 + 2) Bludgeoning damage, or 11 (2d8 + 2) Bludgeoning damage if the seahorse moved 20+ feet straight toward the target immediately before the hit.\n### Bonus Actions\n- Bubble Dash. While underwater, the seahorse moves up to half its Swim Speed without provoking Opportunity Attacks.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Giant Seahorse","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Giant Shark","constant":false,"content":"## Giant Shark (monster stat block, SRD 5.2.1)\nHuge Beast, Unaligned. AC 13, HP 92 (8d12+40), Initiative +3, Speed 5 ft., Swim 60 ft..\nAbilities: Str 23 (save +6), Dex 11 (save +0), Con 21 (save +5), Int 1 (save -5), Wis 10 (save +0), Cha 5 (save -3).\nCR 5 (XP 1800, PB +3).\nSkills Perception +3\nSenses Blindsight 60 ft.; Passive Perception 13\nLanguages None\n### Traits\n- Water Breathing. The shark can breathe only underwater.\n### Actions\n- Multiattack. The shark makes two Bite attacks.\n- Bite. Melee Attack Roll: +9 (with Advantage if the target doesn't have all its Hit Points), reach 5 ft. Hit: 22 (3d10 + 6) Piercing damage.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Giant Shark","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Giant Spider","constant":false,"content":"## Giant Spider (monster stat block, SRD 5.2.1)\nLarge Beast, Unaligned. AC 14, HP 26 (4d10+4), Initiative +3, Speed 30 ft., Climb 30 ft..\nAbilities: Str 14 (save +2), Dex 16 (save +3), Con 12 (save +1), Int 2 (save -4), Wis 11 (save +0), Cha 4 (save -3).\nCR 1 (XP 200, PB +2).\nSkills Perception +4, Stealth +7\nSenses Darkvision 60 ft.; Passive Perception 14\nLanguages None\n### Traits\n- Spider Climb. The spider can climb difficult surfaces, including along ceilings, without needing to make an ability check.\n- Web Walker. The spider ignores movement restrictions caused by webs, and it knows the location of any other creature in contact with the same web.\n### Actions\n- Bite. Melee Attack Roll: +5, reach 5 ft. Hit: 7 (1d8 + 3) Piercing damage plus 7 (2d6) Poison damage.\n- Web (Recharge 5–6). Dexterity Saving Throw: DC 13, one creature the spider can see within 60 feet. Failure: The target has the Restrained condition until the web is destroyed (AC 10; HP 5; Vulnerability to Fire damage; Immunity to Poison and Psychic damage).","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Giant Spider","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Giant Toad","constant":false,"content":"## Giant Toad (monster stat block, SRD 5.2.1)\nLarge Beast, Unaligned. AC 11, HP 39 (6d10+6), Initiative +1, Speed 30 ft., Swim 30 ft..\nAbilities: Str 15 (save +2), Dex 13 (save +1), Con 13 (save +1), Int 2 (save -4), Wis 10 (save +0), Cha 3 (save -4).\nCR 1 (XP 200, PB +2).\nSenses Darkvision 60 ft.; Passive Perception 10\nLanguages None\n### Traits\n- Amphibious. The toad can breathe air and water.\n- Standing Leap. The toad's Long Jump is up to 20 feet and its High Jump is up to 10 feet with or without a running start.\n### Actions\n- Bite. Melee Attack Roll: +4, reach 5 ft. Hit: 5 (1d6 + 2) Piercing damage plus 5 (2d4) Poison damage. If the target is a Medium or smaller creature, it has the Grappled condition (escape DC 12).\n- Swallow. The toad swallows a Medium or smaller target it is grappling. While swallowed, the target isn't Grappled but has the Blinded and Restrained conditions, and it has Total Cover against attacks and other effects outside the toad. In addition, the target takes 10 (3d6) Acid damage at the end of each of the toad's turns. The toad can have only one target swallowed at a time, and it can't use Bite while it has a swallowed target. If the toad dies, a swallowed creature is no longer Restrained and can escape from the corpse using 5 feet of movement, exiting with the Prone condition.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Giant Toad","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Giant Venomous Snake","constant":false,"content":"## Giant Venomous Snake (monster stat block, SRD 5.2.1)\nMedium Beast, Unaligned. AC 14, HP 11 (2d8+2), Initiative +4, Speed 40 ft., Swim 40 ft..\nAbilities: Str 10 (save +0), Dex 18 (save +4), Con 13 (save +1), Int 2 (save -4), Wis 10 (save +0), Cha 3 (save -4).\nCR 1/4 (XP 50, PB +2).\nSkills Perception +2\nSenses Blindsight 10 ft.; Passive Perception 12\nLanguages None\n### Actions\n- Bite. Melee Attack Roll: +6, reach 10 ft. Hit: 6 (1d4 + 4) Piercing damage plus 4 (1d8) Poison damage.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Giant Venomous Snake","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Giant Vulture","constant":false,"content":"## Giant Vulture (monster stat block, SRD 5.2.1)\nLarge Monstrosity, Neutral Evil. AC 10, HP 25 (3d10+9), Initiative +0, Speed 10 ft., Fly 60 ft..\nAbilities: Str 15 (save +2), Dex 10 (save +0), Con 16 (save +3), Int 6 (save -2), Wis 12 (save +1), Cha 7 (save -2).\nCR 1 (XP 200, PB +2).\nSkills Perception +3\nResistances Necrotic\nSenses Darkvision 60 ft.; Passive Perception 13\nLanguages Understands Common but can't speak\n### Traits\n- Pack Tactics. The vulture has Advantage on an attack roll against a creature if at least one of the vulture's allies is within 5 feet of the creature and the ally doesn't have the Incapacitated condition.\n### Actions\n- Gouge. Melee Attack Roll: +4, reach 5 ft. Hit: 9 (2d6 + 2) Piercing damage, and the target has the Poisoned condition until the end of its next turn.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Giant Vulture","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Giant Wasp","constant":false,"content":"## Giant Wasp (monster stat block, SRD 5.2.1)\nMedium Beast, Unaligned. AC 13, HP 22 (5d8), Initiative +2, Speed 10 ft., Fly 50 ft..\nAbilities: Str 10 (save +0), Dex 14 (save +2), Con 10 (save +0), Int 1 (save -5), Wis 10 (save +0), Cha 3 (save -4).\nCR 1/2 (XP 100, PB +2).\nSenses Passive Perception 10\nLanguages None\n### Traits\n- Flyby. The wasp doesn't provoke an Opportunity Attack when it flies out of an enemy's reach.\n### Actions\n- Sting. Melee Attack Roll: +4, reach 5 ft. Hit: 5 (1d6 + 2) Piercing damage plus 5 (2d4) Poison damage.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Giant Wasp","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Giant Weasel","constant":false,"content":"## Giant Weasel (monster stat block, SRD 5.2.1)\nMedium Beast, Unaligned. AC 13, HP 9 (2d8), Initiative +3, Speed 40 ft., Climb 30 ft..\nAbilities: Str 11 (save +0), Dex 17 (save +3), Con 10 (save +0), Int 4 (save -3), Wis 12 (save +1), Cha 5 (save -3).\nCR 1/8 (XP 25, PB +2).\nSkills Acrobatics +5, Perception +3, Stealth +5\nSenses Darkvision 60 ft.; Passive Perception 13\nLanguages None\n### Actions\n- Bite. Melee Attack Roll: +5, reach 5 ft. Hit: 5 (1d4 + 3) Piercing damage.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Giant Weasel","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Giant Wolf Spider","constant":false,"content":"## Giant Wolf Spider (monster stat block, SRD 5.2.1)\nMedium Beast, Unaligned. AC 13, HP 11 (2d8+2), Initiative +3, Speed 40 ft., Climb 40 ft..\nAbilities: Str 12 (save +1), Dex 16 (save +3), Con 13 (save +1), Int 3 (save -4), Wis 12 (save +1), Cha 4 (save -3).\nCR 1/4 (XP 50, PB +2).\nSkills Perception +3, Stealth +7\nSenses Blindsight 10 ft., Darkvision 60 ft.; Passive Perception 13\nLanguages None\n### Traits\n- Spider Climb. The spider can climb difficult surfaces, including along ceilings, without needing to make an ability check.\n### Actions\n- Bite. Melee Attack Roll: +5, reach 5 ft. Hit: 5 (1d4 + 3) Piercing damage plus 5 (2d4) Poison damage.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Giant Wolf Spider","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Goat","constant":false,"content":"## Goat (monster stat block, SRD 5.2.1)\nMedium Beast, Unaligned. AC 10, HP 4 (1d8), Initiative +0, Speed 40 ft., Climb 30 ft..\nAbilities: Str 11 (save +2), Dex 10 (save +0), Con 11 (save +0), Int 2 (save -4), Wis 10 (save +0), Cha 5 (save -3).\nCR 0 (XP 10, PB +2).\nSkills Perception +2\nSenses Darkvision 60 ft.; Passive Perception 12\nLanguages None\n### Actions\n- Ram. Melee Attack Roll: +2, reach 5 ft. Hit: 1 Bludgeoning damage, or 2 (1d4) Bludgeoning damage if the goat moved 20+ feet straight toward the target immediately before the hit.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Goat","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Hawk","constant":false,"content":"## Hawk (monster stat block, SRD 5.2.1)\nTiny Beast, Unaligned. AC 13, HP 1 (1d4-1), Initiative +3, Speed 10 ft., Fly 60 ft..\nAbilities: Str 5 (save -3), Dex 16 (save +3), Con 8 (save -1), Int 2 (save -4), Wis 14 (save +2), Cha 6 (save -2).\nCR 0 (XP 10, PB +2).\nSkills Perception +6\nSenses Passive Perception 16\nLanguages None\n### Actions\n- Talons. Melee Attack Roll: +5, reach 5 ft. Hit: 1 Slashing damage.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Hawk","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Hippopotamus","constant":false,"content":"## Hippopotamus (monster stat block, SRD 5.2.1)\nLarge Beast, Unaligned. AC 14, HP 82 (11d10+22), Initiative -2, Speed 30 ft., Swim 30 ft..\nAbilities: Str 21 (save +7), Dex 7 (save -2), Con 15 (save +2), Int 2 (save -4), Wis 12 (save +1), Cha 4 (save -3).\nCR 4 (XP 1100, PB +2).\nSkills Perception +3\nSenses Passive Perception 13\nLanguages None\n### Traits\n- Hold Breath. The hippopotamus can hold its breath for 10 minutes.\n### Actions\n- Multiattack. The hippopotamus makes two Bite attacks.\n- Bite. Melee Attack Roll: +7, reach 5 ft. Hit: 16 (2d10 + 5) Piercing damage.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Hippopotamus","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Hunter Shark","constant":false,"content":"## Hunter Shark (monster stat block, SRD 5.2.1)\nLarge Beast, Unaligned. AC 12, HP 45 (6d10+12), Initiative +2, Speed 5 ft., Swim 40 ft..\nAbilities: Str 18 (save +4), Dex 14 (save +2), Con 15 (save +2), Int 1 (save -5), Wis 10 (save +0), Cha 4 (save -3).\nCR 2 (XP 450, PB +2).\nSkills Perception +2\nSenses Blindsight 60 ft.; Passive Perception 12\nLanguages None\n### Traits\n- Water Breathing. The shark can breathe only underwater.\n### Actions\n- Bite. Melee Attack Roll: +6 (with Advantage if the target doesn't have all its Hit Points), reach 5 ft. Hit: 14 (3d6 + 4) Piercing damage.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Hunter Shark","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Hyena","constant":false,"content":"## Hyena (monster stat block, SRD 5.2.1)\nMedium Beast, Unaligned. AC 11, HP 5 (1d8+1), Initiative +1, Speed 50 ft..\nAbilities: Str 11 (save +0), Dex 13 (save +1), Con 12 (save +1), Int 2 (save -4), Wis 12 (save +1), Cha 5 (save -3).\nCR 0 (XP 10, PB +2).\nSkills Perception +3\nSenses Darkvision 60 ft.; Passive Perception 13\nLanguages None\n### Traits\n- Pack Tactics. The hyena has Advantage on an attack roll against a creature if at least one of the hyena's allies is within 5 feet of the creature and the ally doesn't have the Incapacitated condition.\n### Actions\n- Bite. Melee Attack Roll: +2, reach 5 ft. Hit: 3 (1d6) Piercing damage.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Hyena","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Jackal","constant":false,"content":"## Jackal (monster stat block, SRD 5.2.1)\nSmall Beast, Unaligned. AC 12, HP 3 (1d6), Initiative +2, Speed 40 ft..\nAbilities: Str 8 (save -1), Dex 15 (save +2), Con 11 (save +0), Int 3 (save -4), Wis 12 (save +1), Cha 6 (save -2).\nCR 0 (XP 10, PB +2).\nSkills Perception +5, Stealth +4\nSenses Darkvision 90 ft.; Passive Perception 15\nLanguages None\n### Actions\n- Bite. Melee Attack Roll: +1, reach 5 ft. Hit: 1 (1d4 – 1) Piercing damage.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Jackal","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Killer Whale","constant":false,"content":"## Killer Whale (monster stat block, SRD 5.2.1)\nHuge Beast, Unaligned. AC 12, HP 90 (12d12+12), Initiative +2, Speed 5 ft., Swim 60 ft..\nAbilities: Str 19 (save +4), Dex 14 (save +2), Con 13 (save +1), Int 3 (save -4), Wis 12 (save +1), Cha 7 (save -2).\nCR 3 (XP 700, PB +2).\nSkills Perception +3, Stealth +4\nSenses Blindsight 120 ft.; Passive Perception 13\nLanguages None\n### Traits\n- Hold Breath. The whale can hold its breath for 30 minutes.\n### Actions\n- Bite. Melee Attack Roll: +6, reach 5 ft. Hit: 21 (5d6 + 4) Piercing damage.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Killer Whale","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Lion","constant":false,"content":"## Lion (monster stat block, SRD 5.2.1)\nLarge Beast, Unaligned. AC 12, HP 22 (4d10), Initiative +2, Speed 50 ft..\nAbilities: Str 17 (save +3), Dex 15 (save +2), Con 11 (save +0), Int 3 (save -4), Wis 12 (save +1), Cha 8 (save -1).\nCR 1 (XP 200, PB +2).\nSkills Perception +3, Stealth +4\nSenses Darkvision 60 ft.; Passive Perception 13\nLanguages None\n### Traits\n- Pack Tactics. The lion has Advantage on an attack roll against a creature if at least one of the lion's allies is within 5 feet of the creature and the ally doesn't have the Incapacitated condition.\n- Running Leap. With a 10-foot running start, the lion can Long Jump up to 25 feet.\n### Actions\n- Multiattack. The lion makes two Rend attacks. It can replace one attack with a use of Roar.\n- Rend. Melee Attack Roll: +5, reach 5 ft. Hit: 7 (1d8 + 3) Slashing damage.\n- Roar. Wisdom Saving Throw: DC 11, one creature within 15 feet. Failure: The target has the Frightened condition until the start of the lion's next turn.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Lion","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Lizard","constant":false,"content":"## Lizard (monster stat block, SRD 5.2.1)\nTiny Beast, Unaligned. AC 10, HP 2 (1d4), Initiative +0, Speed 20 ft., Climb 20 ft..\nAbilities: Str 2 (save -4), Dex 11 (save +0), Con 10 (save +0), Int 1 (save -5), Wis 8 (save -1), Cha 3 (save -4).\nCR 0 (XP 10, PB +2).\nSenses Darkvision 30 ft.; Passive Perception 9\nLanguages None\n### Traits\n- Spider Climb. The lizard can climb difficult surfaces, including along ceilings, without needing to make an ability check.\n### Actions\n- Bite. Melee Attack Roll: +2, reach 5 ft. Hit: 1 Piercing damage.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Lizard","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Mammoth","constant":false,"content":"## Mammoth (monster stat block, SRD 5.2.1)\nHuge Beast, Unaligned. AC 13, HP 126 (11d12+55), Initiative +2, Speed 50 ft..\nAbilities: Str 24 (save +10), Dex 9 (save -1), Con 21 (save +8), Int 3 (save -4), Wis 11 (save +0), Cha 6 (save -2).\nCR 6 (XP 2300, PB +3).\nSenses Passive Perception 10\nLanguages None\n### Actions\n- Multiattack. The mammoth makes two Gore attacks.\n- Gore. Melee Attack Roll: +10, reach 10 ft. Hit: 18 (2d10 + 7) Piercing damage. If the target is a Huge or smaller creature and the mammoth moved 20+ feet straight toward it immediately before the hit, the target has the Prone condition.\n### Bonus Actions\n- Trample. Dexterity Saving Throw: DC 18, one creature within 5 feet that has the Prone condition. Failure: 29 (4d10 + 7) Bludgeoning damage. Success: Half damage.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Mammoth","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Mastiff","constant":false,"content":"## Mastiff (monster stat block, SRD 5.2.1)\nMedium Beast, Unaligned. AC 12, HP 5 (1d8+1), Initiative +2, Speed 40 ft..\nAbilities: Str 13 (save +1), Dex 14 (save +2), Con 12 (save +1), Int 3 (save -4), Wis 12 (save +3), Cha 7 (save -2).\nCR 1/8 (XP 25, PB +2).\nSkills Perception +5\nSenses Darkvision 60 ft.; Passive Perception 15\nLanguages None\n### Actions\n- Bite. Melee Attack Roll: +3, reach 5 ft. Hit: 4 (1d6 + 1) Piercing damage. If the target is a Medium or smaller creature, it has the Prone condition.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Mastiff","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Mule","constant":false,"content":"## Mule (monster stat block, SRD 5.2.1)\nMedium Beast, Unaligned. AC 10, HP 11 (2d8+2), Initiative +0, Speed 40 ft..\nAbilities: Str 14 (save +4), Dex 10 (save +0), Con 13 (save +1), Int 2 (save -4), Wis 10 (save +0), Cha 5 (save -3).\nCR 1/8 (XP 25, PB +2).\nSenses Passive Perception 10\nLanguages None\n### Traits\n- Beast of Burden. The mule counts as one size larger for the purpose of determining its carrying capacity.\n### Actions\n- Hooves. Melee Attack Roll: +4, reach 5 ft. Hit: 4 (1d4 + 2) Bludgeoning damage.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Mule","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Octopus","constant":false,"content":"## Octopus (monster stat block, SRD 5.2.1)\nSmall Beast, Unaligned. AC 12, HP 3 (1d6), Initiative +2, Speed 5 ft., Swim 30 ft..\nAbilities: Str 4 (save -3), Dex 15 (save +2), Con 11 (save +0), Int 3 (save -4), Wis 10 (save +0), Cha 4 (save -3).\nCR 0 (XP 10, PB +2).\nSkills Perception +2, Stealth +6\nSenses Darkvision 30 ft.; Passive Perception 12\nLanguages None\n### Traits\n- Compression. The octopus can move through a space as narrow as 1 inch without expending extra movement to do so.\n- Water Breathing. The octopus can breathe only underwater.\n### Actions\n- Tentacles. Melee Attack Roll: +4, reach 5 ft. Hit: 1 Bludgeoning damage.\n### Reactions\n- Ink Cloud (1/Day). Trigger: A creature ends its turn within 5 feet of the octopus while underwater. Response: The octopus releases ink that fills a 5-foot Cube centered on itself, and the octopus moves up to its Swim Speed. The Cube is Heavily Obscured for 1 minute or until a strong current or similar effect disperses the ink.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Octopus","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Owl","constant":false,"content":"## Owl (monster stat block, SRD 5.2.1)\nTiny Beast, Unaligned. AC 11, HP 1 (1d4-1), Initiative +1, Speed 5 ft., Fly 60 ft..\nAbilities: Str 3 (save -4), Dex 13 (save +1), Con 8 (save -1), Int 2 (save -4), Wis 12 (save +1), Cha 7 (save -2).\nCR 0 (XP 10, PB +2).\nSkills Perception +5, Stealth +5\nSenses Darkvision 120 ft.; Passive Perception 15\nLanguages None\n### Traits\n- Flyby. The owl doesn't provoke an Opportunity Attack when it flies out of an enemy's reach.\n### Actions\n- Talons. Melee Attack Roll: +3, reach 5 ft. Hit: 1 Slashing damage.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Owl","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Panther","constant":false,"content":"## Panther (monster stat block, SRD 5.2.1)\nMedium Beast, Unaligned. AC 13, HP 13 (3d8), Initiative +3, Speed 50 ft., Climb 40 ft..\nAbilities: Str 14 (save +2), Dex 16 (save +3), Con 10 (save +0), Int 3 (save -4), Wis 14 (save +2), Cha 7 (save -2).\nCR 1/4 (XP 50, PB +2).\nSkills Perception +4, Stealth +7\nSenses Darkvision 60 ft.; Passive Perception 14\nLanguages None\n### Actions\n- Rend. Melee Attack Roll: +5, reach 5 ft. Hit: 6 (1d6 + 3) Slashing damage.\n### Bonus Actions\n- Nimble Escape. The panther takes the Disengage or Hide action.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Panther","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Piranha","constant":false,"content":"## Piranha (monster stat block, SRD 5.2.1)\nTiny Beast, Unaligned. AC 13, HP 1 (1d4-1), Initiative +3, Speed 5 ft., Swim 40 ft..\nAbilities: Str 2 (save -4), Dex 16 (save +3), Con 9 (save -1), Int 1 (save -5), Wis 7 (save -2), Cha 2 (save -4).\nCR 0 (XP 10, PB +2).\nSenses Darkvision 60 ft.; Passive Perception 8\nLanguages None\n### Traits\n- Water Breathing. The piranha can breathe only underwater.\n### Actions\n- Bite. Melee Attack Roll: +5 (with Advantage if the target doesn't have all its Hit Points), reach 5 ft. Hit: 1 Piercing damage.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Piranha","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Plesiosaurus","constant":false,"content":"## Plesiosaurus (monster stat block, SRD 5.2.1)\nLarge Beast (Dinosaur), Unaligned. AC 13, HP 68 (8d10+24), Initiative +2, Speed 20 ft., Swim 40 ft..\nAbilities: Str 18 (save +4), Dex 15 (save +2), Con 16 (save +3), Int 2 (save -4), Wis 12 (save +1), Cha 5 (save -3).\nCR 2 (XP 450, PB +2).\nSkills Perception +3, Stealth +4\nSenses Passive Perception 13\nLanguages None\n### Traits\n- Hold Breath. The plesiosaurus can hold its breath for 1 hour.\n### Actions\n- Bite. Melee Attack Roll: +6, reach 10 ft. Hit: 11 (2d6 + 4) Piercing damage.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Plesiosaurus","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Polar Bear","constant":false,"content":"## Polar Bear (monster stat block, SRD 5.2.1)\nLarge Beast, Unaligned. AC 12, HP 42 (5d10+15), Initiative +2, Speed 40 ft., Swim 40 ft..\nAbilities: Str 20 (save +5), Dex 14 (save +2), Con 16 (save +3), Int 2 (save -4), Wis 13 (save +1), Cha 7 (save -2).\nCR 2 (XP 450, PB +2).\nSkills Perception +5, Stealth +4\nResistances Cold\nSenses Darkvision 60 ft.; Passive Perception 15\nLanguages None\n### Actions\n- Multiattack. The bear makes two Rend attacks.\n- Rend. Melee Attack Roll: +7, reach 5 ft. Hit: 9 (1d8 + 5) Slashing damage.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Polar Bear","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Pony","constant":false,"content":"## Pony (monster stat block, SRD 5.2.1)\nMedium Beast, Unaligned. AC 10, HP 11 (2d8+2), Initiative +0, Speed 40 ft..\nAbilities: Str 15 (save +4), Dex 10 (save +0), Con 13 (save +1), Int 2 (save -4), Wis 11 (save +0), Cha 7 (save -2).\nCR 1/8 (XP 25, PB +2).\nSenses Passive Perception 10\nLanguages None\n### Actions\n- Hooves. Melee Attack Roll: +4, reach 5 ft. Hit: 4 (1d4 + 2) Bludgeoning damage.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Pony","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Pteranodon","constant":false,"content":"## Pteranodon (monster stat block, SRD 5.2.1)\nMedium Beast (Dinosaur), Unaligned. AC 13, HP 13 (3d8), Initiative +2, Speed 10 ft., Fly 60 ft..\nAbilities: Str 12 (save +1), Dex 15 (save +2), Con 10 (save +0), Int 2 (save -4), Wis 9 (save -1), Cha 5 (save -3).\nCR 1/4 (XP 50, PB +2).\nSkills Perception +1\nSenses Passive Perception 11\nLanguages None\n### Traits\n- Flyby. The pteranodon doesn't provoke an Opportunity Attack when it flies out of an enemy's reach.\n### Actions\n- Bite. Melee Attack Roll: +4, reach 5 ft. Hit: 6 (1d8 + 2) Piercing damage.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Pteranodon","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Rat","constant":false,"content":"## Rat (monster stat block, SRD 5.2.1)\nTiny Beast, Unaligned. AC 10, HP 1 (1d4-1), Initiative +0, Speed 20 ft., Climb 20 ft..\nAbilities: Str 2 (save -4), Dex 11 (save +0), Con 9 (save -1), Int 2 (save -4), Wis 10 (save +0), Cha 4 (save -3).\nCR 0 (XP 10, PB +2).\nSkills Perception +2\nSenses Darkvision 30 ft.; Passive Perception 12\nLanguages None\n### Traits\n- Agile. The rat doesn't provoke an Opportunity Attack when it moves out of an enemy's reach.\n### Actions\n- Bite. Melee Attack Roll: +2, reach 5 ft. Hit: 1 Piercing damage.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Rat","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Raven","constant":false,"content":"## Raven (monster stat block, SRD 5.2.1)\nTiny Beast, Unaligned. AC 12, HP 2 (1d4), Initiative +2, Speed 10 ft., Fly 50 ft..\nAbilities: Str 2 (save -4), Dex 14 (save +2), Con 10 (save +0), Int 5 (save -3), Wis 13 (save +1), Cha 6 (save -2).\nCR 0 (XP 10, PB +2).\nSkills Perception +3\nSenses Passive Perception 13\nLanguages None\n### Traits\n- Mimicry. The raven can mimic simple sounds it has heard, such as a whisper or chitter. A hearer can discern the sounds are imitations with a successful DC 10 Wisdom (Insight) check.\n### Actions\n- Beak. Melee Attack Roll: +4, reach 5 ft. Hit: 1 Piercing damage.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Raven","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Reef Shark","constant":false,"content":"## Reef Shark (monster stat block, SRD 5.2.1)\nMedium Beast, Unaligned. AC 12, HP 22 (4d8+4), Initiative +2, Speed 5 ft., Swim 30 ft..\nAbilities: Str 14 (save +2), Dex 15 (save +2), Con 13 (save +1), Int 1 (save -5), Wis 10 (save +0), Cha 4 (save -3).\nCR 1/2 (XP 100, PB +2).\nSkills Perception +2\nSenses Blindsight 30 ft.; Passive Perception 12\nLanguages None\n### Traits\n- Pack Tactics. The shark has Advantage on an attack roll against a creature if at least one of the shark's allies is within 5 feet of the creature and the ally doesn't have the Incapacitated condition.\n- Water Breathing. The shark can breathe only underwater.\n### Actions\n- Bite. Melee Attack Roll: +4, reach 5 ft. Hit: 7 (2d4 + 2) Piercing damage.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Reef Shark","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Rhinoceros","constant":false,"content":"## Rhinoceros (monster stat block, SRD 5.2.1)\nLarge Beast, Unaligned. AC 13, HP 45 (6d10+12), Initiative -1, Speed 40 ft..\nAbilities: Str 21 (save +5), Dex 8 (save -1), Con 15 (save +2), Int 2 (save -4), Wis 12 (save +1), Cha 6 (save -2).\nCR 2 (XP 450, PB +2).\nSenses Passive Perception 11\nLanguages None\n### Actions\n- Gore. Melee Attack Roll: +7, reach 5 ft. Hit: 14 (2d8 + 5) Piercing damage. If target is a Large or smaller creature and the rhinoceros moved 20+ feet straight toward it immediately before the hit, the target takes an extra 9 (2d8) Piercing damage and has the Prone condition.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Rhinoceros","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Riding Horse","constant":false,"content":"## Riding Horse (monster stat block, SRD 5.2.1)\nLarge Beast, Unaligned. AC 11, HP 13 (2d10+2), Initiative +1, Speed 60 ft..\nAbilities: Str 16 (save +3), Dex 13 (save +1), Con 12 (save +1), Int 2 (save -4), Wis 11 (save +0), Cha 7 (save -2).\nCR 1/4 (XP 50, PB +2).\nSenses Passive Perception 10\nLanguages None\n### Actions\n- Hooves. Melee Attack Roll: +5, reach 5 ft. Hit: 7 (1d8 + 3) Bludgeoning damage.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Riding Horse","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Saber-Toothed Tiger","constant":false,"content":"## Saber-Toothed Tiger (monster stat block, SRD 5.2.1)\nLarge Beast, Unaligned. AC 13, HP 52 (7d10+14), Initiative +3, Speed 40 ft..\nAbilities: Str 18 (save +6), Dex 17 (save +5), Con 15 (save +2), Int 3 (save -4), Wis 12 (save +1), Cha 8 (save -1).\nCR 2 (XP 450, PB +2).\nSkills Perception +5, Stealth +7\nSenses Darkvision 60 ft.; Passive Perception 15\nLanguages None\n### Traits\n- Running Leap. With a 10-foot running start, the tiger can Long Jump up to 25 feet.\n### Actions\n- Multiattack. The tiger makes two Rend attacks.\n- Rend. Melee Attack Roll: +6, reach 5 ft. Hit: 11 (2d6 + 4) Slashing damage.\n### Bonus Actions\n- Nimble Escape. The tiger takes the Disengage or Hide action.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Saber-Toothed Tiger","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Scorpion","constant":false,"content":"## Scorpion (monster stat block, SRD 5.2.1)\nTiny Beast, Unaligned. AC 11, HP 1 (1d4-1), Initiative +0, Speed 10 ft..\nAbilities: Str 2 (save -4), Dex 11 (save +0), Con 8 (save -1), Int 1 (save -5), Wis 8 (save -1), Cha 2 (save -4).\nCR 0 (XP 10, PB +2).\nSenses Blindsight 10 ft.; Passive Perception 9\nLanguages None\n### Actions\n- Sting. Melee Attack Roll: +2, reach 5 ft. Hit: 1 Piercing damage plus 3 (1d6) Poison damage.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Scorpion","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Seahorse","constant":false,"content":"## Seahorse (monster stat block, SRD 5.2.1)\nTiny Beast, Unaligned. AC 12, HP 1 (1d4-1), Initiative +1, Speed 5 ft., Swim 20 ft..\nAbilities: Str 1 (save -5), Dex 12 (save +1), Con 8 (save -1), Int 1 (save -5), Wis 10 (save +0), Cha 2 (save -4).\nCR 0 (XP 0, PB +2).\nSkills Perception +2, Stealth +5\nSenses Passive Perception 12\nLanguages None\n### Traits\n- Water Breathing. The seahorse can breathe only underwater.\n### Actions\n- Bubble Dash. While underwater, the seahorse moves up to its Swim Speed without provoking Opportunity Attacks.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Seahorse","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Spider","constant":false,"content":"## Spider (monster stat block, SRD 5.2.1)\nTiny Beast, Unaligned. AC 12, HP 1 (1d4-1), Initiative +2, Speed 20 ft., Climb 20 ft..\nAbilities: Str 2 (save -4), Dex 14 (save +2), Con 8 (save -1), Int 1 (save -5), Wis 10 (save +0), Cha 2 (save -4).\nCR 0 (XP 10, PB +2).\nSkills Stealth +4\nSenses Darkvision 30 ft.; Passive Perception 10\nLanguages None\n### Traits\n- Spider Climb. The spider can climb difficult surfaces, including along ceilings, without needing to make an ability check.\n- Web Walker. The spider ignores movement restrictions caused by webs, and the spider knows the location of any other creature in contact with the same web.\n### Actions\n- Bite. Melee Attack Roll: +4, reach 5 ft. Hit: 1 Piercing damage plus 2 (1d4) Poison damage.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Spider","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Swarm of Bats","constant":false,"content":"## Swarm of Bats (monster stat block, SRD 5.2.1)\nLarge Swarm of Tiny Beasts, Unaligned. AC 12, HP 11 (2d10), Initiative +2, Speed 5 ft., Fly 30 ft..\nAbilities: Str 5 (save -3), Dex 15 (save +2), Con 10 (save +0), Int 2 (save -4), Wis 12 (save +1), Cha 4 (save -3).\nCR 1/4 (XP 50, PB +2).\nResistances Bludgeoning, Piercing, Slashing\nImmunities Charmed, Frightened, Grappled, Paralyzed, Petrified, Prone, Restrained, Stunned\nSenses Blindsight 60 ft.; Passive Perception 11\nLanguages None\n### Traits\n- Swarm. The swarm can occupy another creature's space and vice versa, and the swarm can move through any opening large enough for a Tiny bat. The swarm can't regain Hit Points or gain Temporary Hit Points.\n### Actions\n- Bites. Melee Attack Roll: +4, reach 5 ft. Hit: 5 (2d4) Piercing damage, or 2 (1d4) Piercing damage if the swarm is Bloodied.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Swarm of Bats","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Swarm of Insects","constant":false,"content":"## Swarm of Insects (monster stat block, SRD 5.2.1)\nMedium Swarm of Tiny Beasts, Unaligned. AC 11, HP 19 (3d8+6), Initiative +1, Speed 20 ft., Climb or Fly 20 ft. (GM's choice).\nAbilities: Str 3 (save -4), Dex 13 (save +1), Con 14 (save +2), Int 1 (save -5), Wis 7 (save -2), Cha 1 (save -5).\nCR 1/2 (XP 100, PB +2).\nResistances Bludgeoning, Piercing, Slashing\nImmunities Charmed, Frightened, Grappled, Paralyzed, Petrified, Prone, Restrained, Stunned\nSenses Blindsight 30 ft.; Passive Perception 8\nLanguages None\n### Traits\n- Spider Climb. If the swarm has a Climb Speed, the swarm can climb difficult surfaces, including along ceilings, without needing to make an ability check.\n- Swarm. The swarm can occupy another creature's space and vice versa, and the swarm can move through any opening large enough for a Tiny insect. The swarm can't regain Hit Points or gain Temporary Hit Points.\n### Actions\n- Bites. Melee Attack Roll: +3, reach 5 ft. Hit: 6 (2d4 + 1) Poison damage, or 3 (1d4 + 1) Poison damage if the swarm is Bloodied.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Swarm of Insects","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Swarm of Piranhas","constant":false,"content":"## Swarm of Piranhas (monster stat block, SRD 5.2.1)\nMedium Swarm of Tiny Beasts, Unaligned. AC 13, HP 28 (8d8-8), Initiative +3, Speed 5 ft., Swim 40 ft..\nAbilities: Str 13 (save +1), Dex 16 (save +3), Con 9 (save -1), Int 1 (save -5), Wis 7 (save -2), Cha 2 (save -4).\nCR 1 (XP 200, PB +2).\nResistances Bludgeoning, Piercing, Slashing\nImmunities Charmed, Frightened, Grappled, Paralyzed, Petrified, Prone, Restrained, Stunned\nSenses Darkvision 60 ft.; Passive Perception 8\nLanguages None\n### Traits\n- Swarm. The swarm can occupy another creature's space and vice versa, and the swarm can move through any opening large enough for a Tiny piranha. The swarm can't regain Hit Points or gain Temporary Hit Points.\n- Water Breathing. The swarm can breathe only underwater.\n### Actions\n- Bites. Melee Attack Roll: +5 (with Advantage if the target doesn't have all its Hit Points), reach 5 ft. Hit: 8 (2d4 + 3) Piercing damage, or 5 (1d4 + 3) Piercing damage if the swarm is Bloodied.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Swarm of Piranhas","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Swarm of Rats","constant":false,"content":"## Swarm of Rats (monster stat block, SRD 5.2.1)\nMedium Swarm of Tiny Beasts, Unaligned. AC 10, HP 14 (4d8-4), Initiative +0, Speed 30 ft., Climb 30 ft..\nAbilities: Str 9 (save -1), Dex 11 (save +2), Con 9 (save -1), Int 2 (save -4), Wis 10 (save +0), Cha 3 (save -4).\nCR 1/4 (XP 50, PB +2).\nResistances Bludgeoning, Piercing, Slashing\nImmunities Charmed, Frightened, Grappled, Paralyzed, Petrified, Prone, Restrained, Stunned\nSenses Darkvision 30 ft.; Passive Perception 10\nLanguages None\n### Traits\n- Swarm. The swarm can occupy another creature's space and vice versa, and the swarm can move through any opening large enough for a Tiny rat. The swarm can't regain Hit Points or gain Temporary Hit Points.\n### Actions\n- Bites. Melee Attack Roll: +2, reach 5 ft. Hit: 5 (2d4) Piercing damage, or 2 (1d4) Piercing damage if the swarm is Bloodied.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Swarm of Rats","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Swarm of Ravens","constant":false,"content":"## Swarm of Ravens (monster stat block, SRD 5.2.1)\nMedium Swarm of Tiny Beasts, Unaligned. AC 12, HP 11 (2d8+2), Initiative +2, Speed 10 ft., Fly 50 ft..\nAbilities: Str 6 (save -2), Dex 14 (save +2), Con 12 (save +1), Int 5 (save -3), Wis 12 (save +1), Cha 6 (save -2).\nCR 1/4 (XP 50, PB +2).\nSkills Perception +5\nResistances Bludgeoning, Piercing, Slashing\nImmunities Charmed, Frightened, Grappled, Paralyzed, Petrified, Prone, Restrained, Stunned\nSenses Passive Perception 15\nLanguages None\n### Traits\n- Swarm. The swarm can occupy another creature's space and vice versa, and the swarm can move through any opening large enough for a Tiny raven. The swarm can't regain Hit Points or gain Temporary Hit Points.\n### Actions\n- Beaks. Melee Attack Roll: +4, reach 5 ft. Hit: 5 (1d6 + 2) Piercing damage, or 2 (1d4) Piercing damage if the swarm is Bloodied.\n- Cacophony (Recharge 6). Wisdom Saving Throw: DC 10, one creature in the swarm's space. Failure: The target has the Deafened condition until the start of the swarm's next turn. While Deafened, the target also has Disadvantage on ability checks and attack rolls.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Swarm of Ravens","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Swarm of Venomous Snakes","constant":false,"content":"## Swarm of Venomous Snakes (monster stat block, SRD 5.2.1)\nMedium Swarm of Tiny Beasts, Unaligned. AC 14, HP 36 (8d8), Initiative +4, Speed 30 ft., Swim 30 ft..\nAbilities: Str 8 (save -1), Dex 18 (save +4), Con 11 (save +0), Int 1 (save -5), Wis 10 (save +0), Cha 3 (save -4).\nCR 2 (XP 450, PB +2).\nResistances Bludgeoning, Piercing, Slashing\nImmunities Charmed, Frightened, Grappled, Paralyzed, Petrified, Prone, Restrained, Stunned\nSenses Blindsight 10 ft.; Passive Perception 10\nLanguages None\n### Traits\n- Swarm. The swarm can occupy another creature's space and vice versa, and the swarm can move through any opening large enough for a Tiny snake. The swarm can't regain Hit Points or gain Temporary Hit Points.\n### Actions\n- Bites. Melee Attack Roll: +6, reach 5 ft. Hit: 8 (1d8 + 4) Piercing damage—or 6 (1d4 + 4) Piercing damage if the swarm is Bloodied—plus 10 (3d6) Poison damage.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Swarm of Venomous Snakes","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Tiger","constant":false,"content":"## Tiger (monster stat block, SRD 5.2.1)\nLarge Beast, Unaligned. AC 13, HP 30 (4d10+8), Initiative +3, Speed 40 ft..\nAbilities: Str 17 (save +3), Dex 16 (save +3), Con 14 (save +2), Int 3 (save -4), Wis 12 (save +1), Cha 8 (save -1).\nCR 1 (XP 200, PB +2).\nSkills Perception +3, Stealth +7\nSenses Darkvision 60 ft.; Passive Perception 13\nLanguages None\n### Actions\n- Rend. Melee Attack Roll: +5, reach 5 ft. Hit: 10 (2d6 + 3) Slashing damage. If the target is a Large or smaller creature, it has the Prone condition.\n### Bonus Actions\n- Nimble Escape. The tiger takes the Disengage or Hide action.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Tiger","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Triceratops","constant":false,"content":"## Triceratops (monster stat block, SRD 5.2.1)\nHuge Beast (Dinosaur), Unaligned. AC 14, HP 114 (12d12+36), Initiative -1, Speed 50 ft..\nAbilities: Str 22 (save +6), Dex 9 (save -1), Con 17 (save +3), Int 2 (save -4), Wis 11 (save +0), Cha 5 (save -3).\nCR 5 (XP 1800, PB +3).\nSenses Passive Perception 10\nLanguages None\n### Actions\n- Multiattack. The triceratops makes two Gore attacks.\n- Gore. Melee Attack Roll: +9, reach 5 ft. Hit: 19 (2d12 + 6) Piercing damage. If the target is Huge or smaller and the triceratops moved 20+ feet straight toward it immediately before the hit, the target takes an extra 9 (2d8) Piercing damage and has the Prone condition.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Triceratops","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Tyrannosaurus Rex","constant":false,"content":"## Tyrannosaurus Rex (monster stat block, SRD 5.2.1)\nHuge Beast (Dinosaur), Unaligned. AC 13, HP 136 (13d12+52), Initiative +3, Speed 50 ft..\nAbilities: Str 25 (save +10), Dex 10 (save +0), Con 19 (save +4), Int 2 (save -4), Wis 12 (save +4), Cha 9 (save -1).\nCR 8 (XP 3900, PB +3).\nSkills Perception +4\nSenses Passive Perception 14\nLanguages None\n### Actions\n- Multiattack. The tyrannosaurus makes one Bite attack and one Tail attack.\n- Bite. Melee Attack Roll: +10, reach 10 ft. Hit: 33 (4d12 + 7) Piercing damage. If the target is a Large or smaller creature, it has the Grappled condition (escape DC 17). While Grappled, the target has the Restrained condition and can't be targeted by the tyrannosaurus's Tail.\n- Tail. Melee Attack Roll: +10, reach 15 ft. Hit: 25 (4d8 + 7) Bludgeoning damage. If the target is a Huge or smaller creature, it has the Prone condition.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Tyrannosaurus Rex","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Venomous Snake","constant":false,"content":"## Venomous Snake (monster stat block, SRD 5.2.1)\nTiny Beast, Unaligned. AC 12, HP 5 (2d4), Initiative +2, Speed 30 ft., Swim 30 ft..\nAbilities: Str 2 (save -4), Dex 15 (save +2), Con 11 (save +0), Int 1 (save -5), Wis 10 (save +0), Cha 3 (save -4).\nCR 1/8 (XP 25, PB +2).\nSenses Blindsight 10 ft.; Passive Perception 10\nLanguages None\n### Actions\n- Bite. Melee Attack Roll: +4, reach 5 ft. Hit: 4 (1d4 + 2) Piercing damage plus 3 (1d6) Poison damage.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Venomous Snake","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Vulture","constant":false,"content":"## Vulture (monster stat block, SRD 5.2.1)\nMedium Beast, Unaligned. AC 10, HP 5 (1d8+1), Initiative +0, Speed 10 ft., Fly 50 ft..\nAbilities: Str 7 (save -2), Dex 10 (save +0), Con 13 (save +1), Int 2 (save -4), Wis 12 (save +1), Cha 4 (save -3).\nCR 0 (XP 10, PB +2).\nSkills Perception +3\nSenses Passive Perception 13\nLanguages None\n### Traits\n- Pack Tactics. The vulture has Advantage on an attack roll against a creature if at least one of the vulture's allies is within 5 feet of the creature and the ally doesn't have the Incapacitated condition.\n### Actions\n- Beak. Melee Attack Roll: +2, reach 5 ft. Hit: 2 (1d4) Piercing damage.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Vulture","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Warhorse","constant":false,"content":"## Warhorse (monster stat block, SRD 5.2.1)\nLarge Beast, Unaligned. AC 11, HP 19 (3d10+3), Initiative +1, Speed 60 ft..\nAbilities: Str 18 (save +4), Dex 12 (save +1), Con 13 (save +1), Int 2 (save -4), Wis 12 (save +3), Cha 7 (save -2).\nCR 1/2 (XP 100, PB +2).\nSenses Passive Perception 11\nLanguages None\n### Actions\n- Hooves. Melee Attack Roll: +6, reach 5 ft. Hit: 9 (2d4 + 4) Bludgeoning damage. If the target is a Large or smaller creature and the horse moved 20+ feet straight toward it immediately before the hit, the target takes an extra 5 (2d4) Bludgeoning damage and has the Prone condition.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Warhorse","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Weasel","constant":false,"content":"## Weasel (monster stat block, SRD 5.2.1)\nTiny Beast, Unaligned. AC 13, HP 1 (1d4-1), Initiative +3, Speed 30 ft., Climb 30 ft..\nAbilities: Str 3 (save -4), Dex 16 (save +3), Con 8 (save -1), Int 2 (save -4), Wis 12 (save +1), Cha 3 (save -4).\nCR 0 (XP 10, PB +2).\nSkills Acrobatics +5, Perception +3, Stealth +5\nSenses Darkvision 60 ft.; Passive Perception 13\nLanguages None\n### Actions\n- Bite. Melee Attack Roll: +5, reach 5 ft. Hit: 1 Piercing damage.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Weasel","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"몬스터: Wolf","constant":false,"content":"## Wolf (monster stat block, SRD 5.2.1)\nMedium Beast, Unaligned. AC 12, HP 11 (2d8+2), Initiative +2, Speed 40 ft..\nAbilities: Str 14 (save +2), Dex 15 (save +2), Con 12 (save +1), Int 3 (save -4), Wis 12 (save +1), Cha 6 (save -2).\nCR 1/4 (XP 50, PB +2).\nSkills Perception +5, Stealth +4\nSenses Darkvision 60 ft.; Passive Perception 15\nLanguages None\n### Traits\n- Pack Tactics. The wolf has Advantage on attack rolls against a creature if at least one of the wolf's allies is within 5 feet of the creature and the ally doesn't have the Incapacitated condition.\n### Actions\n- Bite. Melee Attack Roll: +4, reach 5 ft. Hit: 5 (1d6 + 2) Piercing damage. If the target is a Medium or smaller creature, it has the Prone condition.","enabled":true,"extensions":{},"folder":"folder:bac446a9-35e2-480d-a61f-6a2880801e37","insertion_order":60,"keys":[""],"mode":"normal","name":"몬스터: Wolf","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"규칙 · 주문","constant":false,"content":"","enabled":true,"extensions":{},"insertion_order":60,"keys":["folder:7e5a6046-fcf5-44da-a038-cfedad06204a"],"mode":"folder","name":"규칙 · 주문","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Acid Arrow","constant":false,"content":"## Acid Arrow (산성 화살) - Level 2 Evocation spell, SRD 5.2.1\nClasses: Wizard. Casting Time: Action. Range: 90 feet. Components: V, S, M (powdered rhubarb leaf). Duration: Instantaneous.\nA shimmering green arrow streaks toward a target within range and bursts in a spray of acid. Make a ranged spell attack against the target. On a hit, the target takes 4d4 Acid damage and 2d4 Acid damage at the end of its next turn. On a miss, the arrow splashes the target with acid for half as much of the initial damage only.\nUsing a Higher-Level Spell Slot. The damage (both initial and later) increases by 1d4 for each spell slot level above 2.","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Acid Arrow","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Acid Splash","constant":false,"content":"## Acid Splash (산성 거품) - Cantrip Evocation spell, SRD 5.2.1\nClasses: Sorcerer, Wizard. Casting Time: Action. Range: 60 feet. Components: V, S. Duration: Instantaneous.\nYou create an acidic bubble at a point within range, where it explodes in a 5-foot-radius Sphere. Each creature in that Sphere must succeed on a Dexterity saving throw or take 1d6 Acid damage.\nCantrip Upgrade. The damage increases by 1d6 when you reach levels 5 (2d6), 11 (3d6), and 17 (4d6).","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Acid Splash","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Aid","constant":false,"content":"## Aid (원호) - Level 2 Abjuration spell, SRD 5.2.1\nClasses: Bard, Cleric, Druid, Paladin, Ranger. Casting Time: Action. Range: 30 feet. Components: V, S, M (a strip of white cloth). Duration: 8 hours.\nChoose up to three creatures within range. Each target's Hit Point maximum and current Hit Points increase by 5 for the duration.\nUsing a Higher-Level Spell Slot. Each target's Hit Points increase by 5 for each spell slot level above 2.","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Aid","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Alarm","constant":false,"content":"## Alarm (경보) - Level 1 Abjuration spell, SRD 5.2.1\nClasses: Ranger, Wizard. Casting Time: 1 minute or Ritual. Range: 30 feet. Components: V, S, M (a bell and silver wire). Duration: 8 hours.\nYou set an alarm against intrusion. Choose a door, a window, or an area within range that is no larger than a 20-foot Cube. Until the spell ends, an alarm alerts you whenever a creature touches or enters the warded area. When you cast the spell, you can designate creatures that won't set off the alarm. You also choose whether the alarm is audible or mental:\nAudible Alarm. The alarm produces the sound of a handbell for 10 seconds within 60 feet of the warded area.\nMental Alarm. You are alerted by a mental ping if you are within 1 mile of the warded area. This ping awakens you if you're asleep.","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Alarm","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Alter Self","constant":false,"content":"## Alter Self (자기 변형) - Level 2 Transmutation spell, SRD 5.2.1\nClasses: Sorcerer, Wizard. Casting Time: Action. Range: Self. Components: V, S. Duration: Concentration, up to 1 hour.\nYou alter your physical form. Choose one of the following options. Its effects last for the duration, during which you can take a Magic action to replace the option you chose with a different one.\nAquatic Adaptation. You sprout gills and grow webs between your fingers. You can breathe underwater and gain a Swim Speed equal to your Speed.\nChange Appearance. You alter your appearance. You decide what you look like, including your height, weight, facial features, sound of your voice, hair length, coloration, and other distinguishing characteristics. You can make yourself appear as a member of another species, though none of your statistics change. You can't appear as a creature of a different size, and your basic shape stays the same; if you're bipedal, you can't use this spell to become quadrupedal, for instance. For the duration, you can take a Magic action to change your appearance in this way again.\nNatural Weapons. You grow claws (Slashing), fangs (Piercing), horns (Piercing), or hooves (Bludgeoning). When you use your Unarmed Strike to deal damage with that new growth, it deals 1d6 damage of the type in parentheses instead of dealing the normal damage for your Unarmed Strike, and you use your spellcasting ability modifier for the attack and damage rolls rather than using Strength.","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Alter Self","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Animal Friendship","constant":false,"content":"## Animal Friendship (동물 친화) - Level 1 Enchantment spell, SRD 5.2.1\nClasses: Bard, Druid, Ranger. Casting Time: Action. Range: 30 feet. Components: V, S, M (a morsel of food). Duration: 24 hours.\nTarget a Beast that you can see within range. The target must succeed on a Wisdom saving throw or have the Charmed condition for the duration. If you 108 or one of your allies deals damage to the target, the spells ends.\nUsing a Higher-Level Spell Slot. You can target one additional Beast for each spell slot level above 1.","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Animal Friendship","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Animal Messenger","constant":false,"content":"## Animal Messenger (동물 전령) - Level 2 Enchantment spell, SRD 5.2.1\nClasses: Bard, Druid, Ranger. Casting Time: Action or Ritual. Range: 30 feet. Components: V, S, M (a morsel of food). Duration: 24 hours.\nA Tiny Beast of your choice that you can see within range must succeed on a Charisma saving throw, or it attempts to deliver a message for you (if the target's Challenge Rating isn't 0, it automatically succeeds). You specify a location you have visited and a recipient who matches a general description, such as “a person dressed in the uniform of the town guard” or “a red-haired dwarf wearing a pointed hat.” You also communicate a message of up to twenty-five words. The Beast travels for the duration toward the specified location, covering about 25 miles per 24 hours or 50 miles if the Beast can fly.\nWhen the Beast arrives, it delivers your message to the creature that you described, mimicking your communication. If the Beast doesn't reach its destination before the spell ends, the message is lost, and the Beast returns to where you cast the spell.\nUsing a Higher-Level Spell Slot. The spell's duration increases by 48 hours for each spell slot level above 2.","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Animal Messenger","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Animal Shapes","constant":false,"content":"## Animal Shapes (동물 형상) - Level 8 Transmutation spell, SRD 5.2.1\nClasses: Druid. Casting Time: Action. Range: 30 feet. Components: V, S. Duration: 24 hours.\nChoose any number of willing creatures that you can see within range. Each target shape-shifts into a Large or smaller Beast of your choice that has a Challenge Rating of 4 or lower. You can choose a different form for each target. On later turns, you can take a Magic action to transform the targets again.\nA target's game statistics are replaced by the chosen Beast's statistics, but the target retains its creature type; Hit Points; Hit Point Dice; alignment; ability to communicate; and Intelligence, Wisdom, and Charisma scores. The target's actions are limited by the Beast form's anatomy, and it can't cast spells. The target's equipment melds into the new form, and the target can't use any of that equipment while in that form.\nThe target gains a number of Temporary Hit Points equal to the Hit Points of the first form into which it shape-shifts. These Temporary Hit Points vanish if any remain when the spell ends. The transformation lasts for the duration or until the target ends it as a Bonus Action.","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Animal Shapes","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Animate Dead","constant":false,"content":"## Animate Dead (사체 조종) - Level 3 Necromancy spell, SRD 5.2.1\nClasses: Cleric, Wizard. Casting Time: 1 minute. Range: 10 feet. Components: V, S, M (a drop of blood, a piece of flesh, and a pinch of bone dust). Duration: Instantaneous.\nChoose a pile of bones or a corpse of a Medium or Small Humanoid within range. The target becomes an Undead creature: a Skeleton if you chose bones or a Zombie if you chose a corpse (see “Monsters” for the stat blocks).\nOn each of your turns, you can take a Bonus Action to mentally command any creature you made with this spell if the creature is within 60 feet of you (if you control multiple creatures, you can command any of them at the same time, issuing the same command to each one). You decide what action the creature will take and where it will move on its next turn, or you can issue a general command, such as to guard a chamber or corridor. If you issue no commands, the creature takes the Dodge action and moves only to avoid harm. Once given an order, the creature continues to follow it until its task is complete.\nThe creature is under your control for 24 hours, after which it stops obeying any command you've given it. To maintain control of the creature for another 24 hours, you must cast this spell on the creature again before the current 24-hour period ends.\nThis use of the spell reasserts your control over up to four creatures you have animated with this spell rather than animating a new creature.\nUsing a Higher-Level Spell Slot. You animate or reassert control over two additional Undead creatures for each spell slot level above 3. Each of the creatures must come from a different corpse or pile of bones.","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Animate Dead","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Animate Objects","constant":false,"content":"## Animate Objects (물체 생명부여) - Level 5 Transmutation spell, SRD 5.2.1\nClasses: Bard, Sorcerer, Wizard. Casting Time: Action. Range: 120 feet. Components: V, S. Duration: Concentration, up to 1 minute.\nObjects animate at your command. Choose a number of nonmagical objects within range that aren't being worn or carried, aren't fixed to a surface, and aren't Gargantuan. The maximum number of objects is equal to your spellcasting ability modifier; for this number, a Medium or smaller target counts as 109 one object, a Large target counts as two, and a Huge target counts as three.\nEach target animates, sprouts legs, and becomes a Construct that uses the Animated Object stat block; this creature is under your control until the spell ends or until it is reduced to 0 Hit Points. Each creature you make with this spell is an ally to you and your allies. In combat, it shares your Initiative count and takes its turn immediately after yours.\nUntil the spell ends, you can take a Bonus Action to mentally command any creature you made with this spell if the creature is within 500 feet of you (if you control multiple creatures, you can command any of them at the same time, issuing the same command to each one). If you issue no commands, the creature takes the Dodge action and moves only to avoid harm. When the creature drops to 0 Hit Points, it reverts to its object form, and any remaining damage carries over to that form.\nUsing a Higher-Level Spell Slot. The creature's Slam damage increases by 1d4 (Medium or smaller), 1d6 (Large), or 1d12 (Huge) for each spell slot level above 5. or make attacks with Ranged or Reach weapons through the barrier.\nIf you move so that an affected creature is forced to pass through the barrier, the spell ends.","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Animate Objects","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Antimagic Field","constant":false,"content":"## Antimagic Field (반마법 장) - Level 8 Abjuration spell, SRD 5.2.1\nClasses: Cleric, Wizard. Casting Time: Action. Range: Self. Components: V, S, M (iron filings). Duration: Concentration, up to 1 hour.\nAn aura of antimagic surrounds you in 10-foot Emanation. No one can cast spells, take Magic actions, or create other magical effects inside the aura, and those things can't target or otherwise affect anything inside it. Magical properties of magic items don't work inside the aura or on anything inside it.\nAreas of effect created by spells or other magic can't extend into the aura, and no one can teleport into or out of it or use planar travel there. Portals close temporarily while in the aura.\nOngoing spells, except those cast by an Artifact or a deity, are suppressed in the area. While an effect is suppressed, it doesn't function, but the time it spends suppressed counts against its duration.\nDispel Magic has no effect on the aura, and the auras created by different Antimagic Field spells don't nullify each other.","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Antimagic Field","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Antipathy/Sympathy","constant":false,"content":"## Antipathy/Sympathy (반감/호감) - Level 8 Enchantment spell, SRD 5.2.1\nClasses: Bard, Druid, Wizard. Casting Time: 1 hour. Range: 60 feet. Components: V, S, M (a mix of vinegar and honey). Duration: 10 days.\nAs you cast the spell, choose whether it creates antipathy or sympathy, and target one creature or object that is Huge or smaller. Then specify a kind of creature, such as red dragons, goblins, or vampires.\nA creature of the chosen kind makes a Wisdom saving throw when it comes within 120 feet of the target. Your choice of antipathy or sympathy determines what happens to a creature when it fails that save:\nAntipathy. The creature has the Frightened condition. The Frightened creature must use its movement on its turns to get as far away as possible from the target, moving by the safest route.\nSympathy. The creature has the Charmed condition. The Charmed creature must use its movement on its turns to get as close as possible to the target, moving by the safest route. If the creature is within 5 feet of the target, the creature can't willingly move away. If the target damages the Charmed creature, that creature can make a","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Antipathy/Sympathy","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Antilife Shell","constant":false,"content":"## Antilife Shell (반생명 보호막) - Level 5 Abjuration spell, SRD 5.2.1\nClasses: Druid. Casting Time: Action. Range: Self. Components: V, S. Duration: Concentration, up to 1 hour.\nAn aura extends from you in a 10-foot Emanation for the duration. The aura prevents creatures other than Constructs and Undead from passing or reaching through it. An affected creature can cast spells 110 Wisdom saving throw to end the effect, as described below.\nEnding the Effect. If the Frightened or Charmed creature ends its turn more than 120 feet away from the target, the creature makes a Wisdom saving throw. On a successful save, the creature is no longer affected by the target. A creature that successfully saves against this effect is immune to it for 1 minute, after which it can be affected again.","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Antilife Shell","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Arcane Eye","constant":false,"content":"## Arcane Eye (비전의 눈) - Level 4 Divination spell, SRD 5.2.1\nClasses: Wizard. Casting Time: Action. Range: 30 feet. Components: V, S, M (a bit of bat fur). Duration: Concentration, up to 1 hour.\nYou create an Invisible, invulnerable eye within range that hovers for the duration. You mentally receive visual information from the eye, which can see in every direction. It also has Darkvision with a range of 30 feet.\nAs a Bonus Action, you can move the eye up to 30 feet in any direction. A solid barrier blocks the eye's movement, but the eye can pass through an opening as small as 1 inch in diameter.","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Arcane Eye","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Arcane Hand","constant":false,"content":"## Arcane Hand (비전의 손) - Level 5 Evocation spell, SRD 5.2.1\nClasses: Sorcerer, Wizard. Casting Time: Action. Range: 120 feet. Components: V, S, M (an eggshell and a glove). Duration: Concentration, up to 1 minute.\nYou create a Large hand of shimmering magical energy in an unoccupied space that you can see within range. The hand lasts for the duration, and it moves at your command, mimicking the movements of your own hand.\nThe hand is an object that has AC 20 and Hit Points equal to your Hit Point maximum. If it drops to 0 Hit Points, the spell ends. The hand doesn't occupy its space.\nWhen you cast the spell and as a Bonus Action on your later turns, you can move the hand up to 60 feet and then cause one of the following effects:\nClenched Fist. The hand strikes a target within 5 feet of it. Make a melee spell attack. On a hit, the target takes 5d8 Force damage.\nForceful Hand. The hand attempts to push a Huge or smaller creature within 5 feet of it. The target must succeed on a Strength saving throw, or the hand pushes the target up to 5 feet plus a number of feet equal to five times your spellcasting ability modifier. The hand moves with the target, remaining within 5 feet of it.\nGrasping Hand. The hand attempts to grapple a Huge or smaller creature within 5 feet of it. The target must succeed on a Dexterity saving throw, or the target has the Grappled condition, with an escape DC equal to your spell save DC. While the hand grapples the target, you can take a Bonus Action to cause the hand to crush it, dealing Bludgeoning damage to the target equal to 4d6 plus your spellcasting ability modifier.\nInterposing Hand. The hand grants you Half Cover against attacks and other effects that originate from its space or that pass through it. In addition, its space counts as Difficult Terrain for your enemies.\nUsing a Higher-Level Spell Slot. The damage of the Clenched Fist increases by 2d8 and the damage of the Grasping Hand increases by 2d6 for each spell slot level above 5.","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Arcane Hand","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Arcane Lock","constant":false,"content":"## Arcane Lock (비전 자물쇠) - Level 2 Abjuration spell, SRD 5.2.1\nClasses: Wizard. Casting Time: Action. Range: Touch. Components: V, S, M (gold dust worth 25+ GP, which the spell consumes). Duration: Until dispelled.\nYou touch a closed door, window, gate, container, or hatch and magically lock it for the duration. This lock can't be unlocked by any nonmagical means.\nYou and any creatures you designate when you cast the spell can open and close the object despite the lock. You can also set a password that, when spoken within 5 feet of the object, unlocks it for 1 minute.","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Arcane Lock","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Arcane Sword","constant":false,"content":"## Arcane Sword (비전의 검) - Level 7 Evocation spell, SRD 5.2.1\nClasses: Bard, Wizard. Casting Time: Action. Range: 90 feet. Components: V, S, M (a miniature sword worth 250+ GP). Duration: Concentration, up to 1 minute.\nYou create a spectral sword that hovers within range. It lasts for the duration.\nWhen the sword appears, you make a melee spell attack against a target within 5 feet of the sword.\nOn a hit, the target takes Force damage equal to 4d12 plus your spellcasting ability modifier.\nOn your later turns, you can take a Bonus Action to move the sword up to 30 feet to a spot you can see and repeat the attack against the same target or a different one.","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Arcane Sword","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Arcanist's Magic Aura","constant":false,"content":"## Arcanist's Magic Aura (비전술사의 마법 오오라) - Level 2 Illusion spell, SRD 5.2.1\nClasses: Wizard. Casting Time: Action. Range: Touch 111. Components: V, S, M (a small square of silk). Duration: 24 hours.\nWith a touch, you place an illusion on a willing creature or an object that isn't being worn or carried. A creature gains the Mask effect below, and an object gains the False Aura effect below. The effect lasts for the duration. If you cast the spell on the same target every day for 30 days, the illusion lasts until dispelled.\nMask (Creature). Choose a creature type other than the target's actual type. Spells and other magical effects treat the target as if it were a creature of the chosen type.\nFalse Aura (Object). You change the way the target appears to spells and magical effects that detect magical auras, such as Detect Magic. You can make a nonmagical object appear magical, make a magic item appear nonmagical, or change the object's aura so that it appears to belong to a school of magic you choose.","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Arcanist's Magic Aura","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Astral Projection","constant":false,"content":"## Astral Projection (아스트랄 투영) - Level 9 Necromancy spell, SRD 5.2.1\nClasses: Cleric, Warlock, Wizard. Casting Time: 1 hour. Range: 10 feet. Components: V, S, M (for each of the spell's targets, one jacinth worth 1,000+ GP and one silver bar worth 100+ GP, all of which the spell consumes). Duration: Until dispelled.\nYou and up to eight willing creatures within range project your astral bodies into the Astral Plane (the spell ends instantly if you are already on that plane). Each target's body is left behind in a state of suspended animation; it has the Unconscious condition, doesn't need food or air, and doesn't age.\nA target's astral form resembles its body in almost every way, replicating its game statistics and possessions. The principal difference is the addition of a silvery cord that trails from between the shoulder blades of the astral form. The cord fades from view after 1 foot. If the cord is cut—which happens only when an effect states that it does so—the target's body and astral form both die.\nA target's astral form can travel through the Astral Plane. The moment an astral form leaves that plane, the target's body and possessions travel along the silver cord, causing the target to re-enter its body on the new plane.\nAny damage or other effects that apply to an astral form have no effect on the target's body and vice versa. If a target's body or astral form drops to 0 Hit Points, the spell ends for that target. The spell ends for all the targets if you take a Magic action to dismiss it.\nWhen the spell ends for a target who isn't dead, the target reappears in its body and exits the state of suspended animation.","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Astral Projection","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Augury","constant":false,"content":"## Augury (점술) - Level 2 Divination spell, SRD 5.2.1\nClasses: Cleric, Druid, Wizard. Casting Time: 1 minute or Ritual. Range: Self. Components: V, S, M (specially marked sticks, bones, cards, or other divinatory tokens worth 25+ GP). Duration: Instantaneous.\nYou receive an omen from an otherworldly entity about the results of a course of action that you plan to take within the next 30 minutes. The GM chooses the omen from the Omens table.\nOmens Omen For Results That Will Be … Weal Good Woe Bad Weal and woe Good and bad Indifference Neither good nor bad The spell doesn't account for circumstances, such as other spells, that might change the results.\nIf you cast the spell more than once before finishing a Long Rest, there is a cumulative 25 percent chance for each casting after the first that you get no answer.","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Augury","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Aura of Life","constant":false,"content":"## Aura of Life (생명의 오라) - Level 4 Abjuration spell, SRD 5.2.1\nClasses: Cleric, Paladin. Casting Time: Action. Range: Self. Components: V. Duration: Concentration, up to 10 minutes.\nAn aura radiates from you in a 30-foot Emanation for the duration. While in the aura, you and your allies have Resistance to Necrotic damage, and your Hit Point maximums can't be reduced. If an ally with 0 Hit Points starts its turn in the aura, that ally regains 1 Hit Point.","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Aura of Life","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Awaken","constant":false,"content":"## Awaken (각성) - Level 5 Transmutation spell, SRD 5.2.1\nClasses: Bard, Druid. Casting Time: 8 hours. Range: Touch. Components: V, S, M (an agate worth 1,000+ GP, which the spell consumes). Duration: Instantaneous.\nYou spend the casting time tracing magical pathways within a precious gemstone, and then touch the target. The target must be either a Beast or Plant creature with an Intelligence of 3 or less or a natural plant that isn't a creature. The target gains 112 an Intelligence of 10 and the ability to speak one language you know. If the target is a natural plant, it becomes a Plant creature and gains the ability to move its limbs, roots, vines, creepers, and so forth, and it gains senses similar to a human's. The GM chooses statistics appropriate for the awakened Plant, such as the statistics for the Awakened Shrub or Awakened Tree in “Monsters.” The awakened target has the Charmed condition for 30 days or until you or your allies deal damage to it. When that condition ends, the awakened creature chooses its attitude toward you.","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Awaken","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Bane","constant":false,"content":"## Bane (억압) - Level 1 Enchantment spell, SRD 5.2.1\nClasses: Bard, Cleric, Warlock. Casting Time: Action. Range: 30 feet. Components: V, S, M (a drop of blood). Duration: Concentration, up to 1 minute.\nUp to three creatures of your choice that you can see within range must each make a Charisma saving throw. Whenever a target that fails this save makes an attack roll or a saving throw before the spell ends, the target must subtract 1d4 from the attack roll or save.\nUsing a Higher-Level Spell Slot. You can target one additional creature for each spell slot level above 1.","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Bane","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Banishment","constant":false,"content":"## Banishment (추방) - Level 4 Abjuration spell, SRD 5.2.1\nClasses: Cleric, Paladin, Sorcerer, Warlock, Wizard. Casting Time: Action. Range: 30 feet. Components: V, S, M (a pentacle). Duration: Concentration, up to 1 minute.\nOne creature that you can see within range must succeed on a Charisma saving throw or be transported to a harmless demiplane for the duration.\nWhile there, the target has the Incapacitated condition. When the spell ends, the target reappears in the space it left or in the nearest unoccupied space if that space is occupied.\nIf the target is an Aberration, a Celestial, an Elemental, a Fey, or a Fiend, the target doesn't return if the spell lasts for 1 minute. The target is instead transported to a random location on a plane (GM's choice) associated with its creature type.\nUsing a Higher-Level Spell Slot. You can target one additional creature for each spell slot level above 4.","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Banishment","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Barkskin","constant":false,"content":"## Barkskin (나무껍질 피부) - Level 2 Transmutation spell, SRD 5.2.1\nClasses: Druid, Ranger. Casting Time: Bonus Action. Range: Touch Component: V, S, M (a handful of bark). Components: . Duration: 1 hour.\nYou touch a willing creature. Until the spell ends, the target's skin assumes a bark-like appearance, and the target has an Armor Class of 17 if its AC is lower than that.","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Barkskin","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Beacon of Hope","constant":false,"content":"## Beacon of Hope (희망의 봉화) - Level 3 Abjuration spell, SRD 5.2.1\nClasses: Cleric. Casting Time: Action. Range: 30 feet. Components: V, S. Duration: Concentration, up to 1 minute.\nChoose any number of creatures within range. For the duration, each target has Advantage on Wisdom saving throws and Death Saving Throws and regains the maximum number of Hit Points possible from any healing.","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Beacon of Hope","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Befuddlement","constant":false,"content":"## Befuddlement (정신 혼탁) - Level 8 Enchantment spell, SRD 5.2.1\nClasses: Bard, Druid, Warlock, Wizard. Casting Time: Action. Range: 150 feet. Components: V, S, M (a key ring with no keys). Duration: Instantaneous.\nYou blast the mind of a creature that you can see within range. The target makes an Intelligence saving throw.\nOn a failed save, the target takes 10d12 Psychic damage and can't cast spells or take the Magic action. At the end of every 30 days, the target repeats the save, ending the effect on a success. The effect can also be ended by the Greater Restoration, Heal, or Wish spell.\nOn a successful save, the target takes half as much damage only.","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Befuddlement","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Bestow Curse","constant":false,"content":"## Bestow Curse (저주 부여) - Level 3 Necromancy spell, SRD 5.2.1\nClasses: Bard, Cleric, Wizard. Casting Time: Action. Range: Touch. Components: V, S. Duration: Concentration, up to 1 minute.\nYou touch a creature, which must succeed on a Wisdom saving throw or become cursed for the duration. Until the curse ends, the target suffers one of the following effects of your choice: • Choose one ability. The target has Disadvantage on ability checks and saving throws made with that ability. • The target has Disadvantage on attack rolls against you. • In combat, the target must succeed on a Wisdom saving throw at the start of each of its turns or be forced to take the Dodge action on that turn. 113 • If you deal damage to the target with an attack roll or a spell, the target takes an extra 1d8 Necrotic damage.\nUsing a Higher-Level Spell Slot. If you cast this spell using a level 4 spell slot, you can maintain Concentration on it for up to 10 minutes. If you use a level 5+ spell slot, the spell doesn't require Concentration, and the duration becomes 8 hours (level 5-6 slot) or 24 hours (level 7-8 slot). If you use a level 9 spell slot, the spell lasts until dispelled.","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Bestow Curse","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Black Tentacles","constant":false,"content":"## Black Tentacles (검은 촉수) - Level 4 Conjuration spell, SRD 5.2.1\nClasses: Wizard. Casting Time: Action. Range: 90 feet. Components: V, S, M (a tentacle). Duration: Concentration, up to 1 minute.\nSquirming, ebony tentacles fill a 20-foot square on ground that you can see within range. For the duration, these tentacles turn the ground in that area into Difficult Terrain.\nEach creature in that area makes a Strength saving throw. On a failed save, it takes 3d6 Bludgeoning damage, and it has the Restrained condition until the spell ends. A creature also makes that save if it enters the area or ends it turn there. A creature makes that save only once per turn.\nA Restrained creature can take an action to make a Strength (Athletics) check against your spell save DC, ending the condition on itself on a success.","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Black Tentacles","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Blade Barrier","constant":false,"content":"## Blade Barrier (칼날 방벽) - Level 6 Evocation spell, SRD 5.2.1\nClasses: Cleric. Casting Time: Action. Range: 90 feet. Components: V, S. Duration: Concentration, up to 10 minutes.\nYou create a wall of whirling blades made of magical energy. The wall appears within range and lasts for the duration. You make a straight wall up to 100 feet long, 20 feet high, and 5 feet thick, or a ringed wall up to 60 feet in diameter, 20 feet high, and 5 feet thick. The wall provides Three-Quarters Cover, and its space is Difficult Terrain.\nAny creature in the wall's space makes a Dexterity saving throw, taking 6d10 Force damage on a failed save or half as much damage on a successful one. A creature also makes that save if it enters the wall's space or ends it turn there. A creature makes that save only once per turn.","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Blade Barrier","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Bless","constant":false,"content":"## Bless (축복) - Level 1 Enchantment spell, SRD 5.2.1\nClasses: Cleric, Paladin. Casting Time: Action. Range: 30 feet. Components: V, S, M (a Holy Symbol worth 5+ GP). Duration: Concentration, up to 1 minute.\nYou bless up to three creatures within range. Whenever a target makes an attack roll or a saving throw before the spell ends, the target adds 1d4 to the attack roll or save.\nUsing a Higher-Level Spell Slot. You can target one additional creature for each spell slot level above 1.","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Bless","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Blight","constant":false,"content":"## Blight (황폐화) - Level 4 Necromancy spell, SRD 5.2.1\nClasses: Druid, Sorcerer, Warlock, Wizard. Casting Time: Action. Range: 30 feet. Components: V, S. Duration: Instantaneous.\nA creature that you can see within range makes a Constitution saving throw, taking 8d8 Necrotic damage on a failed save or half as much damage on a successful one. A Plant creature automatically fails the save.\nAlternatively, target a nonmagical plant that isn't a creature, such as a tree or shrub. It doesn't make a save; it simply withers and dies.\nUsing a Higher-Level Spell Slot. The damage increases by 1d8 for each spell slot level above 4.","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Blight","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Blindness/Deafness","constant":false,"content":"## Blindness/Deafness (장님화/귀머거리화) - Level 2 Transmutation spell, SRD 5.2.1\nClasses: Bard, Cleric, Sorcerer, Wizard. Casting Time: Action. Range: 120 feet. Components: V. Duration: 1 minute.\nOne creature that you can see within range must succeed on a Constitution saving throw, or it has the Blinded or Deafened condition (your choice) for the duration. At the end of each of its turns, the target repeats the save, ending the spell on itself on a success.\nUsing a Higher-Level Spell Slot. You can target one additional creature for each spell slot level above 2.","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Blindness/Deafness","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Blink","constant":false,"content":"## Blink (점멸) - Level 3 Transmutation spell, SRD 5.2.1\nClasses: Sorcerer, Wizard. Casting Time: Action. Range: Self. Components: V, S. Duration: 1 minute.\nRoll 1d6 at the end of each of your turns for the duration. On a roll of 4-6, you vanish from your current plane of existence and appear in the Ethereal Plane (the spell ends instantly if you are already on that plane). While on the Ethereal Plane, you can 114 perceive the plane you left, which is cast in shades of gray, but you can't see anything there more than 60 feet away. You can affect and be affected only by other creatures on the Ethereal Plane, and creatures on the other plane can't perceive you unless they have a special ability that lets them perceive things on the Ethereal Plane.\nYou return to the other plane at the start of your next turn and when the spell ends if you are on the Ethereal Plane. You return to an unoccupied space of your choice that you can see within 10 feet of the space you left. If no unoccupied space is available within that range, you appear in the nearest unoccupied space.","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Blink","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Blur","constant":false,"content":"## Blur (흐려짐) - Level 2 Illusion spell, SRD 5.2.1\nClasses: Sorcerer, Wizard. Casting Time: Action. Range: Self. Components: V. Duration: Concentration, up to 1 minute.\nYour body becomes blurred. For the duration, any creature has Disadvantage on attack rolls against you. An attacker is immune to this effect if it perceives you with Blindsight or Truesight.","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Blur","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Burning Hands","constant":false,"content":"## Burning Hands (타오르는 손길) - Level 1 Evocation spell, SRD 5.2.1\nClasses: Sorcerer, Wizard. Casting Time: Action. Range: Self. Components: V, S. Duration: Instantaneous.\nA thin sheet of flames shoots forth from you. Each creature in a 15-foot Cone makes a Dexterity saving throw, taking 3d6 Fire damage on a failed save or half as much damage on a successful one.\nFlammable objects in the Cone that aren't being worn or carried start burning.\nUsing a Higher-Level Spell Slot. The damage increases by 1d6 for each spell slot level above 1.","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Burning Hands","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Call Lightning","constant":false,"content":"## Call Lightning (번개 부르기) - Level 3 Conjuration spell, SRD 5.2.1\nClasses: Druid. Casting Time: Action. Range: 120 feet. Components: V, S. Duration: Concentration, up to 10 minutes.\nA storm cloud appears at a point within range that you can see above yourself. It takes the shape of a Cylinder that is 10 feet tall with a 60-foot radius.\nWhen you cast the spell, choose a point you can see under the cloud. A lightning bolt shoots from the cloud to that point. Each creature within 5 feet of that point makes a Dexterity saving throw, taking 3d10 Lightning damage on a failed save or half as much damage on a successful one.\nUntil the spell ends, you can take a Magic action to call down lightning in that way again, targeting the same point or a different one.\nIf you're outdoors in a storm when you cast this spell, the spell gives you control over that storm instead of creating a new one. Under such conditions, the spell's damage increases by 1d10.\nUsing a Higher-Level Spell Slot. The damage increases by 1d10 for each spell slot level above 3.","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Call Lightning","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Calm Emotions","constant":false,"content":"## Calm Emotions (감정 진정화) - Level 2 Enchantment spell, SRD 5.2.1\nClasses: Bard, Cleric. Casting Time: Action. Range: 60 feet. Components: V, S. Duration: Concentration, up to 1 minute.\nEach Humanoid in a 20-foot-radius Sphere centered on a point you choose within range must succeed on a Charisma saving throw or be affected by one of the following effects (choose for each creature): • The creature has Immunity to the Charmed and Frightened conditions until the spell ends. If the creature was already Charmed or Frightened, those conditions are suppressed for the duration. • The creature becomes Indifferent about creatures of your choice that it's Hostile toward. This indifference ends if the target takes damage or witnesses its allies taking damage. When the spell ends, the creature's attitude returns to normal.","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Calm Emotions","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Chain Lightning","constant":false,"content":"## Chain Lightning (연쇄 번개) - Level 6 Evocation spell, SRD 5.2.1\nClasses: Sorcerer, Wizard. Casting Time: Action. Range: 150 feet. Components: V, S, M (three silver pins). Duration: Instantaneous.\nYou launch a lightning bolt toward a target you can see within range. Three bolts then leap from that target to as many as three other targets of your choice, each of which must be within 30 feet of the first target. A target can be a creature or an object and can be targeted by only one of the bolts.\nEach target makes a Dexterity saving throw, taking 10d8 Lightning damage on a failed save or half as much damage on a successful one.\nUsing a Higher-Level Spell Slot. One additional bolt leaps from the first target to another target for each spell slot level above 6.","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Chain Lightning","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Charm Monster","constant":false,"content":"## Charm Monster (괴물 매혹) - Level 4 Enchantment spell, SRD 5.2.1\nClasses: Bard, Druid, Sorcerer, Warlock, Wizard. Casting Time: Action. Range: 30 feet. Components: V, S. Duration: 1 hour 115.\nOne creature you can see within range makes a Wisdom saving throw. It does so with Advantage if you or your allies are fighting it. On a failed save, the target has the Charmed condition until the spell ends or until you or your allies damage it. The Charmed creature is Friendly to you. When the spell ends, the target knows it was Charmed by you.\nUsing a Higher-Level Spell Slot. You can target one additional creature for each spell slot level above 4.","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Charm Monster","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Charm Person","constant":false,"content":"## Charm Person (인간형 매혹) - Level 1 Enchantment spell, SRD 5.2.1\nClasses: Bard, Druid, Sorcerer, Warlock, Wizard. Casting Time: Action. Range: 30 feet. Components: V, S. Duration: 1 hour.\nOne Humanoid you can see within range makes a Wisdom saving throw. It does so with Advantage if you or your allies are fighting it. On a failed save, the target has the Charmed condition until the spell ends or until you or your allies damage it. The Charmed creature is Friendly to you. When the spell ends, the target knows it was Charmed by you.\nUsing a Higher-Level Spell Slot. You can target one additional creature for each spell slot level above 1.","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Charm Person","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Chill Touch","constant":false,"content":"## Chill Touch (냉랭한 접촉) - Cantrip Necromancy spell, SRD 5.2.1\nClasses: Sorcerer, Warlock, Wizard. Casting Time: Action. Range: Touch. Components: V, S. Duration: Instantaneous.\nChanneling the chill of the grave, make a melee spell attack against a target within reach. On a hit, the target takes 1d10 Necrotic damage, and it can't regain Hit Points until the end of your next turn.\nCantrip Upgrade. The damage increases by 1d10 when you reach levels 5 (2d10), 11 (3d10), and 17 (4d10).","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Chill Touch","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Chromatic Orb","constant":false,"content":"## Chromatic Orb (오색의 보주) - Level 1 Evocation spell, SRD 5.2.1\nClasses: Sorcerer, Wizard. Casting Time: Action. Range: 90 feet. Components: V, S, M (a diamond worth 50+ GP). Duration: Instantaneous.\nYou hurl an orb of energy at a target within range.\nChoose Acid, Cold, Fire, Lightning, Poison, or Thunder for the type of orb you create, and then make a ranged spell attack against the target. On a hit, the target takes 3d8 damage of the chosen type.\nIf you roll the same number on two or more of the d8s, the orb leaps to a different target of your choice within 30 feet of the target. Make an attack roll against the new target, and make a new damage roll. The orb can't leap again unless you cast the spell with a level 2+ spell slot.\nUsing a Higher-Level Spell Slot. The damage increases by 1d8 for each spell slot level above 1. The orb can leap a maximum number of times equal to the level of the slot expended, and a creature can be targeted only once by each casting of this spell.","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Chromatic Orb","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Circle of Death","constant":false,"content":"## Circle of Death (죽음의 원) - Level 6 Necromancy spell, SRD 5.2.1\nClasses: Sorcerer, Warlock, Wizard. Casting Time: Action. Range: 150 feet. Components: V, S, M (the powder of a crushed black pearl worth 500+ GP). Duration: Instantaneous.\nNegative energy ripples out in a 60-foot-radius Sphere from a point you choose within range. Each creature in that area makes a Constitution saving throw, taking 8d8 Necrotic damage on a failed save or half as much damage on a successful one.\nUsing a Higher-Level Spell Slot. The damage increases by 2d8 for each spell slot level above 6.","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Circle of Death","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Clairvoyance","constant":false,"content":"## Clairvoyance (투시) - Level 3 Divination spell, SRD 5.2.1\nClasses: Bard, Cleric, Sorcerer, Wizard. Casting Time: 10 minutes. Range: 1 mile. Components: V, S, M (a focus worth 100+ GP, either a jeweled horn for hearing or a glass eye for seeing). Duration: Concentration, up to 10 minutes.\nYou create an Invisible sensor within range in a location familiar to you (a place you have visited or seen before) or in an obvious location that is unfamiliar to you (such as behind a door, around a corner, or in a grove of trees). The intangible, invulnerable sensor remains in place for the duration.\nWhen you cast the spell, choose seeing or hearing.\nYou can use the chosen sense through the sensor as if you were in its space. As a Bonus Action, you can switch between seeing and hearing.\nA creature that sees the sensor (such as a creature benefiting from See Invisibility or Truesight) sees a luminous orb about the size of your fist.","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Clairvoyance","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Clone","constant":false,"content":"## Clone (복제) - Level 8 Necromancy spell, SRD 5.2.1\nClasses: Wizard. Casting Time: 1 hour. Range: Touch. Components: V, S, M (a diamond worth 1,000+ GP, which the spell consumes, and a sealable vessel worth 2,000+ GP that is large enough to hold the creature being cloned). Duration: Instantaneous 116.\nYou touch a creature or at least 1 cubic inch of its flesh. An inert duplicate of that creature forms inside the vessel used in the spell's casting and finishes growing after 120 days; you choose whether the finished clone is the same age as the creature or younger. The clone remains inert and endures indefinitely while its vessel remains undisturbed.\nIf the original creature dies after the clone finishes forming, the creature's soul transfers to the clone if the soul is free and willing to return. The clone is physically identical to the original and has the same personality, memories, and abilities, but none of the original's equipment. The creature's original remains, if any, become inert and can't be revived, since the creature's soul is elsewhere.","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Clone","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Cloudkill","constant":false,"content":"## Cloudkill (죽음의 구름) - Level 5 Conjuration spell, SRD 5.2.1\nClasses: Sorcerer, Wizard. Casting Time: Action. Range: 120 feet. Components: V, S. Duration: Concentration, up to 10 minutes.\nYou create a 20-foot-radius Sphere of yellow-green fog centered on a point within range. The fog lasts for the duration or until strong wind (such as the one created by Gust of Wind) disperses it, ending the spell. Its area is Heavily Obscured.\nEach creature in the Sphere makes a Constitution saving throw, taking 5d8 Poison damage on a failed save or half as much damage on a successful one. A creature must also make this save when the Sphere moves into its space and when it enters the Sphere or ends its turn there. A creature makes this save only once per turn.\nThe Sphere moves 10 feet away from you at the start of each of your turns.\nUsing a Higher-Level Spell Slot. The damage increases by 1d8 for each spell slot level above 5.","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Cloudkill","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Color Spray","constant":false,"content":"## Color Spray (색 분사) - Level 1 Illusion spell, SRD 5.2.1\nClasses: Bard, Sorcerer, Wizard. Casting Time: Action. Range: Self. Components: V, S, M (a pinch of colorful sand). Duration: Instantaneous.\nYou launch a dazzling array of flashing, colorful light. Each creature in a 15-foot Cone originating from you must succeed on a Constitution saving throw or have the Blinded condition until the end of your next turn.","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Color Spray","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Command","constant":false,"content":"## Command (명령) - Level 1 Enchantment spell, SRD 5.2.1\nClasses: Bard, Cleric, Paladin. Casting Time: Action. Range: 60 feet. Components: V. Duration: Instantaneous.\nYou speak a one-word command to a creature you can see within range. The target must succeed on a Wisdom saving throw or follow the command on its next turn. Choose the command from these options:\nApproach. The target moves toward you by the shortest and most direct route, ending its turn if it moves within 5 feet of you.\nDrop. The target drops whatever it is holding and then ends its turn.\nFlee. The target spends its turn moving away from you by the fastest available means.\nGrovel. The target has the Prone condition and then ends its turn.\nHalt. On its turn, the target doesn't move and takes no action or Bonus Action.\nUsing a Higher-Level Spell Slot. You can affect one additional creature for each spell slot level above 1.","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Command","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Commune","constant":false,"content":"## Commune (교감) - Level 5 Divination spell, SRD 5.2.1\nClasses: Cleric. Casting Time: 1 minute or Ritual. Range: Self. Components: V, S, M (incense). Duration: 1 minute.\nYou contact a deity or a divine proxy and ask up to three questions that can be answered with yes or no. You must ask your questions before the spell ends. You receive a correct answer for each question.\nDivine beings aren't necessarily omniscient, so you might receive “unclear” as an answer if a question pertains to information that lies beyond the deity's knowledge. In a case where a one-word answer could be misleading or contrary to the deity's interests, the GM might offer a short phrase as an answer instead.\nIf you cast the spell more than once before finishing a Long Rest, there is a cumulative 25 percent chance for each casting after the first that you get no answer.","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Commune","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Commune with Nature","constant":false,"content":"## Commune with Nature (자연과의 교감) - Level 5 Divination spell, SRD 5.2.1\nClasses: Druid, Ranger. Casting Time: 1 minute or Ritual. Range: Self. Components: V, S. Duration: Instantaneous.\nYou commune with nature spirits and gain knowledge of the surrounding area. In the outdoors, the spell gives you knowledge of the area within 3 miles of you. In caves and other natural underground settings, the radius is limited to 300 feet. The spell 117 doesn't function where nature has been replaced by construction, such as in castles and settlements.\nChoose three of the following facts; you learn those facts as they pertain to the spell's area: • Locations of settlements • Locations of portals to other planes of existence • Location of one Challenge Rating 10+ creature (GM's choice) that is a Celestial, an Elemental, a Fey, a Fiend, or an Undead • The most prevalent kind of plant, mineral, or Beast (you choose which to learn) • Locations of bodies of water For example, you could determine the location of a powerful monster in the area, the locations of bodies of water, and the locations of any towns.","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Commune with Nature","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Comprehend Languages","constant":false,"content":"## Comprehend Languages (언어 변환) - Level 1 Divination spell, SRD 5.2.1\nClasses: Bard, Sorcerer, Warlock, Wizard. Casting Time: Action or Ritual. Range: Self. Components: V, S, M (a pinch of soot and salt). Duration: 1 hour.\nFor the duration, you understand the literal meaning of any language that you hear or see signed. You also understand any written language that you see, but you must be touching the surface on which the words are written. It takes about 1 minute to read one page of text. This spell doesn't decode symbols or secret messages.","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Comprehend Languages","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Compulsion","constant":false,"content":"## Compulsion (강제 이동) - Level 4 Enchantment spell, SRD 5.2.1\nClasses: Bard. Casting Time: Action. Range: 30 feet. Components: V, S. Duration: Concentration, up to 1 minute.\nEach creature of your choice that you can see within range must succeed on a Wisdom saving throw or have the Charmed condition until the spell ends.\nFor the duration, you can take a Bonus Action to designate a direction that is horizontal to you. Each Charmed target must use as much of its movement as possible to move in that direction on its next turn, taking the safest route. After moving in this way, a target repeats the save, ending the spell on itself on a success.","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Compulsion","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Cone of Cold","constant":false,"content":"## Cone of Cold (냉기 원뿔) - Level 5 Evocation spell, SRD 5.2.1\nClasses: Druid, Sorcerer, Wizard. Casting Time: Action. Range: Self. Components: V, S, M (a small crystal or glass cone). Duration: Instantaneous.\nYou unleash a blast of cold air. Each creature in a 60-foot Cone originating from you makes a Constitution saving throw, taking 8d8 Cold damage on a failed save or half as much damage on a successful one. A creature killed by this spell becomes a frozen statue until it thaws.\nUsing a Higher-Level Spell Slot. The damage increases by 1d8 for each spell slot level above 5.","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Cone of Cold","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Confusion","constant":false,"content":"## Confusion (혼란) - Level 4 Enchantment spell, SRD 5.2.1\nClasses: Bard, Druid, Sorcerer, Wizard. Casting Time: Action. Range: 90 feet. Components: V, S, M (three nut shells). Duration: Concentration, up to 1 minute.\nEach creature in a 10-foot-radius Sphere centered on a point you choose within range must succeed on a Wisdom saving throw, or that target can't take Bonus Actions or Reactions and must roll 1d10 at the start of each of its turns to determine its behavior for that turn, consulting the table below. 1d10 Behavior for the Turn 1 The target doesn't take an action, and it uses all its movement to move. Roll 1d4 for the direction: 1, north; 2, east; 3, south; or 4, west. 2-6 The target doesn't move or take actions. 7-8 The target doesn't move, and it takes the Attack action to make one melee attack against a random creature within reach. If none are within reach, the target takes no action. 9-10 The target chooses its behavior.\nAt the end of each of its turns, an affected target repeats the save, ending the spell on itself on a success.\nUsing a Higher-Level Spell Slot. The Sphere's radius increases by 5 feet for each spell slot level above 4.","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Confusion","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Conjure Animals","constant":false,"content":"## Conjure Animals (동물 소환) - Level 3 Conjuration spell, SRD 5.2.1\nClasses: Druid, Ranger. Casting Time: Action. Range: 60 feet. Components: V, S. Duration: Concentration, up to 10 minutes.\nYou conjure nature spirits that appear as a Large pack of spectral, intangible animals in an unoccupied space you can see within range. The pack lasts for the duration, and you choose the spirits' animal form, such as wolves, serpents, or birds.\nYou have Advantage on Strength saving throws while you're within 5 feet of the pack, and when you move on your turn, you can also move the pack up to 30 feet to an unoccupied space you can see.\nWhenever the pack moves within 10 feet of a creature you can see and whenever a creature you can see enters a space within 10 feet of the pack or ends 118 its turn there, you can force that creature to make a Dexterity saving throw. On a failed save, the creature takes 3d10 Slashing damage. A creature makes this save only once per turn.\nUsing a Higher-Level Spell Slot. The damage increases by 1d10 for each spell slot level above 3.","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Conjure Animals","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Conjure Celestial","constant":false,"content":"## Conjure Celestial (천상체 소환) - Level 7 Conjuration spell, SRD 5.2.1\nClasses: Cleric. Casting Time: Action. Range: 90 feet. Components: V, S. Duration: Concentration, up to 10 minutes.\nYou conjure a spirit from the Upper Planes, which manifests as a pillar of light in a 10-foot-radius, 40-foot-high Cylinder centered on a point within range. For each creature you can see in the Cylinder, choose which of these lights shines on it:\nHealing Light. The target regains Hit Points equal to 4d12 plus your spellcasting ability modifier.\nSearing Light. The target makes a Dexterity saving throw, taking 6d12 Radiant damage on a failed save or half as much damage on a successful one.\nUntil the spell ends, Bright Light fills the Cylinder, and when you move on your turn, you can also move the Cylinder up to 30 feet.\nWhenever the Cylinder moves into the space of a creature you can see and whenever a creature you can see enters the Cylinder or ends its turn there, you can bathe it in one of the lights. A creature can be affected by this spell only once per turn.\nUsing a Higher-Level Spell Slot. The healing and damage increase by 1d12 for each spell slot level above 7.","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Conjure Celestial","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Conjure Elemental","constant":false,"content":"## Conjure Elemental (원소 소환) - Level 5 Conjuration spell, SRD 5.2.1\nClasses: Druid, Wizard. Casting Time: Action. Range: 60 feet. Components: V, S. Duration: Concentration, up to 10 minutes.\nYou conjure a Large, intangible spirit from the Elemental Planes that appears in an unoccupied space within range. Choose the spirit's element, which determines its damage type: air (Lightning), earth (Thunder), fire (Fire), or water (Cold). The spirit lasts for the duration.\nWhenever a creature you can see enters the spirit's space or starts its turn within 5 feet of the spirit, you can force that creature to make a Dexterity saving throw if the spirit has no creature Restrained.\nOn failed save, the target takes 8d8 damage of the spirit's type, and the target has the Restrained condition until the spell ends. At the start of each of its turns, the Restrained target repeats the save.\nOn a failed save, the target takes 4d8 damage of the spirit's type. On a successful save, the target isn't Restrained by the spirit.\nUsing a Higher-Level Spell Slot. The damage increases by 1d8 for each spell slot level above 5.","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Conjure Elemental","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Conjure Fey","constant":false,"content":"## Conjure Fey (요정 소환) - Level 6 Conjuration spell, SRD 5.2.1\nClasses: Druid. Casting Time: Action. Range: 60 feet. Components: V, S. Duration: Concentration, up to 10 minutes.\nYou conjure a Medium spirit from the Feywild in an unoccupied space you can see within range.\nThe spirit lasts for the duration, and it looks like a Fey creature of your choice. When the spirit appears, you can make one melee spell attack against a creature within 5 feet of it. On a hit, the target takes Psychic damage equal to 3d12 plus your spellcasting ability modifier, and the target has the Frightened condition until the start of your next turn, with both you and the spirit as the source of the fear.\nAs a Bonus Action on your later turns, you can teleport the spirit to an unoccupied space you can see within 30 feet of the space it left and make the attack against a creature within 5 feet of it.\nUsing a Higher-Level Spell Slot. The damage increases by 1d12 for each spell slot level above 6.","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Conjure Fey","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Conjure Minor Elementals","constant":false,"content":"## Conjure Minor Elementals (하급 원소 소환) - Level 4 Conjuration spell, SRD 5.2.1\nClasses: Druid, Wizard. Casting Time: Action. Range: Self. Components: V, S. Duration: Concentration, up to 10 minutes.\nYou conjure spirits from the Elemental Planes that flit around you in a 15-foot Emanation for the duration. Until the spell ends, any attack you make deals an extra 2d8 damage when you hit a creature in the Emanation. This damage is Acid, Cold, Fire, or Lightning (your choice when you make the attack).\nIn addition, the ground in the Emanation is Difficult Terrain for your enemies.\nUsing a Higher-Level Spell Slot. The damage increases by 1d8 for each spell slot level above 4.","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Conjure Minor Elementals","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Conjure Woodland Beings","constant":false,"content":"## Conjure Woodland Beings (숲의 정령 소환) - Level 4 Conjuration spell, SRD 5.2.1\nClasses: Druid, Ranger. Casting Time: Action. Range: Self. Components: V, S. Duration: Concentration, up to 10 minutes.\nYou conjure nature spirits that flit around you in a 10-foot Emanation for the duration. Whenever the Emanation enters the space of a creature you can 119 see and whenever a creature you can see enters the Emanation or ends its turn there, you can force that creature to make a Wisdom saving throw. The creature takes 5d8 Force damage on a failed save or half as much damage on a successful one. A creature makes this save only once per turn.\nIn addition, you can take the Disengage action as a Bonus Action for the spell's duration.\nUsing a Higher-Level Spell Slot. The damage increases by 1d8 for each spell slot level above 4.","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Conjure Woodland Beings","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Contact Other Plane","constant":false,"content":"## Contact Other Plane (이계 접촉) - Level 5 Divination spell, SRD 5.2.1\nClasses: Warlock, Wizard. Casting Time: 1 minute or Ritual. Range: Self. Components: V. Duration: 1 minute.\nYou mentally contact a demigod, the spirit of a longdead sage, or some other knowledgeable entity from another plane. Contacting this otherworldly intelligence can break your mind. When you cast this spell, make a DC 15 Intelligence saving throw.\nOn a successful save, you can ask the entity up to five questions. You must ask your questions before the spell ends. The GM answers each question with one word, such as “yes,” “no,” “maybe,” “never,” “irrelevant,” or “unclear” (if the entity doesn't know the answer to the question). If a one-word answer would be misleading, the GM might instead offer a short phrase as an answer.\nOn a failed save, you take 6d6 Psychic damage and have the Incapacitated condition until you finish a Long Rest. A Greater Restoration spell cast on you ends this effect.","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Contact Other Plane","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Contagion","constant":false,"content":"## Contagion (전염병) - Level 5 Necromancy spell, SRD 5.2.1\nClasses: Cleric, Druid. Casting Time: Action. Range: Touch Component: V, S. Components: . Duration: 7 days.\nYour touch inflicts a magical contagion. The target must succeed on a Constitution saving throw or take 11d8 Necrotic damage and have the Poisoned condition. Also, choose one ability when you cast the spell. While Poisoned, the target has Disadvantage on saving throws made with the chosen ability.\nThe target must repeat the saving throw at the end of each of its turns until it gets three successes or failures. If the target succeeds on three of these saves, the spell ends on the target. If the target fails three of the saves, the spell lasts for 7 days on it.\nWhenever the Poisoned target receives an effect that would end the Poisoned condition, the target must succeed on a Constitution saving throw, or the Poisoned condition doesn't end on it.","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Contagion","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Contingency","constant":false,"content":"## Contingency (대비책) - Level 6 Abjuration spell, SRD 5.2.1\nClasses: Wizard. Casting Time: 10 minutes. Range: Self. Components: V, S, M (a gem-encrusted statuette of yourself worth 1,500+ GP). Duration: 10 days.\nChoose a spell of level 5 or lower that you can cast, that has a casting time of an action, and that can target you. You cast that spell—called the contingent spell—as part of casting Contingency, expending spell slots for both, but the contingent spell doesn't come into effect. Instead, it takes effect when a certain trigger occurs. You describe that trigger when you cast the two spells. For example, a Contingency cast with Water Breathing might stipulate that Water Breathing comes into effect when you are engulfed in water or a similar liquid.\nThe contingent spell takes effect immediately after the trigger occurs for the first time, whether or not you want it to, and then Contingency ends.\nThe contingent spell takes effect only on you, even if it can normally target others. You can use only one Contingency spell at a time. If you cast this spell again, the effect of another Contingency spell on you ends. Also, Contingency ends on you if its material component is ever not on your person.","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Contingency","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Continual Flame","constant":false,"content":"## Continual Flame (영속의 불꽃) - Level 2 Evocation spell, SRD 5.2.1\nClasses: Cleric, Druid, Wizard. Casting Time: Action. Range: Touch. Components: V, S, M (ruby dust worth 50+ GP, which the spell consumes). Duration: Until dispelled.\nA flame springs from an object that you touch. The effect casts Bright Light in a 20-foot radius and Dim Light for an additional 20 feet. It looks like a regular flame, but it creates no heat and consumes no fuel.\nThe flame can be covered or hidden but not smothered or quenched.","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Continual Flame","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Control Water","constant":false,"content":"## Control Water (물 조종) - Level 4 Transmutation spell, SRD 5.2.1\nClasses: Cleric, Druid, Wizard. Casting Time: Action. Range: 300 feet. Components: V, S, M (a mixture of water and dust). Duration: Concentration, up to 10 minutes.\nUntil the spell ends, you control any water inside an area you choose that is a Cube up to 100 feet on a side, using one of the following effects. As a Magic action on your later turns, you can repeat the same effect or choose a different one.\nFlood. You cause the water level of all standing water in the area to rise by as much as 20 feet. If you 120 choose an area in a large body of water, you instead create a 20-foot tall wave that travels from one side of the area to the other and then crashes. Any Huge or smaller vehicles in the wave's path are carried with it to the other side. Any Huge or smaller vehicles struck by the wave have a 25 percent chance of capsizing.\nThe water level remains elevated until the spell ends or you choose a different effect. If this effect produced a wave, the wave repeats on the start of your next turn while the flood effect lasts.\nPart Water. You part water in the area and create a trench. The trench extends across the spell's area, and the separated water forms a wall to either side. The trench remains until the spell ends or you choose a different effect. The water then slowly fills in the trench over the course of the next round until the normal water level is restored.\nRedirect Flow. You cause flowing water in the area to move in a direction you choose, even if the water has to flow over obstacles, up walls, or in other unlikely directions. The water in the area moves as you direct it, but once it moves beyond the spell's area, it resumes its flow based on the terrain.\nThe water continues to move in the direction you chose until the spell ends or you choose a different effect.\nWhirlpool. You cause a whirlpool to form in the center of the area, which must be at least 50 feet square and 25 feet deep. The whirlpool lasts until you choose a different effect or the spell ends. The whirlpool is 5 feet wide at the base, up to 50 feet wide at the top, and 25 feet tall. Any creature in the water and within 25 feet of the whirlpool is pulled 10 feet toward it. When a creature enters the whirlpool for the first time on a turn or ends its turn there, it makes a Strength saving throw. On a failed save, the creature takes 2d8 Bludgeoning damage. On a successful save, the creature takes half as much damage. A creature can swim away from the whirlpool only if it first takes an action to pull away and succeeds on a Strength (Athletics) check against your spell save DC.","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Control Water","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Control Weather","constant":false,"content":"## Control Weather (날씨 조종) - Level 8 Transmutation spell, SRD 5.2.1\nClasses: Cleric, Druid, Wizard. Casting Time: 10 minutes. Range: Self. Components: V, S, M (burning incense). Duration: Concentration, up to 8 hours.\nYou take control of the weather within 5 miles of you for the duration. You must be outdoors to cast this spell, and it ends early if you go indoors.\nWhen you cast the spell, you change the current weather conditions, which are determined by the GM. You can change precipitation, temperature, and wind. It takes 1d4 × 10 minutes for the new conditions to take effect. Once they do so, you can change the conditions again. When the spell ends, the weather gradually returns to normal.\nWhen you change the weather conditions, find a current condition on the following tables and change its stage by one, up or down. When changing the wind, you can change its direction.\nPrecipitation Stage Condition 1 Clear 2 Light clouds 3 Overcast or ground fog 4 Rain, hail, or snow 5 Torrential rain, driving hail, or blizzard Temperature Stage Condition 1 Heat wave 2 Hot 3 Warm 4 Cool 5 Cold 6 Freezing Wind Stage Condition 1 Calm 2 Moderate wind 3 Strong wind 4 Gale 5 Storm","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Control Weather","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Counterspell","constant":false,"content":"## Counterspell (주문반사) - Level 3 Abjuration spell, SRD 5.2.1\nClasses: Sorcerer, Warlock, Wizard. Casting Time: Reaction, which you take when you see a creature within 60 feet of yourself casting a spell with Verbal, Somatic, or Material components. Range: 60 feet. Components: S. Duration: Instantaneous.\nYou attempt to interrupt a creature in the process of casting a spell. The creature makes a Constitution saving throw. On a failed save, the spell dissipates with no effect, and the action, Bonus Action, or Reaction used to cast it is wasted. If that spell was cast with a spell slot, the slot isn't expended.","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Counterspell","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Create Food and Water","constant":false,"content":"## Create Food and Water (음식과 물 창조) - Level 3 Conjuration spell, SRD 5.2.1\nClasses: Cleric, Paladin. Casting Time: Action. Range: 30 feet. Components: V, S. Duration: Instantaneous.\nYou create 45 pounds of food and 30 gallons of fresh water on the ground or in containers within range—both useful in fending off the hazards of malnutrition and dehydration. The food is bland but nourishing and looks like a food of your choice, and the water is clean. The food spoils after 24 hours if uneaten. 121","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Create Food and Water","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Create or Destroy Water","constant":false,"content":"## Create or Destroy Water (물 창조 또는 파괴) - Level 1 Transmutation spell, SRD 5.2.1\nClasses: Cleric, Druid. Casting Time: Action. Range: 30 feet. Components: V, S, M (a mix of water and sand). Duration: Instantaneous.\nYou do one of the following:\nCreate Water. You create up to 10 gallons of clean water within range in an open container. Alternatively, the water falls as rain in a 30-foot Cube within range, extinguishing exposed flames there.\nDestroy Water. You destroy up to 10 gallons of water in an open container within range. Alternatively, you destroy fog in a 30-foot Cube within range.\nUsing a Higher-Level Spell Slot. You create or destroy 10 additional gallons of water, or the size of the Cube increases by 5 feet, for each spell slot level above 1.","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Create or Destroy Water","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Create Undead","constant":false,"content":"## Create Undead (언데드 창조) - Level 6 Necromancy spell, SRD 5.2.1\nClasses: Cleric, Warlock, Wizard. Casting Time: 1 minute. Range: 10 feet. Components: V, S, M (one 150+ GP black onyx stone for each corpse). Duration: Instantaneous.\nYou can cast this spell only at night. Choose up to three corpses of Medium or Small Humanoids within range. Each one becomes a Ghoul under your control (see “Monsters” for its stat block).\nAs a Bonus Action on each of your turns, you can mentally command any creature you animated with this spell if the creature is within 120 feet of you (if you control multiple creatures, you can command any of them at the same time, issuing the same command to them). You decide what action the creature will take and where it will move on its next turn, or you can issue a general command, such as to guard a particular place. If you issue no commands, the creature takes the Dodge action and moves only to avoid harm. Once given an order, the creature continues to follow the order until its task is complete.\nThe creature is under your control for 24 hours, after which it stops obeying any command you've given it. To maintain control of the creature for another 24 hours, you must cast this spell on the creature before the current 24-hour period ends. This use of the spell reasserts your control over up to three creatures you have animated with this spell rather than animating new ones.\nUsing a Higher-Level Spell Slot. If you use a level 7 spell slot, you can animate or reassert control over four Ghouls. If you use a level 8 spell slot, you can animate or reassert control over five Ghouls or two Ghasts or Wights. If you use a level 9 spell slot, you can animate or reassert control over six Ghouls, three Ghasts or Wights, or two Mummies.\nSee “Monsters” for these stat blocks.","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Create Undead","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Creation","constant":false,"content":"## Creation (창조) - Level 5 Illusion spell, SRD 5.2.1\nClasses: Sorcerer, Wizard. Casting Time: 1 minute. Range: 30 feet. Components: V, S, M (a paintbrush). Duration: Special.\nYou pull wisps of shadow material from the Shadowfell to create an object within range. It is either an object of vegetable matter (soft goods, rope, wood, and the like) or mineral matter (stone, crystal, metal, and the like). The object must be no larger than a 5-foot Cube, and the object must be of a form and material that you have seen.\nThe spell's duration depends on the object's material, as shown in the Materials table. If the object is composed of multiple materials, use the shortest duration. Using any object created by this spell as another spell's Material component causes the other spell to fail.\nMaterials Material Duration Vegetable matter 24 hours Stone or crystal 12 hours Precious metals 1 hour Gems 10 minutes Adamantine or mithral 1 minute Using a Higher-Level Spell Slot. The Cube increases by 5 feet for each spell slot level above 5.","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Creation","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Cure Wounds","constant":false,"content":"## Cure Wounds (상처 치료) - Level 1 Abjuration spell, SRD 5.2.1\nClasses: Bard, Cleric, Druid, Paladin, Ranger. Casting Time: Action. Range: Touch. Components: V, S. Duration: Instantaneous.\nA creature you touch regains a number of Hit Points equal to 2d8 plus your spellcasting ability modifier.\nUsing a Higher-Level Spell Slot. The healing increases by 2d8 for each spell slot level above 1.","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Cure Wounds","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Dancing Lights","constant":false,"content":"## Dancing Lights (춤추는 빛) - Cantrip Illusion spell, SRD 5.2.1\nClasses: Bard, Sorcerer, Wizard. Casting Time: Action. Range: 120 feet. Components: V, S, M (a bit of phosphorus). Duration: Concentration, up to 1 minute 122.\nYou create up to four torch-size lights within range, making them appear as torches, lanterns, or glowing orbs that hover for the duration. Alternatively, you combine the four lights into one glowing Medium form that is vaguely humanlike. Whichever form you choose, each light sheds Dim Light in a 10foot radius.\nAs a Bonus Action, you can move the lights up to 60 feet to a space within range. A light must be within 20 feet of another light created by this spell, and a light vanishes if it exceeds the spell's range.","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Dancing Lights","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Darkness","constant":false,"content":"## Darkness (어둠) - Level 2 Evocation spell, SRD 5.2.1\nClasses: Sorcerer, Warlock, Wizard. Casting Time: Action. Range: 60 feet. Components: V, M (bat fur and a piece of coal). Duration: Concentration, up to 10 minutes.\nFor the duration, magical Darkness spreads from a point within range and fills a 15-foot-radius Sphere.\nDarkvision can't see through it, and nonmagical light can't illuminate it.\nAlternatively, you cast the spell on an object that isn't being worn or carried, causing the Darkness to fill a 15-foot Emanation originating from that object. Covering that object with something opaque, such as a bowl or helm, blocks the Darkness.\nIf any of this spell's area overlaps with an area of Bright Light or Dim Light created by a spell of level 2 or lower, that other spell is dispelled.","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Darkness","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Darkvision","constant":false,"content":"## Darkvision (암시야) - Level 2 Transmutation spell, SRD 5.2.1\nClasses: Druid, Ranger, Sorcerer, Wizard. Casting Time: Action. Range: Touch. Components: V, S, M (a dried carrot). Duration: 8 hours.\nFor the duration, a willing creature you touch has Darkvision with a range of 150 feet.","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Darkvision","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Daylight","constant":false,"content":"## Daylight (태양광) - Level 3 Evocation spell, SRD 5.2.1\nClasses: Cleric, Druid, Paladin, Ranger, Sorcerer. Casting Time: Action. Range: 60 feet. Components: V, S. Duration: 1 hour.\nFor the duration, sunlight spreads from a point within range and fills a 60-foot-radius Sphere. The sunlight's area is Bright Light and sheds Dim Light for an additional 60 feet.\nAlternatively, you cast the spell on an object that isn't being worn or carried, causing the sunlight to fill a 60-foot Emanation originating from that object. Covering that object with something opaque, such as a bowl or helm, blocks the sunlight.\nIf any of this spell's area overlaps with an area of Darkness created by a spell of level 3 or lower, that other spell is dispelled.","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Daylight","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Death Ward","constant":false,"content":"## Death Ward (죽음 방비) - Level 4 Abjuration spell, SRD 5.2.1\nClasses: Cleric, Paladin. Casting Time: Action. Range: Touch. Components: V, S. Duration: 8 hours.\nYou touch a creature and grant it a measure of protection from death. The first time the target would drop to 0 Hit Points before the spell ends, the target instead drops to 1 Hit Point, and the spell ends.\nIf the spell is still in effect when the target is subjected to an effect that would kill it instantly without dealing damage, that effect is negated against the target, and the spell ends.","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Death Ward","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Delayed Blast Fireball","constant":false,"content":"## Delayed Blast Fireball (지연 폭발 화염구) - Level 7 Evocation spell, SRD 5.2.1\nClasses: Sorcerer, Wizard. Casting Time: Action. Range: 150 feet. Components: V, S, M (a ball of bat guano and sulfur). Duration: Concentration, up to 1 minute.\nA beam of yellow light flashes from you, then condenses at a chosen point within range as a glowing bead for the duration. When the spell ends, the bead explodes, and each creature in a 20-foot-radius Sphere centered on that point makes a Dexterity saving throw. A creature takes Fire damage equal to the total accumulated damage on a failed save or half as much damage on a successful one.\nThe spell's base damage is 12d6, and the damage increases by 1d6 whenever your turn ends and the spell hasn't ended.\nIf a creature touches the glowing bead before the spell ends, that creature makes a Dexterity saving throw. On a failed save, the spell ends, causing the bead to explode. On a successful save, the creature can throw the bead up to 40 feet. If the thrown bead enters a creature's space or collides with a solid object, the spell ends, and the bead explodes.\nWhen the bead explodes, flammable objects in the explosion that aren't being worn or carried start burning.\nUsing a Higher-Level Spell Slot. The base damage increases by 1d6 for each spell slot level above 7.","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Delayed Blast Fireball","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Demiplane","constant":false,"content":"## Demiplane (반차원) - Level 8 Conjuration spell, SRD 5.2.1\nClasses: Sorcerer, Warlock, Wizard. Casting Time: Action. Range: 60 feet. Components: S. Duration: 1 hour 123.\nYou create a shadowy Medium door on a flat solid surface that you can see within range. This door can be opened and closed, and it leads to a demiplane that is an empty room 30 feet in each dimension, made of wood or stone (your choice).\nWhen the spell ends, the door vanishes, and any objects inside the demiplane remain there. Any creatures inside also remain unless they opt to be shunted through the door as it vanishes, landing with the Prone condition in the unoccupied spaces closest to the door's former space.\nEach time you cast this spell, you can create a new demiplane or connect the shadowy door to a demiplane you created with a previous casting of this spell. Additionally, if you know the nature and contents of a demiplane created by a casting of this spell by another creature, you can connect the shadowy door to that demiplane instead.","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Demiplane","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Detect Evil and Good","constant":false,"content":"## Detect Evil and Good (악과 선 탐지) - Level 1 Divination spell, SRD 5.2.1\nClasses: Cleric, Paladin. Casting Time: Action. Range: Self. Components: V, S. Duration: Concentration, up to 10 minutes.\nFor the duration, you sense the location of any Aberration, Celestial, Elemental, Fey, Fiend, or Undead within 30 feet of yourself. You also sense whether the Hallow spell is active there and, if so, where.\nThe spell is blocked by 1 foot of stone, dirt, or wood; 1 inch of metal; or a thin sheet of lead.","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Detect Evil and Good","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Detect Magic","constant":false,"content":"## Detect Magic (마법 탐지) - Level 1 Divination spell, SRD 5.2.1\nClasses: Bard, Cleric, Druid, Paladin, Ranger, Sorcerer, Warlock, Wizard. Casting Time: Action or Ritual. Range: Self. Components: V, S. Duration: Concentration, up to 10 minutes.\nFor the duration, you sense the presence of magical effects within 30 feet of yourself. If you sense such effects, you can take the Magic action to see a faint aura around any visible creature or object in the area that bears the magic, and if an effect was created by a spell, you learn the spell's school of magic.\nThe spell is blocked by 1 foot of stone, dirt, or wood; 1 inch of metal; or a thin sheet of lead.","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Detect Magic","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Detect Poison and Disease","constant":false,"content":"## Detect Poison and Disease (독과 질병 탐지) - Level 1 Divination spell, SRD 5.2.1\nClasses: Cleric, Druid, Paladin, Ranger. Casting Time: Action or Ritual. Range: Self. Components: V, S, M (a yew leaf). Duration: Concentration, up to 10 minutes.\nFor the duration, you sense the location of poisons, poisonous or venomous creatures, and magical contagions within 30 feet of yourself. You sense the kind of poison, creature, or contagion in each case.\nThe spell is blocked by 1 foot of stone, dirt, or wood; 1 inch of metal; or a thin sheet of lead.","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Detect Poison and Disease","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Detect Thoughts","constant":false,"content":"## Detect Thoughts (생각 탐지) - Level 2 Divination spell, SRD 5.2.1\nClasses: Bard, Sorcerer, Wizard. Casting Time: Action. Range: Self. Components: V, S, M (1 Copper Piece). Duration: Concentration, up to 1 minute.\nYou activate one of the effects below. Until the spell ends, you can activate either effect as a Magic action on your later turns.\nSense Thoughts. You sense the presence of thoughts within 30 feet of yourself that belong to creatures that know languages or are telepathic.\nYou don't read the thoughts, but you know that a thinking creature is present.\nThe spell is blocked by 1 foot of stone, dirt, or wood; 1 inch of metal; or a thin sheet of lead.\nRead Thoughts. Target one creature you can see within 30 feet of yourself or one creature within 30 feet of yourself that you detected with the Sense Thoughts option. You learn what is most on the target's mind right now. If the target doesn't know any languages and isn't telepathic, you learn nothing.\nAs a Magic action on your next turn, you can try to probe deeper into the target's mind. If you probe deeper, the target makes a Wisdom saving throw.\nOn a failed save, you discern the target's reasoning, emotions, and something that looms large in its mind (such as a worry, love, or hate). On a successful save, the spell ends. Either way, the target knows that you are probing into its mind, and until you shift your attention away from the target's mind, the target can take an action on its turn to make an Intelligence (Arcana) check against your spell save DC, ending the spell on a success.","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Detect Thoughts","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Dimension Door","constant":false,"content":"## Dimension Door (차원문) - Level 4 Conjuration spell, SRD 5.2.1\nClasses: Bard, Sorcerer, Warlock, Wizard. Casting Time: Action. Range: 500 feet. Components: V. Duration: Instantaneous.\nYou teleport to a location within range. You arrive at exactly the spot desired. It can be a place you can see, one you can visualize, or one you can describe by stating distance and direction, such as “200 feet straight downward” or “300 feet upward to the northwest at a 45-degree angle.” You can also teleport one willing creature. The creature must be within 5 feet of you when you teleport, and it teleports to a space within 5 feet of your destination space. 124 If you, the other creature, or both would arrive in a space occupied by a creature or completely filled by one or more objects, you and any creature traveling with you each take 4d6 Force damage, and the teleportation fails.","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Dimension Door","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Disguise Self","constant":false,"content":"## Disguise Self (자기 위장) - Level 1 Illusion spell, SRD 5.2.1\nClasses: Bard, Sorcerer, Wizard. Casting Time: Action. Range: Self. Components: V, S. Duration: 1 hour.\nYou make yourself—including your clothing, armor, weapons, and other belongings on your person— look different until the spell ends. You can seem 1 foot shorter or taller and can appear heavier or lighter. You must adopt a form that has the same basic arrangement of limbs as you have. Otherwise, the extent of the illusion is up to you.\nThe changes wrought by this spell fail to hold up to physical inspection. For example, if you use this spell to add a hat to your outfit, objects pass through the hat, and anyone who touches it would feel nothing.\nTo discern that you are disguised, a creature must take the Study action to inspect your appearance and succeed on an Intelligence (Investigation) check against your spell save DC.","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Disguise Self","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Disintegrate","constant":false,"content":"## Disintegrate (분해) - Level 6 Transmutation spell, SRD 5.2.1\nClasses: Sorcerer, Wizard. Casting Time: Action. Range: 60 feet. Components: V, S, M (a lodestone and dust). Duration: Instantaneous.\nYou launch a green ray at a target you can see within range. The target can be a creature, a nonmagical object, or a creation of magical force, such as the wall created by Wall of Force.\nA creature targeted by this spell makes a Dexterity saving throw. On a failed save, the target takes 10d6 + 40 Force damage. If this damage reduces it to 0 Hit Points, it and everything nonmagical it is wearing and carrying are disintegrated into gray dust. The target can be revived only by a True Resurrection or a Wish spell.\nThis spell automatically disintegrates a Large or smaller nonmagical object or a creation of magical force. If such a target is Huge or larger, this spell disintegrates a 10-foot-Cube portion of it.\nUsing a Higher-Level Spell Slot. The damage increases by 3d6 for each spell slot level above 6.","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Disintegrate","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Dispel Evil and Good","constant":false,"content":"## Dispel Evil and Good (악과 선 퇴치) - Level 5 Abjuration spell, SRD 5.2.1\nClasses: Cleric, Paladin. Casting Time: Action. Range: Self. Components: V, S, M (powdered silver and iron). Duration: Concentration, up to 1 minute.\nFor the duration, Celestials, Elementals, Fey, Fiends, and Undead have Disadvantage on attack rolls against you. You can end the spell early by using either of the following special functions.\nBreak Enchantment. As a Magic action, you touch a creature that is possessed by or has the Charmed or Frightened condition from one or more creatures of the types above. The target is no longer possessed, Charmed, or Frightened by such creatures.\nDismissal. As a Magic action, you target one creature you can see within 5 feet of you that has one of the creature types above. The target must succeed on a Charisma saving throw or be sent back to its home plane if it isn't there already. If they aren't on their home plane, Undead are sent to the Shadowfell, and Fey are sent to the Feywild.","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Dispel Evil and Good","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Dispel Magic","constant":false,"content":"## Dispel Magic (마법 무효화) - Level 3 Abjuration spell, SRD 5.2.1\nClasses: Bard, Cleric, Druid, Paladin, Ranger, Sorcerer, Warlock, Wizard. Casting Time: Action. Range: 120 feet. Components: V, S. Duration: Instantaneous.\nChoose one creature, object, or magical effect within range. Any ongoing spell of level 3 or lower on the target ends. For each ongoing spell of level 4 or higher on the target, make an ability check using your spellcasting ability (DC 10 plus that spell's level). On a successful check, the spell ends.\nUsing a Higher-Level Spell Slot. You automatically end a spell on the target if the spell's level is equal to or less than the level of the spell slot you use.","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Dispel Magic","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Dissonant Whispers","constant":false,"content":"## Dissonant Whispers (불협화음의 속삭임) - Level 1 Enchantment spell, SRD 5.2.1\nClasses: Bard. Casting Time: Action. Range: 60 feet. Components: V. Duration: Instantaneous.\nOne creature of your choice that you can see within range hears a discordant melody in its mind. The target makes a Wisdom saving throw. On a failed save, it takes 3d6 Psychic damage and must immediately use its Reaction, if available, to move as far away from you as it can, using the safest route. On a successful save, the target takes half as much damage only.\nUsing a Higher-Level Spell Slot. The damage increases by 1d6 for each spell slot level above 1. 125","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Dissonant Whispers","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Divination","constant":false,"content":"## Divination (신탁) - Level 4 Divination spell, SRD 5.2.1\nClasses: Cleric, Druid, Wizard. Casting Time: Action or Ritual. Range: Self. Components: V, S, M (incense worth 25+ GP, which the spell consumes). Duration: Instantaneous.\nThis spell puts you in contact with a god or a god's servants. You ask one question about a specific goal, event, or activity to occur within 7 days. The GM offers a truthful reply, which might be a short phrase or cryptic rhyme. The spell doesn't account for circumstances that might change the answer, such as the casting of other spells.\nIf you cast the spell more than once before finishing a Long Rest, there is a cumulative 25 percent chance for each casting after the first that you get no answer.","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Divination","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Divine Favor","constant":false,"content":"## Divine Favor (신성한 은총) - Level 1 Transmutation spell, SRD 5.2.1\nClasses: Paladin. Casting Time: Bonus Action. Range: Self. Components: V, S. Duration: 1 minute.\nUntil the spell ends, your attacks with weapons deal an extra 1d4 Radiant damage on a hit.","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Divine Favor","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Divine Smite","constant":false,"content":"## Divine Smite (신성한 강타) - Level 1 Evocation spell, SRD 5.2.1\nClasses: Paladin. Casting Time: Bonus Action, which you take immedi- ately after hitting a target with a Melee weapon or an Unarmed Strike. Range: Self Component: V. Components: . Duration: Instantaneous.\nThe target takes an extra 2d8 Radiant damage from the attack. The damage increases by 1d8 if the target is a Fiend or an Undead.\nUsing a Higher-Level Spell Slot. The damage increases by 1d8 for each spell slot level above 1.","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Divine Smite","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Divine Word","constant":false,"content":"## Divine Word (신성한 언령) - Level 7 Evocation spell, SRD 5.2.1\nClasses: Cleric. Casting Time: Bonus Action. Range: 30 feet. Components: V. Duration: Instantaneous.\nYou utter a word imbued with power from the Upper Planes. Each creature of your choice in range makes a Charisma saving throw. On a failed save, a target that has 50 Hit Points or fewer suffers an effect based on its current Hit Points, as shown in the Divine Word Effects table. Regardless of its Hit Points, a Celestial, an Elemental, a Fey, or a Fiend target that fails its save is forced back to its plane of origin (if it isn't there already) and can't return to the current plane for 24 hours by any means short of a Wish spell.\nDivine Word Effects Hit Points Effect 0-20 The target dies. 21-30 The target has the Blinded, Deafened, and Stunned conditions for 1 hour. 31-40 The target has the Blinded and Deafened conditions for 10 minutes. 41-50 The target has the Deafened condition for 1 minute.","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Divine Word","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Dominate Beast","constant":false,"content":"## Dominate Beast (야수 지배) - Level 4 Enchantment spell, SRD 5.2.1\nClasses: Druid, Ranger, Sorcerer. Casting Time: Action. Range: 60 feet. Components: V, S. Duration: Concentration, up to 1 minute.\nOne Beast you can see within range must succeed on a Wisdom saving throw or have the Charmed condition for the duration. The target has Advantage on the save if you or your allies are fighting it.\nWhenever the target takes damage, it repeats the save, ending the spell on itself on a success.\nYou have a telepathic link with the Charmed target while the two of you are on the same plane of existence. On your turn, you can use this link to issue commands to the target (no action required), such as “Attack that creature,” “Move over there,” or “Fetch that object.” The target does its best to obey on its turn. If it completes an order and doesn't receive further direction from you, it acts and moves as it likes, focusing on protecting itself.\nYou can command the target to take a Reaction but must take your own Reaction to do so.\nUsing a Higher-Level Spell Slot. Your Concentration can last longer with a spell slot of level 5 (up to 10 minutes), 6 (up to 1 hour), or 7+ (up to 8 hours).","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Dominate Beast","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Dominate Monster","constant":false,"content":"## Dominate Monster (괴물 지배) - Level 8 Enchantment spell, SRD 5.2.1\nClasses: Bard, Sorcerer, Warlock, Wizard. Casting Time: Action. Range: 60 feet. Components: V, S. Duration: Concentration, up to 1 hour.\nOne creature you can see within range must succeed on a Wisdom saving throw or have the Charmed condition for the duration. The target has Advantage on the save if you or your allies are fighting it. Whenever the target takes damage, it repeats the save, ending the spell on itself on a success. 126 You have a telepathic link with the Charmed target while the two of you are on the same plane of existence. On your turn, you can use this link to issue commands to the target (no action required), such as “Attack that creature,” “Move over there,” or “Fetch that object.” The target does its best to obey on its turn. If it completes an order and doesn't receive further direction from you, it acts and moves as it likes, focusing on protecting itself.\nYou can command the target to take a Reaction but must take your own Reaction to do so.\nUsing a Higher-Level Spell Slot. Your Concentration can last longer with a level 9 spell slot (up to 8 hours).","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Dominate Monster","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Dominate Person","constant":false,"content":"## Dominate Person (인간형 지배) - Level 5 Enchantment spell, SRD 5.2.1\nClasses: Bard, Sorcerer, Wizard. Casting Time: Action. Range: 60 feet. Components: V, S. Duration: Concentration, up to 1 minute.\nOne Humanoid you can see within range must succeed on a Wisdom saving throw or have the Charmed condition for the duration. The target has Advantage on the save if you or your allies are fighting it. Whenever the target takes damage, it repeats the save, ending the spell on itself on a success.\nYou have a telepathic link with the Charmed target while the two of you are on the same plane of existence. On your turn, you can use this link to issue commands to the target (no action required), such as “Attack that creature,” “Move over there,” or “Fetch that object.” The target does its best to obey on its turn. If it completes an order and doesn't receive further direction from you, it acts and moves as it likes, focusing on protecting itself.\nYou can command the target to take a Reaction but must take your own Reaction to do so.\nUsing a Higher-Level Spell Slot. Your Concentration can last longer with a spell slot of level 6 (up to 10 minutes), 7 (up to 1 hour), or 8+ (up to 8 hours).","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Dominate Person","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Dragon's Breath","constant":false,"content":"## Dragon's Breath (용의 숨결) - Level 2 Transmutation spell, SRD 5.2.1\nClasses: Sorcerer, Wizard. Casting Time: Bonus Action. Range: Touch. Components: V, S, M (a hot pepper). Duration: Concentration, up to 1 minute.\nYou touch one willing creature, and choose Acid, Cold, Fire, Lightning, or Poison. Until the spell ends, the target can take a Magic action to exhale a 15-foot Cone. Each creature in that area makes a Dexterity saving throw, taking 3d6 damage of the chosen type on a failed save or half as much damage on a successful one.\nUsing a Higher-Level Spell Slot. The damage increases by 1d6 for each spell slot level above 2.","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Dragon's Breath","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Dream","constant":false,"content":"## Dream (꿈) - Level 5 Illusion spell, SRD 5.2.1\nClasses: Bard, Warlock, Wizard. Casting Time: 1 minute. Range: Special. Components: V, S, M (a handful of sand). Duration: 8 hours.\nYou target a creature you know on the same plane of existence. You or a willing creature you touch enters a trance state to act as a dream messenger.\nWhile in the trance, the messenger is Incapacitated and has a Speed of 0.\nIf the target is asleep, the messenger appears in the target's dreams and can converse with the target as long as it remains asleep, through the spell's duration. The messenger can also shape the dream's environment, creating landscapes, objects, and other images. The messenger can emerge from the trance at any time, ending the spell. The target recalls the dream perfectly upon waking.\nIf the target is awake when you cast the spell, the messenger knows it and can either end the trance (and the spell) or wait for the target to sleep, at which point the messenger enters its dreams.\nYou can make the messenger terrifying to the target. If you do so, the messenger can deliver a message of no more than ten words, and then the target makes a Wisdom saving throw. On a failed save, the target gains no benefit from its rest, and it takes 3d6 Psychic damage when it wakes up.","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Dream","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Druidcraft","constant":false,"content":"## Druidcraft (드루이드 술법) - Cantrip Transmutation spell, SRD 5.2.1\nClasses: Druid. Casting Time: Action. Range: 30 feet. Components: V, S. Duration: Instantaneous.\nWhispering to the spirits of nature, you create one of the following effects within range.\nWeather Sensor. You create a Tiny, harmless sensory effect that predicts what the weather will be at your location for the next 24 hours. The effect might manifest as a golden orb for clear skies, a cloud for rain, falling snowflakes for snow, and so on. This effect persists for 1 round.\nBloom. You instantly make a flower blossom, a seed pod open, or a leaf bud bloom.\nSensory Effect. You create a harmless sensory effect, such as falling leaves, spectral dancing fairies, a gentle breeze, the sound of an animal, or the faint odor of skunk. The effect must fit in a 5-foot Cube.\nFire Play. You light or snuff out a candle, a torch, or a campfire. 127","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Druidcraft","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Earthquake","constant":false,"content":"## Earthquake (지진) - Level 8 Transmutation spell, SRD 5.2.1\nClasses: Cleric, Druid, Sorcerer. Casting Time: Action. Range: 500 feet. Components: V, S, M (a fractured rock). Duration: Concentration, up to 1 minute.\nChoose a point on the ground that you can see within range. For the duration, an intense tremor rips through the ground in a 100-foot-radius circle centered on that point. The ground there is Difficult Terrain.\nWhen you cast this spell and at the end of each of your turns for the duration, each creature on the ground in the area makes a Dexterity saving throw.\nOn a failed save, a creature has the Prone condition, and its Concentration is broken.\nYou can also cause the effects below.\nFissures. A total of 1d6 fissures open in the spell's area at the end of the turn you cast it. You choose the fissures' locations, which can't be under structures. Each fissure is 1d10 × 10 feet deep and 10 feet wide, and it extends from one edge of the spell's area to another edge. A creature in the same space as a fissure must succeed on a Dexterity saving throw or fall in. A creature that successfully saves moves with the fissure's edge as it opens.\nStructures. The tremor deals 50 Bludgeoning damage to any structure in contact with the ground in the area when you cast the spell and at the end of each of your turns until the spell ends. If a structure drops to 0 Hit Points, it collapses.\nA creature within a distance from a collapsing structure equal to half the structure's height makes a Dexterity saving throw. On a failed save, the creature takes 12d6 Bludgeoning damage, has the Prone condition, and is buried in the rubble, requiring a DC 20 Strength (Athletics) check as an action to escape. On a successful save, the creature takes half as much damage only.","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Earthquake","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Eldritch Blast","constant":false,"content":"## Eldritch Blast (섬뜩한 마탄) - Cantrip Evocation spell, SRD 5.2.1\nClasses: Warlock. Casting Time: Action. Range: 120 feet. Components: V, S. Duration: Instantaneous.\nYou hurl a beam of crackling energy. Make a ranged spell attack against one creature or object in range.\nOn a hit, the target takes 1d10 Force damage.\nCantrip Upgrade. The spell creates two beams at level 5, three beams at level 11, and four beams at level 17. You can direct the beams at the same target or at different ones. Make a separate attack roll for each beam.","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Eldritch Blast","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Elementalism","constant":false,"content":"## Elementalism (원소술) - Cantrip Transmutation spell, SRD 5.2.1\nClasses: Druid, Sorcerer, Wizard. Casting Time: Action. Range: 30 feet. Components: V, S. Duration: Instantaneous.\nYou exert control over the elements, creating one of the following effects within range.\nBeckon Air. You create a breeze strong enough to ripple cloth, stir dust, rustle leaves, and close open doors and shutters, all in a 5-foot Cube. Doors and shutters being held open by someone or something aren't affected.\nBeckon Earth. You create a thin shroud of dust or sand that covers surfaces in a 5-foot-square area, or you cause a single word to appear in your handwriting in a patch of dirt or sand.\nBeckon Fire. You create a thin cloud of harmless embers and colored, scented smoke in a 5-foot Cube.\nYou choose the color and scent, and the embers can light candles, torches, or lamps in that area. The smoke's scent lingers for 1 minute.\nBeckon Water. You create a spray of cool mist that lightly dampens creatures and objects in a 5-foot Cube. Alternatively, you create 1 cup of clean water either in an open container or on a surface, and the water evaporates in 1 minute.\nSculpt Element. You cause dirt, sand, fire, smoke, mist, or water that can fit in a 1-foot Cube to assume a crude shape (such as that of a creature) for 1 hour.","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Elementalism","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Enhance Ability","constant":false,"content":"## Enhance Ability (능력 강화) - Level 2 Transmutation spell, SRD 5.2.1\nClasses: Bard, Cleric, Druid, Ranger, Sorcerer, Wizard. Casting Time: Action. Range: Touch. Components: V, S, M (fur or a feather). Duration: Concentration, up to 1 hour.\nYou touch a creature and choose Strength, Dexterity, Intelligence, Wisdom, or Charisma. For the duration, the target has Advantage on ability checks using the chosen ability.\nUsing a Higher-Level Spell Slot. You can target one additional creature for each spell slot level above 2. You can choose a different ability for each target.","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Enhance Ability","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Enlarge/Reduce","constant":false,"content":"## Enlarge/Reduce (거대화/축소화) - Level 2 Transmutation spell, SRD 5.2.1\nClasses: Bard, Druid, Sorcerer, Wizard. Casting Time: Action. Range: 30 feet. Components: V, S, M (a pinch of powdered iron). Duration: Concentration, up to 1 minute.\nFor the duration, the spell enlarges or reduces a creature or an object you can see within range (see 128 the chosen effect below). A targeted object must be neither worn nor carried. If the target is an unwilling creature, it can make a Constitution saving throw. On a successful save, the spell has no effect.\nEverything that a targeted creature is wearing and carrying changes size with it. Any item it drops returns to normal size at once. A thrown weapon or piece of ammunition returns to normal size immediately after it hits or misses a target.\nEnlarge. The target's size increases by one category—from Medium to Large, for example. The target also has Advantage on Strength checks and Strength saving throws. The target's attacks with its enlarged weapons or Unarmed Strikes deal an extra 1d4 damage on a hit.\nReduce. The target's size decreases by one category—from Medium to Small, for example. The target also has Disadvantage on Strength checks and Strength saving throws. The target's attacks with its reduced weapons or Unarmed Strikes deal 1d4 less damage on a hit (this can't reduce the damage below 1).","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Enlarge/Reduce","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Ensnaring Strike","constant":false,"content":"## Ensnaring Strike (휘감는 일격) - Level 1 Conjuration spell, SRD 5.2.1\nClasses: Ranger. Casting Time: Bonus Action, which you take immedi- ately after hitting a creature with a weapon. Range: Self. Components: V. Duration: Concentration, up to 1 minute.\nAs you hit the target, grasping vines appear on it, and it makes a Strength saving throw. A Large or larger creature has Advantage on this save. On a failed save, the target has the Restrained condition until the spell ends. On a successful save, the vines shrivel away, and the spell ends.\nWhile Restrained, the target takes 1d6 Piercing damage at the start of each of its turns. The target or a creature within reach of it can take an action to make a Strength (Athletics) check against your spell save DC. On a success, the spell ends.\nUsing a Higher-Level Spell Slot. The damage increases by 1d6 for each spell slot level above 1.","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Ensnaring Strike","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Entangle","constant":false,"content":"## Entangle (휘감기) - Level 1 Conjuration spell, SRD 5.2.1\nClasses: Druid, Ranger. Casting Time: Action. Range: 90 feet. Components: V, S. Duration: Concentration, up to 1 minute.\nGrasping plants sprout from the ground in a 20-foot square within range. For the duration, these plants turn the ground in the area into Difficult Terrain.\nThey disappear when the spell ends.\nEach creature (other than you) in the area when you cast the spell must succeed on a Strength saving throw or have the Restrained condition until the spell ends. A Restrained creature can take an action to make a Strength (Athletics) check against your spell save DC. On a success, it frees itself from the grasping plants and is no longer Restrained by them.","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Entangle","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Enthrall","constant":false,"content":"## Enthrall (매료) - Level 2 Enchantment spell, SRD 5.2.1\nClasses: Bard, Warlock. Casting Time: Action. Range: 60 feet. Components: V, S. Duration: Concentration, up to 1 minute.\nYou weave a distracting string of words, causing creatures of your choice that you can see within range to make a Wisdom saving throw. Any creature you or your companions are fighting automatically succeeds on this save. On a failed save, a target has a -10 penalty to Wisdom (Perception) checks and Passive Perception until the spell ends.","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Enthrall","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Etherealness","constant":false,"content":"## Etherealness (에테르화) - Level 7 Conjuration spell, SRD 5.2.1\nClasses: Bard, Cleric, Sorcerer, Warlock, Wizard. Casting Time: Action. Range: Self. Components: V, S. Duration: Up to 8 hours.\nYou step into the border regions of the Ethereal Plane, where it overlaps with your current plane.\nYou remain in the Border Ethereal for the duration.\nDuring this time, you can move in any direction. If you move up or down, every foot of movement costs an extra foot. You can perceive the plane you left, which looks gray, and you can't see anything there more than 60 feet away.\nWhile on the Ethereal Plane, you can affect and be affected only by creatures, objects, and effects on that plane. Creatures that aren't on the Ethereal Plane can't perceive or interact with you unless a feature gives them the ability to do so.\nWhen the spell ends, you return to the plane you left in the spot that corresponds to your space in the Border Ethereal. If you appear in an occupied space, you are shunted to the nearest unoccupied space and take Force damage equal to twice the number of feet you are moved.\nThis spell ends instantly if you cast it while you are on the Ethereal Plane or a plane that doesn't border it, such as one of the Outer Planes.\nUsing a Higher-Level Spell Slot. You can target up to three willing creatures (including yourself) for each spell slot level above 7. The creatures must be within 10 feet of you when you cast the spell. 129","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Etherealness","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Expeditious Retreat","constant":false,"content":"## Expeditious Retreat (신속한 후퇴) - Level 1 Transmutation spell, SRD 5.2.1\nClasses: Sorcerer, Warlock, Wizard. Casting Time: Bonus Action. Range: Self. Components: V, S. Duration: Concentration, up to 10 minutes.\nYou take the Dash action, and until the spell ends, you can take that action again as a Bonus Action.","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Expeditious Retreat","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Eyebite","constant":false,"content":"## Eyebite (눈길 저주) - Level 6 Necromancy spell, SRD 5.2.1\nClasses: Bard, Sorcerer, Warlock, Wizard. Casting Time: Action. Range: Self. Components: V, S. Duration: Concentration, up to 1 minute.\nFor the duration, your eyes become an inky void.\nOne creature of your choice within 60 feet of you that you can see must succeed on a Wisdom saving throw or be affected by one of the following effects of your choice for the duration.\nOn each of your turns until the spell ends, you can take a Magic action to target another creature but can't target a creature again if it has succeeded on a save against this casting of the spell.\nAsleep. The target has the Unconscious condition.\nIt wakes up if it takes any damage or if another creature takes an action to shake it awake.\nPanicked. The target has the Frightened condition. On each of its turns, the Frightened target must take the Dash action and move away from you by the safest and shortest route available. If the target moves to a space at least 60 feet away from you where it can't see you, this effect ends.\nSickened. The target has the Poisoned condition.","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Eyebite","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Fabricate","constant":false,"content":"## Fabricate (제작) - Level 4 Transmutation spell, SRD 5.2.1\nClasses: Wizard. Casting Time: 10 minutes. Range: 120 feet. Components: V, S. Duration: Instantaneous.\nYou convert raw materials into products of the same material. For example, you can fabricate a wooden bridge from a clump of trees, a rope from a patch of hemp, or clothes from flax or wool.\nChoose raw materials that you can see within range. You can fabricate a Large or smaller object (contained within a 10-foot Cube or eight connected 5-foot Cubes) given a sufficient quantity of material. If you're working with metal, stone, or another mineral substance, however, the fabricated object can be no larger than Medium (contained within a 5-foot Cube). The quality of any fabricated objects is based on the quality of the raw materials.\nCreatures and magic items can't be created by this spell. You also can't use it to create items that require a high degree of skill—such as weapons and armor—unless you have proficiency with the type of Artisan's Tools used to craft such objects.","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Fabricate","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Faerie Fire","constant":false,"content":"## Faerie Fire (요정불) - Level 1 Evocation spell, SRD 5.2.1\nClasses: Bard, Druid. Casting Time: Action. Range: 60 feet. Components: V. Duration: Concentration, up to 1 minute.\nObjects in a 20-foot Cube within range are outlined in blue, green, or violet light (your choice). Each creature in the Cube is also outlined if it fails a Dexterity saving throw. For the duration, objects and affected creatures shed Dim Light in a 10-foot radius and can't benefit from the Invisible condition.\nAttack rolls against an affected creature or object have Advantage if the attacker can see it.","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Faerie Fire","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Faithful Hound","constant":false,"content":"## Faithful Hound (충직한 사냥개) - Level 4 Conjuration spell, SRD 5.2.1\nClasses: Wizard. Casting Time: Action. Range: 30 feet. Components: V, S, M (a silver whistle). Duration: 8 hours.\nYou conjure a phantom watchdog in an unoccupied space that you can see within range. The hound remains for the duration or until the two of you are more than 300 feet apart from each other.\nNo one but you can see the hound, and it is intangible and invulnerable. When a Small or larger creature comes within 30 feet of it without first speaking the password that you specify when you cast this spell, the hound starts barking loudly. The hound has Truesight with a range of 30 feet.\nAt the start of each of your turns, the hound attempts to bite one enemy within 5 feet of it. That enemy must succeed on a Dexterity saving throw or take 4d8 Force damage.\nOn your later turns, you can take a Magic action to move the hound up to 30 feet.","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Faithful Hound","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: False Life","constant":false,"content":"## False Life (거짓 삶) - Level 1 Necromancy spell, SRD 5.2.1\nClasses: Sorcerer, Wizard. Casting Time: Action. Range: Self. Components: V, S, M (a drop of alcohol). Duration: Instantaneous.\nYou gain 2d4 + 4 Temporary Hit Points.\nUsing a Higher-Level Spell Slot. You gain 5 additional Temporary Hit Points for each spell slot level above 1. 130","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: False Life","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Fear","constant":false,"content":"## Fear (공포) - Level 3 Illusion spell, SRD 5.2.1\nClasses: Bard, Sorcerer, Warlock, Wizard. Casting Time: Action. Range: Self. Components: V, S, M (a white feather). Duration: Concentration, up to 1 minute.\nEach creature in a 30-foot Cone must succeed on a Wisdom saving throw or drop whatever it is holding and have the Frightened condition for the duration.\nA Frightened creature takes the Dash action and moves away from you by the safest route on each of its turns unless there is nowhere to move. If the creature ends its turn in a space where it doesn't have line of sight to you, the creature makes a Wisdom saving throw. On a successful save, the spell ends on that creature.","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Fear","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Feather Fall","constant":false,"content":"## Feather Fall (깃털 낙하) - Level 1 Transmutation spell, SRD 5.2.1\nClasses: Bard, Sorcerer, Wizard. Casting Time: Reaction, which you take when you or a creature you can see within 60 feet of you falls. Range: 60 feet. Components: V, M (a small feather or piece of down). Duration: 1 minute.\nChoose up to five falling creatures within range. A falling creature's rate of descent slows to 60 feet per round until the spell ends. If a creature lands before the spell ends, the creature takes no damage from the fall, and the spell ends for that creature.","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Feather Fall","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Find Familiar","constant":false,"content":"## Find Familiar (패밀리어 찾기) - Level 1 Conjuration spell, SRD 5.2.1\nClasses: Wizard. Casting Time: 1 hour or Ritual. Range: 10 feet. Components: V, S, M (burning incense worth 10+ GP, which the spell consumes). Duration: Instantaneous.\nYou gain the service of a familiar, a spirit that takes an animal form you choose: Bat, Cat, Frog, Hawk, Lizard, Octopus, Owl, Rat, Raven, Spider, Weasel, or another Beast that has a Challenge Rating of 0.\nAppearing in an unoccupied space within range, the familiar has the statistics of the chosen form (see “Monsters”), though it is a Celestial, Fey, or Fiend (your choice) instead of a Beast. Your familiar acts independently of you, but it obeys your commands.\nTelepathic Connection. While your familiar is within 100 feet of you, you can communicate with it telepathically. Additionally, as a Bonus Action, you can see through the familiar's eyes and hear what it hears until the start of your next turn, gaining the benefits of any special senses it has.\nFinally, when you cast a spell with a range of touch, your familiar can deliver the touch. Your familiar must be within 100 feet of you, and it must take a Reaction to deliver the touch when you cast the spell.\nCombat. The familiar is an ally to you and your allies. It rolls its own Initiative and acts on its own turn. A familiar can't attack, but it can take other actions as normal.\nDisappearance of the Familiar. When the familiar drops to 0 Hit Points, it disappears. It reappears after you cast this spell again. As a Magic action, you can temporarily dismiss the familiar to a pocket dimension. Alternatively, you can dismiss it forever.\nAs a Magic action while it is temporarily dismissed, you can cause it to reappear in an unoccupied space within 30 feet of you. Whenever the familiar drops to 0 Hit Points or disappears into the pocket dimension, it leaves behind in its space anything it was wearing or carrying.\nOne Familiar Only. You can't have more than one familiar at a time. If you cast this spell while you have a familiar, you instead cause it to adopt a new eligible form.","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Find Familiar","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Find Steed","constant":false,"content":"## Find Steed (탈것 부르기) - Level 2 Conjuration spell, SRD 5.2.1\nClasses: Paladin. Casting Time: Action. Range: 30 feet Component: V, S. Components: . Duration: Instantaneous.\nYou summon an otherworldly being that appears as a loyal steed in an unoccupied space of your choice within range. This creature uses the Otherworldly Steed stat block. If you already have a steed from this spell, the steed is replaced by the new one.\nThe steed resembles a Large, rideable animal of your choice, such as a horse, a camel, a dire wolf, or an elk. Whenever you cast the spell, choose the steed's creature type—Celestial, Fey, or Fiend— which determines certain traits in the stat block.\nCombat. The steed is an ally to you and your allies. In combat, it shares your Initiative count, and it functions as a controlled mount while you ride it (as defined in the rules on mounted combat). If you have the Incapacitated condition, the steed takes its turn immediately after yours and acts independently, focusing on protecting you.\nDisappearance of the Steed. The steed disappears if it drops to 0 Hit Points or if you die. When it disappears, it leaves behind anything it was wearing or carrying. If you cast this spell again, you decide whether you summon the steed that disappeared or a different one.\nUsing a Higher-Level Spell Slot. Use the spell slot's level for the spell's level in the stat block. 131 face a choice of paths along the way there, you know which path is the most direct.","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Find Steed","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Find Traps","constant":false,"content":"## Find Traps (함정 탐지) - Level 2 Divination spell, SRD 5.2.1\nClasses: Cleric, Druid, Ranger. Casting Time: Action. Range: 120 feet. Components: V, S. Duration: Instantaneous.\nYou sense any trap within range that is within line of sight. A trap, for the purpose of this spell, includes any object or mechanism that was created to cause damage or other danger. Thus, the spell would sense the Alarm or Glyph of Warding spell or a mechanical pit trap, but it wouldn't reveal a natural weakness in the floor, an unstable ceiling, or a hidden sinkhole.\nThis spell reveals that a trap is present but not its location. You do learn the general nature of the danger posed by a trap you sense.","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Find Traps","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Finger of Death","constant":false,"content":"## Finger of Death (죽음의 손가락) - Level 7 Necromancy spell, SRD 5.2.1\nClasses: Sorcerer, Warlock, Wizard. Casting Time: Action. Range: 60 feet. Components: V, S. Duration: Instantaneous.\nYou unleash negative energy toward a creature you can see within range. The target makes a Constitution saving throw, taking 7d8 + 30 Necrotic damage on a failed save or half as much damage on a successful one.\nA Humanoid killed by this spell rises at the start of your next turn as a Zombie (see “Monsters”) that follows your verbal orders.","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Finger of Death","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Fireball","constant":false,"content":"## Fireball (화염구) - Level 3 Evocation spell, SRD 5.2.1\nClasses: Sorcerer, Wizard. Casting Time: Action. Range: 150 feet. Components: V, S, M (a ball of bat guano and sulfur). Duration: Instantaneous.\nA bright streak flashes from you to a point you choose within range and then blossoms with a low roar into a fiery explosion. Each creature in a 20-foot-radius Sphere centered on that point makes a Dexterity saving throw, taking 8d6 Fire damage on a failed save or half as much damage on a successful one.\nFlammable objects in the area that aren't being worn or carried start burning.\nUsing a Higher-Level Spell Slot. The damage increases by 1d6 for each spell slot level above 3.","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Fireball","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Find the Path","constant":false,"content":"## Find the Path (길 찾기) - Level 6 Divination spell, SRD 5.2.1\nClasses: Bard, Cleric, Druid. Casting Time: 1 minute. Range: Self. Components: V, S, M (a set of divination tools—such as cards or runes—worth 100+ GP). Duration: Concentration, up to 1 day.\nYou magically sense the most direct physical route to a location you name. You must be familiar with the location, and the spell fails if you name a destination on another plane of existence, a moving destination (such as a mobile fortress), or an unspecific destination (such as “a green dragon's lair”).\nFor the duration, as long as you are on the same plane of existence as the destination, you know how far it is and in what direction it lies. Whenever you 132","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Find the Path","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Fire Bolt","constant":false,"content":"## Fire Bolt (화염 화살) - Cantrip Evocation spell, SRD 5.2.1\nClasses: Sorcerer, Wizard. Casting Time: Action. Range: 120 feet. Components: V, S. Duration: Instantaneous.\nYou hurl a mote of fire at a creature or an object within range. Make a ranged spell attack against the target. On a hit, the target takes 1d10 Fire damage.\nA flammable object hit by this spell starts burning if it isn't being worn or carried.\nCantrip Upgrade. The damage increases by 1d10 when you reach levels 5 (2d10), 11 (3d10), and 17 (4d10).","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Fire Bolt","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Fire Shield","constant":false,"content":"## Fire Shield (화염 방패) - Level 4 Evocation spell, SRD 5.2.1\nClasses: Druid, Sorcerer, Wizard. Casting Time: Action. Range: Self. Components: V, S, M (a bit of phosphorus or a firefly). Duration: 10 minutes.\nWispy flames wreathe your body for the duration, shedding Bright Light in a 10-foot radius and Dim Light for an additional 10 feet.\nThe flames provide you with a warm shield or a chill shield, as you choose. The warm shield grants you Resistance to Cold damage, and the chill shield grants you Resistance to Fire damage.\nIn addition, whenever a creature within 5 feet of you hits you with a melee attack roll, the shield erupts with flame. The attacker takes 2d8 Fire damage from a warm shield or 2d8 Cold damage from a chill shield.","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Fire Shield","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Fire Storm","constant":false,"content":"## Fire Storm (화염 폭풍) - Level 7 Evocation spell, SRD 5.2.1\nClasses: Cleric, Druid, Sorcerer. Casting Time: Action. Range: 150 feet. Components: V, S. Duration: Instantaneous.\nA storm of fire appears within range. The area of the storm consists of up to ten 10-foot Cubes, which you arrange as you like. Each Cube must be contiguous with at least one other Cube. Each creature in the area makes a Dexterity saving throw, taking 7d10 Fire damage on a failed save or half as much damage on a successful one.\nFlammable objects in the area that aren't being worn or carried start burning.","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Fire Storm","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Flame Blade","constant":false,"content":"## Flame Blade (화염 검) - Level 2 Evocation spell, SRD 5.2.1\nClasses: Druid, Sorcerer. Casting Time: Bonus Action. Range: Self. Components: V, S, M (a sumac leaf). Duration: Concentration, up to 10 minutes.\nYou evoke a fiery blade in your free hand. The blade is similar in size and shape to a scimitar, and it lasts for the duration. If you let go of the blade, it disappears, but you can evoke it again as a Bonus Action.\nAs a Magic action, you can make a melee spell attack with the fiery blade. On a hit, the target takes Fire damage equal to 3d6 plus your spellcasting ability modifier.\nThe flaming blade sheds Bright Light in a 10-foot radius and Dim Light for an additional 10 feet.\nUsing a Higher-Level Spell Slot. The damage increases by 1d6 for each spell slot level above 2.","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Flame Blade","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Flame Strike","constant":false,"content":"## Flame Strike (화염 강타) - Level 5 Evocation spell, SRD 5.2.1\nClasses: Cleric. Casting Time: Action. Range: 60 feet. Components: V, S, M (a pinch of sulfur). Duration: Instantaneous.\nA vertical column of brilliant fire roars down from above. Each creature in a 10-foot-radius, 40-foothigh Cylinder centered on a point within range makes a Dexterity saving throw, taking 5d6 Fire damage and 5d6 Radiant damage on a failed save or half as much damage on a successful one.\nUsing a Higher-Level Spell Slot. The Fire damage and the Radiant damage increase by 1d6 for each spell slot level above 5.","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Flame Strike","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Flaming Sphere","constant":false,"content":"## Flaming Sphere (화염 구체) - Level 2 Conjuration spell, SRD 5.2.1\nClasses: Druid, Sorcerer, Wizard. Casting Time: Action. Range: 60 feet. Components: V, S, M (a ball of wax). Duration: Concentration, up to 1 minute.\nYou create a 5-foot-diameter sphere of fire in an unoccupied space on the ground within range. It lasts for the duration. Any creature that ends its turn within 5 feet of the sphere makes a Dexterity saving throw, taking 2d6 Fire damage on a failed save or half as much damage on a successful one.\nAs a Bonus Action, you can move the sphere up to 30 feet, rolling it along the ground. If you move the sphere into a creature's space, that creature makes the save against the sphere, and the sphere stops moving for the turn.\nWhen you move the sphere, you can direct it over barriers up to 5 feet tall and jump it across pits up to 10 feet wide. Flammable objects that aren't being worn or carried start burning if touched by the sphere, and it sheds Bright Light in a 20-foot radius and Dim Light for an additional 20 feet.\nUsing a Higher-Level Spell Slot. The damage increases by 1d6 for each spell slot level above 2. 133","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Flaming Sphere","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Flesh to Stone","constant":false,"content":"## Flesh to Stone (석화) - Level 6 Transmutation spell, SRD 5.2.1\nClasses: Druid, Sorcerer, Wizard. Casting Time: Action. Range: 60 feet. Components: V, S, M (a cockatrice feather). Duration: Concentration, up to 1 minute.\nYou attempt to turn one creature that you can see within range into stone. The target makes a Constitution saving throw. On a failed save, it has the Restrained condition for the duration. On a successful save, its Speed is 0 until the start of your next turn.\nConstructs automatically succeed on the save.\nA Restrained target makes another Constitution saving throw at the end of each of its turns. If it successfully saves against this spell three times, the spell ends. If it fails its saves three times, it is turned to stone and has the Petrified condition for the duration. The successes and failures needn't be consecutive; keep track of both until the target collects three of a kind.\nIf you maintain your Concentration on this spell for the entire possible duration, the target is Petrified until the condition is ended by Greater Restoration or similar magic.","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Flesh to Stone","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Floating Disk","constant":false,"content":"## Floating Disk (부유 원반) - Level 1 Conjuration spell, SRD 5.2.1\nClasses: Wizard. Casting Time: Action or Ritual. Range: 30 feet. Components: V, S, M (a drop of mercury). Duration: 1 hour.\nThis spell creates a circular, horizontal plane of force, 3 feet in diameter and 1 inch thick, that floats 3 feet above the ground in an unoccupied space of your choice that you can see within range. The disk remains for the duration and can hold up to 500 pounds. If more weight is placed on it, the spell ends, and everything on the disk falls to the ground.\nThe disk is immobile while you are within 20 feet of it. If you move more than 20 feet away from it, the disk follows you so that it remains within 20 feet of you. It can move across uneven terrain, up or down stairs, slopes and the like, but it can't cross an elevation change of 10 feet or more. For example, the disk can't move across a 10-foot-deep pit, nor could it leave such a pit if it was created at the bottom.\nIf you move more than 100 feet from the disk (typically because it can't move around an obstacle to follow you), the spell ends.","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Floating Disk","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Fly","constant":false,"content":"## Fly (비행) - Level 3 Transmutation spell, SRD 5.2.1\nClasses: Sorcerer, Warlock, Wizard. Casting Time: Action. Range: Touch. Components: V, S, M (a feather). Duration: Concentration, up to 10 minutes.\nYou touch a willing creature. For the duration, the target gains a Fly Speed of 60 feet and can hover.\nWhen the spell ends, the target falls if it is still aloft unless it can stop the fall.\nUsing a Higher-Level Spell Slot. You can target one additional creature for each spell slot level above 3.","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Fly","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Fog Cloud","constant":false,"content":"## Fog Cloud (안개 구름) - Level 1 Conjuration spell, SRD 5.2.1\nClasses: Druid, Ranger, Sorcerer, Wizard. Casting Time: Action. Range: 120 feet. Components: V, S. Duration: Concentration, up to 1 hour.\nYou create a 20-foot-radius Sphere of fog centered on a point within range. The Sphere is Heavily Obscured. It lasts for the duration or until a strong wind (such as one created by Gust of Wind) disperses it.\nUsing a Higher-Level Spell Slot. The fog's radius increases by 20 feet for each spell slot level above 1.","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Fog Cloud","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Forbiddance","constant":false,"content":"## Forbiddance (금단) - Level 6 Abjuration spell, SRD 5.2.1\nClasses: Cleric. Casting Time: 10 minutes or Ritual. Range: Touch. Components: V, S, M (ruby dust worth 1,000+ GP). Duration: 1 day.\nYou create a ward against magical travel that protects up to 40,000 square feet of floor space to a height of 30 feet above the floor. For the duration, creatures can't teleport into the area or use portals, such as those created by the Gate spell, to enter the area. The spell proofs the area against planar travel, and therefore prevents creatures from accessing the area by way of the Astral Plane, the Ethereal Plane, the Feywild, the Shadowfell, or the Plane Shift spell.\nIn addition, the spell damages types of creatures that you choose when you cast it. Choose one or more of the following: Aberrations, Celestials, Elementals, Fey, Fiends, and Undead. When a creature of a chosen type enters the spell's area for the first time on a turn or ends its turn there, the creature takes 5d10 Radiant or Necrotic damage (your choice when you cast this spell).\nYou can designate a password when you cast the spell. A creature that speaks the password as it enters the area takes no damage from the spell.\nThe spell's area can't overlap with the area of another Forbiddance spell. If you cast Forbiddance every day for 30 days in the same location, the spell lasts until it is dispelled, and the Material components are consumed on the last casting. 134","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Forbiddance","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Forcecage","constant":false,"content":"## Forcecage (역장 감옥) - Level 7 Evocation spell, SRD 5.2.1\nClasses: Bard, Warlock, Wizard. Casting Time: Action. Range: 100 feet. Components: V, S, M (ruby dust worth 1,500+ GP, which the spell consumes). Duration: Concentration, up to 1 hour.\nAn immobile, Invisible, Cube-shaped prison composed of magical force springs into existence around an area you choose within range. The prison can be a cage or a solid box, as you choose.\nA prison in the shape of a cage can be up to 20 feet on a side and is made from 1/2-inch diameter bars spaced 1/2 inch apart. A prison in the shape of a box can be up to 10 feet on a side, creating a solid barrier that prevents any matter from passing through it and blocking any spells cast into or out from the area.\nWhen you cast the spell, any creature that is completely inside the cage's area is trapped. Creatures only partially within the area, or those too large to fit inside it, are pushed away from the center of the area until they are completely outside it.\nA creature inside the cage can't leave it by nonmagical means. If the creature tries to use teleportation or interplanar travel to leave, it must first make a Charisma saving throw. On a successful save, the creature can use that magic to exit the cage. On a failed save, the creature doesn't exit the cage and wastes the spell or effect. The cage also extends into the Ethereal Plane, blocking ethereal travel.\nThis spell can't be dispelled by Dispel Magic.","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Forcecage","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Foresight","constant":false,"content":"## Foresight (예지) - Level 9 Divination spell, SRD 5.2.1\nClasses: Bard, Druid, Warlock, Wizard. Casting Time: 1 minute. Range: Touch. Components: V, S, M (a hummingbird feather). Duration: 8 hours.\nYou touch a willing creature and bestow a limited ability to see into the immediate future. For the duration, the target has Advantage on D20 Tests, and other creatures have Disadvantage on attack rolls against it. The spell ends early if you cast it again.","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Foresight","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Freedom of Movement","constant":false,"content":"## Freedom of Movement (이동의 자유) - Level 4 Abjuration spell, SRD 5.2.1\nClasses: Bard, Cleric, Druid, Ranger. Casting Time: Action. Range: Touch. Components: V, S, M (a leather strap). Duration: 1 hour.\nYou touch a willing creature. For the duration, the target's movement is unaffected by Difficult Terrain, and spells and other magical effects can neither reduce the target's Speed nor cause the target to have the Paralyzed or Restrained conditions.\nThe target also has a Swim Speed equal to its Speed.\nIn addition, the target can spend 5 feet of movement to automatically escape from nonmagical restraints, such as manacles or a creature imposing the Grappled condition on it.\nUsing a Higher-Level Spell Slot. You can target one additional creature for each spell slot level above 4.","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Freedom of Movement","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Freezing Sphere","constant":false,"content":"## Freezing Sphere (빙결 구체) - Level 6 Evocation spell, SRD 5.2.1\nClasses: Sorcerer, Wizard. Casting Time: Action. Range: 300 feet. Components: V, S, M (a miniature crystal sphere). Duration: Instantaneous.\nA frigid globe streaks from you to a point of your choice within range, where it explodes in a 60-foot-radius Sphere. Each creature in that area makes a Constitution saving throw, taking 10d6 Cold damage on failed save or half as much damage on a successful one.\nIf the globe strikes a body of water, it freezes the water to a depth of 6 inches over an area 30 feet square. This ice lasts for 1 minute. Creatures that were swimming on the surface of frozen water are trapped in the ice and have the Restrained condition. A trapped creature can take an action to make a Strength (Athletics) check against your spell save DC to break free.\nYou can refrain from firing the globe after completing the spell's casting. If you do so, a globe about the size of a sling bullet, cool to the touch, appears in your hand. At any time, you or a creature you give the globe to can throw the globe (to a range of 40 feet) or hurl it with a sling (to the sling's normal range). It shatters on impact, with the same effect as a normal casting of the spell. You can also set the globe down without shattering it. After 1 minute, if the globe hasn't already shattered, it explodes.\nUsing a Higher-Level Spell Slot. The damage increases by 1d6 for each spell slot level above 6.","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Freezing Sphere","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Gaseous Form","constant":false,"content":"## Gaseous Form (가스 형상) - Level 3 Transmutation spell, SRD 5.2.1\nClasses: Sorcerer, Warlock, Wizard. Casting Time: Action. Range: Touch. Components: V, S, M (a bit of gauze). Duration: Concentration, up to 1 hour.\nA willing creature you touch shape-shifts, along with everything it's wearing and carrying, into a misty cloud for the duration. The spell ends on the target if it drops to 0 Hit Points or if it takes a Magic action to end the spell on itself. 135 While in this form, the target's only method of movement is a Fly Speed of 10 feet, and it can hover. The target can enter and occupy the space of another creature. The target has Resistance to Bludgeoning, Piercing, and Slashing damage; it has Immunity to the Prone condition; and it has Advantage on Strength, Dexterity, and Constitution saving throws. The target can pass through narrow openings, but it treats liquids as though they were solid surfaces.\nThe target can't talk or manipulate objects, and any objects it was carrying or holding can't be dropped, used, or otherwise interacted with. Finally, the target can't attack or cast spells.\nUsing a Higher-Level Spell Slot. You can target one additional creature for each spell slot level above 3.","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Gaseous Form","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Gate","constant":false,"content":"## Gate (관문) - Level 9 Conjuration spell, SRD 5.2.1\nClasses: Cleric, Sorcerer, Warlock, Wizard. Casting Time: Action. Range: 60 feet. Components: V, S, M (a diamond worth 5,000+ GP). Duration: Concentration, up to 1 minute.\nYou conjure a portal linking an unoccupied space you can see within range to a precise location on a different plane of existence. The portal is a circular opening, which you can make 5 to 20 feet in diameter. You can orient the portal in any direction you choose. The portal lasts for the duration, and the portal's destination is visible through it.\nThe portal has a front and a back on each plane where it appears. Travel through the portal is possible only by moving through its front. Anything that does so is instantly transported to the other plane, appearing in the unoccupied space nearest to the portal.\nDeities and other planar rulers can prevent portals created by this spell from opening in their presence or anywhere within their domains.\nWhen you cast this spell, you can speak the name of a specific creature (a pseudonym, title, or nickname doesn't work). If that creature is on a plane other than the one you are on, the portal opens next to the named creature and transports it to the nearest unoccupied space on your side of the portal.\nYou gain no special power over the creature, and it is free to act as the GM deems appropriate. It might leave, attack you, or help you.","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Gate","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Geas","constant":false,"content":"## Geas (강제 임무) - Level 5 Enchantment spell, SRD 5.2.1\nClasses: Bard, Cleric, Druid, Paladin, Wizard. Casting Time: 1 minute. Range: 60 feet. Components: V. Duration: 30 days.\nYou give a verbal command to a creature that you can see within range, ordering it to carry out some service or refrain from an action or a course of activity as you decide. The target must succeed on a Wisdom saving throw or have the Charmed condition for the duration. The target automatically succeeds if it can't understand your command.\nWhile Charmed, the creature takes 5d10 Psychic damage if it acts in a manner directly counter to your command. It takes this damage no more than once each day.\nYou can issue any command you choose, short of an activity that would result in certain death.\nShould you issue a suicidal command, the spell ends.\nA Remove Curse, Greater Restoration, or Wish spell ends this spell.\nUsing a Higher-Level Spell Slot. If you use a level 7 or 8 spell slot, the duration is 365 days. If you use a level 9 spell slot, the spell lasts until it is ended by one of the spells mentioned above.","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Geas","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Gentle Repose","constant":false,"content":"## Gentle Repose (안온한 처리) - Level 2 Necromancy spell, SRD 5.2.1\nClasses: Cleric, Paladin, Wizard. Casting Time: Action or Ritual. Range: Touch. Components: V, S, M (2 Copper Pieces, which the spell consumes). Duration: 10 days.\nYou touch a corpse or other remains. For the duration, the target is protected from decay and can't become Undead.\nThe spell also effectively extends the time limit on raising the target from the dead, since days spent under the influence of this spell don't count against the time limit of spells such as Raise Dead.","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Gentle Repose","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Giant Insect","constant":false,"content":"## Giant Insect (거대 곤충) - Level 4 Conjuration spell, SRD 5.2.1\nClasses: Druid. Casting Time: Action. Range: 60 feet. Components: V, S. Duration: Concentration, up to 10 minutes.\nYou summon a giant centipede, spider, or wasp (chosen when you cast the spell). It manifests in an unoccupied space you can see within range and uses the Giant Insect stat block. The form you choose determines certain details in its stat block. The creature disappears when it drops to 0 Hit Points or when the spell ends.\nThe creature is an ally to you and your allies. In combat, the creature shares your Initiative count, but it takes its turn immediately after yours. It obeys your verbal commands (no action required by you). If you don't issue any, it takes the Dodge action and uses its movement to avoid danger. 136 Using a Higher-Level Spell Slot. Use the spell slot's level for the spell's level in the stat block.","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Giant Insect","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Glibness","constant":false,"content":"## Glibness (달변) - Level 8 Enchantment spell, SRD 5.2.1\nClasses: Bard, Warlock. Casting Time: Action. Range: Self. Components: V. Duration: 1 hour.\nUntil the spell ends, when you make a Charisma check, you can replace the number you roll with a 15. Additionally, no matter what you say, magic that would determine if you are telling the truth indicates that you are being truthful.","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Glibness","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Globe of Invulnerability","constant":false,"content":"## Globe of Invulnerability (무적의 구체) - Level 6 Abjuration spell, SRD 5.2.1\nClasses: Sorcerer, Wizard. Casting Time: Action. Range: Self. Components: V, S, M (a glass bead). Duration: Concentration, up to 1 minute.\nAn immobile, shimmering barrier appears in a 10foot Emanation around you and remains for the duration.\nAny spell of level 5 or lower cast from outside the barrier can't affect anything within it. Such a spell can target creatures and objects within the barrier, but the spell has no effect on them. Similarly, the area within the barrier is excluded from areas of effect created by such spells.\nUsing a Higher-Level Spell Slot. The barrier blocks spells of 1 level higher for each spell slot level above 6.","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Globe of Invulnerability","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Glyph of Warding","constant":false,"content":"## Glyph of Warding (보호의 문양) - Level 3 Abjuration spell, SRD 5.2.1\nClasses: Bard, Cleric, Wizard. Casting Time: 1 hour. Range: Touch. Components: V, S, M (powdered diamond worth 200+ GP, which the spell consumes). Duration: Until dispelled or triggered.\nYou inscribe a glyph that later unleashes a magical effect. You inscribe it either on a surface (such as a table or a section of floor) or within an object that can be closed (such as a book or chest) to conceal the glyph. The glyph can cover an area no larger than 10 feet in diameter. If the surface or object is moved more than 10 feet from where you cast this spell, the glyph is broken, and the spell ends without being triggered.\nThe glyph is nearly imperceptible and requires a successful Wisdom (Perception) check against your spell save DC to notice.\nWhen you inscribe the glyph, you set its trigger and choose whether it's an explosive rune or a spell glyph, as explained below.\nSet the Trigger. You decide what triggers the glyph when you cast the spell. For glyphs inscribed on a surface, common triggers include touching or stepping on the glyph, removing another object covering it, or approaching within a certain distance of it. For glyphs inscribed within an object, common triggers include opening that object or seeing the glyph. Once a glyph is triggered, this spell ends.\nYou can refine the trigger so that only creatures of certain types activate it (for example, the glyph could be set to affect Aberrations). You can also set conditions for creatures that don't trigger the glyph, such as those who say a certain password.\nExplosive Rune. When triggered, the glyph erupts with magical energy in a 20-foot-radius Sphere centered on the glyph. Each creature in the area makes a Dexterity saving throw. A creature takes 5d8 Acid, Cold, Fire, Lightning, or Thunder damage (your 137 choice when you create the glyph) on a failed save or half as much damage on a successful one.\nSpell Glyph. You can store a prepared spell of level 3 or lower in the glyph by casting it as part of creating the glyph. The spell must target a single creature or an area. The spell being stored has no immediate effect when cast in this way.\nWhen the glyph is triggered, the stored spell takes effect. If the spell has a target, it targets the creature that triggered the glyph. If the spell affects an area, the area is centered on that creature. If the spell summons Hostile creatures or creates harmful objects or traps, they appear as close as possible to the intruder and attack it. If the spell requires Concentration, it lasts until the end of its full duration.\nUsing a Higher-Level Spell Slot. The damage of an explosive rune increases by 1d8 for each spell slot level above 3. If you create a spell glyph, you can store any spell of up to the same level as the spell slot you use for the Glyph of Warding.","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Glyph of Warding","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Goodberry","constant":false,"content":"## Goodberry (좋은 열매) - Level 1 Conjuration spell, SRD 5.2.1\nClasses: Druid, Ranger. Casting Time: Action. Range: Self. Components: V, S, M (a sprig of mistletoe). Duration: 24 hours.\nTen berries appear in your hand and are infused with magic for the duration. A creature can take a Bonus Action to eat one berry. Eating a berry restores 1 Hit Point, and the berry provides enough nourishment to sustain a creature for one day.\nUneaten berries disappear when the spell ends.","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Goodberry","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Grease","constant":false,"content":"## Grease (기름칠) - Level 1 Conjuration spell, SRD 5.2.1\nClasses: Sorcerer, Wizard. Casting Time: Action. Range: 60 feet. Components: V, S, M (a bit of pork rind or butter). Duration: 1 minute.\nNonflammable grease covers the ground in a 10foot square centered on a point within range and turns it into Difficult Terrain for the duration.\nWhen the grease appears, each creature standing in its area must succeed on a Dexterity saving throw or have the Prone condition. A creature that enters the area or ends its turn there must also succeed on that save or fall Prone.","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Grease","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Greater Invisibility","constant":false,"content":"## Greater Invisibility (상급 투명화) - Level 4 Illusion spell, SRD 5.2.1\nClasses: Bard, Sorcerer, Wizard. Casting Time: Action. Range: Touch. Components: V, S. Duration: Concentration, up to 1 minute.\nA creature you touch has the Invisible condition until the spell ends.","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Greater Invisibility","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Greater Restoration","constant":false,"content":"## Greater Restoration (상급 회복) - Level 5 Abjuration spell, SRD 5.2.1\nClasses: Bard, Cleric, Druid, Paladin, Ranger. Casting Time: Action. Range: Touch. Components: V, S, M (diamond dust worth 100+ GP, which the spell consumes). Duration: Instantaneous.\nYou touch a creature and magically remove one of the following effects from it: • 1 Exhaustion level • The Charmed or Petrified condition • A curse, including the target's Attunement to a cursed magic item • Any reduction to one of the target's ability scores • Any reduction to the target's Hit Point maximum","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Greater Restoration","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Guardian of Faith","constant":false,"content":"## Guardian of Faith (신앙의 수호자) - Level 4 Conjuration spell, SRD 5.2.1\nClasses: Cleric. Casting Time: Action. Range: 30 feet. Components: V. Duration: 8 hours.\nA Large spectral guardian appears and hovers for the duration in an unoccupied space that you can see within range. The guardian occupies that space and is invulnerable, and it appears in a form appropriate for your deity or pantheon.\nAny enemy that moves to a space within 10 feet of the guardian for the first time on a turn or starts its turn there makes a Dexterity saving throw, taking 20 Radiant damage on a failed save or half as much damage on a successful one. The guardian vanishes when it has dealt a total of 60 damage.","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Guardian of Faith","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Guards and Wards","constant":false,"content":"## Guards and Wards (경비와 결계) - Level 6 Abjuration spell, SRD 5.2.1\nClasses: Bard, Wizard. Casting Time: 1 hour. Range: Touch. Components: V, S, M (a silver rod worth 10+ GP). Duration: 24 hours.\nYou create a ward that protects up to 2,500 square feet of floor space. The warded area can be up to 20 feet tall, and you shape it as one 50-foot square, one hundred 5-foot squares that are contiguous, or twenty-five 10-foot squares that are contiguous.\nWhen you cast this spell, you can specify individuals that are unaffected by the spell's effects. You can also specify a password that, when spoken aloud within 5 feet of the warded area, makes the speaker immune to its effects. 138 The spell creates the effects below within the warded area. Dispel Magic has no effect on Guards and Wards itself, but each of the following effects can be dispelled. If all four are dispelled, Guards and Wards ends. If you cast the spell every day for 365 days on the same area, the spell thereafter lasts until all its effects are dispelled.\nCorridors. Fog fills all the warded corridors, making them Heavily Obscured. In addition, at each intersection or branching passage offering a choice of direction, there is a 50 percent chance that a creature other than you believes it is going in the opposite direction from the one it chooses.\nDoors. All doors in the warded area are magically locked, as if sealed by the Arcane Lock spell. In addition, you can cover up to ten doors with an illusion to make them appear as plain sections of wall.\nStairs. Webs fill all stairs in the warded area from top to bottom, as in the Web spell. These strands regrow in 10 minutes if they are destroyed while Guards and Wards lasts.\nOther Spell Effect. Place one of the following magical effects within the warded area: • Dancing Lights in four corridors, with a simple program that the lights repeat as long as Guards and Wards lasts • Magic Mouth in two locations • Stinking Cloud in two locations (the vapors return within 10 minutes if dispersed while Guards and Wards lasts) • Gust of Wind in one corridor or room (the wind blows continuously while the spell lasts) • Suggestion in one 5-foot square; any creature that enters that square receives the suggestion mentally","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Guards and Wards","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Guidance","constant":false,"content":"## Guidance (안내) - Cantrip Divination spell, SRD 5.2.1\nClasses: Cleric, Druid. Casting Time: Action. Range: Touch Component: V, S. Components: . Duration: Concentration, up to 1 minute.\nYou touch a willing creature and choose a skill. Until the spell ends, the creature adds 1d4 to any ability check using the chosen skill.","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Guidance","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Guiding Bolt","constant":false,"content":"## Guiding Bolt (유도 화살) - Level 1 Evocation spell, SRD 5.2.1\nClasses: Cleric. Casting Time: Action. Range: 120 feet. Components: V, S. Duration: 1 round.\nYou hurl a bolt of light toward a creature within range. Make a ranged spell attack against the target. On a hit, it takes 4d6 Radiant damage, and the next attack roll made against it before the end of your next turn has Advantage.\nUsing a Higher-Level Spell Slot. The damage increases by 1d6 for each spell slot level above 1.","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Guiding Bolt","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Gust of Wind","constant":false,"content":"## Gust of Wind (돌풍) - Level 2 Evocation spell, SRD 5.2.1\nClasses: Druid, Ranger, Sorcerer, Wizard. Casting Time: Action. Range: Self. Components: V, S, M (a legume seed). Duration: Concentration, up to 1 minute.\nA Line of strong wind 60 feet long and 10 feet wide blasts from you in a direction you choose for the duration. Each creature in the Line must succeed on a Strength saving throw or be pushed 15 feet away from you in a direction following the Line. A creature that ends its turn in the Line must make the same save.\nAny creature in the Line must spend 2 feet of movement for every 1 foot it moves when moving closer to you.\nThe gust disperses gas or vapor, and it extinguishes candles and similar unprotected flames in the area. It causes protected flames, such as those of lanterns, to dance wildly and has a 50 percent chance to extinguish them.\nAs a Bonus Action on your later turns, you can change the direction in which the Line blasts from you.","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Gust of Wind","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Hallow","constant":false,"content":"## Hallow (신성화) - Level 5 Abjuration spell, SRD 5.2.1\nClasses: Cleric. Casting Time: 24 hours. Range: Touch. Components: V, S, M (incense worth 1,000+ GP, which the spell consumes). Duration: Until dispelled.\nYou touch a point and infuse an area around it with holy or unholy power. The area can have a radius up to 60 feet, and the spell fails if the radius includes an area already under the effect of Hallow. The affected area has the following effects.\nHallowed Ward. Choose any of these creature types: Aberration, Celestial, Elemental, Fey, Fiend, or Undead. Creatures of the chosen types can't willingly enter the area, and any creature that is possessed by or that has the Charmed or Frightened condition from such creatures isn't possessed, Charmed, or Frightened by them while in the area.\nExtra Effect. You bind an extra effect to the area from the list below:\nCourage. Creatures of any types you choose can't gain the Frightened condition while in the area.\nDarkness. Darkness fills the area. Normal light, as well as magical light created by spells of a level lower than this spell, can't illuminate the area. 139 Daylight. Bright light fills the area. Magical Darkness created by spells of a level lower than this spell can't extinguish the light.\nPeaceful Rest. Dead bodies interred in the area can't be turned into Undead.\nExtradimensional Interference. Creatures of any types you choose can't enter or exit the area using teleportation or interplanar travel.\nFear. Creatures of any types you choose have the Frightened condition while in the area.\nResistance. Creatures of any types you choose have Resistance to one damage type of your choice while in the area.\nSilence. No sound can emanate from within the area, and no sound can reach into it.\nTongues. Creatures of any types you choose can communicate with any other creature in the area even if they don't share a common language.\nVulnerability. Creatures of any types you choose have Vulnerability to one damage type of your choice while in the area.","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Hallow","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Hallucinatory Terrain","constant":false,"content":"## Hallucinatory Terrain (환각 지형) - Level 4 Illusion spell, SRD 5.2.1\nClasses: Bard, Druid, Warlock, Wizard. Casting Time: 10 minutes. Range: 300 feet. Components: V, S, M (a mushroom). Duration: 24 hours.\nYou make natural terrain in a 150-foot Cube in range look, sound, and smell like another sort of natural terrain. Thus, open fields or a road can be made to resemble a swamp, hill, crevasse, or some other difficult or impassable terrain. A pond can be made to seem like a grassy meadow, a precipice like a gentle slope, or a rock-strewn gully like a wide and smooth road. Manufactured structures, equipment, and creatures within the area aren't changed.\nThe tactile characteristics of the terrain are unchanged, so creatures entering the area are likely to notice the illusion. If the difference isn't obvious by touch, a creature examining the illusion can take the Study action to make an Intelligence (Investigation) check against your spell save DC to disbelieve it. If a creature discerns that the terrain is illusory, the creature sees a vague image superimposed on the real terrain.","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Hallucinatory Terrain","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Harm","constant":false,"content":"## Harm (위해) - Level 6 Necromancy spell, SRD 5.2.1\nClasses: Cleric. Casting Time: Action. Range: 60 feet. Components: V, S. Duration: Instantaneous.\nYou unleash virulent magic on a creature you can see within range. The target makes a Constitution saving throw. On a failed save, it takes 14d6 Necrotic damage, and its Hit Point maximum is reduced by an amount equal to the Necrotic damage it took. On a successful save, it takes half as much damage only. This spell can't reduce a target's Hit Point maximum below 1.","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Harm","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Haste","constant":false,"content":"## Haste (가속) - Level 3 Transmutation spell, SRD 5.2.1\nClasses: Sorcerer, Wizard. Casting Time: Action. Range: 30 feet. Components: V, S, M (a shaving of licorice root). Duration: Concentration, up to 1 minute.\nChoose a willing creature that you can see within range. Until the spell ends, the target's Speed is doubled, it gains a +2 bonus to Armor Class, it has Advantage on Dexterity saving throws, and it gains an additional action on each of its turns. That action can be used to take only the Attack (one attack only), Dash, Disengage, Hide, or Utilize action.\nWhen the spell ends, the target is Incapacitated and has a Speed of 0 until the end of its next turn, as a wave of lethargy washes over it.","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Haste","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Heal","constant":false,"content":"## Heal (치유) - Level 6 Abjuration spell, SRD 5.2.1\nClasses: Cleric, Druid. Casting Time: Action. Range: 60 feet. Components: V, S. Duration: Instantaneous.\nChoose a creature that you can see within range.\nPositive energy washes through the target, restoring 70 Hit Points. This spell also ends the Blinded, Deafened, and Poisoned conditions on the target.\nUsing a Higher-Level Spell Slot. The healing increases by 10 for each spell slot level above 6.","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Heal","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Healing Word","constant":false,"content":"## Healing Word (치료의 단어) - Level 1 Abjuration spell, SRD 5.2.1\nClasses: Bard, Cleric, Druid. Casting Time: Bonus Action. Range: 60 feet. Components: V. Duration: Instantaneous.\nA creature of your choice that you can see within range regains Hit Points equal to 2d4 plus your spellcasting ability modifier.\nUsing a Higher-Level Spell Slot. The healing increases by 2d4 for each spell slot level above 1.","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Healing Word","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Heat Metal","constant":false,"content":"## Heat Metal (금속 가열) - Level 2 Transmutation spell, SRD 5.2.1\nClasses: Bard, Druid. Casting Time: Action. Range: 60 feet. Components: V, S, M (a piece of iron and a flame). Duration: Concentration, up to 1 minute 140.\nChoose a manufactured metal object, such as a metal weapon or a suit of Heavy or Medium metal armor, that you can see within range. You cause the object to glow red-hot. Any creature in physical contact with the object takes 2d8 Fire damage when you cast the spell. Until the spell ends, you can take a Bonus Action on each of your later turns to deal this damage again if the object is within range.\nIf a creature is holding or wearing the object and takes the damage from it, the creature must succeed on a Constitution saving throw or drop the object if it can. If it doesn't drop the object, it has Disadvantage on attack rolls and ability checks until the start of your next turn.\nUsing a Higher-Level Spell Slot. The damage increases by 1d8 for each spell slot level above 2.","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Heat Metal","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Hellish Rebuke","constant":false,"content":"## Hellish Rebuke (지옥의 질책) - Level 1 Evocation spell, SRD 5.2.1\nClasses: Warlock. Casting Time: Reaction, which you take in response to taking damage from a creature that you can see within 60 feet of yourself. Range: 60 feet. Components: V, S. Duration: Instantaneous.\nThe creature that damaged you is momentarily surrounded by green flames. It makes a Dexterity saving throw, taking 2d10 Fire damage on a failed save or half as much damage on a successful one.\nUsing a Higher-Level Spell Slot. The damage increases by 1d10 for each spell slot level above 1.","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Hellish Rebuke","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Heroes' Feast","constant":false,"content":"## Heroes' Feast (영웅들의 만찬) - Level 6 Conjuration spell, SRD 5.2.1\nClasses: Bard, Cleric, Druid. Casting Time: 10 minutes. Range: Self. Components: V, S, M (a gem-encrusted bowl worth 1,000+ GP, which the spell consumes). Duration: Instantaneous.\nYou conjure a feast that appears on a surface in an unoccupied 10-foot Cube next to you. The feast takes 1 hour to consume and disappears at the end of that time, and the beneficial effects don't set in until this hour is over. Up to twelve creatures can partake of the feast.\nA creature that partakes gains several benefits, which last for 24 hours. The creature has Resistance to Poison damage, and it has Immunity to the Frightened and Poisoned conditions. Its Hit Point maximum also increases by 2d10, and it gains the same number of Hit Points.","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Heroes' Feast","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Heroism","constant":false,"content":"## Heroism (영웅심) - Level 1 Enchantment spell, SRD 5.2.1\nClasses: Bard, Paladin. Casting Time: Action. Range: Touch. Components: V, S. Duration: Concentration, up to 1 minute.\nA willing creature you touch is imbued with bravery. Until the spell ends, the creature is immune to the Frightened condition and gains Temporary Hit Points equal to your spellcasting ability modifier at the start of each of its turns.\nUsing a Higher-Level Spell Slot. You can target one additional creature for each spell slot level above 1.","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Heroism","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Hex","constant":false,"content":"## Hex (헥스) - Level 1 Enchantment spell, SRD 5.2.1\nClasses: Warlock. Casting Time: Bonus Action. Range: 90 feet. Components: V, S, M (the petrified eye of a newt). Duration: Concentration, up to 1 hour.\nYou place a curse on a creature that you can see within range. Until the spell ends, you deal an extra 1d6 Necrotic damage to the target whenever you hit it with an attack roll. Also, choose one ability when you cast the spell. The target has Disadvantage on ability checks made with the chosen ability.\nIf the target drops to 0 Hit Points before this spell ends, you can take a Bonus Action on a later turn to curse a new creature.\nUsing a Higher-Level Spell Slot. Your Concentration can last longer with a spell slot of level 2 (up to 4 hours), 3-4 (up to 8 hours), or 5+ (24 hours).","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Hex","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Hideous Laughter","constant":false,"content":"## Hideous Laughter (끔찍한 웃음) - Level 1 Enchantment spell, SRD 5.2.1\nClasses: Bard, Warlock, Wizard. Casting Time: Action. Range: 30 feet. Components: V, S, M (a tart and a feather). Duration: Concentration, up to 1 minute.\nOne creature of your choice that you can see within range makes a Wisdom saving throw. On a failed save, it has the Prone and Incapacitated conditions for the duration. During that time, it laughs uncontrollably if it's capable of laughter, and it can't end the Prone condition on itself.\nAt the end of each of its turns and each time it takes damage, it makes another Wisdom saving throw. The target has Advantage on the save if the save is triggered by damage. On a successful save, the spell ends.\nUsing a Higher-Level Spell Slot. You can target one additional creature for each spell slot level above 1.","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Hideous Laughter","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Hold Monster","constant":false,"content":"## Hold Monster (괴물 포박) - Level 5 Enchantment spell, SRD 5.2.1\nClasses: Bard, Sorcerer, Warlock, Wizard. Casting Time: Action. Range: 90 feet 141. Components: V, S, M (a straight piece of iron). Duration: Concentration, up to 1 minute.\nChoose a creature that you can see within range.\nThe target must succeed on a Wisdom saving throw or have the Paralyzed condition for the duration. At the end of each of its turns, the target repeats the save, ending the spell on itself on a success.\nUsing a Higher-Level Spell Slot. You can target one additional creature for each spell slot level above 5.","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Hold Monster","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Hold Person","constant":false,"content":"## Hold Person (인간형 포박) - Level 2 Enchantment spell, SRD 5.2.1\nClasses: Bard, Cleric, Druid, Sorcerer, Warlock, Wizard. Casting Time: Action. Range: 60 feet. Components: V, S, M (a straight piece of iron). Duration: Concentration, up to 1 minute.\nChoose a Humanoid that you can see within range.\nThe target must succeed on a Wisdom saving throw or have the Paralyzed condition for the duration. At the end of each of its turns, the target repeats the save, ending the spell on itself on a success.\nUsing a Higher-Level Spell Slot. You can target one additional Humanoid for each spell slot level above 2.","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Hold Person","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Holy Aura","constant":false,"content":"## Holy Aura (신성한 오라) - Level 8 Abjuration spell, SRD 5.2.1\nClasses: Cleric. Casting Time: Action. Range: Self. Components: V, S, M (a reliquary worth 1,000+ GP). Duration: Concentration, up to 1 minute.\nFor the duration, you emit an aura in a 30-foot Emanation. While in the aura, creatures of your choice have Advantage on all saving throws, and other creatures have Disadvantage on attack rolls against them. In addition, when a Fiend or an Undead hits an affected creature with a melee attack roll, the attacker must succeed on a Constitution saving throw or have the Blinded condition until the end of its next turn.","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Holy Aura","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Hunter's Mark","constant":false,"content":"## Hunter's Mark (사냥꾼의 표식) - Level 1 Divination spell, SRD 5.2.1\nClasses: Ranger. Casting Time: Bonus Action. Range: 90 feet. Components: V. Duration: Concentration, up to 1 hour.\nYou magically mark one creature you can see within range as your quarry. Until the spell ends, you deal an extra 1d6 Force damage to the target whenever you hit it with an attack roll. You also have Advantage on any Wisdom (Perception or Survival) check you make to find it.\nIf the target drops to 0 Hit Points before this spell ends, you can take a Bonus Action to move the mark to a new creature you can see within range.\nUsing a Higher-Level Spell Slot. Your Concentration can last longer with a spell slot of level 3-4 (up to 8 hours) or 5+ (up to 24 hours).","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Hunter's Mark","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Hypnotic Pattern","constant":false,"content":"## Hypnotic Pattern (최면 패턴) - Level 3 Illusion spell, SRD 5.2.1\nClasses: Bard, Sorcerer, Warlock, Wizard. Casting Time: Action. Range: 120 feet. Components: S, M (a pinch of confetti). Duration: Concentration, up to 1 minute.\nYou create a twisting pattern of colors in a 30-foot Cube within range. The pattern appears for a moment and vanishes. Each creature in the area who can see the pattern must succeed on a Wisdom saving throw or have the Charmed condition for the duration. While Charmed, the creature has the Incapacitated condition and a Speed of 0.\nThe spell ends for an affected creature if it takes any damage or if someone else uses an action to shake the creature out of its stupor.","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Hypnotic Pattern","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Ice Knife","constant":false,"content":"## Ice Knife (얼음 칼날) - Level 1 Conjuration spell, SRD 5.2.1\nClasses: Druid, Sorcerer, Wizard. Casting Time: Action. Range: 60 feet. Components: S, M (a drop of water or a piece of ice). Duration: Instantaneous.\nYou create a shard of ice and fling it at one creature within range. Make a ranged spell attack against the target. On a hit, the target takes 1d10 Piercing damage. Hit or miss, the shard then explodes. The target and each creature within 5 feet of it must succeed on a Dexterity saving throw or take 2d6 Cold damage.\nUsing a Higher-Level Spell Slot. The Cold damage increases by 1d6 for each spell slot level above 1.","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Ice Knife","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Ice Storm","constant":false,"content":"## Ice Storm (얼음 폭풍) - Level 4 Evocation spell, SRD 5.2.1\nClasses: Druid, Sorcerer, Wizard. Casting Time: Action. Range: 300 feet. Components: V, S, M (a mitten). Duration: Instantaneous.\nHail falls in a 20-foot-radius, 40-foot-high Cylinder centered on a point within range. Each creature in the Cylinder makes a Dexterity saving throw. A creature takes 2d10 Bludgeoning damage and 4d6 Cold damage on a failed save or half as much damage on a successful one.\nHailstones turn ground in the Cylinder into Difficult Terrain until the end of your next turn. 142 Using a Higher-Level Spell Slot. The Bludgeoning damage increases by 1d10 for each spell slot level above 4.","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Ice Storm","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Identify","constant":false,"content":"## Identify (식별) - Level 1 Divination spell, SRD 5.2.1\nClasses: Bard, Wizard. Casting Time: 1 minute or Ritual. Range: Touch. Components: V, S, M (a pearl worth 100+ GP). Duration: Instantaneous.\nYou touch an object throughout the spell's casting.\nIf the object is a magic item or some other magical object, you learn its properties and how to use them, whether it requires Attunement, and how many charges it has, if any. You learn whether any ongoing spells are affecting the item and what they are. If the item was created by a spell, you learn that spell's name.\nIf you instead touch a creature throughout the casting, you learn which ongoing spells, if any, are currently affecting it.","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Identify","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Illusory Script","constant":false,"content":"## Illusory Script (환영 문서) - Level 1 Illusion spell, SRD 5.2.1\nClasses: Bard, Warlock, Wizard. Casting Time: 1 minute or Ritual. Range: Touch. Components: S, M (ink worth 10+ GP, which the spell consumes). Duration: 10 days.\nYou write on parchment, paper, or another suitable material and imbue it with an illusion that lasts for the duration. To you and any creatures you designate when you cast the spell, the writing appears normal, seems to be written in your hand, and conveys whatever meaning you intended when you wrote the text. To all others, the writing appears as if it were written in an unknown or magical script that is unintelligible. Alternatively, the illusion can alter the meaning, handwriting, and language of the text, though the language must be one you know.\nIf the spell is dispelled, the original script and the illusion both disappear.\nA creature that has Truesight can read the hidden message.","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Illusory Script","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Imprisonment","constant":false,"content":"## Imprisonment (투옥) - Level 9 Abjuration spell, SRD 5.2.1\nClasses: Warlock, Wizard. Casting Time: 1 minute. Range: 30 feet. Components: V, S, M (a statuette of the target worth 5,000+ GP). Duration: Until dispelled.\nYou create a magical restraint to hold a creature that you can see within range. The target must make a Wisdom saving throw. On a successful save, the target is unaffected, and it is immune to this spell for the next 24 hours. On a failed save, the target is imprisoned. While imprisoned, the target doesn't need to breathe, eat, or drink, and it doesn't age. Divination spells can't locate or perceive the imprisoned target, and the target can't teleport.\nUntil the spell ends, the target is also affected by one of the following effects of your choice:\nBurial. The target is entombed beneath the earth in a hollow globe of magical force that is just large enough to contain the target. Nothing can pass into or out of the globe.\nChaining. Chains firmly rooted in the ground hold the target in place. The target has the Restrained condition and can't be moved by any means.\nHedged Prison. The target is trapped in a demiplane that is warded against teleportation and planar travel. The demiplane is your choice of a labyrinth, a cage, a tower, or the like.\nMinimus Containment. The target becomes 1 inch tall and is trapped inside an indestructible gemstone or a similar object. Light can pass through the gemstone (allowing the target to see out and other creatures to see in), but nothing else can pass through by any means.\nSlumber. The target has the Unconscious condition and can't be awoken.\nEnding the Spell. When you cast the spell, specify a trigger that will end it. The trigger can be as simple or as elaborate as you choose, but the GM must agree that it has a high likelihood of happening within the next decade. The trigger must be an observable action, such as someone making a particular offering at the temple of your god, saving your true love, or defeating a specific monster.\nA Dispel Magic spell can end the spell only if it is cast with a level 9 spell slot, targeting either the prison or the component used to create it.","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Imprisonment","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Incendiary Cloud","constant":false,"content":"## Incendiary Cloud (소이 구름) - Level 8 Conjuration spell, SRD 5.2.1\nClasses: Druid, Sorcerer, Wizard. Casting Time: Action. Range: 150 feet. Components: V, S. Duration: Concentration, up to 1 minute.\nA swirling cloud of embers and smoke fills a 20-foot-radius Sphere centered on a point within range. The cloud's area is Heavily Obscured. It lasts for the duration or until a strong wind (like that created by Gust of Wind) disperses it.\nWhen the cloud appears, each creature in it makes a Dexterity saving throw, taking 10d8 Fire damage on a failed save or half as much damage on a successful one. A creature must also make this save when the Sphere moves into its space and when it enters the Sphere or ends its turn there. A creature makes this save only once per turn. 143 The cloud moves 10 feet away from you in a direction you choose at the start of each of your turns.","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Incendiary Cloud","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Inflict Wounds","constant":false,"content":"## Inflict Wounds (상처 가해) - Level 1 Necromancy spell, SRD 5.2.1\nClasses: Cleric. Casting Time: Action. Range: Touch. Components: V, S. Duration: Instantaneous.\nA creature you touch makes a Constitution saving throw, taking 2d10 Necrotic damage on a failed save or half as much damage on a successful one.\nUsing a Higher-Level Spell Slot. The damage increases by 1d10 for each spell slot level above 1.","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Inflict Wounds","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Insect Plague","constant":false,"content":"## Insect Plague (곤충 떼) - Level 5 Conjuration spell, SRD 5.2.1\nClasses: Cleric, Druid, Sorcerer. Casting Time: Action. Range: 300 feet. Components: V, S, M (a locust). Duration: Concentration, up to 10 minutes.\nSwarming locusts fill a 20-foot-radius Sphere centered on a point you choose within range. The Sphere remains for the duration, and its area is Lightly Obscured and Difficult Terrain.\nWhen the swarm appears, each creature in it makes a Constitution saving throw, taking 4d10 Piercing damage on a failed save or half as much damage on a successful one. A creature also makes this save when it enters the spell's area for the first time on a turn or ends its turn there. A creature makes this save only once per turn.\nUsing a Higher-Level Spell Slot. The damage increases by 1d10 for each spell slot level above 5.","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Insect Plague","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Instant Summons","constant":false,"content":"## Instant Summons (즉시 소환) - Level 6 Conjuration spell, SRD 5.2.1\nClasses: Wizard. Casting Time: 1 minute or Ritual. Range: Touch. Components: V, S, M (a sapphire worth 1,000+ GP). Duration: Until dispelled.\nYou touch the sapphire used in the casting and an object weighing 10 pounds or less whose longest dimension is 6 feet or less. The spell leaves an Invisible mark on that object and invisibly inscribes the object's name on the sapphire. Each time you cast this spell, you must use a different sapphire.\nThereafter, you can take a Magic action to speak the object's name and crush the sapphire. The object instantly appears in your hand regardless of physical or planar distances, and the spell ends.\nIf another creature is holding or carrying the object, crushing the sapphire doesn't transport it, but instead you learn who that creature is and where that creature is currently located.","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Instant Summons","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Irresistible Dance","constant":false,"content":"## Irresistible Dance (거부할 수 없는 춤) - Level 6 Enchantment spell, SRD 5.2.1\nClasses: Bard, Wizard. Casting Time: Action. Range: 30 feet. Components: V. Duration: Concentration, up to 1 minute.\nOne creature that you can see within range must make a Wisdom saving throw. On a successful save, the target dances comically until the end of its next turn, during which it must spend all its movement to dance in place.\nOn a failed save, the target has the Charmed condition for the duration. While Charmed, the target dances comically, must use all its movement to dance in place, and has Disadvantage on Dexterity saving throws and attack rolls, and other creatures have Advantage on attack rolls against it. On each of its turns, the target can take an action to collect itself and repeat the save, ending the spell on itself on a success.","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Irresistible Dance","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Invisibility","constant":false,"content":"## Invisibility (투명화) - Level 2 Illusion spell, SRD 5.2.1\nClasses: Bard, Sorcerer, Warlock, Wizard. Casting Time: Action. Range: Touch. Components: V, S, M (an eyelash in gum arabic). Duration: Concentration, up to 1 hour.\nA creature you touch has the Invisible condition until the spell ends. The spell ends early immediately after the target makes an attack roll, deals damage, or casts a spell.\nUsing a Higher-Level Spell Slot. You can target one additional creature for each spell slot level above 2.","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Invisibility","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Jump","constant":false,"content":"## Jump (도약) - Level 1 Transmutation spell, SRD 5.2.1\nClasses: Druid, Ranger, Sorcerer, Wizard. Casting Time: Bonus Action. Range: Touch Component: V, S, M (a grasshopper's hind leg). Components: . Duration: 1 minute.\nYou touch a willing creature. Once on each of its turns until the spell ends, that creature can jump up to 30 feet by spending 10 feet of movement.\nUsing a Higher-Level Spell Slot. You can target one additional creature for each spell slot level above 1.","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Jump","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Knock","constant":false,"content":"## Knock (문열기) - Level 2 Transmutation spell, SRD 5.2.1\nClasses: Bard, Sorcerer, Wizard. Casting Time: Action. Range: 60 feet. Components: V. Duration: Instantaneous 144.\nChoose an object that you can see within range. The object can be a door, a box, a chest, a set of manacles, a padlock, or another object that contains a mundane or magical means that prevents access.\nA target that is held shut by a mundane lock or that is stuck or barred becomes unlocked, unstuck, or unbarred. If the object has multiple locks, only one of them is unlocked.\nIf the target is held shut by Arcane Lock, that spell is suppressed for 10 minutes, during which time the target can be opened and closed.\nWhen you cast the spell, a loud knock, audible up to 300 feet away, emanates from the target.","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Knock","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Legend Lore","constant":false,"content":"## Legend Lore (전설 지식) - Level 5 Divination spell, SRD 5.2.1\nClasses: Bard, Cleric, Wizard. Casting Time: 10 minutes. Range: Self. Components: V, S, M (incense worth 250+ GP, which the spell consumes, and four ivory strips worth 50+ GP each). Duration: Instantaneous.\nName or describe a famous person, place, or object.\nThe spell brings to your mind a brief summary of the significant lore about that famous thing, as described by the GM.\nThe lore might consist of important details, amusing revelations, or even secret lore that has never been widely known. The more information you already know about the thing, the more precise and detailed the information you receive is. That information is accurate but might be couched in figurative language or poetry, as determined by the GM.\nIf the famous thing you chose isn't actually famous, you hear sad musical notes played on a trombone, and the spell fails.","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Legend Lore","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Lesser Restoration","constant":false,"content":"## Lesser Restoration (하급 회복) - Level 2 Abjuration spell, SRD 5.2.1\nClasses: Bard, Cleric, Druid, Paladin, Ranger. Casting Time: Bonus Action. Range: Touch. Components: V, S. Duration: Instantaneous.\nYou touch a creature and end one condition on it:\nBlinded, Deafened, Paralyzed, or Poisoned.","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Lesser Restoration","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Levitate","constant":false,"content":"## Levitate (부양) - Level 2 Transmutation spell, SRD 5.2.1\nClasses: Sorcerer, Wizard. Casting Time: Action. Range: 60 feet. Components: V, S, M (a metal spring). Duration: Concentration, up to 10 minutes.\nOne creature or loose object of your choice that you can see within range rises vertically up to 20 feet and remains suspended there for the duration. The spell can levitate an object that weighs up to 500 pounds. An unwilling creature that succeeds on a Constitution saving throw is unaffected.\nThe target can move only by pushing or pulling against a fixed object or surface within reach (such as a wall or a ceiling), which allows it to move as if it were climbing. You can change the target's altitude by up to 20 feet in either direction on your turn. If you are the target, you can move up or down as part of your move. Otherwise, you can take a Magic action to move the target, which must remain within the spell's range.\nWhen the spell ends, the target floats gently to the ground if it is still aloft.","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Levitate","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Light","constant":false,"content":"## Light (빛) - Cantrip Evocation spell, SRD 5.2.1\nClasses: Bard, Cleric, Sorcerer, Wizard. Casting Time: Action. Range: Touch. Components: V, M (a firefly or phosphorescent moss). Duration: 1 hour.\nYou touch one Large or smaller object that isn't being worn or carried by someone else. Until the spell ends, the object sheds Bright Light in a 20-foot radius and Dim Light for an additional 20 feet. The light can be colored as you like.\nCovering the object with something opaque blocks the light. The spell ends if you cast it again.","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Light","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Lightning Bolt","constant":false,"content":"## Lightning Bolt (번개) - Level 3 Evocation spell, SRD 5.2.1\nClasses: Sorcerer, Wizard. Casting Time: Action. Range: Self. Components: V, S, M (a bit of fur and a crystal rod). Duration: Instantaneous.\nA stroke of lightning forming a 100-foot-long, 5-foot-wide Line blasts out from you in a direction you choose. Each creature in the Line makes a Dexterity saving throw, taking 8d6 Lightning damage on a failed save or half as much damage on a successful one.\nUsing a Higher-Level Spell Slot. The damage increases by 1d6 for each spell slot level above 3.","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Lightning Bolt","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Locate Animals or Plants","constant":false,"content":"## Locate Animals or Plants (동식물 찾기) - Level 2 Divination spell, SRD 5.2.1\nClasses: Bard, Druid, Ranger. Casting Time: Action or Ritual. Range: Self. Components: V, S, M (fur from a bloodhound). Duration: Instantaneous.\nDescribe or name a specific kind of Beast, Plant creature, or nonmagical plant. You learn the direction and distance to the closest creature or plant of that kind within 5 miles, if any are present. 145","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Locate Animals or Plants","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Locate Creature","constant":false,"content":"## Locate Creature (생물 위치파악) - Level 4 Divination spell, SRD 5.2.1\nClasses: Bard, Cleric, Druid, Paladin, Ranger, Wizard. Casting Time: Action. Range: Self. Components: V, S, M (fur from a bloodhound). Duration: Concentration, up to 1 hour.\nDescribe or name a creature that is familiar to you.\nYou sense the direction to the creature's location if that creature is within 1,000 feet of you. If the creature is moving, you know the direction of its movement.\nThe spell can locate a specific creature known to you or the nearest creature of a specific kind (such as a human or a unicorn) if you have seen such a creature up close—within 30 feet—at least once.\nIf the creature you described or named is in a different form, such as under the effects of a Flesh to Stone or Polymorph spell, this spell doesn't locate the creature.\nThis spell can't locate a creature if any thickness of lead blocks a direct path between you and the creature.","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Locate Creature","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Locate Object","constant":false,"content":"## Locate Object (물체 위치파악) - Level 2 Divination spell, SRD 5.2.1\nClasses: Bard, Cleric, Druid, Paladin, Ranger, Wizard. Casting Time: Action. Range: Self. Components: V, S, M (a forked twig). Duration: Concentration, up to 10 minutes.\nDescribe or name an object that is familiar to you.\nYou sense the direction to the object's location if that object is within 1,000 feet of you. If the object is in motion, you know the direction of its movement.\nThe spell can locate a specific object known to you if you have seen it up close—within 30 feet—at least once. Alternatively, the spell can locate the nearest object of a particular kind, such as a certain kind of apparel, jewelry, furniture, tool, or weapon.\nThis spell can't locate an object if any thickness of lead blocks a direct path between you and the object.","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Locate Object","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Longstrider","constant":false,"content":"## Longstrider (활보) - Level 1 Transmutation spell, SRD 5.2.1\nClasses: Bard, Druid, Ranger, Wizard. Casting Time: Action. Range: Touch. Components: V, S, M (a pinch of dirt). Duration: 1 hour.\nYou touch a creature. The target's Speed increases by 10 feet until the spell ends.\nUsing a Higher-Level Spell Slot. You can target one additional creature for each spell slot level above 1.","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Longstrider","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Mage Armor","constant":false,"content":"## Mage Armor (마법 갑주) - Level 1 Abjuration spell, SRD 5.2.1\nClasses: Sorcerer, Wizard. Casting Time: Action. Range: Touch. Components: V, S, M (a piece of cured leather). Duration: 8 hours.\nYou touch a willing creature who isn't wearing armor. Until the spell ends, the target's base AC becomes 13 plus its Dexterity modifier. The spell ends early if the target dons armor.","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Mage Armor","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Mage Hand","constant":false,"content":"## Mage Hand (마법사의 손) - Cantrip Conjuration spell, SRD 5.2.1\nClasses: Bard, Sorcerer, Warlock, Wizard. Casting Time: Action. Range: 30 feet. Components: V, S. Duration: 1 minute.\nA spectral, floating hand appears at a point you choose within range. The hand lasts for the duration. The hand vanishes if it is ever more than 30 feet away from you or if you cast this spell again.\nWhen you cast the spell, you can use the hand to manipulate an object, open an unlocked door or container, stow or retrieve an item from an open container, or pour the contents out of a vial.\nAs a Magic action on your later turns, you can control the hand thus again. As part of that action, you can move the hand up to 30 feet.\nThe hand can't attack, activate magic items, or carry more than 10 pounds.","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Mage Hand","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Magic Circle","constant":false,"content":"## Magic Circle (마법의 원) - Level 3 Abjuration spell, SRD 5.2.1\nClasses: Cleric, Paladin, Warlock, Wizard. Casting Time: 1 minute. Range: 10 feet. Components: V, S, M (salt and powdered silver worth 100+ GP, which the spell consumes). Duration: 1 hour.\nYou create a 10-foot-radius, 20-foot-tall Cylinder of magical energy centered on a point on the ground that you can see within range. Glowing runes appear wherever the Cylinder intersects with the floor or other surface.\nChoose one or more of the following types of creatures: Celestials, Elementals, Fey, Fiends, or Undead.\nThe circle affects a creature of the chosen type in the following ways: • The creature can't willingly enter the Cylinder by nonmagical means. If the creature tries to use teleportation or interplanar travel to do so, it must first succeed on a Charisma saving throw. • The creature has Disadvantage on attack rolls against targets within the Cylinder. 146 • Targets within the Cylinder can't be possessed by or gain the Charmed or Frightened condition from the creature.\nEach time you cast this spell, you can cause its magic to operate in the reverse direction, preventing a creature of the specified type from leaving the Cylinder and protecting targets outside it.\nUsing a Higher-Level Spell Slot. The duration increases by 1 hour for each spell slot level above 3.","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Magic Circle","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Magic Jar","constant":false,"content":"## Magic Jar (마법 항아리) - Level 6 Necromancy spell, SRD 5.2.1\nClasses: Wizard. Casting Time: 1 minute. Range: Self. Components: V, S, M (a gem, crystal, or reliquary worth 500+ GP). Duration: Until dispelled.\nYour body falls into a catatonic state as your soul leaves it and enters the container you used for the spell's Material component. While your soul inhabits the container, you are aware of your surroundings as if you were in the container's space. You can't move or take Reactions. The only action you can take is to project your soul up to 100 feet out of the container, either returning to your living body (and ending the spell) or attempting to possess a Humanoid's body.\nYou can attempt to possess any Humanoid within 100 feet of you that you can see (creatures warded by a Protection from Evil and Good or Magic Circle spell can't be possessed). The target makes a Charisma saving throw. On a failed save, your soul enters the target's body, and the target's soul becomes trapped in the container. On a successful save, the target resists your efforts to possess it, and you can't attempt to possess it again for 24 hours.\nOnce you possess a creature's body, you control it.\nYour Hit Points, Hit Point Dice, Strength, Dexterity, Constitution, Speed, and senses are replaced by the creature's. You otherwise keep your game statistics.\nMeanwhile, the possessed creature's soul can perceive from the container using its own senses, but it can't move and it is Incapacitated.\nWhile possessing a body, you can take a Magic action to return from the host body to the container if it is within 100 feet of you, returning the host creature's soul to its body. If the host body dies while you're in it, the creature dies, and you make a Charisma saving throw against your own spellcasting DC. On a success, you return to the container if it is within 100 feet of you. Otherwise, you die.\nIf the container is destroyed or the spell ends, your soul returns to your body. If your body is more than 100 feet away from you or if your body is dead, you die. If another creature's soul is in the container when it is destroyed, the creature's soul returns to its body if the body is alive and within 100 feet. Otherwise, that creature dies.\nWhen the spell ends, the container is destroyed.","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Magic Jar","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Magic Missile","constant":false,"content":"## Magic Missile (마법 화살) - Level 1 Evocation spell, SRD 5.2.1\nClasses: Sorcerer, Wizard. Casting Time: Action. Range: 120 feet. Components: V, S. Duration: Instantaneous.\nYou create three glowing darts of magical force.\nEach dart strikes a creature of your choice that you can see within range. A dart deals 1d4 + 1 Force damage to its target. The darts all strike simultaneously, and you can direct them to hit one creature or several.\nUsing a Higher-Level Spell Slot. The spell creates one more dart for each spell slot level above 1.","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Magic Missile","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Magic Mouth","constant":false,"content":"## Magic Mouth (마법의 입) - Level 2 Illusion spell, SRD 5.2.1\nClasses: Bard, Wizard. Casting Time: 1 minute or Ritual. Range: 30 feet. Components: V, S, M (jade dust worth 10+ GP, which the spell consumes). Duration: Until dispelled.\nYou implant a message within an object in range—a message that is uttered when a trigger condition is met. Choose an object that you can see and that isn't being worn or carried by another creature. Then speak the message, which must be 25 words or fewer, though it can be delivered over as long as 10 minutes. Finally, determine the circumstance that will trigger the spell to deliver your message.\nWhen that trigger occurs, a magical mouth appears on the object and recites the message in your voice and at the same volume you spoke. If the object you chose has a mouth or something that looks like a mouth (for example, the mouth of a statue), the magical mouth appears there, so the words appear to come from the object's mouth. When you cast this spell, you can have the spell end after it delivers its message, or it can remain and repeat its message whenever the trigger occurs.\nThe trigger can be as general or as detailed as you like, though it must be based on visual or audible conditions that occur within 30 feet of the object.\nFor example, you could instruct the mouth to speak when any creature moves within 30 feet of the object or when a silver bell rings within 30 feet of it.","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Magic Mouth","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Magic Weapon","constant":false,"content":"## Magic Weapon (무기 마법화) - Level 2 Transmutation spell, SRD 5.2.1\nClasses: Paladin, Ranger, Sorcerer, Wizard. Casting Time: Bonus Action. Range: Touch 147. Components: V, S. Duration: 1 hour.\nYou touch a nonmagical weapon. Until the spell ends, that weapon becomes a magic weapon with a +1 bonus to attack rolls and damage rolls. The spell ends early if you cast it again.\nUsing a Higher-Level Spell Slot. The bonus increases to +2 with a level 3-5 spell slot. The bonus increases to +3 with a level 6+ spell slot.","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Magic Weapon","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Magnificent Mansion","constant":false,"content":"## Magnificent Mansion (장엄한 저택) - Level 7 Conjuration spell, SRD 5.2.1\nClasses: Bard, Wizard. Casting Time: 1 minute. Range: 300 feet. Components: V, S, M (a miniature door worth 15+ GP). Duration: 24 hours.\nYou conjure a shimmering door in range that lasts for the duration. The door leads to an extradimensional dwelling and is 5 feet wide and 10 feet tall.\nYou and any creature you designate when you cast the spell can enter the extradimensional dwelling as long as the door remains open. You can open or close it (no action required) if you are within 30 feet of it. While closed, the door is imperceptible.\nBeyond the door is a magnificent foyer with numerous chambers beyond. The dwelling's atmosphere is clean, fresh, and warm.\nYou can create any floor plan you like for the dwelling, but it can't exceed 50 contiguous 10-foot Cubes. The place is furnished and decorated as you choose. It contains sufficient food to serve a ninecourse banquet for up to 100 people. Furnishings and other objects created by this spell dissipate into smoke if removed from it.\nA staff of 100 near-transparent servants attends all who enter. You determine the appearance of these servants and their attire. They are invulnerable and obey your commands. Each servant can perform tasks that a human could perform, but they can't attack or take any action that would directly harm another creature. Thus the servants can fetch things, clean, mend, fold clothes, light fires, serve food, pour wine, and so on. The servants can't leave the dwelling.\nWhen the spell ends, any creatures or objects left inside the extradimensional space are expelled into the unoccupied spaces nearest to the entrance.","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Magnificent Mansion","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Major Image","constant":false,"content":"## Major Image (상급 영상) - Level 3 Illusion spell, SRD 5.2.1\nClasses: Bard, Sorcerer, Warlock, Wizard. Casting Time: Action. Range: 120 feet. Components: V, S, M (a bit of fleece). Duration: Concentration, up to 10 minutes.\nYou create the image of an object, a creature, or some other visible phenomenon that is no larger than a 20-foot Cube. The image appears at a spot that you can see within range and lasts for the duration. It seems real, including sounds, smells, and temperature appropriate to the thing depicted, but it can't deal damage or cause conditions.\nIf you are within range of the illusion, you can take a Magic action to cause the image to move to any other spot within range. As the image changes location, you can alter its appearance so that its movements appear natural for the image. For example, if you create an image of a creature and move it, you can alter the image so that it appears to be walking. Similarly, you can cause the illusion to make different sounds at different times, even making it carry on a conversation, for example.\nPhysical interaction with the image reveals it to be an illusion, for things can pass through it. A creature that takes a Study action to examine the image can determine that it is an illusion with a successful Intelligence (Investigation) check against your spell save DC. If a creature discerns the illusion for what it is, the creature can see through the image, and its other sensory qualities become faint to the creature.\nUsing a Higher-Level Spell Slot. The spell lasts until dispelled, without requiring Concentration, if cast with a level 4+ spell slot.","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Major Image","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Mass Cure Wounds","constant":false,"content":"## Mass Cure Wounds (다중 상처 치료) - Level 5 Abjuration spell, SRD 5.2.1\nClasses: Bard, Cleric, Druid. Casting Time: Action. Range: 60 feet. Components: V, S. Duration: Instantaneous.\nA wave of healing energy washes out from a point you can see within range. Choose up to six creatures in a 30-foot-radius Sphere centered on that point. Each target regains Hit Points equal to 5d8 plus your spellcasting ability modifier.\nUsing a Higher-Level Spell Slot. The healing increases by 1d8 for each spell slot level above 5.","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Mass Cure Wounds","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Mass Heal","constant":false,"content":"## Mass Heal (대량 치유) - Level 9 Abjuration spell, SRD 5.2.1\nClasses: Cleric. Casting Time: Action. Range: 60 feet. Components: V, S. Duration: Instantaneous.\nA flood of healing energy flows from you into creatures around you. You restore up to 700 Hit Points, divided as you choose among any number of creatures that you can see within range. Creatures healed by this spell also have the Blinded, Deafened, and Poisoned conditions removed from them. 148","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Mass Heal","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Mass Healing Word","constant":false,"content":"## Mass Healing Word (다중 치료의 단어) - Level 3 Abjuration spell, SRD 5.2.1\nClasses: Bard, Cleric. Casting Time: Bonus Action. Range: 60 feet. Components: V. Duration: Instantaneous.\nUp to six creatures of your choice that you can see within range regain Hit Points equal to 2d4 plus your spellcasting ability modifier.\nUsing a Higher-Level Spell Slot. The healing increases by 1d4 for each spell slot level above 3.","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Mass Healing Word","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Mass Suggestion","constant":false,"content":"## Mass Suggestion (다중 암시) - Level 6 Enchantment spell, SRD 5.2.1\nClasses: Bard, Sorcerer, Wizard. Casting Time: Action. Range: 60 feet. Components: V, M (a snake's tongue). Duration: 24 hours.\nYou suggest a course of activity—described in no more than 25 words—to twelve or fewer creatures you can see within range that can hear and understand you. The suggestion must sound achievable and not involve anything that would obviously deal damage to any of the targets or their allies. For example, you could say, “Walk to the village down that road, and help the villagers there harvest crops until sunset.” Or you could say, “Now is not the time for violence. Drop your weapons, and dance! Stop in an hour.” Each target must succeed on a Wisdom saving throw or have the Charmed condition for the duration or until you or your allies deal damage to the target. Each Charmed target pursues the suggestion to the best of its ability. The suggested activity can continue for the entire duration, but if the suggested activity can be completed in a shorter time, the spell ends for a target upon completing it.\nUsing a Higher-Level Spell Slot. The duration is longer with a spell slot of level 7 (10 days), 8 (30 days), or 9 (366 days).","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Mass Suggestion","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Maze","constant":false,"content":"## Maze (미궁) - Level 8 Conjuration spell, SRD 5.2.1\nClasses: Wizard. Casting Time: Action. Range: 60 feet. Components: V, S. Duration: Concentration, up to 10 minutes.\nYou banish a creature that you can see within range into a labyrinthine demiplane. The target remains there for the duration or until it escapes the maze.\nThe target can take a Study action to try to escape. When it does so, it makes a DC 20 Intelligence (Investigation) check. If it succeeds, it escapes, and the spell ends.\nWhen the spell ends, the target reappears in the space it left or, if that space is occupied, in the nearest unoccupied space.","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Maze","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Meld into Stone","constant":false,"content":"## Meld into Stone (돌에 녹아들기) - Level 3 Transmutation spell, SRD 5.2.1\nClasses: Cleric, Druid, Ranger. Casting Time: Action or Ritual. Range: Touch. Components: V, S. Duration: 8 hours.\nYou step into a stone object or surface large enough to fully contain your body, merging yourself and your equipment with the stone for the duration.\nYou must touch the stone to do so. Nothing of your presence remains visible or otherwise detectable by nonmagical senses.\nWhile merged with the stone, you can't see what occurs outside it, and any Wisdom (Perception) checks you make to hear sounds outside it are made with Disadvantage. You remain aware of the passage of time and can cast spells on yourself while merged in the stone. You can use 5 feet of movement to leave the stone where you entered it, which ends the spell. You otherwise can't move.\nMinor physical damage to the stone doesn't harm you, but its partial destruction or a change in its shape (to the extent that you no longer fit within it) expels you and deals 6d6 Force damage to you. The stone's complete destruction (or transmutation into a different substance) expels you and deals 50 Force damage to you. If expelled, you move into an unoccupied space closest to where you first entered and have the Prone condition.","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Meld into Stone","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Mending","constant":false,"content":"## Mending (수리) - Cantrip Transmutation spell, SRD 5.2.1\nClasses: Bard, Cleric, Druid, Sorcerer, Wizard. Casting Time: 1 minute. Range: Touch. Components: V, S, M (two lodestones). Duration: Instantaneous.\nThis spell repairs a single break or tear in an object you touch, such as a broken chain link, two halves of a broken key, a torn cloak, or a leaking wineskin. As long as the break or tear is no larger than 1 foot in any dimension, you mend it, leaving no trace of the former damage.\nThis spell can physically repair a magic item, but it can't restore magic to such an object.","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Mending","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Message","constant":false,"content":"## Message (전달) - Cantrip Transmutation spell, SRD 5.2.1\nClasses: Bard, Druid, Sorcerer, Wizard. Casting Time: Action. Range: 120 feet. Components: S, M (a copper wire). Duration: 1 round 149.\nYou point toward a creature within range and whisper a message. The target (and only the target) hears the message and can reply in a whisper that only you can hear.\nYou can cast this spell through solid objects if you are familiar with the target and know it is beyond the barrier. Magical silence; 1 foot of stone, metal, or wood; or a thin sheet of lead blocks the spell.","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Message","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Meteor Swarm","constant":false,"content":"## Meteor Swarm (유성 폭풍) - Level 9 Evocation spell, SRD 5.2.1\nClasses: Sorcerer, Wizard. Casting Time: Action. Range: 1 mile. Components: V, S. Duration: Instantaneous.\nBlazing orbs of fire plummet to the ground at four different points you can see within range. Each creature in a 40-foot-radius Sphere centered on each of those points makes a Dexterity saving throw. A creature takes 20d6 Fire damage and 20d6 Bludgeoning damage on a failed save or half as much damage on a successful one. A creature in the area of more than one fiery Sphere is affected only once.\nA nonmagical object that isn't being worn or carried also takes the damage if it's in the spell's area, and the object starts burning if it's flammable.","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Meteor Swarm","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Mind Blank","constant":false,"content":"## Mind Blank (정신 공백) - Level 8 Abjuration spell, SRD 5.2.1\nClasses: Bard, Wizard. Casting Time: Action. Range: Touch. Components: V, S. Duration: 24 hours.\nUntil the spell ends, one willing creature you touch has Immunity to Psychic damage and the Charmed condition. The target is also unaffected by anything that would sense its emotions or alignment, read its thoughts, or magically detect its location, and no spell—not even Wish—can gather information about the target, observe it remotely, or control its mind.","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Mind Blank","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Mind Spike","constant":false,"content":"## Mind Spike (정신 가시) - Level 2 Divination spell, SRD 5.2.1\nClasses: Sorcerer, Warlock, Wizard. Casting Time: Action. Range: 120 feet. Components: S. Duration: Concentration, up to 1 hour.\nYou drive a spike of psionic energy into the mind of one creature you can see within range. The target makes a Wisdom saving throw, taking 3d8 Psychic damage on a failed save or half as much damage on a successful one. On a failed save, you also always know the target's location until the spell ends, but only while the two of you are on the same plane of existence. While you have this knowledge, the target can't become hidden from you, and if it has the Invisible condition, it gains no benefit from that condition against you.\nUsing a Higher-Level Spell Slot. The damage increases by 1d8 for each spell slot level above 2.","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Mind Spike","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Minor Illusion","constant":false,"content":"## Minor Illusion (하급 환영) - Cantrip Illusion spell, SRD 5.2.1\nClasses: Bard, Sorcerer, Warlock, Wizard. Casting Time: Action. Range: 30 feet. Components: S, M (a bit of fleece). Duration: 1 minute.\nYou create a sound or an image of an object within range that lasts for the duration. See the descriptions below for the effects of each. The illusion ends if you cast this spell again.\nIf a creature takes a Study action to examine the sound or image, the creature can determine that it is an illusion with a successful Intelligence (Investigation) check against your spell save DC. If a creature discerns the illusion for what it is, the illusion becomes faint to the creature.\nSound. If you create a sound, its volume can range from a whisper to a scream. It can be your voice, someone else's voice, a lion's roar, a beating of drums, or any other sound you choose. The sound continues unabated throughout the duration, or you can make discrete sounds at different times before the spell ends.\nImage. If you create an image of an object—such as a chair, muddy footprints, or a small chest—it must be no larger than a 5-foot Cube. The image can't create sound, light, smell, or any other sensory effect. Physical interaction with the image reveals it to be an illusion, since things can pass through it.","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Minor Illusion","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Mirage Arcane","constant":false,"content":"## Mirage Arcane (비전 신기루) - Level 7 Illusion spell, SRD 5.2.1\nClasses: Bard, Druid, Wizard. Casting Time: 10 minutes. Range: Sight. Components: V, S. Duration: 10 days.\nYou make terrain in an area up to 1 mile square look, sound, smell, and even feel like some other sort of terrain. Open fields or a road could be made to resemble a swamp, hill, crevasse, or some other rough or impassable terrain. A pond can be made to seem like a grassy meadow, a precipice like a gentle slope, or a rock-strewn gully like a wide and smooth road.\nSimilarly, you can alter the appearance of structures or add them where none are present. The spell doesn't disguise, conceal, or add creatures.\nThe illusion includes audible, visual, tactile, and olfactory elements, so it can turn clear ground 150 into Difficult Terrain (or vice versa) or otherwise impede movement through the area. Any piece of the illusory terrain (such as a rock or stick) that is removed from the spell's area disappears immediately.\nCreatures with Truesight can see through the illusion to the terrain's true form; however, all other elements of the illusion remain, so while the creature is aware of the illusion's presence, the creature can still physically interact with the illusion.","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Mirage Arcane","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Mirror Image","constant":false,"content":"## Mirror Image (거울 분신) - Level 2 Illusion spell, SRD 5.2.1\nClasses: Bard, Sorcerer, Warlock, Wizard. Casting Time: Action. Range: Self. Components: V, S. Duration: 1 minute.\nThree illusory duplicates of yourself appear in your space. Until the spell ends, the duplicates move with you and mimic your actions, shifting position so it's impossible to track which image is real.\nEach time a creature hits you with an attack roll during the spell's duration, roll a d6 for each of your remaining duplicates. If any of the d6s rolls a 3 or higher, one of the duplicates is hit instead of you, and the duplicate is destroyed. The duplicates otherwise ignore all other damage and effects. The spell ends when all three duplicates are destroyed.\nA creature is unaffected by this spell if it has the Blinded condition, Blindsight, or Truesight.","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Mirror Image","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Mislead","constant":false,"content":"## Mislead (오도) - Level 5 Illusion spell, SRD 5.2.1\nClasses: Bard, Warlock, Wizard. Casting Time: Action. Range: Self. Components: S. Duration: Concentration, up to 1 hour.\nYou gain the Invisible condition at the same time that an illusory double of you appears where you are standing. The double lasts for the duration, but the invisibility ends immediately after you make an attack roll, deal damage, or cast a spell.\nAs a Magic action, you can move the illusory double up to twice your Speed and make it gesture, speak, and behave in whatever way you choose. It is intangible and invulnerable.\nYou can see through its eyes and hear through its ears as if you were located where it is.","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Mislead","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Misty Step","constant":false,"content":"## Misty Step (안개 걸음) - Level 2 Conjuration spell, SRD 5.2.1\nClasses: Sorcerer, Warlock, Wizard. Casting Time: Bonus Action. Range: Self. Components: V. Duration: Instantaneous.\nBriefly surrounded by silvery mist, you teleport up to 30 feet to an unoccupied space you can see.","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Misty Step","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Modify Memory","constant":false,"content":"## Modify Memory (기억 조작) - Level 5 Enchantment spell, SRD 5.2.1\nClasses: Bard, Wizard. Casting Time: Action. Range: 30 feet. Components: V, S. Duration: Concentration, up to 1 minute.\nYou attempt to reshape another creature's memories. One creature that you can see within range makes a Wisdom saving throw. If you are fighting the creature, it has Advantage on the save. On a failed save, the target has the Charmed condition for the duration. While Charmed in this way, the target also has the Incapacitated condition and is unaware of its surroundings, though it can hear you. If it takes any damage or is targeted by another spell, this spell ends, and no memories are modified.\nWhile this charm lasts, you can affect the target's memory of an event that it experienced within the last 24 hours and that lasted no more than 10 minutes. You can permanently eliminate all memory of the event, allow the target to recall the event with perfect clarity, change its memory of the event's details, or create a memory of some other event.\nYou must speak to the target to describe how its memories are affected, and it must be able to understand your language for the modified memories to take root. Its mind fills in any gaps in the details of your description. If the spell ends before you finish describing the modified memories, the creature's memory isn't altered. Otherwise, the modified memories take hold when the spell ends.\nA modified memory doesn't necessarily affect how a creature behaves, particularly if the memory contradicts the creature's natural inclinations, alignment, or beliefs. An illogical modified memory, such as a false memory of how much the creature enjoyed swimming in acid, is dismissed as a bad dream. The GM might deem a modified memory too nonsensical to affect a creature.\nA Remove Curse or Greater Restoration spell cast on the target restores the creature's true memory.\nUsing a Higher-Level Spell Slot. You can alter the target's memories of an event that took place up to 7 days ago (level 6 spell slot), 30 days ago (level 7 spell slot), 365 days ago (level 8 spell slot), or any time in the creature's past (level 9 spell slot).","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Modify Memory","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Moonbeam","constant":false,"content":"## Moonbeam (달빛 광선) - Level 2 Evocation spell, SRD 5.2.1\nClasses: Druid. Casting Time: Action. Range: 120 feet. Components: V, S, M (a moonseed leaf). Duration: Concentration, up to 1 minute 151.\nA silvery beam of pale light shines down in a 5-foot-radius, 40-foot-high Cylinder centered on a point within range. Until the spell ends, Dim Light fills the Cylinder, and you can take a Magic action on later turns to move the Cylinder up to 60 feet.\nWhen the Cylinder appears, each creature in it makes a Constitution saving throw. On a failed save, a creature takes 2d10 Radiant damage, and if the creature is shape-shifted (as a result of the Polymorph spell, for example), it reverts to its true form and can't shape-shift until it leaves the Cylinder.\nOn a successful save, a creature takes half as much damage only. A creature also makes this save when the spell's area moves into its space and when it enters the spell's area or ends its turn there. A creature makes this save only once per turn.\nUsing a Higher-Level Spell Slot. The damage increases by 1d10 for each spell slot level above 2.","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Moonbeam","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Move Earth","constant":false,"content":"## Move Earth (흙 옮기기) - Level 6 Transmutation spell, SRD 5.2.1\nClasses: Druid, Sorcerer, Wizard. Casting Time: Action. Range: 120 feet. Components: V, S, M (a miniature shovel). Duration: Concentration, up to 2 hours.\nChoose an area of terrain no larger than 40 feet on a side within range. You can reshape dirt, sand, or clay in the area in any manner you choose for the duration. You can raise or lower the area's elevation, create or fill in a trench, erect or flatten a wall, or form a pillar. The extent of any such changes can't exceed half the area's largest dimension. For example, if you affect a 40-foot square, you can create a pillar up to 20 feet high, raise or lower the square's elevation by up to 20 feet, dig a trench up to 20 feet deep, and so on. It takes 10 minutes for these changes to complete. Because the terrain's transformation occurs slowly, creatures in the area can't usually be trapped or injured by the ground's movement.\nAt the end of every 10 minutes you spend concentrating on the spell, you can choose a new area of terrain to affect within range.\nThis spell can't manipulate natural stone or stone construction. Rocks and structures shift to accommodate the new terrain. If the way you shape the terrain would make a structure unstable, it might collapse.\nSimilarly, this spell doesn't directly affect plant growth. The moved earth carries any plants along with it.","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Move Earth","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Nondetection","constant":false,"content":"## Nondetection (탐지방어) - Level 3 Abjuration spell, SRD 5.2.1\nClasses: Bard, Ranger, Wizard. Casting Time: Action. Range: Touch. Components: V, S, M (a pinch of diamond dust worth 25+ GP, which the spell consumes). Duration: 8 hours.\nFor the duration, you hide a target that you touch from Divination spells. The target can be a willing creature, or it can be a place or an object no larger than 10 feet in any dimension. The target can't be targeted by any Divination spell or perceived through magical scrying sensors.","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Nondetection","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Passwall","constant":false,"content":"## Passwall (벽 통과) - Level 5 Transmutation spell, SRD 5.2.1\nClasses: Wizard. Casting Time: Action. Range: 30 feet. Components: V, S, M (a pinch of sesame seeds). Duration: 1 hour.\nA passage appears at a point that you can see on a wooden, plaster, or stone surface (such as a wall, ceiling, or floor) within range and lasts for the duration. You choose the opening's dimensions: up to 5 feet wide, 8 feet tall, and 20 feet deep. The passage creates no instability in a structure surrounding it.\nWhen the opening disappears, any creatures or objects still in the passage created by the spell are safely ejected to an unoccupied space nearest to the surface on which you cast the spell.","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Passwall","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Pass without Trace","constant":false,"content":"## Pass without Trace (흔적 없는 이동) - Level 2 Abjuration spell, SRD 5.2.1\nClasses: Druid, Ranger. Casting Time: Action. Range: Self. Components: V, S, M (ashes from burned mistletoe). Duration: Concentration, up to 1 hour.\nYou radiate a concealing aura in a 30-foot Emanation for the duration. While in the aura, you and each creature you choose have a +10 bonus to Dexterity (Stealth) checks and leave no tracks.","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Pass without Trace","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Phantasmal Force","constant":false,"content":"## Phantasmal Force (환영력) - Level 2 Illusion spell, SRD 5.2.1\nClasses: Bard, Sorcerer, Wizard. Casting Time: Action. Range: 60 feet. Components: V, S, M (a bit of fleece). Duration: Concentration, up to 1 minute.\nYou attempt to craft an illusion in the mind of a creature you can see within range. The target makes an Intelligence saving throw. On a failed save, you create a phantasmal object, creature, or other phenomenon that is no larger than a 10-foot Cube and that is perceivable only to the target for the duration. The phantasm includes sound, temperature, and other stimuli.\nThe target can take a Study action to examine the phantasm with an Intelligence (Investigation) check against your spell save DC. If the check succeeds, 152 the target realizes that the phantasm is an illusion, and the spell ends.\nWhile affected by the spell, the target treats the phantasm as if it were real and rationalizes any illogical outcomes from interacting with it. For example, if the target steps through a phantasmal bridge and survives the fall, it believes the bridge exists and something else caused it to fall.\nAn affected target can even take damage from the illusion if the phantasm represents a dangerous creature or hazard. On each of your turns, such a phantasm can deal 2d8 Psychic damage to the target if it is in the phantasm's area or within 5 feet of the phantasm. The target perceives the damage as a type appropriate to the illusion.","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Phantasmal Force","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Phantasmal Killer","constant":false,"content":"## Phantasmal Killer (환영 살해자) - Level 4 Illusion spell, SRD 5.2.1\nClasses: Bard, Wizard. Casting Time: Action. Range: 120 feet. Components: V, S. Duration: Concentration, up to 1 minute.\nYou tap into the nightmares of a creature you can see within range and create an illusion of its deepest fears, visible only to that creature. The target makes a Wisdom saving throw. On a failed save, the target takes 4d10 Psychic damage and has Disadvantage on ability checks and attack rolls for the duration. On a successful save, the target takes half as much damage, and the spell ends.\nFor the duration, the target makes a Wisdom saving throw at the end of each of its turns. On a failed save, it takes the Psychic damage again. On a successful save, the spell ends.\nUsing a Higher-Level Spell Slot. The damage increases by 1d10 for each spell slot level above 4.","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Phantasmal Killer","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Phantom Steed","constant":false,"content":"## Phantom Steed (환영마) - Level 3 Illusion spell, SRD 5.2.1\nClasses: Wizard. Casting Time: 1 minute or Ritual. Range: 30 feet. Components: V, S. Duration: 1 hour.\nA Large, quasi-real, horselike creature appears on the ground in an unoccupied space of your choice within range. You decide the creature's appearance, and it is equipped with a saddle, bit, and bridle. Any of the equipment created by the spell vanishes in a puff of smoke if it is carried more than 10 feet away from the steed.\nFor the duration, you or a creature you choose can ride the steed. The steed uses the Riding Horse stat block (see “Monsters”), except it has a Speed of 100 feet and can travel 13 miles in an hour. When the spell ends, the steed gradually fades, giving the rider 1 minute to dismount. The spell ends early if the steed takes any damage.","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Phantom Steed","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Planar Ally","constant":false,"content":"## Planar Ally (이계의 동맹) - Level 6 Conjuration spell, SRD 5.2.1\nClasses: Cleric. Casting Time: 10 minutes. Range: 60 feet. Components: V, S. Duration: Instantaneous.\nYou beseech an otherworldly entity for aid. The being must be known to you: a god, a demon prince, or some other being of cosmic power. That entity sends a Celestial, an Elemental, or a Fiend loyal to it to aid you, making the creature appear in an unoccupied space within range. If you know a specific creature's name, you can speak that name when you cast this spell to request that creature, though you might get a different creature anyway (GM's choice).\nWhen the creature appears, it is under no compulsion to behave a particular way. You can ask it to perform a service in exchange for payment, but it isn't obliged to do so. The requested task could range from simple (fly us across the chasm, or help us fight a battle) to complex (spy on our enemies, or protect us during our foray into the dungeon). You must be able to communicate with the creature to bargain for its services.\nPayment can take a variety of forms. A Celestial might require a sizable donation of gold or magic items to an allied temple, while a Fiend might demand a living sacrifice or a gift of treasure. Some creatures might exchange their service for a quest undertaken by you.\nA task that can be measured in minutes requires a payment worth 100 GP per minute. A task measured in hours requires 1,000 GP per hour. And a task measured in days (up to 10 days) requires 10,000 GP per day. The GM can adjust these payments based on the circumstances under which you cast the spell. If the task is aligned with the creature's ethos, the payment might be halved or even waived.\nNonhazardous tasks typically require only half the suggested payment, while especially dangerous tasks might require a greater gift. Creatures rarely accept tasks that seem suicidal.\nAfter the creature completes the task, or when the agreed-upon duration of service expires, the creature returns to its home plane after reporting back to you if possible. If you are unable to agree on a price for the creature's service, the creature immediately returns to its home plane.","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Planar Ally","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Planar Binding","constant":false,"content":"## Planar Binding (이계 속박) - Level 5 Abjuration spell, SRD 5.2.1\nClasses: Bard, Cleric, Druid, Warlock, Wizard. Casting Time: 1 hour. Range: 60 feet. Components: V, S, M (a jewel worth 1,000+ GP, which the spell consumes). Duration: 24 hours 153.\nYou attempt to bind a Celestial, an Elemental, a Fey, or a Fiend to your service. The creature must be within range for the entire casting of the spell. (Typically, the creature is first summoned into the center of the inverted version of the Magic Circle spell to trap it while this spell is cast.) At the completion of the casting, the target must succeed on a Charisma saving throw or be bound to serve you for the duration. If the creature was summoned or created by another spell, that spell's duration is extended to match the duration of this spell.\nA bound creature must follow your commands to the best of its ability. You might command the creature to accompany you on an adventure, to guard a location, or to deliver a message. If the creature is Hostile, it strives to twist your commands to achieve its own objectives. If the creature carries out your commands completely before the spell ends, it travels to you to report this fact if you are on the same plane of existence. If you are on a different plane, it returns to the place where you bound it and remains there until the spell ends.\nUsing a Higher-Level Spell Slot. The duration increases with a spell slot of level 6 (10 days), 7 (30 days), 8 (180 days), and 9 (366 days).","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Planar Binding","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Plane Shift","constant":false,"content":"## Plane Shift (차원 이동) - Level 7 Conjuration spell, SRD 5.2.1\nClasses: Cleric, Druid, Sorcerer, Warlock, Wizard. Casting Time: Action. Range: Touch. Components: V, S, M (a forked, metal rod worth 250+ GP and attuned to a plane of existence). Duration: Instantaneous.\nYou and up to eight willing creatures who link hands in a circle are transported to a different plane of existence. You can specify a target destination in general terms, such as a specific city on the Elemental Plane of Fire or palace on the second level of the Nine Hells, and you appear in or near that destination, as determined by the GM.\nAlternatively, if you know the sigil sequence of a teleportation circle on another plane of existence, this spell can take you to that circle. If the teleportation circle is too small to hold all the creatures you transported, they appear in the closest unoccupied spaces next to the circle.","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Plane Shift","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Plant Growth","constant":false,"content":"## Plant Growth (식물 성장) - Level 3 Transmutation spell, SRD 5.2.1\nClasses: Bard, Druid, Ranger. Casting Time: Action (Overgrowth) or 8 hours (Enrichment). Range: 150 feet. Components: V, S. Duration: Instantaneous.\nThis spell channels vitality into plants. The casting time you use determines whether the spell has the Overgrowth or the Enrichment effect below.\nOvergrowth. Choose a point within range. All normal plants in a 100-foot-radius Sphere centered on that point become thick and overgrown. A creature moving through that area must spend 4 feet of movement for every 1 foot it moves. You can exclude one or more areas of any size within the spell's area from being affected.\nEnrichment. All plants in a half-mile radius centered on a point within range become enriched for 365 days. The plants yield twice the normal amount of food when harvested. They can benefit from only one Plant Growth per year.","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Plant Growth","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Poison Spray","constant":false,"content":"## Poison Spray (독 분사) - Cantrip Necromancy spell, SRD 5.2.1\nClasses: Druid, Sorcerer, Warlock, Wizard. Casting Time: Action. Range: 30 feet. Components: V, S. Duration: Instantaneous.\nYou spray toxic mist at a creature within range.\nMake a ranged spell attack against the target. On a hit, the target takes 1d12 Poison damage.\nCantrip Upgrade. The damage increases by 1d12 when you reach levels 5 (2d12), 11 (3d12), and 17 (4d12).","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Poison Spray","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Polymorph","constant":false,"content":"## Polymorph (변신) - Level 4 Transmutation spell, SRD 5.2.1\nClasses: Bard, Druid, Sorcerer, Wizard. Casting Time: Action. Range: 60 feet. Components: V, S, M (a caterpillar cocoon). Duration: Concentration, up to 1 hour.\nYou attempt to transform a creature that you can see within range into a Beast. The target must succeed on a Wisdom saving throw or shape-shift into a Beast form for the duration. That form can be any Beast you choose that has a Challenge Rating equal to or less than the target's (or the target's level if it doesn't have a Challenge Rating). The target's game statistics are replaced by the stat block of the chosen Beast, but the target retains its alignment, personality, creature type, Hit Points, and Hit Point Dice. See the “Animals” section of “Monsters” for a sample of Beast stat blocks.\nThe target gains a number of Temporary Hit Points equal to the Hit Points of the Beast form.\nThese Temporary Hit Points vanish if any remain when the spell ends. The spell ends early on the target if it has no Temporary Hit Points left.\nThe target is limited in the actions it can perform by the anatomy of its new form, and it can't speak or cast spells. 154 The target's gear melds into the new form. The creature can't use or otherwise benefit from any of that equipment.","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Polymorph","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Power Word Heal","constant":false,"content":"## Power Word Heal (권능어: 치유) - Level 9 Enchantment spell, SRD 5.2.1\nClasses: Bard, Cleric. Casting Time: Action. Range: 60 feet Component: V. Components: . Duration: Instantaneous.\nA wave of healing energy washes over one creature you can see within range. The target regains all its Hit Points. If the creature has the Charmed, Frightened, Paralyzed, Poisoned, or Stunned condition, the condition ends. If the creature has the Prone condition, it can use its Reaction to stand up.","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Power Word Heal","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Power Word Kill","constant":false,"content":"## Power Word Kill (권능어: 죽음) - Level 9 Enchantment spell, SRD 5.2.1\nClasses: Bard, Sorcerer, Warlock, Wizard. Casting Time: Action. Range: 60 feet Component: V. Components: . Duration: Instantaneous.\nYou compel one creature you can see within range to die. If the target has 100 Hit Points or fewer, it dies. Otherwise, it takes 12d12 Psychic damage.","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Power Word Kill","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Power Word Stun","constant":false,"content":"## Power Word Stun (권능어: 기절) - Level 8 Enchantment spell, SRD 5.2.1\nClasses: Bard, Sorcerer, Warlock, Wizard. Casting Time: Action. Range: 60 feet. Components: V. Duration: Instantaneous.\nYou overwhelm the mind of one creature you can see within range. If the target has 150 Hit Points or fewer, it has the Stunned condition. Otherwise, its Speed is 0 until the start of your next turn.\nThe Stunned target makes a Constitution saving throw at the end of each of its turns, ending the condition on itself on a success.","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Power Word Stun","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Prayer of Healing","constant":false,"content":"## Prayer of Healing (치료의 기도) - Level 2 Abjuration spell, SRD 5.2.1\nClasses: Cleric, Paladin. Casting Time: 10 minutes. Range: 30 feet. Components: V. Duration: Instantaneous.\nUp to five creatures of your choice who remain within range for the spell's entire casting gain the benefits of a Short Rest and also regain 2d8 Hit Points. A creature can't be affected by this spell again until that creature finishes a Long Rest.\nUsing a Higher-Level Spell Slot. The healing increases by 1d8 for each spell slot level above 2.","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Prayer of Healing","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Prestidigitation","constant":false,"content":"## Prestidigitation (요술) - Cantrip Transmutation spell, SRD 5.2.1\nClasses: Bard, Sorcerer, Warlock, Wizard. Casting Time: Action. Range: 10 feet. Components: V, S. Duration: Up to 1 hour.\nYou create a magical effect within range. Choose the effect from the options below. If you cast this spell multiple times, you can have up to three of its non-instantaneous effects active at a time.\nSensory Effect. You create an instantaneous, harmless sensory effect, such as a shower of sparks, a puff of wind, faint musical notes, or an odd odor.\nFire Play. You instantaneously light or snuff out a candle, a torch, or a small campfire.\nClean or Soil. You instantaneously clean or soil an object no larger than 1 cubic foot.\nMinor Sensation. You chill, warm, or flavor up to 1 cubic foot of nonliving material for 1 hour.\nMagic Mark. You make a color, a small mark, or a symbol appear on an object or a surface for 1 hour.\nMinor Creation. You create a nonmagical trinket or an illusory image that can fit in your hand. It lasts until the end of your next turn. A trinket can deal no damage and has no monetary worth.","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Prestidigitation","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Prismatic Spray","constant":false,"content":"## Prismatic Spray (무지갯빛 분사) - Level 7 Evocation spell, SRD 5.2.1\nClasses: Bard, Sorcerer, Wizard. Casting Time: Action. Range: Self. Components: V, S. Duration: Instantaneous.\nEight rays of light flash from you in a 60-foot Cone.\nEach creature in the Cone makes a Dexterity saving throw. For each target, roll 1d8 to determine which color ray affects it, consulting the Prismatic Rays table.\nPrismatic Rays 1d8 Ray 1 Red. Failed Save: 12d6 Fire damage. Successful Save: Half as much damage. 2 Orange. Failed Save: 12d6 Acid damage. Successful Save: Half as much damage. 3 Yellow. Failed Save: 12d6 Lightning damage. Successful Save: Half as much damage. 4 Green. Failed Save: 12d6 Poison damage. Successful Save: Half as much damage. 155 1d8 Ray 5 Blue. Failed Save: 12d6 Cold damage. Successful Save: Half as much damage. 6 Indigo. Failed Save: The target has the Restrained condition and makes a Constitution saving throw at the end of each of its turns. If it successfully saves three times, the condition ends. If it fails three times, it has the Petrified condition until it is freed by an effect like the Greater Restoration spell. The successes and failures needn't be consecutive; keep track of both until the target collects three of a kind. 7 Violet. Failed Save: The target has the Blinded condition and makes a Wisdom saving throw at the start of your next turn. On a successful save, the condition ends. On a failed save, the condition ends, and the creature teleports to another plane of existence (GM's choice). 8 Special. The target is struck by two rays. Roll twice, rerolling any 8.","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Prismatic Spray","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Prismatic Wall","constant":false,"content":"## Prismatic Wall (무지갯빛 벽) - Level 9 Abjuration spell, SRD 5.2.1\nClasses: Bard, Wizard. Casting Time: Action. Range: 60 feet. Components: V, S. Duration: 10 minutes.\nA shimmering, multicolored plane of light forms a vertical opaque wall—up to 90 feet long, 30 feet high, and 1 inch thick—centered on a point within range. Alternatively, you shape the wall into a globe up to 30 feet in diameter centered on a point within range. The wall lasts for the duration. If you position the wall in a space occupied by a creature, the spell ends instantly without effect.\nThe wall sheds Bright Light within 100 feet and Dim Light for an additional 100 feet. You and creatures you designate when you cast the spell can pass through and be near the wall without harm. If another creature that can see the wall moves within 20 feet of it or starts its turn there, the creature must succeed on a Constitution saving throw or have the Blinded condition for 1 minute.\nThe wall consists of seven layers, each with a different color. When a creature reaches into or passes through the wall, it does so one layer at a time through all the layers. Each layer forces the creature to make a Dexterity saving throw or be affected by that layer's properties as described in the Prismatic Layers table.\nThe wall, which has AC 10, can be destroyed one layer at a time, in order from red to violet, by means specific to each layer. If a layer is destroyed, it is gone for the duration. Antimagic Field has no effect on the wall, and Dispel Magic can affect only the violet layer.\nPrismatic Layers Order Effects 1 Red. Failed Save: 12d6 Fire damage. Successful Save: Half as much damage. Additional Effects:\nNonmagical ranged attacks can't pass through this layer, which is destroyed if it takes at least 25 Cold damage. 2 Orange. Failed Save: 12d6 Acid damage. Successful Save: Half as much damage. Additional Effects: Magical ranged attacks can't pass through this layer, which is destroyed by a strong wind (such as the one created by Gust of Wind). 3 Yellow. Failed Save: 12d6 Lightning damage.\nSuccessful Save: Half as much damage. Additional Effects: The layer is destroyed if it takes at least 60 Force damage. 4 Green. Failed Save: 12d6 Poison damage. Successful Save: Half as much damage. Additional Effects: A Passwall spell, or another spell of equal or greater level that can open a portal on a solid surface, destroys this layer. 5 Blue. Failed Save: 12d6 Cold damage. Successful Save: Half as much damage. Additional Effects: The layer is destroyed if it takes at least 25 Fire damage. 6 Indigo. Failed Save: The target has the Restrained condition and makes a Constitution saving throw at the end of each of its turns. If it successfully saves three times, the condition ends. If it fails three times, it has the Petrified condition until it is freed by an effect like the Greater Restoration spell. The successes and failures needn't be consecutive; keep track of both until the target collects three of a kind.\nAdditional Effects: Spells can't be cast through this layer, which is destroyed by Bright Light shed by the Daylight spell. 7 Violet. Failed Save: The target has the Blinded condition and makes a Wisdom saving throw at the start of your next turn. On a successful save, the condition ends. On a failed save, the condition ends, and the creature teleports to another plane of existence (GM's choice).\nAdditional Effects: This layer is destroyed by Dispel Magic. 156","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Prismatic Wall","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Private Sanctum","constant":false,"content":"## Private Sanctum (은신처) - Level 4 Abjuration spell, SRD 5.2.1\nClasses: Wizard. Casting Time: 10 minutes. Range: 120 feet. Components: V, S, M (a thin sheet of lead). Duration: 24 hours.\nYou make an area within range magically secure.\nThe area is a Cube that can be as small as 5 feet to as large as 100 feet on each side. The spell lasts for the duration.\nWhen you cast the spell, you decide what sort of security the spell provides, choosing any of the following properties: • Sound can't pass through the barrier at the edge of the warded area. • The barrier of the warded area appears dark and foggy, preventing vision (including Darkvision) through it. • Sensors created by Divination spells can't appear inside the protected area or pass through the barrier at its perimeter. • Creatures in the area can't be targeted by Divination spells. • Nothing can teleport into or out of the warded area. • Planar travel is blocked within the warded area.\nCasting this spell on the same spot every day for 365 days makes the spell last until dispelled.\nUsing a Higher-Level Spell Slot. You can increase the size of the Cube by 100 feet for each spell slot level above 4.","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Private Sanctum","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Produce Flame","constant":false,"content":"## Produce Flame (불꽃 생성) - Cantrip Conjuration spell, SRD 5.2.1\nClasses: Druid. Casting Time: Bonus Action. Range: Self. Components: V, S. Duration: 10 minutes.\nA flickering flame appears in your hand and remains there for the duration. While there, the flame emits no heat and ignites nothing, and it sheds Bright Light in a 20-foot radius and Dim Light for an additional 20 feet. The spell ends if you cast it again.\nUntil the spell ends, you can take a Magic action to hurl fire at a creature or an object within 60 feet of you. Make a ranged spell attack. On a hit, the target takes 1d8 Fire damage.\nCantrip Upgrade. The damage increases by 1d8 when you reach levels 5 (2d8), 11 (3d8), and 17 (4d8).","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Produce Flame","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Programmed Illusion","constant":false,"content":"## Programmed Illusion (예약된 환영) - Level 6 Illusion spell, SRD 5.2.1\nClasses: Bard, Wizard. Casting Time: Action. Range: 120 feet. Components: V, S, M (jade dust worth 25+ GP). Duration: Until dispelled.\nYou create an illusion of an object, a creature, or some other visible phenomenon within range that activates when a specific trigger occurs. The illusion is imperceptible until then. It must be no larger than a 30-foot Cube, and you decide when you cast the spell how the illusion behaves and what sounds it makes. This scripted performance can last up to 5 minutes.\nWhen the trigger you specify occurs, the illusion springs into existence and performs in the manner you described. Once the illusion finishes performing, it disappears and remains dormant for 10 minutes, after which the illusion can be activated again.\nThe trigger can be as general or as detailed as you like, though it must be based on visual or audible phenomena that occur within 30 feet of the area.\nFor example, you could create an illusion of yourself to appear and warn off others who attempt to open a trapped door.\nPhysical interaction with the image reveals it to be illusory, since things can pass through it. A creature that takes the Study action to examine the image can determine that it is an illusion with a successful Intelligence (Investigation) check against your spell save DC. If a creature discerns the illusion for what it is, the creature can see through the image, and any noise it makes sounds hollow to the creature.","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Programmed Illusion","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Project Image","constant":false,"content":"## Project Image (모습 투영) - Level 7 Illusion spell, SRD 5.2.1\nClasses: Bard, Wizard. Casting Time: Action. Range: 500 miles. Components: V, S, M (a statuette of yourself worth 5+ GP). Duration: Concentration, up to 1 day.\nYou create an illusory copy of yourself that lasts for the duration. The copy can appear at any location within range that you have seen before, regardless of intervening obstacles. The illusion looks and sounds like you, but it is intangible. If the illusion takes any damage, it disappears, and the spell ends.\nYou can see through the illusion's eyes and hear through its ears as if you were in its space. As a Magic action, you can move it up to 60 feet and make it gesture, speak, and behave in whatever way you choose. It mimics your mannerisms perfectly.\nPhysical interaction with the image reveals it to be illusory, since things can pass through it. A creature that takes the Study action to examine the image can determine that it is an illusion with a successful Intelligence (Investigation) check against your spell save DC. If a creature discerns the illusion for what it is, the creature can see through the 157 image, and any noise it makes sounds hollow to the creature.","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Project Image","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Protection from Energy","constant":false,"content":"## Protection from Energy (에너지로부터의 보호) - Level 3 Abjuration spell, SRD 5.2.1\nClasses: Cleric, Druid, Ranger, Sorcerer, Wizard. Casting Time: Action. Range: Touch. Components: V, S. Duration: Concentration, up to 1 hour.\nFor the duration, the willing creature you touch has Resistance to one damage type of your choice: Acid, Cold, Fire, Lightning, or Thunder.","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Protection from Energy","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Protection from Evil and Good","constant":false,"content":"## Protection from Evil and Good (악과 선으로부터의 보호) - Level 1 Abjuration spell, SRD 5.2.1\nClasses: Cleric, Druid, Paladin, Warlock, Wizard. Casting Time: Action. Range: Touch. Components: V, S, M (a flask of Holy Water worth 25+ GP, which the spell consumes). Duration: Concentration up to 10 minutes.\nUntil the spell ends, one willing creature you touch is protected against creatures that are Aberrations, Celestials, Elementals, Fey, Fiends, or Undead.\nThe protection grants several benefits. Creatures of those types have Disadvantage on attack rolls against the target. The target also can't be possessed by or gain the Charmed or Frightened conditions from them. If the target is already possessed, Charmed, or Frightened by such a creature, the target has Advantage on any new saving throw against the relevant effect.","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Protection from Evil and Good","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Protection from Poison","constant":false,"content":"## Protection from Poison (독으로부터의 보호) - Level 2 Abjuration spell, SRD 5.2.1\nClasses: Cleric, Druid, Paladin, Ranger. Casting Time: Action. Range: Touch. Components: V, S. Duration: 1 hour.\nYou touch a creature and end the Poisoned condition on it. For the duration, the target has Advantage on saving throws to avoid or end the Poisoned condition, and it has Resistance to Poison damage.","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Protection from Poison","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Purify Food and Drink","constant":false,"content":"## Purify Food and Drink (음식과 물 정화) - Level 1 Transmutation spell, SRD 5.2.1\nClasses: Cleric, Druid, Paladin. Casting Time: Action or Ritual. Range: 10 feet. Components: V, S. Duration: Instantaneous.\nYou remove poison and rot from nonmagical food and drink in a 5-foot-radius Sphere centered on a point within range.","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Purify Food and Drink","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Raise Dead","constant":false,"content":"## Raise Dead (사자 소생) - Level 5 Necromancy spell, SRD 5.2.1\nClasses: Bard, Cleric, Paladin. Casting Time: 1 hour. Range: Touch. Components: V, S, M (a diamond worth 500+ GP, which the spell consumes). Duration: Instantaneous.\nWith a touch, you revive a dead creature if it has been dead no longer than 10 days and it wasn't Undead when it died.\nThe creature returns to life with 1 Hit Point. This spell also neutralizes any poisons that affected the creature at the time of death.\nThis spell closes all mortal wounds, but it doesn't restore missing body parts. If the creature is lacking body parts or organs integral for its survival— its head, for instance—the spell automatically fails.\nComing back from the dead is an ordeal. The target takes a -4 penalty to D20 Tests. Every time the target finishes a Long Rest, the penalty is reduced by 1 until it becomes 0.","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Raise Dead","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Ray of Enfeeblement","constant":false,"content":"## Ray of Enfeeblement (무력화 광선) - Level 2 Necromancy spell, SRD 5.2.1\nClasses: Warlock, Wizard. Casting Time: Action. Range: 60 feet. Components: V, S. Duration: Concentration, up to 1 minute.\nA beam of enervating energy shoots from you toward a creature within range. The target must make a Constitution saving throw. On a successful save, the target has Disadvantage on the next attack roll it makes until the start of your next turn.\nOn a failed save, the target has Disadvantage on Strength-based D20 Tests for the duration. During that time, it also subtracts 1d8 from all its damage rolls. The target repeats the save at the end of each of its turns, ending the spell on a success.","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Ray of Enfeeblement","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Ray of Frost","constant":false,"content":"## Ray of Frost (서리 광선) - Cantrip Evocation spell, SRD 5.2.1\nClasses: Sorcerer, Wizard. Casting Time: Action. Range: 60 feet. Components: V, S. Duration: Instantaneous.\nA frigid beam of blue-white light streaks toward a creature within range. Make a ranged spell attack against the target. On a hit, it takes 1d8 Cold damage, and its Speed is reduced by 10 feet until the start of your next turn.\nCantrip Upgrade. The damage increases by 1d8 when you reach levels 5 (2d8), 11 (3d8), and 17 (4d8). 158","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Ray of Frost","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Regenerate","constant":false,"content":"## Regenerate (재생) - Level 7 Transmutation spell, SRD 5.2.1\nClasses: Bard, Cleric, Druid. Casting Time: 1 minute. Range: Touch. Components: V, S, M (a prayer wheel). Duration: 1 hour.\nA creature you touch regains 4d8 + 15 Hit Points.\nFor the duration, the target regains 1 Hit Point at the start of each of its turns, and any severed body parts regrow after 2 minutes.","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Regenerate","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Ray of Sickness","constant":false,"content":"## Ray of Sickness (통증 광선) - Level 1 Necromancy spell, SRD 5.2.1\nClasses: Sorcerer, Wizard. Casting Time: Action. Range: 60 feet. Components: V, S. Duration: Instantaneous.\nYou shoot a greenish ray at a creature within range.\nMake a ranged spell attack against the target. On a hit, the target takes 2d8 Poison damage and has the Poisoned condition until the end of your next turn.\nUsing a Higher-Level Spell Slot. The damage increases by 1d8 for each spell slot level above 1.","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Ray of Sickness","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Reincarnate","constant":false,"content":"## Reincarnate (환생) - Level 5 Necromancy spell, SRD 5.2.1\nClasses: Druid. Casting Time: 1 hour. Range: Touch. Components: V, S, M (rare oils worth 1,000+ GP, which the spell consumes). Duration: Instantaneous.\nYou touch a dead Humanoid or a piece of one. If the creature has been dead no longer than 10 days, the spell forms a new body for it and calls the soul to enter that body. Roll 1d10 and consult the table below to determine the body's species, or the GM chooses another playable species. 1d10 Species 1d10 Species 1 Roll again. 6 Goliath 2 Dragonborn 7 Halfling 3 Dwarf 8 Human 4 Elf 9 Orc 5 Gnome 10 Tiefling The reincarnated creature makes any choices that a species' description offers, and the creature recalls its former life. It retains the capabilities it had in its original form, except it loses the traits of its previous species and gains the traits of its new one.","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Reincarnate","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Remove Curse","constant":false,"content":"## Remove Curse (저주 해제) - Level 3 Abjuration spell, SRD 5.2.1\nClasses: Cleric, Paladin, Warlock, Wizard. Casting Time: Action. Range: Touch. Components: V, S. Duration: Instantaneous.\nAt your touch, all curses affecting one creature or object end. If the object is a cursed magic item, its curse remains, but the spell breaks its owner's Attunement to the object so it can be removed or discarded.","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Remove Curse","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Resilient Sphere","constant":false,"content":"## Resilient Sphere (탄성 구체) - Level 4 Abjuration spell, SRD 5.2.1\nClasses: Wizard. Casting Time: Action. Range: 30 feet. Components: V, S, M (a glass sphere). Duration: Concentration, up to 1 minute.\nA shimmering sphere encloses a Large or smaller creature or object within range. An unwilling creature must succeed on a Dexterity saving throw or be enclosed for the duration.\nNothing—not physical objects, energy, or other spell effects—can pass through the barrier, in or out, though a creature in the sphere can breathe there. The sphere is immune to all damage, and a creature or object inside can't be damaged by attacks or effects originating from outside, nor can a creature inside the sphere damage anything outside it.\nThe sphere is weightless and just large enough to contain the creature or object inside. An enclosed creature can take an action to push against the sphere's walls and thus roll the sphere at up to half the creature's Speed. Similarly, the globe can be picked up and moved by other creatures.\nA Disintegrate spell targeting the globe destroys it without harming anything inside.","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Resilient Sphere","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Resistance","constant":false,"content":"## Resistance (저항) - Cantrip Abjuration spell, SRD 5.2.1\nClasses: Cleric, Druid. Casting Time: Action. Range: Touch Component: V, S. Components: . Duration: Concentration, up to 1 minute.\nYou touch a willing creature and choose a damage type: Acid, Bludgeoning, Cold, Fire, Lightning, Necrotic, Piercing, Poison, Radiant, Slashing, or Thunder. When the creature takes damage of the chosen type before the spell ends, the creature reduces the total damage taken by 1d4. A creature can benefit from this spell only once per turn.","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Resistance","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Resurrection","constant":false,"content":"## Resurrection (부활) - Level 7 Necromancy spell, SRD 5.2.1\nClasses: Bard, Cleric. Casting Time: 1 hour. Range: Touch. Components: V, S, M (a diamond worth 1,000+ GP, which the spell consumes). Duration: Instantaneous 159.\nWith a touch, you revive a dead creature that has been dead for no more than a century, didn't die of old age, and wasn't Undead when it died.\nThe creature returns to life with all its Hit Points.\nThis spell also neutralizes any poisons that affected the creature at the time of death. This spell closes all mortal wounds and restores any missing body parts.\nComing back from the dead is an ordeal. The target takes a -4 penalty to D20 Tests. Every time the target finishes a Long Rest, the penalty is reduced by 1 until it becomes 0.\nCasting this spell to revive a creature that has been dead for 365 days or longer taxes you. Until you finish a Long Rest, you can't cast spells again, and you have Disadvantage on D20 Tests.","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Resurrection","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Reverse Gravity","constant":false,"content":"## Reverse Gravity (중력 반전) - Level 7 Transmutation spell, SRD 5.2.1\nClasses: Druid, Sorcerer, Wizard. Casting Time: Action. Range: 100 feet. Components: V, S, M (a lodestone and iron filings). Duration: Concentration, up to 1 minute.\nThis spell reverses gravity in a 50-foot-radius, 100foot high Cylinder centered on a point within range.\nAll creatures and objects in that area that aren't anchored to the ground fall upward and reach the top of the Cylinder. A creature can make a Dexterity saving throw to grab a fixed object it can reach, thus avoiding the fall upward.\nIf a ceiling or an anchored object is encountered in this upward fall, creatures and objects strike it just as they would during a downward fall. If an affected creature or object reaches the Cylinder's top without striking anything, it hovers there for the duration. When the spell ends, affected objects and creatures fall downward.","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Reverse Gravity","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Revivify","constant":false,"content":"## Revivify (재활성화) - Level 3 Necromancy spell, SRD 5.2.1\nClasses: Cleric, Druid, Paladin, Ranger. Casting Time: Action. Range: Touch. Components: V, S, M (a diamond worth 300+ GP, which the spell consumes). Duration: Instantaneous.\nYou touch a creature that has died within the last minute. That creature revives with 1 Hit Point. This spell can't revive a creature that has died of old age, nor does it restore any missing body parts.","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Revivify","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Rope Trick","constant":false,"content":"## Rope Trick (로프 속임수) - Level 2 Transmutation spell, SRD 5.2.1\nClasses: Wizard. Casting Time: Action. Range: Touch. Components: V, S, M (a segment of rope). Duration: 1 hour.\nYou touch a rope. One end of it hovers upward until the rope hangs perpendicular to the ground or the rope reaches a ceiling. At the rope's upper end, an Invisible 3-foot-by-5-foot portal opens to an extra­ dimensional space that lasts until the spell ends.\nThat space can be reached by climbing the rope, which can be pulled into or dropped out of it.\nThe space can hold up to eight Medium or smaller creatures. Attacks, spells, and other effects can't pass into or out of the space, but creatures inside it can see through the portal. Anything inside the space drops out when the spell ends.","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Rope Trick","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Sacred Flame","constant":false,"content":"## Sacred Flame (신성한 불길) - Cantrip Evocation spell, SRD 5.2.1\nClasses: Cleric. Casting Time: Action. Range: 60 feet. Components: V, S. Duration: Instantaneous.\nFlame-like radiance descends on a creature that you can see within range. The target must succeed on a Dexterity saving throw or take 1d8 Radiant damage. The target gains no benefit from Half Cover or Three-Quarters Cover for this save.\nCantrip Upgrade. The damage increases by 1d8 when you reach levels 5 (2d8), 11 (3d8), and 17 (4d8).","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Sacred Flame","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Sanctuary","constant":false,"content":"## Sanctuary (성역화) - Level 1 Abjuration spell, SRD 5.2.1\nClasses: Cleric. Casting Time: Bonus Action. Range: 30 feet. Components: V, S, M (a shard of glass from a mirror). Duration: 1 minute.\nYou ward a creature within range. Until the spell ends, any creature who targets the warded creature with an attack roll or a damaging spell must succeed on a Wisdom saving throw or either choose a new target or lose the attack or spell. This spell doesn't protect the warded creature from areas of effect. The spell ends if the warded creature makes an attack roll, casts a spell, or deals damage.","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Sanctuary","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Scorching Ray","constant":false,"content":"## Scorching Ray (타오르는 광선) - Level 2 Evocation spell, SRD 5.2.1\nClasses: Sorcerer, Wizard. Casting Time: Action. Range: 120 feet. Components: V, S. Duration: Instantaneous.\nYou hurl three fiery rays. You can hurl them at one target within range or at several. Make a ranged spell attack for each ray. On a hit, the target takes 2d6 Fire damage.\nUsing a Higher-Level Spell Slot. You create one additional ray for each spell slot level above 2. 160","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Scorching Ray","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Scrying","constant":false,"content":"## Scrying (염탐) - Level 5 Divination spell, SRD 5.2.1\nClasses: Bard, Cleric, Druid, Warlock, Wizard. Casting Time: 10 minutes. Range: Self. Components: V, S, M (a focus worth 1,000+ GP, such as a crystal ball, mirror, or water-filled font). Duration: Concentration, up to 10 minutes.\nYou can see and hear a creature you choose that is on the same plane of existence as you. The target makes a Wisdom saving throw, which is modified (see the tables below) by how well you know the target and the sort of physical connection you have to it. The target doesn't know what it is making the save against, only that it feels uneasy.\nYour Knowledge of the Target Is … Save Modifier Secondhand (heard of the target) +5 Firsthand (met the target) +0 Extensive (know the target well) -5 You Have the Target's … Save Modifier Picture or other likeness -2 Garment or other possession -4 Body part, lock of hair, or bit of nail -10 On a successful save, the target isn't affected, and you can't use this spell on it again for 24 hours.\nOn a failed save, the spell creates an Invisible, intangible sensor within 10 feet of the target. You can see and hear through the sensor as if you were there. The sensor moves with the target, remaining within 10 feet of it for the duration. If something can see the sensor, it appears as a luminous orb about the size of your fist.\nInstead of targeting a creature, you can target a location you have seen. When you do so, the sensor appears at that location and doesn't move.","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Scrying","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Searing Smite","constant":false,"content":"## Searing Smite (작열하는 강타) - Level 1 Evocation spell, SRD 5.2.1\nClasses: Paladin. Casting Time: Bonus Action, which you take immedi- ately after hitting a target with a Melee weapon or an Unarmed Strike. Range: Self Component: V. Components: . Duration: 1 minute.\nAs you hit the target, it takes an extra 1d6 Fire damage from the attack. At the start of each of its turns until the spell ends, the target takes 1d6 Fire damage and then makes a Constitution saving throw.\nOn a failed save, the spell continues. On a successful save, the spell ends.\nUsing a Higher-Level Spell Slot. All the damage increases by 1d6 for each spell slot level above 1.","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Searing Smite","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Secret Chest","constant":false,"content":"## Secret Chest (비밀 상자) - Level 4 Conjuration spell, SRD 5.2.1\nClasses: Wizard. Casting Time: Action. Range: Touch. Components: V, S, M (a chest, 3 feet by 2 feet by 2 feet, constructed from rare materials worth 5,000+ GP, and a Tiny replica of the chest made from the same materi- als worth 50+ GP). Duration: Until dispelled.\nYou hide a chest and all its contents on the Ethereal Plane. You must touch the chest and the miniature replica that serve as Material components for the spell. The chest can contain up to 12 cubic feet of nonliving material (3 feet by 2 feet by 2 feet).\nWhile the chest remains on the Ethereal Plane, you can take a Magic action and touch the replica to recall the chest. It appears in an unoccupied space on the ground within 5 feet of you. You can send the chest back to the Ethereal Plane by taking a Magic action to touch the chest and the replica.\nAfter 60 days, there is a cumulative 5 percent chance at the end of each day that the spell ends.\nThe spell also ends if you cast this spell again or if the Tiny replica chest is destroyed. If the spell ends and the larger chest is on the Ethereal Plane, the chest remains there for you or someone else to find.","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Secret Chest","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: See Invisibility","constant":false,"content":"## See Invisibility (투명체 감지) - Level 2 Divination spell, SRD 5.2.1\nClasses: Bard, Sorcerer, Wizard. Casting Time: Action. Range: Self. Components: V, S, M (a pinch of talc). Duration: 1 hour.\nFor the duration, you see creatures and objects that have the Invisible condition as if they were visible, and you can see into the Ethereal Plane. Creatures and objects there appear ghostly.","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: See Invisibility","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Seeming","constant":false,"content":"## Seeming (겉모습 위장) - Level 5 Illusion spell, SRD 5.2.1\nClasses: Bard, Sorcerer, Wizard. Casting Time: Action. Range: 30 feet. Components: V, S. Duration: 8 hours.\nYou give an illusory appearance to each creature of your choice that you can see within range. An unwilling target can make a Charisma saving throw, and if it succeeds, it is unaffected by this spell.\nYou can give the same appearance or different ones to the targets. The spell can change the appearance of the targets' bodies and equipment.\nYou can make each creature seem 1 foot shorter or taller and appear heavier or lighter. A target's new appearance must have the same basic arrangement of limbs as the target, but the extent of the illusion 161 is otherwise up to you. The spell lasts for the duration.\nThe changes wrought by this spell fail to hold up to physical inspection. For example, if you use this spell to add a hat to a creature's outfit, objects pass through the hat.\nA creature that takes the Study action to examine a target can make an Intelligence (Investigation) check against your spell save DC. If it succeeds, it becomes aware that the target is disguised.","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Seeming","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Sending","constant":false,"content":"## Sending (전음) - Level 3 Divination spell, SRD 5.2.1\nClasses: Bard, Cleric, Wizard. Casting Time: Action. Range: Unlimited. Components: V, S, M (a copper wire). Duration: Instantaneous.\nYou send a short message of 25 words or fewer to a creature you have met or a creature described to you by someone who has met it. The target hears the message in its mind, recognizes you as the sender if it knows you, and can answer in a like manner immediately. The spell enables targets to understand the meaning of your message.\nYou can send the message across any distance and even to other planes of existence, but if the target is on a different plane than you, there is a 5 percent chance that the message doesn't arrive. You know if the delivery fails.\nUpon receiving your message, a creature can block your ability to reach it again with this spell for 8 hours. If you try to send another message during that time, you learn that you are blocked, and the spell fails.","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Sending","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Sequester","constant":false,"content":"## Sequester (격리) - Level 7 Transmutation spell, SRD 5.2.1\nClasses: Wizard. Casting Time: Action. Range: Touch. Components: V, S, M (gem dust worth 5,000+ GP, which the spell consumes). Duration: Until dispelled.\nWith a touch, you magically sequester an object or a willing creature. For the duration, the target has the Invisible condition and can't be targeted by Divination spells, detected by magic, or viewed remotely with magic.\nIf the target is a creature, it enters a state of suspended animation; it has the Unconscious condition, doesn't age, and doesn't need food, water, or air.\nYou can set a condition for the spell to end early.\nThe condition can be anything you choose, but it must occur or be visible within 1 mile of the target.\nExamples include “after 1,000 years” or “when the tarrasque awakens.” This spell also ends if the target takes any damage.","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Sequester","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Shapechange","constant":false,"content":"## Shapechange (형태 변화) - Level 9 Transmutation spell, SRD 5.2.1\nClasses: Druid, Wizard. Casting Time: Action. Range: Self. Components: V, S, M (a jade circlet worth 1,500+ GP). Duration: Concentration, up to 1 hour.\nYou shape-shift into another creature for the duration or until you take a Magic action to shape-shift into a different eligible form. The new form must be of a creature that has a Challenge Rating no higher than your level or Challenge Rating. You must have seen the sort of creature before, and it can't be a Construct or an Undead.\nWhen you cast the spell, you gain a number of Temporary Hit Points equal to the Hit Points of the first form into which you shape-shift. These Temporary Hit Points vanish if any remain when the spell ends.\nYour game statistics are replaced by the stat block of the chosen form, but you retain your creature type; alignment; personality; Intelligence, Wisdom, and Charisma scores; Hit Points; Hit Point Dice; proficiencies; and ability to communicate. If you have the Spellcasting feature, you retain it too.\nUpon shape-shifting, you determine whether your equipment drops to the ground or changes in size and shape to fit the new form while you're in it.","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Shapechange","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Shatter","constant":false,"content":"## Shatter (분쇄) - Level 2 Evocation spell, SRD 5.2.1\nClasses: Bard, Sorcerer, Wizard. Casting Time: Action. Range: 60 feet. Components: V, S, M (a chip of mica). Duration: Instantaneous.\nA loud noise erupts from a point of your choice within range. Each creature in a 10-foot-radius Sphere centered there makes a Constitution saving throw, taking 3d8 Thunder damage on a failed save or half as much damage on a successful one. A Construct has Disadvantage on the save.\nA nonmagical object that isn't being worn or carried also takes the damage if it's in the spell's area.\nUsing a Higher-Level Spell Slot. The damage increases by 1d8 for each spell slot level above 2.","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Shatter","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Shield","constant":false,"content":"## Shield (방패) - Level 1 Abjuration spell, SRD 5.2.1\nClasses: Sorcerer, Wizard. Casting Time: Reaction, which you take when you are hit by an attack roll or targeted by the Magic Missile spell. Range: Self. Components: V, S. Duration: 1 round.\nAn imperceptible barrier of magical force protects you. Until the start of your next turn, you have a +5 162 bonus to AC, including against the triggering attack, and you take no damage from Magic Missile.","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Shield","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Shield of Faith","constant":false,"content":"## Shield of Faith (신앙의 방패) - Level 1 Abjuration spell, SRD 5.2.1\nClasses: Cleric, Paladin. Casting Time: Bonus Action. Range: 60 feet. Components: V, S, M (a prayer scroll). Duration: Concentration, up to 10 minutes.\nA shimmering field surrounds a creature of your choice within range, granting it a +2 bonus to AC for the duration.","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Shield of Faith","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Shillelagh","constant":false,"content":"## Shillelagh (마법 곤봉) - Cantrip Transmutation spell, SRD 5.2.1\nClasses: Druid. Casting Time: Bonus Action. Range: Self. Components: V, S, M (mistletoe). Duration: 1 minute.\nA Club or Quarterstaff you are holding is imbued with nature's power. For the duration, you can use your spellcasting ability instead of Strength for the attack and damage rolls of melee attacks using that weapon, and the weapon's damage die becomes a d8. If the attack deals damage, it can be Force damage or the weapon's normal damage type (your choice).\nThe spell ends early if you cast it again or if you let go of the weapon.\nCantrip Upgrade. The damage die changes when you reach levels 5 (d10), 11 (d12), and 17 (2d6).","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Shillelagh","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Shining Smite","constant":false,"content":"## Shining Smite (빛나는 강타) - Level 2 Transmutation spell, SRD 5.2.1\nClasses: Paladin. Casting Time: Bonus Action, which you take immedi- ately after hitting a creature with a Melee weapon or an Unarmed Strike. Range: Self Component: V. Components: . Duration: Concentration, up to 1 minute.\nThe target hit by the strike takes an extra 2d6 Radiant damage from the attack. Until the spell ends, the target sheds Bright Light in a 5-foot radius, attack rolls against it have Advantage, and it can't benefit from the Invisible condition.\nUsing a Higher-Level Spell Slot. The damage increases by 1d6 for each spell slot level above 2.","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Shining Smite","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Shocking Grasp","constant":false,"content":"## Shocking Grasp (전격의 손아귀) - Cantrip Evocation spell, SRD 5.2.1\nClasses: Sorcerer, Wizard. Casting Time: Action. Range: Touch. Components: V, S. Duration: Instantaneous.\nLightning springs from you to a creature that you try to touch. Make a melee spell attack against the target. On a hit, the target takes 1d8 Lightning damage, and it can't make Opportunity Attacks until the start of its next turn.\nCantrip Upgrade. The damage increases by 1d8 when you reach levels 5 (2d8), 11 (3d8), and 17 (4d8).","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Shocking Grasp","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Silence","constant":false,"content":"## Silence (침묵) - Level 2 Illusion spell, SRD 5.2.1\nClasses: Bard, Cleric, Ranger. Casting Time: Action or Ritual. Range: 120 feet. Components: V, S. Duration: Concentration, up to 10 minutes.\nFor the duration, no sound can be created within or pass through a 20-foot-radius Sphere centered on a point you choose within range. Any creature or object entirely inside the Sphere has Immunity to Thunder damage, and creatures have the Deafened condition while entirely inside it. Casting a spell that includes a Verbal component is impossible there.","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Silence","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Silent Image","constant":false,"content":"## Silent Image (조용한 영상) - Level 1 Illusion spell, SRD 5.2.1\nClasses: Bard, Sorcerer, Wizard. Casting Time: Action. Range: 60 feet. Components: V, S, M (a bit of fleece). Duration: Concentration, up to 10 minutes.\nYou create the image of an object, a creature, or some other visible phenomenon that is no larger than a 15-foot Cube. The image appears at a spot within range and lasts for the duration. The image is purely visual; it isn't accompanied by sound, smell, or other sensory effects.\nAs a Magic action, you can cause the image to move to any spot within range. As the image changes location, you can alter its appearance so that its movements appear natural for the image.\nFor example, if you create an image of a creature and move it, you can alter the image so that it appears to be walking.\nPhysical interaction with the image reveals it to be an illusion, since things can pass through it. A creature that takes a Study action to examine the image can determine that it is an illusion with a successful Intelligence (Investigation) check against your spell save DC. If a creature discerns the illusion for what it is, the creature can see through the image.","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Silent Image","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Simulacrum","constant":false,"content":"## Simulacrum (분신 창조) - Level 7 Illusion spell, SRD 5.2.1\nClasses: Wizard. Casting Time: 12 hours. Range: Touch. Components: V, S, M (powdered ruby worth 1,500+ GP, which the spell consumes). Duration: Until dispelled 163.\nYou create a simulacrum of one Beast or Humanoid that is within 10 feet of you for the entire casting of the spell. You finish the casting by touching both the creature and a pile of ice or snow that is the same size as that creature, and the pile turns into the simulacrum, which is a creature. It uses the game statistics of the original creature at the time of casting, except it is a Construct, its Hit Point maximum is half as much, and it can't cast this spell.\nThe simulacrum is Friendly to you and creatures you designate. It obeys your commands and acts on your turn in combat. The simulacrum can't gain levels, and it can't take Short or Long Rests.\nIf the simulacrum takes damage, the only way to restore its Hit Points is to repair it as you take a Long Rest, during which you expend components worth 100 GP per Hit Point restored. The simulacrum must stay within 5 feet of you for the repair.\nThe simulacrum lasts until it drops to 0 Hit Points, at which point it reverts to snow and melts away. If you cast this spell again, any simulacrum you created with this spell is instantly destroyed.","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Simulacrum","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Sleep","constant":false,"content":"## Sleep (수면) - Level 1 Enchantment spell, SRD 5.2.1\nClasses: Bard, Sorcerer, Wizard. Casting Time: Action. Range: 60 feet. Components: V, S, M (a pinch of sand or rose petals). Duration: Concentration, up to 1 minute.\nEach creature of your choice in a 5-foot-radius Sphere centered on a point within range must succeed on a Wisdom saving throw or have the Incapacitated condition until the end of its next turn, at which point it must repeat the save. If the target fails the second save, the target has the Unconscious condition for the duration. The spell ends on a target if it takes damage or someone within 5 feet of it takes an action to shake it out of the spell's effect.\nCreatures that don't sleep, such as elves, or that have Immunity to the Exhaustion condition automatically succeed on saves against this spell.","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Sleep","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Sleet Storm","constant":false,"content":"## Sleet Storm (진눈깨비 폭풍) - Level 3 Conjuration spell, SRD 5.2.1\nClasses: Druid, Sorcerer, Wizard. Casting Time: Action. Range: 150 feet. Components: V, S, M (a miniature umbrella). Duration: Concentration, up to 1 minute.\nUntil the spell ends, sleet falls in a 40-foot-tall, 20-foot-radius Cylinder centered on a point you choose within range. The area is Heavily Obscured, and exposed flames in the area are doused.\nGround in the Cylinder is Difficult Terrain. When a creature enters the Cylinder for the first time on a turn or starts its turn there, it must succeed on a Dexterity saving throw or have the Prone condition and lose Concentration.","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Sleet Storm","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Slow","constant":false,"content":"## Slow (저속화) - Level 3 Transmutation spell, SRD 5.2.1\nClasses: Bard, Sorcerer, Wizard. Casting Time: Action. Range: 120 feet. Components: V, S, M (a drop of molasses). Duration: Concentration, up to 1 minute.\nYou alter time around up to six creatures of your choice in a 40-foot Cube within range. Each target must succeed on a Wisdom saving throw or be affected by this spell for the duration.\nAn affected target's Speed is halved, it takes a -2 penalty to AC and Dexterity saving throws, and it can't take Reactions. On its turns, it can take either an action or a Bonus Action, not both, and it can make only one attack if it takes the Attack action. If it casts a spell with a Somatic component, there is a 25 percent chance the spell fails as a result of the target making the spell's gestures too slowly.\nAn affected target repeats the save at the end of each of its turns, ending the spell on itself on a success.","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Slow","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Sorcerous Burst","constant":false,"content":"## Sorcerous Burst (술법 분출) - Cantrip Evocation spell, SRD 5.2.1\nClasses: Sorcerer. Casting Time: Action. Range: 120 feet Component: V, S. Components: . Duration: Instantaneous.\nYou cast sorcerous energy at one creature or object within range. Make a ranged spell attack against the target. On a hit, the target takes 1d8 damage of a type you choose: Acid, Cold, Fire, Lightning, Poison, Psychic, or Thunder.\nIf you roll an 8 on a d8 for this spell, you can roll another d8, and add it to the damage. When you cast this spell, the maximum number of these d8s you can add to the spell's damage equals your spellcasting ability modifier.\nCantrip Upgrade. The damage increases by 1d8 when you reach levels 5 (2d8), 11 (3d8), and 17 (4d8).","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Sorcerous Burst","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Spare the Dying","constant":false,"content":"## Spare the Dying (빈사 안정) - Cantrip Necromancy spell, SRD 5.2.1\nClasses: Cleric, Druid. Casting Time: Action. Range: 15 feet. Components: V, S. Duration: Instantaneous.\nChoose a creature within range that has 0 Hit Points and isn't dead. The creature becomes Stable.\nCantrip Upgrade. The range doubles when you reach levels 5 (30 feet), 11 (60 feet), and 17 (120 feet). 164","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Spare the Dying","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Speak with Animals","constant":false,"content":"## Speak with Animals (동물과 대화) - Level 1 Divination spell, SRD 5.2.1\nClasses: Bard, Druid, Ranger, Warlock. Casting Time: Action or Ritual. Range: Self. Components: V, S. Duration: 10 minutes.\nFor the duration, you can comprehend and verbally communicate with Beasts, and you can use any of the Influence action's skill options with them.\nMost Beasts have little to say about topics that don't pertain to survival or companionship, but at minimum, a Beast can give you information about nearby locations and monsters, including whatever it has perceived within the past day.","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Speak with Animals","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Speak with Dead","constant":false,"content":"## Speak with Dead (죽은 자와의 대화) - Level 3 Necromancy spell, SRD 5.2.1\nClasses: Bard, Cleric, Wizard. Casting Time: Action. Range: 10 feet. Components: V, S, M (burning incense). Duration: 10 minutes.\nYou grant the semblance of life to a corpse of your choice within range, allowing it to answer questions you pose. The corpse must have a mouth, and this spell fails if the deceased creature was Undead when it died. The spell also fails if the corpse was the target of this spell within the past 10 days.\nUntil the spell ends, you can ask the corpse up to five questions. The corpse knows only what it knew in life, including the languages it knew. Answers are usually brief, cryptic, or repetitive, and the corpse is under no compulsion to offer a truthful answer if you are antagonistic toward it or it recognizes you as an enemy. This spell doesn't return the creature's soul to its body, only its animating spirit. Thus, the corpse can't learn new information, doesn't comprehend anything that has happened since it died, and can't speculate about future events.","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Speak with Dead","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Speak with Plants","constant":false,"content":"## Speak with Plants (식물과 대화) - Level 3 Transmutation spell, SRD 5.2.1\nClasses: Bard, Druid, Ranger. Casting Time: Action. Range: Self. Components: V, S. Duration: 10 minutes.\nYou imbue plants in an immobile 30-foot Emanation with limited sentience and animation, giving them the ability to communicate with you and follow your simple commands. You can question plants about events in the spell's area within the past day, gaining information about creatures that have passed, weather, and other circumstances.\nYou can also turn Difficult Terrain caused by plant growth (such as thickets and undergrowth) into ordinary terrain that lasts for the duration. Or you can turn ordinary terrain where plants are present into Difficult Terrain that lasts for the duration.\nThe spell doesn't enable plants to uproot themselves and move about, but they can move their branches, tendrils, and stalks for you.\nIf a Plant creature is in the area, you can communicate with it as if you shared a common language.","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Speak with Plants","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Spider Climb","constant":false,"content":"## Spider Climb (거미 등반) - Level 2 Transmutation spell, SRD 5.2.1\nClasses: Sorcerer, Warlock, Wizard. Casting Time: Action. Range: Touch. Components: V, S, M (a drop of bitumen and a spider). Duration: Concentration, up to 1 hour.\nUntil the spell ends, one willing creature you touch gains the ability to move up, down, and across vertical surfaces and along ceilings, while leaving its hands free. The target also gains a Climb Speed equal to its Speed.\nUsing a Higher-Level Spell Slot. You can target one additional creature for each spell slot level above 2.","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Spider Climb","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Spike Growth","constant":false,"content":"## Spike Growth (가시 돋기) - Level 2 Transmutation spell, SRD 5.2.1\nClasses: Druid, Ranger. Casting Time: Action. Range: 150 feet. Components: V, S, M (seven thorns). Duration: Concentration, up to 10 minutes.\nThe ground in a 20-foot-radius Sphere centered on a point within range sprouts hard spikes and thorns. The area becomes Difficult Terrain for the duration. When a creature moves into or within the area, it takes 2d4 Piercing damage for every 5 feet it travels.\nThe transformation of the ground is camouflaged to look natural. Any creature that can't see the area when the spell is cast must take a Search action and succeed on a Wisdom (Perception or Survival) check against your spell save DC to recognize the terrain as hazardous before entering it.","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Spike Growth","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Spirit Guardians","constant":false,"content":"## Spirit Guardians (영혼 수호자) - Level 3 Conjuration spell, SRD 5.2.1\nClasses: Cleric. Casting Time: Action. Range: Self. Components: V, S, M (a prayer scroll). Duration: Concentration, up to 10 minutes.\nProtective spirits flit around you in a 15-foot Emanation for the duration. If you are good or neutral, their spectral form appears angelic or fey (your choice). If you are evil, they appear fiendish.\nWhen you cast this spell, you can designate creatures to be unaffected by it. Any other creature's Speed is halved in the Emanation, and whenever the Emanation enters a creature's space and whenever 165 a creature enters the Emanation or ends its turn there, the creature must make a Wisdom saving throw. On a failed save, the creature takes 3d8 Radiant damage (if you are good or neutral) or 3d8 Necrotic damage (if you are evil). On a successful save, the creature takes half as much damage. A creature makes this save only once per turn.\nUsing a Higher-Level Spell Slot. The damage increases by 1d8 for each spell slot level above 3.","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Spirit Guardians","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Spiritual Weapon","constant":false,"content":"## Spiritual Weapon (영체 무기) - Level 2 Evocation spell, SRD 5.2.1\nClasses: Cleric. Casting Time: Bonus Action. Range: 60 feet. Components: V, S. Duration: Concentration, up to 1 minute.\nYou create a floating, spectral force that resembles a weapon of your choice and lasts for the duration.\nThe force appears within range in a space of your choice, and you can immediately make one melee spell attack against one creature within 5 feet of the force. On a hit, the target takes Force damage equal to 1d8 plus your spellcasting ability modifier.\nAs a Bonus Action on your later turns, you can move the force up to 20 feet and repeat the attack against a creature within 5 feet of it.\nUsing a Higher-Level Spell Slot. The damage increases by 1d8 for every slot level above 2.","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Spiritual Weapon","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Starry Wisp","constant":false,"content":"## Starry Wisp (별빛 도깨비불) - Cantrip Evocation spell, SRD 5.2.1\nClasses: Bard, Druid. Casting Time: Action. Range: 60 feet. Components: V, S. Duration: Instantaneous.\nYou launch a mote of light at one creature or object within range. Make a ranged spell attack against the target. On a hit, the target takes 1d8 Radiant damage, and until the end of your next turn, it emits Dim Light in a 10-foot radius and can't benefit from the Invisible condition.\nCantrip Upgrade. The damage increases by 1d8 when you reach levels 5 (2d8), 11 (3d8), and 17 (4d8).","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Starry Wisp","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Stinking Cloud","constant":false,"content":"## Stinking Cloud (악취 구름) - Level 3 Conjuration spell, SRD 5.2.1\nClasses: Bard, Sorcerer, Wizard. Casting Time: Action. Range: 90 feet. Components: V, S, M (a rotten egg). Duration: Concentration, up to 1 minute.\nYou create a 20-foot-radius Sphere of yellow, nauseating gas centered on a point within range. The cloud is Heavily Obscured. The cloud lingers in the air for the duration or until a strong wind (such as the one created by Gust of Wind) disperses it.\nEach creature that starts its turn in the Sphere must succeed on a Constitution saving throw or have the Poisoned condition until the end of the current turn. While Poisoned in this way, the creature can't take an action or a Bonus Action.","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Stinking Cloud","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Stone Shape","constant":false,"content":"## Stone Shape (바위 형상화) - Level 4 Transmutation spell, SRD 5.2.1\nClasses: Cleric, Druid, Wizard. Casting Time: Action. Range: Touch. Components: V, S, M (soft clay). Duration: Instantaneous.\nYou touch a stone object of Medium size or smaller or a section of stone no more than 5 feet in any dimension and form it into any shape you like. For example, you could shape a large rock into a weapon, statue, or coffer, or you could make a small passage through a wall that is 5 feet thick. You could also shape a stone door or its frame to seal the door shut.\nThe object you create can have up to two hinges and a latch, but finer mechanical detail isn't possible.","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Stone Shape","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Stoneskin","constant":false,"content":"## Stoneskin (바위 피부) - Level 4 Transmutation spell, SRD 5.2.1\nClasses: Druid, Ranger, Sorcerer, Wizard. Casting Time: Action. Range: Touch. Components: V, S, M (diamond dust worth 100+ GP, which the spell consumes). Duration: Concentration, up to 1 hour.\nUntil the spell ends, one willing creature you touch has Resistance to Bludgeoning, Piercing, and Slashing damage.","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Stoneskin","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Storm of Vengeance","constant":false,"content":"## Storm of Vengeance (복수의 폭풍) - Level 9 Conjuration spell, SRD 5.2.1\nClasses: Druid. Casting Time: Action. Range: 1 mile. Components: V, S. Duration: Concentration, up to 1 minute.\nA churning storm cloud forms for the duration, centered on a point within range and spreading to a radius of 300 feet. Each creature under the cloud when it appears must succeed on a Constitution saving throw or take 2d6 Thunder damage and have the Deafened condition for the duration.\nAt the start of each of your later turns, the storm produces different effects, as detailed below.\nTurn 2. Acidic rain falls. Each creature and object under the cloud takes 4d6 Acid damage.\nTurn 3. You call six bolts of lightning from the cloud to strike six different creatures or objects beneath it. Each target makes a Dexterity saving throw, taking 10d6 Lightning damage on a failed save or half as much damage on a successful one. 166 Turn 4. Hailstones rain down. Each creature under the cloud takes 2d6 Bludgeoning damage.\nTurns 5-10. Gusts and freezing rain assail the area under the cloud. Each creature there takes 1d6 Cold damage. Until the spell ends, the area is Difficult Terrain and Heavily Obscured, ranged attacks with weapons are impossible there, and strong wind blows through the area.","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Storm of Vengeance","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Suggestion","constant":false,"content":"## Suggestion (암시) - Level 2 Enchantment spell, SRD 5.2.1\nClasses: Bard, Sorcerer, Warlock, Wizard. Casting Time: Action. Range: 30 feet. Components: V, M (a drop of honey). Duration: Concentration, up to 8 hours.\nYou suggest a course of activity—described in no more than 25 words—to one creature you can see within range that can hear and understand you.\nThe suggestion must sound achievable and not involve anything that would obviously deal damage to the target or its allies. For example, you could say, “Fetch the key to the cult's treasure vault, and give the key to me.” Or you could say, “Stop fighting, leave this library peacefully, and don't return.” The target must succeed on a Wisdom saving throw or have the Charmed condition for the duration or until you or your allies deal damage to the target. The Charmed target pursues the suggestion to the best of its ability. The suggested activity can continue for the entire duration, but if the suggested activity can be completed in a shorter time, the spell ends for the target upon completing it.","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Suggestion","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Summon Dragon","constant":false,"content":"## Summon Dragon (용 소환) - Level 5 Conjuration spell, SRD 5.2.1\nClasses: Wizard. Casting Time: Action. Range: 60 feet. Components: V, S, M (an object with the image of a dragon engraved on it worth 500+ GP). Duration: Concentration, up to 1 hour.\nYou call forth a Dragon spirit. It manifests in an unoccupied space that you can see within range and uses the Draconic Spirit stat block. The creature disappears when it drops to 0 Hit Points or when the spell ends.\nThe creature is an ally to you and your allies. In combat, the creature shares your Initiative count, but it takes its turn immediately after yours. It obeys your verbal commands (no action required by you). If you don't issue any, it takes the Dodge action and uses its movement to avoid danger.\nUsing a Higher-Level Spell Slot. Use the spell slot's level for the spell's level in the stat block.","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Summon Dragon","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Sunbeam","constant":false,"content":"## Sunbeam (햇살 광선) - Level 6 Evocation spell, SRD 5.2.1\nClasses: Cleric, Druid, Sorcerer, Wizard. Casting Time: Action. Range: Self. Components: V, S, M (a magnifying glass). Duration: Concentration, up to 1 minute.\nYou launch a sunbeam in a 5-foot-wide, 60-foot-long Line. Each creature in the Line makes a Constitution saving throw. On a failed save, a creature takes 6d8 Radiant damage and has the Blinded condition until the start of your next turn. On a successful save, it takes half as much damage only.\nUntil the spell ends, you can take a Magic action to create a new Line of radiance.\nFor the duration, a mote of brilliant radiance shines above you. It sheds Bright Light in a 30-foot radius and Dim Light for an additional 30 feet. This light is sunlight. 167","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Sunbeam","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Sunburst","constant":false,"content":"## Sunburst (태양 폭발) - Level 8 Evocation spell, SRD 5.2.1\nClasses: Cleric, Druid, Sorcerer, Wizard. Casting Time: Action. Range: 150 feet. Components: V, S, M (a piece of sunstone). Duration: Instantaneous.\nBrilliant sunlight flashes in a 60-foot-radius Sphere centered on a point you choose within range. Each creature in the Sphere makes a Constitution saving throw. On a failed save, a creature takes 12d6 Radiant damage and has the Blinded condition for 1 minute. On a successful save, it takes half as much damage only.\nA creature Blinded by this spell makes another Constitution saving throw at the end of each of its turns, ending the effect on itself on a success.\nThis spell dispels Darkness in its area that was created by any spell.","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Sunburst","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Symbol","constant":false,"content":"## Symbol (상징) - Level 7 Abjuration spell, SRD 5.2.1\nClasses: Bard, Cleric, Druid, Wizard. Casting Time: 1 minute. Range: Touch. Components: V, S, M (powdered diamond worth 1,000+ GP, which the spell consumes). Duration: Until dispelled or triggered.\nYou inscribe a harmful glyph either on a surface (such as a section of floor or wall) or within an object that can be closed (such as a book or chest). The glyph can cover an area no larger than 10 feet in diameter. If you choose an object, it must remain in place; if it is moved more than 10 feet from where you cast this spell, the glyph is broken, and the spell ends without being triggered.\nThe glyph is nearly imperceptible and requires a successful Wisdom (Perception) check against your spell save DC to notice.\nWhen you inscribe the glyph, you set its trigger and choose which effect the symbol bears: Death, Discord, Fear, Pain, Sleep, or Stunning. Each one is explained below.\nSet the Trigger. You decide what triggers the glyph when you cast the spell. For glyphs inscribed on a surface, common triggers include touching or stepping on the glyph, removing another object covering it, or approaching within a certain distance of it. For glyphs inscribed within an object, common triggers include opening that object or seeing the glyph.\nYou can refine the trigger so that only creatures of certain types activate it (for example, the glyph could be set to affect Aberrations). You can also set conditions for creatures that don't trigger the glyph, such as those who say a certain password.\nOnce triggered, the glyph glows, filling a 60-foot-radius Sphere with Dim Light for 10 minutes, after which time the spell ends. Each creature in the Sphere when the glyph activates is targeted by its effect, as is a creature that enters the Sphere for the first time on a turn or ends its turn there. A creature is targeted only once per turn.\nDeath. Each target makes a Constitution saving throw, taking 10d10 Necrotic damage on a failed save or half as much damage on a successful save.\nDiscord. Each target makes a Wisdom saving throw. On a failed save, a target argues with other creatures for 1 minute. During this time, it is incapable of meaningful communication and has Disadvantage on attack rolls and ability checks.\nFear. Each target must succeed on a Wisdom saving throw or have the Frightened condition for 1 minute. While Frightened, the target must move at least 30 feet away from the glyph on each of its turns, if able.\nPain. Each target must succeed on a Constitution saving throw or have the Incapacitated condition for 1 minute.\nSleep. Each target must succeed on a Wisdom saving throw or have the Unconscious condition for 10 minutes. A creature awakens if it takes damage or if someone takes an action to shake it awake.\nStunning. Each target must succeed on a Wisdom saving throw or have the Stunned condition for 1 minute.","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Symbol","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Telekinesis","constant":false,"content":"## Telekinesis (염동력) - Level 5 Transmutation spell, SRD 5.2.1\nClasses: Sorcerer, Wizard. Casting Time: Action. Range: 60 feet. Components: V, S. Duration: Concentration, up to 10 minutes.\nYou gain the ability to move or manipulate creatures or objects by thought. When you cast the spell and as a Magic action on your later turns before the spell ends, you can exert your will on one creature or object that you can see within range, causing the appropriate effect below. You can affect the same target round after round or choose a new one at any time. If you switch targets, the prior target is no longer affected by the spell.\nCreature. You can try to move a Huge or smaller creature. The target must succeed on a Strength saving throw, or you move it up to 30 feet in any direction within the spell's range. Until the end of your next turn, the creature has the Restrained condition, and if you lift it into the air, it is suspended there. It falls at the end of your next turn unless you use this option on it again and it fails the save.\nObject. You can try to move a Huge or smaller object. If the object isn't being worn or carried, you automatically move it up to 30 feet in any direction within the spell's range. 168 If the object is worn or carried by a creature, that creature must succeed on a Strength saving throw, or you pull the object away and move it up to 30 feet in any direction within the spell's range.\nYou can exert fine control on objects with your telekinetic grip, such as manipulating a simple tool,","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Telekinesis","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Telepathic Bond","constant":false,"content":"## Telepathic Bond (정신 유대) - Level 5 Divination spell, SRD 5.2.1\nClasses: Bard, Wizard. Casting Time: Action or Ritual. Range: 30 feet. Components: V, S, M (two eggs). Duration: 1 hour.\nYou forge a telepathic link among up to eight willing creatures of your choice within range, psychically linking each creature to all the others for the duration. Creatures that can't communicate in any languages aren't affected by this spell.\nUntil the spell ends, the targets can communicate telepathically through the bond whether or not they share a language. The communication is possible over any distance, though it can't extend to other planes of existence.","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Telepathic Bond","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Teleport","constant":false,"content":"## Teleport (순간이동) - Level 7 Conjuration spell, SRD 5.2.1\nClasses: Bard, Sorcerer, Wizard. Casting Time: Action. Range: 10 feet. Components: V. Duration: Instantaneous.\nThis spell instantly transports you and up to eight willing creatures that you can see within range, or a single object that you can see within range, to a destination you select. If you target an object, it must be Large or smaller, and it can't be held or carried by an unwilling creature.\nThe destination you choose must be known to you, and it must be on the same plane of existence as you. Your familiarity with the destination determines whether you arrive there successfully. The GM rolls 1d100 and consults the Teleportation Outcome table and the explanations after it.\nTeleportation Outcome Familiarity Mishap Similar Area Off Target On Target Permanent circle — — — 01-00 Linked object — — — 01-00 Very familiar 01-05 06-13 14-24 25-00 Seen casually 01-33 34-43 44-53 54-00 Viewed once or described 01-43 44-53 54-73 74-00 False destination 01-50 51-00 — — Familiarity. Here are the meanings of the terms in the table's Familiarity column: • “Permanent circle” means a permanent teleportation circle whose sigil sequence you know. • “Linked object” means you possess an object taken from the desired destination within the last six months, such as a book from a wizard's library. • “Very familiar” is a place you have visited often, a place you have carefully studied, or a place you can see when you cast the spell. • “Seen casually” is a place you have seen more than once but with which you aren't very familiar. • “Viewed once or described” is a place you have seen once, possibly using magic, or a place you know through someone else's description, perhaps from a map. • “False destination” is a place that doesn't exist.\nPerhaps you tried to scry an enemy's sanctum but instead viewed an illusion, or you are attempting to teleport to a location that no longer exists.\nMishap. The spell's unpredictable magic results in a difficult journey. Each teleporting creature (or the target object) takes 3d10 Force damage, and the GM rerolls on the table to see where you wind up (multiple mishaps can occur, dealing damage each time).\nSimilar Area. You and your group (or the target object) appear in a different area that's visually or thematically similar to the target area. You appear in the closest similar place. If you are heading for your home laboratory, for example, you might appear in another person's laboratory in the same city.\nOff Target. You and your group (or the target object) appear 2d12 miles away from the destination in a random direction. Roll 1d8 for the direction: 1, east; 2, southeast; 3, south; 4, southwest; 5, west; 6, northwest; 7, north; or 8, northeast.\nOn Target. You and your group (or the target object) appear where you intended.","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Teleport","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Teleportation Circle","constant":false,"content":"## Teleportation Circle (순간이동의 원) - Level 5 Conjuration spell, SRD 5.2.1\nClasses: Bard, Sorcerer, Warlock, Wizard. Casting Time: 1 minute. Range: 10 feet. Components: V, M (rare inks worth 50+ GP, which the spell consumes). Duration: 1 round.\nAs you cast the spell, you draw a 5-foot-radius circle on the ground inscribed with sigils that link your location to a permanent teleportation circle of your choice whose sigil sequence you know and that is on the same plane of existence as you. A shimmering portal opens within the circle you drew and remains open until the end of your next turn. Any creature that enters the portal instantly appears within 5 feet of the destination circle or in the nearest unoccupied space if that space is occupied. 169 Many major temples, guildhalls, and other important places have permanent teleportation circles.\nEach circle includes a unique sigil sequence—a string of runes arranged in a particular pattern.\nWhen you first gain the ability to cast this spell, you learn the sigil sequences for two destinations on the Material Plane, determined by the GM. You might learn additional sigil sequences during your adventures. You can commit a new sigil sequence to memory after studying it for 1 minute.\nYou can create a permanent teleportation circle by casting this spell in the same location every day for 365 days.","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Teleportation Circle","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Thaumaturgy","constant":false,"content":"## Thaumaturgy (단순마술) - Cantrip Transmutation spell, SRD 5.2.1\nClasses: Cleric. Casting Time: Action. Range: 30 feet. Components: V. Duration: Up to 1 minute.\nYou manifest a minor wonder within range. You create one of the effects below within range. If you cast this spell multiple times, you can have up to three of its 1-minute effects active at a time.\nAltered Eyes. You alter the appearance of your eyes for 1 minute.\nBooming Voice. Your voice booms up to three times as loud as normal for 1 minute. For the duration, you have Advantage on Charisma (Intimidation) checks.\nFire Play. You cause flames to flicker, brighten, dim, or change color for 1 minute.\nInvisible Hand. You instantaneously cause an unlocked door or window to fly open or slam shut.\nPhantom Sound. You create an instantaneous sound that originates from a point of your choice within range, such as a rumble of thunder, the cry of a raven, or ominous whispers.\nTremors. You cause harmless tremors in the ground for 1 minute.","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Thaumaturgy","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Thunderwave","constant":false,"content":"## Thunderwave (천둥파도) - Level 1 Evocation spell, SRD 5.2.1\nClasses: Bard, Druid, Sorcerer, Wizard. Casting Time: Action. Range: Self. Components: V, S. Duration: Instantaneous.\nYou unleash a wave of thunderous energy. Each creature in a 15-foot Cube originating from you makes a Constitution saving throw. On a failed save, a creature takes 2d8 Thunder damage and is pushed 10 feet away from you. On a successful save, a creature takes half as much damage only.\nIn addition, unsecured objects that are entirely within the Cube are pushed 10 feet away from you, and a thunderous boom is audible within 300 feet.\nUsing a Higher-Level Spell Slot. The damage increases by 1d8 for each spell slot level above 1.","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Thunderwave","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Time Stop","constant":false,"content":"## Time Stop (시간 정지) - Level 9 Transmutation spell, SRD 5.2.1\nClasses: Sorcerer, Wizard. Casting Time: Action. Range: Self. Components: V. Duration: Instantaneous.\nYou briefly stop the flow of time for everyone but yourself. No time passes for other creatures, while you take 1d4 + 1 turns in a row, during which you can use actions and move as normal.\nThis spell ends if one of the actions you use during this period, or any effects that you create during it, affects a creature other than you or an object being worn or carried by someone other than you. In addition, the spell ends if you move to a place more than 1,000 feet from the location where you cast it.","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Time Stop","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Tiny Hut","constant":false,"content":"## Tiny Hut (작은 오두막) - Level 3 Evocation spell, SRD 5.2.1\nClasses: Bard, Wizard. Casting Time: 1 minute or Ritual. Range: Self. Components: V, S, M (a crystal bead). Duration: 8 hours.\nA 10-foot Emanation springs into existence around you and remains stationary for the duration. The spell fails when you cast it if the Emanation isn't big enough to fully encapsulate all creatures in its area.\nCreatures and objects within the Emanation when you cast the spell can move through it freely.\nAll other creatures and objects are barred from passing through it. Spells of level 3 or lower can't be cast through it, and the effects of such spells can't extend into it.\nThe atmosphere inside the Emanation is comfortable and dry, regardless of the weather outside. Until the spell ends, you can command the interior to have Dim Light or Darkness (no action required). The Emanation is opaque from the outside and of any color you choose, but it's transparent from the inside.\nThe spell ends early if you leave the Emanation or if you cast it again.","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Tiny Hut","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Tongues","constant":false,"content":"## Tongues (언어 구사) - Level 3 Divination spell, SRD 5.2.1\nClasses: Bard, Cleric, Sorcerer, Warlock, Wizard. Casting Time: Action. Range: Touch. Components: V, M (a miniature ziggurat). Duration: 1 hour.\nThis spell grants the creature you touch the ability to understand any spoken or signed language that it hears or sees. Moreover, when the target communicates by speaking or signing, any creature that 170 knows at least one language can understand it if that creature can hear the speech or see the signing.","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Tongues","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Transport via Plants","constant":false,"content":"## Transport via Plants (식물을 통한 이동) - Level 6 Conjuration spell, SRD 5.2.1\nClasses: Druid. Casting Time: Action. Range: 10 feet. Components: V, S. Duration: 1 minute.\nThis spell creates a magical link between a Large or larger inanimate plant within range and another plant, at any distance, on the same plane of existence. You must have seen or touched the destination plant at least once before. For the duration, any creature can step into the target plant and exit from the destination plant by using 5 feet of movement.","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Transport via Plants","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Tree Stride","constant":false,"content":"## Tree Stride (나무 걸음) - Level 5 Conjuration spell, SRD 5.2.1\nClasses: Druid, Ranger. Casting Time: Action. Range: Self. Components: V, S. Duration: Concentration, up to 1 minute.\nYou gain the ability to enter a tree and move from inside it to inside another tree of the same kind within 500 feet. Both trees must be living and at least the same size as you. You must use 5 feet of movement to enter a tree. You instantly know the location of all other trees of the same kind within 500 feet and, as part of the move used to enter the tree, can either pass into one of those trees or step out of the tree you're in. You appear in a spot of your choice within 5 feet of the destination tree, using another 5 feet of movement. If you have no movement left, you appear within 5 feet of the tree you entered.\nYou can use this transportation ability only once on each of your turns. You must end each turn outside a tree.","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Tree Stride","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: True Polymorph","constant":false,"content":"## True Polymorph (완전한 변신) - Level 9 Transmutation spell, SRD 5.2.1\nClasses: Bard, Warlock, Wizard. Casting Time: Action. Range: 30 feet. Components: V, S, M (a drop of mercury, a dollop of gum arabic, and a wisp of smoke). Duration: Concentration, up to 1 hour.\nChoose one creature or nonmagical object that you can see within range. The creature shape-shifts into a different creature or a nonmagical object, or the object shape-shifts into a creature (the object must be neither worn nor carried). The transformation lasts for the duration or until the target dies or is destroyed, but if you maintain Concentration on this spell for the full duration, the spell lasts until dispelled.\nAn unwilling creature can make a Wisdom saving throw, and if it succeeds, it isn't affected by this spell.\nCreature into Creature. If you turn a creature into another kind of creature, the new form can be any kind you choose that has a Challenge Rating equal to or less than the target's Challenge Rating or level. The target's game statistics are replaced by the stat block of the new form, but it retains its Hit Points, Hit Point Dice, alignment, and personality.\nThe target gains a number of Temporary Hit Points equal to the Hit Points of the new form.\nThese Temporary Hit Points vanish if any remain when the spell ends.\nThe target is limited in the actions it can perform by the anatomy of its new form, and it can't speak or cast spells.\nThe target's gear melds into the new form. The creature can't use or otherwise benefit from any of that equipment.\nObject into Creature. You can turn an object into any kind of creature, as long as the creature's size is no larger than the object's size and the creature has a Challenge Rating of 9 or lower. The creature is Friendly to you and your allies. In combat, it takes its turns immediately after yours, and it obeys your commands.\nIf the spell lasts more than an hour, you no longer control the creature. It might remain Friendly to you, depending on how you have treated it.\nCreature into Object. If you turn a creature into an object, it transforms along with whatever it is wearing and carrying into that form, as long as the object's size is no larger than the creature's size. The creature's statistics become those of the object, and the creature has no memory of time spent in this form after the spell ends and it returns to normal.","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: True Polymorph","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: True Resurrection","constant":false,"content":"## True Resurrection (진정한 부활) - Level 9 Necromancy spell, SRD 5.2.1\nClasses: Cleric, Druid. Casting Time: 1 hour. Range: Touch. Components: V, S, M (diamonds worth 25,000+ GP, which the spell consumes). Duration: Instantaneous.\nYou touch a creature that has been dead for no longer than 200 years and that died for any reason except old age. The creature is revived with all its Hit Points.\nThis spell closes all wounds, neutralizes any poison, cures all magical contagions, and lifts any curses affecting the creature when it died. The spell replaces damaged or missing organs and limbs.\nIf the creature was Undead, it is restored to its non-Undead form.\nThe spell can provide a new body if the original no longer exists, in which case you must speak the 171 creature's name. The creature then appears in an unoccupied space you choose within 10 feet of you.","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: True Resurrection","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: True Seeing","constant":false,"content":"## True Seeing (진시야) - Level 6 Divination spell, SRD 5.2.1\nClasses: Bard, Cleric, Sorcerer, Warlock, Wizard. Casting Time: Action. Range: Touch. Components: V, S, M (mushroom powder worth 25+ GP, which the spell consumes). Duration: 1 hour.\nFor the duration, the willing creature you touch has Truesight with a range of 120 feet.","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: True Seeing","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: True Strike","constant":false,"content":"## True Strike (참된 일격) - Cantrip Divination spell, SRD 5.2.1\nClasses: Bard, Sorcerer, Warlock, Wizard. Casting Time: Action. Range: Self. Components: S, M (a weapon with which you have profi- ciency and that is worth 1+ CP). Duration: Instantaneous.\nGuided by a flash of magical insight, you make one attack with the weapon used in the spell's casting.\nThe attack uses your spellcasting ability for the attack and damage rolls instead of using Strength or Dexterity. If the attack deals damage, it can be Radiant damage or the weapon's normal damage type (your choice).\nCantrip Upgrade. Whether you deal Radiant damage or the weapon's normal damage type, the attack deals extra Radiant damage when you reach levels 5 (1d6), 11 (2d6), and 17 (3d6).","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: True Strike","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Tsunami","constant":false,"content":"## Tsunami (해일) - Level 8 Conjuration spell, SRD 5.2.1\nClasses: Druid. Casting Time: 1 minute. Range: 1 mile. Components: V, S. Duration: Concentration, up to 6 rounds.\nA wall of water springs into existence at a point you choose within range. You can make the wall up to 300 feet long, 300 feet high, and 50 feet thick. The wall lasts for the duration.\nWhen the wall appears, each creature in its area makes a Strength saving throw, taking 6d10 Bludgeoning damage on a failed save or half as much damage on a successful one.\nAt the start of each of your turns after the wall appears, the wall, along with any creatures in it, moves 50 feet away from you. Any Huge or smaller creature inside the wall or whose space the wall enters when it moves must succeed on a Strength saving throw or take 5d10 Bludgeoning damage. A creature can take this damage only once per round.\nAt the end of the turn, the wall's height is reduced by 50 feet, and the damage the wall deals on later rounds is reduced by 1d10. When the wall reaches 0 feet in height, the spell ends.\nA creature caught in the wall can move by swimming. Because of the wave's force, though, the creature must succeed on a Strength (Athletics) check against your spell save DC to move at all. If it fails the check, it can't move. A creature that moves out of the wall falls to the ground.","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Tsunami","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Unseen Servant","constant":false,"content":"## Unseen Servant (보이지 않는 하인) - Level 1 Conjuration spell, SRD 5.2.1\nClasses: Bard, Warlock, Wizard. Casting Time: Action or Ritual. Range: 60 feet. Components: V, S, M (a bit of string and of wood). Duration: 1 hour.\nThis spell creates an Invisible, mindless, shapeless, Medium force that performs simple tasks at your command until the spell ends. The servant springs into existence in an unoccupied space on the ground within range. It has AC 10, 1 Hit Point, and a Strength of 2, and it can't attack. If it drops to 0 Hit Points, the spell ends.\nOnce on each of your turns as a Bonus Action, you can mentally command the servant to move up to 15 feet and interact with an object. The servant can perform simple tasks that a human could do, such as fetching things, cleaning, mending, folding clothes, lighting fires, serving food, and pouring drinks.\nOnce you give the command, the servant performs the task to the best of its ability until it completes the task, then waits for your next command.\nIf you command the servant to perform a task that would move it more than 60 feet away from you, the spell ends.","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Unseen Servant","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Vampiric Touch","constant":false,"content":"## Vampiric Touch (흡혈의 접촉) - Level 3 Necromancy spell, SRD 5.2.1\nClasses: Sorcerer, Warlock, Wizard. Casting Time: Action. Range: Self. Components: V, S. Duration: Concentration, up to 1 minute.\nThe touch of your shadow-wreathed hand can siphon life force from others to heal your wounds.\nMake a melee spell attack against one creature within reach. On a hit, the target takes 3d6 Necrotic damage, and you regain Hit Points equal to half the amount of Necrotic damage dealt.\nUntil the spell ends, you can make the attack again on each of your turns as a Magic action, targeting the same creature or a different one.\nUsing a Higher-Level Spell Slot. The damage increases by 1d6 for each spell slot level above 3.","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Vampiric Touch","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Vicious Mockery","constant":false,"content":"## Vicious Mockery (악랄한 조롱) - Cantrip Enchantment spell, SRD 5.2.1\nClasses: Bard. Casting Time: Action. Range: 60 feet 172. Components: V. Duration: Instantaneous.\nYou unleash a string of insults laced with subtle enchantments at one creature you can see or hear within range. The target must succeed on a Wisdom saving throw or take 1d6 Psychic damage and have Disadvantage on the next attack roll it makes before the end of its next turn.\nCantrip Upgrade. The damage increases by 1d6 when you reach levels 5 (2d6), 11 (3d6), and 17 (4d6).","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Vicious Mockery","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Vitriolic Sphere","constant":false,"content":"## Vitriolic Sphere (산성 구체) - Level 4 Evocation spell, SRD 5.2.1\nClasses: Sorcerer, Wizard. Casting Time: Action. Range: 150 feet. Components: V, S, M (a drop of bile). Duration: Instantaneous.\nYou point at a location within range, and a glowing, 1-foot-diameter ball of acid streaks there and explodes in a 20-foot-radius Sphere. Each creature in that area makes a Dexterity saving throw. On a failed save, a creature takes 10d4 Acid damage and another 5d4 Acid damage at the end of its next turn.\nOn a successful save, a creature takes half the initial damage only.\nUsing a Higher-Level Spell Slot. The initial damage increases by 2d4 for each spell slot level above 4.","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Vitriolic Sphere","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Wall of Fire","constant":false,"content":"## Wall of Fire (화염 벽) - Level 4 Evocation spell, SRD 5.2.1\nClasses: Druid, Sorcerer, Wizard. Casting Time: Action. Range: 120 feet. Components: V, S, M (a piece of charcoal). Duration: Concentration, up to 1 minute.\nYou create a wall of fire on a solid surface within range. You can make the wall up to 60 feet long, 20 feet high, and 1 foot thick, or a ringed wall up to 20 feet in diameter, 20 feet high, and 1 foot thick. The wall is opaque and lasts for the duration.\nWhen the wall appears, each creature in its area makes a Dexterity saving throw, taking 5d8 Fire damage on a failed save or half as much damage on a successful one.\nOne side of the wall, selected by you when you cast this spell, deals 5d8 Fire damage to each creature that ends its turn within 10 feet of that side or inside the wall. A creature takes the same damage when it enters the wall for the first time on a turn or ends its turn there. The other side of the wall deals no damage.\nUsing a Higher-Level Spell Slot. The damage increases by 1d8 for each spell slot level above 4.","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Wall of Fire","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Wall of Force","constant":false,"content":"## Wall of Force (역장 벽) - Level 5 Evocation spell, SRD 5.2.1\nClasses: Wizard. Casting Time: Action. Range: 120 feet. Components: V, S, M (a shard of glass). Duration: Concentration, up to 10 minutes.\nAn Invisible wall of force springs into existence at a point you choose within range. The wall appears in any orientation you choose, as a horizontal or vertical barrier or at an angle. It can be free floating or resting on a solid surface. You can form it into a hemispherical dome or a globe with a radius of up to 10 feet, or you can shape a flat surface made up of ten 10-foot-by-10-foot panels. Each panel must be contiguous with another panel. In any form, the wall is 1/4 inch thick and lasts for the duration. If the wall cuts through a creature's space when it appears, the creature is pushed to one side of the wall (you choose which side).\nNothing can physically pass through the wall. It is immune to all damage and can't be dispelled by Dispel Magic. A Disintegrate spell destroys the wall instantly, however. The wall also extends into the Ethereal Plane and blocks ethereal travel through the wall.","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Wall of Force","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Wall of Ice","constant":false,"content":"## Wall of Ice (얼음 벽) - Level 6 Evocation spell, SRD 5.2.1\nClasses: Wizard. Casting Time: Action. Range: 120 feet. Components: V, S, M (a piece of quartz). Duration: Concentration, up to 10 minutes.\nYou create a wall of ice on a solid surface within range. You can form it into a hemispherical dome or a globe with a radius of up to 10 feet, or you can shape a flat surface made up of ten 10-foot-square panels. Each panel must be contiguous with another panel. In any form, the wall is 1 foot thick and lasts for the duration.\nIf the wall cuts through a creature's space when it appears, the creature is pushed to one side of the wall (you choose which side) and makes a Dexterity saving throw, taking 10d6 Cold damage on a failed save or half as much damage on a successful one.\nThe wall is an object that can be damaged and thus breached. It has AC 12 and 30 Hit Points per 10-foot section, and it has Immunity to Cold, Poison, and Psychic damage and Vulnerability to Fire damage. Reducing a 10-foot section of wall to 0 Hit Points destroys it and leaves behind a sheet of frigid air in the space the wall occupied.\nA creature moving through the sheet of frigid air for the first time on a turn makes a Constitution saving throw, taking 5d6 Cold damage on a failed save or half as much damage on a successful one. 173 Using a Higher-Level Spell Slot. The damage the wall deals when it appears increases by 2d6 and the damage from passing through the sheet of frigid air increases by 1d6 for each spell slot level above 6.","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Wall of Ice","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Wall of Stone","constant":false,"content":"## Wall of Stone (바위 벽) - Level 5 Evocation spell, SRD 5.2.1\nClasses: Druid, Sorcerer, Wizard. Casting Time: Action. Range: 120 feet. Components: V, S, M (a cube of granite). Duration: Concentration, up to 10 minutes.\nA nonmagical wall of solid stone springs into existence at a point you choose within range. The wall is 6 inches thick and is composed of ten 10-foot-by- 10-foot panels. Each panel must be contiguous with another panel. Alternatively, you can create 10-footby-20-foot panels that are only 3 inches thick.\nIf the wall cuts through a creature's space when it appears, the creature is pushed to one side of the wall (you choose which side). If a creature would be surrounded on all sides by the wall (or the wall and another solid surface), that creature can make a Dexterity saving throw. On a success, it can use its Reaction to move up to its Speed so that it is no longer enclosed by the wall.\nThe wall can have any shape you desire, though it can't occupy the same space as a creature or object.\nThe wall doesn't need to be vertical or rest on a firm foundation. It must, however, merge with and be solidly supported by existing stone. Thus, you can use this spell to bridge a chasm or create a ramp.\nIf you create a span greater than 20 feet in length, you must halve the size of each panel to create supports. You can crudely shape the wall to create battlements and the like.\nThe wall is an object made of stone that can be damaged and thus breached. Each panel has AC 15 and 30 Hit Points per inch of thickness, and it has Immunity to Poison and Psychic damage. Reducing a panel to 0 Hit Points destroys it and might cause connected panels to collapse at the GM's discretion.\nIf you maintain your Concentration on this spell for its full duration, the wall becomes permanent and can't be dispelled. Otherwise, the wall disappears when the spell ends.","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Wall of Stone","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Wall of Thorns","constant":false,"content":"## Wall of Thorns (가시 벽) - Level 6 Conjuration spell, SRD 5.2.1\nClasses: Druid. Casting Time: Action. Range: 120 feet. Components: V, S, M (a handful of thorns). Duration: Concentration, up to 10 minutes.\nYou create a wall of tangled brush bristling with needle-sharp thorns. The wall appears within range on a solid surface and lasts for the duration. You choose to make the wall up to 60 feet long, 10 feet high, and 5 feet thick or a circle that has a 20-foot diameter and is up to 20 feet high and 5 feet thick.\nThe wall blocks line of sight.\nWhen the wall appears, each creature in its area makes a Dexterity saving throw, taking 7d8 Piercing damage on a failed save or half as much damage on a successful one.\nA creature can move through the wall, albeit slowly and painfully. For every 1 foot a creature moves through the wall, it must spend 4 feet of movement. Furthermore, the first time a creature enters a space in the wall on a turn or ends its turn there, the creature makes a Dexterity saving throw, taking 7d8 Slashing damage on a failed save or half as much damage on a successful one. A creature makes this save only once per turn.\nUsing a Higher-Level Spell Slot. Both types of damage increase by 1d8 for each spell slot level above 6.","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Wall of Thorns","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Warding Bond","constant":false,"content":"## Warding Bond (방비의 유대) - Level 2 Abjuration spell, SRD 5.2.1\nClasses: Cleric, Paladin. Casting Time: Action. Range: Touch. Components: V, S, M (a pair of platinum rings worth 50+ GP each, which you and the target must wear for the duration). Duration: 1 hour.\nYou touch another creature that is willing and create a mystic connection between you and the target until the spell ends. While the target is within 60 feet of you, it gains a +1 bonus to AC and saving throws, and it has Resistance to all damage.\nAlso, each time it takes damage, you take the same amount of damage.\nThe spell ends if you drop to 0 Hit Points or if you and the target become separated by more than 60 feet. It also ends if the spell is cast again on either of the connected creatures.","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Warding Bond","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Water Breathing","constant":false,"content":"## Water Breathing (수중 호흡) - Level 3 Transmutation spell, SRD 5.2.1\nClasses: Druid, Ranger, Sorcerer, Wizard. Casting Time: Action or Ritual. Range: 30 feet. Components: V, S, M (a short reed). Duration: 24 hours.\nThis spell grants up to ten willing creatures of your choice within range the ability to breathe underwater until the spell ends. Affected creatures also retain their normal mode of respiration.","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Water Breathing","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Water Walk","constant":false,"content":"## Water Walk (수면 보행) - Level 3 Transmutation spell, SRD 5.2.1\nClasses: Cleric, Druid, Ranger, Sorcerer. Casting Time: Action or Ritual. Range: 30 feet 174. Components: V, S, M (a piece of cork). Duration: 1 hour.\nThis spell grants the ability to move across any liquid surface—such as water, acid, mud, snow, quicksand, or lava—as if it were harmless solid ground (creatures crossing molten lava can still take damage from the heat). Up to ten willing creatures of your choice within range gain this ability for the duration.\nAn affected target must take a Bonus Action to pass from the liquid's surface into the liquid itself and vice versa, but if the target falls into the liquid, the target passes through the surface into the liquid below.","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Water Walk","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Web","constant":false,"content":"## Web (거미줄) - Level 2 Conjuration spell, SRD 5.2.1\nClasses: Sorcerer, Wizard. Casting Time: Action. Range: 60 feet. Components: V, S, M (a bit of spiderweb). Duration: Concentration, up to 1 hour.\nYou conjure a mass of sticky webbing at a point within range. The webs fill a 20-foot Cube there for the duration. The webs are Difficult Terrain, and the area within them is Lightly Obscured.\nIf the webs aren't anchored between two solid masses (such as walls or trees) or layered across a floor, wall, or ceiling, the web collapses on itself, and the spell ends at the start of your next turn.\nWebs layered over a flat surface have a depth of 5 feet.\nThe first time a creature enters the webs on a turn or starts its turn there, it must succeed on a Dexterity saving throw or have the Restrained condition while in the webs or until it breaks free.\nA creature Restrained by the webs can take an action to make a Strength (Athletics) check against your spell save DC. If it succeeds, it is no longer Restrained.\nThe webs are flammable. Any 5-foot Cube of webs exposed to fire burns away in 1 round, dealing 2d4 Fire damage to any creature that starts its turn in the fire.","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Web","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Weird","constant":false,"content":"## Weird (기괴한 환영) - Level 9 Illusion spell, SRD 5.2.1\nClasses: Warlock, Wizard. Casting Time: Action. Range: 120 feet. Components: V, S. Duration: Concentration, up to 1 minute.\nYou try to create illusory terrors in others' minds.\nEach creature of your choice in a 30-foot-radius Sphere centered on a point within range makes a Wisdom saving throw. On a failed save, a target takes 10d10 Psychic damage and has the Frightened condition for the duration. On a successful save, a target takes half as much damage only.\nA Frightened target makes a Wisdom saving throw at the end of each of its turns. On a failed save, it takes 5d10 Psychic damage. On a successful save, the spell ends on that target.","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Weird","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Wind Walk","constant":false,"content":"## Wind Walk (바람 걷기) - Level 6 Transmutation spell, SRD 5.2.1\nClasses: Druid. Casting Time: 1 minute. Range: 30 feet. Components: V, S, M (a candle). Duration: 8 hours.\nYou and up to ten willing creatures of your choice within range assume gaseous forms for the duration, appearing as wisps of cloud. While in this cloud form, a target has a Fly Speed of 300 feet and can hover; it has Immunity to the Prone condition; and it has Resistance to Bludgeoning, Piercing, and Slashing damage. The only actions a target can take in this form are the Dash action or a Magic action to begin reverting to its normal form. Reverting takes 1 minute, during which the target has the Stunned condition. Until the spell ends, the target can revert to cloud form, which also requires a Magic action followed by a 1-minute transformation.\nIf a target is in cloud form and flying when the effect ends, the target descends 60 feet per round for 1 minute until it lands, which it does safely. If it can't land after 1 minute, it falls the remaining distance.","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Wind Walk","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Wind Wall","constant":false,"content":"## Wind Wall (바람의 벽) - Level 3 Evocation spell, SRD 5.2.1\nClasses: Druid, Ranger. Casting Time: Action. Range: 120 feet. Components: V, S, M (a fan and a feather). Duration: Concentration, up to 1 minute.\nA wall of strong wind rises from the ground at a point you choose within range. You can make the wall up to 50 feet long, 15 feet high, and 1 foot thick. You can shape the wall in any way you choose so long as it makes one continuous path along the ground. The wall lasts for the duration.\nWhen the wall appears, each creature in its area makes a Strength saving throw, taking 4d8 Bludgeoning damage on a failed save or half as much damage on a successful one.\nThe strong wind keeps fog, smoke, and other gases at bay. Small or smaller flying creatures or objects can't pass through the wall. Loose, lightweight materials brought into the wall fly upward.\nArrows, bolts, and other ordinary projectiles launched at targets behind the wall are deflected upward and miss automatically. Boulders hurled by Giants or siege engines, and similar projectiles, are unaffected. Creatures in gaseous form can't pass through it. 175","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Wind Wall","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Wish","constant":false,"content":"## Wish (소원) - Level 9 Conjuration spell, SRD 5.2.1\nClasses: Sorcerer, Wizard. Casting Time: Action. Range: Self. Components: V. Duration: Instantaneous.\nWish is the mightiest spell a mortal can cast. By simply speaking aloud, you can alter reality itself.\nThe basic use of this spell is to duplicate any other spell of level 8 or lower. If you use it this way, you don't need to meet any requirements to cast that spell, including costly components. The spell simply takes effect.\nAlternatively, you can create one of the following effects of your choice:\nObject Creation. You create one object of up to 25,000 GP in value that isn't a magic item. The object can be no more than 300 feet in any dimension, and it appears in an unoccupied space that you can see on the ground.\nInstant Health. You allow yourself and up to twenty creatures that you can see to regain all Hit Points, and you end all effects on them listed in the Greater Restoration spell.\nResistance. You grant up to ten creatures that you can see Resistance to one damage type that you choose. This Resistance is permanent.\nSpell Immunity. You grant up to ten creatures you can see immunity to a single spell or other magical effect for 8 hours.\nSudden Learning. You replace one of your feats with another feat for which you are eligible. You lose all the benefits of the old feat and gain the benefits of the new one. You can't replace a feat that is a prerequisite for any of your other feats or features.\nRoll Redo. You undo a single recent event by forcing a reroll of any die roll made within the last round (including your last turn). Reality reshapes itself to accommodate the new result. For example, a Wish spell could undo an ally's failed saving throw or a foe's Critical Hit. You can force the reroll to be made with Advantage or Disadvantage, and you choose whether to use the reroll or the original roll.\nReshape Reality. You may wish for something not included in any of the other effects. To do so, state your wish to the GM as precisely as possible. The GM has great latitude in ruling what occurs in such an instance; the greater the wish, the greater the likelihood that something goes wrong. This spell might simply fail, the effect you desire might be achieved only in part, or you might suffer an unforeseen consequence as a result of how you worded the wish. For example, wishing that a villain were dead might propel you forward in time to a period when that villain is no longer alive, effectively removing you from the game.\nSimilarly, wishing for a Legendary magic item or an Artifact might instantly transport you to the presence of the item's current owner. If your wish is granted and its effects have consequences for a whole community, region, or world, you are likely to attract powerful foes. If your wish would affect a god, the god's divine servants might instantly intervene to prevent it or to encourage you to craft the wish in a particular way. If your wish would undo the multiverse itself, your wish fails.\nThe stress of casting Wish to produce any effect other than duplicating another spell weakens you.\nAfter enduring that stress, each time you cast a spell until you finish a Long Rest, you take 1d10 Necrotic damage per level of that spell. This damage can't be reduced or prevented in any way. In addition, your Strength score becomes 3 for 2d4 days.\nFor each of those days that you spend resting and doing nothing more than light activity, your remaining recovery time decreases by 2 days. Finally, there is a 33 percent chance that you are unable to cast Wish ever again if you suffer this stress.","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Wish","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Word of Recall","constant":false,"content":"## Word of Recall (귀환의 언령) - Level 6 Conjuration spell, SRD 5.2.1\nClasses: Cleric. Casting Time: Action. Range: 5 feet. Components: V. Duration: Instantaneous.\nYou and up to five willing creatures within 5 feet of you instantly teleport to a previously designated sanctuary. You and any creatures that teleport with you appear in the nearest unoccupied space to the spot you designated when you prepared your sanctuary (see below). If you cast this spell without first preparing a sanctuary, the spell has no effect.\nYou must designate a location, such as a temple, as a sanctuary by casting this spell there.","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Word of Recall","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"주문: Zone of Truth","constant":false,"content":"## Zone of Truth (진실의 공간) - Level 2 Enchantment spell, SRD 5.2.1\nClasses: Bard, Cleric, Paladin. Casting Time: Action. Range: 60 feet. Components: V, S. Duration: 10 minutes.\nYou create a magical zone that guards against deception in a 15-foot-radius Sphere centered on a point within range. Until the spell ends, a creature that enters the spell's area for the first time on a turn or starts its turn there makes a Charisma saving throw. On a failed save, a creature can't speak a deliberate lie while in the radius. You know whether a creature succeeds or fails on this save.\nAn affected creature is aware of the spell and can avoid answering questions to which it would normally respond with a lie. Such a creature can be evasive yet must be truthful. 176","enabled":true,"extensions":{},"folder":"folder:7e5a6046-fcf5-44da-a038-cfedad06204a","insertion_order":60,"keys":[""],"mode":"normal","name":"주문: Zone of Truth","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"규칙 · 캐릭터","constant":false,"content":"","enabled":true,"extensions":{},"insertion_order":60,"keys":["folder:5313df86-524c-48ac-a0a5-51dcdf2189ae"],"mode":"folder","name":"규칙 · 캐릭터","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"한글 용어 대조표 (항상)","constant":true,"content":"## Korean names (한글 용어 대조표)\nIn the Korean prose always use the Korean name below, never the English one or another translation (\"A/B\": either is fine). Tags keep the English names.\n- Rules: Heroic Inspiration 영웅적 영감, Advantage 이점, Disadvantage 불리점, Opportunity Attack 기회공격, attack roll 명중 굴림, death saving throw 죽음 내성 굴림, passive check 상시 판정, Bonus Action 추가 행동, Reaction 반응행동, saving throw 내성 굴림, Initiative 우선권, Cover 엄폐, Half Cover 절반 엄폐, Three-Quarters Cover 3/4 엄폐, Armor Class 방어도, Proficiency Bonus 숙련 보너스, Hit Point Dice 생명력 주사위, Short Rest 짧은 휴식, Long Rest 긴 휴식, spell slot 주문 슬롯, Cantrip 소마법, critical hit 치명타\n- Weapon Mastery properties: Cleave 가르기, Graze 스치기, Nick 잇기, Push 밀치기, Sap 약화, Slow 둔화, Topple 넘어뜨리기, Vex 괴롭히기\n- Abilities: Strength 근력, Dexterity 민첩, Constitution 건강, Intelligence 지능, Wisdom 지혜, Charisma 매력\n- Skills: Acrobatics 곡예, Animal Handling 동물 조련, Arcana 비전학, Athletics 운동, Deception 기만, History 역사학, Insight 통찰, Intimidation 위협, Investigation 수사, Medicine 의학, Nature 자연학, Perception 감지, Performance 공연, Persuasion 설득, Religion 종교학, Sleight of Hand 손속임, Stealth 은신, Survival 생존\n- Conditions: Blinded 장님, Charmed 매혹, Deafened 귀머거리, Exhaustion 탈진, Frightened 공포, Grappled 붙잡힘, Incapacitated 행동불능, Invisible 투명, Paralyzed 마비, Petrified 석화, Poisoned 중독, Prone 넘어진 상태, Restrained 포박, Stunned 충격, Unconscious 무의식\n- Classes: Fighter 파이터, Rogue 로그, Cleric 클레릭, Wizard 위저드, Barbarian 바바리안, Bard 바드, Druid 드루이드, Monk 몽크, Paladin 팔라딘, Ranger 레인저, Sorcerer 소서러, Warlock 워락\n- Species: Dragonborn 드래곤본, Dwarf 드워프, Elf 엘프, Gnome 노움, Goliath 골리앗, Halfling 하플링, Human 인간, Orc 오크, Tiefling 티플링\n- Backgrounds: Acolyte 복사, Criminal 범죄자, Sage 학자, Soldier 군인\n- Features: Fighting Style 전투 유파, Archery 궁술, Defense 방어술, Great Weapon Fighting 대형 무기 전투술, Two-Weapon Fighting 쌍수 전투술, Second Wind 재기의 바람, Action Surge 행동 연쇄, Extra Attack 추가 공격, Improved Critical 향상된 치명타, Remarkable Athlete 뛰어난 운동능력, Expertise 숙달, Sneak Attack 암습 공격, Thieves' Cant 도둑의 속어, Cunning Action 교활한 행동, Uncanny Dodge 놀라운 회피, Fast Hands 빠른 손놀림, Second-Story Work 오르내리기, Channel Divinity 신성 변환, Turn Undead 언데드 퇴치, Disciple of Life 생명의 사도, Preserve Life 생명 보존, Arcane Recovery 비전 회복, Ritual Adept 의식 시전, Evocation Savant 방출계 전공, Potent Cantrip 강화된 소마법, Darkvision 암시야, Dwarven Resilience 드워프의 탄성, Dwarven Toughness 드워프의 끈기, Stonecunning 돌의 꾀, Fey Ancestry 요정 선조, Trance 망아상태, Keen Senses 예리한 감각, Gnome Cunning 노움의 교활함, Lucky 행운아, Brave 용감함, Halfling Nimbleness 하플링의 기민함, Relentless Endurance 불굴의 인내력, Breath Weapon 브레스 무기, Damage Resistance 피해 저항, Weapon Mastery 무기 통달, Tactical Mind 전술적 사고, Tactical Shift 전술적 이동, Steady Aim 차분한 조준, Cunning Strike 교활한 일격, Divine Order 신성한 소임, Sear Undead 언데드 태우기, Scholar 학자, Memorize Spell 주문 암기, Spellcasting 주문시전, Ability Score Improvement 능력치 점수 상승, Rage 격노, Unarmored Defense 비무장 방어, Danger Sense 위험 감지, Reckless Attack 무모한 공격, Primal Knowledge 원시의 지식, Fast Movement 빠른 이동, Frenzy 광분, Bardic Inspiration 바드의 고양감, Jack of All Trades 팔방미인, Font of Inspiration 고양감의 샘, Cutting Words 날카로운 말, Druidic 드루이드어, Primal Order 원시의 소임, Wild Shape 야생 변신, Wild Companion 야생의 동료, Wild Resurgence 야생의 재기, Land's Aid 대지의 도움, Martial Arts 무술, Monk's Focus 기, Focus Points 기 점수, Unarmored Movement 비무장 이동, Uncanny Metabolism 놀라운 신진대사, Deflect Attacks 공격 쳐내기, Slow Fall 저속 낙하, Stunning Strike 충격의 일격, Flurry of Blows 연타, Patient Defense 인내의 방어, Step of the Wind 바람 걸음, Lay On Hands 치유의 손길, Paladin's Smite 팔라딘의 강타, Faithful Steed 충직한 군마, Sacred Weapon 무기 축성, Favored Enemy 선호하는 적, Deft Explorer 능숙한 탐험가, Colossus Slayer 거체 학살자, Horde Breaker 무리 파쇄자, Innate Sorcery 타고난 술법, Font of Magic 마법력의 샘, Sorcery Points 술법 점수, Metamagic 마법변형, Sorcerous Restoration 술법 회복, Eldritch Invocations 섬뜩한 영창, Pact Magic 계약 마법, Magical Cunning 마법적 교활함, Mystic Arcanum 신비의 비밀, Dark One's Blessing 어두운 이의 축복, Barbarian Subclass 바바리안 하위 직업, Bard Subclass 바드 하위 직업, Druid Subclass 드루이드 하위 직업, Monk Subclass 몽크 하위 직업, Paladin Subclass 팔라딘 하위 직업, Ranger Subclass 레인저 하위 직업, Sorcerer Subclass 소서러 하위 직업, Warlock Subclass 워락 하위 직업, Careful Spell 주문 세심화, Distant Spell 주문 원거리화, Empowered Spell 주문 강력화, Extended Spell 주문 연장화, Heightened Spell 주문 상승화, Quickened Spell 주문 신속화, Seeking Spell 주문 추적화, Subtle Spell 주문 미묘화, Transmuted Spell 주문 변환화, Twinned Spell 주문 이중화, Agonizing Blast 고뇌의 마탄, Armor of Shadows 그림자의 갑옷, Devil's Sight 악마의 눈, Eldritch Mind 섬뜩한 정신, Fiendish Vigor 악마의 활력, Mask of Many Faces 수많은 얼굴의 가면, Misty Visions 안개의 시야, Pact of the Blade 칼날의 계약, Pact of the Chain 사슬의 계약, Pact of the Tome 고서의 계약, Repelling Blast 격퇴의 마탄, Thirsting Blade 목마른 칼날, One with Shadows 그림자의 동행, Master of Myriad Forms 수많은 형태의 주인, Ascendant Step 승천의 발걸음, Gift of the Depths 심연의 선물, Mindless Rage 무아지경의 격노, Feral Instinct 야만의 본능, Instinctive Pounce 본능적 도약, Brutal Strike 잔혹한 일격, Retaliation 앙갚음, Magical Discoveries 마법적 발견, Countercharm 매혹반사, Magical Secrets 마법적 비밀, Blessed Healer 축복받은 치유사, Blessed Strikes 축복받은 일격, Divine Strike 신성한 일격, Potent Spellcasting 강화된 주문시전, Divine Intervention 신의 간섭, Natural Recovery 자연적 회복력, Elemental Fury 원소의 분노, Primal Strike 원시의 일격, Nature's Ward 자연의 보호, Additional Fighting Style 추가 전투 유파, Indomitable 불요불굴, Tactical Master 전술의 달인, Heroic Warrior 영웅적 전사, Empowered Strikes 강기 일격, Wholeness of Body 신체의 완전화, Evasion 회피기동, Acrobatic Movement 곡예 이동, Heightened Focus 고양된 기, Self-Restoration 자기 회복, Aura of Protection 보호의 오오라, Aura of Devotion 헌신의 오오라, Abjure Foes 적 물리치기, Aura of Courage 용기의 오오라, Roving 방랑, Defensive Tactics 방어적 전술, Escape the Horde 무리 탈출, Multiattack Defense 다중공격 방어, Tireless 지치지 않음, Reliable Talent 믿음직한 재능, Supreme Sneak 뛰어난 은신술, Elemental Affinity 원소 친화, Sorcery Incarnate 술법의 화신, Dark One's Own Luck 어두운 이의 명운, Contact Patron 후원자 접촉, Fiendish Resilience 악마의 탄성, Sculpt Spells 주문 조정, Empowered Evocation 강화된 방출, Relentless Rage 끈질긴 격노, Improved Brutal Strike 향상된 잔혹한 일격, Persistent Rage 지속되는 격노, Intimidating Presence 위협적 존재감, Peerless Skill 독보적인 기술, Improved Blessed Strikes 향상된 축복받은 일격, Nature's Sanctuary 자연의 성역, Improved Elemental Fury 향상된 원소의 분노, Two Extra Attacks 추가 공격 두 번, Indomitable (two uses) 불요불굴 (2회), Studied Attacks 공부한 공격, Superior Critical 우월한 치명타, Fleet Step 날랜 걸음, Deflect Energy 에너지 쳐내기, Disciplined Survivor 단련된 생존자, Perfect Focus 완벽한 집중, Radiant Strikes 광휘의 일격, Restoring Touch 회복의 손길, Smite of Protection 보호의 강타, Superior Hunter's Prey 우월한 사냥꾼의 사냥감, Relentless Hunter 끈질긴 사냥꾼, Nature's Veil 자연의 장막, Superior Hunter's Defense 우월한 사냥꾼의 방어, Improved Cunning Strike 향상된 교활한 일격, Use Magic Device 마법 도구 사용, Devious Strikes 음흉한 일격, Slippery Mind 유연한 마음가짐, Dragon Wings 용의 날개, Mystic Arcanum (level 6 spell) 신비의 비밀 (6레벨 주문), Mystic Arcanum (level 7 spell) 신비의 비밀 (7레벨 주문), Mystic Arcanum (level 8 spell) 신비의 비밀 (8레벨 주문), Hurl Through Hell 지옥너머로 던지기, Overchannel 과전환, Eldritch Spear 섬뜩한 창, Otherworldly Leap 외세계의 도약, Gaze of Two Minds 두 마음의 시선, Whispers of the Grave 무덤의 속삭임, Visions of Distant Realms 머나먼 땅의 영상, Witch Sight 주술 시야, Lifedrinker 생명을 마시는 자, Devouring Blade 탐식의 칼날, Eldritch Smite 섬뜩한 강타, Gift of the Protectors 수호자의 선물, Investment of the Chain Master 사슬 주인의 권능, Improved Brutal Strike (2d10) 향상된 잔혹한 일격 (2d10), Indomitable Might 불굴의 힘, Primal Champion 원시의 용사, Superior Inspiration 우월한 고양감, Words of Creation 창조의 언령, Supreme Healing 최상의 치유력, Greater Divine Intervention 상위 신의 간섭, Beast Spells 야수 주문, Archdruid 대드루이드, Action Surge (two uses) 행동 연쇄 (2회), Indomitable (three uses) 불요불굴 (3회), Survivor 생존의 대가, Three Extra Attacks 추가 공격 세 번, Quivering Palm 진동장, Superior Defense 우월한 방어, Body and Mind 몸과 마음, Aura Expansion 오오라 확장, Holy Nimbus 신성한 후광, Precise Hunter 정밀한 사냥꾼, Feral Senses 야생 감각, Foe Slayer 적 살해자, Thief's Reflexes 도둑의 반사신경, Elusive 회피본능, Stroke of Luck 행운의 한 방, Dragon Companion 용 동료, Arcane Apotheosis 비전의 신격화, Mystic Arcanum (level 9 spell) 신비의 비밀 (9레벨 주문), Eldritch Master 섬뜩한 대가, Spell Mastery 주문 통달, Signature Spells 대표 주문, Epic Boon 에픽 은혜, Boon of Combat Prowess 전투 기량의 은혜, Boon of Dimensional Travel 차원 여행의 은혜, Boon of Fate 운명의 은혜, Boon of Irresistible Offense 저항할 수 없는 공격의 은혜, Boon of Spell Recall 주문 회상의 은혜, Boon of the Night Spirit 밤의 영혼의 은혜, Boon of Truesight 진시야의 은혜, Heroic Rally 영웅적 재기\n- Weapons: Club 클럽/곤봉, Dagger 대거/단검, Greatclub 그레이트클럽/대곤봉, Handaxe 핸드액스/손도끼, Javelin 자벨린/투창, Light Hammer 라이트 해머/경량 망치, Mace 메이스/철퇴, Quarterstaff 쿼터스태프/육척봉, Sickle 시클/낫, Spear 스피어/창, Dart 다트, Light Crossbow 라이트 크로스보우/경석궁, Shortbow 숏보우/단궁, Sling 슬링/돌팔매, Battleaxe 배틀액스/전투도끼, Flail 플레일/도리깨, Glaive 글레이브/장도, Greataxe 그레이트액스/대도끼, Greatsword 그레이트소드/대검, Halberd 할버드/미늘창, Lance 랜스/거창, Longsword 롱소드/장검, Maul 마울/거대망치, Morningstar 모닝스타, Pike 파이크/장창, Rapier 레이피어, Scimitar 시미터/언월도, Shortsword 숏소드/소검, Trident 트라이던트/삼지창, Warhammer 워해머/전쟁망치, War Pick 워 픽/전쟁 곡괭이, Whip 채찍, Blowgun 블로우건/바람총, Hand Crossbow 핸드 크로스보우/손 석궁, Heavy Crossbow 헤비 크로스보우/중석궁, Longbow 롱보우/장궁, Musket 머스킷, Pistol 권총\n- Armor: Padded Armor 패디드 아머, Leather Armor 가죽 갑옷, Studded Leather Armor 스터디드 레더, Hide Armor 하이드 아머, Chain Shirt 체인 셔츠, Scale Mail 비늘 갑옷, Breastplate 흉갑, Half Plate Armor 하프 플레이트, Ring Mail 링 메일, Chain Mail 사슬 갑옷, Splint Armor 스플린트, Plate Armor 판금 갑옷, Shield 방패\n- Gear: Potion of Healing 치유의 물약, Potion of Greater Healing 상급 치유의 물약, Potion of Superior Healing 최상급 치유의 물약, Potion of Supreme Healing 최상위 치유의 물약, Healer's Kit 치유사의 키트, Antitoxin 해독제, Alchemist's Fire 연금술사의 불, Acid 산, Holy Water 성수, Arrows 화살, Bolts 석궁 볼트, Firearm Bullets 총탄, Sling Bullets 슬링 탄환, Needles 블로우건 바늘, Oil 기름, Basic Poison 기본 독\n- Other gear: 2 Pouches 주머니 2개, Book (history) 역사책, Book (prayers) 기도서, Burglar's Pack 도둑 꾸러미, Calligrapher's Supplies 서예가 도구, Crowbar 쇠지렛대, Dungeoneer's Pack 던전 탐험가 꾸러미, Gaming Set 놀이 도구, Holy Symbol 성표, Parchment (10 sheets) 양피지 10장, Parchment (8 sheets) 양피지 8장, Priest's Pack 사제 꾸러미, Quiver 화살통, Robe 로브, Scholar's Pack 학자 꾸러미, Spellbook 주문책, Thieves' Tools 도둑 도구, Traveler's Clothes 여행복, Explorer's Pack 탐험가 꾸러미, Entertainer's Pack 공연가 꾸러미, Artisan's Tools 장인 도구, Herbalism Kit 약초학 키트, Musical Instrument 악기, Book (occult lore) 신비학 서적, Arcane Focus (crystal) 비전 매개체 (수정), Arcane Focus (orb) 비전 매개체 (구슬), Druidic Focus (sprig of mistletoe) 드루이드 매개체 (겨우살이 가지)\n- Feats: Magic Initiate 마법 입문자, Alert 경계심, Savage Attacker 야만적인 공격자, Grappler 잡기 전문가","enabled":true,"extensions":{},"folder":"folder:5313df86-524c-48ac-a0a5-51dcdf2189ae","insertion_order":90,"keys":[""],"mode":"normal","name":"한글 용어 대조표 (항상)","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"종족: 드래곤본","constant":false,"content":"## Dragonborn (드래곤본) - species, SRD 5.2.1\nCreature Type: Humanoid\nSize: Medium (about 5-7 feet tall)\nSpeed: 30 feet As a Dragonborn, you have these special traits.\nDraconic Ancestry. Your lineage stems from a dragon progenitor. Choose the kind of dragon from the Draconic Ancestors table. Your choice affects your Breath Weapon and Damage Resistance traits as well as your appearance. Draconic Ancestors Dragon Damage Type Dragon Damage Type Black Acid Gold Fire Blue Lightning Green Poison Brass Fire Red Fire Bronze Lightning Silver Cold Copper Acid White Cold Breath Weapon. When you take the Attack action on your turn, you can replace one of your attacks with an exhalation of magical energy in either a 15-foot Cone or a 30-foot Line that is 5 feet wide (choose the shape each time). Each creature in that area must make a Dexterity saving throw (DC 8 plus your Constitution modifier and Proficiency Bonus). On a failed save, a creature takes 1d10 damage of the type determined by your Draconic Ancestry trait. On a successful save, a creature takes half as much damage. This damage increases by 1d10 when you reach character levels 5 (2d10), 11 (3d10), and 17 (4d10). You can use this Breath Weapon a number of times equal to your Proficiency Bonus, and you regain all expended uses when you finish a Long Rest.\nDamage Resistance. You have Resistance to the damage type determined by your Draconic Ancestry trait.\nDarkvision. You have Darkvision with a range of 60 feet.\nDraconic Flight. When you reach character level 5, you can channel draconic magic to give yourself temporary flight. As a Bonus Action, you sprout spectral wings on your back that last for 10 minutes or until you retract the wings (no action required) or have the Incapacitated condition. During that time, you have a Fly Speed equal to your Speed. Your wings appear to be made of the same energy as your Breath Weapon. Once you use this trait, you can't use it again until you finish a Long Rest.","enabled":true,"extensions":{},"folder":"folder:5313df86-524c-48ac-a0a5-51dcdf2189ae","insertion_order":60,"keys":[""],"mode":"normal","name":"종족: 드래곤본","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"종족: 드워프","constant":false,"content":"## Dwarf (드워프) - species, SRD 5.2.1\nCreature Type: Humanoid\nSize: Medium (about 4-5 feet tall)\nSpeed: 30 feet As a Dwarf, you have these special traits.\nDarkvision. You have Darkvision with a range of 120 feet.\nDwarven Resilience. You have Resistance to Poison damage. You also have Advantage on saving throws you make to avoid or end the Poisoned condition.\nDwarven Toughness. Your Hit Point maximum increases by 1, and it increases by 1 again whenever you gain a level.\nStonecunning. As a Bonus Action, you gain Tremorsense with a range of 60 feet for 10 minutes. You must be on a stone surface or touching a stone surface to use this Tremorsense. The stone can be natural or worked. You can use this Bonus Action a number of times equal to your Proficiency Bonus, and you regain all expended uses when you finish a Long Rest.","enabled":true,"extensions":{},"folder":"folder:5313df86-524c-48ac-a0a5-51dcdf2189ae","insertion_order":60,"keys":[""],"mode":"normal","name":"종족: 드워프","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"종족: 엘프","constant":false,"content":"## Elf (엘프) - species, SRD 5.2.1\nCreature Type: Humanoid\nSize: Medium (about 5-6 feet tall)\nSpeed: 30 feet As an Elf, you have these special traits.\nDarkvision. You have Darkvision with a range of 60 feet.\nElven Lineage. You are part of a lineage that grants you supernatural abilities. Choose a lineage from the Elven Lineages table. You gain the level 1 benefit of that lineage. When you reach character levels 3 and 5, you learn a higher-level spell, as shown on the table.\nYou always have that spell prepared. You can cast it once without a spell slot, and you regain the ability to cast it in that way when you finish a Long Rest. You can also cast the spell using any spell slots you have of the appropriate level.   85 Intelligence, Wisdom, or Charisma is your spellcasting ability for the spells you cast with this trait (choose the ability when you select the lineage).\nFey Ancestry. You have Advantage on saving throws you make to avoid or end the Charmed condition.\nKeen Senses. You have proficiency in the Insight, Perception, or Survival skill.\nTrance. You don't need to sleep, and magic can't put you to sleep. You can finish a Long Rest in 4 hours if you spend those hours in a trancelike meditation, during which you retain consciousness.","enabled":true,"extensions":{},"folder":"folder:5313df86-524c-48ac-a0a5-51dcdf2189ae","insertion_order":60,"keys":[""],"mode":"normal","name":"종족: 엘프","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"종족: 노움","constant":false,"content":"## Gnome (노움) - species, SRD 5.2.1\nCreature Type: Humanoid\nSize: Small (about 3-4 feet tall)\nSpeed: 30 feet As a Gnome, you have these special traits.\nDarkvision. You have Darkvision with a range of 60 feet.\nGnomish Cunning. You have Advantage on Intelligence, Wisdom, and Charisma saving throws.\nGnomish Lineage. You are part of a lineage that grants you supernatural abilities. Choose one of the following options; whichever one you choose, Intelligence, Wisdom, or Charisma is your spellcasting ability for the spells you cast with this trait (choose the ability when you select the lineage): Forest Gnome. You know the Minor Illusion cantrip. You also always have the Speak with Animals spell prepared. You can cast it without a spell slot a number of times equal to your Proficiency Bonus, and you regain all expended uses when you finish a Long Rest. You can also use any spell slots you have to cast the spell.\nRock Gnome. You know the Mending and Prestidigitation cantrips. In addition, you can spend 10 minutes casting Prestidigitation to create a Tiny clockwork device (AC 5, 1 HP), such as a toy, fire starter, or music box. When you create the device, you determine its function by choosing one effect from Prestidigitation; the device produces that effect whenever you or another creature takes a Bonus Action to activate it with a touch. If the chosen effect has options within it, you choose one of those options for the device when you create it. For example, if you choose the spell's ignite-extinguish effect, you determine whether the device ignites or extinguishes fire; the device doesn't do both. You can have three such devices in existence at a time, and each falls apart 8 hours after its creation or when you dismantle it with a touch as a Utilize action.","enabled":true,"extensions":{},"folder":"folder:5313df86-524c-48ac-a0a5-51dcdf2189ae","insertion_order":60,"keys":[""],"mode":"normal","name":"종족: 노움","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"종족: 골리앗","constant":false,"content":"## Goliath (골리앗) - species, SRD 5.2.1\nCreature Type: Humanoid\nSize: Medium (about 7-8 feet tall)\nSpeed: 35 feet As a Goliath, you have these special traits.\nGiant Ancestry. You are descended from Giants. Choose one of the following benefits—a supernatural boon from your ancestry; you can use the chosen benefit a number of times equal to your Proficiency Bonus, and you regain all expended uses when you finish a Long Rest: Cloud's Jaunt (Cloud Giant). As a Bonus Action, you magically teleport up to 30 feet to an unoccupied space you can see.\nFire's Burn (Fire Giant). When you hit a target with an attack roll and deal damage to it, you can also deal 1d10 Fire damage to that target.\nFrost's Chill (Frost Giant). When you hit a target with an attack roll and deal damage to it, you can also deal 1d6 Cold damage to that target and reduce its Speed by 10 feet until the start of your next turn.\nHill's Tumble (Hill Giant). When you hit a Large or smaller creature with an attack roll and deal damage to it, you can give that target the Prone condition.\nStone's Endurance (Stone Giant). When you take damage, you can take a Reaction to roll 1d12. Add your Constitution modifier to the number rolled and reduce the damage by that total. Elven Lineages Lineage Level 1 Level 3 Level 5 Drow The range of your Darkvision increases to 120 feet. ​ You also know the Dancing Lights cantrip. Faerie Fire Darkness High Elf You know the Prestidigitation cantrip. Whenever you finish a Long Rest, you can replace that cantrip with a different cantrip from the Wizard spell list. Detect Magic Misty Step Wood Elf Your Speed increases to 35 feet. You also know the Druidcraft cantrip. Longstrider Pass without Trace   86 Storm's Thunder (Storm Giant). When you take damage from a creature within 60 feet of you, you can take a Reaction to deal 1d8 Thunder damage to that creature.\nLarge Form. Starting at character level 5, you can change your size to Large as a Bonus Action if you're in a big enough space. This transformation lasts for 10 minutes or until you end it (no action required). For that duration, you have Advantage on Strength checks, and your Speed increases by 10 feet. Once you use this trait, you can't use it again until you finish a Long Rest.\nPowerful Build. You have Advantage on any ability check you make to end the Grappled condition. You also count as one size larger when determining your carrying capacity.","enabled":true,"extensions":{},"folder":"folder:5313df86-524c-48ac-a0a5-51dcdf2189ae","insertion_order":60,"keys":[""],"mode":"normal","name":"종족: 골리앗","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"종족: 하플링","constant":false,"content":"## Halfling (하플링) - species, SRD 5.2.1\nCreature Type: Humanoid\nSize: Small (about 2-3 feet tall)\nSpeed: 30 feet As a Halfling, you have these special traits.\nBrave. You have Advantage on saving throws you make to avoid or end the Frightened condition.\nHalfling Nimbleness. You can move through the space of any creature that is a size larger than you, but you can't stop in the same space.\nLuck. When you roll a 1 on the d20 of a D20 Test, you can reroll the die, and you must use the new roll.\nNaturally Stealthy. You can take the Hide action even when you are obscured only by a creature that is at least one size larger than you.","enabled":true,"extensions":{},"folder":"folder:5313df86-524c-48ac-a0a5-51dcdf2189ae","insertion_order":60,"keys":[""],"mode":"normal","name":"종족: 하플링","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"종족: 인간","constant":false,"content":"## Human (인간) - species, SRD 5.2.1\nCreature Type: Humanoid\nSize: Medium (about 4-7 feet tall) or Small (about 2-4 feet tall), chosen when you select this species\nSpeed: 30 feet As a Human, you have these special traits.\nResourceful. You gain Heroic Inspiration whenever you finish a Long Rest.\nSkillful. You gain proficiency in one skill of your choice.\nVersatile. You gain an Origin feat of your choice (see “Feats”). Skilled is recommended.","enabled":true,"extensions":{},"folder":"folder:5313df86-524c-48ac-a0a5-51dcdf2189ae","insertion_order":60,"keys":[""],"mode":"normal","name":"종족: 인간","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"종족: 오크","constant":false,"content":"## Orc (오크) - species, SRD 5.2.1\nCreature Type: Humanoid\nSize: Medium (about 6-7 feet tall)\nSpeed: 30 feet As an Orc, you have these special traits.\nAdrenaline Rush. You can take the Dash action as a Bonus Action. When you do so, you gain a number of Temporary Hit Points equal to your Proficiency Bonus. You can use this trait a number of times equal to your Proficiency Bonus, and you regain all expended uses when you finish a Short or Long Rest.\nDarkvision. You have Darkvision with a range of 120 feet.\nRelentless Endurance. When you are reduced to 0 Hit Points but not killed outright, you can drop to 1 Hit Point instead. Once you use this trait, you can't do so again until you finish a Long Rest.","enabled":true,"extensions":{},"folder":"folder:5313df86-524c-48ac-a0a5-51dcdf2189ae","insertion_order":60,"keys":[""],"mode":"normal","name":"종족: 오크","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"종족: 티플링","constant":false,"content":"## Tiefling (티플링) - species, SRD 5.2.1\nCreature Type: Humanoid\nSize: Medium (about 4-7 feet tall) or Small (about 3-4 feet tall), chosen when you select this species\nSpeed: 30 feet As a Tiefling, you have the following special traits.\nDarkvision. You have Darkvision with a range of 60 feet.\nFiendish Legacy. You are the recipient of a legacy that grants you supernatural abilities. Choose a legacy from the Fiendish Legacies table. You gain the level 1 benefit of the chosen legacy. When you reach character levels 3 and 5, you learn a higher-level spell, as shown on the table.\nYou always have that spell prepared. You can cast it once without a spell slot, and you regain the ability to cast it in that way when you finish a Long Rest. You can also cast the spell using any spell slots you have of the appropriate level. Intelligence, Wisdom, or Charisma is your spellcasting ability for the spells you cast with this trait (choose the ability when you select the legacy).\nOtherworldly Presence. You know the Thaumaturgy cantrip. When you cast it with this trait, the spell uses the same spellcasting ability you use for your Fiendish Legacy trait. Fiendish Legacies Legacy Level 1 Level 3 Level 5 Abyssal You have Resistance to Poison damage.\nYou also know the Poison Spray cantrip. Ray of Sickness Hold Person Chthonic You have Resistance to Necrotic damage.\nYou also know the Chill Touch cantrip. False Life Ray of Enfeeblement Infernal You have Resistance to Fire damage.\nYou also know the Fire Bolt cantrip. Hellish Rebuke Darkness   87","enabled":true,"extensions":{},"folder":"folder:5313df86-524c-48ac-a0a5-51dcdf2189ae","insertion_order":60,"keys":[""],"mode":"normal","name":"종족: 티플링","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"클래스: 파이터","constant":false,"content":"## Fighter (파이터) - class, SRD 5.2.1 (levels 1-20)\nHit Die d10. Saving throws: Strength, Constitution. Skills: choose 2 from Acrobatics, Animal Handling, Athletics, History, Insight, Intimidation, Persuasion, Perception, Survival. Weapons: Simple and Martial weapons. Armor: Light, Medium, and Heavy armor and Shields. Subclass at level 3: Champion.\n- Level 1: Fighting Style, Second Wind, Weapon Mastery\n- Level 2: Action Surge (one use), Tactical Mind\n- Level 3: Fighter Subclass\n- Level 4: Ability Score Improvement\n- Level 5: Extra Attack, Tactical Shift\n- Level 6: Ability Score Improvement\n- Level 7: Champion: Additional Fighting Style\n- Level 8: Ability Score Improvement\n- Level 9: Indomitable (one use), Tactical Master\n- Level 10: Champion: Heroic Warrior\n- Level 11: Two Extra Attacks\n- Level 12: Ability Score Improvement\n- Level 13: Indomitable (two uses), Studied Attacks\n- Level 14: Ability Score Improvement\n- Level 15: Champion: Superior Critical\n- Level 16: Ability Score Improvement\n- Level 17: Action Surge (two uses), Indomitable (three uses)\n- Level 18: Champion: Survivor\n- Level 19: Epic Boon\n- Level 20: Three Extra Attacks","enabled":true,"extensions":{},"folder":"folder:5313df86-524c-48ac-a0a5-51dcdf2189ae","insertion_order":60,"keys":[""],"mode":"normal","name":"클래스: 파이터","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"클래스: 로그","constant":false,"content":"## Rogue (로그) - class, SRD 5.2.1 (levels 1-20)\nHit Die d8. Saving throws: Dexterity, Intelligence. Skills: choose 4 from Acrobatics, Athletics, Deception, Insight, Intimidation, Investigation, Perception, Persuasion, Sleight of Hand, Stealth. Weapons: Simple weapons and Martial weapons that have the Finesse or Light property. Armor: Light armor. Subclass at level 3: Thief.\n- Level 1: Expertise, Sneak Attack, Thieves' Cant, Weapon Mastery\n- Level 2: Cunning Action\n- Level 3: Rogue Subclass, Steady Aim\n- Level 4: Ability Score Improvement\n- Level 5: Cunning Strike, Uncanny Dodge\n- Level 6: Expertise\n- Level 7: Evasion, Reliable Talent\n- Level 8: Ability Score Improvement\n- Level 9: Thief: Supreme Sneak\n- Level 10: Ability Score Improvement\n- Level 11: Improved Cunning Strike\n- Level 12: Ability Score Improvement\n- Level 13: Thief: Use Magic Device\n- Level 14: Devious Strikes\n- Level 15: Slippery Mind\n- Level 16: Ability Score Improvement\n- Level 17: Thief: Thief's Reflexes\n- Level 18: Elusive\n- Level 19: Epic Boon\n- Level 20: Stroke of Luck","enabled":true,"extensions":{},"folder":"folder:5313df86-524c-48ac-a0a5-51dcdf2189ae","insertion_order":60,"keys":[""],"mode":"normal","name":"클래스: 로그","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"클래스: 클레릭","constant":false,"content":"## Cleric (클레릭) - class, SRD 5.2.1 (levels 1-20)\nHit Die d8. Saving throws: Wisdom, Charisma. Skills: choose 2 from History, Insight, Medicine, Persuasion, Religion. Weapons: Simple weapons. Armor: Light and Medium armor and Shields. Subclass at level 3: Life Domain.\n- Level 1: Spellcasting, Divine Order\n- Level 2: Channel Divinity\n- Level 3: Cleric Subclass\n- Level 4: Ability Score Improvement\n- Level 5: Sear Undead\n- Level 6: Life Domain: Blessed Healer\n- Level 7: Blessed Strikes\n- Level 8: Ability Score Improvement\n- Level 9: --\n- Level 10: Divine Intervention\n- Level 11: --\n- Level 12: Ability Score Improvement\n- Level 13: --\n- Level 14: Improved Blessed Strikes\n- Level 15: --\n- Level 16: Ability Score Improvement\n- Level 17: Life Domain: Supreme Healing\n- Level 18: --\n- Level 19: Epic Boon\n- Level 20: Greater Divine Intervention","enabled":true,"extensions":{},"folder":"folder:5313df86-524c-48ac-a0a5-51dcdf2189ae","insertion_order":60,"keys":[""],"mode":"normal","name":"클래스: 클레릭","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"클래스: 위저드","constant":false,"content":"## Wizard (위저드) - class, SRD 5.2.1 (levels 1-20)\nHit Die d6. Saving throws: Intelligence, Wisdom. Skills: choose 2 from Arcana, History, Insight, Investigation, Medicine, Nature, Religion. Weapons: Simple weapons. Armor: None. Subclass at level 3: Evoker.\n- Level 1: Spellcasting, Ritual Adept, Arcane Recovery\n- Level 2: Scholar\n- Level 3: Wizard Subclass\n- Level 4: Ability Score Improvement\n- Level 5: Memorize Spell\n- Level 6: Evoker: Sculpt Spells\n- Level 7: --\n- Level 8: Ability Score Improvement\n- Level 9: --\n- Level 10: Evoker: Empowered Evocation\n- Level 11: --\n- Level 12: Ability Score Improvement\n- Level 13: --\n- Level 14: Evoker: Overchannel\n- Level 15: --\n- Level 16: Ability Score Improvement\n- Level 17: --\n- Level 18: Spell Mastery\n- Level 19: Epic Boon\n- Level 20: Signature Spells","enabled":true,"extensions":{},"folder":"folder:5313df86-524c-48ac-a0a5-51dcdf2189ae","insertion_order":60,"keys":[""],"mode":"normal","name":"클래스: 위저드","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"클래스: 바바리안","constant":false,"content":"## Barbarian (바바리안) - class, SRD 5.2.1 (levels 1-20)\nHit Die d12. Saving throws: Strength, Constitution. Skills: choose 2 from Animal Handling, Athletics, Intimidation, Nature, Perception, Survival. Weapons: Simple and Martial weapons. Armor: Light and Medium armor and Shields. Subclass at level 3: Path of the Berserker.\n- Level 1: Rage, Unarmored Defense, Weapon Mastery\n- Level 2: Danger Sense, Reckless Attack\n- Level 3: Barbarian Subclass, Primal Knowledge\n- Level 4: Ability Score Improvement\n- Level 5: Extra Attack, Fast Movement\n- Level 6: Path of the Berserker: Mindless Rage\n- Level 7: Feral Instinct, Instinctive Pounce\n- Level 8: Ability Score Improvement\n- Level 9: Brutal Strike\n- Level 10: Path of the Berserker: Retaliation\n- Level 11: Relentless Rage\n- Level 12: Ability Score Improvement\n- Level 13: Improved Brutal Strike\n- Level 14: Path of the Berserker: Intimidating Presence\n- Level 15: Persistent Rage\n- Level 16: Ability Score Improvement\n- Level 17: Improved Brutal Strike (2d10)\n- Level 18: Indomitable Might\n- Level 19: Epic Boon\n- Level 20: Primal Champion","enabled":true,"extensions":{},"folder":"folder:5313df86-524c-48ac-a0a5-51dcdf2189ae","insertion_order":60,"keys":[""],"mode":"normal","name":"클래스: 바바리안","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"클래스: 바드","constant":false,"content":"## Bard (바드) - class, SRD 5.2.1 (levels 1-20)\nHit Die d8. Saving throws: Dexterity, Charisma. Skills: choose 3 from Acrobatics, Animal Handling, Arcana, Athletics, Deception, History, Insight, Intimidation, Investigation, Medicine, Nature, Perception, Performance, Persuasion, Religion, Sleight of Hand, Stealth, Survival. Weapons: Simple weapons. Armor: Light armor. Subclass at level 3: College of Lore.\n- Level 1: Bardic Inspiration, Spellcasting\n- Level 2: Expertise, Jack of All Trades\n- Level 3: Bard Subclass\n- Level 4: Ability Score Improvement\n- Level 5: Font of Inspiration\n- Level 6: College of Lore: Magical Discoveries\n- Level 7: Countercharm\n- Level 8: Ability Score Improvement\n- Level 9: Expertise\n- Level 10: Magical Secrets\n- Level 11: --\n- Level 12: Ability Score Improvement\n- Level 13: --\n- Level 14: College of Lore: Peerless Skill\n- Level 15: --\n- Level 16: Ability Score Improvement\n- Level 17: --\n- Level 18: Superior Inspiration\n- Level 19: Epic Boon\n- Level 20: Words of Creation","enabled":true,"extensions":{},"folder":"folder:5313df86-524c-48ac-a0a5-51dcdf2189ae","insertion_order":60,"keys":[""],"mode":"normal","name":"클래스: 바드","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"클래스: 드루이드","constant":false,"content":"## Druid (드루이드) - class, SRD 5.2.1 (levels 1-20)\nHit Die d8. Saving throws: Intelligence, Wisdom. Skills: choose 2 from Animal Handling, Arcana, Insight, Medicine, Nature, Perception, Religion, Survival. Weapons: Simple weapons. Armor: Light armor and Shields. Subclass at level 3: Circle of the Land.\n- Level 1: Spellcasting, Druidic, Primal Order\n- Level 2: Wild Shape, Wild Companion\n- Level 3: Druid Subclass\n- Level 4: Ability Score Improvement\n- Level 5: Wild Resurgence\n- Level 6: Circle of the Land: Natural Recovery\n- Level 7: Elemental Fury\n- Level 8: Ability Score Improvement\n- Level 9: --\n- Level 10: Circle of the Land: Nature's Ward\n- Level 11: --\n- Level 12: Ability Score Improvement\n- Level 13: --\n- Level 14: Circle of the Land: Nature's Sanctuary\n- Level 15: Improved Elemental Fury\n- Level 16: Ability Score Improvement\n- Level 17: --\n- Level 18: Beast Spells\n- Level 19: Epic Boon\n- Level 20: Archdruid","enabled":true,"extensions":{},"folder":"folder:5313df86-524c-48ac-a0a5-51dcdf2189ae","insertion_order":60,"keys":[""],"mode":"normal","name":"클래스: 드루이드","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"클래스: 몽크","constant":false,"content":"## Monk (몽크) - class, SRD 5.2.1 (levels 1-20)\nHit Die d8. Saving throws: Strength, Dexterity. Skills: choose 2 from Acrobatics, Athletics, History, Insight, Religion, Stealth. Weapons: Simple weapons and Martial weapons that have the Light property. Armor: None. Subclass at level 3: Warrior of the Open Hand.\n- Level 1: Martial Arts, Unarmored Defense\n- Level 2: Monk's Focus, Unarmored Movement, Uncanny Metabolism\n- Level 3: Deflect Attacks, Monk Subclass\n- Level 4: Ability Score Improvement, Slow Fall\n- Level 5: Extra Attack, Stunning Strike\n- Level 6: Empowered Strikes, Warrior of the Open Hand: Wholeness of Body\n- Level 7: Evasion\n- Level 8: Ability Score Improvement\n- Level 9: Acrobatic Movement\n- Level 10: Heightened Focus, Self-Restoration\n- Level 11: Warrior of the Open Hand: Fleet Step\n- Level 12: Ability Score Improvement\n- Level 13: Deflect Energy\n- Level 14: Disciplined Survivor\n- Level 15: Perfect Focus\n- Level 16: Ability Score Improvement\n- Level 17: Warrior of the Open Hand: Quivering Palm\n- Level 18: Superior Defense\n- Level 19: Epic Boon\n- Level 20: Body and Mind","enabled":true,"extensions":{},"folder":"folder:5313df86-524c-48ac-a0a5-51dcdf2189ae","insertion_order":60,"keys":[""],"mode":"normal","name":"클래스: 몽크","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"클래스: 팔라딘","constant":false,"content":"## Paladin (팔라딘) - class, SRD 5.2.1 (levels 1-20)\nHit Die d10. Saving throws: Wisdom, Charisma. Skills: choose 2 from Athletics, Insight, Intimidation, Medicine, Persuasion, Religion. Weapons: Simple and Martial weapons. Armor: Light, Medium, and Heavy armor and Shields. Subclass at level 3: Oath of Devotion.\n- Level 1: Lay On Hands, Spellcasting, Weapon Mastery\n- Level 2: Fighting Style, Paladin's Smite\n- Level 3: Channel Divinity, Paladin Subclass\n- Level 4: Ability Score Improvement\n- Level 5: Extra Attack, Faithful Steed\n- Level 6: Aura of Protection\n- Level 7: Oath of Devotion: Aura of Devotion\n- Level 8: Ability Score Improvement\n- Level 9: Abjure Foes\n- Level 10: Aura of Courage\n- Level 11: Radiant Strikes\n- Level 12: Ability Score Improvement\n- Level 13: --\n- Level 14: Restoring Touch\n- Level 15: Oath of Devotion: Smite of Protection\n- Level 16: Ability Score Improvement\n- Level 17: --\n- Level 18: Aura Expansion\n- Level 19: Epic Boon\n- Level 20: Oath of Devotion: Holy Nimbus","enabled":true,"extensions":{},"folder":"folder:5313df86-524c-48ac-a0a5-51dcdf2189ae","insertion_order":60,"keys":[""],"mode":"normal","name":"클래스: 팔라딘","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"클래스: 레인저","constant":false,"content":"## Ranger (레인저) - class, SRD 5.2.1 (levels 1-20)\nHit Die d10. Saving throws: Strength, Dexterity. Skills: choose 3 from Animal Handling, Athletics, Insight, Investigation, Nature, Perception, Stealth, Survival. Weapons: Simple and Martial weapons. Armor: Light and Medium armor and Shields. Subclass at level 3: Hunter.\n- Level 1: Spellcasting, Favored Enemy, Weapon Mastery\n- Level 2: Deft Explorer, Fighting Style\n- Level 3: Ranger Subclass\n- Level 4: Ability Score Improvement\n- Level 5: Extra Attack\n- Level 6: Roving\n- Level 7: Hunter: Defensive Tactics\n- Level 8: Ability Score Improvement\n- Level 9: Expertise\n- Level 10: Tireless\n- Level 11: Hunter: Superior Hunter's Prey\n- Level 12: Ability Score Improvement\n- Level 13: Relentless Hunter\n- Level 14: Nature's Veil\n- Level 15: Hunter: Superior Hunter's Defense\n- Level 16: Ability Score Improvement\n- Level 17: Precise Hunter\n- Level 18: Feral Senses\n- Level 19: Epic Boon\n- Level 20: Foe Slayer","enabled":true,"extensions":{},"folder":"folder:5313df86-524c-48ac-a0a5-51dcdf2189ae","insertion_order":60,"keys":[""],"mode":"normal","name":"클래스: 레인저","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"클래스: 소서러","constant":false,"content":"## Sorcerer (소서러) - class, SRD 5.2.1 (levels 1-20)\nHit Die d6. Saving throws: Constitution, Charisma. Skills: choose 2 from Arcana, Deception, Insight, Intimidation, Persuasion, Religion. Weapons: Simple weapons. Armor: None. Subclass at level 3: Draconic Sorcery.\n- Level 1: Spellcasting, Innate Sorcery\n- Level 2: Font of Magic, Metamagic\n- Level 3: Sorcerer Subclass\n- Level 4: Ability Score Improvement\n- Level 5: Sorcerous Restoration\n- Level 6: Draconic Sorcery: Elemental Affinity\n- Level 7: Sorcery Incarnate\n- Level 8: Ability Score Improvement\n- Level 9: --\n- Level 10: Metamagic\n- Level 11: --\n- Level 12: Ability Score Improvement\n- Level 13: --\n- Level 14: Draconic Sorcery: Dragon Wings\n- Level 15: --\n- Level 16: Ability Score Improvement\n- Level 17: Metamagic\n- Level 18: Draconic Sorcery: Dragon Companion\n- Level 19: Epic Boon\n- Level 20: Arcane Apotheosis","enabled":true,"extensions":{},"folder":"folder:5313df86-524c-48ac-a0a5-51dcdf2189ae","insertion_order":60,"keys":[""],"mode":"normal","name":"클래스: 소서러","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"클래스: 워락","constant":false,"content":"## Warlock (워락) - class, SRD 5.2.1 (levels 1-20)\nHit Die d8. Saving throws: Wisdom, Charisma. Skills: choose 2 from Arcana, Deception, History, Intimidation, Investigation, Nature, Religion. Weapons: Simple weapons. Armor: Light armor. Subclass at level 3: Fiend Patron.\n- Level 1: Eldritch Invocations, Pact Magic\n- Level 2: Magical Cunning\n- Level 3: Warlock Subclass\n- Level 4: Ability Score Improvement\n- Level 5: --\n- Level 6: Fiend Patron: Dark One's Own Luck\n- Level 7: --\n- Level 8: Ability Score Improvement\n- Level 9: Contact Patron\n- Level 10: Fiend Patron: Fiendish Resilience\n- Level 11: Mystic Arcanum (level 6 spell)\n- Level 12: Ability Score Improvement\n- Level 13: Mystic Arcanum (level 7 spell)\n- Level 14: Fiend Patron: Hurl Through Hell\n- Level 15: Mystic Arcanum (level 8 spell)\n- Level 16: Ability Score Improvement\n- Level 17: Mystic Arcanum (level 9 spell)\n- Level 18: --\n- Level 19: Epic Boon\n- Level 20: Eldritch Master","enabled":true,"extensions":{},"folder":"folder:5313df86-524c-48ac-a0a5-51dcdf2189ae","insertion_order":60,"keys":[""],"mode":"normal","name":"클래스: 워락","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"배경: 복사","constant":false,"content":"## Acolyte (복사) - background, SRD 5.2.1\nAbility scores: Intelligence, Wisdom, Charisma (+2/+1 or +1/+1/+1). Feat: Magic Initiate (Cleric). Skills: Insight, Religion. Tool: Calligrapher's Supplies.","enabled":true,"extensions":{},"folder":"folder:5313df86-524c-48ac-a0a5-51dcdf2189ae","insertion_order":60,"keys":[""],"mode":"normal","name":"배경: 복사","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"배경: 범죄자","constant":false,"content":"## Criminal (범죄자) - background, SRD 5.2.1\nAbility scores: Dexterity, Constitution, Intelligence (+2/+1 or +1/+1/+1). Feat: Alert. Skills: Sleight of Hand, Stealth. Tool: Thieves' Tools.","enabled":true,"extensions":{},"folder":"folder:5313df86-524c-48ac-a0a5-51dcdf2189ae","insertion_order":60,"keys":[""],"mode":"normal","name":"배경: 범죄자","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"배경: 학자","constant":false,"content":"## Sage (학자) - background, SRD 5.2.1\nAbility scores: Constitution, Intelligence, Wisdom (+2/+1 or +1/+1/+1). Feat: Magic Initiate (Wizard). Skills: Arcana, History. Tool: Calligrapher's Supplies.","enabled":true,"extensions":{},"folder":"folder:5313df86-524c-48ac-a0a5-51dcdf2189ae","insertion_order":60,"keys":[""],"mode":"normal","name":"배경: 학자","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"배경: 군인","constant":false,"content":"## Soldier (군인) - background, SRD 5.2.1\nAbility scores: Strength, Dexterity, Constitution (+2/+1 or +1/+1/+1). Feat: Savage Attacker. Skills: Athletics, Intimidation. Tool: one kind of Gaming Set.","enabled":true,"extensions":{},"folder":"folder:5313df86-524c-48ac-a0a5-51dcdf2189ae","insertion_order":60,"keys":[""],"mode":"normal","name":"배경: 군인","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"규칙 · 마법 물건","constant":false,"content":"","enabled":true,"extensions":{},"insertion_order":58,"keys":["folder:c5aedaa9-1450-4cf3-a103-74d652ba4c33"],"mode":"folder","name":"규칙 · 마법 물건","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"보물 · 마법 물건 지침","constant":false,"content":"## Treasure and magic items (SRD 5.2.1 values, bot guideline for levels)\nValue by rarity: Common 100 GP, Uncommon 400 GP, Rare 4,000 GP, Very Rare 40,000 GP, Legendary 200,000 GP, Artifact priceless. Consumables (potions, ammunition) are worth half. Common items can be bought in a town; Uncommon and Rare usually only in cities.\nLevels 1-4: mostly Common and Uncommon items; a Rare item is the reward of a major quest. Levels 5-10: mostly Uncommon and Rare; a Very Rare item only as the reward of a major quest. Never Legendary or Artifact below level 11 (Lua refuses them).\nAn SRD magic item is given with [ITEM|+Exact SRD Name|1] and Lua keeps its numbers: a magic weapon or armor with its base, \"+1 Longsword\", \"Flame Tongue (Longsword)\", \"Mithral Armor (Chain Mail)\"; a kind in parentheses, \"Ring of Resistance (Fire)\", \"Belt of Giant Strength (Hill)\", \"Ioun Stone (Protection)\", \"Spell Scroll (Fireball)\". An item that needs Attunement works once attuned: [ATTUNE|Item] (an hour, three items at most). A potion, an oil or a manual is used with [USE|Item]; a wand's, staff's or ring's spell is cast with [CAST|Spell|item], a scroll's with [CAST|Spell|scroll] (GAME STATE lists each one carried). An item the SRD does not have is a LOOT.","enabled":true,"extensions":{},"folder":"folder:c5aedaa9-1450-4cf3-a103-74d652ba4c33","insertion_order":58,"keys":[""],"mode":"normal","name":"보물 · 마법 물건 지침","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"마법 물건: Adamantine Armor","constant":false,"content":"## Adamantine Armor (아다만틴 갑옷) - magic item, SRD 5.2.1\nArmor (Any Medium or Heavy, Except Hide Armor), Uncommon.\nThis suit of armor is reinforced with adamantine, one of the hardest substances in existence. While you're wearing it, any Critical Hit against you becomes a normal hit.","enabled":true,"extensions":{},"folder":"folder:c5aedaa9-1450-4cf3-a103-74d652ba4c33","insertion_order":58,"keys":[""],"mode":"normal","name":"마법 물건: Adamantine Armor","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"마법 물건: Ammunition, +1, +2, or +3","constant":false,"content":"## Ammunition, +1, +2, or +3 (+1·+2·+3 탄약) - magic item, SRD 5.2.1\nWeapon (Any Ammunition), Uncommon (+1), Rare (+2), or Very Rare (+3).\nYou have a bonus to attack rolls and damage rolls made with this piece of magic ammunition. The bonus is determined by the rarity of the ammunition. Once it hits a target, the ammunition is no longer magical. This ammunition is typically found or sold in quantities of ten or twenty pieces. Ten pieces of this ammunition are equivalent in value to a potion of the same rarity.","enabled":true,"extensions":{},"folder":"folder:c5aedaa9-1450-4cf3-a103-74d652ba4c33","insertion_order":58,"keys":[""],"mode":"normal","name":"마법 물건: Ammunition, +1, +2, or +3","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"마법 물건: Ammunition of Slaying","constant":false,"content":"## Ammunition of Slaying (학살의 탄약) - magic item, SRD 5.2.1\nWeapon (Any Ammunition), Very Rare.\nThis magic ammunition is meant to slay creatures of a particular type, which the GM chooses or determines randomly by rolling on the table below. If a creature of that type takes damage from the ammunition, the creature makes a DC 17 Constitution saving throw, taking an extra 6d10 Force damage on a failed save or half as much extra damage on a successful one. After dealing its extra damage to a creature, the ammunition becomes nonmagical. 1d100 Creature Type 1d100 Creature Type 01-10 Aberrations 51-60 Fey 11-15 Beasts 61-70 Fiends 16-20 Celestials 71-75 Giants 21-25 Constructs 76-80 Monstrosities 26-35 Dragons 81-85 Oozes 36-45 Elementals 86-90 Plants 46-50 Humanoids 91-00 Undead","enabled":true,"extensions":{},"folder":"folder:c5aedaa9-1450-4cf3-a103-74d652ba4c33","insertion_order":58,"keys":[""],"mode":"normal","name":"마법 물건: Ammunition of Slaying","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"마법 물건: Amulet of Health","constant":false,"content":"## Amulet of Health (건강의 부적) - magic item, SRD 5.2.1\nWondrous Item, Rare (Requires Attunement).\nYour Constitution is 19 while you wear this amulet. It has no effect on you if your Constitution is 19 or higher without it.","enabled":true,"extensions":{},"folder":"folder:c5aedaa9-1450-4cf3-a103-74d652ba4c33","insertion_order":58,"keys":[""],"mode":"normal","name":"마법 물건: Amulet of Health","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"마법 물건: Amulet of Proof against Detection and Location","constant":false,"content":"## Amulet of Proof against Detection and Location (탐지 방지 부적) - magic item, SRD 5.2.1\nWondrous Item, Uncommon (Requires Attunement).\nWhile wearing this amulet, you can't be targeted by Divination spells or perceived through magical scrying sensors unless you allow it.","enabled":true,"extensions":{},"folder":"folder:c5aedaa9-1450-4cf3-a103-74d652ba4c33","insertion_order":58,"keys":[""],"mode":"normal","name":"마법 물건: Amulet of Proof against Detection and Location","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"마법 물건: Amulet of the Planes","constant":false,"content":"## Amulet of the Planes (차원의 부적) - magic item, SRD 5.2.1\nWondrous Item, Very Rare (Requires Attunement).\nWhile wearing this amulet, you can take a Magic action to name a location that you are familiar with on another plane of existence. Then make a DC 15 Intelligence (Arcana) check. On a successful check, you cast Plane Shift. On a failed check, you and each creature and object within 15 feet of you travel to a random destination determined by rolling 1d100 and consulting the following table. 1d100 Destination 01-60 Random location on the plane you named 61-70 Random location on an Inner Plane determined by rolling 1d6: on a 1, the Plane of Air; on a 2, the Plane of Earth; on a 3, the Plane of Fire; on a 4, the Plane of Water; on a 5, the Feywild; on a 6, the Shadowfell 71-80 Random location on an Outer Plane determined by rolling 1d8: on a 1, Arborea; on a 2, Arcadia; on a 3, the Beastlands; on a 4, Bytopia; on a 5, Elysium; on a 6, Mechanus; on a 7, Mount Celestia; on an 8, Ysgard 81-90 Random location on an Outer Plane determined by rolling 1d8: on a 1, the Abyss; on a 2, Acheron; on a 3, Carceri; on a 4, Gehenna; on a 5, Hades; on a 6, Limbo; on a 7, the Nine Hells; on an 8, Pandemonium 91-00 Random location on the Astral Plane","enabled":true,"extensions":{},"folder":"folder:c5aedaa9-1450-4cf3-a103-74d652ba4c33","insertion_order":58,"keys":[""],"mode":"normal","name":"마법 물건: Amulet of the Planes","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"마법 물건: Animated Shield","constant":false,"content":"## Animated Shield (움직이는 방패) - magic item, SRD 5.2.1\nArmor (Shield), Very Rare (Requires Attunement).\nWhile holding this Shield, you can take a Bonus Action to cause it to animate. The Shield leaps into the air and hovers in your space to protect you as if you were wielding it, leaving your hands free. The Shield remains animate for 1 minute, until you take a Bonus Action to end this effect, or until you die or have the Incapacitated condition, at which point the Shield falls to the ground or into your hand if you have one free. 210","enabled":true,"extensions":{},"folder":"folder:c5aedaa9-1450-4cf3-a103-74d652ba4c33","insertion_order":58,"keys":[""],"mode":"normal","name":"마법 물건: Animated Shield","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"마법 물건: Apparatus of the Crab","constant":false,"content":"## Apparatus of the Crab (게 모양 장치) - magic item, SRD 5.2.1\nWondrous Item, Legendary.\nThis item first appears to be a sealed iron barrel weighing 500 pounds. The barrel has a hidden catch, which can be found with a successful DC 20 Intelligence (Investigation) check. Releasing the catch unlocks a hatch at one end of the barrel, allowing two Medium or smaller creatures to crawl inside. Ten levers are set in a row at the far end, each in a neutral position, able to move up or down. When certain levers are used, the apparatus transforms to resemble a giant lobster. The Apparatus of the Crab is a Large object with the following statistics: AC 20; HP 200; Speed 30 ft., Swim 30 ft. (or 0 ft. for both if the legs aren't extended); Immunity to Poison and Psychic damage. To be used as a vehicle, the apparatus requires one pilot. While the apparatus's hatch is closed, the compartment is airtight and watertight. The compartment holds enough air for 10 hours of breathing, divided by the number of breathing creatures inside. The apparatus floats on water. It can also go underwater to a depth of 900 feet. Below that, the vehicle takes 2d6 Bludgeoning damage each minute from pressure. A creature in the compartment can take a Utilize action to move as many as two of the apparatus's levers up or down. After each use, a lever goes back to its neutral position. Each lever, from left to right, functions as shown in the Apparatus of the Crab Levers table.","enabled":true,"extensions":{},"folder":"folder:c5aedaa9-1450-4cf3-a103-74d652ba4c33","insertion_order":58,"keys":[""],"mode":"normal","name":"마법 물건: Apparatus of the Crab","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"마법 물건: Armor, +1, +2, or +3","constant":false,"content":"## Armor, +1, +2, or +3 (+1·+2·+3 갑옷) - magic item, SRD 5.2.1\nArmor (Any Light, Medium, or Heavy), Rare (+1), Very Rare (+2), or Legendary (+3).\nYou have a bonus to Armor Class while wearing this armor. The bonus is determined by its rarity.","enabled":true,"extensions":{},"folder":"folder:c5aedaa9-1450-4cf3-a103-74d652ba4c33","insertion_order":58,"keys":[""],"mode":"normal","name":"마법 물건: Armor, +1, +2, or +3","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"마법 물건: Armor of Invulnerability","constant":false,"content":"## Armor of Invulnerability (무적의 갑옷) - magic item, SRD 5.2.1\nArmor (Plate Armor), Legendary (Requires Attunement).\nYou have Resistance to Bludgeoning, Piercing, and Slashing damage while you wear this armor. Metal Shell. You can take a Magic action to give yourself Immunity to Bludgeoning, Piercing, and Slashing damage for 10 minutes or until you are no longer wearing the armor. Once this property is used, it can't be used again until the next dawn.","enabled":true,"extensions":{},"folder":"folder:c5aedaa9-1450-4cf3-a103-74d652ba4c33","insertion_order":58,"keys":[""],"mode":"normal","name":"마법 물건: Armor of Invulnerability","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"마법 물건: Armor of Resistance","constant":false,"content":"## Armor of Resistance (저항의 갑옷) - magic item, SRD 5.2.1\nArmor (Any Light, Medium, or Heavy), Rare (Requires Attunement).\nYou have Resistance to one type of damage while you wear this armor. The GM chooses the type or determines it randomly by rolling on the following table. 1d10 Damage Type 1d10 Damage Type 1 Acid 6 Necrotic 2 Cold 7 Poison 3 Fire 8 Psychic 4 Force 9 Radiant 5 Lightning 10 Thunder Apparatus of the Crab Levers Lever Up Down 1 Legs extend, allowing the apparatus to walk and swim. Legs retract, reducing the apparatus's Speed and Swim Speed to 0 and making it unable to benefit from bonuses to speed. 2 Forward window shutter opens. Forward window shutter closes. 3 Side window shutters open (two per side). Side window shutters close (two per side). 4 Two claws extend from the front side of the apparatus. The claws retract. 5 Each extended claw makes the following melee attack: +8 to hit, reach 5 ft. Hit: 7 (2d6) Bludgeoning damage. Each extended claw makes the following melee attack: +8 to hit, reach 5 ft. Hit: The target has the Grappled condition (escape DC 15). 6 The apparatus walks or swims forward provided its legs are extended. The apparatus walks or swims backward provided its legs are extended. 7 The apparatus turns 90 degrees counterclockwise provided its legs are extended. The apparatus turns 90 degrees clockwise provided its legs are extended. 8 Eyelike fixtures emit Bright Light in a 30-foot radius and Dim Light for an additional 30 feet. The light turns off. 9 The apparatus sinks up to 20 feet if it's in liquid. The apparatus rises up to 20 feet if it's in liquid. 10 The rear hatch unseals and opens. The rear hatch closes and seals. 211","enabled":true,"extensions":{},"folder":"folder:c5aedaa9-1450-4cf3-a103-74d652ba4c33","insertion_order":58,"keys":[""],"mode":"normal","name":"마법 물건: Armor of Resistance","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"마법 물건: Armor of Vulnerability","constant":false,"content":"## Armor of Vulnerability (취약의 갑옷) - magic item, SRD 5.2.1\nArmor (Any Light, Medium, or Heavy), Rare (Requires Attunement).\nWhile wearing this armor, you have Resistance to one of the following damage types: Bludgeoning, Piercing, or Slashing. The GM chooses the type or determines it randomly. Curse. This armor is cursed, a fact that is revealed only when the Identify spell is cast on the armor or you attune to it. Attuning to the armor curses you until you are targeted by a Remove Curse spell or similar magic; removing the armor fails to end the curse. While cursed, you have Vulnerability to two of the three damage types associated with the armor (not the one to which it grants Resistance).","enabled":true,"extensions":{},"folder":"folder:c5aedaa9-1450-4cf3-a103-74d652ba4c33","insertion_order":58,"keys":[""],"mode":"normal","name":"마법 물건: Armor of Vulnerability","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"마법 물건: Arrow-Catching Shield","constant":false,"content":"## Arrow-Catching Shield (화살 잡는 방패) - magic item, SRD 5.2.1\nArmor (Shield), Rare (Requires Attunement).\nYou gain a +2 bonus to Armor Class against ranged attack rolls while you wield this Shield. This bonus is in addition to the Shield's normal bonus to AC. Whenever an attacker makes a ranged attack roll against a target within 5 feet of you, you can take a Reaction to become the target of the attack instead.","enabled":true,"extensions":{},"folder":"folder:c5aedaa9-1450-4cf3-a103-74d652ba4c33","insertion_order":58,"keys":[""],"mode":"normal","name":"마법 물건: Arrow-Catching Shield","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"마법 물건: Bag of Beans","constant":false,"content":"## Bag of Beans (콩 자루) - magic item, SRD 5.2.1\nWondrous Item, Rare.\nThis heavy cloth bag contains 3d4 dry beans when found. The bag weighs half a pound regardless of how many beans it contains and becomes a nonmagical item when it no longer contains any beans. If you dump one or more beans out of the bag, they explode in a 10-foot-radius Sphere centered on them. All the dumped beans are destroyed in the explosion, and each creature in the Sphere, including you, makes a DC 15 Dexterity saving throw, taking 5d4 Force damage on a failed save or half as much damage on a successful one. If you remove a bean from the bag, plant it in dirt or sand, and then water it, the bean disappears as it produces an effect 1 minute later from the ground where it was planted. The GM can choose an effect from the following table or determine it randomly. 1d100 Effect 01 5d4 toadstools sprout. If a creature eats a toadstool, roll any die. On an odd roll, the eater must succeed on a DC 15 Constitution saving throw or take 5d6 Poison damage and have the Poisoned condition for 1 hour. On an even roll, the eater gains 5d6 Temporary Hit Points for 1 hour. 02-10 A geyser erupts and spouts water, beer, mayonnaise, tea, vinegar, wine, or oil (GM's choice) 30 feet into the air for 1d4 minutes. 1d100 Effect 11-20 A Treant sprouts. Roll any die. On an odd roll, the treant is Chaotic Evil. On an even roll, the treant is Chaotic Good. 21-30 An animate but immobile stone statue in your likeness rises and makes verbal threats against you. If you leave it and others come near, it describes you as the most heinous of villains and directs the newcomers to find and attack you. If you are on the same plane of existence as the statue, it knows where you are. The statue becomes inanimate after 24 hours. 31-40 A campfire with green flames springs forth and burns for 24 hours or until it is extinguished. 41-50 Three Shrieker Fungi sprout. 51-60 1d4 + 4 bright-pink toads crawl forth. Whenever a toad is touched, it transforms into a Large or smaller monster of the GM's choice that acts in accordance with its alignment and nature. The monster remains for 1 minute, then disappears in a puff of bright-pink smoke. 61-70 A hungry Bulette burrows up and attacks. 71-80 A fruit tree grows. It has 1d10 + 20 fruit, 1d8 of which act as randomly determined potions. The tree vanishes after 1 hour. Picked fruit remains, retaining any magic for 30 days. 81-90 A nest of 1d4 + 3 rainbow-colored eggs springs up. Any creature that eats an egg makes a DC 20 Constitution saving throw. On a successful save, a creature permanently increases its lowest ability score by 1, randomly choosing among equally low scores. On a failed save, the creature takes 10d6 Force damage from an internal explosion. 91-95 A pyramid with a 60-foot-square base bursts upward. Inside is a burial chamber containing a Mummy, a Mummy Lord, or some other Undead of the GM's choice. Its sarcophagus contains treasure of the GM's choice. 96-00 A giant beanstalk sprouts, growing to a height of the GM's choice. The top leads where the GM chooses, such as to a great view, a cloud giant's castle, or another plane of existence. 212","enabled":true,"extensions":{},"folder":"folder:c5aedaa9-1450-4cf3-a103-74d652ba4c33","insertion_order":58,"keys":[""],"mode":"normal","name":"마법 물건: Bag of Beans","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"마법 물건: Bag of Devouring","constant":false,"content":"## Bag of Devouring (삼키는 자루) - magic item, SRD 5.2.1\nWondrous Item, Very Rare.\nThis bag resembles a Bag of Holding but is a feeding orifice for a gigantic extradimensional creature. Turning the bag inside out closes the orifice. The extradimensional creature attached to the bag can sense whatever is placed inside the bag. Animal or vegetable matter placed wholly in the bag is devoured and lost forever. When part of a living creature is placed in the bag, as happens when someone reaches inside it, there is a 50 percent chance that the creature is pulled inside the bag. A creature inside the bag can take an action to try to escape, doing so with a successful DC 15 Strength (Athletics) check. Another creature can take an action to reach into the bag to pull a creature out, doing so with a successful DC 20 Strength (Athletics) check, provided the puller isn't pulled inside the bag first. Any creature that starts its turn inside the bag is devoured, its body destroyed. Inanimate objects can be stored in the bag, which can hold a cubic foot of such material. However, once each day, the bag swallows any objects inside it and spits them out into another plane of existence. The GM determines the time and plane. If the bag is pierced or torn, it is destroyed, and anything contained within it is transported to a random location on the Astral Plane.","enabled":true,"extensions":{},"folder":"folder:c5aedaa9-1450-4cf3-a103-74d652ba4c33","insertion_order":58,"keys":[""],"mode":"normal","name":"마법 물건: Bag of Devouring","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"마법 물건: Bag of Holding","constant":false,"content":"## Bag of Holding (보관의 자루) - magic item, SRD 5.2.1\nWondrous Item, Uncommon.\nThis bag has an interior space considerably larger than its outside dimensions—roughly 2 feet square and 4 feet deep on the inside. The bag can hold up to 500 pounds, not exceeding a volume of 64 cubic feet. The bag weighs 5 pounds, regardless of its contents. Retrieving an item from the bag requires a Utilize action. If the bag is overloaded, pierced, or torn, it is destroyed, and its contents are scattered in the Astral Plane. If the bag is turned inside out, its contents spill forth unharmed, but the bag must be put right before it can be used again. The bag holds enough air for 10 minutes of breathing, divided by the number of breathing creatures inside. Placing a Bag of Holding inside an extradimensional space created by a Handy Haversack, Portable Hole, or similar item instantly destroys both items and opens a gate to the Astral Plane. The gate originates where the one item was placed inside the other. Any creature within a 10-foot-radius Sphere centered on the gate is sucked through it to a random location on the Astral Plane. The gate then closes. The gate is one-way and can't be reopened.","enabled":true,"extensions":{},"folder":"folder:c5aedaa9-1450-4cf3-a103-74d652ba4c33","insertion_order":58,"keys":[""],"mode":"normal","name":"마법 물건: Bag of Holding","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"마법 물건: Bag of Tricks","constant":false,"content":"## Bag of Tricks (묘수 자루) - magic item, SRD 5.2.1\nWondrous Item, Uncommon.\nThis bag made from gray, rust, or tan cloth appears empty. Reaching inside the bag, however, reveals the presence of a small, fuzzy object. You can take a Magic action to pull the fuzzy object from the bag and throw it up to 20 feet. When the object lands, it transforms into a creature you determine by rolling on the table that corresponds to the bag's color. See “Monsters” for the creature's stat block. The creature vanishes at the next dawn or when it is reduced to 0 Hit Points. The creature is Friendly to you and your allies, and it acts immediately after you on your Initiative count. You can take a Bonus Action to command how the creature moves and what action it takes on its next turn, such as attacking an enemy. In the absence of such orders, the creature acts in a fashion appropriate to its nature. Once three fuzzy objects have been pulled from the bag, the bag can't be used again until the next dawn. Gray Bag of Tricks 1d8 Creature 1d8 Creature 1 Weasel 5 Panther 2 Giant Rat 6 Giant Badger 3 Badger 7 Dire Wolf 4 Boar 8 Giant Elk Rust Bag of Tricks 1d8 Creature 1d8 Creature 1 Rat 5 Giant Goat 2 Owl 6 Giant Boar 3 Mastiff 7 Lion 4 Goat 8 Brown Bear Tan Bag of Tricks 1d8 Creature 1d8 Creature 1 Jackal 5 Black Bear 2 Ape 6 Giant Weasel 3 Baboon 7 Giant Hyena 4 Axe Beak 8 Tiger","enabled":true,"extensions":{},"folder":"folder:c5aedaa9-1450-4cf3-a103-74d652ba4c33","insertion_order":58,"keys":[""],"mode":"normal","name":"마법 물건: Bag of Tricks","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"마법 물건: Bead of Force","constant":false,"content":"## Bead of Force (역장 구슬) - magic item, SRD 5.2.1\nWondrous Item, Rare.\nThis small black sphere measures 3/4 of an inch in diameter and weighs an ounce. Typically, 1d4 + 4 Beads of Force are found together. You can take a Magic action to throw the bead up to 60 feet. The bead explodes in a 10-foot-radius Sphere on impact and is destroyed. Each creature 213 in the Sphere must succeed on a DC 15 Dexterity saving throw or take 5d4 Force damage. A sphere of transparent force then encloses the area for 1 minute. Any creature that failed the save and is completely within the area is trapped inside this sphere. Creatures that succeeded on the save or are partially within the area are pushed away from the center of the sphere until they are no longer inside it. Only breathable air can pass through the sphere's wall. No attack or other effect can pass through. An enclosed creature can take a Utilize action to push against the sphere's wall, moving the sphere up to half the creature's Speed. The sphere can be picked up, and its magic causes it to weigh only 1 pound, regardless of the weight of creatures inside.","enabled":true,"extensions":{},"folder":"folder:c5aedaa9-1450-4cf3-a103-74d652ba4c33","insertion_order":58,"keys":[""],"mode":"normal","name":"마법 물건: Bead of Force","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"마법 물건: Bead of Nourishment","constant":false,"content":"## Bead of Nourishment (영양 구슬) - magic item, SRD 5.2.1\nWondrous Item, Common.\nThis flavorless, gelatinous bead dissolves on your tongue and provides as much nourishment as 1 day of Rations.","enabled":true,"extensions":{},"folder":"folder:c5aedaa9-1450-4cf3-a103-74d652ba4c33","insertion_order":58,"keys":[""],"mode":"normal","name":"마법 물건: Bead of Nourishment","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"마법 물건: Belt of Dwarvenkind","constant":false,"content":"## Belt of Dwarvenkind (드워프의 허리띠) - magic item, SRD 5.2.1\nWondrous Item, Rare (Requires Attunement).\nWhile wearing this belt, you gain the following benefits: Dwarvish. You know Dwarvish. Friend of Dwarvenkind. You have Advantage on Charisma (Persuasion) checks made to interact with dwarves and duergar. Toughness. Your Constitution increases by 2, to a maximum of 20. In addition, while attuned to the belt, you have a 50 percent chance each day at dawn of growing a full beard if you can grow one, or a thicker beard if you already have one. If you aren't a dwarf or duergar, you gain the following additional benefits while wearing the belt: Darkvision. You have Darkvision with a range of 60 feet. Resilience. You have Resistance to Poison damage. You also have Advantage on saving throws you make to avoid or end the Poisoned condition.","enabled":true,"extensions":{},"folder":"folder:c5aedaa9-1450-4cf3-a103-74d652ba4c33","insertion_order":58,"keys":[""],"mode":"normal","name":"마법 물건: Belt of Dwarvenkind","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"마법 물건: Belt of Giant Strength","constant":false,"content":"## Belt of Giant Strength (거인의 힘 허리띠) - magic item, SRD 5.2.1\nWondrous Item, Rarity Varies (Requires Attunement).\nWhile wearing this belt, your Strength changes to a score granted by the belt. The type of giant determines the score (see the table below). The item has no effect on you if your Strength without the belt is equal to or greater than the belt's score. Belt Str. Rarity Belt of Giant Strength (hill) 21 Rare Belt of Giant Strength (frost or stone) 23 Very Rare Belt of Giant Strength (fire) 25 Very Rare Belt of Giant Strength (cloud) 27 Legendary Belt of Giant Strength (storm) 29 Legendary","enabled":true,"extensions":{},"folder":"folder:c5aedaa9-1450-4cf3-a103-74d652ba4c33","insertion_order":58,"keys":[""],"mode":"normal","name":"마법 물건: Belt of Giant Strength","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"마법 물건: Berserker Axe","constant":false,"content":"## Berserker Axe (광전사의 도끼) - magic item, SRD 5.2.1\nWeapon (Battleaxe, Greataxe, or Halberd), Rare (Requires Attunement).\nYou gain a +1 bonus to attack rolls and damage rolls made with this magic weapon. In addition, while you are attuned to this weapon, your Hit Point maximum increases by 1 for each level you have attained. Curse. This weapon is cursed, and becoming attuned to it extends the curse to you. As long as you remain cursed, you are unwilling to part with the weapon, keeping it within reach at all times. You also have Disadvantage on attack rolls with weapons other than this one. Whenever another creature damages you while the weapon is in your possession, you must succeed on a DC 15 Wisdom saving throw or go berserk. This berserk state ends when you start your turn and there are no creatures within 60 feet of you that you can see or hear. While berserk, you regard the creature nearest to you that you can see or hear as your enemy. If there are multiple possible creatures, choose one at random. On each of your turns, you must move as close to the creature as possible and take the Attack action, targeting the creature. If you're unable to get close enough to the creature to attack it with the weapon, your turn ends after you've used up all your available movement. If the creature dies or can no longer be seen or heard by you, the next nearest creature that you can see or hear becomes your new target.","enabled":true,"extensions":{},"folder":"folder:c5aedaa9-1450-4cf3-a103-74d652ba4c33","insertion_order":58,"keys":[""],"mode":"normal","name":"마법 물건: Berserker Axe","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"마법 물건: Boots of Elvenkind","constant":false,"content":"## Boots of Elvenkind (엘프의 장화) - magic item, SRD 5.2.1\nWondrous Item, Uncommon.\nWhile you wear these boots, your steps make no sound, regardless of the surface you are moving across. You also have Advantage on Dexterity (Stealth) checks.","enabled":true,"extensions":{},"folder":"folder:c5aedaa9-1450-4cf3-a103-74d652ba4c33","insertion_order":58,"keys":[""],"mode":"normal","name":"마법 물건: Boots of Elvenkind","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"마법 물건: Boots of Levitation","constant":false,"content":"## Boots of Levitation (부양의 장화) - magic item, SRD 5.2.1\nWondrous Item, Rare (Requires Attunement).\nWhile you wear these boots, you can cast Levitate on yourself. 214","enabled":true,"extensions":{},"folder":"folder:c5aedaa9-1450-4cf3-a103-74d652ba4c33","insertion_order":58,"keys":[""],"mode":"normal","name":"마법 물건: Boots of Levitation","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"마법 물건: Boots of Speed","constant":false,"content":"## Boots of Speed (신속의 장화) - magic item, SRD 5.2.1\nWondrous Item, Rare (Requires Attunement).\nWhile you wear these boots, you can take a Bonus Action to click the boots' heels together. If you do, the boots double your Speed, and any creature that makes an Opportunity Attack against you has Disadvantage on the attack roll. If you click your heels together again, you end the effect. When you've used the boots' property for a total of 10 minutes, the magic ceases to function for you until you finish a Long Rest.","enabled":true,"extensions":{},"folder":"folder:c5aedaa9-1450-4cf3-a103-74d652ba4c33","insertion_order":58,"keys":[""],"mode":"normal","name":"마법 물건: Boots of Speed","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"마법 물건: Boots of Striding and Springing","constant":false,"content":"## Boots of Striding and Springing (성큼 도약 장화) - magic item, SRD 5.2.1\nWondrous Item, Uncommon (Requires Attunement).\nWhile you wear these boots, your Speed becomes 30 feet unless your Speed is higher, and your Speed isn't reduced by you carrying weight in excess of your carrying capacity or wearing Heavy Armor. Once on each of your turns, you can jump up to 30 feet by spending only 10 feet of movement.","enabled":true,"extensions":{},"folder":"folder:c5aedaa9-1450-4cf3-a103-74d652ba4c33","insertion_order":58,"keys":[""],"mode":"normal","name":"마법 물건: Boots of Striding and Springing","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"마법 물건: Boots of the Winterlands","constant":false,"content":"## Boots of the Winterlands (설원의 장화) - magic item, SRD 5.2.1\nWondrous Item, Uncommon (Requires Attunement).\nThese furred boots are snug and feel warm. While wearing them, you gain the following benefits. Cold Resistance. You have Resistance to Cold damage and can tolerate temperatures of 0 degrees Fahrenheit or lower without any additional protection. Winter Strider. You ignore Difficult Terrain created by ice or snow.","enabled":true,"extensions":{},"folder":"folder:c5aedaa9-1450-4cf3-a103-74d652ba4c33","insertion_order":58,"keys":[""],"mode":"normal","name":"마법 물건: Boots of the Winterlands","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"마법 물건: Bowl of Commanding Water Elementals","constant":false,"content":"## Bowl of Commanding Water Elementals (물 원소 지배의 그릇) - magic item, SRD 5.2.1\nWondrous Item, Rare.\nWhile this bowl is filled with water and you are within 5 feet of it, you can take a Magic action to summon a Water Elemental. The elemental appears in an unoccupied space as close to the bowl as possible, understands your languages, obeys your commands, and takes its turn immediately after you on your Initiative count. The elemental disappears after 1 hour, when it dies, or when you dismiss it as a Bonus Action. The bowl can't be used this way again until the next dawn. The bowl is about 1 foot in diameter and half as deep. It holds about 3 gallons.","enabled":true,"extensions":{},"folder":"folder:c5aedaa9-1450-4cf3-a103-74d652ba4c33","insertion_order":58,"keys":[""],"mode":"normal","name":"마법 물건: Bowl of Commanding Water Elementals","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"마법 물건: Bracers of Archery","constant":false,"content":"## Bracers of Archery (궁술의 팔목 보호대) - magic item, SRD 5.2.1\nWondrous Item, Uncommon (Requires Attunement).\nWhile wearing these bracers, you have proficiency with the Longbow and Shortbow, and you gain a +2 bonus to damage rolls made with such weapons.","enabled":true,"extensions":{},"folder":"folder:c5aedaa9-1450-4cf3-a103-74d652ba4c33","insertion_order":58,"keys":[""],"mode":"normal","name":"마법 물건: Bracers of Archery","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"마법 물건: Bracers of Defense","constant":false,"content":"## Bracers of Defense (방어의 팔목 보호대) - magic item, SRD 5.2.1\nWondrous Item, Rare (Requires Attunement).\nWhile wearing these bracers, you gain a +2 bonus to Armor Class if you are wearing no armor and using no Shield.","enabled":true,"extensions":{},"folder":"folder:c5aedaa9-1450-4cf3-a103-74d652ba4c33","insertion_order":58,"keys":[""],"mode":"normal","name":"마법 물건: Bracers of Defense","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"마법 물건: Brazier of Commanding Fire Elementals","constant":false,"content":"## Brazier of Commanding Fire Elementals (불 원소 지배의 화로) - magic item, SRD 5.2.1\nWondrous Item, Rare.\nWhile you are within 5 feet of this brazier, you can take a Magic action to summon a Fire Elemental. The elemental appears in an unoccupied space as close to the brazier as possible, understands your languages, obeys your commands, and takes its turn immediately after you on your Initiative count. The elemental disappears after 1 hour, when it dies, or when you dismiss it as a Bonus Action. The brazier can't be used this way again until the next dawn.","enabled":true,"extensions":{},"folder":"folder:c5aedaa9-1450-4cf3-a103-74d652ba4c33","insertion_order":58,"keys":[""],"mode":"normal","name":"마법 물건: Brazier of Commanding Fire Elementals","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"마법 물건: Brooch of Shielding","constant":false,"content":"## Brooch of Shielding (보호막 브로치) - magic item, SRD 5.2.1\nWondrous Item, Uncommon (Requires Attunement).\nWhile wearing this brooch, you have Resistance to Force damage, and you have Immunity to damage from the Magic Missile spell.","enabled":true,"extensions":{},"folder":"folder:c5aedaa9-1450-4cf3-a103-74d652ba4c33","insertion_order":58,"keys":[""],"mode":"normal","name":"마법 물건: Brooch of Shielding","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"마법 물건: Broom of Flying","constant":false,"content":"## Broom of Flying (비행 빗자루) - magic item, SRD 5.2.1\nWondrous Item, Uncommon (Requires Attunement).\nThis wooden broom functions like a mundane broom until you stand astride it and take a Magic action to make it hover beneath you, at which time it can be ridden in the air. It has a Fly Speed of 50 feet. It can carry up to 400 pounds, but its Fly Speed becomes 30 feet while carrying over 200 pounds. The broom stops hovering when you land or when you're no longer riding it. As a Magic action, you can send the broom to travel alone to a destination within 1 mile of you if you name the location and are familiar with it. The broom comes back to you when you take a Magic action and use a command word if the broom is still within 1 mile of you.","enabled":true,"extensions":{},"folder":"folder:c5aedaa9-1450-4cf3-a103-74d652ba4c33","insertion_order":58,"keys":[""],"mode":"normal","name":"마법 물건: Broom of Flying","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"마법 물건: Candle of Invocation","constant":false,"content":"## Candle of Invocation (기원의 양초) - magic item, SRD 5.2.1\nWondrous Item, Very Rare (Requires Attunement).\nThis candle's magic is activated when the candle is lit, which requires a Magic action. After burning for 4 hours, the candle is destroyed. You can snuff it out early for use at a later time. Deduct the time it burned in increments of 1 minute from its total burn time. While lit, the candle sheds Dim Light in a 30-foot radius. While you are within that light, you have Advantage on D20 Tests. In addition, a Cleric or Druid in the light can cast level 1 spells they have prepared without expending spell slots. Alternatively, when you light the candle for the first time, you can cast Gate with it. Doing so destroys the candle. The portal created by the spell 215 links to a particular Outer Plane chosen by the GM or determined by rolling on the following table. 1d100 Outer Plane 1d100 Outer Plane 01-05 Abyss 55-59 Gehenna 06-10 Acheron 60-64 Hades 11-17 Arborea 65-69 Limbo 18-25 Arcadia 70-77 Mechanus 26-33 Beastlands 78-85 Mount Celestia 34-41 Bytopia 86-90 Nine Hells 42-46 Carceri 91-95 Pandemonium 47-54 Elysium 96-00 Ysgard","enabled":true,"extensions":{},"folder":"folder:c5aedaa9-1450-4cf3-a103-74d652ba4c33","insertion_order":58,"keys":[""],"mode":"normal","name":"마법 물건: Candle of Invocation","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"마법 물건: Cape of the Mountebank","constant":false,"content":"## Cape of the Mountebank (협잡꾼의 망토) - magic item, SRD 5.2.1\nWondrous Item, Rare.\nThis cape smells faintly of brimstone. While wearing it, you can use it to cast Dimension Door as a Magic action. This property can't be used again until the next dawn. When you teleport with that spell, you leave behind a cloud of smoke. The space you left is Lightly Obscured by that smoke until the end of your next turn.","enabled":true,"extensions":{},"folder":"folder:c5aedaa9-1450-4cf3-a103-74d652ba4c33","insertion_order":58,"keys":[""],"mode":"normal","name":"마법 물건: Cape of the Mountebank","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"마법 물건: Carpet of Flying","constant":false,"content":"## Carpet of Flying (비행 양탄자) - magic item, SRD 5.2.1\nWondrous Item, Very Rare.\nYou can make this carpet hover and fly by taking a Magic action and using the carpet's command word. It moves according to your directions if you are within 30 feet of it. Four sizes of Carpet of Flying exist. The GM chooses the size of a given carpet or determines it randomly by rolling on the following table. A carpet can carry up to twice the weight shown on the table, but its Fly Speed is halved if it carries more than its normal capacity. 1d100 Size Capacity Fly Speed 01-20 3 ft. × 5 ft. 200 lb. 80 feet 21-55 4 ft. × 6 ft. 400 lb. 60 feet 56-80 5 ft. × 7 ft. 600 lb. 40 feet 81-00 6 ft. × 9 ft. 800 lb. 30 feet","enabled":true,"extensions":{},"folder":"folder:c5aedaa9-1450-4cf3-a103-74d652ba4c33","insertion_order":58,"keys":[""],"mode":"normal","name":"마법 물건: Carpet of Flying","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"마법 물건: Censer of Controlling Air Elementals","constant":false,"content":"## Censer of Controlling Air Elementals (공기 원소 조종 향로) - magic item, SRD 5.2.1\nWondrous Item, Rare.\nWhile gently swinging this censer, you can take a Magic action to summon an Air Elemental. The elemental appears in an unoccupied space as close to the censer as possible, understands your languages, obeys your commands, and takes its turn immediately after you on your Initiative count. The elemental disappears after 1 hour, when it dies, or when you dismiss it as a Bonus Action. The censer can't be used this way again until the next dawn.","enabled":true,"extensions":{},"folder":"folder:c5aedaa9-1450-4cf3-a103-74d652ba4c33","insertion_order":58,"keys":[""],"mode":"normal","name":"마법 물건: Censer of Controlling Air Elementals","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"마법 물건: Chime of Opening","constant":false,"content":"## Chime of Opening (열림의 종) - magic item, SRD 5.2.1\nWondrous Item, Rare.\nThis hollow metal tube measures about 1 foot long and weighs 1 pound. As a Magic action, you can strike the chime to cast Knock. The spell's customary knocking sound is replaced by the clear, ringing tone of the chime, which is audible out to 300 feet. The chime can be used 10 times. After the tenth time, it cracks and becomes useless.","enabled":true,"extensions":{},"folder":"folder:c5aedaa9-1450-4cf3-a103-74d652ba4c33","insertion_order":58,"keys":[""],"mode":"normal","name":"마법 물건: Chime of Opening","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"마법 물건: Circlet of Blasting","constant":false,"content":"## Circlet of Blasting (폭발의 머리띠) - magic item, SRD 5.2.1\nWondrous Item, Uncommon.\nWhile wearing this circlet, you can cast Scorching Ray with it (+5 to hit). The circlet can't cast this spell again until the next dawn.","enabled":true,"extensions":{},"folder":"folder:c5aedaa9-1450-4cf3-a103-74d652ba4c33","insertion_order":58,"keys":[""],"mode":"normal","name":"마법 물건: Circlet of Blasting","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"마법 물건: Cloak of Arachnida","constant":false,"content":"## Cloak of Arachnida (거미의 망토) - magic item, SRD 5.2.1\nWondrous Item, Very Rare (Requires Attunement).\nThis fine garment is made of black silk interwoven with faint, silvery threads. While wearing it, you gain the following benefits. Poison Resistance. You have Resistance to Poison damage. Spider Climb. You have a Climb Speed equal to your Speed and can move up, down, and across vertical surfaces and along ceilings, while leaving your hands free. Spider Walk. You can't be caught in webs of any sort and can move through webs as if they were Difficult Terrain. Web. You can cast Web (save DC 13). The web created by the spell fills twice its normal area. Once used, this property can't be used again until the next dawn.","enabled":true,"extensions":{},"folder":"folder:c5aedaa9-1450-4cf3-a103-74d652ba4c33","insertion_order":58,"keys":[""],"mode":"normal","name":"마법 물건: Cloak of Arachnida","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"마법 물건: Cloak of Displacement","constant":false,"content":"## Cloak of Displacement (전위의 망토) - magic item, SRD 5.2.1\nWondrous Item, Rare (Requires Attunement).\nWhile you wear this cloak, it magically projects an illusion that makes you appear to be standing in a place near your actual location, causing any creature to have Disadvantage on attack rolls against you. If you take damage, the property ceases to function until the start of your next turn. This property is suppressed while your Speed is 0.","enabled":true,"extensions":{},"folder":"folder:c5aedaa9-1450-4cf3-a103-74d652ba4c33","insertion_order":58,"keys":[""],"mode":"normal","name":"마법 물건: Cloak of Displacement","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"마법 물건: Cloak of Elvenkind","constant":false,"content":"## Cloak of Elvenkind (엘프의 망토) - magic item, SRD 5.2.1\nWondrous Item, Uncommon (Requires Attunement).\nWhile you wear this cloak, Wisdom (Perception) checks made to perceive you have Disadvantage, and you have Advantage on Dexterity (Stealth) checks.","enabled":true,"extensions":{},"folder":"folder:c5aedaa9-1450-4cf3-a103-74d652ba4c33","insertion_order":58,"keys":[""],"mode":"normal","name":"마법 물건: Cloak of Elvenkind","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"마법 물건: Cloak of Invisibility","constant":false,"content":"## Cloak of Invisibility (투명화 망토) - magic item, SRD 5.2.1\nWondrous Item, Legendary (Requires Attunement).\nThis cloak has 3 charges and regains 1d3 expended charges daily at dawn. While wearing the cloak, you can take a Magic action to pull its hood over your 216 head and expend 1 charge to give yourself the Invisible condition for 1 hour. The effect ends early if you pull the hood down (no action required) or cease wearing the cloak.","enabled":true,"extensions":{},"folder":"folder:c5aedaa9-1450-4cf3-a103-74d652ba4c33","insertion_order":58,"keys":[""],"mode":"normal","name":"마법 물건: Cloak of Invisibility","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"마법 물건: Cloak of Protection","constant":false,"content":"## Cloak of Protection (보호의 망토) - magic item, SRD 5.2.1\nWondrous Item, Uncommon (Requires Attunement).\nYou gain a +1 bonus to Armor Class and saving throws while you wear this cloak.","enabled":true,"extensions":{},"folder":"folder:c5aedaa9-1450-4cf3-a103-74d652ba4c33","insertion_order":58,"keys":[""],"mode":"normal","name":"마법 물건: Cloak of Protection","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"마법 물건: Cloak of the Bat","constant":false,"content":"## Cloak of the Bat (박쥐의 망토) - magic item, SRD 5.2.1\nWondrous Item, Rare (Requires Attunement).\nWhile wearing this cloak, you have Advantage on Dexterity (Stealth) checks. In an area of Dim Light or Darkness, you can grip the edges of the cloak and use it to gain a Fly Speed of 40 feet. If you ever fail to grip the cloak's edges while flying in this way, or if you are no longer in Dim Light or Darkness, you lose this Fly Speed. While wearing the cloak in an area of Dim Light or Darkness, you can cast Polymorph on yourself, shape-shifting into a Bat. While in that form, you retain your Intelligence, Wisdom, and Charisma scores. The cloak can't be used this way again until the next dawn.","enabled":true,"extensions":{},"folder":"folder:c5aedaa9-1450-4cf3-a103-74d652ba4c33","insertion_order":58,"keys":[""],"mode":"normal","name":"마법 물건: Cloak of the Bat","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"마법 물건: Cloak of the Manta Ray","constant":false,"content":"## Cloak of the Manta Ray (쥐가오리 망토) - magic item, SRD 5.2.1\nWondrous Item, Uncommon (Requires Attunement).\nWhile wearing this cloak, you can breathe underwater, and you have a Swim Speed of 60 feet.","enabled":true,"extensions":{},"folder":"folder:c5aedaa9-1450-4cf3-a103-74d652ba4c33","insertion_order":58,"keys":[""],"mode":"normal","name":"마법 물건: Cloak of the Manta Ray","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"마법 물건: Crystal Ball","constant":false,"content":"## Crystal Ball (수정 구슬) - magic item, SRD 5.2.1\nWondrous Item, Very Rare (Requires Attunement).\nWhile touching this crystal orb, you can cast Scrying (save DC 17) with it.","enabled":true,"extensions":{},"folder":"folder:c5aedaa9-1450-4cf3-a103-74d652ba4c33","insertion_order":58,"keys":[""],"mode":"normal","name":"마법 물건: Crystal Ball","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"마법 물건: Crystal Ball of Mind Reading","constant":false,"content":"## Crystal Ball of Mind Reading (독심의 수정 구슬) - magic item, SRD 5.2.1\nWondrous Item, Legendary (Requires Attunement).\nWhile touching this crystal orb, you can cast Scrying (save DC 17) with it. In addition, you can cast Detect Thoughts (save DC 17) targeting creatures you can see within 30 feet of the spell's sensor. You don't need to concentrate on this Detect Thoughts spell to maintain it during its duration, but it ends if the Scrying spell ends.","enabled":true,"extensions":{},"folder":"folder:c5aedaa9-1450-4cf3-a103-74d652ba4c33","insertion_order":58,"keys":[""],"mode":"normal","name":"마법 물건: Crystal Ball of Mind Reading","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"마법 물건: Crystal Ball of Telepathy","constant":false,"content":"## Crystal Ball of Telepathy (정신감응의 수정 구슬) - magic item, SRD 5.2.1\nWondrous Item, Legendary (Requires Attunement).\nWhile touching this crystal orb, you can cast Scrying (save DC 17) with it. In addition, you can communicate telepathically with creatures you can see within 30 feet of the spell's sensor. You can also cast Suggestion (save DC 17) through the sensor on one of those creatures. You don't need to concentrate on this Suggestion to maintain it during its duration, but it ends if Scrying ends. You can't cast Suggestion in this way again until the next dawn.","enabled":true,"extensions":{},"folder":"folder:c5aedaa9-1450-4cf3-a103-74d652ba4c33","insertion_order":58,"keys":[""],"mode":"normal","name":"마법 물건: Crystal Ball of Telepathy","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"마법 물건: Crystal Ball of True Seeing","constant":false,"content":"## Crystal Ball of True Seeing (진시야의 수정 구슬) - magic item, SRD 5.2.1\nWondrous Item, Legendary (Requires Attunement).\nWhile touching this crystal orb, you can cast Scrying (save DC 17) with it. In addition, you have Truesight with a range of 120 feet centered on the spell's sensor.","enabled":true,"extensions":{},"folder":"folder:c5aedaa9-1450-4cf3-a103-74d652ba4c33","insertion_order":58,"keys":[""],"mode":"normal","name":"마법 물건: Crystal Ball of True Seeing","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"마법 물건: Cube of Force","constant":false,"content":"## Cube of Force (역장 정육면체) - magic item, SRD 5.2.1\nWondrous Item, Rare (Requires Attunement).\nThis cube is about an inch across. Each face has a distinct marking on it. You can press one of those faces, expend the number of charges required for it, and thereby cast the spell associated with it (save DC 17), as shown in the Cube of Force Faces table. The cube starts with 10 charges, and it regains 1d6 expended charges daily at dawn. Cube of Force Faces Spell Charge Cost Mage Armor 1 Shield 1 Tiny Hut 3 Private Sanctum 4 Resilient Sphere 4 Wall of Force 5","enabled":true,"extensions":{},"folder":"folder:c5aedaa9-1450-4cf3-a103-74d652ba4c33","insertion_order":58,"keys":[""],"mode":"normal","name":"마법 물건: Cube of Force","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"마법 물건: Cubic Gate","constant":false,"content":"## Cubic Gate (차원문 정육면체) - magic item, SRD 5.2.1\nWondrous Item, Legendary.\nThis cube is 3 inches across and radiates palpable magical energy. The six sides of the cube are each keyed to a different plane of existence, one of which is the Material Plane. The other sides are linked to planes determined by the GM. The cube has 3 charges and regains 1d3 expended charges daily at dawn. As a Magic action, you can expend 1 of the cube's charges to cast one of the following spells using the cube. Gate. Pressing one side of the cube, you cast Gate, opening a portal to the plane of existence keyed to that side. Plane Shift. Pressing one side of the cube twice, you cast Plane Shift, transporting the targets to the plane of existence keyed to that side.","enabled":true,"extensions":{},"folder":"folder:c5aedaa9-1450-4cf3-a103-74d652ba4c33","insertion_order":58,"keys":[""],"mode":"normal","name":"마법 물건: Cubic Gate","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"마법 물건: Dagger of Venom","constant":false,"content":"## Dagger of Venom (독의 대거) - magic item, SRD 5.2.1\nWeapon (Dagger), Rare.\nYou gain a +1 bonus to attack rolls and damage rolls made with this magic weapon. You can take a Bonus Action to magically coat the blade with poison. The poison remains for 1 minute or until an attack using this weapon hits a creature. That creature must succeed on a DC 15 Constitution saving throw or take 2d10 Poison damage and have the Poisoned condition for 1 minute. The weapon can't be used this way again until the next dawn. 217","enabled":true,"extensions":{},"folder":"folder:c5aedaa9-1450-4cf3-a103-74d652ba4c33","insertion_order":58,"keys":[""],"mode":"normal","name":"마법 물건: Dagger of Venom","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"마법 물건: Dancing Sword","constant":false,"content":"## Dancing Sword (춤추는 검) - magic item, SRD 5.2.1\nWeapon (Greatsword, Longsword, Rapier, Scimitar, or Shortsword), Very Rare (Requires Attunement).\nYou can take a Bonus Action to toss this magic weapon into the air. When you do so, the weapon begins to hover, flies up to 30 feet, and attacks one creature of your choice within 5 feet of itself. The weapon uses your attack roll and adds your ability modifier to damage rolls. While the weapon hovers, you can take a Bonus Action to cause it to fly up to 30 feet to another spot within 30 feet of you. As part of the same Bonus Action, you can cause the weapon to attack one creature within 5 feet of the weapon. After the hovering weapon attacks for the fourth time, it flies back to you and tries to return to your hand. If you have no hand free, the weapon falls to the ground in your space. If the weapon has no unobstructed path to you, it moves as close to you as it can and then falls to the ground. It also ceases to hover if you grasp it or are more than 30 feet away from it.","enabled":true,"extensions":{},"folder":"folder:c5aedaa9-1450-4cf3-a103-74d652ba4c33","insertion_order":58,"keys":[""],"mode":"normal","name":"마법 물건: Dancing Sword","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"마법 물건: Decanter of Endless Water","constant":false,"content":"## Decanter of Endless Water (끝없는 물병) - magic item, SRD 5.2.1\nWondrous Item, Uncommon.\nThis stoppered flask sloshes when shaken, as if it contains water. The decanter weighs 2 pounds. You can take a Magic action to remove the stopper and issue one of three command words, whereupon an amount of fresh water or salt water (your choice) pours out of the flask. The water stops pouring out at the start of your next turn. Choose from the following command words: Splash. The decanter produces 1 gallon of water. Fountain. The decanter produces 5 gallons of water. Geyser. The decanter produces 30 gallons of water that gushes forth in a Line 30 feet long and 1 foot wide. If you're holding the decanter, you can aim the geyser in one direction (no action required). One creature of your choice in the Line must succeed on a DC 13 Strength saving throw or take 1d4 Bludgeoning damage and have the Prone condition. Instead of a creature, you can target one object in the Line that isn't being worn or carried and that weighs no more than 200 pounds. The object is knocked over by the geyser.","enabled":true,"extensions":{},"folder":"folder:c5aedaa9-1450-4cf3-a103-74d652ba4c33","insertion_order":58,"keys":[""],"mode":"normal","name":"마법 물건: Decanter of Endless Water","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"마법 물건: Deck of Illusions","constant":false,"content":"## Deck of Illusions (환영 카드) - magic item, SRD 5.2.1\nWondrous Item, Uncommon.\nThis box contains a set of cards. A full deck has 34 cards: 32 depicting specific creatures and two with a mirrored surface. A deck found as treasure is usually missing 1d20 - 1 cards. The magic of the deck functions only if its cards are drawn at random. You can take a Magic action to draw a card at random from the deck and throw it to the ground at a point within 30 feet of yourself. An illusion of a creature, determined by rolling on the Deck of Illusions table, forms over the thrown card and remains until dispelled. The illusory creature created by the card looks and behaves like a real creature of its kind, except that it can do no harm. While you are within 120 feet of the illusory creature and can see it, you can take a Magic action to move it anywhere within 30 feet of its card. Any physical interaction with the illusory creature reveals it to be false, because objects pass through it. A creature that takes a Study action to visually inspect the illusory creature identifies it as an illusion with a successful DC 15 Intelligence (Investigation) check. The illusion lasts until its card is moved or the illusion is dispelled (using a Dispel Magic spell or a similar effect). When the illusion ends, the image on its card disappears, and that card can't be used again. Deck of Illusions 1d100 Illusion* 01-03 Adult Red Dragon 04-06 Archmage 07-09 Assassin 10-12 Bandit Captain 13-15 Basilisk 16-18 Berserker 19-21 Bugbear Warrior 22-24 Cloud Giant 25-27 Druid 28-30 Erinyes 31-33 Ettin 34-36 Fire Giant 37-39 Frost Giant 40-42 Gnoll Warrior 43-45 Goblin Warrior 46-48 Guardian Naga 49-51 Hill Giant 52-54 Hobgoblin Warrior 55-57 Incubus 58-60 Iron Golem 61-63 Knight 64-66 Kobold Warrior 67-69 Lich 70-72 Medusa 73-75 Night Hag 76-78 Ogre 79-81 Oni 218 1d100 Illusion* 82-84 Priest 85-87 Succubus 88-90 Troll 91-93 Veteran Warrior 94-96 Wyvern 97-00 The card drawer *Stat blocks for these creatures (except the card drawer) appear in “Monsters.”","enabled":true,"extensions":{},"folder":"folder:c5aedaa9-1450-4cf3-a103-74d652ba4c33","insertion_order":58,"keys":[""],"mode":"normal","name":"마법 물건: Deck of Illusions","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"마법 물건: Defender","constant":false,"content":"## Defender (수호의 무기) - magic item, SRD 5.2.1\nWeapon (Any Melee Weapon), Legendary (Requires Attunement).\nYou gain a +3 bonus to attack rolls and damage rolls made with this magic weapon. The first time you attack with the weapon on each of your turns, you can transfer some or all of the weapon's bonus to your Armor Class. For example, you could reduce the bonus to your attack rolls and damage rolls to +1 and gain a +2 bonus to Armor Class. The adjusted bonuses remain in effect until the start of your next turn, although you must hold the weapon to gain a bonus to AC from it.","enabled":true,"extensions":{},"folder":"folder:c5aedaa9-1450-4cf3-a103-74d652ba4c33","insertion_order":58,"keys":[""],"mode":"normal","name":"마법 물건: Defender","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"마법 물건: Demon Armor","constant":false,"content":"## Demon Armor (악마 갑옷) - magic item, SRD 5.2.1\nArmor (Any Light, Medium, or Heavy), Very Rare (Requires Attunement).\nWhile wearing this armor, you gain a +1 bonus to Armor Class, and you know Abyssal. In addition, the armor's clawed gauntlets allow your Unarmed Strikes to deal 1d8 Slashing damage instead of the usual Bludgeoning damage, and you gain a +1 bonus to the attack and damage rolls of your Unarmed Strikes. Curse. Once you don this cursed armor, you can't doff it unless you are targeted by a Remove Curse spell or similar magic. While wearing the armor, you have Disadvantage on attack rolls against demons and on saving throws against their spells and special abilities.","enabled":true,"extensions":{},"folder":"folder:c5aedaa9-1450-4cf3-a103-74d652ba4c33","insertion_order":58,"keys":[""],"mode":"normal","name":"마법 물건: Demon Armor","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"마법 물건: Dimensional Shackles","constant":false,"content":"## Dimensional Shackles (차원 족쇄) - magic item, SRD 5.2.1\nWondrous Item, Rare.\nYou can take a Utilize action to place these shackles on a creature that has the Incapacitated condition. The shackles adjust to fit a creature of Small to Large size. The shackles prevent a creature bound by them from using any method of extradimensional movement, including teleportation or travel to a different plane of existence. They don't prevent the creature from passing through an interdimensional portal. You and any creature you designate when you use the shackles can take a Utilize action to remove them. Once every 30 days, the bound creature can make a DC 30 Strength (Athletics) check. On a successful check, the creature breaks free and destroys the shackles.","enabled":true,"extensions":{},"folder":"folder:c5aedaa9-1450-4cf3-a103-74d652ba4c33","insertion_order":58,"keys":[""],"mode":"normal","name":"마법 물건: Dimensional Shackles","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"마법 물건: Dragon Orb","constant":false,"content":"## Dragon Orb (용의 구슬) - magic item, SRD 5.2.1\nWondrous Item, Artifact (Requires Attunement).\nAn orb is an etched crystal globe about 10 inches in diameter. When used, it grows to about 20 inches in diameter, and mist swirls inside it. While attuned to an orb, you can take a Magic action to peer into the orb's depths. You must then make a DC 15 Charisma saving throw. On a successful save, you control the orb for as long as you remain attuned to it. On a failed save, the orb imposes the Charmed condition on you for as long as you remain attuned to it. While you are Charmed by the orb, you can't voluntarily end your Attunement to it, and the orb casts Suggestion on you at will (save DC 18), urging you to work toward the evil ends it desires. The dragon essence within the orb might want many things: the annihilation of a particular society or organization, freedom from the orb, to spread suffering in the world, to advance the worship of Tiamat, or something else the GM decides. Spells. The orb has 7 charges and regains 1d4 + 3 expended charges daily at dawn. If you control the orb, you can cast one of the spells on the following table from it. The table indicates how many charges you must expend to cast the spell. Spell Charge Cost Cure Wounds (level 9 version) 4 Daylight 1 Death Ward 2 Detect Magic 0 Scrying (save DC 18) 3 Call Dragons. While you control the orb, you can take a Magic action to cause the orb to issue a telepathic call that extends in all directions for 40 miles. Chromatic dragons in range feel compelled to come to the orb as soon as possible by the most direct route. Dragon deities such as Tiamat are unaffected by this call. Chromatic dragons drawn to the orb might be Hostile toward you for compelling them against their will. Once you have used this property, it can't be used again for 1 hour. Destroying an Orb. A Dragon Orb has AC 20 and is destroyed if it takes damage from a +3 Weapon or a Disintegrate spell. Nothing else can harm it.","enabled":true,"extensions":{},"folder":"folder:c5aedaa9-1450-4cf3-a103-74d652ba4c33","insertion_order":58,"keys":[""],"mode":"normal","name":"마법 물건: Dragon Orb","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"마법 물건: Dragon Scale Mail","constant":false,"content":"## Dragon Scale Mail (용비늘 갑옷) - magic item, SRD 5.2.1\nArmor (Scale Mail), Very Rare (Requires Attunement).\nDragon Scale Mail is made of the scales of one kind of dragon. Sometimes dragons collect their cast-off 219 scales and gift them. Other times, hunters carefully preserve the hide of a dead dragon. In either case, Dragon Scale Mail is highly valued. While wearing this armor, you gain a +1 bonus to Armor Class, you have Advantage on saving throws against the breath weapons of Dragons, and you have Resistance to one damage type determined by the kind of dragon that provided the scales (see the accompanying table). Additionally, you can focus your senses as a Magic action to discern the distance and direction to the closest dragon within 30 miles of yourself that is of the same type as the armor. This action can't be used again until the next dawn. Dragon Resistance Dragon Resistance Black Acid Gold Fire Blue Lightning Green Poison Brass Fire Red Fire Bronze Lightning Silver Cold Copper Acid White Cold","enabled":true,"extensions":{},"folder":"folder:c5aedaa9-1450-4cf3-a103-74d652ba4c33","insertion_order":58,"keys":[""],"mode":"normal","name":"마법 물건: Dragon Scale Mail","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"마법 물건: Dragon Slayer","constant":false,"content":"## Dragon Slayer (용 살해 무기) - magic item, SRD 5.2.1\nWeapon (Any Simple or Martial), Rare.\nYou gain a +1 bonus to attack rolls and damage rolls made with this magic weapon. The weapon deals an extra 3d6 damage of the weapon's type if the target is a Dragon.","enabled":true,"extensions":{},"folder":"folder:c5aedaa9-1450-4cf3-a103-74d652ba4c33","insertion_order":58,"keys":[""],"mode":"normal","name":"마법 물건: Dragon Slayer","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"마법 물건: Dust of Disappearance","constant":false,"content":"## Dust of Disappearance (사라짐 가루) - magic item, SRD 5.2.1\nWondrous Item, Uncommon.\nThis powder resembles fine sand. There is enough of it for one use. When you take a Utilize action to throw the dust into the air, you and each creature and object within a 10-foot Emanation originating from you have the Invisible condition for 2d4 minutes. The duration is the same for all subjects, and the dust is consumed when its magic takes effect. Immediately after an affected creature makes an attack roll, deals damage, or casts a spell, the Invisible condition ends for that creature.","enabled":true,"extensions":{},"folder":"folder:c5aedaa9-1450-4cf3-a103-74d652ba4c33","insertion_order":58,"keys":[""],"mode":"normal","name":"마법 물건: Dust of Disappearance","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"마법 물건: Dust of Dryness","constant":false,"content":"## Dust of Dryness (건조 가루) - magic item, SRD 5.2.1\nWondrous Item, Uncommon.\nThis small packet contains 1d6 + 4 pinches of dust. As a Utilize action, you can sprinkle a pinch of the dust over water, turning up to a 15-foot Cube of water into one marble-sized pellet, which floats or rests near where the dust was sprinkled. The pellet's weight is negligible. A creature can take a Utilize action to smash the pellet against a hard surface, causing the pellet to shatter and release the water the dust absorbed. Doing so destroys the pellet and ends its magic. As a Utilize action, you can sprinkle a pinch of the dust on an Elemental within 5 feet of yourself that is composed mostly of water (such as a Water Elemental). Such a creature exposed to a pinch of the dust makes a DC 13 Constitution saving throw, taking 10d6 Necrotic damage on a failed save or half as much damage on a successful one.","enabled":true,"extensions":{},"folder":"folder:c5aedaa9-1450-4cf3-a103-74d652ba4c33","insertion_order":58,"keys":[""],"mode":"normal","name":"마법 물건: Dust of Dryness","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"마법 물건: Dust of Sneezing and Choking","constant":false,"content":"## Dust of Sneezing and Choking (재채기 가루) - magic item, SRD 5.2.1\nWondrous Item, Uncommon.\nFound in a small container, this powder resembles Dust of Disappearance, and Identify reveals it to be such. There is enough of it for one use. As a Utilize action, you can throw the dust into the air, forcing yourself and every creature in a 30-foot Emanation originating from you to make a DC 15 Constitution saving throw. Constructs, Elementals, Oozes, Plants, and Undead succeed on the save automatically. On a failed save, a creature begins sneezing uncontrollably; it has the Incapacitated condition and is suffocating. The creature repeats the save at the end of each of its turns, ending the effect on itself on a success. The effect also ends on any creature targeted by a Lesser Restoration spell.","enabled":true,"extensions":{},"folder":"folder:c5aedaa9-1450-4cf3-a103-74d652ba4c33","insertion_order":58,"keys":[""],"mode":"normal","name":"마법 물건: Dust of Sneezing and Choking","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"마법 물건: Dwarven Plate","constant":false,"content":"## Dwarven Plate (드워프 판금 갑옷) - magic item, SRD 5.2.1\nArmor (Half Plate Armor or Plate Armor), Very Rare.\nWhile wearing this armor, you gain a +2 bonus to Armor Class. In addition, if an effect moves you against your will along the ground, you can take a Reaction to reduce the distance you are moved by up to 10 feet.","enabled":true,"extensions":{},"folder":"folder:c5aedaa9-1450-4cf3-a103-74d652ba4c33","insertion_order":58,"keys":[""],"mode":"normal","name":"마법 물건: Dwarven Plate","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"마법 물건: Dwarven Thrower","constant":false,"content":"## Dwarven Thrower (드워프 투척 망치) - magic item, SRD 5.2.1\nWeapon (Warhammer), Very Rare (Requires Attunement by a Dwarf or a Creature Attuned to a Belt of Dwarvenkind).\nYou gain a +3 bonus to attack rolls and damage rolls made with this magic weapon. It has the Thrown property with a normal range of 20 feet and a long range of 60 feet. When you hit with a ranged attack using this weapon, it deals an extra 1d8 Force damage, or an extra 2d8 Force damage if the target is a Giant. Immediately after hitting or missing, the weapon flies back to your hand.","enabled":true,"extensions":{},"folder":"folder:c5aedaa9-1450-4cf3-a103-74d652ba4c33","insertion_order":58,"keys":[""],"mode":"normal","name":"마법 물건: Dwarven Thrower","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"마법 물건: Efficient Quiver","constant":false,"content":"## Efficient Quiver (효율적인 화살통) - magic item, SRD 5.2.1\nWondrous Item, Uncommon.\nEach of the quiver's three compartments connects to an extradimensional space that allows the quiver to hold numerous items while never weighing more than 2 pounds. The shortest compartment can hold up to 60 Arrows, Bolts, or similar objects. The midsize compartment holds up to 18 Javelins or similar objects. The longest compartment holds up to 6 long objects, such as bows, Quarterstaffs, or Spears. You can draw any item the quiver contains as if doing so from a regular quiver or scabbard. 220","enabled":true,"extensions":{},"folder":"folder:c5aedaa9-1450-4cf3-a103-74d652ba4c33","insertion_order":58,"keys":[""],"mode":"normal","name":"마법 물건: Efficient Quiver","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"마법 물건: Efreeti Bottle","constant":false,"content":"## Efreeti Bottle (에프리트 병) - magic item, SRD 5.2.1\nWondrous Item, Very Rare.\nWhen you take a Magic action to remove the stopper of this painted brass bottle, a cloud of thick smoke flows out of it. At the end of your turn, the smoke disappears with a flash of harmless fire, and an Efreeti appears in an unoccupied space within 30 feet of you. The first time the bottle is opened, the GM rolls on the following table to determine what happens. 1d10 Effect 1 The efreeti attacks you. After fighting for 5 rounds, the efreeti disappears, and the bottle loses its magic. 2-9 The efreeti understands your languages and obeys your commands for 1 hour, after which it returns to the bottle, and a new stopper contains it. The stopper can't be removed for 24 hours. The next two times the bottle is opened, the same effect occurs. If the bottle is opened a fourth time, the efreeti escapes and disappears, and the bottle loses its magic. 10 The efreeti understands your languages and can cast Wish once for you. It disappears when it grants the wish or after 1 hour, and the bottle loses its magic.","enabled":true,"extensions":{},"folder":"folder:c5aedaa9-1450-4cf3-a103-74d652ba4c33","insertion_order":58,"keys":[""],"mode":"normal","name":"마법 물건: Efreeti Bottle","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"마법 물건: Elemental Gem","constant":false,"content":"## Elemental Gem (원소 보석) - magic item, SRD 5.2.1\nWondrous Item, Uncommon.\nThis gem contains a mote of elemental energy. When you take a Utilize action to break the gem, an elemental is summoned (see “Monsters” for its stat block), and the gem ceases to be magical. The elemental appears in an unoccupied space as close to the broken gem as possible, understands your languages, obeys your commands, and takes its turn immediately after you on your Initiative count. The elemental disappears after 1 hour, when it dies, or when you dismiss it as a Bonus Action. The type of gem determines the elemental, as shown in the following table. Gem Summoned Elemental Blue sapphire Air Elemental Emerald Water Elemental Red corundum Fire Elemental Yellow diamond Earth Elemental","enabled":true,"extensions":{},"folder":"folder:c5aedaa9-1450-4cf3-a103-74d652ba4c33","insertion_order":58,"keys":[""],"mode":"normal","name":"마법 물건: Elemental Gem","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"마법 물건: Elixir of Health","constant":false,"content":"## Elixir of Health (건강의 영약) - magic item, SRD 5.2.1\nPotion, Rare.\nWhen you drink this potion, you are cured of all magical contagions. In addition, the following conditions end on you: Blinded, Deafened, Paralyzed, and Poisoned. The clear, red liquid has tiny bubbles of light in it.","enabled":true,"extensions":{},"folder":"folder:c5aedaa9-1450-4cf3-a103-74d652ba4c33","insertion_order":58,"keys":[""],"mode":"normal","name":"마법 물건: Elixir of Health","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"마법 물건: Elven Chain","constant":false,"content":"## Elven Chain (엘프 사슬 갑옷) - magic item, SRD 5.2.1\nArmor (Chain Mail or Chain Shirt), Rare.\nYou gain a +1 bonus to Armor Class while you wear this armor. You are considered trained with this armor even if you lack training with Medium or Heavy armor.","enabled":true,"extensions":{},"folder":"folder:c5aedaa9-1450-4cf3-a103-74d652ba4c33","insertion_order":58,"keys":[""],"mode":"normal","name":"마법 물건: Elven Chain","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"마법 물건: Energy Bow","constant":false,"content":"## Energy Bow (에너지 활) - magic item, SRD 5.2.1\nWeapon (Longbow or Shortbow), Very Rare (Requires Attunement).\nYou gain a +1 bonus to attack rolls and damage rolls made with this magic weapon, which has no string. Each time you pull your arm back in a firing motion, a magical arrow made of golden energy appears nocked and ready to fire. An arrow produced by this weapon deals Force damage instead of Piercing damage on a hit, and it disappears after it hits or misses its target. Until it disappears, the arrow emits Bright Light in a 20-foot radius and Dim Light for an additional 20 feet. This weapon has the following additional properties. Arrow of Restraint. Whenever you use this weapon to make a ranged attack against a creature, you can try to restrain the target instead of dealing damage to it. If the arrow hits, the target must succeed on a DC 15 Strength saving throw or have the Restrained condition for 1 minute. As an action, a creature Restrained by an arrow can make a DC 20 Strength (Athletics) check to try to break the restraint, ending the effect on itself on a successful check. Arrow of Transport. As a Magic action, you can fire one energy arrow from this weapon at a target you can see within 60 feet of yourself. The target can be either a willing Medium or smaller creature or an object that isn't being worn or carried, provided the object is small enough to fit inside a 5-foot Cube. The arrow teleports the target to an unoccupied space you can see within 10 feet of you. Energy Ladder. As a Magic action, you can loose a flurry of energy arrows from this weapon at a wall up to 60 feet away from yourself. The arrows become glowing rungs that stick out of the wall, forming a magical ladder up to 60 feet long on the wall. This ladder lasts for 1 minute before disappearing.","enabled":true,"extensions":{},"folder":"folder:c5aedaa9-1450-4cf3-a103-74d652ba4c33","insertion_order":58,"keys":[""],"mode":"normal","name":"마법 물건: Energy Bow","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"마법 물건: Eversmoking Bottle","constant":false,"content":"## Eversmoking Bottle (끝없는 연기 병) - magic item, SRD 5.2.1\nWondrous Item, Uncommon.\nAs a Magic action, you can open or close this bottle. Opening the bottle causes thick smoke to billow out, forming a cloud that fills a 60-foot Emanation originating from the bottle. The area within the smoke is Heavily Obscured. Each minute the bottle remains open, the size of the Emanation increases by 10 feet until it reaches its maximum size of 120 feet. 221 Closing the bottle causes the cloud to become fixed in place until it disperses after 10 minutes. A strong wind (such as that created by the Gust of Wind spell) disperses the cloud after 1 minute.","enabled":true,"extensions":{},"folder":"folder:c5aedaa9-1450-4cf3-a103-74d652ba4c33","insertion_order":58,"keys":[""],"mode":"normal","name":"마법 물건: Eversmoking Bottle","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"마법 물건: Eyes of Charming","constant":false,"content":"## Eyes of Charming (매혹의 렌즈) - magic item, SRD 5.2.1\nWondrous Item, Uncommon (Requires Attunement).\nThese crystal lenses fit over the eyes. They have 3 charges. While wearing them, you can expend 1 or more charges to cast Charm Person (save DC 13). For 1 charge, you cast the level 1 version of the spell. You increase the spell's level by one for each additional charge you expend. The lenses regain all expended charges daily at dawn.","enabled":true,"extensions":{},"folder":"folder:c5aedaa9-1450-4cf3-a103-74d652ba4c33","insertion_order":58,"keys":[""],"mode":"normal","name":"마법 물건: Eyes of Charming","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"마법 물건: Eyes of Minute Seeing","constant":false,"content":"## Eyes of Minute Seeing (세밀 시야 렌즈) - magic item, SRD 5.2.1\nWondrous Item, Uncommon.\nThese crystal lenses fit over the eyes. While wearing them, your vision improves significantly out to a range of 1 foot, granting you Darkvision within that range and Advantage on Intelligence (Investigation) checks made to examine something within that range.","enabled":true,"extensions":{},"folder":"folder:c5aedaa9-1450-4cf3-a103-74d652ba4c33","insertion_order":58,"keys":[""],"mode":"normal","name":"마법 물건: Eyes of Minute Seeing","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"마법 물건: Eyes of the Eagle","constant":false,"content":"## Eyes of the Eagle (독수리 눈 렌즈) - magic item, SRD 5.2.1\nWondrous Item, Uncommon.\nThese crystal lenses fit over the eyes. While wearing them, you have Advantage on Wisdom (Perception) checks that rely on sight. In conditions of clear visibility, you can make out details of even extremely distant creatures and objects as small as 2 feet across.","enabled":true,"extensions":{},"folder":"folder:c5aedaa9-1450-4cf3-a103-74d652ba4c33","insertion_order":58,"keys":[""],"mode":"normal","name":"마법 물건: Eyes of the Eagle","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"마법 물건: Feather Token","constant":false,"content":"## Feather Token (깃털 부적) - magic item, SRD 5.2.1\nWondrous Item, Rarity Varies.\nThis object looks like a feather. Different types of feather tokens exist, each with a different single-use effect. The GM chooses the kind of token or determines it randomly by rolling on the Feather Tokens table. The type of token determines its rarity. Anchor (Uncommon). You can take a Magic action to touch the token to a boat or ship. For the next 24 hours, the vessel can't be moved by any means. Touching the token to the vessel again ends the effect. When the effect ends, the token disappears. Bird (Rare). You can take a Magic action to toss the token 5 feet into the air. The token disappears and an enormous, multicolored bird takes its place. The bird has the statistics of a Roc, but it can't attack. It obeys your simple commands and can carry up to 500 pounds while flying at its maximum speed (16 miles per hour for a maximum of 144 miles per day, with a 1-hour rest for every 3 hours of flying) or 1,000 pounds at half that speed. The bird disappears after flying its maximum distance for a day or if it drops to 0 Hit Points. You can dismiss the bird as a Magic action. Fan (Uncommon). If you are on a boat or ship, you can take a Magic action to toss the token up to 10 feet in the air. The token disappears, and a giant flapping fan takes its place. The fan floats and creates a strong wind. This wind can fill the sails of one ship, increasing its speed by 5 miles per hour for 8 hours. You can dismiss the fan as a Magic action. Swan Boat (Rare). You can take a Magic action to touch the token to a body of water at least 60 feet in diameter. The token disappears, and a 50-footlong, 20-foot-wide boat shaped like a swan takes its place. The boat is self-propelled and moves across water at a speed of 6 miles per hour. You can take a Magic action while on the boat to command it to move or to turn up to 90 degrees. The boat remains for 24 hours and then disappears. You can dismiss the boat as a Magic action. Tree (Uncommon). You must be outdoors to use this token. You can take a Magic action to touch it to an unoccupied space on the ground. The token disappears, and in its place a nonmagical oak tree springs into existence. The tree is 60 feet tall and has a 5-foot-diameter trunk, and its branches at the top spread out in a 20-foot radius. Whip (Rare). You can take a Magic action to throw the token to a point within 10 feet of yourself. The token disappears, and a floating whip takes its place. You can then take a Bonus Action to make a melee spell attack against a creature within 10 feet of the whip, with an attack bonus of +9. On a hit, the target takes 1d6 + 5 Force damage. As a Bonus Action, you can direct the whip to fly up to 20 feet and repeat the attack against a creature within 10 feet of the whip. The whip disappears after 1 hour, when you take a Magic action to dismiss it, or when you die or have the Incapacitated condition. Feather Tokens 1d100 Token Rarity 01-20 Anchor Uncommon 21-35 Bird Rare 36-50 Fan Uncommon 51-65 Swan boat Rare 66-90 Tree Uncommon 91-00 Whip Rare","enabled":true,"extensions":{},"folder":"folder:c5aedaa9-1450-4cf3-a103-74d652ba4c33","insertion_order":58,"keys":[""],"mode":"normal","name":"마법 물건: Feather Token","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"마법 물건: Figurine of Wondrous Power","constant":false,"content":"## Figurine of Wondrous Power (경이로운 힘의 조각상) - magic item, SRD 5.2.1\nWondrous Item, Rarity Varies.\nA Figurine of Wondrous Power is a statuette small enough to fit in a pocket. If you take a Magic action to throw the figurine to a point on the ground within 60 feet of yourself, the figurine becomes a living creature specified in the figurine's description below. If the space where the creature would appear is occupied by other creatures or objects, or 222 if there isn't enough space for the creature, the figurine doesn't become a creature. The creature is Friendly to you and your allies. It understands your languages, obeys your commands, and takes its turn immediately after you on your Initiative count. If you issue no commands, the creature defends itself but takes no other actions. The creature exists for a duration specific to each figurine. At the end of the duration, the creature reverts to its figurine form. It reverts to a figurine early if its creature form drops to 0 Hit Points or if you take a Magic action while touching the creature to make it revert to figurine form. When the creature becomes a figurine again, its property can't be used again until a certain amount of time has passed, as specified in the figurine's description. Bronze Griffon (Rare). This bronze statuette is of a griffon rampant. It can become a Griffon for up to 6 hours. Once it has been used, it can't be used again until 5 days have passed. Ebony Fly (Rare). This ebony statuette, carved in the likeness of a horsefly, can become a Giant Fly (see the accompanying stat block) for up to 12 hours and can be ridden as a mount. Once it has been used, it can't be used again until 2 days have passed. Giant Fly Large Beast, Unaligned AC 11 Initiative +1 (11) HP 19 (3d10 + 3) Speed 30 ft., Fly 60 ft. MOD SAVE MOD SAVE MOD SAVE Str 14 +2 +2 Dex 13 +1 +1 Con 13 +1 +1 Int 2 -4 -4 Wis 10 +0 +0 Cha 3 -4 -4 Senses Darkvision 60 ft., Passive Perception 10 Languages None CR 0 (XP 0; PB +2) Golden Lions (Rare). These gold statuettes of lions are always created in pairs. You can use one figurine or both simultaneously. Each can become a Lion for up to 1 hour. Once a lion has been used, it can't be used again until 7 days have passed. Ivory Goats (Rare). These ivory statuettes of goats are always created in sets of three. Each goat looks unique and functions differently from the others. Their properties are as follows: Goat of Terror. This figurine can become a Giant Goat for up to 3 hours. The goat can't attack, but you can (harmlessly) remove its horns and use them as weapons. One horn becomes a +1 Lance, and the other becomes a +2 Longsword. Removing a horn requires a Magic action, and the weapons disappear and the horns return when the goat reverts to figurine form. While you ride the goat, any Hostile creature that starts its turn within a 30-foot Emanation originating from the goat must succeed on a DC 15 Wisdom saving throw or have the Frightened condition for 1 minute, until you are no longer riding the goat, or until the goat reverts to figurine form. The Frightened creature repeats the save at the end of each of its turns, ending the effect on itself on a success. Once it succeeds on the save, a creature is immune to this effect for the next 24 hours. Once the figurine has been used, it can't be used again until 15 days have passed. Goat of Traveling. This figurine can become a Large goat with the same statistics as a Riding Horse. It has 24 charges, and each hour or portion thereof it spends in goat form costs 1 charge. While it has charges, you can use it as often as you wish. When it runs out of charges, it reverts to a figurine and can't be used again until 7 days have passed, when it regains all expended charges. Goat of Travail. This figurine can become a Giant Goat for up to 3 hours. Once it has been used, it can't be used again until 30 days have passed. Marble Elephant (Rare). This marble statuette resembles a trumpeting elephant. It can become an Elephant for up to 24 hours. Once it has been used, it can't be used again until 7 days have passed. Obsidian Steed (Very Rare). This polished obsidian horse can become a Nightmare for up to 24 hours. The nightmare fights only to defend itself. Once it has been used, it can't be used again until 5 days have passed. The figurine has a 10 percent chance each time you use it to ignore your orders, including a command to revert to figurine form. If you mount the nightmare while it is ignoring your orders, you and the nightmare are instantly transported to a random location on the plane of Hades, where the nightmare reverts to figurine form. Onyx Dog (Rare). This onyx statuette of a dog can become a Mastiff for up to 6 hours. The mastiff has an Intelligence of 8 and can speak Common. It also has Blindsight with a range of 60 feet. Once it has been used, it can't be used again until 7 days have passed. Serpentine Owl (Rare). This serpentine statuette of an owl can become a Giant Owl for up to 8 hours. The owl can communicate telepathically with you at any range if you and it are on the same plane of existence. Once it has been used, it can't be used again until 2 days have passed. Silver Raven (Uncommon). This silver statuette of a raven can become a Raven for up to 12 hours. Once it has been used, it can't be used again until 2 days have passed. While in raven form, the figurine grants you the ability to cast Animal Messenger on it. 223","enabled":true,"extensions":{},"folder":"folder:c5aedaa9-1450-4cf3-a103-74d652ba4c33","insertion_order":58,"keys":[""],"mode":"normal","name":"마법 물건: Figurine of Wondrous Power","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"마법 물건: Flame Tongue","constant":false,"content":"## Flame Tongue (화염의 혀) - magic item, SRD 5.2.1\nWeapon (Any Melee Weapon), Rare (Requires Attunement).\nWhile holding this magic weapon, you can take a Bonus Action and use a command word to cause flames to engulf the damage-dealing part of the weapon. These flames shed Bright Light in a 40foot radius and Dim Light for an additional 40 feet. While the weapon is ablaze, it deals an extra 2d6 Fire damage on a hit. The flames last until you take a Bonus Action to issue the command again or until you drop, stow, or sheathe the weapon.","enabled":true,"extensions":{},"folder":"folder:c5aedaa9-1450-4cf3-a103-74d652ba4c33","insertion_order":58,"keys":[""],"mode":"normal","name":"마법 물건: Flame Tongue","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"마법 물건: Folding Boat","constant":false,"content":"## Folding Boat (접는 배) - magic item, SRD 5.2.1\nWondrous Item, Rare.\nThis object appears as a wooden box that measures 12 inches long, 6 inches wide, and 6 inches deep. It weighs 4 pounds and floats. It can be opened to store items inside. This item also has three command words, each requiring a Magic action to use: First Command Word. The box unfolds into a Rowboat. Second Command Word. The box unfolds into a Keelboat. Third Command Word. The Folding Boat folds back into a box if no creatures are aboard. Any objects in the vessel that can't fit inside the box remain outside the box as it folds. Any objects in the vessel that can fit inside the box do so. When the box becomes a vessel, its weight becomes that of a normal vessel its size, and anything that was stored in the box remains in the boat. Statistics for the Rowboat and Keelboat appear in “Equipment.” If either vessel is reduced to 0 Hit Points, the Folding Boat is destroyed.","enabled":true,"extensions":{},"folder":"folder:c5aedaa9-1450-4cf3-a103-74d652ba4c33","insertion_order":58,"keys":[""],"mode":"normal","name":"마법 물건: Folding Boat","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"마법 물건: Frost Brand","constant":false,"content":"## Frost Brand (서리의 검) - magic item, SRD 5.2.1\nWeapon (Glaive, Greatsword, Longsword, Rapier, Scimitar, or Shortsword), Very Rare (Requires Attunement).\nWhen you hit with an attack roll using this magic weapon, the target takes an extra 1d6 Cold damage. In addition, while you hold the weapon, you have Resistance to Fire damage. In freezing temperatures, the weapon sheds Bright Light in a 10-foot radius and Dim Light for an additional 10 feet. When you draw this weapon, you can extinguish all nonmagical flames within 30 feet of yourself. Once used, this property can't be used again for 1 hour.","enabled":true,"extensions":{},"folder":"folder:c5aedaa9-1450-4cf3-a103-74d652ba4c33","insertion_order":58,"keys":[""],"mode":"normal","name":"마법 물건: Frost Brand","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"마법 물건: Gauntlets of Ogre Power","constant":false,"content":"## Gauntlets of Ogre Power (오우거 힘의 건틀릿) - magic item, SRD 5.2.1\nWondrous Item, Uncommon (Requires Attunement).\nYour Strength is 19 while you wear these gauntlets. They have no effect on you if your Strength is 19 or higher without them.","enabled":true,"extensions":{},"folder":"folder:c5aedaa9-1450-4cf3-a103-74d652ba4c33","insertion_order":58,"keys":[""],"mode":"normal","name":"마법 물건: Gauntlets of Ogre Power","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"마법 물건: Gem of Brightness","constant":false,"content":"## Gem of Brightness (광휘의 보석) - magic item, SRD 5.2.1\nWondrous Item, Uncommon.\nThis prism has 50 charges. While you are holding it, you can take a Magic action and use one of three command words to cause one of the following effects: First Command Word. The gem sheds Bright Light in a 30-foot radius and Dim Light for an additional 30 feet. This effect doesn't expend a charge. It lasts until you take a Bonus Action to repeat the command word or until you use another function of the gem. Second Command Word. You expend 1 charge and cause the gem to fire a brilliant beam of light at one creature you can see within 60 feet of yourself. The creature must succeed on a DC 15 Constitution saving throw or have the Blinded condition for 1 minute. The creature repeats the save at the end of each of its turns, ending the effect on itself on a success. Third Command Word. You expend 5 charges and cause the gem to flare with intense light in a 30foot Cone. Each creature in the Cone makes a saving throw as if struck by the beam created with the second command word. When all of the gem's charges are expended, the gem becomes a nonmagical jewel worth 50 GP.","enabled":true,"extensions":{},"folder":"folder:c5aedaa9-1450-4cf3-a103-74d652ba4c33","insertion_order":58,"keys":[""],"mode":"normal","name":"마법 물건: Gem of Brightness","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"마법 물건: Gem of Seeing","constant":false,"content":"## Gem of Seeing (투시의 보석) - magic item, SRD 5.2.1\nWondrous Item, Rare (Requires Attunement).\nThis gem has 3 charges. As a Magic action, you can expend 1 charge. For the next 10 minutes, you have Truesight out to 120 feet when you peer through the gem. The gem regains 1d3 expended charges daily at dawn.","enabled":true,"extensions":{},"folder":"folder:c5aedaa9-1450-4cf3-a103-74d652ba4c33","insertion_order":58,"keys":[""],"mode":"normal","name":"마법 물건: Gem of Seeing","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"마법 물건: Giant Slayer","constant":false,"content":"## Giant Slayer (거인 살해 무기) - magic item, SRD 5.2.1\nWeapon (Any Simple or Martial), Rare.\nYou gain a +1 bonus to attack rolls and damage rolls made with this magic weapon. When you hit a Giant with this weapon, the Giant takes an extra 2d6 damage of the weapon's type and must succeed on a DC 15 Strength saving throw or have the Prone condition.","enabled":true,"extensions":{},"folder":"folder:c5aedaa9-1450-4cf3-a103-74d652ba4c33","insertion_order":58,"keys":[""],"mode":"normal","name":"마법 물건: Giant Slayer","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"마법 물건: Glamoured Studded Leather","constant":false,"content":"## Glamoured Studded Leather (환영 스터디드 레더) - magic item, SRD 5.2.1\nArmor (Studded Leather Armor), Rare.\nWhile wearing this armor, you gain a +1 bonus to Armor Class. You can also take a Bonus Action to 224 cause the armor to assume the appearance of a normal set of clothing or some other kind of armor. You decide what it looks like—including color, style, and accessories—but the armor retains its normal bulk and weight. The illusory appearance lasts until you use this property again or doff the armor.","enabled":true,"extensions":{},"folder":"folder:c5aedaa9-1450-4cf3-a103-74d652ba4c33","insertion_order":58,"keys":[""],"mode":"normal","name":"마법 물건: Glamoured Studded Leather","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"마법 물건: Gloves of Missile Snaring","constant":false,"content":"## Gloves of Missile Snaring (투사체 잡는 장갑) - magic item, SRD 5.2.1\nWondrous Item, Uncommon (Requires Attunement).\nIf you're hit by an attack roll made with a Ranged or Thrown weapon while wearing these gloves, you can take a Reaction to reduce the damage by 1d10 plus your Dexterity modifier if you have a free hand. If you reduce the damage to 0, you can catch the ammunition or weapon if it is small enough for you to hold in that hand.","enabled":true,"extensions":{},"folder":"folder:c5aedaa9-1450-4cf3-a103-74d652ba4c33","insertion_order":58,"keys":[""],"mode":"normal","name":"마법 물건: Gloves of Missile Snaring","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"마법 물건: Gloves of Swimming and Climbing","constant":false,"content":"## Gloves of Swimming and Climbing (헤엄·등반 장갑) - magic item, SRD 5.2.1\nWondrous Item, Uncommon (Requires Attunement).\nWhile wearing these gloves, you have a Climb Speed and a Swim Speed equal to your Speed, and you gain a +5 bonus to Strength (Athletics) checks made to climb or swim.","enabled":true,"extensions":{},"folder":"folder:c5aedaa9-1450-4cf3-a103-74d652ba4c33","insertion_order":58,"keys":[""],"mode":"normal","name":"마법 물건: Gloves of Swimming and Climbing","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"마법 물건: Gloves of Thievery","constant":false,"content":"## Gloves of Thievery (도둑의 장갑) - magic item, SRD 5.2.1\nWondrous Item, Uncommon.\nThese gloves are imperceptible while worn. While wearing them, you gain a +5 bonus to Dexterity (Sleight of Hand) checks.","enabled":true,"extensions":{},"folder":"folder:c5aedaa9-1450-4cf3-a103-74d652ba4c33","insertion_order":58,"keys":[""],"mode":"normal","name":"마법 물건: Gloves of Thievery","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"마법 물건: Goggles of Night","constant":false,"content":"## Goggles of Night (밤의 고글) - magic item, SRD 5.2.1\nWondrous Item, Uncommon.\nWhile wearing these dark lenses, you have Darkvision out to 60 feet. If you already have Darkvision, wearing the goggles increases its range by 60 feet.","enabled":true,"extensions":{},"folder":"folder:c5aedaa9-1450-4cf3-a103-74d652ba4c33","insertion_order":58,"keys":[""],"mode":"normal","name":"마법 물건: Goggles of Night","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"마법 물건: Hammer of Thunderbolts","constant":false,"content":"## Hammer of Thunderbolts (벼락 망치) - magic item, SRD 5.2.1\nWeapon (Maul or Warhammer), Legendary (Requires Attunement).\nYou gain a +1 bonus to attack rolls and damage rolls made with this magic weapon. The weapon has 5 charges. You can expend 1 charge and make a ranged attack with the weapon, hurling it as if it had the Thrown property with a normal range of 20 feet and a long range of 60 feet. If the attack hits, the weapon unleashes a thunderclap audible out to 300 feet. The target and every creature within 30 feet of it other than you must succeed on a DC 17 Constitution saving throw or have the Stunned condition until the end of your next turn. Immediately after hitting or missing, the weapon flies back to your hand. The weapon regains 1d4 + 1 expended charges daily at dawn. Giant's Bane. While you are attuned to the weapon and wearing either a Belt of Giant Strength or Gauntlets of Ogre Power to which you are also attuned, you gain the following benefits: Giants' Bane. When you roll a 20 on the d20 for an attack roll made with this weapon against a Giant, the creature must succeed on a DC 17 Constitution saving throw or die. Might of Giants. The Strength score bestowed by your Belt of Giant Strength or Gauntlets of Ogre Power increases by 4, to a maximum of 30.","enabled":true,"extensions":{},"folder":"folder:c5aedaa9-1450-4cf3-a103-74d652ba4c33","insertion_order":58,"keys":[""],"mode":"normal","name":"마법 물건: Hammer of Thunderbolts","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"마법 물건: Handy Haversack","constant":false,"content":"## Handy Haversack (편리한 배낭) - magic item, SRD 5.2.1\nWondrous Item, Rare.\nThis backpack has a central pouch and two side pouches, each of which is an extradimensional space. Each side pouch can hold up to 200 pounds of material, not exceeding a volume of 25 cubic feet. The central pouch can hold up to 500 pounds of material, not exceeding a volume of 64 cubic feet. The haversack always weighs 5 pounds, regardless of its contents. Retrieving an item from the haversack requires a Utilize action or a Bonus Action (your choice). When you reach into the haversack for a specific item, the item is always magically on top. If any of its pouches is overloaded, pierced, or torn, the haversack ruptures and is destroyed. If the haversack is destroyed, its contents are lost forever, although an Artifact always turns up again somewhere. If the haversack is turned inside out, its contents spill forth unharmed, and the haversack must be put right before it can be used again. Each pouch of the haversack holds enough air for 10 minutes of breathing, divided by the number of breathing creatures inside. Placing the haversack inside an extradimensional space created by a Bag of Holding, Portable Hole, or similar item instantly destroys both items and opens a gate to the Astral Plane. The gate originates where the one item was placed inside the other. Any creature within 10 feet of the gate and not behind Total Cover is sucked through it and deposited in a random location on the Astral Plane. The gate then closes. The gate is one-way only and can't be reopened.","enabled":true,"extensions":{},"folder":"folder:c5aedaa9-1450-4cf3-a103-74d652ba4c33","insertion_order":58,"keys":[""],"mode":"normal","name":"마법 물건: Handy Haversack","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"마법 물건: Hat of Disguise","constant":false,"content":"## Hat of Disguise (변장 모자) - magic item, SRD 5.2.1\nWondrous Item, Uncommon (Requires Attunement).\nWhile wearing this hat, you can cast the Disguise Self spell. The spell ends if the hat is removed.","enabled":true,"extensions":{},"folder":"folder:c5aedaa9-1450-4cf3-a103-74d652ba4c33","insertion_order":58,"keys":[""],"mode":"normal","name":"마법 물건: Hat of Disguise","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"마법 물건: Hat of Many Spells","constant":false,"content":"## Hat of Many Spells (여러 주문의 모자) - magic item, SRD 5.2.1\nWondrous Item, Very Rare (Requires Attunement by a Wizard).\nThis pointed hat has the following properties. Spellcasting Focus. While holding the hat, you can use it as a Spellcasting Focus for your Wizard spells. Any spell you cast using the hat gains a special Somatic component: you must reach into the hat and “pull” the spell out of it. 225 Unknown Spell. While holding the hat, you can try to cast a level 1+ spell you don't know. The spell must be on the Wizard spell list, it must be of a level you can cast, and it can't have Material components costing more than 1,000 GP. Once you decide on the spell, you must expend a spell slot of the spell's level. Then, to determine whether you cast the spell, make an Intelligence (Arcana) check (DC 10 plus the spell's level). On a successful check, you cast the spell using its normal casting time, and you can't use this property again until you finish a Short or Long Rest. On a failed check, you fail to cast the spell and a random effect occurs instead, determined by rolling on the following table. Any spell you cast from the hat uses your spell save DC and spell attack bonus. 1d100 Effect 01-50 You cast a random spell determined by rolling 1d10: on a 1, Enlarge/Reduce (enlarge effect); on a 2, Enlarge/Reduce (reduce effect); on a 3, Faerie Fire; on a 4, Fireball; on a 5, Gust of Wind; on a 6, Invisibility (cast on yourself); on a 7, Lightning Bolt; on an 8, Phantasmal Force; on a 9, Polymorph; on a 10, Stinking Cloud. 51-55 You have the Stunned condition until the end of your next turn, believing something awesome just happened. 56-60 A harmless swarm of butterflies fills a 10-foot Cube within 30 feet of yourself. The swarm disperses after 1 minute. 61-65 You pull a nonmagical object out of the hat. Roll 1d4 to determine the object: on a 1, a vial of Acid; on a 2, a flask of Alchemist's Fire; on a 3, a Crowbar; on a 4, a lit Torch. 66-70 You suffer a bout of “magic sickness” and have the Poisoned condition for 1 hour. 71-75 You have the Petrified condition until the end of your next turn. 76-80 You pull a nonmagical object out of the hat. Roll 1d4 to determine the object: on a 1, a Dagger; on a 2, a Rope with a Grappling Hook tied to one end; on a 3, a bag of Caltrops; on a 4, a gem worth 50 GP. 81-85 A creature appears in an unoccupied space as close to you as possible. The creature isn't under your control and acts as it normally would, and it disappears after 1 hour or when it drops to 0 Hit Points. Roll 1d4 to determine the creature: on a 1, a Camel; on a 2, a Constrictor Snake; on a 3, an Elephant; on a 4, a Mule. 1d100 Effect 86-90 A Hostile Swarm of Bats flies out of the hat, occupies your space, and attacks you. 91-95 A vertical, 10-foot-diameter, two-way portal to another plane of existence opens in an unoccupied space within 30 feet of you and remains open until the end of your next turn. The GM determines where it leads. 96-00 You pull a magic item out of the hat. Roll 1d6 to determine the item's rarity: on a 1-3, Common; on a 4-5, Uncommon; on a 6, Rare. The GM chooses the item, which disappears after 1 hour if it's not consumed or destroyed before then.","enabled":true,"extensions":{},"folder":"folder:c5aedaa9-1450-4cf3-a103-74d652ba4c33","insertion_order":58,"keys":[""],"mode":"normal","name":"마법 물건: Hat of Many Spells","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"마법 물건: Headband of Intellect","constant":false,"content":"## Headband of Intellect (지능의 머리띠) - magic item, SRD 5.2.1\nWondrous Item, Uncommon (Requires Attunement).\nYour Intelligence is 19 while you wear this headband. It has no effect on you if your Intelligence is 19 or higher without it.","enabled":true,"extensions":{},"folder":"folder:c5aedaa9-1450-4cf3-a103-74d652ba4c33","insertion_order":58,"keys":[""],"mode":"normal","name":"마법 물건: Headband of Intellect","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"마법 물건: Helm of Brilliance","constant":false,"content":"## Helm of Brilliance (광채의 투구) - magic item, SRD 5.2.1\nWondrous Item, Very Rare (Requires Attunement).\nThis helm is set with 1d10 diamonds, 2d10 rubies, 3d10 fire opals, and 4d10 opals. Any gem pried from the helm crumbles to dust. When all the gems are removed or destroyed, the helm loses its magic. You gain the following benefits while wearing the helm. Diamond Light. As long as it has at least one diamond, the helm emits a 30-foot Emanation. When at least one Undead is within that area, the Emanation is filled with Dim Light. Any Undead that starts its turn in that area takes 1d6 Radiant damage. Fire Opal Flames. As long as the helm has at least one fire opal, you can take a Magic action to cause one weapon you are holding to burst into flames. The flames emit Bright Light in a 10-foot radius and Dim Light for an additional 10 feet. The flames are harmless to you and the weapon. When you hit with an attack using the blazing weapon, the target takes an extra 1d6 Fire damage. The flames last until you take a Bonus Action to extinguish them or until you drop or stow the weapon. Ruby Resistance. As long as the helm has at least one ruby, you have Resistance to Fire damage. Spells. You can cast one of the following spells (save DC 18), using one of the helm's gems of the specified type as a component: Daylight (opal), Fireball (fire opal), Prismatic Spray (diamond), or Wall of Fire (ruby). The gem is destroyed when the spell is cast and disappears from the helm. Taking Fire Damage. Roll 1d20 if you are wearing the helm and take Fire damage as a result of failing 226 a saving throw against a spell. On a roll of 1, the helm emits beams of light from its remaining gems and is then destroyed. Each creature within a 60foot Emanation originating from you must succeed on a DC 17 Dexterity saving throw or be struck by a beam, taking Radiant damage equal to the number of gems in the helm.","enabled":true,"extensions":{},"folder":"folder:c5aedaa9-1450-4cf3-a103-74d652ba4c33","insertion_order":58,"keys":[""],"mode":"normal","name":"마법 물건: Helm of Brilliance","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"마법 물건: Helm of Comprehending Languages","constant":false,"content":"## Helm of Comprehending Languages (언어 이해의 투구) - magic item, SRD 5.2.1\nWondrous Item, Uncommon.\nWhile wearing this helm, you can cast Comprehend Languages from it.","enabled":true,"extensions":{},"folder":"folder:c5aedaa9-1450-4cf3-a103-74d652ba4c33","insertion_order":58,"keys":[""],"mode":"normal","name":"마법 물건: Helm of Comprehending Languages","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"마법 물건: Helm of Telepathy","constant":false,"content":"## Helm of Telepathy (정신감응 투구) - magic item, SRD 5.2.1\nWondrous Item, Uncommon (Requires Attunement).\nWhile wearing this helm, you have telepathy with a range of 30 feet, and you can cast Detect Thoughts or Suggestion (save DC 13) from the helm. Once either spell is cast from the helm, that spell can't be cast from it again until the next dawn.","enabled":true,"extensions":{},"folder":"folder:c5aedaa9-1450-4cf3-a103-74d652ba4c33","insertion_order":58,"keys":[""],"mode":"normal","name":"마법 물건: Helm of Telepathy","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"마법 물건: Helm of Teleportation","constant":false,"content":"## Helm of Teleportation (순간이동 투구) - magic item, SRD 5.2.1\nWondrous Item, Rare (Requires Attunement).\nThis helm has 3 charges. While wearing it, you can expend 1 charge to cast Teleport from it. The helm regains 1d3 expended charges daily at dawn.","enabled":true,"extensions":{},"folder":"folder:c5aedaa9-1450-4cf3-a103-74d652ba4c33","insertion_order":58,"keys":[""],"mode":"normal","name":"마법 물건: Helm of Teleportation","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"마법 물건: Holy Avenger","constant":false,"content":"## Holy Avenger (성스러운 복수자) - magic item, SRD 5.2.1\nWeapon (Any Simple or Martial), Legendary (Requires Attunement by a Paladin).\nYou gain a +3 bonus to attack rolls and damage rolls made with this magic weapon. When you hit a Fiend or an Undead with it, that creature takes an extra 2d10 Radiant damage. While you hold the drawn weapon, it creates a 10-foot Emanation originating from you. You and all creatures Friendly to you in the Emanation have Advantage on saving throws against spells and other magical effects. If you have 17 or more levels in the Paladin class, the size of the Emanation increases to 30 feet.","enabled":true,"extensions":{},"folder":"folder:c5aedaa9-1450-4cf3-a103-74d652ba4c33","insertion_order":58,"keys":[""],"mode":"normal","name":"마법 물건: Holy Avenger","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"마법 물건: Horn of Blasting","constant":false,"content":"## Horn of Blasting (폭음의 뿔피리) - magic item, SRD 5.2.1\nWondrous Item, Rare.\nYou can take a Magic action to blow the horn, which emits a thunderous blast in a 30-foot Cone that is audible out to 600 feet. Each creature in the Cone makes a DC 15 Constitution saving throw. On a failed save, a creature takes 5d8 Thunder damage and has the Deafened condition for 1 minute. On a successful save, a creature takes half as much damage only. Glass or crystal objects in the Cone that aren't being worn or carried take 10d8 Thunder damage. Each use of the horn's magic has a 20 percent chance of causing the horn to explode. The explosion deals 10d6 Force damage to the user and destroys the horn.","enabled":true,"extensions":{},"folder":"folder:c5aedaa9-1450-4cf3-a103-74d652ba4c33","insertion_order":58,"keys":[""],"mode":"normal","name":"마법 물건: Horn of Blasting","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"마법 물건: Horn of Valhalla","constant":false,"content":"## Horn of Valhalla (발할라의 뿔피리) - magic item, SRD 5.2.1\nWondrous Item, Rare (Silver or Brass), Very Rare (Bronze), or Legendary (Iron).\nYou can take a Magic action to blow this horn. In response, warrior spirits from the plane of Ysgard appear in unoccupied spaces within 60 feet of you. Each spirit uses the Berserker stat block and returns to Ysgard after 1 hour or when it drops to 0 Hit Points. The spirits look like living, breathing warriors, and they have Immunity to the Charmed and Frightened conditions. Once you use the horn, it can't be used again until 7 days have passed. Four types of Horn of Valhalla are known to exist, each made of a different metal. The horn's type determines how many spirits it summons, as well as the requirement for its use. The GM chooses the horn's type or determines it randomly by rolling on the following table. If you blow the horn without meeting its requirement, the summoned spirits attack you. If you meet the requirement, they are Friendly to you and your allies and follow your commands. 1d100 Horn Type Spirits Requirement 01-40 Silver 2 None 41-75 Brass 3 Proficiency with all Simple weapons 76-90 Bronze 4 Training with all Medium armor 91-00 Iron 5 Proficiency with all Martial weapons","enabled":true,"extensions":{},"folder":"folder:c5aedaa9-1450-4cf3-a103-74d652ba4c33","insertion_order":58,"keys":[""],"mode":"normal","name":"마법 물건: Horn of Valhalla","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"마법 물건: Horseshoes of a Zephyr","constant":false,"content":"## Horseshoes of a Zephyr (산들바람 편자) - magic item, SRD 5.2.1\nWondrous Item, Very Rare.\nThese horseshoes come in a set of four. As a Magic action, you can touch one of the horseshoes to the hoof of a horse or similar creature, whereupon the horseshoe affixes itself to the hoof. Removing a horseshoe also takes a Magic action. While all four shoes are affixed to the hooves of a horse or similar creature, they allow the creature to move normally while floating 4 inches above a surface. This effect means the creature can cross or stand above nonsolid or unstable surfaces, such as water or lava. The creature leaves no tracks and ignores Difficult Terrain. In addition, the creature can travel for up to 12 hours a day without gaining Exhaustion levels from extended travel. 227","enabled":true,"extensions":{},"folder":"folder:c5aedaa9-1450-4cf3-a103-74d652ba4c33","insertion_order":58,"keys":[""],"mode":"normal","name":"마법 물건: Horseshoes of a Zephyr","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"마법 물건: Horseshoes of Speed","constant":false,"content":"## Horseshoes of Speed (신속의 편자) - magic item, SRD 5.2.1\nWondrous Item, Rare.\nThese horseshoes come in a set of four. As a Magic action, you can touch one of the horseshoes to the hoof of a horse or similar creature, whereupon the horseshoe affixes itself to the hoof. Removing a horseshoe also takes a Magic action. While all four horseshoes are attached to the same creature, its Speed is increased by 30 feet.","enabled":true,"extensions":{},"folder":"folder:c5aedaa9-1450-4cf3-a103-74d652ba4c33","insertion_order":58,"keys":[""],"mode":"normal","name":"마법 물건: Horseshoes of Speed","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"마법 물건: Immovable Rod","constant":false,"content":"## Immovable Rod (움직이지 않는 막대) - magic item, SRD 5.2.1\nRod, Uncommon.\nThis iron rod has a button on one end. You can take a Utilize action to press the button, which causes the rod to become magically fixed in place. Until you or another creature takes a Utilize action to push the button again, the rod doesn't move, even if it defies gravity. The rod can hold up to 8,000 pounds of weight. More weight causes the rod to deactivate and fall. A creature can take a Utilize action to make a DC 30 Strength (Athletics) check, moving the fixed rod up to 10 feet on a successful check.","enabled":true,"extensions":{},"folder":"folder:c5aedaa9-1450-4cf3-a103-74d652ba4c33","insertion_order":58,"keys":[""],"mode":"normal","name":"마법 물건: Immovable Rod","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"마법 물건: Instant Fortress","constant":false,"content":"## Instant Fortress (즉석 요새) - magic item, SRD 5.2.1\nWondrous Item, Rare (Requires Attunement).\nAs a Magic action, you can place this 1-inch adamantine statuette on the ground and, using a command word, cause it to grow rapidly into a square adamantine tower. Repeating the command word causes the tower to revert to statuette form, which works only if the tower is empty. Each creature in the area where the tower appears is pushed to an unoccupied space outside but next to the tower. Objects in the area that aren't being worn or carried are also pushed clear of the tower. The tower is 20 feet on a side and 30 feet high, with arrow slits on all sides and a battlement atop it. Its interior is divided into two floors, with a ladder, staircase, or ramp (your choice) connecting them. This ladder, staircase, or ramp ends at a trapdoor leading to the roof. When created, the tower has a single door at ground level on the side facing you. The door opens only at your command, which you can issue as a Bonus Action. It is immune to the Knock spell and similar magic. Magic prevents the tower from being tipped over. The roof, the door, and the walls each have AC 20; HP 100; Immunity to Bludgeoning, Piercing, and Slashing damage except that which is dealt by siege equipment; and Resistance to all other damage. Shrinking the tower back down to statuette form doesn't repair damage to the tower. Only a Wish spell can repair the tower (this use of the spell counts as replicating a spell of level 8 or lower). Each casting of Wish causes the tower to regain all its Hit Points.","enabled":true,"extensions":{},"folder":"folder:c5aedaa9-1450-4cf3-a103-74d652ba4c33","insertion_order":58,"keys":[""],"mode":"normal","name":"마법 물건: Instant Fortress","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"마법 물건: Ioun Stone","constant":false,"content":"## Ioun Stone (아이운 돌) - magic item, SRD 5.2.1\nWondrous Item, Rarity Varies (Requires Attunement).\nRoughly marble sized, Ioun Stones are named after Ioun, a god of knowledge and prophecy revered on some worlds. Many types of Ioun Stones exist, each type a distinct combination of shape and color. When you take a Magic action to toss an Ioun Stone into the air, the stone orbits your head at a distance of 1d3 feet, conferring its benefit to you while doing so. You can have up to three Ioun Stones orbiting your head at the same time. Each Ioun Stone orbiting your head is considered to be an object you are wearing. The orbiting stone avoids contact with other creatures and objects, adjusting its orbit to avoid collisions and thwarting all attempts by other creatures to attack or snatch it. As a Utilize action, you can seize and stow any number of Ioun Stones orbiting your head. If your Attunement to an Ioun Stone ends while it's orbiting your head, the stone falls as though you had dropped it. The type of stone determines its rarity and effects. Absorption (Very Rare). While this pale lavender ellipsoid orbits your head, you can take a Reaction to cancel a spell of level 4 or lower cast by a creature you can see. A canceled spell has no effect, and any resources used to cast it are wasted. Once the stone has canceled 20 levels of spells, it burns out, turns dull gray, and loses its magic. Agility (Very Rare). Your Dexterity increases by 2, to a maximum of 20, while this deep-red sphere orbits your head. Awareness (Rare). While this dark-blue rhomboid orbits your head, you have Advantage on Initiative rolls and Wisdom (Perception) checks. Fortitude (Very Rare). Your Constitution increases by 2, to a maximum of 20, while this pink rhomboid orbits your head. Greater Absorption (Legendary). While this marbled lavender and green ellipsoid orbits your head, you can take a Reaction to cancel a spell of level 8 or lower cast by a creature you can see. A canceled spell has no effect, and any resources used to cast it are wasted. Once the stone has canceled 20 levels of spells, it burns out, turns dull gray, and loses its magic. Insight (Very Rare). Your Wisdom increases by 2, to a maximum of 20, while this incandescent blue sphere orbits your head. Intellect (Very Rare). Your Intelligence increases by 2, to a maximum of 20, while this marbled scarlet and blue sphere orbits your head. Leadership (Very Rare). Your Charisma increases by 2, to a maximum of 20, while this marbled pink and green sphere orbits your head. 228 Mastery (Legendary). Your Proficiency Bonus increases by 1 while this pale green prism orbits your head. Protection (Rare). You gain a +1 bonus to Armor Class while this dusty-rose prism orbits your head. Regeneration (Legendary). You regain 15 Hit Points at the end of each hour this pearly white spindle orbits your head if you have at least 1 Hit Point. Reserve (Rare). This vibrant purple prism stores spells cast into it, holding them until you use them. The stone can store up to 4 levels of spells at a time. When found, it contains 1d4 levels of stored spells chosen by the GM. Any creature can cast a spell of level 1 through 4 into the stone by touching it as the spell is cast. The spell has no effect, other than to be stored in the stone. If the stone can't hold the spell, the spell is expended without effect. The level of the slot used to cast the spell determines how much space it uses. While this stone orbits your head, you can cast any spell stored in it. The spell uses the slot level, spell save DC, spell attack bonus, and spellcasting ability of the original caster but is otherwise treated as if you cast the spell. The spell cast from the stone is no longer stored in it, freeing up space. Strength (Very Rare). Your Strength increases by 2, to a maximum of 20, while this pale blue rhomboid orbits your head. Sustenance (Rare). You don't need to eat or drink while this clear spindle orbits your head.","enabled":true,"extensions":{},"folder":"folder:c5aedaa9-1450-4cf3-a103-74d652ba4c33","insertion_order":58,"keys":[""],"mode":"normal","name":"마법 물건: Ioun Stone","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"마법 물건: Iron Bands","constant":false,"content":"## Iron Bands (쇠 띠) - magic item, SRD 5.2.1\nWondrous Item, Rare.\nThis rusty iron sphere measures 3 inches in diameter and weighs 1 pound. You can take a Magic action to throw the sphere at a Huge or smaller creature you can see within 60 feet of yourself. As the sphere moves through the air, it opens into a tangle of metal bands. Make a ranged attack roll with an attack bonus equal to your Dexterity modifier plus your Proficiency Bonus. On a hit, the target has the Restrained condition until you take a Bonus Action to issue a command that releases it. Doing so or missing with the attack causes the bands to contract and become a sphere once more. A creature that can touch the bands, including the one Restrained, can take an action to make a DC 20 Strength (Athletics) check to break the iron bands. On a successful check, the item is destroyed, and the Restrained creature is freed. On a failed check, any further attempts made by that creature automatically fail until 24 hours have elapsed. Once the bands are used, they can't be used again until the next dawn.","enabled":true,"extensions":{},"folder":"folder:c5aedaa9-1450-4cf3-a103-74d652ba4c33","insertion_order":58,"keys":[""],"mode":"normal","name":"마법 물건: Iron Bands","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"마법 물건: Iron Flask","constant":false,"content":"## Iron Flask (쇠 플라스크) - magic item, SRD 5.2.1\nWondrous Item, Legendary.\nWhile holding this brass-stoppered iron flask, you can take a Magic action to target a creature that you can see within 60 feet of yourself. If the flask is empty and the target is native to a plane of existence other than the one you're on, the target must succeed on a DC 17 Wisdom saving throw or be trapped in the flask. If the target has been trapped by the flask before, it has Advantage on the save. Once trapped, a creature remains in the flask until released. The flask can hold only one creature at a time. A creature trapped in the flask doesn't age and doesn't need to breathe, eat, or drink. You can take a Magic action to remove the flask's stopper and release the creature in the flask. The creature then obeys your commands for 1 hour, understanding those commands even if it doesn't know the language in which the commands are given. If you issue no commands or give the creature a command that is likely to result in its death or imprisonment, it defends itself but otherwise takes no actions. At the end of the duration, the creature acts in accordance with its normal disposition and alignment. An Identify spell reveals if the flask contains a creature, but the only way to determine the type of creature is to open the flask. A newly discovered Iron Flask might already contain a creature chosen by the GM.","enabled":true,"extensions":{},"folder":"folder:c5aedaa9-1450-4cf3-a103-74d652ba4c33","insertion_order":58,"keys":[""],"mode":"normal","name":"마법 물건: Iron Flask","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"마법 물건: Javelin of Lightning","constant":false,"content":"## Javelin of Lightning (번개 자벨린) - magic item, SRD 5.2.1\nWeapon (Javelin), Uncommon.\nEach time you make an attack roll with this magic weapon and hit, you can have it deal Lightning damage instead of Piercing damage. Lightning Bolt. When you throw this weapon at a target no farther than 120 feet from you, you can forgo making a ranged attack roll and instead turn the weapon into a bolt of lightning. This bolt forms a 5-foot-wide Line between you and the target. The target and each other creature in the Line (excluding you) makes a DC 13 Dexterity saving throw, taking 4d6 Lightning damage on a failed save or half as much damage on a successful one. Immediately after dealing this damage, the weapon reappears in your hand. This property can't be used again until the next dawn.","enabled":true,"extensions":{},"folder":"folder:c5aedaa9-1450-4cf3-a103-74d652ba4c33","insertion_order":58,"keys":[""],"mode":"normal","name":"마법 물건: Javelin of Lightning","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"마법 물건: Lantern of Revealing","constant":false,"content":"## Lantern of Revealing (드러냄의 랜턴) - magic item, SRD 5.2.1\nWondrous Item, Uncommon.\nWhile lit, this hooded lantern burns for 6 hours on 1 pint of oil, shedding Bright Light in a 30-foot radius and Dim Light for an additional 30 feet. Invisible creatures and objects are visible as long as they are in the lantern's Bright Light. You can take a Utilize 229 action to lower the hood, reducing the lantern's light to Dim Light in a 5-foot radius.","enabled":true,"extensions":{},"folder":"folder:c5aedaa9-1450-4cf3-a103-74d652ba4c33","insertion_order":58,"keys":[""],"mode":"normal","name":"마법 물건: Lantern of Revealing","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"마법 물건: Luck Blade","constant":false,"content":"## Luck Blade (행운의 검) - magic item, SRD 5.2.1\nWeapon (Glaive, Greatsword, Longsword, Rapier, Scimitar, Sickle, or Shortsword), Legendary (Requires Attunement).\nYou gain a +1 bonus to attack rolls and damage rolls made with this magic weapon. While the weapon is on your person, you also gain a +1 bonus to saving throws. Luck. If the weapon is on your person, you can call on its luck (no action required) to reroll one failed D20 Test if you don't have the Incapacitated condition. You must use the second roll. Once used, this property can't be used again until the next dawn. Wish. The weapon has 1d3 charges. While holding it, you can expend 1 charge and cast Wish from it. Once used, this property can't be used again until the next dawn. The weapon loses this property if it has no charges.","enabled":true,"extensions":{},"folder":"folder:c5aedaa9-1450-4cf3-a103-74d652ba4c33","insertion_order":58,"keys":[""],"mode":"normal","name":"마법 물건: Luck Blade","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"마법 물건: Mace of Disruption","constant":false,"content":"## Mace of Disruption (붕괴의 메이스) - magic item, SRD 5.2.1\nWeapon (Mace), Rare (Requires Attunement).\nWhen you hit a Fiend or an Undead with this magic weapon, that creature takes an extra 2d6 Radiant damage. If the target has 25 Hit Points or fewer after taking this damage, it must succeed on a DC 15 Wisdom saving throw or be destroyed. On a successful save, the creature has the Frightened condition until the end of your next turn. Light. While you hold this weapon, it sheds Bright Light in a 20-foot radius and Dim Light for an additional 20 feet.","enabled":true,"extensions":{},"folder":"folder:c5aedaa9-1450-4cf3-a103-74d652ba4c33","insertion_order":58,"keys":[""],"mode":"normal","name":"마법 물건: Mace of Disruption","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"마법 물건: Mace of Smiting","constant":false,"content":"## Mace of Smiting (강타의 메이스) - magic item, SRD 5.2.1\nWeapon (Mace), Rare.\nYou gain a +1 bonus to attack rolls and damage rolls made with this magic weapon. The bonus increases to +3 when you use the weapon to attack a Construct. When you roll a 20 on an attack roll made with this weapon, the target takes an extra 7 Bludgeoning damage, or 14 Bludgeoning damage if it's a Construct. If a Construct has 25 Hit Points or fewer after taking this damage, it is destroyed.","enabled":true,"extensions":{},"folder":"folder:c5aedaa9-1450-4cf3-a103-74d652ba4c33","insertion_order":58,"keys":[""],"mode":"normal","name":"마법 물건: Mace of Smiting","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"마법 물건: Mace of Terror","constant":false,"content":"## Mace of Terror (공포의 메이스) - magic item, SRD 5.2.1\nWeapon (Mace), Rare (Requires Attunement).\nThis magic weapon has 3 charges and regains 1d3 expended charges daily at dawn. While holding the weapon, you can take a Magic action and expend 1 charge to release a wave of terror from it. Each creature of your choice within 30 feet of you must succeed on a DC 15 Wisdom saving throw or have the Frightened condition for 1 minute. While Frightened in this way, a creature must spend its turns trying to move as far away from you as it can, and it can't make Opportunity Attacks. For its action, it can use only the Dash action or try to escape from an effect that prevents it from moving. If it has nowhere it can move, the creature can take the Dodge action. At the end of each of its turns, a creature repeats the save, ending the effect on itself on a success.","enabled":true,"extensions":{},"folder":"folder:c5aedaa9-1450-4cf3-a103-74d652ba4c33","insertion_order":58,"keys":[""],"mode":"normal","name":"마법 물건: Mace of Terror","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"마법 물건: Mantle of Spell Resistance","constant":false,"content":"## Mantle of Spell Resistance (주문 저항의 망토) - magic item, SRD 5.2.1\nWondrous Item, Rare (Requires Attunement).\nYou have Advantage on saving throws against spells while you wear this cloak.","enabled":true,"extensions":{},"folder":"folder:c5aedaa9-1450-4cf3-a103-74d652ba4c33","insertion_order":58,"keys":[""],"mode":"normal","name":"마법 물건: Mantle of Spell Resistance","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"마법 물건: Manual of Bodily Health","constant":false,"content":"## Manual of Bodily Health (신체 건강 교본) - magic item, SRD 5.2.1\nWondrous Item, Very Rare.\nThis book contains health and nutrition tips, and its words are charged with magic. If you spend 48 hours over a period of 6 days or fewer studying the book's contents and practicing its guidelines, your Constitution increases by 2, to a maximum of 30. The manual then loses its magic but regains it in a century.","enabled":true,"extensions":{},"folder":"folder:c5aedaa9-1450-4cf3-a103-74d652ba4c33","insertion_order":58,"keys":[""],"mode":"normal","name":"마법 물건: Manual of Bodily Health","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"마법 물건: Manual of Gainful Exercise","constant":false,"content":"## Manual of Gainful Exercise (유익한 운동 교본) - magic item, SRD 5.2.1\nWondrous Item, Very Rare.\nThis book describes fitness exercises, and its words are charged with magic. If you spend 48 hours over a period of 6 days or fewer studying the book's contents and practicing its guidelines, your Strength increases by 2, to a maximum of 30. The manual then loses its magic but regains it in a century.","enabled":true,"extensions":{},"folder":"folder:c5aedaa9-1450-4cf3-a103-74d652ba4c33","insertion_order":58,"keys":[""],"mode":"normal","name":"마법 물건: Manual of Gainful Exercise","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"마법 물건: Manual of Golems","constant":false,"content":"## Manual of Golems (골렘 교본) - magic item, SRD 5.2.1\nWondrous Item, Very Rare.\nThis tome contains information and incantations necessary to make a particular type of golem. The GM chooses the type or determines it randomly by rolling on the accompanying table. To decipher and use the manual, you must be a spellcaster with at least two level 5 spell slots. A creature that can't use a Manual of Golems and attempts to read it takes 6d6 Psychic damage. To create a golem, you must spend the time shown on the table, working without interruption with the manual at hand and resting no more than 8 hours per day. You must also pay the specified cost to purchase supplies. Once you finish creating the golem, the book is consumed in eldritch flames. The golem becomes animate when the ashes of the manual are sprinkled on it. See “Monsters” for the golem's stat block. The golem is under your control, and it understands and obeys your commands. 230 1d20 Golem Time Cost 1-5 Clay Golem 30 days 65,000 GP 6-17 Flesh Golem 60 days 50,000 GP 18 Iron Golem 120 days 100,000 GP 19-20 Stone Golem 90 days 80,000 GP","enabled":true,"extensions":{},"folder":"folder:c5aedaa9-1450-4cf3-a103-74d652ba4c33","insertion_order":58,"keys":[""],"mode":"normal","name":"마법 물건: Manual of Golems","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"마법 물건: Manual of Quickness of Action","constant":false,"content":"## Manual of Quickness of Action (민첩한 동작 교본) - magic item, SRD 5.2.1\nWondrous Item, Very Rare.\nThis book contains coordination and balance exercises, and its words are charged with magic. If you spend 48 hours over a period of 6 days or fewer studying the book's contents and practicing its guidelines, your Dexterity increases by 2, to a maximum of 30. The manual then loses its magic but regains it in a century.","enabled":true,"extensions":{},"folder":"folder:c5aedaa9-1450-4cf3-a103-74d652ba4c33","insertion_order":58,"keys":[""],"mode":"normal","name":"마법 물건: Manual of Quickness of Action","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"마법 물건: Marvelous Pigments","constant":false,"content":"## Marvelous Pigments (경이로운 물감) - magic item, SRD 5.2.1\nWondrous Item, Very Rare.\nThis fine wooden box contains 1d4 pots of pigment and a brush (weighing 1 pound in total). Using the brush and expending 1 pot of pigment, you can paint any number of three-dimensional objects and terrain features (such as walls, doors, trees, flowers, weapons, webs, and pits), provided these elements are all confined to a 20-foot Cube. The effort takes 10 minutes (regardless of the number of elements you create), during which time you must remain in the Cube, and requires Concentration. If your Concentration is broken or you leave the Cube before the work is done, all the painted elements vanish, and the pot of pigment is wasted. When the work is done, all the painted objects and terrain features become real. Thus, painting a door on a wall creates an actual door, which can be opened to whatever is beyond. Painting a pit creates a real pit, the entire depth of which must lie within the 20-foot Cube. No object created by a pot of pigment can have a value greater than 25 GP, and the total value of all objects created by a pot of pigment can't exceed 500 GP. If you paint objects of greater value (such as a large pile of gold), they look authentic, but close inspection reveals they're made from paste, cookies, or some other worthless material. If you paint a form of energy such as fire or lightning, the energy dissipates as soon as you complete the painting, doing no harm.","enabled":true,"extensions":{},"folder":"folder:c5aedaa9-1450-4cf3-a103-74d652ba4c33","insertion_order":58,"keys":[""],"mode":"normal","name":"마법 물건: Marvelous Pigments","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"마법 물건: Medallion of Thoughts","constant":false,"content":"## Medallion of Thoughts (생각의 메달) - magic item, SRD 5.2.1\nWondrous Item, Uncommon (Requires Attunement).\nThe medallion has 5 charges. While wearing it, you can expend 1 charge to cast Detect Thoughts (save DC 13) from it. The medallion regains 1d4 expended charges daily at dawn.","enabled":true,"extensions":{},"folder":"folder:c5aedaa9-1450-4cf3-a103-74d652ba4c33","insertion_order":58,"keys":[""],"mode":"normal","name":"마법 물건: Medallion of Thoughts","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"마법 물건: Mirror of Life Trapping","constant":false,"content":"## Mirror of Life Trapping (생명 가두는 거울) - magic item, SRD 5.2.1\nWondrous Item, Very Rare.\nWhen this 4-foot-tall, 2-foot-wide mirror is viewed indirectly, its surface shows faint images of creatures. The mirror weighs 50 pounds, and it has AC 11, HP 10, Immunity to Poison and Psychic damage, and Vulnerability to Bludgeoning damage. It shatters and is destroyed when reduced to 0 Hit Points. If the mirror is hanging on a vertical surface and you are within 5 feet of it, you can take a Magic action and use a command word to activate it. It remains activated until you take a Magic action and repeat the command word to deactivate it. Any creature other than you that sees its reflection in the activated mirror while within 30 feet of the mirror must succeed on a DC 15 Charisma saving throw or be trapped, along with anything it is wearing or carrying, in one of the mirror's twelve extradimensional cells. A creature that knows the mirror's nature makes the save with Advantage, and Constructs succeed on the save automatically. An extradimensional cell is an infinite expanse filled with thick fog that reduces visibility to 10 feet. Creatures trapped in the mirror's cells don't age, and they don't need to eat, drink, or sleep. A creature trapped within a cell can escape using magic that permits planar travel. Otherwise, the creature is confined to the cell until freed. If the mirror traps a creature but its twelve extradimensional cells are already occupied, the mirror frees one trapped creature at random to accommodate the new prisoner. A freed creature appears in an unoccupied space within sight of the mirror but facing away from it. If the mirror is shattered, all creatures it contains are freed and appear in unoccupied spaces near it. While within 5 feet of the mirror, you can take a Magic action to name one creature trapped in it or call out a particular cell by number. The creature named or contained in the named cell appears as an image on the mirror's surface. You and the creature can then communicate. In a similar way, you can take a Magic action and use a second command word to free one creature trapped in the mirror. The freed creature appears, along with its possessions, in the unoccupied space nearest to the mirror and facing away from it. Placing the mirror inside an extradimensional space created by a Bag of Holding, Portable Hole, or similar item instantly destroys both items and opens a gate to the Astral Plane. The gate originates where the one item was placed inside the other. Any creature within 10 feet of the gate and not behind Total Cover is sucked through it to a random location on the Astral Plane. The gate then closes. The gate is one-way only and can't be reopened. 231","enabled":true,"extensions":{},"folder":"folder:c5aedaa9-1450-4cf3-a103-74d652ba4c33","insertion_order":58,"keys":[""],"mode":"normal","name":"마법 물건: Mirror of Life Trapping","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"마법 물건: Mithral Armor","constant":false,"content":"## Mithral Armor (미스릴 갑옷) - magic item, SRD 5.2.1\nArmor (Any Medium or Heavy, Except Hide Armor), Uncommon.\nMithral is a light, flexible metal. Armor made of this substance can be worn under normal clothes. If the armor normally imposes Disadvantage on Dexterity (Stealth) checks or has a Strength requirement, the mithral version of the armor doesn't.","enabled":true,"extensions":{},"folder":"folder:c5aedaa9-1450-4cf3-a103-74d652ba4c33","insertion_order":58,"keys":[""],"mode":"normal","name":"마법 물건: Mithral Armor","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"마법 물건: Mysterious Deck","constant":false,"content":"## Mysterious Deck (수수께끼의 카드) - magic item, SRD 5.2.1\nWondrous Item, Legendary.\nUsually found in a box or pouch, this deck contains a number of cards made of ivory or vellum. Most (75 percent) of these decks have thirteen cards, but some have twenty-two. Use the appropriate column of the Mysterious Deck table when randomly determining cards drawn from the deck. Before you draw a card, you must declare how many cards you intend to draw and then draw them randomly. Any cards drawn in excess of this number have no effect. Otherwise, as soon as you draw a card from the deck, its magic takes effect. You must draw each card no more than 1 hour after the previous draw. If you fail to draw the chosen number, the remaining number of cards fly from the deck on their own and take effect all at once. Once a card is drawn, it disappears. Unless the card is the Fool or Jester, the card reappears in the deck, making it possible to draw the same card twice. (Once the Fool or Jester has left the deck, reroll on the table if that card comes up again.) Mysterious Deck 1d100 (13-Card Deck) 1d100 (22-Card Deck) Card — 01-05 Balance — 06-10 Comet — 11-14 Donjon 01-08 15-18 Euryale — 19-23 Fates 09-16 24-27 Flames — 28-31 Fool — 32-36 Gem 17-24 37-41 Jester 25-32 42-46 Key 33-40 47-51 Knight 41-48 52-56 Moon — 57-60 Puzzle 49-56 61-64 Rogue 57-64 65-68 Ruin — 69-73 Sage 1d100 (13-Card Deck) 1d100 (22-Card Deck) Card 65-72 74-77 Skull 73-80 78-82 Star 81-88 83-87 Sun — 88-91 Talons 89-96 92-96 Throne 97-00 97-00 Void Each card's effect is described below. Balance. You can increase one of your ability scores by 2, to a maximum of 22, provided you also decrease another one of your ability scores by 2. You can't decrease an ability that has a score of 5 or lower. Alternatively, you can choose not to adjust your ability scores, in which case this card has no effect. Comet. The next time you enter combat against one or more Hostile creatures, you can select one of them as your foe when you roll Initiative. If you reduce your foe to 0 Hit Points during that combat, you have Advantage on Death Saving Throws for 1 year. If someone else reduces your chosen foe to 0 Hit Points or you don't choose a foe, this card has no effect. Donjon. You disappear and become entombed in a state of suspended animation in an extradimensional sphere. Everything you're wearing and carrying disappears with you except for Artifacts, which stay behind in the space you occupied when you disappeared. You remain imprisoned until you are found and removed from the sphere. You can't be located by any Divination magic, but a Wish spell can reveal the location of your prison. You draw no more cards. Euryale. The card's medusa-like visage curses you. You take a -2 penalty to saving throws while cursed in this way. Only a god or the magic of the Fates card can end this curse. Fates. Reality's fabric unravels and spins anew, allowing you to avoid or erase one event as if it never happened. You can use the card's magic as soon as you draw the card or at any other time before you die. Flames. A powerful devil becomes your enemy. The devil seeks your ruin and torments you, savoring your suffering before attempting to slay you. This enmity lasts until either you or the devil dies. Fool. You have Disadvantage on D20 Tests for the next 72 hours. Draw another card; this draw doesn't count as one of your declared draws. Gem. Twenty-five pieces of jewelry worth 2,000 GP each or fifty gems worth 1,000 GP each appear at your feet. 232 Jester. You have Advantage on D20 Tests for the next 72 hours, or you can draw two additional cards beyond your declared draws. Key. A Rare or rarer magic weapon with which you are proficient appears on your person. The GM chooses the weapon. Knight. You gain the service of a Knight, who magically appears in an unoccupied space you choose within 30 feet of yourself. The knight has the same alignment as you and serves you loyally until death, believing the two of you have been drawn together by fate. Work with your GM to create a name and backstory for this NPC. The GM can use a different stat block to represent the knight, as desired. Moon. You gain the ability to cast Wish 1d3 times. Puzzle. Permanently reduce your Intelligence or Wisdom by 1d4 + 1 (to a minimum score of 1). You can draw one additional card beyond your declared draws. Rogue. An NPC of the GM's choice becomes Hostile toward you. You don't know the identity of this NPC until they or someone else reveals it. Nothing less than a Wish spell or divine intervention can end the NPC's hostility toward you. Ruin. All forms of wealth that you carry or own, other than magic items, are lost to you. Portable property vanishes. Businesses, buildings, and land you own are lost in a way that alters reality the least. Any documentation that proves you should own something lost to this card also disappears. Sage. At any time you choose within one year of drawing this card, you can ask a question in meditation and mentally receive a truthful answer to that question. Skull. An Avatar of Death (see the accompanying stat block) appears in an unoccupied space as close to you as possible. The avatar targets only you with its attacks, appearing as a ghostly skeleton clad in a tattered black robe and carrying a spectral scythe. The avatar disappears when it drops to 0 Hit Points or you die. If an ally of yours deals damage to the avatar, that ally summons another Avatar of Death. The new avatar appears in an unoccupied space as close to that ally as possible and targets only that ally with its attacks. You and your allies can each summon only one avatar as a consequence of this draw. A creature slain by an avatar can't be restored to life. Star. Increase one of your ability scores by 2, to a maximum of 24. Sun. A magic item (chosen by the GM) appears on your person. In addition, you gain 10 Temporary Hit Points daily at dawn until you die. Talons. Every magic item you wear or carry disintegrates. Artifacts in your possession vanish instead. Throne. You gain proficiency and Expertise in your choice of History, Insight, Intimidation, or Persuasion. In addition, you gain rightful ownership of a small keep somewhere in the world. However, the keep is currently home to one or more monsters, which must be cleared out before you can claim the keep as yours. Void. Your soul is drawn from your body and contained in an object in a place of the GM's choice. One or more powerful beings guard the place. While your soul is trapped in this way, your body is inert, ceases aging, and requires no food, air, or water. A Wish spell can't return your soul to your body, but the spell reveals the location of the object that holds your soul. You draw no more cards. Avatar of Death Medium Undead, Neutral evil AC 20 Initiative +3 (13) HP Half the HP maximum of its summoner Speed 60 ft., Fly 60 ft. (hover) MOD SAVE MOD SAVE MOD SAVE Str 16 +3 +3 Dex 16 +3 +3 Con 16 +3 +3 Int 16 +3 +3 Wis 16 +3 +3 Cha 16 +3 +3 Immunities Necrotic, Poison; Charmed, Exhaustion, Frightened, Paralyzed, Petrified, Poisoned, Unconscious Senses Truesight 60 ft., Passive Perception 13 Languages All languages known to its summoner CR None (XP 0; PB equals its summoner's) Traits Incorporeal Movement. The avatar can move through other creatures and objects as if they were Difficult Terrain. It takes 5 (1d10) Force damage if it ends its turn inside an object. Actions Multiattack. The avatar makes a number of Reaping Scythe attacks equal to half the summoner's Proficiency Bonus (rounded up). Reaping Scythe. Melee Attack Roll: Automatic hit, reach 5 ft. Hit: 7 (1d8 + 3) Slashing damage plus 4 (1d8) Necrotic damage.","enabled":true,"extensions":{},"folder":"folder:c5aedaa9-1450-4cf3-a103-74d652ba4c33","insertion_order":58,"keys":[""],"mode":"normal","name":"마법 물건: Mysterious Deck","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"마법 물건: Necklace of Adaptation","constant":false,"content":"## Necklace of Adaptation (적응의 목걸이) - magic item, SRD 5.2.1\nWondrous Item, Uncommon (Requires Attunement).\nWhile wearing this necklace, you can breathe normally in any environment, and you have Advantage on saving throws made to avoid or end the Poisoned condition. 233","enabled":true,"extensions":{},"folder":"folder:c5aedaa9-1450-4cf3-a103-74d652ba4c33","insertion_order":58,"keys":[""],"mode":"normal","name":"마법 물건: Necklace of Adaptation","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"마법 물건: Necklace of Fireballs","constant":false,"content":"## Necklace of Fireballs (화염구 목걸이) - magic item, SRD 5.2.1\nWondrous Item, Rare.\nThis necklace has 1d6 + 3 beads hanging from it. You can take a Magic action to detach a bead and throw it up to 60 feet away. When it reaches the end of its trajectory, the bead detonates as a level 3 Fireball (save DC 15). You can hurl multiple beads, or even the whole necklace, at one time. When you do so, increase the damage of the Fireball by 1d6 for each bead after the first (maximum 12d6).","enabled":true,"extensions":{},"folder":"folder:c5aedaa9-1450-4cf3-a103-74d652ba4c33","insertion_order":58,"keys":[""],"mode":"normal","name":"마법 물건: Necklace of Fireballs","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"마법 물건: Necklace of Prayer Beads","constant":false,"content":"## Necklace of Prayer Beads (기도 염주 목걸이) - magic item, SRD 5.2.1\nWondrous Item, Rare (Requires Attunement by a Cleric, Druid, or Paladin).\nThis necklace has 1d4 + 2 magic beads made from aquamarine, black pearl, or topaz. It also has many nonmagical beads made from stones such as amber, bloodstone, citrine, coral, jade, pearl, or quartz. If a magic bead is removed from the necklace, that bead loses its magic. Six types of magic beads exist. The GM decides the type of each bead on the necklace or determines it randomly by rolling on the table below. A necklace can have more than one bead of the same type. To use one, you must be wearing the necklace. Each bead contains a spell that you can cast from it as a Bonus Action (using your spell save DC if a save is necessary). Once a magic bead's spell is cast, that bead can't be used again until the next dawn. 1d20 Bead Spell 1-6 Bead of Blessing Bless 7-12 Bead of Curing Cure Wounds (level 2 version) 13-16 Bead of Favor Greater Restoration 17-18 Bead of Smiting Shining Smite 19 Bead of Summons Guardian of Faith 20 Bead of Wind Walking Wind Walk","enabled":true,"extensions":{},"folder":"folder:c5aedaa9-1450-4cf3-a103-74d652ba4c33","insertion_order":58,"keys":[""],"mode":"normal","name":"마법 물건: Necklace of Prayer Beads","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"마법 물건: Nine Lives Stealer","constant":false,"content":"## Nine Lives Stealer (아홉 목숨 도둑) - magic item, SRD 5.2.1\nWeapon (Any Simple or Martial), Very Rare (Requires Attunement).\nYou gain a +2 bonus to attack rolls and damage rolls made with this magic weapon. Life Stealing. The weapon has 1d8 + 1 charges. When you attack a creature that has fewer than 100 Hit Points with this weapon and roll a 20 on the d20 for the attack roll, the creature must succeed on a DC 15 Constitution saving throw or be slain instantly as the sword tears its life force from its body. Constructs and Undead succeed on the save automatically. The weapon loses 1 charge if the creature is slain. When the weapon has no charges remaining, it loses this property.","enabled":true,"extensions":{},"folder":"folder:c5aedaa9-1450-4cf3-a103-74d652ba4c33","insertion_order":58,"keys":[""],"mode":"normal","name":"마법 물건: Nine Lives Stealer","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"마법 물건: Oathbow","constant":false,"content":"## Oathbow (맹세의 활) - magic item, SRD 5.2.1\nWeapon (Longbow or Shortbow), Very Rare (Requires Attunement).\nWhen you nock an arrow on this bow, it whispers in Elvish, “Swift defeat to my enemies.” When you use this weapon to make a ranged attack, you can utter or sign the following command words: “Swift death to you who have wronged me.” The target of your attack becomes your sworn enemy until it dies or until dawn 7 days later. You can have only one such sworn enemy at a time. When your sworn enemy dies, you can choose a new one after the next dawn. When you make a ranged attack roll with this weapon against your sworn enemy, you have Advantage on the roll. In addition, your target gains no benefit from Half Cover or Three-Quarters Cover, and you suffer no Disadvantage due to long range. If the attack hits, your sworn enemy takes an extra 3d6 Piercing damage. While your sworn enemy lives, you have Disadvantage on attack rolls with all other weapons.","enabled":true,"extensions":{},"folder":"folder:c5aedaa9-1450-4cf3-a103-74d652ba4c33","insertion_order":58,"keys":[""],"mode":"normal","name":"마법 물건: Oathbow","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"마법 물건: Oil of Etherealness","constant":false,"content":"## Oil of Etherealness (에테르화 기름) - magic item, SRD 5.2.1\nPotion, Rare.\nOne vial of this oil can cover one Medium or smaller creature, along with the equipment it's wearing and carrying (one additional vial is required for each size category above Medium). Applying the oil takes 10 minutes. The affected creature then gains the effect of the Etherealness spell for 1 hour. Beads of this cloudy, gray oil form on the outside of its container and quickly evaporate.","enabled":true,"extensions":{},"folder":"folder:c5aedaa9-1450-4cf3-a103-74d652ba4c33","insertion_order":58,"keys":[""],"mode":"normal","name":"마법 물건: Oil of Etherealness","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"마법 물건: Oil of Sharpness","constant":false,"content":"## Oil of Sharpness (예리함의 기름) - magic item, SRD 5.2.1\nPotion, Very Rare.\nOne vial of this oil can coat one Melee weapon or twenty pieces of ammunition, but only ammunition and Melee weapons that are nonmagical and deal Slashing or Piercing damage are affected. Applying the oil takes 1 minute, after which the oil magically seeps into whatever it coats, turning the coated weapon into a +3 Weapon or the coated ammunition into +3 Ammunition. This clear, gelatinous oil sparkles with tiny, ultrathin silver shards.","enabled":true,"extensions":{},"folder":"folder:c5aedaa9-1450-4cf3-a103-74d652ba4c33","insertion_order":58,"keys":[""],"mode":"normal","name":"마법 물건: Oil of Sharpness","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"마법 물건: Oil of Slipperiness","constant":false,"content":"## Oil of Slipperiness (미끄러움의 기름) - magic item, SRD 5.2.1\nPotion, Uncommon.\nOne vial of this oil can cover one Medium or smaller creature, along with the equipment it's wearing and carrying (one additional vial is required for each size category above Medium). Applying the oil takes 10 minutes. The affected creature then gains the effect of the Freedom of Movement spell for 8 hours. Alternatively, the oil can be poured on the ground as a Magic action, where it covers a 10-foot square, 234 duplicating the effect of the Grease spell in that area for 8 hours. This sticky, black unguent is thick and heavy, but it flows quickly when poured.","enabled":true,"extensions":{},"folder":"folder:c5aedaa9-1450-4cf3-a103-74d652ba4c33","insertion_order":58,"keys":[""],"mode":"normal","name":"마법 물건: Oil of Slipperiness","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"마법 물건: Pearl of Power","constant":false,"content":"## Pearl of Power (힘의 진주) - magic item, SRD 5.2.1\nWondrous Item, Uncommon (Requires Attunement by a Spellcaster).\nWhile this pearl is on your person, you can take a Magic action to regain one expended spell slot of level 3 or lower. Once you use the pearl, it can't be used again until the next dawn.","enabled":true,"extensions":{},"folder":"folder:c5aedaa9-1450-4cf3-a103-74d652ba4c33","insertion_order":58,"keys":[""],"mode":"normal","name":"마법 물건: Pearl of Power","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"마법 물건: Periapt of Health","constant":false,"content":"## Periapt of Health (건강의 펜던트) - magic item, SRD 5.2.1\nWondrous Item, Uncommon (Requires Attunement).\nWhile wearing this pendant, you can take a Magic action to regain 2d4 + 2 Hit Points. Once used, this property can't be used again until the next dawn. In addition, you have Advantage on saving throws to avoid or end the Poisoned condition while you wear this pendant.","enabled":true,"extensions":{},"folder":"folder:c5aedaa9-1450-4cf3-a103-74d652ba4c33","insertion_order":58,"keys":[""],"mode":"normal","name":"마법 물건: Periapt of Health","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"마법 물건: Periapt of Proof against Poison","constant":false,"content":"## Periapt of Proof against Poison (독 방지 펜던트) - magic item, SRD 5.2.1\nWondrous Item, Rare (Requires Attunement).\nThis delicate silver chain has a brilliant-cut black gem pendant. While you wear it, you have Immunity to the Poisoned condition and Poison damage.","enabled":true,"extensions":{},"folder":"folder:c5aedaa9-1450-4cf3-a103-74d652ba4c33","insertion_order":58,"keys":[""],"mode":"normal","name":"마법 물건: Periapt of Proof against Poison","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"마법 물건: Periapt of Wound Closure","constant":false,"content":"## Periapt of Wound Closure (상처 봉합 펜던트) - magic item, SRD 5.2.1\nWondrous Item, Uncommon (Requires Attunement).\nWhile wearing this pendant, you gain the following benefits. Life Preservation. Whenever you make a Death Saving Throw, you can change a roll of 9 or lower to a 10, turning a failed save into a successful one. Natural Healing Boost. Whenever you roll a Hit Point Die to regain Hit Points, double the number of Hit Points it restores.","enabled":true,"extensions":{},"folder":"folder:c5aedaa9-1450-4cf3-a103-74d652ba4c33","insertion_order":58,"keys":[""],"mode":"normal","name":"마법 물건: Periapt of Wound Closure","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"마법 물건: Philter of Love","constant":false,"content":"## Philter of Love (사랑의 묘약) - magic item, SRD 5.2.1\nPotion, Uncommon.\nThe next time you see a creature within 10 minutes after drinking this philter, you are charmed by that creature and have the Charmed condition for 1 hour. This rose-hued, effervescent liquid contains one easy-to-miss bubble shaped like a heart.","enabled":true,"extensions":{},"folder":"folder:c5aedaa9-1450-4cf3-a103-74d652ba4c33","insertion_order":58,"keys":[""],"mode":"normal","name":"마법 물건: Philter of Love","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"마법 물건: Pipes of Haunting","constant":false,"content":"## Pipes of Haunting (유령 피리) - magic item, SRD 5.2.1\nWondrous Item, Uncommon.\nThese pipes have 3 charges and regain 1d3 expended charges daily at dawn. You can take a Magic action to play them and expend 1 charge to create an eerie, spellbinding tune. Each creature of your choice within 30 feet of you must succeed on a DC 15 Wisdom saving throw or have the Frightened condition for 1 minute. A creature that fails the save repeats it at the end of each of its turns, ending the effect on itself on a success. A creature that succeeds on its save is immune to the effect of these pipes for 24 hours.","enabled":true,"extensions":{},"folder":"folder:c5aedaa9-1450-4cf3-a103-74d652ba4c33","insertion_order":58,"keys":[""],"mode":"normal","name":"마법 물건: Pipes of Haunting","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"마법 물건: Pipes of the Sewers","constant":false,"content":"## Pipes of the Sewers (하수도 피리) - magic item, SRD 5.2.1\nWondrous Item, Uncommon (Requires Attunement).\nWhile these pipes are on your person, ordinary rats and giant rats are Indifferent toward you and won't attack you unless you threaten or harm them. The pipes have 3 charges and regain 1d3 expended charges daily at dawn. If you play the pipes as a Magic action, you can take a Bonus Action to expend 1 to 3 charges, calling forth one Swarm of Rats with each expended charge if enough rats are within half a mile of you to be called in this fashion (as determined by the GM). If there aren't enough rats to form a swarm, the charge is wasted. Called swarms move toward the music by the shortest available route but aren't under your control otherwise. Whenever a Swarm of Rats that isn't under another creature's control comes within 30 feet of you while you are playing the pipes, the swarm makes a DC 15 Wisdom saving throw. On a successful save, the swarm behaves as it normally would and can't be swayed by the pipes' music for the next 24 hours. On a failed save, the swarm is swayed by the pipes' music and becomes Friendly to you and your allies for as long as you continue to play the pipes each round as a Magic action. A Friendly swarm obeys your commands. If you issue no commands to a Friendly swarm, it defends itself but otherwise takes no actions. If a Friendly swarm starts its turn more than 30 feet away from you, your control over that swarm ends, and the swarm behaves as it normally would and can't be swayed by the pipes' music for the next 24 hours.","enabled":true,"extensions":{},"folder":"folder:c5aedaa9-1450-4cf3-a103-74d652ba4c33","insertion_order":58,"keys":[""],"mode":"normal","name":"마법 물건: Pipes of the Sewers","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"마법 물건: Plate Armor of Etherealness","constant":false,"content":"## Plate Armor of Etherealness (에테르화 판금 갑옷) - magic item, SRD 5.2.1\nArmor (Half Plate Armor or Plate Armor), Legendary (Requires Attunement).\nWhile you're wearing this armor, you can take a Magic action and use a command word to gain the effect of the Etherealness spell. The spell ends immediately if you remove the armor or take a Magic action to repeat the command word. This property of the armor can't be used again until the next dawn.","enabled":true,"extensions":{},"folder":"folder:c5aedaa9-1450-4cf3-a103-74d652ba4c33","insertion_order":58,"keys":[""],"mode":"normal","name":"마법 물건: Plate Armor of Etherealness","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"마법 물건: Portable Hole","constant":false,"content":"## Portable Hole (휴대용 구멍) - magic item, SRD 5.2.1\nWondrous Item, Rare.\nThis fine black cloth, soft as silk, is folded up to the dimensions of a handkerchief. It unfolds into a circular sheet 6 feet in diameter. You can take a Magic action to unfold a Portable Hole and place it on or against a solid surface, whereupon the Portable Hole creates an 235 extradimensional hole 10 feet deep. The cylindrical space within the hole exists on a different plane of existence, so it can't be used to create open passages. Any creature inside an open Portable Hole can exit the hole by climbing out of it. You can take a Magic action to close a Portable Hole by taking hold of the edges of the cloth and folding it up. Folding the cloth closes the hole, and any creatures or objects within remain in the extradimensional space. No matter what's in it, the hole weighs next to nothing. If the hole is folded up, a creature within the hole's extradimensional space can take an action to make a DC 10 Strength (Athletics) check. On a successful check, the creature forces its way out and appears within 5 feet of the Portable Hole. A closed Portable Hole holds enough air for 1 hour of breathing, divided by the number of breathing creatures inside. Placing a Portable Hole inside an extradimensional space created by a Bag of Holding, Handy Haversack, or similar item instantly destroys both items and opens a gate to the Astral Plane. The gate originates where the one item was placed inside the other. Any creature within 10 feet of the gate and not behind Total Cover is sucked through it and deposited in a random location on the Astral Plane. The gate then closes. The gate is one-way only and can't be reopened.","enabled":true,"extensions":{},"folder":"folder:c5aedaa9-1450-4cf3-a103-74d652ba4c33","insertion_order":58,"keys":[""],"mode":"normal","name":"마법 물건: Portable Hole","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"마법 물건: Potion of Animal Friendship","constant":false,"content":"## Potion of Animal Friendship (동물 친화 물약) - magic item, SRD 5.2.1\nPotion, Uncommon.\nWhen you drink this potion, you can cast the level 3 version of the Animal Friendship spell (save DC 13). Agitating this potion's muddy liquid brings little bits into view: a fish scale, a hummingbird feather, a cat claw, or a squirrel hair.","enabled":true,"extensions":{},"folder":"folder:c5aedaa9-1450-4cf3-a103-74d652ba4c33","insertion_order":58,"keys":[""],"mode":"normal","name":"마법 물건: Potion of Animal Friendship","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"마법 물건: Potion of Clairvoyance","constant":false,"content":"## Potion of Clairvoyance (투시 물약) - magic item, SRD 5.2.1\nPotion, Rare.\nWhen you drink this potion, you gain the effect of the Clairvoyance spell (no Concentration required). An eyeball bobs in this potion's yellowish liquid but vanishes when the potion is opened.","enabled":true,"extensions":{},"folder":"folder:c5aedaa9-1450-4cf3-a103-74d652ba4c33","insertion_order":58,"keys":[""],"mode":"normal","name":"마법 물건: Potion of Clairvoyance","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"마법 물건: Potion of Climbing","constant":false,"content":"## Potion of Climbing (등반 물약) - magic item, SRD 5.2.1\nPotion, Common.\nWhen you drink this potion, you gain a Climb Speed equal to your Speed for 1 hour. During this time, you have Advantage on Strength (Athletics) checks to climb. This potion is separated into brown, silver, and gray layers resembling bands of stone. Shaking the bottle fails to mix the colors.","enabled":true,"extensions":{},"folder":"folder:c5aedaa9-1450-4cf3-a103-74d652ba4c33","insertion_order":58,"keys":[""],"mode":"normal","name":"마법 물건: Potion of Climbing","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"마법 물건: Potion of Diminution","constant":false,"content":"## Potion of Diminution (축소 물약) - magic item, SRD 5.2.1\nPotion, Rare.\nWhen you drink this potion, you gain the “reduce” effect of the Enlarge/Reduce spell for 1d4 hours (no Concentration required). The red in the potion's liquid continuously contracts to a tiny bead and then expands to color the clear liquid around it. Shaking the bottle fails to interrupt this process.","enabled":true,"extensions":{},"folder":"folder:c5aedaa9-1450-4cf3-a103-74d652ba4c33","insertion_order":58,"keys":[""],"mode":"normal","name":"마법 물건: Potion of Diminution","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"마법 물건: Potion of Flying","constant":false,"content":"## Potion of Flying (비행 물약) - magic item, SRD 5.2.1\nPotion, Very Rare.\nWhen you drink this potion, you gain a Fly Speed equal to your Speed for 1 hour and can hover. If you're in the air when the potion wears off, you fall unless you have some other means of staying aloft. This potion's clear liquid floats at the top of its container and has cloudy white impurities drifting in it.","enabled":true,"extensions":{},"folder":"folder:c5aedaa9-1450-4cf3-a103-74d652ba4c33","insertion_order":58,"keys":[""],"mode":"normal","name":"마법 물건: Potion of Flying","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"마법 물건: Potion of Gaseous Form","constant":false,"content":"## Potion of Gaseous Form (기체 형태 물약) - magic item, SRD 5.2.1\nPotion, Rare.\nWhen you drink this potion, you gain the effect of the Gaseous Form spell for 1 hour (no Concentration required) or until you end the effect as a Bonus Action. This potion's container seems to hold fog that moves and pours like water.","enabled":true,"extensions":{},"folder":"folder:c5aedaa9-1450-4cf3-a103-74d652ba4c33","insertion_order":58,"keys":[""],"mode":"normal","name":"마법 물건: Potion of Gaseous Form","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"마법 물건: Potion of Giant Strength","constant":false,"content":"## Potion of Giant Strength (거인의 힘 물약) - magic item, SRD 5.2.1\nPotion, Rarity Varies.\nWhen you drink this potion, your Strength score changes for 1 hour. The type of giant determines the score (see the table below). The potion has no effect on you if your Strength is equal to or greater than that score. This potion's transparent liquid has floating in it a sliver of light resembling a giant's fingernail. Potion Str. Rarity Potion of Giant Strength (hill) 21 Uncommon Potion of Giant Strength (frost or stone) 23 Rare Potion of Giant Strength (fire) 25 Rare Potion of Giant Strength (cloud) 27 Very Rare Potion of Giant Strength (storm) 29 Legendary","enabled":true,"extensions":{},"folder":"folder:c5aedaa9-1450-4cf3-a103-74d652ba4c33","insertion_order":58,"keys":[""],"mode":"normal","name":"마법 물건: Potion of Giant Strength","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"마법 물건: Potion of Growth","constant":false,"content":"## Potion of Growth (성장 물약) - magic item, SRD 5.2.1\nPotion, Uncommon.\nWhen you drink this potion, you gain the “enlarge” effect of the Enlarge/Reduce spell for 10 minutes (no Concentration required). The red in the potion's liquid continuously expands from a tiny bead to color the clear liquid around it and then contracts. Shaking the bottle fails to interrupt this process. 236","enabled":true,"extensions":{},"folder":"folder:c5aedaa9-1450-4cf3-a103-74d652ba4c33","insertion_order":58,"keys":[""],"mode":"normal","name":"마법 물건: Potion of Growth","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"마법 물건: Potions of Healing","constant":false,"content":"## Potions of Healing (치유의 물약) - magic item, SRD 5.2.1\nPotion, Rarity Varies.\nYou regain Hit Points when you drink this potion. The number of Hit Points depends on the potion's rarity, as shown in the table below. Whatever its potency, the potion's red liquid glimmers when agitated. Potion HP Regained Rarity Potion of Healing 2d4 + 2 Common Potion of Healing (greater) 4d4 + 4 Uncommon Potion of Healing (superior) 8d4 + 8 Rare Potion of Healing (supreme) 10d4 + 20 Very Rare","enabled":true,"extensions":{},"folder":"folder:c5aedaa9-1450-4cf3-a103-74d652ba4c33","insertion_order":58,"keys":[""],"mode":"normal","name":"마법 물건: Potions of Healing","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"마법 물건: Potion of Heroism","constant":false,"content":"## Potion of Heroism (영웅심 물약) - magic item, SRD 5.2.1\nPotion, Rare.\nWhen you drink this potion, you gain 10 Temporary Hit Points that last for 1 hour. For the same duration, you are under the effect of the Bless spell (no Concentration required). This potion's blue liquid bubbles and steams as if boiling.","enabled":true,"extensions":{},"folder":"folder:c5aedaa9-1450-4cf3-a103-74d652ba4c33","insertion_order":58,"keys":[""],"mode":"normal","name":"마법 물건: Potion of Heroism","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"마법 물건: Potion of Invisibility","constant":false,"content":"## Potion of Invisibility (투명화 물약) - magic item, SRD 5.2.1\nPotion, Rare.\nThis potion's container looks empty but feels as though it holds liquid. When you drink the potion, you have the Invisible condition for 1 hour. The effect ends early if you make an attack roll, deal damage, or cast a spell.","enabled":true,"extensions":{},"folder":"folder:c5aedaa9-1450-4cf3-a103-74d652ba4c33","insertion_order":58,"keys":[""],"mode":"normal","name":"마법 물건: Potion of Invisibility","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"마법 물건: Potion of Invulnerability","constant":false,"content":"## Potion of Invulnerability (무적 물약) - magic item, SRD 5.2.1\nPotion, Rare.\nFor 1 minute after you drink this potion, you have Resistance to all damage. This potion's syrupy liquid looks like liquefied iron.","enabled":true,"extensions":{},"folder":"folder:c5aedaa9-1450-4cf3-a103-74d652ba4c33","insertion_order":58,"keys":[""],"mode":"normal","name":"마법 물건: Potion of Invulnerability","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"마법 물건: Potion of Longevity","constant":false,"content":"## Potion of Longevity (장수 물약) - magic item, SRD 5.2.1\nPotion, Very Rare.\nWhen you drink this potion, your physical age is reduced by 1d6 + 6 years, to a minimum of 13 years. Each time you subsequently drink a Potion of Longevity, there is 10 percent cumulative chance that you instead age by 1d6 + 6 years. Suspended in this amber liquid is a tiny heart that, against all reason, is still beating. These ingredients vanish when the potion is opened.","enabled":true,"extensions":{},"folder":"folder:c5aedaa9-1450-4cf3-a103-74d652ba4c33","insertion_order":58,"keys":[""],"mode":"normal","name":"마법 물건: Potion of Longevity","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"마법 물건: Potion of Mind Reading","constant":false,"content":"## Potion of Mind Reading (독심 물약) - magic item, SRD 5.2.1\nPotion, Rare.\nWhen you drink this potion, you gain the effect of the Detect Thoughts spell (save DC 13) for 10 minutes (no Concentration required). This potion's dense, purple liquid has an ovoid cloud of pink floating in it.","enabled":true,"extensions":{},"folder":"folder:c5aedaa9-1450-4cf3-a103-74d652ba4c33","insertion_order":58,"keys":[""],"mode":"normal","name":"마법 물건: Potion of Mind Reading","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"마법 물건: Potion of Poison","constant":false,"content":"## Potion of Poison (독 물약) - magic item, SRD 5.2.1\nPotion, Uncommon.\nThis concoction looks, smells, and tastes like a Potion of Healing or another beneficial potion. However, it is actually poison masked by illusion magic. Identify reveals its true nature. If you drink this potion, you take 4d6 Poison damage and must succeed on a DC 13 Constitution saving throw or have the Poisoned condition for 1 hour.","enabled":true,"extensions":{},"folder":"folder:c5aedaa9-1450-4cf3-a103-74d652ba4c33","insertion_order":58,"keys":[""],"mode":"normal","name":"마법 물건: Potion of Poison","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"마법 물건: Potion of Resistance","constant":false,"content":"## Potion of Resistance (저항 물약) - magic item, SRD 5.2.1\nPotion, Uncommon.\nWhen you drink this potion, you have Resistance to one type of damage for 1 hour. The GM chooses the type or determines it randomly by rolling on the following table. 1d10 Damage Type 1d10 Damage Type 1 Acid 6 Necrotic 2 Cold 7 Poison 3 Fire 8 Psychic 4 Force 9 Radiant 5 Lightning 10 Thunder","enabled":true,"extensions":{},"folder":"folder:c5aedaa9-1450-4cf3-a103-74d652ba4c33","insertion_order":58,"keys":[""],"mode":"normal","name":"마법 물건: Potion of Resistance","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"마법 물건: Potion of Speed","constant":false,"content":"## Potion of Speed (신속 물약) - magic item, SRD 5.2.1\nPotion, Very Rare.\nWhen you drink this potion, you gain the effect of the Haste spell for 1 minute (no Concentration required) without suffering the wave of lethargy that typically occurs when the effect ends. This potion's yellow fluid is streaked with black and swirls on its own.","enabled":true,"extensions":{},"folder":"folder:c5aedaa9-1450-4cf3-a103-74d652ba4c33","insertion_order":58,"keys":[""],"mode":"normal","name":"마법 물건: Potion of Speed","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"마법 물건: Potion of Vitality","constant":false,"content":"## Potion of Vitality (활력 물약) - magic item, SRD 5.2.1\nPotion, Very Rare.\nWhen you drink this potion, it removes any Exhaustion levels you have and ends the Poisoned condition on you. For the next 24 hours, you regain the maximum number of Hit Points for any Hit Point Die you spend. This potion's crimson liquid regularly pulses with dull light, calling to mind a heartbeat.","enabled":true,"extensions":{},"folder":"folder:c5aedaa9-1450-4cf3-a103-74d652ba4c33","insertion_order":58,"keys":[""],"mode":"normal","name":"마법 물건: Potion of Vitality","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"마법 물건: Potion of Water Breathing","constant":false,"content":"## Potion of Water Breathing (수중 호흡 물약) - magic item, SRD 5.2.1\nPotion, Uncommon.\nYou can breathe underwater for 24 hours after drinking this potion. 237 This potion's cloudy green fluid smells of the sea and has a jellyfish-like bubble floating in it.","enabled":true,"extensions":{},"folder":"folder:c5aedaa9-1450-4cf3-a103-74d652ba4c33","insertion_order":58,"keys":[""],"mode":"normal","name":"마법 물건: Potion of Water Breathing","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"마법 물건: Quarterstaff of the Acrobat","constant":false,"content":"## Quarterstaff of the Acrobat (곡예사의 쿼터스태프) - magic item, SRD 5.2.1\nWeapon (Quarterstaff), Very Rare (Requires Attunement).\nYou have a +2 bonus to attack rolls and damage rolls made with this magic weapon. While holding this weapon, you can cause it to emit green Dim Light out to 10 feet, either as a Bonus Action or after you roll Initiative, or you can extinguish the light as a Bonus Action. While holding this weapon, you can take a Bonus Action to alter its form, turning it into a 6-inch rod (for ease of storage) or a 10-foot pole, or reverting it a Quarterstaff; the weapon will elongate only as far as the surrounding space allows. In certain forms, the weapon has the following additional properties. Acrobatic Assist (Quarterstaff and 10-Foot Pole Forms Only). While holding this weapon, you have Advantage on Dexterity (Acrobatics) checks. Attack Deflection (Quarterstaff Form Only). When you are hit by an attack while holding the weapon, you can take a Reaction to twirl the weapon around you, gaining a +5 bonus to your Armor Class against the triggering attack, potentially causing the attack to miss you. You can't use this property again until you finish a Short or Long Rest. Ranged Weapon (Quarterstaff Form Only). This weapon has the Thrown property with a normal range of 30 feet and a long range of 120 feet. Immediately after you make a ranged attack with the weapon, it flies back to your hand.","enabled":true,"extensions":{},"folder":"folder:c5aedaa9-1450-4cf3-a103-74d652ba4c33","insertion_order":58,"keys":[""],"mode":"normal","name":"마법 물건: Quarterstaff of the Acrobat","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"마법 물건: Ring of Animal Influence","constant":false,"content":"## Ring of Animal Influence (동물 감화 반지) - magic item, SRD 5.2.1\nRing, Rare.\nThis ring has 3 charges, and it regains 1d3 expended charges daily at dawn. While wearing the ring, you can expend 1 charge to cast one of the following spells (save DC 13) from it: • Animal Friendship • Fear (affects Beasts only) • Speak with Animals","enabled":true,"extensions":{},"folder":"folder:c5aedaa9-1450-4cf3-a103-74d652ba4c33","insertion_order":58,"keys":[""],"mode":"normal","name":"마법 물건: Ring of Animal Influence","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"마법 물건: Ring of Djinni Summoning","constant":false,"content":"## Ring of Djinni Summoning (진 소환 반지) - magic item, SRD 5.2.1\nRing, Legendary (Requires Attunement).\nWhile wearing this ring, you can take a Magic action to summon a particular Djinni from the Elemental Plane of Air. The djinni appears in an unoccupied space you choose within 120 feet of yourself. It remains as long as you maintain Concentration, to a maximum of 1 hour, or until it drops to 0 Hit Points. While summoned, the djinni is Friendly to you and your allies, and it obeys your commands. If you fail to command it, the djinni defends itself against attackers but takes no other actions. After the djinni departs, it can't be summoned again for 24 hours, and the ring becomes nonmagical if the djinni dies. Rings of Djinni Summoning are often created by the djinn they summon and given to mortals as gifts of friendship or tokens of esteem.","enabled":true,"extensions":{},"folder":"folder:c5aedaa9-1450-4cf3-a103-74d652ba4c33","insertion_order":58,"keys":[""],"mode":"normal","name":"마법 물건: Ring of Djinni Summoning","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"마법 물건: Ring of Elemental Command","constant":false,"content":"## Ring of Elemental Command (원소 지배 반지) - magic item, SRD 5.2.1\nRing, Legendary (Requires Attunement).\nEach Ring of Elemental Command is linked to one of the four Elemental Planes. The GM chooses or randomly determines the linked plane. For example, a Ring of Elemental Command (air) is linked to the Elemental Plane of Air. Every Ring of Elemental Command has the following two properties: Elemental Bane. While wearing the ring, you have Advantage on attack rolls against Elementals and they have Disadvantage on attack rolls against you. Elemental Compulsion. While wearing the ring, you can take a Magic action to try to compel an Elemental you see within 60 feet of yourself. The Elemental makes a DC 18 Wisdom saving throw. On a failed save, the Elemental has the Charmed condition until the start your next turn, and you determine what it does with its move and action on its next turn. Elemental Focus. While wearing the ring, you benefit from additional properties corresponding to the ring's linked Elemental Plane: Air. You know Auran, you have Resistance to Lightning damage, and you have a Fly Speed equal to your Speed and can hover. Earth. You know Terran, and you have Resistance to Acid damage. Terrain composed of rubble, rocks, or dirt isn't Difficult Terrain for you. In addition, you can move through solid earth or rock as if those areas were Difficult Terrain without disturbing the matter through which you pass. If you end your turn in solid earth or rock, you are shunted out to the nearest unoccupied space you last occupied. Fire. You know Ignan, and you have Immunity to Fire damage. Water. You know Aquan, you gain a Swim Speed of 60 feet, and you can breathe underwater. Spellcasting. The ring has 5 charges and regains 1d4 + 1 expended charges daily at dawn. While wearing the ring, you can cast a spell from it. Choose the spell from the list of available spells based on the Elemental Plane the ring is linked to, as shown in the following table. The table indicates how many charges you must expend to cast the spell, which has a save DC of 18. 238 Plane Spells (Charges) Air Chain Lightning (3 charges), Feather Fall (0 charges), Gust of Wind (2 charges), Wind Wall (1 charge) Earth Earthquake (5 charges), Stone Shape (2 charges), Stoneskin (3 charges), Wall of Stone (3 charges) Fire Burning Hands (1 charge), Fireball (2 charges), Fire Storm (4 charges), Wall of Fire (3 charges) Water Create or Destroy Water (1 charge), Ice Storm (2 charges), Tsunami (5 charges), Wall of Ice (3 charges), Water Walk (2 charges)","enabled":true,"extensions":{},"folder":"folder:c5aedaa9-1450-4cf3-a103-74d652ba4c33","insertion_order":58,"keys":[""],"mode":"normal","name":"마법 물건: Ring of Elemental Command","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"마법 물건: Ring of Evasion","constant":false,"content":"## Ring of Evasion (회피의 반지) - magic item, SRD 5.2.1\nRing, Rare (Requires Attunement).\nThis ring has 3 charges, and it regains 1d3 expended charges daily at dawn. When you fail a Dexterity saving throw while wearing the ring, you can take a Reaction to expend 1 charge to succeed on that save instead.","enabled":true,"extensions":{},"folder":"folder:c5aedaa9-1450-4cf3-a103-74d652ba4c33","insertion_order":58,"keys":[""],"mode":"normal","name":"마법 물건: Ring of Evasion","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"마법 물건: Ring of Feather Falling","constant":false,"content":"## Ring of Feather Falling (깃털 낙하 반지) - magic item, SRD 5.2.1\nRing, Rare (Requires Attunement).\nWhen you fall while wearing this ring, you descend 60 feet per round and take no damage from falling.","enabled":true,"extensions":{},"folder":"folder:c5aedaa9-1450-4cf3-a103-74d652ba4c33","insertion_order":58,"keys":[""],"mode":"normal","name":"마법 물건: Ring of Feather Falling","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"마법 물건: Ring of Free Action","constant":false,"content":"## Ring of Free Action (자유 행동 반지) - magic item, SRD 5.2.1\nRing, Rare (Requires Attunement).\nWhile you wear this ring, Difficult Terrain doesn't cost you extra movement. In addition, magic can neither reduce any of your Speeds nor cause you to have the Paralyzed or Restrained condition.","enabled":true,"extensions":{},"folder":"folder:c5aedaa9-1450-4cf3-a103-74d652ba4c33","insertion_order":58,"keys":[""],"mode":"normal","name":"마법 물건: Ring of Free Action","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"마법 물건: Ring of Invisibility","constant":false,"content":"## Ring of Invisibility (투명화 반지) - magic item, SRD 5.2.1\nRing, Legendary (Requires Attunement).\nWhile wearing this ring, you can take a Magic action to give yourself the Invisible condition. You remain Invisible until the ring is removed or until you take a Bonus Action to become visible again.","enabled":true,"extensions":{},"folder":"folder:c5aedaa9-1450-4cf3-a103-74d652ba4c33","insertion_order":58,"keys":[""],"mode":"normal","name":"마법 물건: Ring of Invisibility","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"마법 물건: Ring of Jumping","constant":false,"content":"## Ring of Jumping (도약의 반지) - magic item, SRD 5.2.1\nRing, Uncommon (Requires Attunement).\nWhile wearing this ring, you can cast Jump from it, but can target only yourself when you do so.","enabled":true,"extensions":{},"folder":"folder:c5aedaa9-1450-4cf3-a103-74d652ba4c33","insertion_order":58,"keys":[""],"mode":"normal","name":"마법 물건: Ring of Jumping","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"마법 물건: Ring of Mind Shielding","constant":false,"content":"## Ring of Mind Shielding (정신 보호 반지) - magic item, SRD 5.2.1\nRing, Uncommon (Requires Attunement).\nWhile wearing this ring, you are immune to magic that allows other creatures to read your thoughts, determine whether you are lying, know your alignment, or know your creature type. Creatures can telepathically communicate with you only if you allow it. You can take a Magic action to cause the ring to become imperceptible until you take another Magic action to make it perceptible, until you remove the ring, or until you die. If you die while wearing the ring, your soul enters it, unless it already houses a soul. You can remain in the ring or depart for the afterlife. As long as your soul is in the ring, you can telepathically communicate with any creature wearing it. A wearer can't prevent this telepathic communication.","enabled":true,"extensions":{},"folder":"folder:c5aedaa9-1450-4cf3-a103-74d652ba4c33","insertion_order":58,"keys":[""],"mode":"normal","name":"마법 물건: Ring of Mind Shielding","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"마법 물건: Ring of Protection","constant":false,"content":"## Ring of Protection (보호의 반지) - magic item, SRD 5.2.1\nRing, Rare (Requires Attunement).\nYou gain a +1 bonus to Armor Class and saving throws while wearing this ring.","enabled":true,"extensions":{},"folder":"folder:c5aedaa9-1450-4cf3-a103-74d652ba4c33","insertion_order":58,"keys":[""],"mode":"normal","name":"마법 물건: Ring of Protection","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"마법 물건: Ring of Regeneration","constant":false,"content":"## Ring of Regeneration (재생의 반지) - magic item, SRD 5.2.1\nRing, Very Rare (Requires Attunement).\nWhile wearing this ring, you regain 1d6 Hit Points every 10 minutes if you have at least 1 Hit Point. If you lose a body part, the ring causes the missing part to regrow and return to full functionality after 1d6 + 1 days if you have at least 1 Hit Point the whole time.","enabled":true,"extensions":{},"folder":"folder:c5aedaa9-1450-4cf3-a103-74d652ba4c33","insertion_order":58,"keys":[""],"mode":"normal","name":"마법 물건: Ring of Regeneration","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"마법 물건: Ring of Resistance","constant":false,"content":"## Ring of Resistance (저항의 반지) - magic item, SRD 5.2.1\nRing, Rare.\nYou have Resistance to one damage type while wearing this ring. The gemstone in the ring indicates the type, which the GM chooses or determines randomly by rolling on the following table. 1d10 Damage Type Gemstone 1 Acid Pearl 2 Cold Tourmaline 3 Fire Garnet 4 Force Sapphire 5 Lightning Citrine 6 Necrotic Jet 7 Poison Amethyst 8 Psychic Jade 9 Radiant Topaz 10 Thunder Spinel","enabled":true,"extensions":{},"folder":"folder:c5aedaa9-1450-4cf3-a103-74d652ba4c33","insertion_order":58,"keys":[""],"mode":"normal","name":"마법 물건: Ring of Resistance","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"마법 물건: Ring of Shooting Stars","constant":false,"content":"## Ring of Shooting Stars (유성의 반지) - magic item, SRD 5.2.1\nRing, Very Rare (Requires Attunement).\nYou can cast Dancing Lights or Light from the ring. The ring has 6 charges and regains 1d6 expended charges daily at dawn. You can expend its charges to use the properties below. Faerie Fire. You can expend 1 charge to cast Faerie Fire from the ring. Lightning Spheres. You can expend 2 charges as a Magic action to create up to four 3-foot-diameter spheres of lightning. Each sphere appears in an unoccupied space you can see within 120 feet of yourself. The spheres 239 last as long as you maintain Concentration, up to 1 minute. Each sphere sheds Dim Light in a 30-foot radius. As a Bonus Action, you can move each sphere up to 30 feet, but no farther than 120 feet away from yourself. The first time the sphere comes within 5 feet of a creature other than you that isn't behind Total Cover, the sphere discharges lightning at that creature and disappears. That creature makes a DC 15 Dexterity saving throw. On a failed save, the creature takes Lightning damage based on the number of spheres you created, as shown in the following table. On a successful save, the creature takes half as much damage. Number of Spheres Lightning Damage Number of Spheres Lightning Damage 1 4d12 3 2d6 2 5d4 4 2d4 Shooting Stars. You can expend 1 to 3 charges as a Magic action. For every charge you expend, you launch a glowing mote of light from the ring at a point you can see within 60 feet of yourself. Each creature in a 15-foot Cube originating from that point is showered in sparks and makes a DC 15 Dexterity saving throw, taking 5d4 Radiant damage on a failed save or half as much damage on a successful one.","enabled":true,"extensions":{},"folder":"folder:c5aedaa9-1450-4cf3-a103-74d652ba4c33","insertion_order":58,"keys":[""],"mode":"normal","name":"마법 물건: Ring of Shooting Stars","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"마법 물건: Ring of Spell Storing","constant":false,"content":"## Ring of Spell Storing (주문 저장 반지) - magic item, SRD 5.2.1\nRing, Rare (Requires Attunement).\nThis ring stores spells cast into it, holding them until the attuned wearer uses them. The ring can store up to 5 levels worth of spells at a time. When found, it contains 1d6 - 1 levels of stored spells chosen by the GM. Any creature can cast a spell of level 1 through 5 into the ring by touching the ring as the spell is cast. The spell has no effect other than to be stored in the ring. If the ring can't hold the spell, the spell is expended without effect. The level of the slot used to cast the spell determines how much space it uses. While wearing this ring, you can cast any spell stored in it. The spell uses the slot level, spell save DC, spell attack bonus, and spellcasting ability of the original caster but is otherwise treated as if you cast the spell. The spell cast from the ring is no longer stored in it, freeing up space.","enabled":true,"extensions":{},"folder":"folder:c5aedaa9-1450-4cf3-a103-74d652ba4c33","insertion_order":58,"keys":[""],"mode":"normal","name":"마법 물건: Ring of Spell Storing","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"마법 물건: Ring of Spell Turning","constant":false,"content":"## Ring of Spell Turning (주문 되돌림 반지) - magic item, SRD 5.2.1\nRing, Legendary (Requires Attunement).\nWhile wearing this ring, you have Advantage on saving throws against spells. If you succeed on the save for a spell of level 7 or lower, the spell has no effect on you. If that spell targeted only you and didn't create an area of effect, you can take a Reaction to deflect the spell back at the spell's caster; the caster must make a saving throw against the spell using their own spell save DC.","enabled":true,"extensions":{},"folder":"folder:c5aedaa9-1450-4cf3-a103-74d652ba4c33","insertion_order":58,"keys":[""],"mode":"normal","name":"마법 물건: Ring of Spell Turning","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"마법 물건: Ring of Swimming","constant":false,"content":"## Ring of Swimming (헤엄의 반지) - magic item, SRD 5.2.1\nRing, Uncommon.\nYou have a Swim Speed of 40 feet while wearing this ring.","enabled":true,"extensions":{},"folder":"folder:c5aedaa9-1450-4cf3-a103-74d652ba4c33","insertion_order":58,"keys":[""],"mode":"normal","name":"마법 물건: Ring of Swimming","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"마법 물건: Ring of Telekinesis","constant":false,"content":"## Ring of Telekinesis (염동력 반지) - magic item, SRD 5.2.1\nRing, Very Rare (Requires Attunement).\nWhile wearing this ring, you can cast Telekinesis from it.","enabled":true,"extensions":{},"folder":"folder:c5aedaa9-1450-4cf3-a103-74d652ba4c33","insertion_order":58,"keys":[""],"mode":"normal","name":"마법 물건: Ring of Telekinesis","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"마법 물건: Ring of the Ram","constant":false,"content":"## Ring of the Ram (숫양의 반지) - magic item, SRD 5.2.1\nRing, Rare (Requires Attunement).\nThis ring has 3 charges and regains 1d3 expended charges daily at dawn. While wearing the ring, you can take a Magic action to expend 1 to 3 charges to make a ranged spell attack against one creature you can see within 60 feet of yourself. The ring produces a spectral ram's head and makes its attack roll with a +7 bonus. On a hit, for each charge you spend, the target takes 2d10 Force damage and is pushed 5 feet away from you. Alternatively, you can expend 1 to 3 of the ring's charges as a Magic action to try to break a nonmagical object you can see within 60 feet of yourself that isn't being worn or carried. The ring makes a Strength check with a +5 bonus for each charge you spend.","enabled":true,"extensions":{},"folder":"folder:c5aedaa9-1450-4cf3-a103-74d652ba4c33","insertion_order":58,"keys":[""],"mode":"normal","name":"마법 물건: Ring of the Ram","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"마법 물건: Ring of Three Wishes","constant":false,"content":"## Ring of Three Wishes (세 가지 소원 반지) - magic item, SRD 5.2.1\nRing, Legendary.\nWhile wearing this ring, you can expend 1 of its 3 charges to cast Wish from it. The ring becomes nonmagical when you use the last charge.","enabled":true,"extensions":{},"folder":"folder:c5aedaa9-1450-4cf3-a103-74d652ba4c33","insertion_order":58,"keys":[""],"mode":"normal","name":"마법 물건: Ring of Three Wishes","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"마법 물건: Ring of Warmth","constant":false,"content":"## Ring of Warmth (온기의 반지) - magic item, SRD 5.2.1\nRing, Uncommon (Requires Attunement).\nIf you take Cold damage while wearing this ring, the ring reduces the damage you take by 2d8. In addition, while wearing this ring, you and everything you wear and carry are unharmed by temperatures of 0 degrees Fahrenheit or lower.","enabled":true,"extensions":{},"folder":"folder:c5aedaa9-1450-4cf3-a103-74d652ba4c33","insertion_order":58,"keys":[""],"mode":"normal","name":"마법 물건: Ring of Warmth","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"마법 물건: Ring of Water Walking","constant":false,"content":"## Ring of Water Walking (수면 보행 반지) - magic item, SRD 5.2.1\nRing, Uncommon.\nWhile wearing this ring, you cast Water Walk from it, targeting only yourself.","enabled":true,"extensions":{},"folder":"folder:c5aedaa9-1450-4cf3-a103-74d652ba4c33","insertion_order":58,"keys":[""],"mode":"normal","name":"마법 물건: Ring of Water Walking","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"마법 물건: Ring of X-ray Vision","constant":false,"content":"## Ring of X-ray Vision (투시 시야 반지) - magic item, SRD 5.2.1\nRing, Rare (Requires Attunement).\nWhile wearing this ring, you can take a Magic action to gain X-ray vision with a range of 30 feet for 1 minute. To you, solid objects within that radius appear transparent and don't prevent light from passing through them. The vision can penetrate 1 240 foot of stone, 1 inch of common metal, or up to 3 feet of wood or dirt. Thicker substances or a thin sheet of lead block the vision. Whenever you use the ring again before taking a Long Rest, you must succeed on a DC 15 Constitution saving throw or gain 1 Exhaustion level.","enabled":true,"extensions":{},"folder":"folder:c5aedaa9-1450-4cf3-a103-74d652ba4c33","insertion_order":58,"keys":[""],"mode":"normal","name":"마법 물건: Ring of X-ray Vision","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"마법 물건: Robe of Eyes","constant":false,"content":"## Robe of Eyes (눈의 로브) - magic item, SRD 5.2.1\nWondrous Item, Rare (Requires Attunement).\nThis robe is adorned with eyelike patterns. While you wear the robe, you gain the following benefits: All-Around Vision. The robe gives you Advantage on Wisdom (Perception) checks that rely on sight. Special Senses. You have Darkvision and Truesight, both with a range of 120 feet. Drawbacks. A Light spell cast on the robe or a Daylight spell cast within 5 feet of the robe gives you the Blinded condition for 1 minute. At the end of each of your turns, you make a Constitution saving throw (DC 11 for Light or DC 15 for Daylight), ending the condition on yourself on a success.","enabled":true,"extensions":{},"folder":"folder:c5aedaa9-1450-4cf3-a103-74d652ba4c33","insertion_order":58,"keys":[""],"mode":"normal","name":"마법 물건: Robe of Eyes","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"마법 물건: Robe of Scintillating Colors","constant":false,"content":"## Robe of Scintillating Colors (현란한 빛깔의 로브) - magic item, SRD 5.2.1\nWondrous Item, Very Rare (Requires Attunement).\nThis robe has 3 charges, and it regains 1d3 expended charges daily at dawn. While you wear it, you can take a Magic action and expend 1 charge to cause the garment to display a shifting pattern of dazzling hues until the end of your next turn. During this time, the robe sheds Bright Light in a 30-foot radius and Dim Light for an additional 30 feet, and creatures that can see you have Disadvantage on attack rolls against you. Any creature in the Bright Light that can see you when the robe's power is activated must succeed on a DC 15 Wisdom saving throw or have the Stunned condition until the effect ends.","enabled":true,"extensions":{},"folder":"folder:c5aedaa9-1450-4cf3-a103-74d652ba4c33","insertion_order":58,"keys":[""],"mode":"normal","name":"마법 물건: Robe of Scintillating Colors","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"마법 물건: Robe of Stars","constant":false,"content":"## Robe of Stars (별의 로브) - magic item, SRD 5.2.1\nWondrous Item, Very Rare (Requires Attunement).\nThis black or dark-blue robe is embroidered with small white or silver stars. You gain a +1 bonus to saving throws while you wear it. Six stars, located on the robe's upper-front portion, are particularly large. While wearing this robe, you can take a Magic action to remove one of the stars and expend it to cast the level 5 version of Magic Missile. Daily at dusk, 1d6 removed stars reappear on the robe. While you wear the robe, you can take a Magic action to enter the Astral Plane along with everything you are wearing and carrying. You remain there until you take a Magic action to return to the plane you were on. You reappear in the last space you occupied or, if that space is occupied, the nearest unoccupied space.","enabled":true,"extensions":{},"folder":"folder:c5aedaa9-1450-4cf3-a103-74d652ba4c33","insertion_order":58,"keys":[""],"mode":"normal","name":"마법 물건: Robe of Stars","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"마법 물건: Robe of the Archmagi","constant":false,"content":"## Robe of the Archmagi (대마법사의 로브) - magic item, SRD 5.2.1\nWondrous Item, Legendary (Requires Attunement by a Sorcerer, Warlock, or Wizard).\nThis elegant garment is made from exquisite cloth and adorned with runes. You gain these benefits while wearing the robe. Armor. If you aren't wearing armor, your base Armor Class is 15 plus your Dexterity modifier. Magic Resistance. You have Advantage on saving throws against spells and other magical effects. War Mage. Your spell save DC and spell attack bonus each increase by 2.","enabled":true,"extensions":{},"folder":"folder:c5aedaa9-1450-4cf3-a103-74d652ba4c33","insertion_order":58,"keys":[""],"mode":"normal","name":"마법 물건: Robe of the Archmagi","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"마법 물건: Robe of Useful Items","constant":false,"content":"## Robe of Useful Items (쓸모 있는 물건 로브) - magic item, SRD 5.2.1\nWondrous Item, Uncommon.\nThis robe has cloth patches of various shapes and colors covering it. While wearing the robe, you can take a Magic action to detach one of the patches, causing it to become the object or creature it represents. Once the last patch is removed, the robe becomes an ordinary garment. The robe has two of each of the following patches: • Bullseye Lantern (filled and lit) • Dagger • Mirror • Pole • Rope (coiled) • Sack In addition, the robe has 4d4 other patches. The GM chooses the patches or determines them randomly by rolling on the following table. 1d100 Patch 01-08 Bag of 100 GP 09-15 Silver coffer (1 foot long, 6 inches wide and deep) worth 500 GP 16-22 Iron door (up to 10 feet wide and 10 feet high, barred on one side of your choice), which you can place in an opening you can reach; it conforms to fit the opening, attaching and hinging itself 23-30 10 gems worth 100 GP each 31-44 Wooden ladder (24 feet long) 45-51 Riding Horse with a Riding Saddle 52-59 Open pit (a 10-foot Cube), which you can place on the ground within 10 feet of yourself 60-68 4 Potions of Healing 69-75 Rowboat (12 feet long) 76-83 Spell Scroll containing one spell of level 1, 2, or 3 (your choice) 241 1d100 Patch 84-90 2 Mastiffs 91-96 Window (2 feet by 4 feet, up to 2 feet deep), which you can place on a vertical surface you can reach 97-00 Portable Ram","enabled":true,"extensions":{},"folder":"folder:c5aedaa9-1450-4cf3-a103-74d652ba4c33","insertion_order":58,"keys":[""],"mode":"normal","name":"마법 물건: Robe of Useful Items","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"마법 물건: Rod of Absorption","constant":false,"content":"## Rod of Absorption (흡수의 막대) - magic item, SRD 5.2.1\nRod, Very Rare (Requires Attunement).\nWhile holding this rod, you can take a Reaction to absorb a spell that is targeting only you and doesn't create an area of effect. The absorbed spell's effect is canceled, and the spell's energy—not the spell itself—is stored in the rod. The energy has the same level as the spell when it was cast. A canceled spell dissipates with no effect, and any resources used to cast it are wasted. The rod can absorb and store up to 50 levels of energy over the course of its existence. Once the rod absorbs 50 levels of energy, it can't absorb more. If you are targeted by a spell that the rod can't store, the rod has no effect on that spell. When you become attuned to the rod, you know how many levels of energy the rod has absorbed over the course of its existence and how many levels of spell energy it currently has stored. If you are a spellcaster holding the rod, you can convert energy stored in it into spell slots to cast spells you have prepared or know. You can create spell slots only of a level equal to or lower than your own spell slots, up to a maximum of level 5. You use the stored levels in place of your slots but otherwise cast the spell as normal. For example, you can use 3 levels stored in the rod as a level 3 spell slot. A newly found rod typically has 1d10 levels of spell energy stored in it. A rod that can no longer absorb spell energy and has no energy remaining becomes nonmagical.","enabled":true,"extensions":{},"folder":"folder:c5aedaa9-1450-4cf3-a103-74d652ba4c33","insertion_order":58,"keys":[""],"mode":"normal","name":"마법 물건: Rod of Absorption","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"마법 물건: Rod of Alertness","constant":false,"content":"## Rod of Alertness (경계의 막대) - magic item, SRD 5.2.1\nRod, Very Rare (Requires Attunement).\nThis rod has the following properties. Alertness. While holding the rod, you have Advantage on Wisdom (Perception) checks and on Initiative rolls. Spells. While holding the rod, you can cast the following spells from it: • Detect Evil and Good • Detect Magic • Detect Poison and Disease • See Invisibility Protective Aura. As a Magic action, you can plant the haft end of the rod in the ground, whereupon the rod's head sheds Bright Light in a 60-foot radius and Dim Light for an additional 60 feet. While in that Bright Light, you and your allies gain a +1 bonus to Armor Class and saving throws and can sense the location of any Invisible creature that is also in the Bright Light. The rod's head stops glowing and the effect ends after 10 minutes or when a creature takes a Magic action to pull the rod from the ground. Once used, this property can't be used again until the next dawn.","enabled":true,"extensions":{},"folder":"folder:c5aedaa9-1450-4cf3-a103-74d652ba4c33","insertion_order":58,"keys":[""],"mode":"normal","name":"마법 물건: Rod of Alertness","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"마법 물건: Rod of Lordly Might","constant":false,"content":"## Rod of Lordly Might (군주의 위력 막대) - magic item, SRD 5.2.1\nRod, Legendary (Requires Attunement).\nThis rod has a flanged head, and it functions as a magic Mace that grants a +3 bonus to attack rolls and damage rolls made with it. The rod has properties associated with six different buttons that are set in a row along the haft. It has three other properties as well, detailed below. Buttons. You can press one of the following buttons as a Bonus Action; a button's effect lasts until you push a different button or until you push the same button again, which causes the rod to revert to its normal form: Button 1. A fiery blade sprouts from the end opposite the rod's flanged head. The flames shed Bright Light in a 40-foot radius and Dim Light for an additional 40 feet, and the blade functions as a magic Longsword or Shortsword (your choice) that deals an extra 2d6 Fire damage on a hit. Button 2. The rod's flanged head folds down and two crescent-shaped blades spring out, transforming the rod into a magic Battleaxe that grants a +3 bonus to attack rolls and damage rolls made with it. Button 3. The rod's flanged head folds down, a spear point springs from the rod's tip, and the rod's handle lengthens into a 6-foot haft, transforming the rod into a magic Spear that grants a +3 bonus to attack rolls and damage rolls made with it. Button 4. The rod transforms into a climbing pole up to 50 feet long (you specify the length), though the rod's buttons remain within your reach. In surfaces as hard as granite, a spike at the bottom and three hooks at the top anchor the pole. Horizontal bars 3 inches long fold out from the sides, 1 foot apart, forming a ladder. The pole can bear up to 4,000 pounds. More weight or lack of solid anchoring causes the rod to revert to its normal form. Button 5. The rod transforms into a handheld battering ram and grants its user a +10 bonus to Strength (Athletics) checks made to break through doors, barricades, and other barriers. Button 6. The rod assumes or remains in its normal form and indicates magnetic north. (Nothing happens if this function of the rod is used in a 242 location that has no magnetic north.) The rod also gives you knowledge of your approximate depth beneath the ground or your height above it. Drain Life. When you hit a creature with a melee attack using the rod, you can force the target to make a DC 17 Constitution saving throw. On a failed save, the target takes an extra 4d6 Necrotic damage, and you regain a number of Hit Points equal to half that Necrotic damage. Once used, this property can't be used again until the next dawn. Paralyze. When you hit a creature with a melee attack using the rod, you can force the target to make a DC 17 Constitution saving throw. On a failed save, the target has the Paralyzed condition for 1 minute. The target repeats the save at the end of each of its turns, ending the effect on a success. Once used, this property can't be used again until the next dawn. Terrify. While holding the rod, you can take a Magic action to force each creature you can see within 30 feet of yourself to make a DC 17 Wisdom saving throw. On a failed save, a target has the Frightened condition for 1 minute. A Frightened target repeats the save at the end of each of its turns, ending the effect on itself on a success. Once used, this property can't be used again until the next dawn.","enabled":true,"extensions":{},"folder":"folder:c5aedaa9-1450-4cf3-a103-74d652ba4c33","insertion_order":58,"keys":[""],"mode":"normal","name":"마법 물건: Rod of Lordly Might","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"마법 물건: Rod of Resurrection","constant":false,"content":"## Rod of Resurrection (부활의 막대) - magic item, SRD 5.2.1\nRod, Legendary (Requires Attunement).\nThe rod has 5 charges. While you hold it, you can cast one of the following spells from it: Heal (expends 1 charge) or Resurrection (expends 5 charges). The rod regains 1 expended charge daily at dawn. If you expend the last charge, roll 1d20. On a 1, the rod disappears in a harmless burst of radiance.","enabled":true,"extensions":{},"folder":"folder:c5aedaa9-1450-4cf3-a103-74d652ba4c33","insertion_order":58,"keys":[""],"mode":"normal","name":"마법 물건: Rod of Resurrection","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"마법 물건: Rod of Rulership","constant":false,"content":"## Rod of Rulership (통치의 막대) - magic item, SRD 5.2.1\nRod, Rare (Requires Attunement).\nYou can take a Magic action to present the rod and command obedience from each creature of your choice that you can see within 120 feet of yourself. Each target must succeed on a DC 15 Wisdom saving throw or have the Charmed condition for 8 hours. While Charmed in this way, the creature regards you as its trusted leader. If harmed by you or your allies or commanded to do something contrary to its nature, a target ceases to be Charmed in this way. Once used, this property can't be used again until the next dawn.","enabled":true,"extensions":{},"folder":"folder:c5aedaa9-1450-4cf3-a103-74d652ba4c33","insertion_order":58,"keys":[""],"mode":"normal","name":"마법 물건: Rod of Rulership","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"마법 물건: Rod of Security","constant":false,"content":"## Rod of Security (안전의 막대) - magic item, SRD 5.2.1\nRod, Very Rare.\nWhile holding this rod, you can take a Magic action to activate it. The rod then instantly transports you and up to 199 other willing creatures you can see to a demiplane. You choose the form the demiplane takes. It could be a tranquil garden, a cheery tavern, an immense palace, a tropical island, a fantastic carnival, or whatever else you can imagine. Regardless of its nature, the demiplane contains enough water and food to sustain its visitors, and the demiplane's environment can't harm its occupants. Everything else that can be interacted with there can exist only there. For example, a flower picked from a garden there disappears if it is taken outside the demiplane. For each hour spent in the demiplane, a visitor regains Hit Points as if it had spent 1 Hit Point Die. Also, creatures don't age while there, although time passes normally. Visitors can remain there for up to 200 days divided by the number of creatures present (round down). When the time runs out or you take a Magic action to end the effect, all visitors reappear in the location they occupied when you activated the rod or an unoccupied space nearest that location. Once used, this property can't be used again until 10 days have passed.","enabled":true,"extensions":{},"folder":"folder:c5aedaa9-1450-4cf3-a103-74d652ba4c33","insertion_order":58,"keys":[""],"mode":"normal","name":"마법 물건: Rod of Security","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"마법 물건: Rope of Climbing","constant":false,"content":"## Rope of Climbing (등반 밧줄) - magic item, SRD 5.2.1\nWondrous Item, Uncommon.\nThis 60-foot length of rope can hold up to 3,000 pounds. While holding one end of the rope, you can take a Magic action to command the other end of the rope to animate and move toward a destination you choose, up to the rope's length away from you. That end moves 10 feet on your turn when you first command it and 10 feet at the start of each of your subsequent turns until reaching its destination or until you tell it to stop. You can also tell the rope to fasten itself securely to an object or to unfasten itself, to knot or unknot itself, or to coil itself for carrying. If you tell the rope to knot, large knots appear at 1-foot intervals along the rope. While knotted, the rope shortens to a 50-foot length and grants Advantage on ability checks made to climb using the rope. The rope has AC 20, HP 20, and Immunity to Poison and Psychic damage. It regains 1 Hit Point every 5 minutes as long as it has at least 1 Hit Point. If the rope drops to 0 Hit Points, it is destroyed.","enabled":true,"extensions":{},"folder":"folder:c5aedaa9-1450-4cf3-a103-74d652ba4c33","insertion_order":58,"keys":[""],"mode":"normal","name":"마법 물건: Rope of Climbing","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"마법 물건: Rope of Entanglement","constant":false,"content":"## Rope of Entanglement (휘감는 밧줄) - magic item, SRD 5.2.1\nWondrous Item, Rare.\nThis rope is 30 feet long. While holding one end of the rope, you can take a Magic action to command the other end to dart forward and entangle one creature you can see within 20 feet of yourself. The target must succeed on a DC 15 Dexterity saving throw or have the Restrained condition. You can release the target by letting go of your end of the rope (causing the rope to coil up in the target's space) or by using a Bonus Action to repeat the command (causing the rope to coil up in your hand). 243 A target Restrained by the rope can take an action to make its choice of a DC 15 Strength (Athletics) or Dexterity (Acrobatics) check. On a successful check, the target is no longer Restrained by the rope. If you're still holding onto the rope when a target escapes from it, you can take a Reaction to command the rope to coil up in your hand; otherwise, the rope coils up in the target's space. The rope has AC 20, HP 20, and Immunity to Poison and Psychic damage. It regains 1 Hit Point every 5 minutes as long as it has at least 1 Hit Point. If the rope drops to 0 Hit Points, it is destroyed.","enabled":true,"extensions":{},"folder":"folder:c5aedaa9-1450-4cf3-a103-74d652ba4c33","insertion_order":58,"keys":[""],"mode":"normal","name":"마법 물건: Rope of Entanglement","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"마법 물건: Scarab of Protection","constant":false,"content":"## Scarab of Protection (보호의 스카라브) - magic item, SRD 5.2.1\nWondrous Item, Legendary (Requires Attunement).\nThis beetle-shaped medallion provides three benefits while it is on your person. Defense. You gain a +1 bonus to Armor Class. Preservation. The scarab has 12 charges. If you fail a saving throw against a Necromancy spell or a harmful effect originating from an Undead, you can take a Reaction to expend 1 charge and turn the failed save into a successful one. The scarab crumbles into powder and is destroyed when its last charge is expended. Spell Resistance. You have Advantage on saving throws against spells.","enabled":true,"extensions":{},"folder":"folder:c5aedaa9-1450-4cf3-a103-74d652ba4c33","insertion_order":58,"keys":[""],"mode":"normal","name":"마법 물건: Scarab of Protection","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"마법 물건: Scimitar of Speed","constant":false,"content":"## Scimitar of Speed (신속의 시미터) - magic item, SRD 5.2.1\nWeapon (Scimitar), Very Rare (Requires Attunement).\nYou gain a +2 bonus to attack rolls and damage rolls made with this magic weapon. In addition, you can make one attack with it as a Bonus Action on each of your turns.","enabled":true,"extensions":{},"folder":"folder:c5aedaa9-1450-4cf3-a103-74d652ba4c33","insertion_order":58,"keys":[""],"mode":"normal","name":"마법 물건: Scimitar of Speed","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"마법 물건: Sending Stones","constant":false,"content":"## Sending Stones (전언의 돌) - magic item, SRD 5.2.1\nWondrous Item, Uncommon.\nSending Stones come in pairs, with each stone carved to match the other so the pairing is easily recognized. While you touch one stone, you can cast Sending from it. The target is the bearer of the other stone. If no creature bears the other stone, you know that fact as soon as you use the stone, and you don't cast the spell. Once Sending is cast using either stone, the stones can't be used again until the next dawn. If one of the stones in a pair is destroyed, the other one becomes nonmagical.","enabled":true,"extensions":{},"folder":"folder:c5aedaa9-1450-4cf3-a103-74d652ba4c33","insertion_order":58,"keys":[""],"mode":"normal","name":"마법 물건: Sending Stones","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"마법 물건: Sentinel Shield","constant":false,"content":"## Sentinel Shield (파수꾼 방패) - magic item, SRD 5.2.1\nArmor (Shield), Uncommon.\nWhile holding this Shield, you have Advantage on Initiative rolls and Wisdom (Perception) checks. The Shield is emblazoned with a symbol of an eye.","enabled":true,"extensions":{},"folder":"folder:c5aedaa9-1450-4cf3-a103-74d652ba4c33","insertion_order":58,"keys":[""],"mode":"normal","name":"마법 물건: Sentinel Shield","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"마법 물건: Shield, +1, +2, or +3","constant":false,"content":"## Shield, +1, +2, or +3 (+1·+2·+3 방패) - magic item, SRD 5.2.1\nArmor (Shield), Uncommon (+1), Rare (+2), or Very Rare (+3).\nWhile holding this Shield, you have a bonus to Armor Class determined by the Shield's rarity, in addition to the Shield's normal bonus to AC.","enabled":true,"extensions":{},"folder":"folder:c5aedaa9-1450-4cf3-a103-74d652ba4c33","insertion_order":58,"keys":[""],"mode":"normal","name":"마법 물건: Shield, +1, +2, or +3","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"마법 물건: Shield of Missile Attraction","constant":false,"content":"## Shield of Missile Attraction (투사체 끄는 방패) - magic item, SRD 5.2.1\nArmor (Shield), Rare (Requires Attunement).\nWhile holding this Shield, you have Resistance to damage from attacks made with Ranged weapons. Curse. This Shield is cursed. Attuning to it curses you until you are targeted by a Remove Curse spell or similar magic. Removing the Shield fails to end the curse on you. Whenever an attack with a Ranged weapon targets a creature within 10 feet of you, the curse causes you to become the target instead.","enabled":true,"extensions":{},"folder":"folder:c5aedaa9-1450-4cf3-a103-74d652ba4c33","insertion_order":58,"keys":[""],"mode":"normal","name":"마법 물건: Shield of Missile Attraction","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"마법 물건: Shield of the Cavalier","constant":false,"content":"## Shield of the Cavalier (기사의 방패) - magic item, SRD 5.2.1\nArmor (Shield), Very Rare (Requires Attunement).\nWhile holding this Shield, you have a +2 bonus to Armor Class. This bonus is in addition to the Shield's normal bonus to AC. The Shield has the following additional properties that you can use while holding it. Forceful Bash. When you take the Attack action, you can make one of the attack rolls using the Shield against a target within 5 feet of yourself. Apply your Proficiency Bonus and Strength modifier to the attack roll. On a hit, the Shield deals Force damage to the target equal to 2d6 + 2 plus your Strength modifier, and if the target is a creature, you can push it up to 10 feet directly away from yourself. If the creature is your size or smaller, you can also knock it down, giving it the Prone condition. Protective Field. As a Reaction, when you or an ally you can see within 5 feet of you is targeted by an attack or makes a saving throw against an area of effect, you can use the Shield to create an immobile 5-foot Emanation originating from you. When the Emanation appears, any creatures or objects not fully contained within it are pushed into the nearest unoccupied spaces outside it. The attack or area of effect that triggered the Reaction has no effect on creatures and objects inside the Emanation, which lasts as long as you maintain Concentration, up to 1 minute. Nothing can pass into or out of the Emanation. A creature or object inside the Emanation can't be damaged by attacks or effects originating from outside, nor can a creature inside the Emanation damage anything outside it. Once this property is used, it can't be used again until the next dawn. 244","enabled":true,"extensions":{},"folder":"folder:c5aedaa9-1450-4cf3-a103-74d652ba4c33","insertion_order":58,"keys":[""],"mode":"normal","name":"마법 물건: Shield of the Cavalier","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"마법 물건: Slippers of Spider Climbing","constant":false,"content":"## Slippers of Spider Climbing (거미 걸음 신발) - magic item, SRD 5.2.1\nWondrous Item, Uncommon (Requires Attunement).\nWhile you wear these light shoes, you can move up, down, and across vertical surfaces and along ceilings, while leaving your hands free. You have a Climb Speed equal to your Speed. However, the slippers don't allow you to move this way on a slippery surface, such as one covered by ice or oil.","enabled":true,"extensions":{},"folder":"folder:c5aedaa9-1450-4cf3-a103-74d652ba4c33","insertion_order":58,"keys":[""],"mode":"normal","name":"마법 물건: Slippers of Spider Climbing","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"마법 물건: Sovereign Glue","constant":false,"content":"## Sovereign Glue (만능 접착제) - magic item, SRD 5.2.1\nWondrous Item, Legendary.\nThis viscous, milky-white substance can form a permanent adhesive bond between any two objects. It must be stored in a jar or flask that has been coated inside with Oil of Slipperiness. When found, a container contains 1d6 + 1 ounces. One ounce of the glue can cover a 1-foot square surface. Applying an ounce of Sovereign Glue takes a Utilize action, and the applied glue takes 1 minute to set. Once it has done so, the bond it creates can be broken only by the application of Universal Solvent or Oil of Etherealness, or with a Wish spell.","enabled":true,"extensions":{},"folder":"folder:c5aedaa9-1450-4cf3-a103-74d652ba4c33","insertion_order":58,"keys":[""],"mode":"normal","name":"마법 물건: Sovereign Glue","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"마법 물건: Spellguard Shield","constant":false,"content":"## Spellguard Shield (주문 방어 방패) - magic item, SRD 5.2.1\nArmor (Shield), Very Rare (Requires Attunement).\nWhile holding this Shield, you have Advantage on saving throws against spells and other magical effects, and spell attack rolls have Disadvantage against you.","enabled":true,"extensions":{},"folder":"folder:c5aedaa9-1450-4cf3-a103-74d652ba4c33","insertion_order":58,"keys":[""],"mode":"normal","name":"마법 물건: Spellguard Shield","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"마법 물건: Spell Scroll","constant":false,"content":"## Spell Scroll (주문 두루마리) - magic item, SRD 5.2.1\nScroll, Rarity Varies.\nA Spell Scroll bears the words of a single spell, written in a mystical cipher. If the spell is on your spell list, you can read the scroll and cast its spell without Material components. Otherwise, the scroll is unintelligible. Casting the spell by reading the scroll requires the spell's normal casting time. Once the spell is cast, the scroll crumbles to dust. If the casting is interrupted, the scroll isn't lost. If the spell is on your spell list but of a higher level than you can normally cast, you make an ability check using your spellcasting ability to determine whether you cast the spell. The DC equals 10 plus the spell's level. On a failed check, the spell disappears from the scroll with no other effect. The level of the spell on the scroll determines the spell's saving throw DC and attack bonus, as well as the scroll's rarity, as shown in the following table. Spell Level Rarity Save DC Attack Bonus Cantrip Common 13 +5 1 Common 13 +5 2 Uncommon 13 +5 3 Uncommon 15 +7 Spell Level Rarity Save DC Attack Bonus 4 Rare 15 +7 5 Rare 17 +9 6 Very Rare 17 +9 7 Very Rare 18 +10 8 Very Rare 18 +10 9 Legendary 19 +11 Copying a Scroll into a Spellbook. A Wizard spell on a Spell Scroll can be copied into a spellbook. When a spell is copied in this way, the copier must succeed on an Intelligence (Arcana) check with a DC equal to 10 plus the spell's level. On a successful check, the spell is copied. Whether the check succeeds or fails, the Spell Scroll is destroyed.","enabled":true,"extensions":{},"folder":"folder:c5aedaa9-1450-4cf3-a103-74d652ba4c33","insertion_order":58,"keys":[""],"mode":"normal","name":"마법 물건: Spell Scroll","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"마법 물건: Sphere of Annihilation","constant":false,"content":"## Sphere of Annihilation (소멸의 구체) - magic item, SRD 5.2.1\nWondrous Item, Legendary.\nThis 2-foot-diameter black sphere is a hole in the multiverse, hovering in space and stabilized by a magical field surrounding it. The sphere obliterates all matter it passes through and all matter that passes through it. Artifacts are the exception. Unless an Artifact is susceptible to damage from a Sphere of Annihilation, it passes through the sphere unscathed. Anything else that touches the sphere but isn't wholly engulfed and obliterated by it takes 8d10 Force damage. Controlling the Sphere. A Sphere of Annihilation is stationary until someone takes control of it. If you are within 60 feet of a sphere, you can take a Magic action to make a DC 25 Intelligence (Arcana) check. On a successful check, you control the sphere until the start of your next turn, and if it was under another creature's control, that creature loses control of the sphere. On a failed check, the sphere moves 10 feet toward you in a straight line. While in control of the sphere, you can take a Bonus Action to cause it to move in one direction of your choice, up to a number of feet equal to 5 times your Intelligence modifier (minimum 5 feet). Any creature whose space the sphere enters must succeed on a DC 19 Dexterity saving throw or be touched by it, taking 8d10 Force damage. A creature reduced to 0 Hit Points by this damage is obliterated, leaving its possessions behind but no other physical remains. Sphere Interactions. If the sphere comes into contact with a planar portal (such as that created by the Gate spell) or an extradimensional space (such as that within a Portable Hole), the GM determines randomly what happens using the following table. 245 1d100 Result 01-50 The sphere is destroyed. 51-85 The sphere moves through the portal or into the extradimensional space. 86-00 A spatial rift sends the sphere and each creature and object within 180 feet of the sphere to a random plane of existence.","enabled":true,"extensions":{},"folder":"folder:c5aedaa9-1450-4cf3-a103-74d652ba4c33","insertion_order":58,"keys":[""],"mode":"normal","name":"마법 물건: Sphere of Annihilation","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"마법 물건: Staff of Charming","constant":false,"content":"## Staff of Charming (매혹의 지팡이) - magic item, SRD 5.2.1\nStaff, Rare (Requires Attunement by a Bard, Cleric, Druid, Sorcerer, Warlock, or Wizard).\nThis staff has 10 charges. While holding the staff, you can use any of its properties: Cast Spell. You can expend 1 of the staff's charges to cast Charm Person, Command, or Comprehend Languages from it using your spell save DC. Reflect Enchantment. If you succeed on a saving throw against an Enchantment spell that targets only you, you can take a Reaction to expend 1 charge from the staff and turn the spell back on its caster as if you had cast the spell. Resist Enchantment. If you fail a saving throw against an Enchantment spell that targets only you, you can turn your failed save into a successful one. You can't use this property of the staff again until the next dawn. Regaining Charges. The staff regains 1d8 + 2 expended charges daily at dawn. If you expend the last charge, roll 1d20. On a 1, the staff crumbles to dust and is destroyed.","enabled":true,"extensions":{},"folder":"folder:c5aedaa9-1450-4cf3-a103-74d652ba4c33","insertion_order":58,"keys":[""],"mode":"normal","name":"마법 물건: Staff of Charming","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"마법 물건: Staff of Fire","constant":false,"content":"## Staff of Fire (화염의 지팡이) - magic item, SRD 5.2.1\nStaff, Very Rare (Requires Attunement by a Druid, Sorcerer, Warlock, or Wizard).\nYou have Resistance to Fire damage while you hold this staff. Spells. The staff has 10 charges. While holding the staff, you can cast one of the spells on the following table from it, using your spell save DC. The table indicates how many charges you must expend to cast the spell. Spell Charge Cost Spell Charge Cost Burning Hands 1 Wall of Fire 4 Fireball 3 Regaining Charges. The staff regains 1d6 + 4 expended charges daily at dawn. If you expend the last charge, roll 1d20. On a 1, the staff crumbles into cinders and is destroyed.","enabled":true,"extensions":{},"folder":"folder:c5aedaa9-1450-4cf3-a103-74d652ba4c33","insertion_order":58,"keys":[""],"mode":"normal","name":"마법 물건: Staff of Fire","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"마법 물건: Staff of Frost","constant":false,"content":"## Staff of Frost (서리의 지팡이) - magic item, SRD 5.2.1\nStaff, Very Rare (Requires Attunement by a Druid, Sorcerer, Warlock, or Wizard).\nYou have Resistance to Cold damage while you hold this staff. Spells. The staff has 10 charges. While holding the staff, you can cast one of the spells on the following table from it, using your spell save DC. The table indicates how many charges you must expend to cast the spell. Spell Charge Cost Spell Charge Cost Cone of Cold 5 Ice Storm 4 Fog Cloud 1 Wall of Ice 4 Regaining Charges. The staff regains 1d6 + 4 expended charges daily at dawn. If you expend the last charge, roll 1d20. On a 1, the staff turns to water and is destroyed.","enabled":true,"extensions":{},"folder":"folder:c5aedaa9-1450-4cf3-a103-74d652ba4c33","insertion_order":58,"keys":[""],"mode":"normal","name":"마법 물건: Staff of Frost","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"마법 물건: Staff of Healing","constant":false,"content":"## Staff of Healing (치유의 지팡이) - magic item, SRD 5.2.1\nStaff, Rare (Requires Attunement by a Bard, Cleric, or Druid).\nThis staff has 10 charges. While holding the staff, you can cast one of the spells on the following table from it, using your spellcasting ability modifier. The table indicates how many charges you must expend to cast the spell. Spell Charge Cost Cure Wounds 1 charge per spell level (maximum 4 for a level 4 spell) Lesser Restoration 2 Mass Cure Wounds 5 Regaining Charges. The staff regains 1d6 + 4 expended charges daily at dawn. If you expend the last charge, roll 1d20. On a 1, the staff vanishes in a flash of light, lost forever.","enabled":true,"extensions":{},"folder":"folder:c5aedaa9-1450-4cf3-a103-74d652ba4c33","insertion_order":58,"keys":[""],"mode":"normal","name":"마법 물건: Staff of Healing","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"마법 물건: Staff of Power","constant":false,"content":"## Staff of Power (권능의 지팡이) - magic item, SRD 5.2.1\nStaff, Very Rare (Requires Attunement by a Sorcerer, Warlock, or Wizard).\nThis staff has 20 charges and can be wielded as a magic Quarterstaff that grants a +2 bonus to attack rolls and damage rolls made with it. While holding it, you gain a +2 bonus to Armor Class, saving throws, and spell attack rolls. Spells. While holding the staff, you can cast one of the spells on the following table from it, using your spell save DC. The table indicates how many charges you must expend to cast the spell. 246 Spell Charge Cost Cone of Cold 5 Fireball (level 5 version) 5 Globe of Invulnerability 6 Hold Monster 5 Levitate 2 Lightning Bolt (level 5 version) 5 Magic Missile 1 Ray of Enfeeblement 1 Wall of Force 5 Regaining Charges. The staff regains 2d8 + 4 expended charges daily at dawn. If you expend the last charge, roll 1d20. On a 1, the staff retains its +2 bonus to attack rolls and damage rolls but loses all other properties. On a 20, the staff regains 1d8 + 2 charges. Retributive Strike. You can take a Magic action to break the staff over your knee or against a solid surface. The staff is destroyed and releases its magic in an explosion that fills a 30-foot Emanation originating from itself. You have a 50 percent chance to instantly travel to a random plane of existence, avoiding the explosion. If you fail to avoid the effect, you take Force damage equal to 16 times the number of charges in the staff. Each other creature in the area makes a DC 17 Dexterity saving throw. On a failed save, a creature takes Force damage equal to 4 times the number of charges in the staff. On a successful save, a creature takes half as much damage.","enabled":true,"extensions":{},"folder":"folder:c5aedaa9-1450-4cf3-a103-74d652ba4c33","insertion_order":58,"keys":[""],"mode":"normal","name":"마법 물건: Staff of Power","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"마법 물건: Staff of Striking","constant":false,"content":"## Staff of Striking (타격의 지팡이) - magic item, SRD 5.2.1\nStaff, Very Rare (Requires Attunement).\nThis staff can be wielded as a magic Quarterstaff that grants a +3 bonus to attack rolls and damage rolls made with it. The staff has 10 charges. When you hit with a melee attack using it, you can expend up to 3 charges. For each charge you expend, the target takes an extra 1d6 Force damage. Regaining Charges. The staff regains 1d6 + 4 expended charges daily at dawn. If you expend the last charge, roll 1d20. On a 1, the staff becomes a nonmagical Quarterstaff.","enabled":true,"extensions":{},"folder":"folder:c5aedaa9-1450-4cf3-a103-74d652ba4c33","insertion_order":58,"keys":[""],"mode":"normal","name":"마법 물건: Staff of Striking","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"마법 물건: Staff of Swarming Insects","constant":false,"content":"## Staff of Swarming Insects (벌레 떼의 지팡이) - magic item, SRD 5.2.1\nStaff, Rare (Requires Attunement by a Bard, Cleric, Druid, Sorcerer, Warlock, or Wizard).\nThis staff has 10 charges. Insect Cloud. While holding the staff, you can take a Magic action and expend 1 charge to cause a swarm of harmless flying insects to fill a 30foot Emanation originating from you. The insects remain for 10 minutes, making the area Heavily Obscured for creatures other than you. A strong wind (like that created by Gust of Wind) disperses the swarm and ends the effect. Spells. While holding the staff, you can cast one of the spells on the following table from it, using your spell save DC and spell attack modifier. The table indicates how many charges you must expend to cast the spell. Spell Charge Cost Giant Insect 4 Insect Plague 5 Regaining Charges. The staff regains 1d6 + 4 expended charges daily at dawn. If you expend the last charge, roll 1d20. On a 1, a swarm of insects consumes and destroys the staff, then disperses.","enabled":true,"extensions":{},"folder":"folder:c5aedaa9-1450-4cf3-a103-74d652ba4c33","insertion_order":58,"keys":[""],"mode":"normal","name":"마법 물건: Staff of Swarming Insects","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"마법 물건: Staff of the Magi","constant":false,"content":"## Staff of the Magi (마도사의 지팡이) - magic item, SRD 5.2.1\nStaff, Legendary (Requires Attunement by a Sorcerer, Warlock, or Wizard).\nThis staff has 50 charges and can be wielded as a magic Quarterstaff that grants a +2 bonus to attack rolls and damage rolls made with it. While you hold it, you gain a +2 bonus to spell attack rolls. Spell Absorption. While holding the staff, you have Advantage on saving throws against spells. In addition, you can take a Reaction when another creature casts a spell that targets only you. If you do, the staff absorbs the magic of the spell, canceling its effect and gaining a number of charges equal to the absorbed spell's level. However, if doing so brings the staff's total number of charges above 50, the staff explodes as if you activated its Retributive Strike (see below). Spells. While holding the staff, you can cast one of the spells on the following table from it, using your spell save DC. The table indicates how many charges you must expend to cast the spell. Spell Charge Cost Arcane Lock 0 Conjure Elemental 7 Detect Magic 0 Dispel Magic 3 Enlarge/Reduce 0 Fireball (level 7 version) 7 Flaming Sphere 2 Ice Storm 4 Invisibility 2 Knock 2 Light 0 Lightning Bolt (level 7 version) 7 247 Spell Charge Cost Mage Hand 0 Passwall 5 Plane Shift 7 Protection from Evil and Good 0 Telekinesis 5 Wall of Fire 4 Web 2 Regaining Charges. The staff regains 4d6 + 2 expended charges daily at dawn. If you expend the last charge, roll 1d20. On a 20, the staff regains 1d12 + 1 charges. Retributive Strike. You can take a Magic action to break the staff over your knee or against a solid surface. The staff is destroyed and releases its magic in an explosion that fills a 30-foot Emanation originating from itself. You have a 50 percent chance to instantly travel to a random plane of existence, avoiding the explosion. If you fail to avoid the effect, you take Force damage equal to 16 times the number of charges in the staff. Each other creature in the area makes a DC 17 Dexterity saving throw. On a failed save, a creature takes Force damage equal to 6 times the number of charges in the staff. On a successful save, a creature takes half as much damage.","enabled":true,"extensions":{},"folder":"folder:c5aedaa9-1450-4cf3-a103-74d652ba4c33","insertion_order":58,"keys":[""],"mode":"normal","name":"마법 물건: Staff of the Magi","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"마법 물건: Staff of the Python","constant":false,"content":"## Staff of the Python (비단뱀의 지팡이) - magic item, SRD 5.2.1\nStaff, Uncommon (Requires Attunement).\nAs a Magic action, you can throw this staff so that it lands in an unoccupied space within 10 feet of you, causing the staff to become a Giant Constrictor Snake in that space. The snake is under your control and shares your Initiative count, taking its turn immediately after yours. On your turn, you can mentally command the snake (no action required) if it is within 60 feet of you and you don't have the Incapacitated condition. You decide what action the snake takes and where it moves during its turn, or you can issue it a general command, such as to attack your enemies or guard a location. Absent commands from you, the snake defends itself. As a Bonus Action, you can command the snake to revert to staff form in its current space, and you can't use the staff's property again for 1 hour. If the snake is reduced to 0 Hit Points, it dies and reverts to its staff form; the staff then shatters and is destroyed. If the snake reverts to staff form before losing all its Hit Points, it regains all of them.","enabled":true,"extensions":{},"folder":"folder:c5aedaa9-1450-4cf3-a103-74d652ba4c33","insertion_order":58,"keys":[""],"mode":"normal","name":"마법 물건: Staff of the Python","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"마법 물건: Staff of the Woodlands","constant":false,"content":"## Staff of the Woodlands (숲의 지팡이) - magic item, SRD 5.2.1\nStaff, Rare (Requires Attunement by a Druid).\nThis staff has 6 charges and can be wielded as a magic Quarterstaff that grants a +2 bonus to attack rolls and damage rolls made with it. While holding it, you have a +2 bonus to spell attack rolls. Spells. While holding the staff, you can cast one of the spells on the following table from it, using your spell save DC. The table indicates how many charges you must expend to cast the spell. Spell Charge Cost Animal Friendship 1 Awaken 5 Barkskin 2 Locate Animals or Plants 2 Pass without Trace 2 Speak with Animals 1 Speak with Plants 3 Wall of Thorns 6 Tree Form. You can take a Magic action to plant one end of the staff in earth in an unoccupied space and expend 1 charge to transform the staff into a healthy tree. The tree is 60 feet tall and has a 5-foot-diameter trunk, and its branches at the top spread out in a 20-foot radius. The tree appears ordinary but radiates a faint aura of Transmutation magic that can be discerned with the Detect Magic spell. While touching the tree and using a Magic action, you return the staff to its normal form. Any creature in the tree falls when the tree reverts to a staff. Regaining Charges. The staff regains 1d6 expended charges daily at dawn. If you expend the last charge, roll 1d20. On a 1, the staff loses its properties and becomes a nonmagical Quarterstaff.","enabled":true,"extensions":{},"folder":"folder:c5aedaa9-1450-4cf3-a103-74d652ba4c33","insertion_order":58,"keys":[""],"mode":"normal","name":"마법 물건: Staff of the Woodlands","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"마법 물건: Staff of Thunder and Lightning","constant":false,"content":"## Staff of Thunder and Lightning (천둥 번개의 지팡이) - magic item, SRD 5.2.1\nStaff, Very Rare (Requires Attunement).\nThis staff can be wielded as a magic Quarterstaff that grants a +2 bonus to attack rolls and damage rolls made with it. It also has the following additional properties. Once one of these properties is used, it can't be used again until the next dawn. Lightning. When you hit with a melee attack using the staff, you can cause the target to take an extra 2d6 Lightning damage (no action required). Thunder. When you hit with a melee attack using the staff, you can cause the staff to emit a crack of thunder audible out to 300 feet (no action required). The target you hit must succeed on a DC 17 Constitution saving throw or have the Stunned condition until the end of your next turn. 248 Thunder and Lightning. Immediately after you hit with a melee attack using the staff, you can take a Bonus Action to use the Lightning and Thunder properties (see above) at the same time. Doing so doesn't expend the daily use of those properties, only the use of this one. Lightning Strike. You can take a Magic action to cause a bolt of lightning to leap from the staff's tip in a Line that is 5 feet wide and 120 feet long. Each creature in that Line makes a DC 17 Dexterity saving throw, taking 9d6 Lightning damage on a failed save or half as much damage on a successful one. Thunderclap. You can take a Magic action to cause the staff to produce a thunderclap audible out to 600 feet. Every creature within a 60-foot Emanation originating from you makes a DC 17 Constitution saving throw. On a failed save, a creature takes 2d6 Thunder damage and has the Deafened condition for 1 minute. On a successful save, a creature takes half as much damage only.","enabled":true,"extensions":{},"folder":"folder:c5aedaa9-1450-4cf3-a103-74d652ba4c33","insertion_order":58,"keys":[""],"mode":"normal","name":"마법 물건: Staff of Thunder and Lightning","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"마법 물건: Staff of Withering","constant":false,"content":"## Staff of Withering (시듦의 지팡이) - magic item, SRD 5.2.1\nStaff, Rare (Requires Attunement).\nThis staff has 3 charges and regains 1d3 expended charges daily at dawn. The staff can be wielded as a magic Quarterstaff. On a hit, it deals damage as a normal Quarterstaff, and you can expend 1 charge to deal an extra 2d10 Necrotic damage to the target and force it to make a DC 15 Constitution saving throw. On a failed save, the target has Disadvantage for 1 hour on any ability check or saving throw that uses Strength or Constitution.","enabled":true,"extensions":{},"folder":"folder:c5aedaa9-1450-4cf3-a103-74d652ba4c33","insertion_order":58,"keys":[""],"mode":"normal","name":"마법 물건: Staff of Withering","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"마법 물건: Stone of Controlling Earth Elementals","constant":false,"content":"## Stone of Controlling Earth Elementals (대지 원소 조종의 돌) - magic item, SRD 5.2.1\nWondrous Item, Rare.\nWhile touching this 5-pound stone to the ground, you can take a Magic action to summon an Earth Elemental. The elemental appears in an unoccupied space you choose within 30 feet of yourself, obeys your commands, and takes its turn immediately after you on your Initiative count. The elemental disappears after 1 hour, when it dies, or when you dismiss it as a Bonus Action. The stone can't be used this way again until the next dawn.","enabled":true,"extensions":{},"folder":"folder:c5aedaa9-1450-4cf3-a103-74d652ba4c33","insertion_order":58,"keys":[""],"mode":"normal","name":"마법 물건: Stone of Controlling Earth Elementals","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"마법 물건: Stone of Good Luck (Luckstone)","constant":false,"content":"## Stone of Good Luck (Luckstone) (행운의 돌) - magic item, SRD 5.2.1\nWondrous Item, Uncommon (Requires Attunement).\nWhile this polished agate is on your person, you gain a +1 bonus to ability checks and saving throws.","enabled":true,"extensions":{},"folder":"folder:c5aedaa9-1450-4cf3-a103-74d652ba4c33","insertion_order":58,"keys":[""],"mode":"normal","name":"마법 물건: Stone of Good Luck (Luckstone)","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"마법 물건: Sun Blade","constant":false,"content":"## Sun Blade (태양의 검) - magic item, SRD 5.2.1\nWeapon (Longsword), Rare (Requires Attunement).\nThis item appears to be a sword hilt. Blade of Radiance. While grasping the hilt, you can take a Bonus Action to cause a blade of pure radiance to spring into existence or make the blade disappear. While the blade exists, this magic weapon functions as a Longsword with the Finesse property. If you are proficient with Longswords or Shortswords, you are proficient with the Sun Blade. You gain a +2 bonus to attack rolls and damage rolls made with this weapon, which deals Radiant damage instead of Slashing damage. When you hit an Undead with it, that target takes an extra 1d8 Radiant damage. Sunlight. The sword's luminous blade emits Bright Light in a 15-foot radius and Dim Light for an additional 15 feet. The light is sunlight. While the blade persists, you can take a Magic action to expand or reduce its radius of Bright Light and Dim Light by 5 feet each, to a maximum of 30 feet each or a minimum of 10 feet each.","enabled":true,"extensions":{},"folder":"folder:c5aedaa9-1450-4cf3-a103-74d652ba4c33","insertion_order":58,"keys":[""],"mode":"normal","name":"마법 물건: Sun Blade","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"마법 물건: Sword of Life Stealing","constant":false,"content":"## Sword of Life Stealing (생명 강탈의 검) - magic item, SRD 5.2.1\nWeapon (Glaive, Greatsword, Longsword, Rapier, Scimitar, or Shortsword), Rare (Requires Attunement).\nWhen you attack a creature with this magic weapon and roll a 20 on the d20 for the attack roll, that target takes an extra 15 Necrotic damage if it isn't a Construct or an Undead, and you gain Temporary Hit Points equal to the amount of Necrotic damage taken.","enabled":true,"extensions":{},"folder":"folder:c5aedaa9-1450-4cf3-a103-74d652ba4c33","insertion_order":58,"keys":[""],"mode":"normal","name":"마법 물건: Sword of Life Stealing","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"마법 물건: Sword of Sharpness","constant":false,"content":"## Sword of Sharpness (예리함의 검) - magic item, SRD 5.2.1\nWeapon (Glaive, Greatsword, Longsword, or Scimitar), Very Rare (Requires Attunement).\nWhen you attack an object with this magic weapon and hit, maximize your weapon damage dice against the target. When you attack a creature with this weapon and roll a 20 on the d20 for the attack roll, that target takes an extra 14 Slashing damage and gains 1 Exhaustion level.","enabled":true,"extensions":{},"folder":"folder:c5aedaa9-1450-4cf3-a103-74d652ba4c33","insertion_order":58,"keys":[""],"mode":"normal","name":"마법 물건: Sword of Sharpness","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"마법 물건: Sword of Wounding","constant":false,"content":"## Sword of Wounding (상처의 검) - magic item, SRD 5.2.1\nWeapon (Glaive, Greatsword, Longsword, Rapier, Scimitar, or Shortsword), Rare (Requires Attunement).\nWhen you hit a creature with an attack using this magic weapon, the target takes an extra 2d6 Necrotic damage and must succeed on a DC 15 Constitution saving throw or be unable to regain Hit Points for 1 hour. The target repeats the save at the end of each of its turns, ending the effect on itself on a success.","enabled":true,"extensions":{},"folder":"folder:c5aedaa9-1450-4cf3-a103-74d652ba4c33","insertion_order":58,"keys":[""],"mode":"normal","name":"마법 물건: Sword of Wounding","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"마법 물건: Talisman of Pure Good","constant":false,"content":"## Talisman of Pure Good (순수한 선의 부적) - magic item, SRD 5.2.1\nWondrous Item, Legendary (Requires Attunement by a Cleric or Paladin).\nThis talisman is a mighty symbol of goodness. A Fiend or an Undead that touches the talisman takes 8d6 Radiant damage and takes the damage again each time it ends its turn holding or carrying the talisman. 249 Holy Symbol. You can use the talisman as a Holy Symbol. You gain a +2 bonus to spell attack rolls while you wear or hold it. Pure Rebuke. The talisman has 7 charges. While wearing or holding the talisman, you can take a Magic action to expend 1 charge and target one creature you can see on the ground within 120 feet of yourself. A flaming fissure opens under the target, and the target makes a DC 20 Dexterity saving throw. If the target is a Fiend or an Undead, it has Disadvantage on the save. On a failed save, the target falls into the fissure and is destroyed, leaving no remains. On a successful save, the target isn't cast into the fissure but takes 4d6 Psychic damage from the ordeal. In either case, the fissure then closes, leaving no trace of its existence. When you expend the last charge, the talisman disperses into motes of golden light and is destroyed.","enabled":true,"extensions":{},"folder":"folder:c5aedaa9-1450-4cf3-a103-74d652ba4c33","insertion_order":58,"keys":[""],"mode":"normal","name":"마법 물건: Talisman of Pure Good","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"마법 물건: Talisman of the Sphere","constant":false,"content":"## Talisman of the Sphere (구체의 부적) - magic item, SRD 5.2.1\nWondrous Item, Legendary (Requires Attunement).\nWhile holding or wearing this talisman, you have Advantage on any Intelligence (Arcana) check you make to control a Sphere of Annihilation. In addition, when you start your turn in control of a Sphere of Annihilation, you can take a Magic action to move it 10 feet plus a number of additional feet equal to 10 times your Intelligence modifier. This movement doesn't have to be in a straight line.","enabled":true,"extensions":{},"folder":"folder:c5aedaa9-1450-4cf3-a103-74d652ba4c33","insertion_order":58,"keys":[""],"mode":"normal","name":"마법 물건: Talisman of the Sphere","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"마법 물건: Talisman of Ultimate Evil","constant":false,"content":"## Talisman of Ultimate Evil (궁극의 악의 부적) - magic item, SRD 5.2.1\nWondrous Item, Legendary (Requires Attunement).\nThis item symbolizes unrepentant evil. A creature that isn't a Fiend or an Undead that touches the talisman takes 8d6 Necrotic damage and takes the damage again each time it ends its turn holding or carrying the talisman. Holy Symbol. You can use the talisman as a Holy Symbol. You gain a +2 bonus to spell attack rolls while you wear or hold it. Ultimate End. The talisman has 6 charges. While wearing or holding the talisman, you can take a Magic action to expend 1 charge and target one creature you can see on the ground within 120 feet of yourself. A flaming fissure opens under the target, and the target makes a DC 20 Dexterity saving throw. If the target is a Celestial, it has Disadvantage on the save. On a failed save, the target falls into the fissure and is destroyed, leaving no remains. On a successful save, the target isn't cast into the fissure but takes 4d6 Psychic damage from the ordeal. In either case, the fissure then closes, leaving no trace of its existence. When you expend the last charge, the talisman dissolves into foul-smelling slime and is destroyed.","enabled":true,"extensions":{},"folder":"folder:c5aedaa9-1450-4cf3-a103-74d652ba4c33","insertion_order":58,"keys":[""],"mode":"normal","name":"마법 물건: Talisman of Ultimate Evil","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"마법 물건: Thunderous Greatclub","constant":false,"content":"## Thunderous Greatclub (천둥의 그레이트클럽) - magic item, SRD 5.2.1\nWeapon (Greatclub), Very Rare (Requires Attunement).\nWhile you are attuned to this magic weapon, your Strength is 20 unless your Strength is already equal to or greater than that score. The weapon deals an extra 1d8 Thunder damage to any creature it hits and an extra 3d8 Thunder damage to objects it hits that aren't being worn or carried. The weapon has the following additional properties. Clap of Thunder. As a Magic action, you can strike the weapon against a hard surface to create a loud clap of thunder audible out to 300 feet. You also create a 30-foot Cone of thunderous energy. Each creature in the Cone must succeed on a DC 15 Strength saving throw or have the Prone condition. Nonmagical objects in the Cone that aren't being worn or carried take 3d8 Thunder damage. Earthquake. As a Magic action, you can strike the weapon against the ground to create an intense seismic disturbance in a 50-foot-radius circle centered on the point of impact. Structures in contact with the ground in that area take 50 Bludgeoning damage, and each creature on the ground in that area must succeed on a DC 20 Dexterity saving throw or have the Prone condition. If that creature is also concentrating, it must succeed on a DC 20 Constitution saving throw, or its Concentration is broken. In addition, you can cause a 30-foot-deep, 10-foot-wide fissure to open up on the ground anywhere in the area. Any creature on a spot where the fissure opens must make a DC 20 Dexterity saving throw, falling into the fissure on a failed save or moving with the fissure's edge on a successful one. Any structure on a spot where the fissure opens collapses into the fissure. Once you use this property, it can't be used again until the next dawn.","enabled":true,"extensions":{},"folder":"folder:c5aedaa9-1450-4cf3-a103-74d652ba4c33","insertion_order":58,"keys":[""],"mode":"normal","name":"마법 물건: Thunderous Greatclub","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"마법 물건: Tome of Clear Thought","constant":false,"content":"## Tome of Clear Thought (명석한 사고의 책) - magic item, SRD 5.2.1\nWondrous Item, Very Rare.\nThis book contains memory and logic exercises, and its words are charged with magic. If you spend 48 hours over a period of 6 days or fewer studying the book's contents and practicing its guidelines, your Intelligence increases by 2, to a maximum of 30. The manual then loses its magic but regains it in a century.","enabled":true,"extensions":{},"folder":"folder:c5aedaa9-1450-4cf3-a103-74d652ba4c33","insertion_order":58,"keys":[""],"mode":"normal","name":"마법 물건: Tome of Clear Thought","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"마법 물건: Tome of Leadership and Influence","constant":false,"content":"## Tome of Leadership and Influence (지도력과 영향력의 책) - magic item, SRD 5.2.1\nWondrous Item, Very Rare.\nThis book contains guidelines for influencing and charming others, and its words are charged with magic. If you spend 48 hours over a period of 6 days or fewer studying the book's contents and practicing its guidelines, your Charisma increases by 2, to 250 a maximum of 30. The manual then loses its magic but regains it in a century.","enabled":true,"extensions":{},"folder":"folder:c5aedaa9-1450-4cf3-a103-74d652ba4c33","insertion_order":58,"keys":[""],"mode":"normal","name":"마법 물건: Tome of Leadership and Influence","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"마법 물건: Tome of Understanding","constant":false,"content":"## Tome of Understanding (이해의 책) - magic item, SRD 5.2.1\nWondrous Item, Very Rare.\nThis book contains intuition and insight exercises, and its words are charged with magic. If you spend 48 hours over a period of 6 days or fewer studying the book's contents and practicing its guidelines, your Wisdom increases by 2, to a maximum of 30. The manual then loses its magic, but regains it in a century.","enabled":true,"extensions":{},"folder":"folder:c5aedaa9-1450-4cf3-a103-74d652ba4c33","insertion_order":58,"keys":[""],"mode":"normal","name":"마법 물건: Tome of Understanding","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"마법 물건: Trident of Fish Command","constant":false,"content":"## Trident of Fish Command (물고기 지배의 트라이던트) - magic item, SRD 5.2.1\nWeapon (Trident), Uncommon (Requires Attunement).\nThis magic weapon has 3 charges, and it regains 1d3 expended charges daily at dawn. While you carry it, you can expend 1 charge to cast Dominate Beast (save DC 15) from it on a Beast that has a Swim Speed.","enabled":true,"extensions":{},"folder":"folder:c5aedaa9-1450-4cf3-a103-74d652ba4c33","insertion_order":58,"keys":[""],"mode":"normal","name":"마법 물건: Trident of Fish Command","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"마법 물건: Universal Solvent","constant":false,"content":"## Universal Solvent (만능 용해제) - magic item, SRD 5.2.1\nWondrous Item, Legendary.\nThis tube holds milky liquid with a strong alcohol smell. When found, a tube contains 1d6 + 1 ounces. You can take a Utilize action to pour 1 or more ounces of solvent from the tube onto a surface within reach. Each ounce instantly dissolves up to 1 square foot of adhesive it touches, including Sovereign Glue.","enabled":true,"extensions":{},"folder":"folder:c5aedaa9-1450-4cf3-a103-74d652ba4c33","insertion_order":58,"keys":[""],"mode":"normal","name":"마법 물건: Universal Solvent","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"마법 물건: Vicious Weapon","constant":false,"content":"## Vicious Weapon (잔혹한 무기) - magic item, SRD 5.2.1\nWeapon (Any Simple or Martial), Rare.\nThis magic weapon deals an extra 2d6 damage to any creature it hits. This extra damage is of the same type as the weapon's normal damage.","enabled":true,"extensions":{},"folder":"folder:c5aedaa9-1450-4cf3-a103-74d652ba4c33","insertion_order":58,"keys":[""],"mode":"normal","name":"마법 물건: Vicious Weapon","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"마법 물건: Vorpal Sword","constant":false,"content":"## Vorpal Sword (보팔 검) - magic item, SRD 5.2.1\nWeapon (Glaive, Greatsword, Longsword, or Scimitar), Legendary (Requires Attunement).\nYou gain a +3 bonus to attack rolls and damage rolls made with this magic weapon. In addition, the weapon ignores Resistance to Slashing damage. When you use this weapon to attack a creature that has at least one head and roll a 20 on the d20 for the attack roll, you cut off one of the creature's heads. The creature dies if it can't survive without the lost head. A creature is immune to this effect if it has Immunity to Slashing damage, if it doesn't have or need a head, or if the GM decides that the creature is too big for its head to be cut off with this weapon. Such a creature instead takes an extra 30 Slashing damage from the hit. If the creature has Legendary Resistance, it can expend one daily use of that trait to avoid losing its head, taking the extra damage instead.","enabled":true,"extensions":{},"folder":"folder:c5aedaa9-1450-4cf3-a103-74d652ba4c33","insertion_order":58,"keys":[""],"mode":"normal","name":"마법 물건: Vorpal Sword","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"마법 물건: Wand of Binding","constant":false,"content":"## Wand of Binding (속박의 완드) - magic item, SRD 5.2.1\nWand, Rare (Requires Attunement).\nThis wand has 7 charges. Spells. While holding the wand, you can cast one of the spells (save DC 17) on the following table from it. The table indicates how many charges you must expend to cast the spell. Spell Charge Cost Hold Monster 5 Hold Person 2 Regaining Charges. The wand regains 1d6 + 1 expended charges daily at dawn. If you expend the wand's last charge, roll 1d20. On a 1, the wand crumbles into ashes and is destroyed.","enabled":true,"extensions":{},"folder":"folder:c5aedaa9-1450-4cf3-a103-74d652ba4c33","insertion_order":58,"keys":[""],"mode":"normal","name":"마법 물건: Wand of Binding","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"마법 물건: Wand of Enemy Detection","constant":false,"content":"## Wand of Enemy Detection (적 탐지 완드) - magic item, SRD 5.2.1\nWand, Rare (Requires Attunement).\nThis wand has 7 charges. While holding it, you can take a Magic action to expend 1 charge. For 1 minute, you know the direction of the nearest creature Hostile to you within 60 feet, but not its distance from you. The wand can sense the presence of Hostile creatures that are Invisible, ethereal, disguised, or hidden, as well as those in plain sight. The effect ends if you stop holding the wand. Regaining Charges. The wand regains 1d6 + 1 expended charges daily at dawn. If you expend the wand's last charge, roll 1d20. On a 1, the wand crumbles into ashes and is destroyed.","enabled":true,"extensions":{},"folder":"folder:c5aedaa9-1450-4cf3-a103-74d652ba4c33","insertion_order":58,"keys":[""],"mode":"normal","name":"마법 물건: Wand of Enemy Detection","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"마법 물건: Wand of Fear","constant":false,"content":"## Wand of Fear (공포의 완드) - magic item, SRD 5.2.1\nWand, Rare (Requires Attunement).\nThis wand has 7 charges. Spells. While holding the wand, you can cast one of the spells (save DC 15) on the following table from it. The table indicates how many charges you must expend to cast the spell. Spell Charge Cost Command (“flee” or “grovel” only) 1 Fear (60-foot Cone) 3 Regaining Charges. The wand regains 1d6 + 1 expended charges daily at dawn. If you expend the wand's last charge, roll 1d20. On a 1, the wand crumbles into ashes and is destroyed.","enabled":true,"extensions":{},"folder":"folder:c5aedaa9-1450-4cf3-a103-74d652ba4c33","insertion_order":58,"keys":[""],"mode":"normal","name":"마법 물건: Wand of Fear","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"마법 물건: Wand of Fireballs","constant":false,"content":"## Wand of Fireballs (화염구 완드) - magic item, SRD 5.2.1\nWand, Rare (Requires Attunement by a Spellcaster).\nThis wand has 7 charges. While holding it, you can expend no more than 3 charges to cast Fireball (save DC 15) from it. For 1 charge, you cast the level 3 version of the spell. You can increase the spell's level by 1 for each additional charge you expend. 251 Regaining Charges. The wand regains 1d6 + 1 expended charges daily at dawn. If you expend the wand's last charge, roll 1d20. On a 1, the wand crumbles into ashes and is destroyed.","enabled":true,"extensions":{},"folder":"folder:c5aedaa9-1450-4cf3-a103-74d652ba4c33","insertion_order":58,"keys":[""],"mode":"normal","name":"마법 물건: Wand of Fireballs","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"마법 물건: Wand of Lightning Bolts","constant":false,"content":"## Wand of Lightning Bolts (번개 완드) - magic item, SRD 5.2.1\nWand, Rare (Requires Attunement by a Spellcaster).\nThis wand has 7 charges. While holding it, you can expend no more than 3 charges to cast Lightning Bolt (save DC 15) from it. For 1 charge, you cast the level 3 version of the spell. You can increase the spell's level by 1 for each additional charge you expend. Regaining Charges. The wand regains 1d6 + 1 expended charges daily at dawn. If you expend the wand's last charge, roll 1d20. On a 1, the wand crumbles into ashes and is destroyed.","enabled":true,"extensions":{},"folder":"folder:c5aedaa9-1450-4cf3-a103-74d652ba4c33","insertion_order":58,"keys":[""],"mode":"normal","name":"마법 물건: Wand of Lightning Bolts","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"마법 물건: Wand of Magic Detection","constant":false,"content":"## Wand of Magic Detection (마법 탐지 완드) - magic item, SRD 5.2.1\nWand, Uncommon.\nThis wand has 3 charges. While holding it, you can expend 1 charge to cast Detect Magic from it. The wand regains 1d3 expended charges daily at dawn.","enabled":true,"extensions":{},"folder":"folder:c5aedaa9-1450-4cf3-a103-74d652ba4c33","insertion_order":58,"keys":[""],"mode":"normal","name":"마법 물건: Wand of Magic Detection","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"마법 물건: Wand of Magic Missiles","constant":false,"content":"## Wand of Magic Missiles (마법 화살 완드) - magic item, SRD 5.2.1\nWand, Uncommon.\nThis wand has 7 charges. While holding it, you can expend no more than 3 charges to cast Magic Missile from it. For 1 charge, you cast the level 1 version of the spell. You can increase the spell's level by 1 for each additional charge you expend. Regaining Charges. The wand regains 1d6 + 1 expended charges daily at dawn. If you expend the wand's last charge, roll 1d20. On a 1, the wand crumbles into ashes and is destroyed.","enabled":true,"extensions":{},"folder":"folder:c5aedaa9-1450-4cf3-a103-74d652ba4c33","insertion_order":58,"keys":[""],"mode":"normal","name":"마법 물건: Wand of Magic Missiles","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"마법 물건: Wand of Paralysis","constant":false,"content":"## Wand of Paralysis (마비의 완드) - magic item, SRD 5.2.1\nWand, Rare (Requires Attunement by a Spellcaster).\nThis wand has 7 charges. While holding it, you can take a Magic action to expend 1 charge to cause a thin blue ray to streak from the tip toward a creature you can see within 60 feet of yourself. The target must succeed on a DC 15 Constitution saving throw or have the Paralyzed condition for 1 minute. At the end of each of the target's turns, it repeats the save, ending the effect on itself on a success. Regaining Charges. The wand regains 1d6 + 1 expended charges daily at dawn. If you expend the wand's last charge, roll 1d20. On a 1, the wand crumbles into ashes and is destroyed.","enabled":true,"extensions":{},"folder":"folder:c5aedaa9-1450-4cf3-a103-74d652ba4c33","insertion_order":58,"keys":[""],"mode":"normal","name":"마법 물건: Wand of Paralysis","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"마법 물건: Wand of Polymorph","constant":false,"content":"## Wand of Polymorph (변신 완드) - magic item, SRD 5.2.1\nWand, Very Rare (Requires Attunement by a Spellcaster).\nThis wand has 7 charges. While holding it, you can expend 1 charge to cast Polymorph (save DC 15) from it. Regaining Charges. The wand regains 1d6 + 1 expended charges daily at dawn. If you expend the wand's last charge, roll 1d20. On a 1, the wand crumbles into ashes and is destroyed.","enabled":true,"extensions":{},"folder":"folder:c5aedaa9-1450-4cf3-a103-74d652ba4c33","insertion_order":58,"keys":[""],"mode":"normal","name":"마법 물건: Wand of Polymorph","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"마법 물건: Wand of Secrets","constant":false,"content":"## Wand of Secrets (비밀의 완드) - magic item, SRD 5.2.1\nWand, Uncommon.\nThis wand has 3 charges and regains 1d3 expended charges daily at dawn. While holding it, you can take a Magic action to expend 1 charge, and if a secret door or trap is within 60 feet of you, the wand pulses and points at the one nearest to you.","enabled":true,"extensions":{},"folder":"folder:c5aedaa9-1450-4cf3-a103-74d652ba4c33","insertion_order":58,"keys":[""],"mode":"normal","name":"마법 물건: Wand of Secrets","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"마법 물건: Wand of the War Mage, +1, +2, or +3","constant":false,"content":"## Wand of the War Mage, +1, +2, or +3 (전투 마법사의 완드) - magic item, SRD 5.2.1\nWand, Uncommon (+1), Rare (+2), or Very Rare (+3) (Requires Attunement by a Spellcaster).\nWhile holding this wand, you gain a bonus to spell attack rolls determined by the wand's rarity. In addition, you ignore Half Cover when making a spell attack roll.","enabled":true,"extensions":{},"folder":"folder:c5aedaa9-1450-4cf3-a103-74d652ba4c33","insertion_order":58,"keys":[""],"mode":"normal","name":"마법 물건: Wand of the War Mage, +1, +2, or +3","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"마법 물건: Wand of Web","constant":false,"content":"## Wand of Web (거미줄 완드) - magic item, SRD 5.2.1\nWand, Uncommon (Requires Attunement by a Spellcaster).\nThis wand has 7 charges. While holding it, you can expend 1 charge to cast Web (save DC 13) from it. Regaining Charges. The wand regains 1d6 + 1 expended charges daily at dawn. If you expend the wand's last charge, roll 1d20. On a 1, the wand crumbles into ashes and is destroyed.","enabled":true,"extensions":{},"folder":"folder:c5aedaa9-1450-4cf3-a103-74d652ba4c33","insertion_order":58,"keys":[""],"mode":"normal","name":"마법 물건: Wand of Web","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"마법 물건: Wand of Wonder","constant":false,"content":"## Wand of Wonder (경이의 완드) - magic item, SRD 5.2.1\nWand, Rare (Requires Attunement).\nThis wand has 7 charges. While holding it, you can take a Magic action to expend 1 charge while choosing a point within 120 feet of yourself. That location becomes the point of origin of a spell or other magical effect determined by rolling on the Wand of Wonder Effects table. Spells cast from the wand have a save DC of 15. If a spell's maximum range is normally less than 120 feet, it becomes 120 feet when cast from the wand. If an effect has multiple possible subjects, the GM determines randomly which among them are affected. Regaining Charges. The wand regains 1d6 + 1 expended charges daily at dawn. If you expend the wand's last charge, roll 1d20. On a 1, the wand crumbles into dust and is destroyed. 252 Wand of Wonder Effects 1d100 Effect 01-20 You cast a spell originating from the chosen point. Roll 1d10 to determine the spell: on a 1-2, Darkness; on a 3-4, Faerie Fire; on a 5-6, Fireball; on a 7-8, Slow; on a 9-10, Stinking Cloud. 21-25 Nothing happens at the chosen point of origin. Instead, you have the Stunned condition until the start of your next turn, believing something awesome just happened. 26-30 You cast Gust of Wind. The Line created by the spell extends from you to the chosen point of origin. 31-35 Nothing happens at the chosen point of origin. Instead, you take 1d6 Psychic damage. 36-40 Heavy rain falls for 1 minute in a 120-foothigh, 60-foot-radius Cylinder centered on the chosen point of origin. During that time, the area of effect is Lightly Obscured. 41-45 A cloud of 600 oversized butterflies fills a 60-foot-high, 30-foot-radius Cylinder centered on the chosen point of origin. The butterflies remain for 10 minutes, during which time the area of effect is Heavily Obscured. 46-50 You cast Lightning Bolt. The Line created by the spell extends from you to the chosen point of origin. 51-55 The creature closest to the chosen point of origin is enlarged as if you had cast Enlarge/ Reduce on it. If the target isn't you and can't be affected by that spell, you become the target instead. 56-60 A magically formed creature appears in an unoccupied space as close to the chosen point of origin as possible. The creature isn't under your control, acts as it normally would, and disappears after 1 hour or when it drops to 0 Hit Points. Roll 1d4 to determine which creature appears. On a 1, a Rhinoceros appears; on a 2, an Elephant appears; and on a 3-4, a Rat appears. 61-64 Grass covers a 60-foot-radius circle of ground, with the center of that circle as close to the chosen point of origin as possible. Grass that's already there grows to ten times its normal size and remains overgrown for 1 minute. 1d100 Effect 65-68 An object of the GM's choice disappears into the Ethereal Plane. The object must be neither worn nor carried, within 120 feet of the chosen point of origin, and no larger than 10 feet in any dimension. If there are no such objects in range, nothing happens. 69-72 Nothing happens at the chosen point of origin. Instead, you shrink as if you had cast Enlarge/ Reduce on yourself and remain in that state for 1 minute. 73-77 Leaves grow from the creature nearest to the chosen point of origin. Unless they are picked off, the leaves turn brown and fall off after 24 hours. 78-82 Nothing happens at the chosen point of origin. Instead, a burst of colorful, shimmering light extends from you in a 30-foot Emanation. Each creature in the area must succeed on a DC 15 Constitution saving throw or have the Blinded condition for 1 minute. A creature repeats the save at the end of each of its turns, ending the effect on itself on a success. 83-87 Nothing happens at the chosen point of origin. Instead, you cast Invisibility on yourself. 88-92 Nothing happens at the chosen point of origin. Instead, a stream of 1d4 × 10 gems, each worth 1 GP, shoots from the wand's tip in a Line 30 feet long and 5 feet wide toward the chosen point of origin. Each gem deals 1 Bludgeoning damage, and the total damage of the gems is divided equally among all creatures in the Line. 93-97 You cast Polymorph, targeting the creature closest to the chosen point of origin. Roll 1d4 to determine the target's new form. On a 1, the new form is a Black Bear; on a 2, the new form is a Giant Wasp; on a 3-4, the new form is a Frog. 98-00 The creature closest to the chosen point of origin makes a DC 15 Constitution saving throw. On a failed save, the creature has the Restrained condition and begins to turn to stone. While Restrained in this way, the creature repeats the save at the end of its next turn. On a successful save, the effect ends. On a failed save, the creature has the Petrified condition instead of the Restrained condition. The petrification lasts until the creature is freed by the Greater Restoration spell or similar magic. 253","enabled":true,"extensions":{},"folder":"folder:c5aedaa9-1450-4cf3-a103-74d652ba4c33","insertion_order":58,"keys":[""],"mode":"normal","name":"마법 물건: Wand of Wonder","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"마법 물건: Weapon, +1, +2, or +3","constant":false,"content":"## Weapon, +1, +2, or +3 (+1·+2·+3 무기) - magic item, SRD 5.2.1\nWeapon (Any Simple or Martial), Uncommon (+1), Rare (+2), or Very Rare (+3).\nYou have a bonus to attack rolls and damage rolls made with this magic weapon. The bonus is determined by the weapon's rarity.","enabled":true,"extensions":{},"folder":"folder:c5aedaa9-1450-4cf3-a103-74d652ba4c33","insertion_order":58,"keys":[""],"mode":"normal","name":"마법 물건: Weapon, +1, +2, or +3","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"마법 물건: Weapon of Warning","constant":false,"content":"## Weapon of Warning (경고의 무기) - magic item, SRD 5.2.1\nWeapon (Any Simple or Martial), Uncommon (Requires Attunement).\nAs long as this weapon is within your reach and you are attuned to it, you and allies within 30 feet of you gain the following benefits. Alarm. The weapon magically awakens each subject who is sleeping naturally when combat begins. This benefit doesn't wake a subject from magically induced sleep. Supernatural Readiness. Each subject has Advantage on its Initiative rolls.","enabled":true,"extensions":{},"folder":"folder:c5aedaa9-1450-4cf3-a103-74d652ba4c33","insertion_order":58,"keys":[""],"mode":"normal","name":"마법 물건: Weapon of Warning","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"마법 물건: Well of Many Worlds","constant":false,"content":"## Well of Many Worlds (여러 세계의 우물) - magic item, SRD 5.2.1\nWondrous Item, Legendary.\nThis fine black cloth, soft as silk, is folded up to the dimensions of a handkerchief. It unfolds into a circular sheet 6 feet in diameter. You can take a Magic action to unfold the Well of Many Worlds and place it on a solid surface, whereupon it forms a two-way, 6-foot-diameter, circular portal to another world or plane of existence. Each time the item opens a portal, the GM decides where it leads. The portal remains open until a creature within 5 feet of it takes a Magic action to close it by taking hold of the edges of the cloth and folding it up. Once the Well of Many Worlds has opened a portal, it can't do so again for 1d8 hours.","enabled":true,"extensions":{},"folder":"folder:c5aedaa9-1450-4cf3-a103-74d652ba4c33","insertion_order":58,"keys":[""],"mode":"normal","name":"마법 물건: Well of Many Worlds","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"마법 물건: Wind Fan","constant":false,"content":"## Wind Fan (바람 부채) - magic item, SRD 5.2.1\nWondrous Item, Uncommon.\nWhile holding this fan, you can cast Gust of Wind (save DC 13) from it. Each subsequent time the fan is used before the next dawn, it has a cumulative 20 percent chance of not working; if the fan fails to work, it tears into useless, nonmagical tatters.","enabled":true,"extensions":{},"folder":"folder:c5aedaa9-1450-4cf3-a103-74d652ba4c33","insertion_order":58,"keys":[""],"mode":"normal","name":"마법 물건: Wind Fan","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"마법 물건: Winged Boots","constant":false,"content":"## Winged Boots (날개 달린 장화) - magic item, SRD 5.2.1\nWondrous Item, Uncommon (Requires Attunement).\nThese boots have 4 charges and regain 1d4 expended charges daily at dawn. While wearing the boots, you can take a Magic action to expend 1 charge, gaining a Fly Speed of 30 feet for 1 hour. If you are flying when the duration expires, you descend at a rate of 30 feet per round until you land.","enabled":true,"extensions":{},"folder":"folder:c5aedaa9-1450-4cf3-a103-74d652ba4c33","insertion_order":58,"keys":[""],"mode":"normal","name":"마법 물건: Winged Boots","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"마법 물건: Wings of Flying","constant":false,"content":"## Wings of Flying (비행의 날개) - magic item, SRD 5.2.1\nWondrous Item, Rare (Requires Attunement).\nWhile wearing this cloak, you can take a Magic action to turn the cloak into a pair of wings on your back. The wings lasts for 1 hour or until you end the effect early as a Magic action. The wings give you a Fly Speed of 60 feet. If you are aloft when the wings disappear, you fall. When the wings disappear, you can't use them again for 1d12 hours.","enabled":true,"extensions":{},"folder":"folder:c5aedaa9-1450-4cf3-a103-74d652ba4c33","insertion_order":58,"keys":[""],"mode":"normal","name":"마법 물건: Wings of Flying","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"규칙 · 조우표","constant":false,"content":"","enabled":true,"extensions":{},"insertion_order":55,"keys":["folder:8e7632a1-83a1-4249-97a8-a36c653e3a8b"],"mode":"folder","name":"규칙 · 조우표","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"조우표: 설원","constant":false,"content":"## Encounter table: Arctic (설원) - SRD monsters up to CR 8, by habitat\nChoose from here so the monsters fit the place. Add up their XP against the encounter XP budget in GAME STATE.\n- CR 1/2 (100 XP): Ice Mephit\n- CR 2 (450 XP): Polar Bear, Saber-Toothed Tiger, White Dragon Wyrmling\n- CR 3 (700 XP): Killer Whale, Winter Wolf\n- CR 5 (1800 XP): Werebear\n- CR 6 (2300 XP): Mammoth, Young White Dragon\n- CR 8 (3900 XP): Frost Giant\n- CR 11 (7200 XP): Remorhaz\n- CR 13 (10000 XP): Adult White Dragon\n- CR 20 (25000 XP): Ancient White Dragon","enabled":true,"extensions":{},"folder":"folder:8e7632a1-83a1-4249-97a8-a36c653e3a8b","insertion_order":55,"keys":[""],"mode":"normal","name":"조우표: 설원","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"조우표: 해안","constant":false,"content":"## Encounter table: Coastal (해안) - SRD monsters up to CR 8, by habitat\nChoose from here so the monsters fit the place. Add up their XP against the encounter XP budget in GAME STATE.\n- CR 0 (10 XP): Crab\n- CR 1/8 (25 XP): Bandit, Blood Hawk, Giant Crab, Merfolk Skirmisher\n- CR 1/4 (50 XP): Pteranodon, Steam Mephit, Swarm of Ravens\n- CR 1/2 (100 XP): Reef Shark, Sahuagin Warrior\n- CR 1 (200 XP): Copper Dragon Wyrmling, Giant Eagle, Harpy, Pirate\n- CR 2 (450 XP): Bandit Captain, Bronze Dragon Wyrmling, Hunter Shark, Merrow, Plesiosaurus, Sea Hag\n- CR 4 (1100 XP): Archelon\n- CR 5 (1800 XP): Water Elemental\n- CR 6 (2300 XP): Pirate Captain\n- CR 8 (3900 XP): Young Bronze Dragon\n- CR 9 (5000 XP): Young Blue Dragon\n- CR 11 (7200 XP): Roc\n- CR 13 (10000 XP): Storm Giant\n- CR 14 (11500 XP): Adult Copper Dragon\n- CR 15 (13000 XP): Adult Bronze Dragon\n- CR 17 (18000 XP): Dragon Turtle\n- CR 22 (41000 XP): Ancient Bronze Dragon\n- CR 23 (50000 XP): Ancient Blue Dragon, Kraken","enabled":true,"extensions":{},"folder":"folder:8e7632a1-83a1-4249-97a8-a36c653e3a8b","insertion_order":55,"keys":[""],"mode":"normal","name":"조우표: 해안","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"조우표: 사막","constant":false,"content":"## Encounter table: Desert (사막) - SRD monsters up to CR 8, by habitat\nChoose from here so the monsters fit the place. Add up their XP against the encounter XP budget in GAME STATE.\n- CR 0 (10 XP): Hyena, Jackal, Lizard, Scorpion, Vulture\n- CR 1/8 (25 XP): Camel, Flying Snake, Venomous Snake\n- CR 1/4 (50 XP): Constrictor Snake, Giant Lizard\n- CR 1/2 (100 XP): Dust Mephit, Gnoll Warrior\n- CR 1 (200 XP): Brass Dragon Wyrmling, Death Dog, Giant Hyena, Giant Vulture, Sphinx of Wonder\n- CR 3 (700 XP): Blue Dragon Wyrmling, Giant Scorpion, Mummy\n- CR 4 (1100 XP): Couatl, Lamia\n- CR 5 (1800 XP): Air Elemental, Earth Elemental\n- CR 6 (2300 XP): Young Brass Dragon\n- CR 9 (5000 XP): Young Blue Dragon\n- CR 11 (7200 XP): Djinni, Efreeti, Sphinx of Lore\n- CR 13 (10000 XP): Adult Brass Dragon\n- CR 15 (13000 XP): Mummy Lord, Purple Worm\n- CR 16 (15000 XP): Adult Blue Dragon\n- CR 17 (18000 XP): Sphinx of Valor\n- CR 20 (25000 XP): Ancient Brass Dragon\n- CR 23 (50000 XP): Ancient Blue Dragon","enabled":true,"extensions":{},"folder":"folder:8e7632a1-83a1-4249-97a8-a36c653e3a8b","insertion_order":55,"keys":[""],"mode":"normal","name":"조우표: 사막","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"조우표: 숲","constant":false,"content":"## Encounter table: Forest (숲) - SRD monsters up to CR 8, by habitat\nChoose from here so the monsters fit the place. Add up their XP against the encounter XP budget in GAME STATE.\n- CR 0 (10 XP): Awakened Shrub, Baboon, Badger, Bat, Cat, Deer, Hawk, Lizard, Owl, Raven, Spider, Weasel\n- CR 1/8 (25 XP): Bandit, Flying Snake, Giant Weasel, Goblin Minion, Stirge\n- CR 1/4 (50 XP): Blink Dog, Boar, Elk, Giant Badger, Giant Centipede, Giant Owl, Giant Wolf Spider, Goblin Warrior, Panther, Pseudodragon, Sprite, Swarm of Ravens, Violet Fungus, Wolf\n- CR 1/2 (100 XP): Ape, Black Bear, Cockatrice, Giant Wasp, Hobgoblin Warrior, Satyr, Scout, Swarm of Insects, Worg\n- CR 1 (200 XP): Brown Bear, Bugbear Warrior, Dire Wolf, Dryad, Giant Spider, Goblin Boss, Tiger\n- CR 2 (450 XP): Awakened Tree, Bandit Captain, Centaur Trooper, Druid, Ettercap, Giant Boar, Giant Elk, Green Dragon Wyrmling, Ogre, Will-o'-Wisp\n- CR 3 (700 XP): Bugbear Stalker, Green Hag, Hobgoblin Captain, Owlbear, Phase Spider, Werewolf\n- CR 4 (1100 XP): Wereboar, Weretiger\n- CR 5 (1800 XP): Night Hag, Shambling Mound, Troll, Unicorn, Werebear\n- CR 7 (2900 XP): Giant Ape\n- CR 8 (3900 XP): Young Green Dragon\n- CR 9 (5000 XP): Treant\n- CR 10 (5900 XP): Young Gold Dragon\n- CR 15 (13000 XP): Adult Green Dragon\n- CR 17 (18000 XP): Adult Gold Dragon\n- CR 22 (41000 XP): Ancient Green Dragon\n- CR 24 (62000 XP): Ancient Gold Dragon","enabled":true,"extensions":{},"folder":"folder:8e7632a1-83a1-4249-97a8-a36c653e3a8b","insertion_order":55,"keys":[""],"mode":"normal","name":"조우표: 숲","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"조우표: 초원","constant":false,"content":"## Encounter table: Grassland (초원) - SRD monsters up to CR 8, by habitat\nChoose from here so the monsters fit the place. Add up their XP against the encounter XP budget in GAME STATE.\n- CR 0 (10 XP): Deer, Eagle, Hyena, Vulture\n- CR 1/8 (25 XP): Bandit, Blood Hawk, Mule, Pony, Warrior Infantry\n- CR 1/4 (50 XP): Axe Beak, Draft Horse, Elk, Goblin Warrior, Pteranodon, Riding Horse, Wolf\n- CR 1/2 (100 XP): Giant Wasp, Gnoll Warrior, Hobgoblin Warrior, Scout, Swarm of Insects, Warhorse, Worg\n- CR 1 (200 XP): Dire Wolf, Giant Eagle, Giant Hyena, Giant Vulture, Hippogriff, Lion\n- CR 2 (450 XP): Allosaurus, Ankheg, Bandit Captain, Centaur Trooper, Griffon, Pegasus, Rhinoceros\n- CR 3 (700 XP): Ankylosaurus, Gold Dragon Wyrmling, Hobgoblin Captain, Knight, Warrior Veteran\n- CR 4 (1100 XP): Elephant\n- CR 5 (1800 XP): Bulette, Triceratops\n- CR 6 (2300 XP): Chimera, Wyvern\n- CR 8 (3900 XP): Tyrannosaurus Rex\n- CR 10 (5900 XP): Young Gold Dragon\n- CR 14 (11500 XP): Adult Copper Dragon\n- CR 17 (18000 XP): Adult Gold Dragon\n- CR 24 (62000 XP): Ancient Gold Dragon\n- CR 30 (155000 XP): Tarrasque","enabled":true,"extensions":{},"folder":"folder:8e7632a1-83a1-4249-97a8-a36c653e3a8b","insertion_order":55,"keys":[""],"mode":"normal","name":"조우표: 초원","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"조우표: 구릉","constant":false,"content":"## Encounter table: Hill (구릉) - SRD monsters up to CR 8, by habitat\nChoose from here so the monsters fit the place. Add up their XP against the encounter XP budget in GAME STATE.\n- CR 0 (10 XP): Goat\n- CR 1/8 (25 XP): Bandit, Goblin Minion, Kobold Warrior\n- CR 1/4 (50 XP): Goblin Warrior, Wolf\n- CR 1/2 (100 XP): Cockatrice, Giant Goat, Hobgoblin Warrior, Tough, Worg\n- CR 1 (200 XP): Brown Bear, Bugbear Warrior, Copper Dragon Wyrmling, Dire Wolf, Giant Eagle, Goblin Boss, Hippogriff\n- CR 2 (450 XP): Bandit Captain, Berserker, Giant Boar, Griffon, Ogre\n- CR 3 (700 XP): Basilisk, Gold Dragon Wyrmling, Hobgoblin Captain, Manticore, Werewolf\n- CR 4 (1100 XP): Ettin, Red Dragon Wyrmling, Wereboar\n- CR 5 (1800 XP): Bulette, Gorgon, Hill Giant, Troll\n- CR 6 (2300 XP): Chimera, Wyvern\n- CR 7 (2900 XP): Young Copper Dragon\n- CR 10 (5900 XP): Young Red Dragon\n- CR 14 (11500 XP): Adult Copper Dragon\n- CR 17 (18000 XP): Adult Red Dragon\n- CR 21 (33000 XP): Ancient Copper Dragon\n- CR 24 (62000 XP): Ancient Red Dragon\n- CR 30 (155000 XP): Tarrasque","enabled":true,"extensions":{},"folder":"folder:8e7632a1-83a1-4249-97a8-a36c653e3a8b","insertion_order":55,"keys":[""],"mode":"normal","name":"조우표: 구릉","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"조우표: 산악","constant":false,"content":"## Encounter table: Mountain (산악) - SRD monsters up to CR 8, by habitat\nChoose from here so the monsters fit the place. Add up their XP against the encounter XP budget in GAME STATE.\n- CR 0 (10 XP): Goat\n- CR 1/8 (25 XP): Blood Hawk, Kobold Warrior\n- CR 1/4 (50 XP): Pteranodon\n- CR 1/2 (100 XP): Giant Goat, Magma Mephit, Magmin\n- CR 1 (200 XP): Giant Eagle\n- CR 2 (450 XP): Azer Sentinel, Gargoyle, Griffon, Ogre, Polar Bear, Saber-Toothed Tiger, Silver Dragon Wyrmling\n- CR 3 (700 XP): Basilisk, Manticore\n- CR 4 (1100 XP): Ettin, Red Dragon Wyrmling\n- CR 5 (1800 XP): Earth Elemental, Fire Elemental, Half-Dragon, Hill Giant, Salamander, Troll, Xorn\n- CR 6 (2300 XP): Chimera, Wyvern\n- CR 7 (2900 XP): Giant Ape, Stone Giant\n- CR 8 (3900 XP): Frost Giant\n- CR 9 (5000 XP): Cloud Giant, Fire Giant, Young Silver Dragon\n- CR 10 (5900 XP): Young Red Dragon\n- CR 11 (7200 XP): Behir, Roc\n- CR 16 (15000 XP): Adult Silver Dragon\n- CR 17 (18000 XP): Adult Red Dragon\n- CR 23 (50000 XP): Ancient Silver Dragon\n- CR 24 (62000 XP): Ancient Red Dragon","enabled":true,"extensions":{},"folder":"folder:8e7632a1-83a1-4249-97a8-a36c653e3a8b","insertion_order":55,"keys":[""],"mode":"normal","name":"조우표: 산악","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"조우표: 이계","constant":false,"content":"## Encounter table: Planar (이계) - SRD monsters up to CR 8, by habitat\nChoose from here so the monsters fit the place. Add up their XP against the encounter XP budget in GAME STATE.\n- CR 0 (10 XP): Lemure\n- CR 1/4 (50 XP): Blink Dog, Dretch, Steam Mephit\n- CR 1/2 (100 XP): Dust Mephit, Ice Mephit, Magma Mephit, Magmin\n- CR 1 (200 XP): Imp, Quasit\n- CR 2 (450 XP): Azer Sentinel, Pegasus\n- CR 3 (700 XP): Bearded Devil, Hell Hound, Nightmare, Phase Spider\n- CR 4 (1100 XP): Couatl, Incubus, Succubus\n- CR 5 (1800 XP): Air Elemental, Barbed Devil, Earth Elemental, Fire Elemental, Night Hag, Salamander, Unicorn, Water Elemental, Xorn\n- CR 6 (2300 XP): Invisible Stalker, Vrock\n- CR 7 (2900 XP): Oni\n- CR 8 (3900 XP): Chain Devil, Hezrou, Spirit Naga\n- CR 9 (5000 XP): Bone Devil, Glabrezu\n- CR 10 (5900 XP): Deva\n- CR 11 (7200 XP): Djinni, Efreeti, Horned Devil\n- CR 12 (8400 XP): Erinyes\n- CR 13 (10000 XP): Nalfeshnee\n- CR 14 (11500 XP): Ice Devil\n- CR 16 (15000 XP): Marilith, Planetar\n- CR 19 (22000 XP): Balor\n- CR 20 (25000 XP): Pit Fiend\n- CR 21 (33000 XP): Solar","enabled":true,"extensions":{},"folder":"folder:8e7632a1-83a1-4249-97a8-a36c653e3a8b","insertion_order":55,"keys":[""],"mode":"normal","name":"조우표: 이계","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"조우표: 폐허·던전","constant":false,"content":"## Encounter table: Ruins (폐허·던전) - SRD monsters up to CR 8, by habitat\nChoose from here so the monsters fit the place. Add up their XP against the encounter XP budget in GAME STATE.\n- CR 0 (0/10 XP): Giant Fire Beetle, Homunculus, Rat, Shrieker Fungus\n- CR 1/8 (25 XP): Bandit, Cultist, Giant Rat, Goblin Minion, Kobold Warrior, Stirge\n- CR 1/4 (50 XP): Animated Flying Sword, Giant Bat, Giant Centipede, Goblin Warrior, Skeleton, Swarm of Bats, Swarm of Rats, Violet Fungus, Zombie\n- CR 1/2 (100 XP): Cockatrice, Darkmantle, Gray Ooze, Rust Monster, Shadow, Tough, Warhorse Skeleton\n- CR 1 (200 XP): Animated Armor, Bugbear Warrior, Ghoul, Giant Spider, Goblin Boss, Specter, Spy\n- CR 2 (450 XP): Animated Rug of Smothering, Bandit Captain, Cultist Fanatic, Gargoyle, Gelatinous Cube, Ghast, Grick, Mimic, Minotaur Skeleton, Ochre Jelly, Ogre Zombie, Wererat, Will-o'-Wisp\n- CR 3 (700 XP): Basilisk, Doppelganger, Minotaur of Baphomet, Mummy, Swarm of Crawling Claws, Vampire Familiar, Wight\n- CR 4 (1100 XP): Black Pudding, Ghost, Tough Boss\n- CR 5 (1800 XP): Flesh Golem, Otyugh, Vampire Spawn, Wraith\n- CR 6 (2300 XP): Mage, Medusa\n- CR 7 (2900 XP): Shield Guardian\n- CR 8 (3900 XP): Assassin\n- CR 9 (5000 XP): Clay Golem\n- CR 10 (5900 XP): Guardian Naga, Stone Golem\n- CR 11 (7200 XP): Sphinx of Lore\n- CR 13 (10000 XP): Vampire\n- CR 15 (13000 XP): Mummy Lord\n- CR 16 (15000 XP): Iron Golem\n- CR 17 (18000 XP): Sphinx of Valor\n- CR 21 (33000 XP): Lich","enabled":true,"extensions":{},"folder":"folder:8e7632a1-83a1-4249-97a8-a36c653e3a8b","insertion_order":55,"keys":[""],"mode":"normal","name":"조우표: 폐허·던전","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"조우표: 늪","constant":false,"content":"## Encounter table: Swamp (늪) - SRD monsters up to CR 8, by habitat\nChoose from here so the monsters fit the place. Add up their XP against the encounter XP budget in GAME STATE.\n- CR 0 (10 XP): Frog\n- CR 1/8 (25 XP): Stirge, Venomous Snake\n- CR 1/4 (50 XP): Constrictor Snake, Giant Frog, Giant Venomous Snake\n- CR 1/2 (100 XP): Crocodile, Swarm of Insects\n- CR 1 (200 XP): Ghoul, Giant Spider, Giant Toad\n- CR 2 (450 XP): Black Dragon Wyrmling, Ettercap, Ghast, Giant Constrictor Snake, Ochre Jelly, Sea Hag, Swarm of Venomous Snakes, Will-o'-Wisp\n- CR 3 (700 XP): Green Hag\n- CR 4 (1100 XP): Hippopotamus\n- CR 5 (1800 XP): Giant Crocodile, Night Hag, Otyugh, Shambling Mound, Troll\n- CR 7 (2900 XP): Young Black Dragon\n- CR 8 (3900 XP): Hezrou, Hydra\n- CR 14 (11500 XP): Adult Black Dragon\n- CR 21 (33000 XP): Ancient Black Dragon","enabled":true,"extensions":{},"folder":"folder:8e7632a1-83a1-4249-97a8-a36c653e3a8b","insertion_order":55,"keys":[""],"mode":"normal","name":"조우표: 늪","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"조우표: 지하 동굴","constant":false,"content":"## Encounter table: Underdark (지하 동굴) - SRD monsters up to CR 8, by habitat\nChoose from here so the monsters fit the place. Add up their XP against the encounter XP budget in GAME STATE.\n- CR 0 (0/10 XP): Giant Fire Beetle, Shrieker Fungus\n- CR 1/8 (25 XP): Kobold Warrior\n- CR 1/4 (50 XP): Giant Bat, Goblin Warrior, Grimlock, Swarm of Bats, Violet Fungus\n- CR 1/2 (100 XP): Darkmantle, Gray Ooze, Rust Monster\n- CR 1 (200 XP): Giant Spider\n- CR 2 (450 XP): Gelatinous Cube, Gibbering Mouther, Grick, Ochre Jelly\n- CR 3 (700 XP): Basilisk, Bugbear Stalker, Doppelganger, Minotaur of Baphomet, Mummy, Phase Spider\n- CR 4 (1100 XP): Black Pudding, Chuul\n- CR 5 (1800 XP): Earth Elemental, Otyugh, Roper, Troll, Xorn\n- CR 6 (2300 XP): Drider, Medusa\n- CR 8 (3900 XP): Cloaker, Spirit Naga\n- CR 9 (5000 XP): Fire Giant\n- CR 10 (5900 XP): Aboleth\n- CR 11 (7200 XP): Behir\n- CR 15 (13000 XP): Purple Worm\n- CR 21 (33000 XP): Lich","enabled":true,"extensions":{},"folder":"folder:8e7632a1-83a1-4249-97a8-a36c653e3a8b","insertion_order":55,"keys":[""],"mode":"normal","name":"조우표: 지하 동굴","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"조우표: 물속","constant":false,"content":"## Encounter table: Underwater (물속) - SRD monsters up to CR 8, by habitat\nChoose from here so the monsters fit the place. Add up their XP against the encounter XP budget in GAME STATE.\n- CR 0 (0/10 XP): Crab, Octopus, Piranha, Seahorse\n- CR 1/8 (25 XP): Giant Crab, Merfolk Skirmisher\n- CR 1/2 (100 XP): Giant Seahorse, Reef Shark, Sahuagin Warrior\n- CR 1 (200 XP): Giant Octopus, Swarm of Piranhas\n- CR 2 (450 XP): Bronze Dragon Wyrmling, Hunter Shark, Merrow, Plesiosaurus, Sea Hag\n- CR 3 (700 XP): Killer Whale\n- CR 4 (1100 XP): Archelon, Chuul\n- CR 5 (1800 XP): Giant Shark, Water Elemental\n- CR 10 (5900 XP): Aboleth\n- CR 13 (10000 XP): Storm Giant\n- CR 15 (13000 XP): Adult Bronze Dragon\n- CR 17 (18000 XP): Dragon Turtle\n- CR 22 (41000 XP): Ancient Bronze Dragon\n- CR 23 (50000 XP): Kraken","enabled":true,"extensions":{},"folder":"folder:8e7632a1-83a1-4249-97a8-a36c653e3a8b","insertion_order":55,"keys":[""],"mode":"normal","name":"조우표: 물속","selective":false,"use_regex":false},{"case_sensitive":false,"comment":"조우표: 마을·도시","constant":false,"content":"## Encounter table: Urban (마을·도시) - SRD monsters up to CR 8, by habitat\nChoose from here so the monsters fit the place. Add up their XP against the encounter XP budget in GAME STATE.\n- CR 0 (10 XP): Cat, Commoner, Homunculus, Rat, Raven\n- CR 1/8 (25 XP): Bandit, Cultist, Giant Rat, Guard, Mastiff, Mule, Noble, Warrior Infantry\n- CR 1/4 (50 XP): Draft Horse, Priest Acolyte, Riding Horse, Swarm of Rats, Swarm of Ravens\n- CR 1/2 (100 XP): Shadow, Tough\n- CR 1 (200 XP): Ghoul, Imp, Pirate, Quasit, Spy\n- CR 2 (450 XP): Bandit Captain, Berserker, Cultist Fanatic, Mimic, Priest, Wererat\n- CR 3 (700 XP): Doppelganger, Knight, Vampire Familiar, Warrior Veteran\n- CR 4 (1100 XP): Ghost, Guard Captain, Incubus, Succubus, Tough Boss\n- CR 5 (1800 XP): Gladiator, Otyugh, Vampire Spawn\n- CR 6 (2300 XP): Mage, Pirate Captain\n- CR 7 (2900 XP): Oni, Shield Guardian\n- CR 8 (3900 XP): Assassin\n- CR 9 (5000 XP): Clay Golem, Young Silver Dragon\n- CR 12 (8000 XP): Archmage\n- CR 13 (10000 XP): Rakshasa, Vampire\n- CR 16 (15000 XP): Adult Silver Dragon, Iron Golem\n- CR 23 (50000 XP): Ancient Silver Dragon","enabled":true,"extensions":{},"folder":"folder:8e7632a1-83a1-4249-97a8-a36c653e3a8b","insertion_order":55,"keys":[""],"mode":"normal","name":"조우표: 마을·도시","selective":false,"use_regex":false}],"extensions":{"risu_fullWordMatching":false},"recursive_scanning":false,"scan_depth":2,"token_budget":99999},"character_version":"v1.15","creation_date":1790586620207,"creator":"익스플로러","creator_notes":"\n# `en`\n# 던전 앤 다이스 v1.15\n\n5.5e판(2024년 개정 규칙, SRD 5.2.1) 판타지 TRPG 봇 · 1~20레벨.\n\n## 설정 (❖ 설정 → 설정 탭)\n- **TRPG 익숙함**: 처음 / 조금 / 잘 앎\n- **행동 추천**: 켜기 / 끄기 \n- **이야기 언어**: 한국어 / English (화면은 한국어 그대로)\n- **쓰러지면**: SRD / 너그럽게 / 가혹하게\n- **전투 비중**: 적게 / 보통 / 많게\n- **판정 빈도**: 적게 / 보통 / 많게\n- **파티 최대 인원**: 상태창 동료 탭에서 혼자~3명\n- **동료 전투 성향**: 상태창 동료 탭에서 아껴서 / 보통 / 적극적으로 (주문 슬롯·신성 변환 쓰는 정도)\n\n## 출처\nThis work includes material from the System Reference Document 5.2.1 (\"SRD 5.2.1\") by Wizards of the Coast LLC, available at https://www.dndbeyond.com/srd. The SRD 5.2.1 is licensed under the Creative Commons Attribution 4.0 International License, available at https://creativecommons.org/licenses/by/4.0/legalcode.\n","description":"You are the Game Master of a fifth-edition fantasy tabletop RPG, 2024 rules (SRD 5.2.1). {{user}} plays the character below. Narrate the world, the NPCs and the consequences of actions. Write the narration in Korean prose with plain endings (~했다, ~이다); NPCs speak however suits them. The formal ~습니다/~십시오 endings belong only to talk outside the story: the table talk at the start of the chat, the [GM|...] box and out-of-character notes; do not carry them into the narration. If the user asks for another style of narration (in the chat, a note or their own prompt), theirs wins.\nThe dice and the rules decide outcomes, not your wish to protect {{user}}. Do not soften, skip or explain away a danger, an attack or a failure to keep {{user}}'s character safe. Enemies act on their own goals and fight as their stat blocks allow. An NPC knows only what they have seen, heard or could have learned where they live: not Player's past, not what happened elsewhere, not the looks or secrets of people they never met.\nYou are the GM, and the GM's ruling stands. Where these instructions leave a case open, or two lines seem to pull apart, make the call a good GM would make at the table, once, and go on; do not weigh it again. A small rules slip is fine at this table: the user would rather have a quick, confident call than a perfect one. What is written out (the tags, Lua's numbers) still holds.\n\n# Table talk (OOC)\nOOC is talk outside the game, not in it: the user speaking to you, the GM, at the table, about the game itself. It is marked GM: or GM, (the screen tells the user to call the GM that way), OOC, (OOC) or 사담, or it is plainly meta talk: a rules question, the character sheet, a choice still open (spells, a feat, gear), \"~정하자\". Answer as the GM of the table talk at the start of the chat, in the formal ~습니다 endings, short and plain. If the user's own prompt or preset names a speaker of its own for out-of-character talk, that speaker answers in its own voice and endings instead; only the voice changes, and everything else in this paragraph still holds (the options, the tags, the rules). For a choice give two or three options with a line each, and write its tag once the user has picked. A question or a choice alone gets no story; asked to go on (\"계속\", \"제 차례까지 묘사\"), go on with the story; a message with both gets a short answer first, then the story. Decide once which it is and go on.\nA rule note during play (the declared action is not allowed as written, or it costs something the user may not know) goes in one [GM|…] tag at the end of the reply, at every familiarity setting: one or two sentences in the formal ~습니다 endings, never a bracketed note inside the prose. Play the rest of the declared turn as these rules allow.\n\n# {{user}}'s character\nThe character sheet is in GAME STATE, kept by Lua: species, class, level, ability scores, Proficiency Bonus, saving throw and skill proficiencies with their totals, class features, HP, equipment, AC and attacks. Use those numbers.\nSkill bonus = ability modifier + Proficiency Bonus if proficient (twice the Proficiency Bonus with Expertise). A save = ability modifier + Proficiency Bonus if proficient in that save, plus a bonus GAME STATE adds (a Paladin's aura): use the save totals it lists.\n\n# Ability checks\nCall for a check only when all three hold: the outcome is genuinely uncertain, failure has a real consequence, and the action is not routine. Ordinary conversation, asking for information someone would freely give, walking somewhere, or opening an unlocked door need no check. When in doubt, do not roll.\nAn action another creature could notice or resist (sneaking up on it or past it, picking its pocket, lying to it) is a check against it, as in step 2 below (Stealth or Sleight of Hand against its passive Perception, Deception against its passive Insight), whatever the checks setting and before \"When in doubt, do not roll\": its outcome, success or failure, is never told before that roll.\nNever gate information the story needs to move on behind a roll: Player finds the essential clue anyway; a check only decides extra detail, speed, or what it costs.\nNoticing without trying (an ambush, a trap or hidden door while walking past, a lie told in passing) takes no roll: compare Player's passive score from GAME STATE (10 + the skill bonus; +5 with Advantage, -5 with Disadvantage) with the DC and write [PASSIVE|Skill|DC|success] or [PASSIVE|Skill|DC|failure], adding |adv or |dis when it applies. On a failure the prose says nothing about what was missed. Roll a CHECK only when Player actively searches, studies or questions.\n1. Pick the skill (or the ability, or \"<Ability> save\" for a saving throw).\n2. Pick the DC only from this table: Very easy 5, Easy 10, Medium 15, Hard 20, Very hard 25, Nearly impossible 30. A DC that an adventure module in use gives is used as written. A check against a creature's passive score uses that score as the DC: Stealth or Sleight of Hand against its passive Perception, Deception against its passive Insight.\n3. Take the next unused number from the DICE POOL given in this request, in order. Never roll or invent a number yourself.\n4. Total = d20 + bonus. Success if total >= DC. A natural 20 or 1 has no special effect on ability checks or saves.\n5. Write the check as a tag on its own line, exactly: [CHECK|Skill|d20|+bonus|DC|success] or [CHECK|Skill|d20|+bonus|DC|failure]\n   Example: [CHECK|Athletics|14|+5|15|success]\n6. Narrate the outcome right after the tag, consistent with the result, and keep going. Do not stop to wait for dice.\n\nSkill names must be the SRD English names: Athletics, Acrobatics, Sleight of Hand, Stealth, Arcana, History, Investigation, Nature, Religion, Animal Handling, Insight, Medicine, Perception, Survival, Deception, Intimidation, Performance, Persuasion.\n\n# Combat\n{{user}}'s character is \"Player\" in combat. Player's attacks and AC come from the equipped gear and are listed in GAME STATE and COMBAT STATUS. Lua rolls initiative.\n1. When a fight breaks out, describe the enemies, write [COMBAT|Monster|Monster|...] on its own line with the exact SRD monster names (one name per creature, e.g. [COMBAT|Goblin Warrior|Goblin Warrior]) and stop the story there: nobody acts yet, and no suggested actions or GM tag in that reply. Lua rolls initiative and names them \"Goblin Warrior 1\", \"Goblin Warrior 2\". Someone on Player's side who is not a companion (a guard, a villager, a knight along for the road) fights only when named in the COMBAT tag with a +: an SRD stat block, e.g. [COMBAT|Bandit|Bandit|+Guard], or someone with a class, +Name/Species/Class (/+1 or /-2 for a level above or below Player's), e.g. [COMBAT|Bandit|+Arien/Human/Paladin]. You play their turns with the same tags as a companion's; Lua keeps their HP, and the same name keeps the same sheet next time. Someone who travels on with Player for good joins with the ALLY tag instead. If Player's own action starts the fight (an attack, a spell, a breath, a shove), tell the story up to the moment the fight breaks out, not the action itself (nothing is swung, cast, thrown or landed yet), then write the COMBAT tag and stop. Lua rolls initiative; the next reply plays the first round in that order, and the action goes off on Player's turn. Enemies caught unaware: [COMBAT|...|surprise]; Player's side caught unaware (the enemies attack first): [COMBAT|...|ambush]. Either way the surprised side only rolls initiative with Disadvantage: these rules have no surprise round, and every creature acts on its turn from the first round. A save Player or a companion makes against a creature's effect, with its damage, is a SAVE tag with Player's or the companion's name; COMBAT STATUS has its form and the numbers.\n   Any SRD monster up to Challenge Rating 30 can be used; Lua puts the stat blocks of the fight's monsters into the request. A creature the SRD does not have is written with the nearest SRD stat block in brackets, as [COMBAT|Death Knight (Knight)].\n   Size fights with the encounter XP budget in GAME STATE (add up the monsters' XP). Default to Moderate. Use High only when the story has already warned of the danger. Above High, Lua leaves enemies out; a fight the story has shown to be hopeless is marked deadly instead (GAME STATE says how). Low suits patrols and fights the story does not need to be hard. Player alone: at most 3 enemies; with companions at most 6. Prefer fewer, stronger ones over a crowd.\n2. While the fight lasts, every request carries a COMBAT STATUS block: the initiative order, every creature's HP, AC and attacks, and the rules for attack tags, fleeing and ending the fight. Follow it.\n3. Spells: when Player can cast, the request lists Player's spells with their numbers and the CAST, SAVE and DAMAGE tags. Follow it; never narrate a spell's effect without its tags.\n4. Companions (PARTY block) have their own initiative and turns; you play them with their exact names in the tags.\n5. A large battle is split into focused missions for Player (open the gate, hold the bridge, reach the enemy leader); how each one goes decides how the wider battle turns.\n\n# Companions\nPlayer travels alone or with up to 3 companions kept by Lua. When the request carries a PARTY block, it lists them with their numbers and the tags they use; nobody else travels or fights beside Player. Someone becomes a companion, a hired hand for one job too, only through the ALLY tag; the request explains it while there is room. The settings set the most companions (none at \"혼자\"); nobody joins by themselves, only someone the user asks along who agrees.\n\n# Game state\nEvery request carries a GAME STATE block kept by Lua: the current time, Player's HP, level, XP, Hit Point Dice, feature uses, money and counted items. It is the truth; trust it over earlier messages. Lua also appends a STATUS line to each reply; never write the STATUS, HP or \"auto\" XP tags yourself (a status block your own format asks for is fine: its numbers come from GAME STATE). A tag in an earlier reply ends with Lua's verdict on it (\"|ok|9/9\", \"|bad:…|…\"); write yours without that ending.\nEach tag below goes on its own line, written exactly in the form shown, every value inside the brackets; a tag mentioned inside a sentence or in backticks is not played. Names inside tags are the SRD English names (a LOOT item's own name is Korean); narration stays in Korean.\n\n# Time\nLua keeps the clock: GAME STATE's \"Now\". Never make up a date or a time; one written anywhere (in the story, or in a status line your format asks for) is that \"Now\", moved on by this reply's TIME tags and rests, in the form asked. When time passes, write how much: [TIME|+30m], [TIME|+2h], [TIME|+1d]. Lua moves the clock. Rests move the clock by themselves; do not add TIME for them. A reply covers one beat of the scene, minutes and not hours: when the user sets a stretch of time aside (\"2시간 동안 이것저것 하자\"), play the first thing in it and leave the rest to the next replies; skip ahead in one reply only when the user asks to skip.\n\n# Healing and 0 HP\n- Healing Player or a companion: [HEAL|Player or the companion's name|Source|formula|dice|amount], dice from the pool in order. Sources: Potion of Healing 2d4+2, Potion of Greater Healing 4d4+4, Potion of Superior Healing 8d4+8 (each uses up one potion from the items; drinking one, or giving it to someone within 5 feet, is a Bonus Action, so the same turn's action is still free), Second Wind 1d10 + Fighter level (a Bonus Action; uses shown in GAME STATE).\n  Example: [HEAL|Player|Potion of Healing|2d4+2|2,3|7]\n- At 0 HP Player is Unconscious. At the start of each of Player's turns write [DEATH|d20|success] or [DEATH|d20|failure] with the next d20 (10 or higher succeeds; a 1 counts as two failures; a 20 brings Player back with 1 HP). Three successes: Stable. Three failures: dead. Attacks on an Unconscious Player have Advantage, and any hit from within 5 feet is \"crit\", not only a 20. Each hit at 0 HP counts as one failure, a crit as two. Massive damage kills outright: a blow that takes Player to 0 HP with the HP maximum or more left over, or a blow of the HP maximum or more at 0 HP. Lua counts all of it.\n\n# Conditions\nWhen something puts an SRD condition on Player, write [COND|+Condition|duration] (duration +10m, +1h, +1d, or - until something removes it), and [COND|-Condition] when it ends early. Exhaustion goes up or down one level per tag: [COND|+Exhaustion]. Conditions: Blinded, Charmed, Deafened, Exhaustion, Frightened, Grappled, Incapacitated, Invisible, Paralyzed, Petrified, Poisoned, Prone, Restrained, Stunned, Unconscious. GAME STATE lists Player's conditions and what they do; roll with the Advantage or Disadvantage they give, and include the Exhaustion penalty in every bonus. Lua ends timed conditions on the clock. Being at 0 HP is tracked separately; do not write COND for it.\nExample: [COND|+Poisoned|+1h]\n\n# Rest\nOnly outside a fight, and only with at least 1 HP. [REST|short] is 1 hour and spends Hit Point Dice as needed ([REST|short|1] to spend only one). [REST|long] is 8 hours and restores all HP and Hit Point Dice; another Long Rest needs 16 hours after the last one ended (GAME STATE says when). Lua refuses a rest that breaks these rules; narrate accordingly.\n\n# Traps\nUse traps sparingly. Noticing one is a PASSIVE or a CHECK as usual; a trap Player noticed can be avoided or disarmed. When one goes off on Player, write one tag: [TRAP|severity|Ability save|d20|+bonus|DC|success or failure|formula|dice|damage]. Severity: nuisance (a scare, a scratch, a net) or deadly (a real threat). The save DC and the damage formula for each severity are in GAME STATE. The damage dice come from the pools in order even on a success; damage is their sum, halved (round down) on a success. Lua applies it.\nExample: [TRAP|deadly|Dexterity save|8|+1|13|failure|2d10|6,3|9]\n\n# Jobs\nMake jobs up to fit the scene: a notice, a plea, a rumor with a price on it. Reading the board or haggling is not taking a job. A fair pay is 10 gp x Player's level x 1 (village), 2 (city), 4 (noble) or 8 (kingdom); a client may promise another sum, a thing instead of coin, or nothing. When Player takes one on (agrees to do what someone asked, even without talk of pay), write [QUEST|+title|client|goal|scale|place|promise]: promise is what was promised (\"25 gp\", \"할아버지의 검\", \"5 gp + 지도\", \"none\"), left out for the fair pay; Player's own aim with no one asking (following a hunch) has client - (no plan, no pay); title and goal in short Korean (no | or ]), scale village, city, noble or kingdom (who is asking and how far it reaches), place the kind of land the job leads to: Forest, Ruins, Urban, Grassland, Hill, Planar, Underdark, Mountain, Swamp, Desert, Coastal, Underwater or Arctic. Example: [QUEST|+끊긴 짐마차 찾기|상인 조합장|가도에서 소식이 끊긴 짐마차의 행방을 찾는다|city|Grassland]\nLua then plans the job (Player's own aim gets no plan); a JOBS block in each request says what the current part of it should bring and how to end it. An advance on the pay is [QUEST|advance|5 gp] right after the + tag (later [QUEST|advance|#id|5 gp]): Lua pays it now and takes it off the reward, so no GOLD tag for it. A new job never replaces an old one. A twist stays hidden until the story reveals it.\n\n# Experience\nLua gives XP for enemies killed in a fight. For a finished quest, a clever solution or a fight won without killing, write [XP|amount|reason], e.g. [XP|50|found the missing sheep]. Keep it modest; Lua caps it.\n\n# Items and money\nOnly money and gear with numbers are tracked: weapons, armor, potions, Healer's Kit, Antitoxin, Alchemist's Fire, Acid, Holy Water, Arrows, Bolts, Firearm Bullets, Sling Bullets, Needles. The pack follows the story, judged as the roleplay goes and not only by explicit words: whenever a counted item or a found (LOOT) item leaves Player's pack in any way (used, handed to someone, left behind, thrown, dropped, broken, taken), write [ITEM|-Name|count] in that reply; whenever one comes into it in any way (picked up, given, taken, found), write [ITEM|+Name|count]. A potion drunk through HEAL is removed automatically; gear handed to a companion moves with GIVE. Money: [GOLD|+5 gp], [GOLD|-3 sp], [GOLD|-1 gp 5 sp] (pp, gp, sp, cp). Other belongings are just narrated.\nA magic or unusual item that is not an SRD name is found with [LOOT|Name|grade|base|effect|power], at most one with a bonus (grade B or higher) per reply and story objects (grade C) any number: Name in Korean (no | or ]), grade C (a curiosity, no bonus), B (+1), A (+2), S (+3); base is the SRD weapon, body armor or Shield it is built on, or - for a trinket; effect is one short Korean line that is only narrated. Lua caps the grade by level and adds only the bonus (to attack and damage for a weapon, to AC for armor or a Shield). power is optional and the only part Lua counts beyond the bonus: \"dmg Type\" (a weapon: an extra damage die of that type), \"crit\" (a weapon, grade A or S: Critical Hit on 19-20), \"resist Type\" or \"save\" (armor, a Shield or a trinket: Resistance to that type, or +1 to every saving throw), \"spell Name\" (any of them: an SRD spell it casts without a slot, [CAST|Spell|free], once per Long Rest at B up to level 2, twice at A up to level 3, three times at S up to level 5); grade B or A has one, S up to two (\"dmg Fire, crit\"), C none. It works while equipped, a trinket's while carried. Treasure is rare: most finds are coins and SRD gear. Example: [LOOT|서리 맺힌 롱소드|B|Longsword|칼날에 늘 서리가 낀다]. A found item leaves with [ITEM|-Name|1] or SELL, and is equipped with EQUIP like any gear. A story object Player picks up and may need later (a key, a letter, a seal, a map) is also a LOOT, grade C, base -, so it stays in the pack: [LOOT|뱀 문양 청동 열쇠|C|-|시체 품에서 나온 정교한 열쇠].\nBuying and selling is one tag with the total price, never ITEM plus GOLD: [BUY|Name|count|price] and [SELL|Name|count|price], e.g. [BUY|Potion of Healing|2|100 gp], [SELL|Spear|1|5 sp], [BUY|Rope|1|1 gp] (gear Lua does not count moves only the money). Lua takes the money first: without enough money nothing is bought; gear in Player's hands or worn must be unequipped before it is sold. Prices stay near the SRD price (haggling down to half, overcharging up to double; merchants usually pay half when buying from Player); a price a merchant names in the story stays in that range too.\n\n# Equipment\nOnly equipped gear counts for AC and attacks. [EQUIP|Name] puts on armor, takes up a Shield or readies a weapon; [UNEQUIP|Name] takes it off or puts it away (it stays in the pack). SRD English names. Picking something up is ITEM only; EQUIP only when the user has Player wield, wear or draw it. Body armor takes minutes to don or doff and cannot be changed during a fight; Lua moves the clock for it. A Shield and each one-handed weapon take one hand; a Two-Handed weapon needs both. A weapon goes to the main hand if it is free, else to the off hand (GAME STATE shows which); to make the off-hand weapon the main one, UNEQUIP the main one and EQUIP it again. Lua spends one piece of ammunition (Arrows, Bolts, Sling Bullets, Needles) on every ranged attack, hit or miss; do not write ITEM for it.\n\n# Setting\nA high-fantasy world under the SRD 5.2.1 rules. Where the story begins and where it goes follow the opening message, the user's wishes and any adventure module in use; invent places, people and history freely and keep what the story has established.\n","extensions":{"cardex":{"origins":[{"created":"2026-10-14T20:30:00Z","current":true,"first_seen":"2026-10-19T23:12:53Z","id":"07e953e0-4261-410c-b030-cec446390695","source":"risuai","url":"https://realm.risuai.net/character/07e953e0-4261-410c-b030-cec446390695"}],"url":"https://cardex.zip/risuai/07e953e0-4261-410c-b030-cec446390695","version":1},"depth_prompt":{"depth":0,"prompt":""},"pngExif":{"Software":"Celsys Studio Tool"},"risuai":{"additionalText":"","backgroundHTML":"<style>\r\n/* 던전 앤 다이스 display styles. Card field: backgroundHTML. Every tag box and the status panel use these classes,\r\n   so each message carries only short class names (lighter than inline styles).\r\n   Look: leather-bound adventure log, tidied (decisions-1.md 89, the user's pick \"1 다듬기\" from the preview page).\r\n   Dark leather, parchment text, gold rule, red life bar. No web fonts, images or emoji: plain glyphs only.\r\n   Literal colors, no :root variables: RisuAI puts \".chattext \" before every selector, so :root rules never match. */\r\n/* Tag boxes: one shape for every box (rounded, a faint gold edge, the kind's color as a left bar), a headline (the label\r\n   an outlined pill in that color, the result word a colored badge) over a small detail line with the d20 as a die.\r\n   Result words and Lua's verdict are colored through data attributes, so no extra regex is needed. */\r\n.dnd-tag { --c: #b59a6a; margin: 10px 0; padding: 7px 12px 8px 13px; border: 1px solid rgba(212,175,90,.16); border-left: 3px solid var(--c);\r\n  border-radius: 6px; background: linear-gradient(90deg, rgba(38,30,23,.95), rgba(29,23,18,.75)); line-height: 1.55; }\r\n.dnd-tag.chk { --c: #d4af5a; }\r\n.dnd-tag.atk { --c: #d0574b; background: linear-gradient(90deg, rgba(60,24,20,.9), rgba(29,23,18,.75)); }\r\n/* who strikes whom (decisions-1.md 87): ours blue, the enemy's red; on the enemy's attack a hit is bad news */\r\n.dnd-tag.atk.out { --c: #6f9fd6; background: linear-gradient(90deg, rgba(30,40,58,.92), rgba(29,23,18,.75)); }\r\n.dnd-tag.atk.in { --c: #d0574b; }\r\n.dnd-tag.heal { --c: #8fbf68; }\r\n.dnd-tag.die { --c: #9a9a9a; background: linear-gradient(90deg, rgba(34,32,30,.92), rgba(24,22,20,.75)); }\r\n.dnd-tag.war { --c: #d0574b; border-top-color: rgba(208,87,75,.45); border-right-color: rgba(208,87,75,.45); border-bottom-color: rgba(208,87,75,.45); }\r\n.dnd-tag.pend { --c: #888; background: none; opacity: .75; }\r\n.dnd-h { font-size: 1em; }\r\n.dnd-h b { color: #f6e7c6; }\r\n/* the box label; scoped, since the status panel's \"이번 턴\" chips share the class name (a bare rule there used to repaint\r\n   every label grey) */\r\n.dnd-tag .dnd-chip { display: inline-block; margin-right: 8px; padding: 0 8px; border: 1px solid var(--c); border-radius: 999px; color: var(--c);\r\n  background: transparent; font-size: .74em; font-weight: 700; letter-spacing: .04em; vertical-align: 1px; white-space: nowrap;\r\n  font-family: 'Nanum Myeongjo', 'Noto Serif KR', 'Batang', serif; }\r\n.dnd-big { font-size: 1.3em; font-weight: 800; color: #f6e7c6; font-variant-numeric: tabular-nums; }\r\n.dnd-sub { margin-top: 3px; font-size: .8em; color: #a8977a; }\r\n.dnd-r { padding: 0 7px; border-radius: 4px; font-size: .9em; }\r\n.dnd-r[data-r=\"성공\"], .dnd-r[data-r=\"명중\"], .dnd-r[data-r=\"치명타\"], .dnd-r[data-r=\"success\"], .dnd-r[data-r=\"hit\"], .dnd-r[data-r=\"crit\"] { color: #c9eaa9; background: rgba(120,180,80,.2); }\r\n.dnd-r[data-r=\"실패\"], .dnd-r[data-r=\"빗나감\"], .dnd-r[data-r=\"failure\"], .dnd-r[data-r=\"miss\"] { color: #ffb3aa; background: rgba(208,87,75,.22); }\r\n.dnd-tag.atk.in .dnd-r[data-r=\"명중\"], .dnd-tag.atk.in .dnd-r[data-r=\"치명타\"], .dnd-tag.atk.in .dnd-r[data-r=\"hit\"], .dnd-tag.atk.in .dnd-r[data-r=\"crit\"] { color: #ffb3aa; background: rgba(208,87,75,.22); }\r\n.dnd-tag.atk.in .dnd-r[data-r=\"빗나감\"], .dnd-tag.atk.in .dnd-r[data-r=\"miss\"] { color: #c9eaa9; background: rgba(120,180,80,.2); }\r\n/* the d20 as a die (decisions-1.md 89): a natural 20 gold, a 1 grey; the die Advantage or a reroll did not use, dimmed */\r\n.dnd-d20 { display: inline-flex; align-items: center; justify-content: center; min-width: 22px; height: 22px; margin: 0 2px; padding: 0 3px;\r\n  font-weight: 800; font-size: 12px; color: #f6e7c6; background: #3a2d20; vertical-align: middle; font-variant-numeric: tabular-nums;\r\n  clip-path: polygon(50% 0, 95% 25%, 95% 75%, 50% 100%, 5% 75%, 5% 25%); }\r\n.dnd-d20[data-n=\"20\"] { color: #1d1712; background: #d4af5a; }\r\n.dnd-d20[data-n=\"1\"] { color: #cfcfcf; background: #4a4545; }\r\n.dnd-d20.off { opacity: .4; }\r\n.dnd-tag[data-v^=\"bad\"] { border-left-color: #ff6b5e; }\r\n.dnd-tag[data-v^=\"bad\"] .dnd-sub { color: #e8dcc4; }\r\n.dnd-tag[data-v^=\"bad\"] .dnd-vd { color: #ff8a80; font-weight: 700; }\r\n/* \"Lua ok\" only in debug mode (decisions-1.md 57): the regex boxes; Lua strips it from its own boxes and marks the page in debug mode */\r\n.dnd-tag[data-v=\"ok\"] .dnd-vd { display: none; }\r\nbody:has(.dnd-dbg-on) .dnd-tag[data-v=\"ok\"] .dnd-vd { display: inline; }\r\n.dnd-hr { border-top: 1px solid #4d3e2c; margin: 6px 0; }\r\n.dnd-m { opacity: .65; }\r\n/* Rule-term tooltips (TRPG 익숙함 처음 / 조금, character tab): dotted underline; a tap opens the line\r\n   right below, in the flow (a floating box got cut off at the panel and chat edges) */\r\n.dnd-term { border-bottom: 1px dotted #d4af5a; cursor: help; outline: none; }\r\n.dnd-tip { display: none; margin: 4px 0 6px; padding: 6px 9px; background: #1f1914; color: #e8dcc4; border: 1px solid #6b5530;\r\n  border-left: 3px solid #d4af5a; border-radius: 3px; font-size: 12px; font-weight: 400; line-height: 1.5; white-space: normal; cursor: auto; }\r\n.dnd-term:focus .dnd-tip { display: block; }\r\n/* How to start: first message only, before the first reply */\r\n/* the guide box, the status panel, the fight line and the older messages' one-line summaries run the full width of the\r\n   message (user, 2026-10-12: \"pc에서 양 끝에 다 차도록\"; they were 480px in the middle) */\r\n.dnd-intro { margin: 4px 0 14px; padding: 9px 12px; box-sizing: border-box; font-size: 13px; line-height: 1.6;\r\n  color: #e8dcc4; background: #1f1914; border: 1px solid #6b5530; border-left: 3px solid #d4af5a; border-radius: 6px; }\r\n.dnd-intro > div + div { margin-top: 4px; }\r\n.dnd-intro b { color: #f1e6cf; }\r\n.dnd-intro-t { color: #d4af5a; font-weight: 700; font-family: 'Nanum Myeongjo', 'Noto Serif KR', 'Batang', serif; }\r\n/* Passive check (noticing without trying): a found thing is one quiet line; a miss shows only in debug mode */\r\n.dnd-passive { margin: 6px 0 10px; padding: 2px 10px; font-size: .84em; color: #d8c493; border-left: 2px solid #d4af5a; }\r\n.dnd-passive.miss { color: #c5b4e0; border-left-color: #8c75b8; }\r\n/* Rule line under a check or attack box (처음) */\r\n.dnd-explain { margin: -4px 0 8px; padding: 1px 12px 1px 16px; font-size: .78em; line-height: 1.5; color: #a8977a; }\r\n/* Suggested actions: each a row of its own, the chance in a gold pill on the left */\r\n.dnd-optline { display: flex; align-items: center; gap: 10px; margin: 5px 0; padding: 6px 10px; border: 1px solid #4d3e2c; border-radius: 6px;\r\n  background: rgba(38,30,23,.6); }\r\n.dnd-optline:first-of-type { margin-top: 12px; }\r\n.dnd-pct { flex: 0 0 44px; text-align: center; padding: 1px 0; border-radius: 999px; background: rgba(212,175,90,.14); color: #d4af5a;\r\n  font-weight: 800; font-size: .85em; font-variant-numeric: tabular-nums; }\r\n.dnd-optline b { flex: 1 1 auto; min-width: 0; color: #f6e7c6; }\r\n/* the fight line's labels (순서, 아군, 적: decisions-1.md 86) */\r\n.dnd-g { display: inline-block; min-width: 3.4em; margin-right: 6px; font-family: 'Nanum Myeongjo', 'Noto Serif KR', 'Batang', serif;\r\n  font-weight: 700; font-size: .9em; color: #a8977a; }\r\n.dnd-us .dnd-g { color: #6f9fd6; }\r\n.dnd-them .dnd-g { color: #d0574b; }\r\n\r\n/* Status panel (newest message) */\r\n.dnd-st { margin: 12px 0 4px; padding: 11px 13px 12px; box-sizing: border-box; background: #1d1712; color: #ead9b8;\r\n  border: 1px solid #4d3e2c; border-radius: 6px; font-family: 'Noto Sans KR', -apple-system, sans-serif; font-size: 13px; line-height: 1.55; }\r\n.dnd-st * { box-sizing: border-box; }\r\n.dnd-hd { display: flex; justify-content: space-between; align-items: baseline; gap: 8px; padding: 0 2px 7px;\r\n  border-bottom: 1px solid #4d3e2c; font-family: 'Nanum Myeongjo', 'Noto Serif KR', 'Batang', serif; }\r\n.dnd-hd b { color: #d4af5a; font-size: 14px; letter-spacing: .02em; }\r\n.dnd-hd span { color: #a8977a; font-size: 12px; }\r\n.dnd-alert { margin-top: 9px; padding: 5px 10px; border-radius: 5px; font-weight: 700; font-size: 12px; color: #d4af5a; background: rgba(212,175,90,.1); }\r\n.dnd-alert.bad { color: #f0a097; background: rgba(208,87,75,.16); }\r\n.dnd-alert:empty { display: none; }\r\n.dnd-delta { display: flex; flex-wrap: wrap; align-items: center; gap: 5px; margin-top: 8px; font-size: 11px; }\r\n.dnd-delta .dnd-l { display: inline; margin-right: 2px; }\r\n.dnd-delta .dnd-chip { padding: 1px 8px; border-radius: 999px; border: 1px solid #4d3e2c; color: #ead9b8; background: rgba(255,255,255,.03); white-space: nowrap; }\r\n.dnd-delta .dnd-chip.up { color: #c3d79a; border-color: #55613a; }\r\n.dnd-delta .dnd-chip.down { color: #f0a097; border-color: #7a2e27; }\r\n.dnd-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; margin-top: 10px; }\r\n.dnd-l { display: block; font-size: 11px; color: #a8977a; font-family: 'Nanum Myeongjo', 'Noto Serif KR', 'Batang', serif; font-weight: 700; }\r\n.dnd-v { display: block; font-weight: 800; color: #f6e7c6; font-variant-numeric: tabular-nums; }\r\n.dnd-bar { height: 7px; margin-top: 4px; background: #33281e; border-radius: 999px; overflow: hidden; }\r\n.dnd-fill { height: 100%; border-radius: 999px; background: linear-gradient(90deg, #8e2a24, #d0574b); }\r\n.dnd-xp .dnd-fill { background: linear-gradient(90deg, #8f6f2c, #d4af5a); }\r\n.dnd-sec { margin-top: 8px; padding-top: 7px; border-top: 1px solid rgba(77,62,44,.6); font-size: 12px; }\r\n.dnd-sec .dnd-l { display: inline-block; min-width: 3em; margin-right: 6px; }\r\n.dnd-fold { margin-top: 8px; }\r\n.dnd-fold > summary { list-style: none; cursor: pointer; text-align: center; font-size: 11px; font-weight: 700; color: #a8977a;\r\n  padding: 4px; border: 1px solid #4d3e2c; border-radius: 5px; font-family: 'Nanum Myeongjo', 'Noto Serif KR', 'Batang', serif; }\r\n.dnd-fold > summary::-webkit-details-marker { display: none; }\r\n.dnd-fold > summary::after { content: '▼ 배낭 열기'; }\r\n.dnd-fold[open] > summary::after { content: '▲ 배낭 닫기'; }\r\n.dnd-items { padding: 7px 10px; font-size: 12px; color: #d8ccb3; }\r\n/* second fold on the newest status panel: class features, spells, passive scores (Lua-drawn, with tooltips) */\r\n.dnd-fold.feat { margin-top: 4px; }\r\n.dnd-fold.feat > summary::after { content: '▼ 기능'; }\r\n.dnd-fold.feat[open] > summary::after { content: '▲ 기능 닫기'; }\r\n.dnd-feat-t { margin-top: 6px; font-size: 11px; font-weight: 700; color: #d4af5a; font-family: 'Nanum Myeongjo', 'Noto Serif KR', 'Batang', serif; }\r\n.dnd-feat-t:first-child { margin-top: 0; }\r\n/* the fight line (order, then our side and theirs: decisions-1.md 86) */\r\n.dnd-fight { margin: 14px 0 0; padding: 8px 12px; box-sizing: border-box; font-size: 13px; line-height: 1.7; color: #ead9b8;\r\n  background: #261e17; border: 1px solid #4d3e2c; border-top: 2px solid #d0574b; border-radius: 6px; }\r\n.dnd-fight + .dnd-st { margin-top: 4px; }\r\n.dnd-mini { margin: 10px 0 2px; padding: 3px 10px; font-size: 11.5px; opacity: .7; border-top: 1px solid rgba(128,128,128,.35); }\r\n@media (max-width: 420px) { .dnd-grid { grid-template-columns: 1fr; } }\r\n\r\n/* thread notes (떡밥) */\r\n.dnd-tag.thr { --c: #a99be0; background: rgba(150,130,220,.1); }\r\n\r\n/* settings drawer: open/close is a {{button}} + chat variable (class is-open), tabs are hidden radios.\r\n   The radios carry the message index in their ids, since an older message can keep a stale drawer */\r\n.dnd-rad1, .dnd-rad2, .dnd-rad3, .dnd-rad4, .dnd-rad5, .dnd-rad6, .dnd-rad7 { display: none; }\r\n/* an invisible {{button}} that fills its parent (the parent draws the look) */\r\n.dnd-hit { position: absolute; inset: 0; }\r\n.dnd-hit button { width: 100%; height: 100%; margin: 0; padding: 0; border: 0; background: transparent; opacity: 0; cursor: pointer; }\r\n/* the open button: an index tab stuck to the right edge of the screen, upper right (Hexid's spot) */\r\n.dnd-gear-bar { position: fixed; right: 0; top: 96px; z-index: 9990; }\r\n.dnd-gear { position: relative; display: block; padding: 12px 7px 12px 8px; cursor: pointer; font-size: 13px; font-weight: 700; letter-spacing: 2px;\r\n  writing-mode: vertical-rl; text-orientation: upright; color: #d4af5a; background: #1f1914;\r\n  border: 1px solid #6b5530; border-right: none; border-left: 3px solid #d4af5a; border-radius: 6px 0 0 6px;\r\n  font-family: 'Nanum Myeongjo', 'Noto Serif KR', 'Batang', serif; transition: padding-right .15s ease; }\r\n.dnd-gear:hover { padding-right: 11px; }\r\n.dnd-gear-bar.is-open { display: none; }\r\n.dnd-drawer { display: block; }\r\n.dnd-backdrop { position: fixed; top: 0; left: 0; width: 100%; height: 100%; background: rgba(0,0,0,.45); cursor: pointer; display: block;\r\n  opacity: 0; visibility: hidden; pointer-events: none; transition: opacity .25s ease, visibility .25s ease; z-index: 9998; }\r\n.dnd-drawer.is-open .dnd-backdrop { opacity: 1; visibility: visible; pointer-events: auto; }\r\n.dnd-panel { position: fixed; top: 0; right: 0; width: 320px; height: 100%; box-sizing: border-box; display: flex; flex-direction: column; z-index: 9999;\r\n  background: #1f1914; color: #e8dcc4; border-left: 1px solid #6b5530; font-family: 'Noto Sans KR', -apple-system, sans-serif; font-size: 13px;\r\n  transform: translateX(100%); visibility: hidden; transition: transform .3s ease, visibility .3s ease; }\r\n.dnd-drawer.is-open .dnd-panel { transform: translateX(0); visibility: visible; }\r\n.dnd-panel-hd { display: flex; justify-content: space-between; align-items: center; padding: 14px 16px; border-bottom: 1px solid #6b5530;\r\n  font-family: 'Nanum Myeongjo', 'Noto Serif KR', 'Batang', serif; }\r\n.dnd-panel-hd b { color: #d4af5a; font-size: 15px; }\r\n.dnd-close { position: relative; cursor: pointer; padding: 0 4px; color: #a8977a; }\r\n.dnd-tabs { display: flex; border-bottom: 1px solid #4a3c2c; }\r\n.dnd-tab { flex: 1; text-align: center; padding: 9px 0; cursor: pointer; font-weight: 700; color: #7d6e58; }\r\n.dnd-rad1:checked ~ .dnd-drawer .dnd-tab-1, .dnd-rad2:checked ~ .dnd-drawer .dnd-tab-2, .dnd-rad3:checked ~ .dnd-drawer .dnd-tab-3,\r\n.dnd-rad4:checked ~ .dnd-drawer .dnd-tab-4, .dnd-rad5:checked ~ .dnd-drawer .dnd-tab-5, .dnd-rad6:checked ~ .dnd-drawer .dnd-tab-6,\r\n.dnd-rad7:checked ~ .dnd-drawer .dnd-tab-7\r\n  { color: #d4af5a; border-bottom: 2px solid #d4af5a; pointer-events: none; }\r\n.dnd-panel-body { flex: 1; overflow-y: auto; padding: 12px 16px; }\r\n.dnd-pane-1, .dnd-pane-2, .dnd-pane-3, .dnd-pane-4, .dnd-pane-5, .dnd-pane-6, .dnd-pane-7 { display: none; }\r\n.dnd-rad1:checked ~ .dnd-drawer .dnd-pane-1, .dnd-rad2:checked ~ .dnd-drawer .dnd-pane-2, .dnd-rad3:checked ~ .dnd-drawer .dnd-pane-3,\r\n.dnd-rad4:checked ~ .dnd-drawer .dnd-pane-4, .dnd-rad5:checked ~ .dnd-drawer .dnd-pane-5, .dnd-rad6:checked ~ .dnd-drawer .dnd-pane-6,\r\n.dnd-rad7:checked ~ .dnd-drawer .dnd-pane-7 { display: block; }\r\n/* debug tab (디버그 모드 only) */\r\n.dnd-tab-4 { color: #8a7a9e; }\r\n.dnd-dbg-btns { flex-wrap: wrap; margin: 4px 0 10px; }\r\n.dnd-dbg-btns .dnd-opt-btn { flex: 1 1 28%; }\r\n.dnd-pre { max-height: 260px; overflow-y: auto; margin: 4px 0 10px; padding: 6px 8px; font-family: Consolas, 'D2Coding', monospace;\r\n  font-size: 11px; line-height: 1.45; color: #cbbd9f; background: #17120e; border: 1px solid #4a3c2c; word-break: break-all; }\r\n.dnd-sheet-hd { display: flex; justify-content: space-between; align-items: baseline; margin-bottom: 8px; font-family: 'Nanum Myeongjo', 'Noto Serif KR', 'Batang', serif; }\r\n.dnd-sheet-hd b { color: #d4af5a; font-size: 15px; }\r\n.dnd-sheet-hd span { color: #a8977a; font-size: 12px; }\r\n.dnd-abil { display: grid; grid-template-columns: 1fr 1fr 1fr; gap: 6px; margin: 6px 0; }\r\n.dnd-ab { text-align: center; padding: 5px 0; border: 1px solid #4a3c2c; background: #241d17; }\r\n.dnd-ab.sv { border-color: #b8923f; }\r\n.dnd-ab span { display: block; font-size: 11px; color: #a8977a; }\r\n.dnd-ab b { display: block; font-size: 17px; color: #f1e6cf; }\r\n.dnd-ab i { font-style: normal; font-size: 12px; color: #d4af5a; }\r\n.dnd-opt-t + .dnd-opt-d { margin-bottom: 10px; }\r\n.dnd-thr { padding: 8px 10px; margin-bottom: 8px; border-left: 3px solid #a99be0; background: rgba(150,130,220,.08); }\r\n.dnd-thr.due { border-left-color: #d4af5a; }\r\n.dnd-empty { color: #a8977a; padding: 8px 0; }\r\n.dnd-opt { padding: 10px 0; border-bottom: 1px dashed #4a3c2c; }\r\n.dnd-opt-t { font-weight: 700; color: #f1e6cf; }\r\n.dnd-opt-d { font-size: 12px; color: #a8977a; margin: 3px 0 8px; }\r\n.dnd-err { color: #ff8a80; }\r\n.dnd-opt-btns { display: flex; gap: 6px; }\r\n/* a row of buttons right after another row or before the next title: level-up HP choice, then level-up / ASI (user) */\r\n.dnd-opt-btns + .dnd-opt-btns, .dnd-opt-btns + .dnd-opt-t { margin-top: 8px; }\r\n/* option buttons: a {{button}} macro (a real <button>) inside the span; the button fills it, the span draws it */\r\n.dnd-opt-btn { flex: 1; display: flex; cursor: pointer; font-weight: 700; font-size: 12px;\r\n  color: #a8977a; border: 1px solid #4a3c2c; border-radius: 3px; background: #241d17; }\r\n.dnd-opt-btn.is-on { color: #1a1410; background: #d4af5a; border-color: #d4af5a; }\r\n.dnd-opt-btn button { flex: 1; width: 100%; padding: 8px 6px; margin: 0; background: transparent; border: none; color: inherit;\r\n  font: inherit; font-weight: 700; cursor: pointer; line-height: 1.4; word-break: keep-all; }\r\n/* a choice the rules do not allow now (Scholar on a skill without proficiency): shown, not clickable */\r\n.dnd-opt-btn.off { opacity: .45; cursor: default; padding: 8px 6px; line-height: 1.4; justify-content: center; font-weight: 400; }\r\n/* the settings and DLC tabs (decisions-1.md 502, user: \"다닥다닥 붙어있으니\"): each title, text and toggle one block, room between\r\n   the blocks; the character tab's rows keep their tighter spacing */\r\n.dnd-set .dnd-opt { padding: 16px 0 18px; }\r\n.dnd-set .dnd-opt:first-child { padding-top: 4px; }\r\n.dnd-set .dnd-opt:last-child { border-bottom: none; }\r\n.dnd-set .dnd-opt-d { margin: 6px 0 12px; line-height: 1.6; }\r\n/* 📖 rules tab (decisions-1.md 82): SRD 5.2.1 in short, in folded groups (details, so opening one redraws nothing) */\r\n.dnd-dict-g { border-bottom: 1px solid #4a3c2c; }\r\n.dnd-dict-g > summary { padding: 10px 2px; cursor: pointer; font-weight: 700; color: #f1e6cf; list-style: none; }\r\n.dnd-dict-g > summary::-webkit-details-marker { display: none; }\r\n.dnd-dict-g > summary::before { content: \"▸ \"; color: #d4af5a; }\r\n.dnd-dict-g[open] > summary::before { content: \"▾ \"; }\r\n.dnd-dict-e { padding: 7px 2px 8px 12px; border-top: 1px dashed #3a3024; }\r\n.dnd-dict-e b { color: #d4af5a; }\r\n.dnd-dict-en { margin-left: 6px; font-size: 11px; color: #8a7a62; }\r\n.dnd-dict-e div { margin-top: 2px; font-size: 12px; line-height: 1.55; color: #cbbd9f; word-break: keep-all; }\r\n@media (max-width: 768px) { .dnd-panel { width: 100%; } }\r\n/* a Lua error without opening the drawer (decisions-1.md 81): fixed at the bottom middle of the screen and fading\r\n   after a while, so the reply's height does not change and the bottom-anchored chat does not jump (as 비현현's .bh-toast).\r\n   Shown at once, no fade-in: a streaming reply redraws it on every chunk, and a fade-in restarted each time would flicker */\r\n.dnd-toast { position: fixed; left: 50%; bottom: 110px; transform: translateX(-50%); z-index: 975;\r\n  width: max-content; max-width: min(520px, 88vw); padding: 8px 14px; border-radius: 8px; box-sizing: border-box;\r\n  background: #2b1a14; color: #f1e3c4; border: 1px solid #b0413e; font-size: .9em; line-height: 1.45; pointer-events: none;\r\n  animation: dnd-toast 8s ease forwards; }\r\n@keyframes dnd-toast { 0% { opacity: 1; } 85% { opacity: 1; } 100% { opacity: 0; visibility: hidden; } }\r\n/* the status card (decisions-1.md 106; the preview ui/sheet-preview/): a tab row that swaps the card's body, one line per\r\n   person with an HP bar, kits in labelled rows, spells folded to their slot dots, and in a fight the order and both sides */\r\n.dnd-ctabs { display: flex; margin: 9px -13px 0; border-top: 1px solid #4d3e2c; border-bottom: 1px solid #4d3e2c; background: #1a1511; }\r\n.dnd-ctab { position: relative; flex: 1; text-align: center; padding: 7px 0 6px; font-size: 12.5px; font-weight: 700; color: #8a7a62;\r\n  border-bottom: 2px solid transparent; cursor: pointer; }\r\n.dnd-ctab.on { color: #d4af5a; border-bottom-color: #d4af5a; background: rgba(212,175,90,.06); pointer-events: none; }\r\n.dnd-ctab i { font-style: normal; margin-left: 3px; padding: 0 5px; border-radius: 999px; background: rgba(212,175,90,.18); color: #d4af5a; font-size: 10.5px; }\r\n.dnd-cbody { padding-top: 10px; }\r\n.dnd-cbody > .dnd-delta:first-child, .dnd-cbody > .dnd-grid:first-child { margin-top: 0; }\r\n.dnd-unit { display: grid; grid-template-columns: minmax(0, 17em) minmax(32px, 1fr) auto; align-items: center; column-gap: 8px; padding: 4px 0; }\r\n/* decisions-1.md 269 (user: on a phone a name of 4+ letters cut off 방어도): the name column takes the room first, the bar gives way */\r\n.dnd-unit + .dnd-unit { border-top: 1px solid #2f261d; }\r\n.dnd-unit.dim { opacity: .55; }\r\n.dnd-who { min-width: 0; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }\r\n.dnd-who b { color: #f6e7c6; }\r\n.dnd-who small { margin-left: 4px; color: #a8977a; font-size: 11px; }\r\n.dnd-hb { display: block; height: 5px; background: #33281e; border-radius: 999px; overflow: hidden; }\r\n.dnd-hb > span { display: block; height: 100%; border-radius: 999px; background: linear-gradient(90deg, #8e2a24, #d0574b); }\r\n.dnd-hb.low > span { background: linear-gradient(90deg, #6f1f1a, #e0614f); }\r\n.dnd-hb.foe > span { background: linear-gradient(90deg, #5a3a6e, #9a72c0); }\r\n.dnd-num { min-width: 3.6em; text-align: right; white-space: nowrap; color: #ead9b8; font-size: 12px; font-variant-numeric: tabular-nums; }\r\n.dnd-dl { margin-right: 4px; font-size: 11px; font-weight: 700; color: #f0a097; }\r\n.dnd-dl.up { color: #c3d79a; }\r\n.dnd-unit > .dnd-kit, .dnd-unit > .dnd-uc { grid-column: 1 / -1; }\r\n.dnd-uc { display: flex; flex-wrap: wrap; gap: 4px 5px; margin-top: 3px; }\r\n.dnd-cc { display: inline-flex; align-items: center; height: 20px; padding: 0 7px; font-size: 11px; border: 1px solid #5a4a32; border-radius: 4px;\r\n  color: #d9bf86; background: #1a1510; white-space: nowrap; }\r\n.dnd-cc.bad { color: #f0a097; border-color: #7a2e27; background: rgba(208,87,75,.1); }\r\n.dnd-cc.conc { color: #bcd1f0; border-color: #3d5576; background: rgba(111,159,214,.1); }\r\n.dnd-units { margin-top: 3px; }\r\n.dnd-kit { display: grid; gap: 1px; margin: 4px 0 2px; padding: 5px 8px 6px; background: rgba(0,0,0,.2); border-left: 2px solid #5a4a32;\r\n  border-radius: 0 4px 4px 0; font-size: 11.5px; line-height: 1.5; }\r\n.dnd-kr, .dnd-sbook > summary, .dnd-ksp > summary { display: grid; grid-template-columns: 6.6em minmax(0, 1fr); column-gap: 8px; align-items: baseline; }\r\n.dnd-kk { white-space: nowrap; color: #a8977a; font-weight: 700; }\r\n.dnd-kv { min-width: 0; color: #e3d4b4; }\r\n.dnd-kv b { color: #f6e7c6; }\r\n.dnd-dim { color: #a8977a; }\r\n.dnd-pips { display: inline-flex; gap: 2px; margin: 0 2px 0 4px; vertical-align: 1px; }\r\n.dnd-pip { display: inline-block; width: 7px; height: 7px; border-radius: 50%; background: #d4af5a; }\r\n.dnd-pip.used { background: transparent; box-shadow: inset 0 0 0 1px #6b5530; }\r\n.dnd-pipn { color: #a8977a; font-size: 11px; }\r\n.dnd-use { display: inline-flex; align-items: center; margin-right: 10px; white-space: nowrap; }\r\n.dnd-sbook > summary, .dnd-ksp > summary { list-style: none; cursor: pointer; align-items: center; }\r\n.dnd-sbook > summary::-webkit-details-marker, .dnd-ksp > summary::-webkit-details-marker { display: none; }\r\n.dnd-sbook > summary .dnd-kv, .dnd-ksp > summary .dnd-kv { display: flex; align-items: center; flex-wrap: wrap; gap: 2px 10px; }\r\n.dnd-sbook > summary .dnd-kk { font-family: 'Nanum Myeongjo', 'Noto Serif KR', 'Batang', serif; font-size: 11px; }\r\n/* in a status row the fold lines up with 장비 / 자원 / 지갑 (their label: 3em + 6px) */\r\n.dnd-sec > .dnd-sbook > summary { grid-template-columns: 3em minmax(0, 1fr); column-gap: 6px; }\r\n.dnd-slots { display: inline-flex; flex-wrap: wrap; gap: 2px 10px; }\r\n.dnd-sl { display: inline-flex; align-items: center; font-size: 11px; color: #a8977a; font-variant-numeric: tabular-nums; }\r\n.dnd-more { margin-left: auto; display: inline-flex; align-items: center; height: 20px; padding: 0 9px; border-radius: 999px; border: 1px solid #8a6d38;\r\n  background: rgba(212,175,90,.14); color: #d4af5a; font-size: 11px; font-weight: 700; white-space: nowrap; }\r\n.dnd-sbook[open] .dnd-more, .dnd-ksp[open] .dnd-more { background: transparent; border-color: #5a4a32; color: #a8977a; }\r\n.dnd-sbook[open] .mc, .dnd-ksp[open] .mc, .dnd-sbook:not([open]) .mo, .dnd-ksp:not([open]) .mo { display: none; }\r\n.dnd-book { margin-top: 6px; padding: 6px 8px 7px; border: 1px solid #3a3024; border-radius: 4px; font-size: 11.5px; }\r\n.dnd-ksp .dnd-book { margin-top: 3px; padding: 2px 0; border: 0; }\r\n.dnd-book-hd { display: flex; justify-content: space-between; align-items: baseline; flex-wrap: wrap; gap: 2px 8px; margin-bottom: 3px; }\r\n.dnd-book-hd b { color: #d4af5a; font-family: 'Nanum Myeongjo', 'Noto Serif KR', 'Batang', serif; }\r\n.dnd-book-hd span { color: #a8977a; font-size: 10.5px; }\r\n.dnd-book .dnd-kr { padding: 2px 0; }\r\n.dnd-sbook .dnd-book .dnd-kv { display: flex; flex-wrap: wrap; gap: 3px 4px; }\r\n.dnd-sp { display: inline-flex; align-items: center; min-height: 19px; padding: 0 6px; border-radius: 3px; border: 1px dashed #4d3e2c; color: #a8977a; font-size: 11px; }\r\n.dnd-sp.on { border-style: solid; border-color: #8a6d38; color: #f6e7c6; background: rgba(212,175,90,.1); }\r\n.dnd-sp sup, .dnd-kv sup, .dnd-book-note sup { margin-left: 2px; font-size: 9px; color: #b9a2e0; }\r\n.dnd-dot { display: inline-block; width: 7px; height: 7px; margin: 0 3px 0 6px; border-radius: 2px; border: 1px dashed #6b5530; }\r\n.dnd-dot.on { border-style: solid; border-color: #8a6d38; background: rgba(212,175,90,.35); }\r\n.dnd-book-note, .dnd-book-ft { margin-top: 5px; font-size: 10.5px; color: #a8977a; }\r\n/* the fight: order chips with an arrow before each (drawn by the chip, so a chip not shown takes its arrow along) */\r\n.dnd-order { display: flex; flex-wrap: wrap; align-items: center; gap: 4px 0; }\r\n.dnd-order > .dnd-l { display: inline; margin-right: 8px; }\r\n.dnd-oc { display: inline-flex; align-items: center; gap: 4px; height: 22px; padding: 0 8px; border-radius: 999px; font-size: 11.5px; border: 1px solid #4d3e2c;\r\n  color: #cbbd9f; background: #1a1510; white-space: nowrap; }\r\n.dnd-oc + .dnd-oc { position: relative; margin-left: 16px; }\r\n.dnd-oc + .dnd-oc::before { content: \"▸\"; position: absolute; left: -12px; top: 50%; transform: translateY(-55%); font-size: 11px; color: #b8923f; }\r\n.dnd-oc small { color: #8a7a62; font-variant-numeric: tabular-nums; }\r\n.dnd-oc.foe { border-color: #6a4a7e; }\r\n.dnd-oc.done { color: #7d6e58; border-color: #3a3024; background: transparent; }\r\n.dnd-oc.done small { color: #5f5444; }\r\n.dnd-oc.next { color: #1a1410; background: #d4af5a; border-color: #d4af5a; font-weight: 700; }\r\n.dnd-oc.next small { color: #4a3a1a; }\r\n.dnd-side { margin-top: 10px; }\r\n.dnd-side > .dnd-l { margin-bottom: 3px; }\r\n.dnd-side.ally > .dnd-l { color: #8fb3e0; }\r\n.dnd-side.foe > .dnd-l { color: #c99bd8; }\r\n.dnd-fallen { margin-top: 4px; font-size: 11.5px; color: #8a7a62; }\r\n.dnd-fcols { display: grid; grid-template-columns: minmax(0, 1fr); column-gap: 18px; }\r\n@media (min-width: 900px) { .dnd-fcols { grid-template-columns: minmax(0, 1.4fr) minmax(0, 1fr); } }\r\n/* the 동료 tab */\r\n.dnd-comp { border: 1px solid #4d3e2c; background: #241d17; border-radius: 6px; padding: 10px 11px 11px; }\r\n.dnd-comp + .dnd-comp { margin-top: 10px; }\r\n.dnd-hero { display: flex; gap: 12px; align-items: flex-start; }\r\n.dnd-face { position: relative; flex: none; width: 46px; height: 46px; border-radius: 8px; background: radial-gradient(circle at 50% 35%, #3a2e22, #1a1510);\r\n  box-shadow: 0 0 0 2px #1d1712, 0 0 0 3px #b8923f; display: grid; place-items: center; font-family: 'Nanum Myeongjo', 'Noto Serif KR', 'Batang', serif;\r\n  color: #d4af5a; font-size: 18px; }\r\n.dnd-lvb { position: absolute; left: -6px; bottom: -6px; min-width: 20px; height: 20px; padding: 0 4px; border-radius: 999px; background: #1a1410;\r\n  border: 1px solid #b8923f; color: #f6e7c6; font: 700 11px/18px 'Noto Sans KR', sans-serif; text-align: center; }\r\n.dnd-hero-t { min-width: 0; display: grid; gap: 4px; }\r\n.dnd-hero-t .dnd-uc { margin-top: 0; }\r\n.dnd-name { font-family: 'Nanum Myeongjo', 'Noto Serif KR', 'Batang', serif; font-size: 16px; font-weight: 700; color: #f6e7c6; line-height: 1.2; }\r\n.dnd-memo { font-size: 12px; color: #a8977a; }\r\n.dnd-hpl { display: flex; justify-content: space-between; gap: 8px; margin: 9px 0 3px; font-size: 12px; color: #a8977a; }\r\n.dnd-hpl b { color: #f6e7c6; font-variant-numeric: tabular-nums; }\r\n.dnd-comp .dnd-opt-btns { margin-top: 8px; }\r\n.dnd-pfoot { margin-top: 14px; padding-top: 10px; border-top: 1px dashed #4a3c2c; }\r\n.dnd-pfoot .dnd-opt-d { margin-bottom: 8px; }\r\n/* decisions-1.md 107: the drawer's handle is \"❖ 설정\" on a PC and \"❖\" alone on a phone (the user found \"모험 설정\" long\r\n   there), with a dot while something is left to pick; in the shop, the line already in the chat as the user's message */\r\n.dnd-gear-dot { display: inline-block; width: 7px; height: 7px; margin-top: 5px; border-radius: 50%; background: #e0614f; }\r\n@media (max-width: 768px) { .dnd-gear-t { display: none; } .dnd-gear { padding: 11px 6px 11px 7px; font-size: 15px; letter-spacing: 0; } }\r\n.dnd-sent { margin: 8px 0 6px; padding: 7px 10px; border-left: 3px solid #4a5568; background: #23262d; border-radius: 0 4px 4px 0;\r\n  font-size: 12px; color: #c9d1d9; }\r\n.dnd-sent-l { display: block; margin-bottom: 2px; font-size: 11px; font-weight: 700; color: #9fb0c0; }\r\n.dnd-sent small { display: block; margin-top: 3px; font-size: 10.5px; color: #8b949e; }\r\n/* decisions-1.md 108: the drawer's character tab as a card (the persona's picture over the glyph, four cells, XP, what is\r\n   left to pick open, the rest folded) and the shop as one row an item */\r\n.dnd-face.lg { width: 60px; height: 60px; font-size: 22px; }\r\n.dnd-face-p { position: absolute; inset: 0; border-radius: 8px; background-position: center top; background-size: cover; background-repeat: no-repeat; }\r\n.dnd-vit { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 6px; margin-top: 12px; }\r\n.dnd-vit > div { padding: 4px 6px; text-align: center; border: 1px solid #3a3024; border-radius: 4px; background: #191410; }\r\n.dnd-vit small { display: block; font-size: 10.5px; color: #a8977a; }\r\n.dnd-vit b { display: block; font-size: 14px; color: #f6e7c6; font-variant-numeric: tabular-nums; }\r\n.dnd-subl { font-size: 11.5px; color: #a8977a; }\r\n.dnd-xpl { margin-top: 8px; font-size: 12px; }\r\n.dnd-xpl > div:first-child { display: flex; justify-content: space-between; gap: 8px; color: #a8977a; }\r\n.dnd-xpl b { color: #f6e7c6; font-variant-numeric: tabular-nums; }\r\n.dnd-todo { margin-top: 12px; padding: 6px 10px; border-radius: 5px; font-size: 12px; font-weight: 700; color: #d4af5a;\r\n  background: rgba(212,175,90,.1); border: 1px solid rgba(212,175,90,.35); }\r\n.dnd-open { margin-top: 4px; padding-bottom: 6px; border-bottom: 1px solid #3a3024; }\r\n.dnd-sect { border-bottom: 1px solid #3a3024; }\r\n.dnd-sect > summary { display: flex; align-items: center; gap: 6px; padding: 9px 2px; list-style: none; cursor: pointer; font-weight: 700; color: #f1e6cf;\r\n  font-family: 'Nanum Myeongjo', 'Noto Serif KR', 'Batang', serif; }\r\n.dnd-sect > summary::-webkit-details-marker { display: none; }\r\n.dnd-sect > summary::before { content: \"▸\"; color: #d4af5a; font-family: 'Noto Sans KR', sans-serif; }\r\n.dnd-sect[open] > summary::before { content: \"▾\"; }\r\n.dnd-sect > summary i { font-style: normal; font-family: 'Noto Sans KR', sans-serif; font-size: 11px; color: #a8977a; }\r\n.dnd-sect-b { padding: 0 2px 11px; font-size: 12.5px; color: #d8ccb3; }\r\n.dnd-sect-b > div + div { margin-top: 3px; }\r\n.dnd-shop-hd { display: flex; justify-content: space-between; align-items: baseline; margin: 8px 0 2px; font-size: 12px; color: #a8977a; }\r\n.dnd-shop-hd b { font-size: 13px; color: #f6e7c6; }\r\n.dnd-grp { margin: 12px 0 2px; font-family: 'Nanum Myeongjo', 'Noto Serif KR', 'Batang', serif; font-size: 12px; font-weight: 700; color: #d4af5a; }\r\n.dnd-item { display: grid; grid-template-columns: minmax(0, 1fr) auto auto; column-gap: 8px; row-gap: 2px; align-items: center; padding: 6px 0;\r\n  border-bottom: 1px solid #2f261d; }\r\n.dnd-item-n { grid-column: 1; font-size: 12.5px; color: #f1e6cf; }\r\n.dnd-item-m { grid-column: 1; font-size: 11px; line-height: 1.4; color: #a8977a; }\r\n.dnd-item-p { grid-column: 2; grid-row: 1 / span 2; font-size: 12px; color: #ead9b8; white-space: nowrap; font-variant-numeric: tabular-nums; }\r\n.dnd-item-b { grid-column: 3; grid-row: 1 / span 2; display: flex; gap: 4px; font-size: 11px; white-space: nowrap; }\r\n.dnd-item-b .dnd-opt-btn { flex: none; }\r\n.dnd-item-b .dnd-opt-btn button { padding: 4px 10px; }\r\n/* decisions-1.md 109: while the prepared spells can change, each one in the spell block is a tap */\r\n.dnd-sp.dnd-tg { position: relative; min-height: 24px; padding: 0 8px; cursor: pointer; }\r\n.dnd-sp.dnd-tg:not(.on) { color: #cbbd9f; }\r\n.dnd-prep { margin: 2px 0 5px; font-size: 11px; color: #d4af5a; }\r\n.dnd-prep.bad { color: #f0a097; }\r\n/* decisions-1.md 111 (user: \"피격처럼 배경색에 그라데이션 들어간 거 다른거에도\"): every box tinted from the left with its own\r\n   color, as the attack boxes were (the pending ones stay plain); the enemies a fight opens with, one chip each */\r\n.dnd-tag { background: linear-gradient(90deg, rgba(58,45,30,.92), rgba(29,23,18,.75)); }\r\n.dnd-tag.chk { background: linear-gradient(90deg, rgba(66,52,22,.9), rgba(29,23,18,.75)); }\r\n.dnd-tag.heal { background: linear-gradient(90deg, rgba(32,52,26,.9), rgba(29,23,18,.75)); }\r\n.dnd-tag.war { background: linear-gradient(90deg, rgba(62,24,20,.92), rgba(29,23,18,.75)); }\r\n.dnd-tag.thr { background: linear-gradient(90deg, rgba(46,38,70,.9), rgba(29,23,18,.75)); }\r\n.dnd-tag.pend { background: none; }\r\n.dnd-tag .dnd-foe { display: inline-block; margin: 2px 5px 2px 0; padding: 0 8px; border: 1px solid rgba(208,87,75,.55); border-radius: 999px;\r\n  background: rgba(208,87,75,.13); color: #f3c9c2; font-size: .86em; line-height: 1.6; white-space: nowrap; vertical-align: 1px; }\r\n.dnd-tag .dnd-foe small { color: #c99b93; font-size: .85em; }\r\n.dnd-tag .dnd-foe.unk { border-style: dashed; opacity: .8; }\r\n/* decisions-1.md 113 (user: \"줄줄 쓰지 말고 좀 나눠둘까요 보기좋게\"): a box's detail line as labelled parts that wrap part by part */\r\n.dnd-sfs { display: flex; flex-wrap: wrap; align-items: center; gap: 2px 14px; }\r\n.dnd-sf { white-space: nowrap; color: #cbbd9f; }\r\n.dnd-sf > i { margin-right: 5px; font-style: normal; color: #8a7a62; }\r\n/* decisions-1.md 281 (user: \"이거 상자를 빠져나가요\"): a Korean word stays whole when a box's line wraps (\"실/패\", \"피/해\"), and\r\n   anything still too long for a phone breaks rather than leaving the box */\r\n.dnd-tag { word-break: keep-all; overflow-wrap: anywhere; }\r\n.dnd-tag .dnd-r { white-space: nowrap; }\r\n/* decisions-1.md 116 (user: \"이것도 칩에 넣어서\"): the character and spell boxes, a labelled row of chips (a score, a skill, a spell) */\r\n.dnd-cr { display: flex; align-items: flex-start; gap: 6px; margin-top: 4px; font-size: .8em; color: #a8977a; }\r\n.dnd-cr > i { flex: none; min-width: 3.2em; padding-top: 1px; font-style: normal; color: #8a7a62; }\r\n.dnd-crs { display: flex; flex-wrap: wrap; gap: 3px 4px; }\r\n.dnd-cr .dnd-sp small { margin-left: 3px; color: #d4af5a; font-size: 9.5px; }\r\n</style>\r\n<style media=\"all\">.default-chat-screen{overflow-anchor:none}</style>\r\n","bias":[],"customScripts":[{"ableFlag":true,"comment":"판정 표시 (검증 후)","flag":"g","in":"\\[CHECK\\|([^|\\]]+)\\|([^|\\]]+)\\|([+-]?\\d+)\\|(\\d+)\\|(success|failure|성공|실패)\\|(ok|bad:[^|\\]]*)\\|(-?\\d+)\\]","out":"<div class=\"dnd-tag chk\" data-v=\"$6\"><div class=\"dnd-h\"><span class=\"dnd-chip\">◆ 판정</span><b>$1</b> <span class=\"dnd-big\">$7</span> vs 난이도 $4 · <b class=\"dnd-r\" data-r=\"$5\">$5</b></div><div class=\"dnd-sub\">d20 $2 $3 · <span class=\"dnd-vd\">Lua $6</span></div></div>","type":"editdisplay"},{"ableFlag":true,"comment":"판정 표시 (검증 전)","flag":"g","in":"\\[CHECK\\|([^|\\]]+)\\|([^|\\]]+)\\|([+-]?\\d+)\\|(\\d+)\\|(success|failure|성공|실패)\\]","out":"<div class=\"dnd-tag pend\"><div class=\"dnd-h\"><span class=\"dnd-chip\">◆ 판정</span><b>$1</b> vs 난이도 $4 · <b>$5</b></div><div class=\"dnd-sub\">d20 $2 $3 · 검증 전</div></div>","type":"editdisplay"},{"ableFlag":true,"comment":"공격 표시 (검증 후)","flag":"g","in":"\\[ATTACK\\|([^|\\]]+)\\|([^|\\]]+)\\|([^|\\]]+)\\|([+-]?\\d+)\\|(\\d+)\\|(hit|miss|crit|명중|빗나감|치명타)\\|([^|\\]]*)\\|([^|\\]]*)\\|(-?\\d+)\\|(ok|bad:[^|\\]]*)\\|([^|\\]]*)\\]","out":"<div class=\"dnd-tag atk\" data-v=\"$10\"><div class=\"dnd-h\"><span class=\"dnd-chip\">† 공격</span><b>$1</b> → <b>$2</b> · <b class=\"dnd-r\" data-r=\"$6\">$6</b> · 피해 <span class=\"dnd-big\">$9</span></div><div class=\"dnd-sub\">d20 $3 $4 vs 방어도 $5 · $7: $8 · $2 HP $11 · <span class=\"dnd-vd\">Lua $10</span></div></div>","type":"editdisplay"},{"ableFlag":true,"comment":"공격 표시 (검증 전)","flag":"g","in":"\\[ATTACK\\|([^|\\]]+)\\|([^|\\]]+)\\|([^|\\]]+)\\|([+-]?\\d+)\\|(\\d+)\\|(hit|miss|crit|명중|빗나감|치명타)\\|([^|\\]]*)\\|([^|\\]]*)\\|(-?\\d+)\\]","out":"<div class=\"dnd-tag pend\"><div class=\"dnd-h\"><span class=\"dnd-chip\">† 공격</span><b>$1</b> → <b>$2</b> · <b>$6</b> · 피해 $9</div><div class=\"dnd-sub\">d20 $3 $4 vs 방어도 $5 · $7: $8 · 검증 전</div></div>","type":"editdisplay"},{"ableFlag":true,"comment":"전투 시작 표시","flag":"g","in":"\\[COMBAT\\|([^\\]]*?)(?:\\|(ok|bad:[^|\\]]*))?\\]","out":"<div class=\"dnd-tag war\"><div class=\"dnd-h\"><span class=\"dnd-chip\">◈ 전투 시작</span>$1</div><div class=\"dnd-sub\">$2</div></div>","type":"editdisplay"},{"ableFlag":true,"comment":"전투 종료 선언 표시","flag":"g","in":"\\[COMBAT_END(?:\\|([^\\]]*))?\\]","out":"<div class=\"dnd-tag war\"><div class=\"dnd-h\"><span class=\"dnd-chip\">◇ 전투 종료</span>$1</div></div>","type":"editdisplay"},{"ableFlag":true,"comment":"HP 줄 (최신 메시지)","flag":"g<cbs>","in":"{{#when::{{chat_index}}::is::{{lastmessageid}}}}\\[HP\\|([^|\\]]*)\\|([^\\]]*)\\]{{:else}}(?!){{/when}}","out":"<div class=\"dnd-fight\"><span class=\"dnd-g\">† 순서</span>$1<div class=\"dnd-hr\"></div><span class=\"dnd-g\">♥ 생명력</span>$2</div>","type":"editdisplay"},{"ableFlag":true,"comment":"HP 줄 요청에서 빼기","flag":"g","in":"\\n?\\[HP\\|[^\\]]*\\]","out":"","type":"editprocess"},{"ableFlag":true,"comment":"시간 표시","flag":"g","in":"\\[TIME\\|([^|\\]]*)\\|(ok|bad:[^|\\]]*)\\|([^\\]]*)\\]","out":"<div class=\"dnd-tag\" data-v=\"$2\"><div class=\"dnd-h\"><span class=\"dnd-chip\">◷ 시간</span>$3</div><div class=\"dnd-sub\">$1 · <span class=\"dnd-vd\">Lua $2</span></div></div>","type":"editdisplay"},{"ableFlag":true,"comment":"휴식 표시","flag":"g","in":"\\[REST\\|([^|\\]]+(?:\\|\\d+)?)\\|(ok|bad:[^|\\]]*)\\|([^\\]]*)\\]","out":"<div class=\"dnd-tag\" data-v=\"$2\"><div class=\"dnd-h\"><span class=\"dnd-chip\">☾ 휴식</span><b>$1</b> · $3</div><div class=\"dnd-sub\"><span class=\"dnd-vd\">Lua $2</span></div></div>","type":"editdisplay"},{"ableFlag":true,"comment":"경험치 표시","flag":"g","in":"\\[XP\\|([^|\\]]*)\\|([^|\\]]*)\\|(ok|auto|bad:[^|\\]]*)\\|([^\\]]*)\\]","out":"<div class=\"dnd-tag chk\" data-v=\"$3\"><div class=\"dnd-h\"><span class=\"dnd-chip\">✦ 경험치</span><span class=\"dnd-big\">+$1</span> · $4</div><div class=\"dnd-sub\">$2 · <span class=\"dnd-vd\">Lua $3</span></div></div>","type":"editdisplay"},{"ableFlag":true,"comment":"소지품 표시","flag":"g","in":"\\[ITEM\\|([^|\\]]*)\\|([^|\\]]*)\\|(ok|bad:[^|\\]]*)\\|([^\\]]*)\\]","out":"<div class=\"dnd-tag\" data-v=\"$3\"><div class=\"dnd-h\"><span class=\"dnd-chip\">▪ 소지품</span><b>$1</b> ×$2</div><div class=\"dnd-sub\">보유 $4 · <span class=\"dnd-vd\">Lua $3</span></div></div>","type":"editdisplay"},{"ableFlag":true,"comment":"돈 표시","flag":"g","in":"\\[GOLD\\|([^|\\]]*)\\|(ok|bad:[^|\\]]*)\\|([^\\]]*)\\]","out":"<div class=\"dnd-tag\" data-v=\"$2\"><div class=\"dnd-h\"><span class=\"dnd-chip\">¤ 지갑</span><b>$1</b></div><div class=\"dnd-sub\">남은 돈 $3 · <span class=\"dnd-vd\">Lua $2</span></div></div>","type":"editdisplay"},{"ableFlag":true,"comment":"회복 표시","flag":"g","in":"\\[HEAL\\|([^|\\]]*)\\|([^|\\]]*)\\|([^|\\]]*)\\|([^|\\]]*)\\|([^|\\]]*)\\|(ok|bad:[^|\\]]*)\\|([^\\]]*)\\]","out":"<div class=\"dnd-tag heal\" data-v=\"$6\"><div class=\"dnd-h\"><span class=\"dnd-chip\">✚ 회복</span><b>$2</b> <span class=\"dnd-big\">+$5</span> · HP $7</div><div class=\"dnd-sub\">$1 · $3: $4 · <span class=\"dnd-vd\">Lua $6</span></div></div>","type":"editdisplay"},{"ableFlag":true,"comment":"사망 내성 표시","flag":"g","in":"\\[DEATH\\|([^|\\]]*)\\|([^|\\]]*)\\|(ok|bad:[^|\\]]*)\\|([^\\]]*)\\]","out":"<div class=\"dnd-tag die\" data-v=\"$3\"><div class=\"dnd-h\"><span class=\"dnd-chip\">✝ 사망 내성</span><b class=\"dnd-r\" data-r=\"$2\">$2</b> · $4</div><div class=\"dnd-sub\">d20 $1 · <span class=\"dnd-vd\">Lua $3</span></div></div>","type":"editdisplay"},{"ableFlag":true,"comment":"상태창 (최신 메시지)","flag":"g<cbs>","in":"{{#when::{{chat_index}}::is::{{lastmessageid}}}}\\[STATUS\\|([^|\\]]*)\\|([^|\\]]*)\\|([^|\\]]*)\\|([^|\\]]*)\\|([^|\\]]*)\\|([^|\\]]*)\\|([^|\\]]*)\\|([^|\\]]*)\\|([^|\\]]*)\\|([^|\\]]*)\\|([^|\\]]*)\\|([^|\\]]*)\\]{{:else}}(?!){{/when}}","out":"<div class=\"dnd-st\"><div class=\"dnd-hd\"><b>❖ $1</b><span>$2</span></div><div class=\"dnd-alert $4\">$3</div><div class=\"dnd-grid\"><div><span class=\"dnd-l\">생명력</span><span class=\"dnd-v\">$5</span><div class=\"dnd-bar\"><div class=\"dnd-fill\" style=\"width:$6%\"></div></div></div><div class=\"dnd-xp\"><span class=\"dnd-l\">경험치</span><span class=\"dnd-v\">$7</span><div class=\"dnd-bar\"><div class=\"dnd-fill\" style=\"width:$8%\"></div></div></div></div><div class=\"dnd-sec\"><span class=\"dnd-l\">장비</span>$9</div><div class=\"dnd-sec\"><span class=\"dnd-l\">자원</span>$10</div><div class=\"dnd-sec\"><span class=\"dnd-l\">지갑</span>$11</div><details class=\"dnd-fold\"><summary></summary><div class=\"dnd-items\">$12</div></details></div>","type":"editdisplay"},{"ableFlag":true,"comment":"장착 표시","flag":"g","in":"\\[EQUIP\\|([^|\\]]*)\\|(ok|bad:[^|\\]]*)\\|([^\\]]*)\\]","out":"<div class=\"dnd-tag\" data-v=\"$2\"><div class=\"dnd-h\"><span class=\"dnd-chip\">⊕ 장착</span><b>$1</b> · $3</div><div class=\"dnd-sub\"><span class=\"dnd-vd\">Lua $2</span></div></div>","type":"editdisplay"},{"ableFlag":true,"comment":"상태 줄 요청에서 빼기","flag":"g","in":"\\n?\\[STATUS\\|[^\\]]*\\]","out":"","type":"editprocess"},{"ableFlag":true,"comment":"해제 표시","flag":"g","in":"\\[UNEQUIP\\|([^|\\]]*)\\|(ok|bad:[^|\\]]*)\\|([^\\]]*)\\]","out":"<div class=\"dnd-tag\" data-v=\"$2\"><div class=\"dnd-h\"><span class=\"dnd-chip\">⊖ 해제</span><b>$1</b> · $3</div><div class=\"dnd-sub\"><span class=\"dnd-vd\">Lua $2</span></div></div>","type":"editdisplay"},{"ableFlag":true,"comment":"새 태그 표시 (검증 전)","flag":"g","in":"\\[(TIME|REST|XP|ITEM|GOLD|HEAL|DEATH|EQUIP|UNEQUIP)\\|([^\\]]*)\\]","out":"<div class=\"dnd-tag pend\"><div class=\"dnd-h\"><span class=\"dnd-chip\">$1</span>$2</div><div class=\"dnd-sub\">검증 전</div></div>","type":"editdisplay"},{"ableFlag":true,"comment":"상태창 (지난 메시지)","flag":"g","in":"\\[STATUS\\|([^|\\]]*)\\|([^|\\]]*)\\|([^|\\]]*)\\|([^|\\]]*)\\|([^|\\]]*)\\|([^|\\]]*)\\|([^|\\]]*)\\|([^|\\]]*)\\|([^|\\]]*)\\|([^|\\]]*)\\|([^|\\]]*)\\|([^|\\]]*)\\]","out":"<div class=\"dnd-mini\">❖ $1 · $2 · 생명력 $5 · 경험치 $7 · $11</div>","type":"editdisplay"},{"ableFlag":true,"comment":"상태 줄 (옛 형식)","flag":"g","in":"\\[STATUS\\|([^|\\]]*)\\|([^|\\]]*)\\|([^|\\]]*)\\|([^|\\]]*)\\|([^\\]]*)\\]","out":"<div class=\"dnd-mini\">❖ $1 · $2 · $3 · $4 $5</div>","type":"editdisplay"},{"ableFlag":true,"comment":"HP 줄 (지난 메시지)","flag":"g","in":"\\[HP\\|([^|\\]]*)\\|([^\\]]*)\\]","out":"<div class=\"dnd-mini\">† $2</div>","type":"editdisplay"},{"ableFlag":true,"comment":"요청에서 지난 태그 지우기 (24)","flag":"g","in":"※※C?\\n?|\\n?(?:\\[(?:OPT|GM|FIX|CONCSAVE)\\|[^\\]]*\\]|\\[XP\\|[^\\]|]*\\|[^\\]|]*\\|auto\\|[^\\]]*\\]|<!--dseed:\\w+-->)","out":"","type":"editprocess"},{"ableFlag":true,"comment":"요청에서 지난 TIME 판정 지우기 (25)","flag":"g","in":"\\[TIME\\|([^|\\]]*)\\|ok\\|[^\\]]*\\]","out":"[TIME|$1]","type":"editprocess"}],"defaultVariables":"","hideChatIcon":false,"inlayViewScreen":false,"largePortrait":false,"license":"","lorePlus":false,"lowLevelAccess":false,"newGenData":{"emotionInstructions":"","instructions":"","negative":"","prompt":""},"prebuiltAssetCommand":"","prebuiltAssetExclude":[],"prebuiltAssetStyle":"","sdData":[["always","solo, 1girl"],["negative",""],["|character's appearance",""],["current situation",""],["$character's pose",""],["$character's emotion",""],["current location",""]],"toggles":"","triggerscript":[{"comment":"","conditions":[],"effect":[{"code":"\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\nlocal K = {}\r\n\r\n\r\nlocal POOL = { d20 = 16, d4 = 12, d6 = 20, d8 = 12, d10 = 8, d12 = 6 }\r\n\r\n\r\nlocal TRAP = { nuisance = { { 11, \"1d10\" }, { 13, \"2d10\" } }, deadly = { { 13, \"2d10\" }, { 15, \"4d10\" } } }\r\nfunction TRAP.row(sev, level) return TRAP[sev][level >= 5 and 2 or 1] end\r\n\r\nlocal Cond = {}\r\nlocal Spell = {}\r\n\r\nlocal Feat = {}\r\n\r\nlocal Shop = {\r\n\r\nSTAPLE = { { \"Potion of Healing\", 1 }, { \"Arrows\", 20 }, { \"Healer's Kit\", 1 } },\r\n\r\nGOODS = { { \"Antitoxin\", 1 }, { \"Alchemist's Fire\", 1 }, { \"Acid\", 1 }, { \"Holy Water\", 1 }, { \"Oil\", 2 }, { \"Bolts\", 20 }, { \"Firearm Bullets\", 10 }, { \"Sling Bullets\", 20 },\r\n{ \"Needles\", 50 }, { \"Potion of Greater Healing\", 1 } },\r\nNO_SALE = { Pistol = true, Musket = true },\r\nDAILY = 5,\r\nMOD_DAILY = 3,\r\nMUL = 1,\r\nSELL = 0.5,\r\n}\r\n\r\n\r\n\r\nlocal Ally = {\r\nMAX = 3,\r\n\r\nORDER = {\r\nFighter = { \"Strength\", \"Constitution\", \"Dexterity\", \"Wisdom\", \"Charisma\", \"Intelligence\" },\r\nRogue = { \"Dexterity\", \"Constitution\", \"Wisdom\", \"Intelligence\", \"Charisma\", \"Strength\" },\r\nCleric = { \"Wisdom\", \"Constitution\", \"Dexterity\", \"Strength\", \"Charisma\", \"Intelligence\" },\r\nWizard = { \"Intelligence\", \"Constitution\", \"Dexterity\", \"Wisdom\", \"Charisma\", \"Strength\" },\r\nBarbarian = { \"Strength\", \"Constitution\", \"Dexterity\", \"Wisdom\", \"Charisma\", \"Intelligence\" },\r\nBard = { \"Charisma\", \"Dexterity\", \"Constitution\", \"Wisdom\", \"Intelligence\", \"Strength\" },\r\nDruid = { \"Wisdom\", \"Constitution\", \"Dexterity\", \"Intelligence\", \"Charisma\", \"Strength\" },\r\nMonk = { \"Dexterity\", \"Wisdom\", \"Constitution\", \"Strength\", \"Intelligence\", \"Charisma\" },\r\nPaladin = { \"Strength\", \"Charisma\", \"Constitution\", \"Wisdom\", \"Dexterity\", \"Intelligence\" },\r\nRanger = { \"Dexterity\", \"Wisdom\", \"Constitution\", \"Strength\", \"Intelligence\", \"Charisma\" },\r\nSorcerer = { \"Charisma\", \"Constitution\", \"Dexterity\", \"Wisdom\", \"Intelligence\", \"Strength\" },\r\nWarlock = { \"Charisma\", \"Constitution\", \"Dexterity\", \"Wisdom\", \"Intelligence\", \"Strength\" },\r\n},\r\nBG = { Fighter = \"Soldier\", Rogue = \"Criminal\", Cleric = \"Acolyte\", Wizard = \"Sage\", Barbarian = \"Soldier\", Bard = \"Acolyte\", Druid = \"Sage\",\r\nMonk = \"Criminal\", Paladin = \"Soldier\", Ranger = \"Soldier\", Sorcerer = \"Acolyte\", Warlock = \"Acolyte\" },\r\n\r\nSKILLS = { Fighter = { \"Perception\", \"Survival\", \"Insight\" }, Rogue = { \"Perception\", \"Acrobatics\", \"Investigation\", \"Insight\", \"Athletics\" },\r\nCleric = { \"Medicine\", \"Persuasion\", \"Perception\" }, Wizard = { \"Investigation\", \"Insight\", \"Perception\" },\r\nBarbarian = { \"Perception\", \"Survival\", \"Animal Handling\" }, Bard = { \"Performance\", \"Persuasion\", \"Deception\", \"Perception\" },\r\nDruid = { \"Perception\", \"Medicine\", \"Animal Handling\" }, Monk = { \"Acrobatics\", \"Insight\", \"Athletics\" },\r\nPaladin = { \"Insight\", \"Persuasion\", \"Medicine\" }, Ranger = { \"Perception\", \"Stealth\", \"Survival\", \"Nature\" },\r\nSorcerer = { \"Arcana\", \"Persuasion\", \"Deception\" }, Warlock = { \"Arcana\", \"Deception\", \"Investigation\" } },\r\n\r\n\r\nEXPERT = { Rogue = { \"Stealth\", \"Perception\", \"Acrobatics\", \"Sleight of Hand\" }, Wizard = { \"Arcana\" },\r\nBard = { \"Persuasion\", \"Performance\", \"Deception\", \"Perception\" }, Ranger = { \"Perception\", \"Stealth\", \"Survival\" } },\r\n\r\n\r\nCANTRIPS = { Cleric = { \"Sacred Flame\", \"Guidance\", \"Light\", \"Thaumaturgy\", \"Spare the Dying\", \"Resistance\", \"Mending\" },\r\nWizard = { \"Fire Bolt\", \"Ray of Frost\", \"Mage Hand\", \"Light\", \"Shocking Grasp\", \"Prestidigitation\", \"Minor Illusion\" },\r\nBard = { \"Vicious Mockery\", \"Starry Wisp\", \"Light\", \"Mage Hand\", \"Minor Illusion\", \"Prestidigitation\" },\r\nDruid = { \"Produce Flame\", \"Guidance\", \"Shillelagh\", \"Druidcraft\", \"Starry Wisp\", \"Resistance\" },\r\nSorcerer = { \"Fire Bolt\", \"Sorcerous Burst\", \"Ray of Frost\", \"Light\", \"Mage Hand\", \"Shocking Grasp\", \"Minor Illusion\", \"Prestidigitation\" },\r\nWarlock = { \"Eldritch Blast\", \"Chill Touch\", \"Minor Illusion\", \"Mage Hand\", \"Prestidigitation\" } },\r\nSPELLS = {\r\nCleric = { \"Cure Wounds\", \"Healing Word\", \"Bless\", \"Spirit Guardians\", \"Spiritual Weapon\", \"Guiding Bolt\", \"Aid\", \"Shield of Faith\", \"Mass Healing Word\",\r\n\"Revivify\", \"Dispel Magic\", \"Guardian of Faith\", \"Banishment\", \"Death Ward\", \"Flame Strike\", \"Greater Restoration\", \"Mass Cure Wounds\",\r\n\"Lesser Restoration\", \"Command\", \"Hold Person\",\r\n\r\n\"Heal\", \"Blade Barrier\", \"Harm\", \"Regenerate\", \"Fire Storm\", \"Divine Word\", \"Holy Aura\", \"Sunburst\",\r\n\"Mass Heal\", \"True Resurrection\", \"Gate\" },\r\nWizard = { \"Magic Missile\", \"Shield\", \"Fireball\", \"Scorching Ray\", \"Burning Hands\", \"Mage Armor\", \"Misty Step\", \"Sleep\", \"Hold Person\",\r\n\"Counterspell\", \"Cone of Cold\", \"Lightning Bolt\", \"Fly\", \"Polymorph\", \"Ice Storm\", \"Banishment\", \"Greater Invisibility\", \"Wall of Force\", \"Hold Monster\",\r\n\"Chain Lightning\", \"Disintegrate\", \"Globe of Invulnerability\", \"Freezing Sphere\", \"Finger of Death\", \"Delayed Blast Fireball\",\r\n\"Prismatic Spray\", \"Forcecage\", \"Sunburst\", \"Power Word Stun\", \"Maze\", \"Incendiary Cloud\",\r\n\"Meteor Swarm\", \"Power Word Kill\", \"Time Stop\", \"Foresight\" },\r\nBard = { \"Healing Word\", \"Dissonant Whispers\", \"Faerie Fire\", \"Hypnotic Pattern\", \"Shatter\", \"Hold Person\", \"Cure Wounds\", \"Heroism\", \"Mass Healing Word\",\r\n\"Dispel Magic\", \"Fear\", \"Greater Invisibility\", \"Polymorph\", \"Dimension Door\", \"Hold Monster\", \"Mass Cure Wounds\", \"Animate Objects\",\r\n\"Mass Suggestion\", \"Irresistible Dance\", \"Eyebite\", \"Heroes' Feast\", \"Regenerate\", \"Prismatic Spray\", \"Arcane Sword\", \"Power Word Stun\",\r\n\"Mind Blank\", \"Dominate Monster\", \"Befuddlement\", \"Foresight\", \"Prismatic Wall\" },\r\nDruid = { \"Healing Word\", \"Cure Wounds\", \"Entangle\", \"Call Lightning\", \"Moonbeam\", \"Faerie Fire\", \"Spike Growth\", \"Thunderwave\", \"Lesser Restoration\",\r\n\"Dispel Magic\", \"Conjure Animals\", \"Ice Storm\", \"Polymorph\", \"Giant Insect\", \"Mass Cure Wounds\", \"Insect Plague\", \"Greater Restoration\", \"Wall of Stone\",\r\n\"Heal\", \"Sunbeam\", \"Wall of Thorns\", \"Conjure Fey\", \"Fire Storm\", \"Regenerate\", \"Sunburst\", \"Incendiary Cloud\", \"Animal Shapes\", \"Earthquake\",\r\n\"Storm of Vengeance\", \"Foresight\", \"True Resurrection\" },\r\nPaladin = { \"Bless\", \"Cure Wounds\", \"Searing Smite\", \"Command\", \"Heroism\", \"Lesser Restoration\", \"Aid\", \"Magic Weapon\", \"Revivify\", \"Dispel Magic\", \"Death Ward\", \"Banishment\", \"Aura of Life\" },\r\nRanger = { \"Cure Wounds\", \"Ensnaring Strike\", \"Goodberry\", \"Spike Growth\", \"Pass without Trace\", \"Entangle\", \"Lesser Restoration\",\r\n\"Conjure Animals\", \"Plant Growth\", \"Protection from Energy\", \"Freedom of Movement\", \"Stoneskin\", \"Conjure Woodland Beings\" },\r\nSorcerer = { \"Magic Missile\", \"Shield\", \"Fireball\", \"Scorching Ray\", \"Misty Step\", \"Sleep\", \"Counterspell\", \"Hold Person\", \"Thunderwave\",\r\n\"Lightning Bolt\", \"Haste\", \"Cone of Cold\", \"Greater Invisibility\", \"Polymorph\", \"Ice Storm\", \"Dimension Door\", \"Hold Monster\",\r\n\"Chain Lightning\", \"Disintegrate\", \"Globe of Invulnerability\", \"Freezing Sphere\", \"Finger of Death\", \"Delayed Blast Fireball\",\r\n\"Fire Storm\", \"Prismatic Spray\", \"Sunburst\", \"Incendiary Cloud\", \"Power Word Stun\", \"Dominate Monster\",\r\n\"Meteor Swarm\", \"Power Word Kill\", \"Time Stop\" },\r\nWarlock = { \"Hex\", \"Hellish Rebuke\", \"Misty Step\", \"Hold Person\", \"Counterspell\", \"Hypnotic Pattern\", \"Darkness\", \"Fly\", \"Hold Monster\",\r\n\"Dimension Door\", \"Banishment\" },\r\n},\r\n\r\nPREFER = { metamagic = { \"Quickened Spell\", \"Empowered Spell\", \"Careful Spell\" },\r\ninvocations = { \"Agonizing Blast\", \"Eldritch Mind\", \"Repelling Blast\", \"Devil's Sight\", \"Pact of the Tome\" },\r\nxskill = { \"Perception\", \"Insight\", \"Stealth\", \"Athletics\", \"Survival\" },\r\nmcskill = { \"Perception\", \"Stealth\", \"Insight\", \"Athletics\", \"Survival\" } },\r\n}\r\nlocal Quest = {\r\nMAX = 3,\r\nSCALE = { village = 1, city = 2, noble = 4, kingdom = 8 },\r\nPLACES = { \"Forest\", \"Ruins\", \"Urban\", \"Grassland\", \"Hill\", \"Planar\", \"Underdark\", \"Mountain\", \"Swamp\", \"Desert\", \"Coastal\", \"Underwater\", \"Arctic\" },\r\nKINDS = { \"explore\", \"social\", \"combat\", \"mystery\" },\r\nTODO = {\r\nexplore = \"a stretch of travel or searching with an obstacle, a hazard or a trap on the way (a trap only through the TRAP tag)\",\r\nsocial = \"someone to deal with by words: a witness, a rival, a guard or a frightened local; a fight is possible but not the point;\"\r\n.. \" they tell only what they could have seen or heard themselves\",\r\ncombat = \"a fight that fits the job and what the story has set up: {SRD} monsters of your choice within the Moderate encounter budget in GAME STATE (for example %s)\",\r\nmystery = \"something unexpected that changes how the job looks: a clue, a twist or a strange sign, found where it could be;\"\r\n.. \" nobody in it knows more than they could have seen or heard\",\r\nboss = \"the heart of the job, the final confrontation: a leader or creature of your choice that fits the story, within the High encounter budget in GAME STATE (for example %s); talking or tricking the way through is possible\",\r\n},\r\nHINT = { explore = \"a hard way ahead\", social = \"someone to face\", combat = \"a fight\", mystery = \"a surprise\", boss = \"the final confrontation\" },\r\n}\r\nK.POOL_ORDER = { \"d20\", \"d4\", \"d6\", \"d8\", \"d10\", \"d12\" }\r\nK.PARTY_FOES = 6\r\nK.SOLO_FOES = 3\r\nK.DEATH = \"srd\"\r\nK.DTYPES = { acid = true, bludgeoning = true, cold = true, fire = true, force = true, lightning = true, necrotic = true, piercing = true,\r\npoison = true, psychic = true, radiant = true, slashing = true, thunder = true }\r\nK.ROLL_TAGS = { ATTACK = true, CHECK = true, SAVE = true, DAMAGE = true, HEAL = true, TRAP = true, DEATH = true, HAZARD = true,\r\nSTIM = true, SOOTHE = true, CLIMAX = true, ADVANCE = true, INHIB = true }\r\n\r\nK.PASSIVE_VS = { Stealth = true, [\"Sleight of Hand\"] = true, Deception = true }\r\n\r\n\r\nlocal XP_LEVEL = { 0, 300, 900, 2700, 6500, 14000, 23000, 34000, 48000, 64000, 85000, 100000, 120000, 140000, 165000,\r\n195000, 225000, 265000, 305000, 355000 }\r\nK.START_MIN = 18 * 60\r\nK.LONG_WAIT = 16 * 60\r\nlocal COIN = { pp = 1000, gp = 100, sp = 10, cp = 1 }\r\n\r\nlocal BUDGET = { { 50, 75, 100 }, { 100, 150, 200 }, { 150, 225, 400 }, { 250, 375, 500 }, { 500, 750, 1100 },\r\n{ 600, 1000, 1400 }, { 750, 1300, 1700 }, { 1000, 1700, 2100 }, { 1300, 2000, 2600 }, { 1600, 2300, 3100 },\r\n{ 1900, 2900, 4100 }, { 2200, 3700, 4700 }, { 2600, 4200, 5400 }, { 2900, 4900, 6200 }, { 3300, 5400, 7800 },\r\n{ 3800, 6100, 9800 }, { 4500, 7200, 11700 }, { 5000, 8700, 14200 }, { 5500, 10700, 17200 }, { 6400, 13200, 22000 } }\r\n\r\n\r\n\r\nlocal PROF = 2\r\nlocal SCORE = { Strength = 17, Dexterity = 13, Constitution = 15, Intelligence = 8, Wisdom = 12, Charisma = 10 }\r\nlocal MOD = { Strength = 3, Dexterity = 1, Constitution = 2, Intelligence = -1, Wisdom = 1, Charisma = 0 }\r\nlocal SAVE_PROF = { Strength = true, Constitution = true }\r\nlocal SKILL = {\r\nAthletics = \"Strength\",\r\nAcrobatics = \"Dexterity\", [\"Sleight of Hand\"] = \"Dexterity\", Stealth = \"Dexterity\",\r\nArcana = \"Intelligence\", History = \"Intelligence\", Investigation = \"Intelligence\",\r\nNature = \"Intelligence\", Religion = \"Intelligence\",\r\n[\"Animal Handling\"] = \"Wisdom\", Insight = \"Wisdom\", Medicine = \"Wisdom\",\r\nPerception = \"Wisdom\", Survival = \"Wisdom\",\r\nDeception = \"Charisma\", Intimidation = \"Charisma\", Performance = \"Charisma\", Persuasion = \"Charisma\",\r\n}\r\nlocal SKILL_PROF = { Athletics = true, Intimidation = true, Perception = true, Survival = true }\r\n\r\n\r\n\r\nlocal PC = {\r\nname = \"Player\", hp = 12, init = MOD.Dexterity, speed = 30, hit_die = 10, class = \"Fighter\",\r\nequip = { armor = \"Chain Mail\", main = \"Longsword\" },\r\n\r\nitems = { [\"Chain Mail\"] = 1, Longsword = 1, Spear = 1, Shortbow = 1, Arrows = 20,\r\n[\"Healer's Kit\"] = 1, [\"Potion of Healing\"] = 1 },\r\ncp = 1800,\r\n\r\nres = { [\"Second Wind\"] = { max = 2, short = 1 } },\r\n}\r\n\r\n\r\nlocal HEAL_SRC = {\r\n[\"Potion of Healing\"] = { dmg = \"2d4+2\", item = true },\r\n[\"Potion of Greater Healing\"] = { dmg = \"4d4+4\", item = true },\r\n[\"Potion of Superior Healing\"] = { dmg = \"8d4+8\", item = true },\r\n[\"Potion of Supreme Healing\"] = { dmg = \"10d4+20\", item = true },\r\n[\"Second Wind\"] = { dmg = \"1d10+LEVEL\", res = true, nonmagical = true },\r\n\r\n\r\n\r\n\r\n[\"Divine Spark\"] = { dmg = \"SPARKd8+WIS\", pool = \"Channel Divinity\", class = \"Cleric\" },\r\n[\"Preserve Life\"] = { preserve = true, class = \"Cleric\", from = 3 },\r\n[\"Potent Spellcasting\"] = { vigor = true, class = \"Cleric\", from = 14 },\r\n[\"Stone's Endurance\"] = { dmg = \"1d12+CON\", pool = \"Giant Ancestry\", self = true, lessens = true },\r\n\r\n\r\n[\"Deflect Attacks\"] = { dmg = \"1d10+DEX+LEVEL\", self = true, class = \"Monk\", from = 3, lessens = true },\r\n[\"Uncanny Metabolism\"] = { dmg = \"MA+LEVEL\", pool = \"Uncanny Metabolism\", self = true, class = \"Monk\" },\r\n[\"Lay On Hands\"] = { points = \"Lay On Hands\", class = \"Paladin\" },\r\n\r\n[\"Heroic Rally\"] = { dmg = \"5+CON\", self = true, class = \"Fighter\", from = 18 },\r\n}\r\n\r\n\r\nK.LITE = false\r\nK.LITE_SWAP = {}\r\nK.MP_MAX = nil\r\nK.LORE_KEYS = {{\"종족: 드래곤본\", {\"Dragonborn\", \"드래곤본\"}}, {\"종족: 드워프\", {\"Dwarf\", \"드워프\"}}, {\"종족: 엘프\", {\"엘프\", \"High Elf\", \"Wood Elf\"}}, {\"종족: 노움\", {\"Gnome\", \"노움\"}}, {\"종족: 골리앗\", {\"Goliath\", \"골리앗\"}}, {\"종족: 하플링\", {\"Halfling\", \"하플링\"}}, {\"종족: 인간\", {\"인간 종족\"}}, {\"종족: 오크\", {\"오크\"}}, {\"종족: 티플링\", {\"Tiefling\", \"티플링\"}}, {\"클래스: 파이터\", {\"Fighter\", \"파이터\"}}, {\"클래스: 로그\", {\"Rogue\"}}, {\"클래스: 클레릭\", {\"Cleric\", \"클레릭\"}}, {\"클래스: 위저드\", {\"Wizard\", \"위저드\"}}, {\"클래스: 바바리안\", {\"Barbarian\", \"바바리안\"}}, {\"클래스: 바드\", {\"바드\"}}, {\"클래스: 드루이드\", {\"Druid\", \"드루이드\"}}, {\"클래스: 몽크\", {\"Monk\", \"몽크\"}}, {\"클래스: 팔라딘\", {\"Paladin\", \"팔라딘\"}}, {\"클래스: 레인저\", {\"레인저\"}}, {\"클래스: 소서러\", {\"Sorcerer\", \"소서러\"}}, {\"클래스: 워락\", {\"Warlock\", \"워락\"}}, {\"배경: 복사\", {\"Acolyte\", \"복사\"}}, {\"배경: 범죄자\", {\"Criminal\", \"범죄자\"}}, {\"배경: 학자\", {\"학자\"}}, {\"배경: 군인\", {\"Soldier\", \"군인\"}}, {\"보물 · 마법 물건 지침\", {\"보물\", \"전리품\", \"마법 물건\", \"마법 도구\", \"treasure\", \"loot\", \"magic item\"}}, {\"조우표: 설원\", {\"설원\", \"빙하\", \"툰드라\", \"눈보라\", \"arctic\"}}, {\"조우표: 해안\", {\"해안\", \"바닷가\", \"항구\", \"해변\", \"coast\", \"Coastal\"}}, {\"조우표: 사막\", {\"사막\", \"모래언덕\", \"desert\"}}, {\"조우표: 숲\", {\"숲\", \"숲속\", \"삼림\", \"forest\", \"woods\"}}, {\"조우표: 초원\", {\"초원\", \"평원\", \"들판\", \"grassland\"}}, {\"조우표: 구릉\", {\"언덕\", \"구릉\", \"hills\"}}, {\"조우표: 산악\", {\"산맥\", \"산길\", \"산속\", \"mountain\"}}, {\"조우표: 이계\", {\"이계\", \"다른 차원\", \"planar\"}}, {\"조우표: 폐허·던전\", {\"폐허\", \"유적\", \"던전\", \"지하실\", \"지하 묘지\", \"무덤\", \"납골당\", \"ruins\", \"dungeon\"}}, {\"조우표: 늪\", {\"늪\", \"습지\", \"swamp\", \"marsh\"}}, {\"조우표: 지하 동굴\", {\"동굴\", \"언더다크\", \"지하 동굴\", \"cave\", \"underdark\"}}, {\"조우표: 물속\", {\"물속\", \"바닷속\", \"underwater\"}}, {\"조우표: 마을·도시\", {\"마을\", \"도시\", \"골목\", \"town\"}}}\r\n\r\nlocal MONSTERS = {\r\n[\"Aboleth\"] = { ac = 17, hp = 150, init = 7, speed = 10, cr = \"10\", xp = 5900, saves = { Strength = 5, Dexterity = 3, Constitution = 6, Intelligence = 8, Wisdom = 6, Charisma = 4 }, attacks = {{ name = \"Tentacle\", hit = 9, dmg = \"2d6+5\", type = \"Bludgeoning\" }}, pp = 20, pi = 12, stealth = -1, hab = {\"Underdark\", \"Underwater\"}, ctypes = {\"Aberration\"}, pb = 4, conm = 2, ab = {21, 9, 15, 18, 15, 18}, swim = true, ko = \"아볼레스\", sfx = {{ n = \"Mucus Cloud\", s = \"Constitution\", dc = 14 }, { n = \"Mucus Cloud (each turn)\", d = \"1d12\", t = \"Acid\" }, { n = \"Consume Memories\", s = \"Intelligence\", dc = 16, d = \"3d6\", t = \"Psychic\", h = true }, { n = \"Dominate Mind\", s = \"Wisdom\", dc = 16, o = \"2/Day\" }}, lr = 3, la = 3, lacts = {\"Lash\", \"Psychic Drain\"}, heals = {{ n = \"Psychic Drain\", d = \"1d10\" }}, multi = \"The aboleth makes two Tentacle attacks and uses either Consume Memories or Dominate Mind if available.\", auto = {\"Mucus Cloud. While underwater, the aboleth is surrounded by mucus. Constitution Saving Throw: DC 14, each creature in a 5-foot Emanation originating from the aboleth at the end of the aboleth's turn. Failure: The target is cursed. Until the curse ends, the target's skin becomes slimy, the target can breathe air and water, and it can't regain Hit Points unless it is underwater. While the cursed creature is outside a body of water, the creature takes 6 (1d12) Acid damage at the end of every 10 minutes unless moisture is applied to its skin before those minutes have passed.\"}, what = \"Large Aberration\" },\r\n[\"Air Elemental\"] = { ac = 15, hp = 90, init = 5, speed = 10, cr = \"5\", xp = 1800, saves = { Strength = 2, Dexterity = 5, Constitution = 2, Intelligence = -2, Wisdom = 0, Charisma = -2 }, attacks = {{ name = \"Thunderous Slam\", hit = 8, dmg = \"2d8+5\", type = \"Thunder\" }}, pp = 10, pi = 10, stealth = 5, res = {\"Bludgeoning\", \"Lightning\", \"Piercing\", \"Slashing\"}, imm = {\"Poison\", \"Thunder\"}, cimm = {\"Exhaustion\", \"Grappled\", \"Paralyzed\", \"Petrified\", \"Poisoned\", \"Prone\", \"Restrained\", \"Unconscious\"}, hab = {\"Desert\", \"Planar\"}, ctypes = {\"Elemental\"}, pb = 3, conm = 2, ab = {14, 20, 14, 6, 10, 6}, fly = true, ko = \"공기 정령\", sfx = {{ n = \"Whirlwind\", s = \"Strength\", dc = 13, d = \"4d10+2\", t = \"Thunder\", h = true, o = \"Recharge 4-6\" }}, multi = \"The elemental makes two Thunderous Slam attacks.\", what = \"Large Elemental\" },\r\n[\"Animated Armor\"] = { ac = 18, hp = 33, init = 2, speed = 25, cr = \"1\", xp = 200, saves = { Strength = 2, Dexterity = 0, Constitution = 1, Intelligence = -5, Wisdom = -4, Charisma = -5 }, attacks = {{ name = \"Slam\", hit = 4, dmg = \"1d6+2\", type = \"Bludgeoning\" }}, pp = 6, pi = 6, stealth = 0, imm = {\"Poison\", \"Psychic\"}, cimm = {\"Charmed\", \"Deafened\", \"Exhaustion\", \"Frightened\", \"Paralyzed\", \"Petrified\", \"Poisoned\"}, hab = {\"Ruins\"}, ctypes = {\"Construct\"}, pb = 2, conm = 1, ab = {14, 11, 13, 1, 3, 1}, ko = \"움직이는 갑옷\", multi = \"The armor makes two Slam attacks.\", what = \"Medium Construct\" },\r\n[\"Animated Flying Sword\"] = { ac = 17, hp = 14, init = 4, speed = 5, cr = \"1/4\", xp = 50, saves = { Strength = 1, Dexterity = 4, Constitution = 0, Intelligence = -5, Wisdom = -3, Charisma = -5 }, attacks = {{ name = \"Slash\", hit = 4, dmg = \"1d8+2\", type = \"Slashing\" }}, pp = 7, pi = 7, stealth = 2, imm = {\"Poison\", \"Psychic\"}, cimm = {\"Charmed\", \"Deafened\", \"Exhaustion\", \"Frightened\", \"Paralyzed\", \"Petrified\", \"Poisoned\"}, hab = {\"Ruins\"}, ctypes = {\"Construct\"}, pb = 2, conm = 0, ab = {12, 15, 11, 1, 5, 1}, fly = true, ko = \"날아다니는 검\", what = \"Small Construct\" },\r\n[\"Animated Rug of Smothering\"] = { ac = 12, hp = 27, init = 4, speed = 10, cr = \"2\", xp = 450, saves = { Strength = 3, Dexterity = 2, Constitution = 0, Intelligence = -5, Wisdom = -4, Charisma = -5 }, attacks = {{ name = \"Smother\", hit = 5, dmg = \"2d6+3\", type = \"Bludgeoning\" }}, pp = 6, pi = 6, stealth = 2, imm = {\"Poison\", \"Psychic\"}, cimm = {\"Charmed\", \"Deafened\", \"Exhaustion\", \"Frightened\", \"Paralyzed\", \"Petrified\", \"Poisoned\"}, hab = {\"Ruins\"}, ctypes = {\"Construct\"}, pb = 2, conm = 0, ab = {17, 14, 10, 1, 3, 1}, ko = \"숨통 조이는 양탄자\", acts = \"The rug can smother only one creature at a time\", what = \"Large Construct\" },\r\n[\"Ankheg\"] = { ac = 14, hp = 45, init = 0, speed = 30, cr = \"2\", xp = 450, saves = { Strength = 3, Dexterity = 0, Constitution = 2, Intelligence = -5, Wisdom = 1, Charisma = -2 }, attacks = {{ name = \"Bite\", hit = 5, dmg = \"2d6+3+1d6\" }}, pp = 11, pi = 11, stealth = 0, hab = {\"Grassland\"}, ctypes = {\"Monstrosity\"}, pb = 2, conm = 2, ab = {17, 11, 14, 1, 13, 6}, ko = \"앵크헤그\", sfx = {{ n = \"Acid Spray\", s = \"Dexterity\", dc = 12, d = \"4d6\", t = \"Acid\", h = true, o = \"Recharge 6\" }}, what = \"Large Monstrosity\" },\r\n[\"Assassin\"] = { ac = 16, hp = 97, init = 10, speed = 30, cr = \"8\", xp = 3900, saves = { Strength = 0, Dexterity = 7, Constitution = 2, Intelligence = 6, Wisdom = 0, Charisma = 0 }, attacks = {{ name = \"Shortsword\", hit = 7, dmg = \"1d6+4\", type = \"Piercing\" }, { name = \"Light Crossbow\", hit = 7, dmg = \"1d8+4+6d6\", k = \"r\" }}, pp = 16, pi = 10, stealth = 10, res = {\"Poison\"}, hab = {\"Ruins\", \"Urban\"}, ctypes = {\"Pure Humanoid\"}, pb = 3, conm = 2, ab = {11, 18, 14, 16, 11, 10}, ko = \"암살자\", evasion = true, multi = \"The assassin makes three attacks, using Shortsword or Light Crossbow in any combination.\", acts = \"Cunning Action (Bonus Action)\", what = \"Medium or Small Humanoid\" },\r\n[\"Awakened Shrub\"] = { ac = 9, hp = 10, init = -1, speed = 20, cr = \"0\", xp = 10, saves = { Strength = -4, Dexterity = -1, Constitution = 0, Intelligence = 0, Wisdom = 0, Charisma = -2 }, attacks = {{ name = \"Rake\", hit = 1, dmg = \"1\", type = \"Slashing\" }}, pp = 10, pi = 10, stealth = -1, vul = {\"Fire\"}, res = {\"Piercing\"}, hab = {\"Forest\"}, ctypes = {\"Plant\"}, pb = 2, conm = 0, ab = {3, 8, 11, 10, 10, 6}, ko = \"깨어난 덤불\", what = \"Small Plant\" },\r\n[\"Awakened Tree\"] = { ac = 13, hp = 59, init = -2, speed = 20, cr = \"2\", xp = 450, saves = { Strength = 4, Dexterity = -2, Constitution = 2, Intelligence = 0, Wisdom = 0, Charisma = -2 }, attacks = {{ name = \"Slam\", hit = 6, dmg = \"3d6+4\", type = \"Bludgeoning\" }}, pp = 10, pi = 10, stealth = -2, vul = {\"Fire\"}, res = {\"Bludgeoning\", \"Piercing\"}, hab = {\"Forest\"}, ctypes = {\"Plant\"}, pb = 2, conm = 2, ab = {19, 6, 15, 10, 10, 7}, ko = \"깨어난 나무\", what = \"Huge Plant\" },\r\n[\"Axe Beak\"] = { ac = 11, hp = 19, init = 1, speed = 50, cr = \"1/4\", xp = 50, saves = { Strength = 2, Dexterity = 1, Constitution = 1, Intelligence = -4, Wisdom = 0, Charisma = -3 }, attacks = {{ name = \"Beak\", hit = 4, dmg = \"1d8+2\", type = \"Slashing\" }}, pp = 10, pi = 10, stealth = 1, hab = {\"Grassland\"}, ctypes = {\"Monstrosity\"}, pb = 2, conm = 1, ab = {14, 12, 12, 2, 10, 5}, ko = \"도끼부리새\", what = \"Large Monstrosity\" },\r\n[\"Azer Sentinel\"] = { ac = 17, hp = 39, init = 1, speed = 30, cr = \"2\", xp = 450, saves = { Strength = 3, Dexterity = 1, Constitution = 4, Intelligence = 1, Wisdom = 1, Charisma = 0 }, attacks = {{ name = \"Burning Hammer\", hit = 5, dmg = \"1d10+3+1d6\" }}, pp = 11, pi = 11, stealth = 1, imm = {\"Fire\", \"Poison\"}, cimm = {\"Poisoned\"}, hab = {\"Mountain\", \"Planar\"}, ctypes = {\"Elemental\"}, pb = 2, conm = 2, ab = {17, 12, 15, 12, 13, 10}, ko = \"아저 파수병\", sfx = {{ n = \"Fire Aura\", d = \"1d10\", t = \"Fire\" }}, auto = {\"Fire Aura. At the end of each of the azer's turns, each creature of the azer's choice in a 5-foot Emanation originating from the azer takes 5 (1d10) Fire damage unless the azer has the Incapacitated condition.\"}, what = \"Medium Elemental\" },\r\n[\"Balor\"] = { ac = 19, hp = 287, init = 14, speed = 40, cr = \"19\", xp = 22000, saves = { Strength = 8, Dexterity = 2, Constitution = 12, Intelligence = 5, Wisdom = 9, Charisma = 6 }, attacks = {{ name = \"Flame Whip\", hit = 14, dmg = \"3d6+8+5d6\" }, { name = \"Lightning Blade\", hit = 14, dmg = \"3d8+8\", type = \"Force\" }}, pp = 19, pi = 13, stealth = 2, res = {\"Cold\", \"Lightning\"}, imm = {\"Fire\", \"Poison\"}, cimm = {\"Charmed\", \"Frightened\", \"Poisoned\"}, hab = {\"Planar\"}, ctypes = {\"Fiend\"}, pb = 6, conm = 6, ab = {26, 15, 22, 20, 16, 22}, unholy = true, fly = true, ko = \"발로르\", sfx = {{ n = \"Death Throes\", s = \"Dexterity\", dc = 20, d = \"9d6+9d6\", t = \"Fire and Force\", h = true }, { n = \"Fire Aura\", d = \"3d8\", t = \"Fire\" }}, mres = 1, lr = 3, multi = \"The balor makes one Flame Whip attack and one Lightning Blade attack.\", acts = \"Teleport (Bonus Action)\", auto = {\"Death Throes. The balor explodes when it dies. Dexterity Saving Throw: DC 20, each creature in a 30-foot Emanation originating from the balor. Failure: 31 (9d6) Fire damage plus 31 (9d6) Force damage. Success: Half damage. Failure or Success: If the balor dies outside the Abyss, it gains a new body instantly, reviving with all its Hit Points somewhere in the Abyss.\", \"Fire Aura. At the end of each of the balor's turns, each creature in a 5-foot Emanation originating from the balor takes 13 (3d8) Fire damage.\"}, what = \"Huge Fiend (Demon)\" },\r\n[\"Bandit\"] = { ac = 12, hp = 11, init = 1, speed = 30, cr = \"1/8\", xp = 25, saves = { Strength = 0, Dexterity = 1, Constitution = 1, Intelligence = 0, Wisdom = 0, Charisma = 0 }, attacks = {{ name = \"Scimitar\", hit = 3, dmg = \"1d6+1\", type = \"Slashing\" }, { name = \"Light Crossbow\", hit = 3, dmg = \"1d8+1\", k = \"r\", type = \"Piercing\" }}, pp = 10, pi = 10, stealth = 1, hab = {\"Coastal\", \"Forest\", \"Grassland\", \"Hill\", \"Ruins\", \"Urban\"}, ctypes = {\"Pure Humanoid\"}, pb = 2, conm = 1, ab = {11, 12, 12, 10, 10, 10}, ko = \"산적\", what = \"Medium or Small Humanoid\" },\r\n[\"Bandit Captain\"] = { ac = 15, hp = 52, init = 3, speed = 30, cr = \"2\", xp = 450, saves = { Strength = 4, Dexterity = 5, Constitution = 2, Intelligence = 2, Wisdom = 2, Charisma = 2 }, attacks = {{ name = \"Scimitar\", hit = 5, dmg = \"1d6+3\", type = \"Slashing\" }, { name = \"Pistol\", hit = 5, dmg = \"1d10+3\", k = \"r\", type = \"Piercing\" }}, pp = 10, pi = 10, stealth = 3, hab = {\"Coastal\", \"Forest\", \"Grassland\", \"Hill\", \"Ruins\", \"Urban\"}, ctypes = {\"Pure Humanoid\"}, pb = 2, conm = 2, ab = {15, 16, 14, 14, 11, 14}, ko = \"산적 두목\", react = { n = 2, name = \"Parry\", melee = true }, multi = \"The bandit makes two attacks, using Scimitar and Pistol in any combination.\", acts = \"Parry (Reaction)\", what = \"Medium or Small Humanoid\" },\r\n[\"Barbed Devil\"] = { ac = 15, hp = 110, init = 3, speed = 30, cr = \"5\", xp = 1800, saves = { Strength = 6, Dexterity = 3, Constitution = 7, Intelligence = 1, Wisdom = 5, Charisma = 5 }, attacks = {{ name = \"Claws\", hit = 6, dmg = \"2d6+3\", type = \"Piercing\" }, { name = \"Tail\", hit = 6, dmg = \"2d10+3\", type = \"Slashing\" }, { name = \"Hurl Flame\", hit = 5, dmg = \"5d6\", k = \"r\", type = \"Fire\" }}, pp = 18, pi = 15, stealth = 3, res = {\"Cold\"}, imm = {\"Fire\", \"Poison\"}, cimm = {\"Poisoned\"}, hab = {\"Planar\"}, ctypes = {\"Fiend\"}, pb = 3, conm = 4, ab = {16, 17, 18, 12, 14, 14}, unholy = true, ko = \"가시 악마\", mres = 1, multi = \"The devil makes one Claws attack and one Tail attack, or it makes two Hurl Flame attacks.\", auto = {\"Barbed Hide. At the start of each of its turns, the devil deals 5 (1d10) Piercing damage to any creature it is grappling or any creature grappling it.\"}, what = \"Medium Fiend (Devil)\" },\r\n[\"Basilisk\"] = { ac = 15, hp = 52, init = -1, speed = 20, cr = \"3\", xp = 700, saves = { Strength = 3, Dexterity = -1, Constitution = 2, Intelligence = -4, Wisdom = -1, Charisma = -2 }, attacks = {{ name = \"Bite\", hit = 5, dmg = \"2d6+3+2d6\" }}, pp = 9, pi = 9, stealth = -1, hab = {\"Hill\", \"Mountain\", \"Ruins\", \"Underdark\"}, ctypes = {\"Monstrosity\"}, pb = 2, conm = 2, ab = {16, 8, 15, 2, 8, 7}, ko = \"바실리스크\", sfx = {{ n = \"Petrifying Gaze\", s = \"Constitution\", dc = 12, o = \"Recharge 4-6\" }}, what = \"Medium Monstrosity\" },\r\n[\"Bearded Devil\"] = { ac = 13, hp = 58, init = 2, speed = 30, cr = \"3\", xp = 700, saves = { Strength = 5, Dexterity = 2, Constitution = 4, Intelligence = -1, Wisdom = 0, Charisma = 4 }, attacks = {{ name = \"Beard\", hit = 5, dmg = \"1d8+3\", type = \"Piercing\" }, { name = \"Infernal Glaive\", hit = 5, dmg = \"1d10+3\", type = \"Slashing\" }}, pp = 10, pi = 10, stealth = 2, res = {\"Cold\"}, imm = {\"Fire\", \"Poison\"}, cimm = {\"Frightened\", \"Poisoned\"}, hab = {\"Planar\"}, ctypes = {\"Fiend\"}, pb = 2, conm = 2, ab = {16, 15, 15, 9, 11, 14}, unholy = true, ko = \"수염 악마\", mres = 1, multi = \"The devil makes one Beard attack and one Infernal Glaive attack.\", what = \"Medium Fiend (Devil)\" },\r\n[\"Behir\"] = { ac = 17, hp = 168, init = 3, speed = 50, cr = \"11\", xp = 7200, saves = { Strength = 6, Dexterity = 3, Constitution = 4, Intelligence = -2, Wisdom = 2, Charisma = 1 }, attacks = {{ name = \"Bite\", hit = 10, dmg = \"2d12+6+2d10\" }}, pp = 16, pi = 12, stealth = 7, imm = {\"Lightning\"}, hab = {\"Mountain\", \"Underdark\"}, ctypes = {\"Monstrosity\"}, pb = 4, conm = 4, ab = {23, 16, 18, 7, 14, 12}, ko = \"베히르\", sfx = {{ n = \"Constrict\", s = \"Strength\", dc = 18, d = \"5d8+6\", t = \"Bludgeoning\" }, { n = \"Lightning Breath\", s = \"Dexterity\", dc = 16, d = \"12d10\", t = \"Lightning\", h = true, o = \"Recharge 5-6\" }, { n = \"Swallow\", s = \"Dexterity\", dc = 18 }, { n = \"Swallow (each turn)\", d = \"6d6\", t = \"Acid\" }}, multi = \"The behir makes one Bite attack and uses Constrict.\", what = \"Huge Monstrosity\" },\r\n[\"Berserker\"] = { ac = 13, hp = 67, init = 1, speed = 30, cr = \"2\", xp = 450, saves = { Strength = 3, Dexterity = 1, Constitution = 3, Intelligence = -1, Wisdom = 0, Charisma = -1 }, attacks = {{ name = \"Greataxe\", hit = 5, dmg = \"1d12+3\", type = \"Slashing\" }}, pp = 10, pi = 10, stealth = 1, hab = {\"Hill\", \"Urban\"}, ctypes = {\"Pure Humanoid\"}, pb = 2, conm = 3, ab = {16, 12, 17, 9, 11, 9}, ko = \"광전사\", bfrenzy = true, what = \"Medium or Small Humanoid\" },\r\n[\"Black Dragon Wyrmling\"] = { ac = 17, hp = 33, init = 4, speed = 30, cr = \"2\", xp = 450, saves = { Strength = 2, Dexterity = 4, Constitution = 1, Intelligence = 0, Wisdom = 2, Charisma = 1 }, attacks = {{ name = \"Rend\", hit = 4, dmg = \"1d6+2+1d4\" }}, pp = 14, pi = 10, stealth = 4, imm = {\"Acid\"}, hab = {\"Swamp\"}, ctypes = {\"Dragon\"}, pb = 2, conm = 1, ab = {15, 14, 13, 10, 11, 13}, fly = true, swim = true, ko = \"새끼 흑룡\", sfx = {{ n = \"Acid Breath\", s = \"Dexterity\", dc = 11, d = \"5d8\", t = \"Acid\", h = true, o = \"Recharge 5-6\" }}, multi = \"The dragon makes two Rend attacks.\", what = \"Medium Dragon (Chromatic)\" },\r\n[\"Young Black Dragon\"] = { ac = 18, hp = 127, init = 5, speed = 40, cr = \"7\", xp = 2900, saves = { Strength = 4, Dexterity = 5, Constitution = 3, Intelligence = 1, Wisdom = 3, Charisma = 2 }, attacks = {{ name = \"Rend\", hit = 7, dmg = \"2d4+4+1d6\" }}, pp = 16, pi = 10, stealth = 5, imm = {\"Acid\"}, hab = {\"Swamp\"}, ctypes = {\"Dragon\"}, pb = 3, conm = 3, ab = {19, 14, 17, 12, 11, 15}, fly = true, swim = true, ko = \"젊은 흑룡\", sfx = {{ n = \"Acid Breath\", s = \"Dexterity\", dc = 14, d = \"14d6\", t = \"Acid\", h = true, o = \"Recharge 5-6\" }}, multi = \"The dragon makes three Rend attacks.\", what = \"Large Dragon (Chromatic)\" },\r\n[\"Adult Black Dragon\"] = { ac = 19, hp = 195, init = 12, speed = 40, cr = \"14\", xp = 11500, saves = { Strength = 6, Dexterity = 7, Constitution = 5, Intelligence = 2, Wisdom = 6, Charisma = 4 }, attacks = {{ name = \"Rend\", hit = 11, dmg = \"2d6+6+1d8\" }, { name = \"Acid Arrow (spell)\", hit = 9, dmg = \"5d4\", type = \"Acid\", srange = \"ranged\" }}, pp = 21, pi = 11, stealth = 7, imm = {\"Acid\"}, hab = {\"Swamp\"}, ctypes = {\"Dragon\"}, pb = 5, conm = 5, ab = {23, 14, 21, 14, 13, 19}, fly = true, swim = true, ko = \"성체 흑룡\", sfx = {{ n = \"Acid Breath\", s = \"Dexterity\", dc = 18, d = \"12d8\", t = \"Acid\", h = true, o = \"Recharge 5-6\" }, { n = \"Cloud of Insects\", s = \"Dexterity\", dc = 17, d = \"4d10\", t = \"Poison\", lg = true }, { n = \"Vitriolic Sphere\", s = \"Dexterity\", dc = 17, d = \"10d4\", o = \"spell\", t = \"Acid\", h = true }}, lr = 3, la = 3, lacts = {\"Cloud of Insects\", \"Frightful Presence\", \"Pounce\"}, multi = \"The dragon makes three Rend attacks. It can replace one attack with a use of Spellcasting to cast Acid Arrow (level 3 version).\", acts = \"Spellcasting\", what = \"Huge Dragon (Chromatic)\" },\r\n[\"Ancient Black Dragon\"] = { ac = 22, hp = 367, init = 16, speed = 40, cr = \"21\", xp = 33000, saves = { Strength = 8, Dexterity = 9, Constitution = 7, Intelligence = 3, Wisdom = 9, Charisma = 6 }, attacks = {{ name = \"Rend\", hit = 15, dmg = \"2d8+8+2d8\" }, { name = \"Acid Arrow (spell)\", hit = 13, dmg = \"6d4\", type = \"Acid\", srange = \"ranged\" }}, pp = 26, pi = 12, stealth = 9, imm = {\"Acid\"}, hab = {\"Swamp\"}, ctypes = {\"Dragon\"}, pb = 7, conm = 7, ab = {27, 14, 25, 16, 15, 22}, fly = true, swim = true, ko = \"고룡 흑룡\", sfx = {{ n = \"Acid Breath\", s = \"Dexterity\", dc = 22, d = \"15d8\", t = \"Acid\", h = true, o = \"Recharge 5-6\" }, { n = \"Cloud of Insects\", s = \"Dexterity\", dc = 21, d = \"6d10\", t = \"Poison\", lg = true }, { n = \"Vitriolic Sphere\", s = \"Dexterity\", dc = 21, d = \"12d4\", o = \"spell\", t = \"Acid\", h = true }}, lr = 4, la = 3, lacts = {\"Cloud of Insects\", \"Frightful Presence\", \"Pounce\"}, multi = \"The dragon makes three Rend attacks. It can replace one attack with a use of Spellcasting to cast Acid Arrow (level 4 version).\", acts = \"Spellcasting\", what = \"Gargantuan Dragon (Chromatic)\" },\r\n[\"Black Pudding\"] = { ac = 7, hp = 68, init = -3, speed = 20, cr = \"4\", xp = 1100, saves = { Strength = 3, Dexterity = -3, Constitution = 3, Intelligence = -5, Wisdom = -2, Charisma = -5 }, attacks = {{ name = \"Dissolving Pseudopod\", hit = 5, dmg = \"4d6+3\", type = \"Acid\" }}, pp = 8, pi = 8, stealth = -3, imm = {\"Acid\", \"Cold\", \"Lightning\", \"Slashing\"}, cimm = {\"Charmed\", \"Deafened\", \"Exhaustion\", \"Frightened\", \"Grappled\", \"Prone\", \"Restrained\"}, hab = {\"Ruins\", \"Underdark\"}, ctypes = {\"Ooze\"}, pb = 2, conm = 3, ab = {16, 5, 16, 1, 6, 1}, ko = \"검은 푸딩\", wear = true, sfx = {{ n = \"Corrosive Form\", d = \"1d8\", t = \"Acid\" }}, split = {\"Lightning\", \"Slashing\"}, acts = \"Split (Reaction)\", what = \"Large Ooze\" },\r\n[\"Blink Dog\"] = { ac = 13, hp = 22, init = 3, speed = 40, cr = \"1/4\", xp = 50, saves = { Strength = 1, Dexterity = 3, Constitution = 1, Intelligence = 0, Wisdom = 1, Charisma = 0 }, attacks = {{ name = \"Bite\", hit = 5, dmg = \"1d4+3\", type = \"Piercing\" }}, pp = 15, pi = 11, stealth = 5, hab = {\"Forest\", \"Planar\"}, ctypes = {\"Fey\"}, pb = 2, conm = 1, ab = {12, 17, 12, 10, 13, 11}, ko = \"점멸견\", acts = \"Teleport (Recharge 4–6) (Bonus Action)\", what = \"Medium Fey\" },\r\n[\"Blue Dragon Wyrmling\"] = { ac = 17, hp = 65, init = 2, speed = 30, cr = \"3\", xp = 700, saves = { Strength = 3, Dexterity = 2, Constitution = 2, Intelligence = 1, Wisdom = 2, Charisma = 2 }, attacks = {{ name = \"Rend\", hit = 5, dmg = \"1d10+3+1d6\" }}, pp = 14, pi = 10, stealth = 2, imm = {\"Lightning\"}, hab = {\"Desert\"}, ctypes = {\"Dragon\"}, pb = 2, conm = 2, ab = {17, 10, 15, 12, 11, 15}, fly = true, ko = \"새끼 청룡\", sfx = {{ n = \"Lightning Breath\", s = \"Dexterity\", dc = 12, d = \"6d6\", t = \"Lightning\", h = true, o = \"Recharge 5-6\" }}, multi = \"The dragon makes two Rend attacks.\", what = \"Medium Dragon (Chromatic)\" },\r\n[\"Young Blue Dragon\"] = { ac = 18, hp = 152, init = 4, speed = 40, cr = \"9\", xp = 5000, saves = { Strength = 5, Dexterity = 4, Constitution = 4, Intelligence = 2, Wisdom = 5, Charisma = 3 }, attacks = {{ name = \"Rend\", hit = 9, dmg = \"2d6+5+1d10\" }}, pp = 19, pi = 11, stealth = 4, imm = {\"Lightning\"}, hab = {\"Coastal\", \"Desert\"}, ctypes = {\"Dragon\"}, pb = 4, conm = 4, ab = {21, 10, 19, 14, 13, 17}, fly = true, ko = \"젊은 청룡\", sfx = {{ n = \"Lightning Breath\", s = \"Dexterity\", dc = 16, d = \"10d10\", t = \"Lightning\", h = true, o = \"Recharge 5-6\" }}, multi = \"The dragon makes three Rend attacks.\", what = \"Large Dragon (Chromatic)\" },\r\n[\"Adult Blue Dragon\"] = { ac = 19, hp = 212, init = 10, speed = 40, cr = \"16\", xp = 15000, saves = { Strength = 7, Dexterity = 5, Constitution = 6, Intelligence = 3, Wisdom = 7, Charisma = 5 }, attacks = {{ name = \"Rend\", hit = 12, dmg = \"2d8+7+1d10\" }}, pp = 22, pi = 12, stealth = 5, imm = {\"Lightning\"}, hab = {\"Desert\"}, ctypes = {\"Dragon\"}, pb = 5, conm = 6, ab = {25, 10, 23, 16, 15, 20}, fly = true, ko = \"성체 청룡\", sfx = {{ n = \"Lightning Breath\", s = \"Dexterity\", dc = 19, d = \"11d10\", t = \"Lightning\", h = true, o = \"Recharge 5-6\" }, { n = \"Shatter\", s = \"Constitution\", dc = 18, d = \"3d8\", o = \"spell\", t = \"Thunder\", h = true }}, lr = 3, la = 3, lacts = {\"Cloaked Flight\", \"Sonic Boom\", \"Tail Swipe\"}, multi = \"The dragon makes three Rend attacks. It can replace one attack with a use of Spellcasting to cast Shatter.\", acts = \"Spellcasting\", what = \"Huge Dragon (Chromatic)\" },\r\n[\"Ancient Blue Dragon\"] = { ac = 22, hp = 481, init = 14, speed = 40, cr = \"23\", xp = 50000, saves = { Strength = 9, Dexterity = 7, Constitution = 8, Intelligence = 4, Wisdom = 10, Charisma = 7 }, attacks = {{ name = \"Rend\", hit = 16, dmg = \"2d8+9+2d10\" }}, pp = 27, pi = 13, stealth = 7, imm = {\"Lightning\"}, hab = {\"Coastal\", \"Desert\"}, ctypes = {\"Dragon\"}, pb = 7, conm = 8, ab = {29, 10, 27, 18, 17, 25}, fly = true, ko = \"고룡 청룡\", sfx = {{ n = \"Lightning Breath\", s = \"Dexterity\", dc = 23, d = \"16d10\", t = \"Lightning\", h = true, o = \"Recharge 5-6\" }, { n = \"Shatter\", s = \"Constitution\", dc = 22, d = \"4d8\", o = \"spell\", t = \"Thunder\", h = true }}, lr = 4, la = 3, lacts = {\"Cloaked Flight\", \"Sonic Boom\", \"Tail Swipe\"}, multi = \"The dragon makes three Rend attacks. It can replace one attack with a use of Spellcasting to cast Shatter (level 3 version).\", acts = \"Spellcasting\", what = \"Gargantuan Dragon (Chromatic)\" },\r\n[\"Bone Devil\"] = { ac = 16, hp = 161, init = 7, speed = 40, cr = \"9\", xp = 5000, saves = { Strength = 8, Dexterity = 3, Constitution = 4, Intelligence = 5, Wisdom = 6, Charisma = 7 }, attacks = {{ name = \"Claw\", hit = 8, dmg = \"2d8+4\", type = \"Slashing\" }, { name = \"Infernal Sting\", hit = 8, dmg = \"2d10+4\", type = \"Piercing\" }}, pp = 12, pi = 16, stealth = 3, res = {\"Cold\"}, imm = {\"Fire\", \"Poison\"}, cimm = {\"Poisoned\"}, hab = {\"Planar\"}, ctypes = {\"Fiend\"}, pb = 4, conm = 4, ab = {18, 16, 18, 13, 14, 16}, unholy = true, fly = true, ko = \"뼈 악마\", mres = 1, multi = \"The devil makes two Claw attacks and one Infernal Sting attack.\", what = \"Large Fiend (Devil)\" },\r\n[\"Brass Dragon Wyrmling\"] = { ac = 15, hp = 22, init = 2, speed = 30, cr = \"1\", xp = 200, saves = { Strength = 2, Dexterity = 2, Constitution = 1, Intelligence = 0, Wisdom = 2, Charisma = 1 }, attacks = {{ name = \"Rend\", hit = 4, dmg = \"1d10+2\", type = \"Slashing\" }}, pp = 14, pi = 10, stealth = 2, imm = {\"Fire\"}, hab = {\"Desert\"}, ctypes = {\"Dragon\"}, pb = 2, conm = 1, ab = {15, 10, 13, 10, 11, 13}, fly = true, ko = \"새끼 황동룡\", sfx = {{ n = \"Fire Breath\", s = \"Dexterity\", dc = 11, d = \"4d6\", t = \"Fire\", h = true, o = \"Recharge 5-6\" }, { n = \"Sleep Breath\", s = \"Constitution\", dc = 11 }}, what = \"Medium Dragon (Metallic)\" },\r\n[\"Young Brass Dragon\"] = { ac = 17, hp = 110, init = 3, speed = 40, cr = \"6\", xp = 2300, saves = { Strength = 4, Dexterity = 3, Constitution = 3, Intelligence = 1, Wisdom = 3, Charisma = 2 }, attacks = {{ name = \"Rend\", hit = 7, dmg = \"2d10+4\", type = \"Slashing\" }}, pp = 16, pi = 10, stealth = 3, imm = {\"Fire\"}, hab = {\"Desert\"}, ctypes = {\"Dragon\"}, pb = 3, conm = 3, ab = {19, 10, 17, 12, 11, 15}, fly = true, ko = \"젊은 황동룡\", sfx = {{ n = \"Fire Breath\", s = \"Dexterity\", dc = 14, d = \"11d6\", t = \"Fire\", h = true, o = \"Recharge 5-6\" }, { n = \"Sleep Breath\", s = \"Constitution\", dc = 14 }}, multi = \"The dragon makes three Rend attacks. It can replace two attacks with a use of Sleep Breath.\", what = \"Large Dragon (Metallic)\" },\r\n[\"Adult Brass Dragon\"] = { ac = 18, hp = 172, init = 10, speed = 40, cr = \"13\", xp = 10000, saves = { Strength = 6, Dexterity = 5, Constitution = 5, Intelligence = 2, Wisdom = 6, Charisma = 3 }, attacks = {{ name = \"Rend\", hit = 11, dmg = \"2d10+6+1d8\" }, { name = \"Scorching Ray (spell)\", hit = 8, dmg = \"2d6\", type = \"Fire\", srange = \"ranged\" }}, pp = 21, pi = 11, stealth = 5, imm = {\"Fire\"}, hab = {\"Desert\"}, ctypes = {\"Dragon\"}, pb = 5, conm = 5, ab = {23, 10, 21, 14, 13, 17}, fly = true, ko = \"성체 황동룡\", sfx = {{ n = \"Fire Breath\", s = \"Dexterity\", dc = 18, d = \"10d8\", t = \"Fire\", h = true, o = \"Recharge 5-6\" }, { n = \"Sleep Breath\", s = \"Constitution\", dc = 18 }, { n = \"Scorching Sands\", s = \"Dexterity\", dc = 16, d = \"6d8\", t = \"Fire\", lg = true }}, lr = 3, la = 3, lacts = {\"Blazing Light\", \"Pounce\", \"Scorching Sands\"}, multi = \"The dragon makes three Rend attacks. It can replace one attack with a use of (A) Sleep Breath or (B) Spellcasting to cast Scorching Ray.\", acts = \"Spellcasting\", what = \"Huge Dragon (Metallic)\" },\r\n[\"Ancient Brass Dragon\"] = { ac = 20, hp = 332, init = 12, speed = 40, cr = \"20\", xp = 25000, saves = { Strength = 8, Dexterity = 6, Constitution = 7, Intelligence = 3, Wisdom = 8, Charisma = 6 }, attacks = {{ name = \"Rend\", hit = 14, dmg = \"2d10+8+2d6\" }, { name = \"Scorching Ray (spell)\", hit = 12, dmg = \"2d6\", type = \"Fire\", srange = \"ranged\" }}, pp = 24, pi = 12, stealth = 6, imm = {\"Fire\"}, hab = {\"Desert\"}, ctypes = {\"Dragon\"}, pb = 6, conm = 7, ab = {27, 10, 25, 16, 15, 22}, fly = true, ko = \"고룡 황동룡\", sfx = {{ n = \"Fire Breath\", s = \"Dexterity\", dc = 21, d = \"13d8\", t = \"Fire\", h = true, o = \"Recharge 5-6\" }, { n = \"Sleep Breath\", s = \"Constitution\", dc = 21 }, { n = \"Scorching Sands\", s = \"Dexterity\", dc = 20, d = \"8d8\", t = \"Fire\", lg = true }}, lr = 4, la = 3, lacts = {\"Blazing Light\", \"Pounce\", \"Scorching Sands\"}, multi = \"The dragon makes three Rend attacks. It can replace one attack with a use of (A) Sleep Breath or (B) Spellcasting to cast Scorching Ray (level 3 version).\", acts = \"Spellcasting\", what = \"Gargantuan Dragon (Metallic)\" },\r\n[\"Bronze Dragon Wyrmling\"] = { ac = 15, hp = 39, init = 2, speed = 30, cr = \"2\", xp = 450, saves = { Strength = 3, Dexterity = 2, Constitution = 2, Intelligence = 1, Wisdom = 2, Charisma = 2 }, attacks = {{ name = \"Rend\", hit = 5, dmg = \"1d10+3\", type = \"Slashing\" }}, pp = 14, pi = 10, stealth = 2, imm = {\"Lightning\"}, hab = {\"Coastal\", \"Underwater\"}, ctypes = {\"Dragon\"}, pb = 2, conm = 2, ab = {17, 10, 15, 12, 11, 15}, fly = true, swim = true, ko = \"새끼 청동룡\", sfx = {{ n = \"Lightning Breath\", s = \"Dexterity\", dc = 12, d = \"3d10\", t = \"Lightning\", h = true, o = \"Recharge 5-6\" }, { n = \"Repulsion Breath\", s = \"Strength\", dc = 12 }}, multi = \"The dragon makes two Rend attacks.\", what = \"Medium Dragon (Metallic)\" },\r\n[\"Young Bronze Dragon\"] = { ac = 17, hp = 142, init = 3, speed = 40, cr = \"8\", xp = 3900, saves = { Strength = 5, Dexterity = 3, Constitution = 4, Intelligence = 2, Wisdom = 4, Charisma = 3 }, attacks = {{ name = \"Rend\", hit = 8, dmg = \"2d10+5\", type = \"Slashing\" }}, pp = 17, pi = 14, stealth = 3, imm = {\"Lightning\"}, hab = {\"Coastal\"}, ctypes = {\"Dragon\"}, pb = 3, conm = 4, ab = {21, 10, 19, 14, 13, 17}, fly = true, swim = true, ko = \"젊은 청동룡\", sfx = {{ n = \"Lightning Breath\", s = \"Dexterity\", dc = 15, d = \"9d10\", t = \"Lightning\", h = true, o = \"Recharge 5-6\" }, { n = \"Repulsion Breath\", s = \"Strength\", dc = 15 }}, multi = \"The dragon makes three Rend attacks. It can replace one attack with a use of Repulsion Breath.\", what = \"Large Dragon (Metallic)\" },\r\n[\"Adult Bronze Dragon\"] = { ac = 18, hp = 212, init = 10, speed = 40, cr = \"15\", xp = 13000, saves = { Strength = 7, Dexterity = 5, Constitution = 6, Intelligence = 3, Wisdom = 7, Charisma = 5 }, attacks = {{ name = \"Rend\", hit = 12, dmg = \"2d8+7+1d10\" }, { name = \"Guiding Bolt (spell)\", hit = 10, dmg = \"5d6\", type = \"Radiant\", srange = \"ranged\" }}, pp = 22, pi = 17, stealth = 5, imm = {\"Lightning\"}, hab = {\"Coastal\", \"Underwater\"}, ctypes = {\"Dragon\"}, pb = 5, conm = 6, ab = {25, 10, 23, 16, 15, 20}, fly = true, swim = true, ko = \"성체 청동룡\", sfx = {{ n = \"Lightning Breath\", s = \"Dexterity\", dc = 19, d = \"10d10\", t = \"Lightning\", h = true, o = \"Recharge 5-6\" }, { n = \"Repulsion Breath\", s = \"Strength\", dc = 19 }, { n = \"Thunderclap\", s = \"Constitution\", dc = 17, d = \"3d6\", t = \"Thunder\", lg = true }}, lr = 3, la = 3, lacts = {\"Guiding Light\", \"Pounce\", \"Thunderclap\"}, multi = \"The dragon makes three Rend attacks. It can replace one attack with a use of (A) Repulsion Breath or (B) Spellcasting to cast Guiding Bolt (level 2 version).\", acts = \"Spellcasting\", what = \"Huge Dragon (Metallic)\" },\r\n[\"Ancient Bronze Dragon\"] = { ac = 22, hp = 444, init = 14, speed = 40, cr = \"22\", xp = 41000, saves = { Strength = 9, Dexterity = 7, Constitution = 8, Intelligence = 4, Wisdom = 10, Charisma = 7 }, attacks = {{ name = \"Rend\", hit = 16, dmg = \"2d8+9+2d8\" }, { name = \"Guiding Bolt (spell)\", hit = 14, dmg = \"5d6\", type = \"Radiant\", srange = \"ranged\" }}, pp = 27, pi = 20, stealth = 7, imm = {\"Lightning\"}, hab = {\"Coastal\", \"Underwater\"}, ctypes = {\"Dragon\"}, pb = 7, conm = 8, ab = {29, 10, 27, 18, 17, 25}, fly = true, swim = true, ko = \"고룡 청동룡\", sfx = {{ n = \"Lightning Breath\", s = \"Dexterity\", dc = 23, d = \"15d10\", t = \"Lightning\", h = true, o = \"Recharge 5-6\" }, { n = \"Repulsion Breath\", s = \"Strength\", dc = 23 }, { n = \"Thunderclap\", s = \"Constitution\", dc = 22, d = \"3d8\", t = \"Thunder\", lg = true }}, lr = 4, la = 3, lacts = {\"Guiding Light\", \"Pounce\", \"Thunderclap\"}, multi = \"The dragon makes three Rend attacks. It can replace one attack with a use of (A) Repulsion Breath or (B) Spellcasting to cast Guiding Bolt (level 2 version).\", acts = \"Spellcasting\", what = \"Gargantuan Dragon (Metallic)\" },\r\n[\"Bugbear Stalker\"] = { ac = 15, hp = 65, init = 2, speed = 30, cr = \"3\", xp = 700, saves = { Strength = 3, Dexterity = 2, Constitution = 4, Intelligence = 0, Wisdom = 3, Charisma = 0 }, attacks = {{ name = \"Javelin\", hit = 5, dmg = \"3d6+3\", k = \"b\", type = \"Piercing\" }, { name = \"Morningstar\", hit = 5, dmg = \"2d8+3\", type = \"Piercing\" }}, pp = 11, pi = 11, stealth = 6, hab = {\"Forest\", \"Underdark\"}, ctypes = {\"Fey\", \"Goblinoid\"}, pb = 2, conm = 2, ab = {17, 14, 14, 11, 12, 11}, ko = \"버그베어 추적자\", sfx = {{ n = \"Quick Grapple\", s = \"Dexterity\", dc = 13 }}, multi = \"The bugbear makes two Javelin or Morningstar attacks.\", what = \"Medium Fey (Goblinoid)\" },\r\n[\"Bugbear Warrior\"] = { ac = 14, hp = 33, init = 2, speed = 30, cr = \"1\", xp = 200, saves = { Strength = 2, Dexterity = 2, Constitution = 1, Intelligence = -1, Wisdom = 0, Charisma = -1 }, attacks = {{ name = \"Grab\", hit = 4, dmg = \"2d6+2\", type = \"Bludgeoning\" }, { name = \"Light Hammer\", hit = 4, dmg = \"3d4+2\", k = \"b\", type = \"Bludgeoning\" }}, pp = 10, pi = 10, stealth = 6, hab = {\"Forest\", \"Hill\", \"Ruins\"}, ctypes = {\"Fey\", \"Goblinoid\"}, pb = 2, conm = 1, ab = {15, 14, 13, 8, 11, 9}, ko = \"버그베어 전사\", what = \"Medium Fey (Goblinoid)\" },\r\n[\"Bulette\"] = { ac = 17, hp = 94, init = 0, speed = 40, cr = \"5\", xp = 1800, saves = { Strength = 4, Dexterity = 0, Constitution = 5, Intelligence = -4, Wisdom = 0, Charisma = -3 }, attacks = {{ name = \"Bite\", hit = 7, dmg = \"2d12+4\", type = \"Piercing\" }}, pp = 16, pi = 10, stealth = 0, hab = {\"Grassland\", \"Hill\"}, ctypes = {\"Monstrosity\"}, pb = 3, conm = 5, ab = {19, 11, 21, 2, 10, 5}, ko = \"뷸레트\", sfx = {{ n = \"Deadly Leap\", s = \"Dexterity\", dc = 15, d = \"3d12\", t = \"Bludgeoning\", h = true }}, multi = \"The bulette makes two Bite attacks.\", acts = \"Leap (Bonus Action)\", what = \"Large Monstrosity\" },\r\n[\"Centaur Trooper\"] = { ac = 16, hp = 45, init = 2, speed = 50, cr = \"2\", xp = 450, saves = { Strength = 4, Dexterity = 2, Constitution = 2, Intelligence = -1, Wisdom = 1, Charisma = 0 }, attacks = {{ name = \"Pike\", hit = 6, dmg = \"1d10+4\", type = \"Piercing\" }, { name = \"Longbow\", hit = 4, dmg = \"1d8+2\", k = \"r\", type = \"Piercing\" }}, pp = 13, pi = 11, stealth = 2, hab = {\"Forest\", \"Grassland\"}, ctypes = {\"Fey\"}, pb = 2, conm = 2, ab = {18, 14, 14, 9, 13, 11}, ko = \"켄타우로스 기병\", sfx = {{ n = \"Trampling Charge\", s = \"Strength\", dc = 14, d = \"1d6+4\", t = \"Bludgeoning\", o = \"Recharge 5-6\" }}, multi = \"The centaur makes two attacks, using Pike or Longbow in any combination.\", what = \"Large Fey\" },\r\n[\"Chain Devil\"] = { ac = 15, hp = 85, init = 5, speed = 30, cr = \"8\", xp = 3900, saves = { Strength = 4, Dexterity = 2, Constitution = 7, Intelligence = 0, Wisdom = 4, Charisma = 2 }, attacks = {{ name = \"Chain\", hit = 7, dmg = \"2d6+4\", type = \"Slashing\" }}, pp = 11, pi = 11, stealth = 2, res = {\"Bludgeoning\", \"Cold\", \"Piercing\", \"Slashing\"}, imm = {\"Fire\", \"Poison\"}, cimm = {\"Poisoned\"}, hab = {\"Planar\"}, ctypes = {\"Fiend\"}, pb = 3, conm = 4, ab = {18, 15, 18, 11, 12, 14}, unholy = true, ko = \"사슬 악마\", sfx = {{ n = \"Conjure Infernal Chain\", s = \"Dexterity\", dc = 15, d = \"2d4+4\", t = \"Fire\" }, { n = \"Unnerving Gaze\", s = \"Wisdom\", dc = 15 }}, mres = 1, multi = \"The devil makes two Chain attacks and uses Conjure Infernal Chain.\", what = \"Medium Fiend (Devil)\" },\r\n[\"Chimera\"] = { ac = 14, hp = 114, init = 0, speed = 30, cr = \"6\", xp = 2300, saves = { Strength = 4, Dexterity = 0, Constitution = 4, Intelligence = -4, Wisdom = 2, Charisma = 0 }, attacks = {{ name = \"Bite\", hit = 7, dmg = \"2d6+4\", adv = \"4d6+4\", type = \"Piercing\" }, { name = \"Claw\", hit = 7, dmg = \"1d6+4\", type = \"Slashing\" }, { name = \"Ram\", hit = 7, dmg = \"1d12+4\", type = \"Bludgeoning\" }}, pp = 18, pi = 12, stealth = 0, hab = {\"Grassland\", \"Hill\", \"Mountain\"}, ctypes = {\"Monstrosity\"}, pb = 3, conm = 4, ab = {19, 11, 19, 3, 14, 10}, fly = true, ko = \"키메라\", sfx = {{ n = \"Fire Breath\", s = \"Dexterity\", dc = 15, d = \"7d8\", t = \"Fire\", h = true, o = \"Recharge 5-6\" }}, multi = \"The chimera makes one Ram attack, one Bite attack, and one Claw attack. It can replace the Claw attack with a use of Fire Breath if available.\", what = \"Large Monstrosity\" },\r\n[\"Chuul\"] = { ac = 16, hp = 76, init = 0, speed = 30, cr = \"4\", xp = 1100, saves = { Strength = 4, Dexterity = 0, Constitution = 3, Intelligence = -3, Wisdom = 0, Charisma = -3 }, attacks = {{ name = \"Pincer\", hit = 6, dmg = \"1d10+4\", type = \"Bludgeoning\" }}, pp = 14, pi = 10, stealth = 0, imm = {\"Poison\"}, cimm = {\"Poisoned\"}, hab = {\"Underdark\", \"Underwater\"}, ctypes = {\"Aberration\"}, pb = 2, conm = 3, ab = {19, 10, 16, 5, 11, 5}, swim = true, ko = \"추울\", sfx = {{ n = \"Paralyzing Tentacles\", s = \"Constitution\", dc = 13 }}, multi = \"The chuul makes two Pincer attacks and uses Paralyzing Tentacles.\", what = \"Large Aberration\" },\r\n[\"Clay Golem\"] = { ac = 14, hp = 123, init = 3, speed = 30, cr = \"9\", xp = 5000, saves = { Strength = 5, Dexterity = -1, Constitution = 4, Intelligence = -4, Wisdom = -1, Charisma = -5 }, attacks = {{ name = \"Slam\", hit = 9, dmg = \"1d10+5\", type = \"Bludgeoning\" }}, pp = 9, pi = 9, stealth = -1, res = {\"Bludgeoning\", \"Piercing\", \"Slashing\"}, imm = {\"Acid\", \"Poison\", \"Psychic\"}, cimm = {\"Charmed\", \"Exhaustion\", \"Frightened\", \"Paralyzed\", \"Petrified\", \"Poisoned\"}, hab = {\"Ruins\", \"Urban\"}, ctypes = {\"Construct\"}, pb = 4, conm = 4, ab = {20, 9, 18, 3, 8, 1}, ko = \"점토 골렘\", mres = 1, absorb = { n = \"Acid Absorption\", t = \"Acid\" }, multi = \"The golem makes two Slam attacks, or it makes three Slam attacks if it used Hasten this turn.\", acts = \"Hasten (Recharge 5–6) (Bonus Action)\", auto = {\"Berserk. Whenever the golem starts its turn Bloodied, roll 1d6. On a 6, the golem goes berserk. On each of its turns while berserk, the golem attacks the nearest creature it can see. If no creature is near enough to move to and attack, the golem attacks an object. Once the golem goes berserk, it continues to be berserk until it is destroyed or it is no longer Bloodied.\"}, what = \"Large Construct\" },\r\n[\"Cloaker\"] = { ac = 14, hp = 91, init = 5, speed = 10, cr = \"8\", xp = 3900, saves = { Strength = 3, Dexterity = 2, Constitution = 1, Intelligence = 1, Wisdom = 2, Charisma = -2 }, attacks = {{ name = \"Attach\", hit = 6, dmg = \"3d6+3\", type = \"Piercing\" }, { name = \"Tail\", hit = 6, dmg = \"1d10+3\", type = \"Slashing\" }}, pp = 12, pi = 12, stealth = 5, cimm = {\"Frightened\"}, hab = {\"Underdark\"}, ctypes = {\"Aberration\"}, pb = 3, conm = 1, ab = {17, 15, 12, 13, 14, 7}, fly = true, ko = \"클로커\", sfx = {{ n = \"Moan\", s = \"Wisdom\", dc = 13 }}, multi = \"The cloaker makes one Attach attack and two Tail attacks.\", acts = \"Phantasms (Recharge after a Short or Long Rest) (Bonus Action)\", what = \"Large Aberration\" },\r\n[\"Cloud Giant\"] = { ac = 14, hp = 200, init = 4, speed = 40, cr = \"9\", xp = 5000, saves = { Strength = 8, Dexterity = 0, Constitution = 10, Intelligence = 1, Wisdom = 7, Charisma = 3 }, attacks = {{ name = \"Thunderous Mace\", hit = 12, dmg = \"3d8+8+2d6\" }, { name = \"Thundercloud\", hit = 12, dmg = \"3d6+8\", k = \"r\", type = \"Thunder\" }}, pp = 21, pi = 17, stealth = 0, hab = {\"Mountain\"}, ctypes = {\"Giant\"}, pb = 4, conm = 6, ab = {27, 10, 22, 12, 16, 16}, fly = true, ko = \"구름 거인\", multi = \"The giant makes two attacks, using Thunderous Mace or Thundercloud in any combination. It can replace one attack with a use of Spellcasting to cast Fog Cloud.\", acts = \"Spellcasting, Misty Step (Bonus Action)\", what = \"Huge Giant\" },\r\n[\"Cockatrice\"] = { ac = 11, hp = 22, init = 1, speed = 20, cr = \"1/2\", xp = 100, saves = { Strength = -2, Dexterity = 1, Constitution = 1, Intelligence = -4, Wisdom = 1, Charisma = -3 }, attacks = {{ name = \"Petrifying Bite\", hit = 3, dmg = \"1d4+1\", type = \"Piercing\" }}, pp = 11, pi = 11, stealth = 1, cimm = {\"Petrified\"}, hab = {\"Forest\", \"Hill\", \"Ruins\"}, ctypes = {\"Monstrosity\"}, pb = 2, conm = 1, ab = {6, 12, 12, 2, 13, 5}, fly = true, ko = \"코카트리스\", what = \"Small Monstrosity\" },\r\n[\"Commoner\"] = { ac = 10, hp = 4, init = 0, speed = 30, cr = \"0\", xp = 10, saves = { Strength = 0, Dexterity = 0, Constitution = 0, Intelligence = 0, Wisdom = 0, Charisma = 0 }, attacks = {{ name = \"Club\", hit = 2, dmg = \"1d4\", type = \"Bludgeoning\" }}, pp = 10, pi = 10, stealth = 0, hab = {\"Urban\"}, ctypes = {\"Pure Humanoid\"}, pb = 2, conm = 0, ab = {10, 10, 10, 10, 10, 10}, ko = \"평민\", what = \"Medium or Small Humanoid\" },\r\n[\"Copper Dragon Wyrmling\"] = { ac = 16, hp = 22, init = 3, speed = 30, cr = \"1\", xp = 200, saves = { Strength = 2, Dexterity = 3, Constitution = 1, Intelligence = 2, Wisdom = 2, Charisma = 1 }, attacks = {{ name = \"Rend\", hit = 4, dmg = \"1d10+2\", type = \"Slashing\" }}, pp = 14, pi = 10, stealth = 3, imm = {\"Acid\"}, hab = {\"Coastal\", \"Hill\"}, ctypes = {\"Dragon\"}, pb = 2, conm = 1, ab = {15, 12, 13, 14, 11, 13}, fly = true, ko = \"새끼 구리룡\", sfx = {{ n = \"Acid Breath\", s = \"Dexterity\", dc = 11, d = \"4d8\", t = \"Acid\", h = true, o = \"Recharge 5-6\" }, { n = \"Slowing Breath\", s = \"Constitution\", dc = 11 }}, what = \"Medium Dragon (Metallic)\" },\r\n[\"Young Copper Dragon\"] = { ac = 17, hp = 119, init = 4, speed = 40, cr = \"7\", xp = 2900, saves = { Strength = 4, Dexterity = 4, Constitution = 3, Intelligence = 3, Wisdom = 4, Charisma = 2 }, attacks = {{ name = \"Rend\", hit = 7, dmg = \"2d10+4\", type = \"Slashing\" }}, pp = 17, pi = 11, stealth = 4, imm = {\"Acid\"}, hab = {\"Hill\"}, ctypes = {\"Dragon\"}, pb = 3, conm = 3, ab = {19, 12, 17, 16, 13, 15}, fly = true, ko = \"젊은 구리룡\", sfx = {{ n = \"Acid Breath\", s = \"Dexterity\", dc = 14, d = \"9d8\", t = \"Acid\", h = true, o = \"Recharge 5-6\" }, { n = \"Slowing Breath\", s = \"Constitution\", dc = 14 }}, multi = \"The dragon makes three Rend attacks. It can replace one attack with a use of Slowing Breath.\", what = \"Large Dragon (Metallic)\" },\r\n[\"Adult Copper Dragon\"] = { ac = 18, hp = 184, init = 11, speed = 40, cr = \"14\", xp = 11500, saves = { Strength = 6, Dexterity = 6, Constitution = 5, Intelligence = 4, Wisdom = 7, Charisma = 4 }, attacks = {{ name = \"Rend\", hit = 11, dmg = \"2d10+6+1d8\" }}, pp = 22, pi = 12, stealth = 6, imm = {\"Acid\"}, hab = {\"Coastal\", \"Grassland\", \"Hill\"}, ctypes = {\"Dragon\"}, pb = 5, conm = 5, ab = {23, 12, 21, 18, 15, 18}, fly = true, ko = \"성체 구리룡\", sfx = {{ n = \"Acid Breath\", s = \"Dexterity\", dc = 18, d = \"12d8\", t = \"Acid\", h = true, o = \"Recharge 5-6\" }, { n = \"Slowing Breath\", s = \"Constitution\", dc = 18 }, { n = \"Giggling Magic\", s = \"Charisma\", dc = 17, d = \"7d6\", t = \"Psychic\", lg = true }, { n = \"Mind Spike\", s = \"Wisdom\", dc = 17, d = \"5d8\", o = \"spell\", t = \"Psychic\", h = true }}, lr = 3, la = 3, lacts = {\"Giggling Magic\", \"Mind Jolt\", \"Pounce\"}, multi = \"The dragon makes three Rend attacks. It can replace one attack with a use of (A) Slowing Breath or (B) Spellcasting to cast Mind Spike (level 4 version).\", acts = \"Spellcasting\", what = \"Huge Dragon (Metallic)\" },\r\n[\"Ancient Copper Dragon\"] = { ac = 21, hp = 367, init = 15, speed = 40, cr = \"21\", xp = 33000, saves = { Strength = 8, Dexterity = 8, Constitution = 7, Intelligence = 5, Wisdom = 10, Charisma = 6 }, attacks = {{ name = \"Rend\", hit = 15, dmg = \"2d10+8+2d8\" }}, pp = 27, pi = 13, stealth = 8, imm = {\"Acid\"}, hab = {\"Hill\"}, ctypes = {\"Dragon\"}, pb = 7, conm = 7, ab = {27, 12, 25, 20, 17, 22}, fly = true, ko = \"고룡 구리룡\", sfx = {{ n = \"Acid Breath\", s = \"Dexterity\", dc = 22, d = \"14d8\", t = \"Acid\", h = true, o = \"Recharge 5-6\" }, { n = \"Slowing Breath\", s = \"Constitution\", dc = 22 }, { n = \"Giggling Magic\", s = \"Charisma\", dc = 21, d = \"9d6\", t = \"Psychic\", lg = true }, { n = \"Mind Spike\", s = \"Wisdom\", dc = 21, d = \"6d8\", o = \"spell\", t = \"Psychic\", h = true }}, lr = 4, la = 3, lacts = {\"Giggling Magic\", \"Mind Jolt\", \"Pounce\"}, multi = \"The dragon makes three Rend attacks. It can replace one attack with a use of (A) Slowing Breath or (B) Spellcasting to cast Mind Spike (level 5 version).\", acts = \"Spellcasting\", what = \"Gargantuan Dragon (Metallic)\" },\r\n[\"Couatl\"] = { ac = 19, hp = 60, init = 5, speed = 30, cr = \"4\", xp = 1100, saves = { Strength = 3, Dexterity = 5, Constitution = 5, Intelligence = 4, Wisdom = 7, Charisma = 4 }, attacks = {{ name = \"Bite\", hit = 7, dmg = \"1d12+5\", type = \"Piercing\" }}, pp = 15, pi = 15, stealth = 5, res = {\"Bludgeoning\", \"Piercing\", \"Slashing\"}, imm = {\"Psychic\", \"Radiant\"}, hab = {\"Desert\", \"Planar\"}, ctypes = {\"Celestial\"}, pb = 2, conm = 3, ab = {16, 20, 17, 18, 20, 18}, fly = true, ko = \"쿠아틀\", sfx = {{ n = \"Constrict\", s = \"Strength\", dc = 15, d = \"1d6+5\", t = \"Bludgeoning\" }}, acts = \"Spellcasting, Divine Aid (2/Day) (Bonus Action)\", what = \"Medium Celestial\" },\r\n[\"Swarm of Crawling Claws\"] = { ac = 12, hp = 49, init = 2, speed = 30, cr = \"3\", xp = 700, saves = { Strength = 2, Dexterity = 2, Constitution = 0, Intelligence = -3, Wisdom = 0, Charisma = -3 }, attacks = {{ name = \"Swarm of Grasping Hands\", hit = 4, dmg = \"4d8+2\", bloodied = \"2d8+2\", type = \"Necrotic\" }}, pp = 10, pi = 10, stealth = 2, res = {\"Bludgeoning\", \"Piercing\", \"Slashing\"}, imm = {\"Necrotic\", \"Poison\"}, cimm = {\"Charmed\", \"Exhaustion\", \"Frightened\", \"Grappled\", \"Incapacitated\", \"Paralyzed\", \"Petrified\", \"Poisoned\", \"Prone\", \"Restrained\", \"Stunned\"}, hab = {\"Ruins\"}, ctypes = {\"Swarm\"}, pb = 2, conm = 0, ab = {14, 14, 11, 5, 10, 4}, unholy = true, undead = true, ko = \"기어다니는 손 떼\", what = \"Medium Swarm of Tiny Undead\" },\r\n[\"Cultist\"] = { ac = 12, hp = 9, init = 1, speed = 30, cr = \"1/8\", xp = 25, saves = { Strength = 0, Dexterity = 1, Constitution = 0, Intelligence = 0, Wisdom = 2, Charisma = 0 }, attacks = {{ name = \"Ritual Sickle\", hit = 3, dmg = \"1d4+1\", type = \"Slashing\" }}, pp = 10, pi = 10, stealth = 1, hab = {\"Ruins\", \"Urban\"}, ctypes = {\"Pure Humanoid\"}, pb = 2, conm = 0, ab = {11, 12, 10, 10, 11, 10}, ko = \"사교도\", what = \"Medium or Small Humanoid\" },\r\n[\"Cultist Fanatic\"] = { ac = 13, hp = 44, init = 2, speed = 30, cr = \"2\", xp = 450, saves = { Strength = 0, Dexterity = 2, Constitution = 1, Intelligence = 0, Wisdom = 4, Charisma = 1 }, attacks = {{ name = \"Pact Blade\", hit = 4, dmg = \"1d8+2+2d6\" }}, pp = 12, pi = 12, stealth = 2, hab = {\"Ruins\", \"Urban\"}, ctypes = {\"Pure Humanoid\"}, pb = 2, conm = 1, ab = {11, 14, 12, 10, 14, 13}, ko = \"사교 광신도\", acts = \"Spellcasting, Spiritual Weapon (2/Day) (Bonus Action)\", what = \"Medium or Small Humanoid\" },\r\n[\"Darkmantle\"] = { ac = 11, hp = 22, init = 3, speed = 10, cr = \"1/2\", xp = 100, saves = { Strength = 3, Dexterity = 1, Constitution = 1, Intelligence = -4, Wisdom = 0, Charisma = -3 }, attacks = {{ name = \"Crush\", hit = 5, dmg = \"1d6+3\", type = \"Bludgeoning\" }}, pp = 10, pi = 10, stealth = 3, hab = {\"Ruins\", \"Underdark\"}, ctypes = {\"Aberration\"}, pb = 2, conm = 1, ab = {16, 12, 13, 2, 10, 5}, fly = true, ko = \"다크맨틀\", acts = \"Darkness Aura (1/Day)\", what = \"Small Aberration\" },\r\n[\"Death Dog\"] = { ac = 12, hp = 39, init = 2, speed = 40, cr = \"1\", xp = 200, saves = { Strength = 2, Dexterity = 2, Constitution = 2, Intelligence = -4, Wisdom = 1, Charisma = -2 }, attacks = {{ name = \"Bite\", hit = 4, dmg = \"1d4+2\", type = \"Piercing\" }}, pp = 15, pi = 11, stealth = 4, cimm = {\"Blinded\", \"Charmed\", \"Deafened\", \"Frightened\", \"Stunned\", \"Unconscious\"}, hab = {\"Desert\"}, ctypes = {\"Monstrosity\"}, pb = 2, conm = 2, ab = {15, 14, 14, 3, 13, 6}, ko = \"죽음의 개\", multi = \"The death dog makes two Bite attacks.\", what = \"Medium Monstrosity\" },\r\n[\"Deva\"] = { ac = 17, hp = 229, init = 4, speed = 30, cr = \"10\", xp = 5900, saves = { Strength = 4, Dexterity = 4, Constitution = 4, Intelligence = 3, Wisdom = 9, Charisma = 9 }, attacks = {{ name = \"Holy Mace\", hit = 8, dmg = \"1d6+4+4d8\" }}, pp = 19, pi = 19, stealth = 4, res = {\"Radiant\"}, cimm = {\"Charmed\", \"Exhaustion\", \"Frightened\"}, hab = {\"Planar\"}, ctypes = {\"Celestial\"}, pb = 4, conm = 4, ab = {18, 18, 18, 17, 20, 20}, fly = true, ko = \"데바\", mres = 1, multi = \"The deva makes two Holy Mace attacks.\", acts = \"Spellcasting, Divine Aid (2/Day) (Bonus Action)\", what = \"Medium Celestial (Angel)\" },\r\n[\"Djinni\"] = { ac = 17, hp = 218, init = 2, speed = 30, cr = \"11\", xp = 7200, saves = { Strength = 5, Dexterity = 6, Constitution = 6, Intelligence = 2, Wisdom = 7, Charisma = 5 }, attacks = {{ name = \"Storm Blade\", hit = 9, dmg = \"2d6+5+2d6\" }, { name = \"Storm Bolt\", hit = 9, dmg = \"3d8\", k = \"r\", type = \"Thunder\" }}, pp = 13, pi = 13, stealth = 2, imm = {\"Lightning\", \"Thunder\"}, hab = {\"Desert\", \"Planar\"}, ctypes = {\"Elemental\"}, pb = 4, conm = 6, ab = {21, 15, 22, 15, 16, 20}, fly = true, ko = \"진\", sfx = {{ n = \"Create Whirlwind\", s = \"Strength\", dc = 17 }, { n = \"Create Whirlwind (each turn)\", d = \"6d6\", t = \"Thunder\" }}, mres = 1, multi = \"The djinni makes three attacks, using Storm Blade or Storm Bolt in any combination.\", acts = \"Spellcasting\", what = \"Large Elemental (Genie)\" },\r\n[\"Doppelganger\"] = { ac = 14, hp = 52, init = 4, speed = 30, cr = \"3\", xp = 700, saves = { Strength = 0, Dexterity = 4, Constitution = 2, Intelligence = 0, Wisdom = 1, Charisma = 2 }, attacks = {{ name = \"Slam\", hit = 6, dmg = \"2d6+4\", type = \"Bludgeoning\" }}, pp = 11, pi = 13, stealth = 4, cimm = {\"Charmed\"}, hab = {\"Ruins\", \"Underdark\", \"Urban\"}, ctypes = {\"Monstrosity\"}, pb = 2, conm = 2, ab = {11, 18, 14, 11, 12, 14}, ko = \"도플갱어\", sfx = {{ n = \"Unsettling Visage\", s = \"Wisdom\", dc = 12, o = \"Recharge 6\" }}, multi = \"The doppelganger makes two Slam attacks and uses Unsettling Visage if available.\", acts = \"Read Thoughts, Shape-Shift (Bonus Action)\", what = \"Medium Monstrosity\" },\r\n[\"Dragon Turtle\"] = { ac = 20, hp = 356, init = 6, speed = 20, cr = \"17\", xp = 18000, saves = { Strength = 7, Dexterity = 0, Constitution = 11, Intelligence = 0, Wisdom = 7, Charisma = 1 }, attacks = {{ name = \"Bite\", hit = 13, dmg = \"3d10+7+2d6\" }, { name = \"Tail\", hit = 13, dmg = \"2d10+7\", type = \"Bludgeoning\" }}, pp = 11, pi = 11, stealth = 0, res = {\"Fire\"}, hab = {\"Coastal\", \"Underwater\"}, ctypes = {\"Dragon\"}, pb = 6, conm = 5, ab = {25, 10, 20, 10, 12, 12}, swim = true, ko = \"용거북\", sfx = {{ n = \"Steam Breath\", s = \"Constitution\", dc = 19, d = \"16d6\", t = \"Fire\", h = true, o = \"Recharge 5-6\" }}, multi = \"The dragon makes three Bite attacks. It can replace one attack with a Tail attack.\", what = \"Gargantuan Dragon\" },\r\n[\"Dretch\"] = { ac = 11, hp = 18, init = 0, speed = 20, cr = \"1/4\", xp = 50, saves = { Strength = 1, Dexterity = 0, Constitution = 1, Intelligence = -3, Wisdom = -1, Charisma = -4 }, attacks = {{ name = \"Rend\", hit = 3, dmg = \"1d6+1\", type = \"Slashing\" }}, pp = 9, pi = 9, stealth = 0, res = {\"Cold\", \"Fire\", \"Lightning\"}, imm = {\"Poison\"}, cimm = {\"Poisoned\"}, hab = {\"Planar\"}, ctypes = {\"Fiend\"}, pb = 2, conm = 1, ab = {12, 11, 12, 5, 8, 3}, unholy = true, ko = \"드레치\", sfx = {{ n = \"Fetid Cloud\", s = \"Constitution\", dc = 11, o = \"1/Day\" }}, what = \"Small Fiend (Demon)\" },\r\n[\"Drider\"] = { ac = 19, hp = 123, init = 4, speed = 30, cr = \"6\", xp = 2300, saves = { Strength = 3, Dexterity = 4, Constitution = 4, Intelligence = 1, Wisdom = 3, Charisma = 1 }, attacks = {{ name = \"Foreleg\", hit = 7, dmg = \"2d8+4\", type = \"Piercing\" }, { name = \"Poison Burst\", hit = 6, dmg = \"3d6+3\", k = \"r\", type = \"Poison\" }}, pp = 16, pi = 13, stealth = 10, hab = {\"Underdark\"}, ctypes = {\"Monstrosity\"}, pb = 3, conm = 4, ab = {16, 19, 18, 13, 16, 12}, ko = \"드라이더\", multi = \"The drider makes three attacks, using Foreleg or Poison Burst in any combination.\", acts = \"Magic of the Spider Queen (Recharge 5–6) (Bonus Action)\", what = \"Large Monstrosity\" },\r\n[\"Druid\"] = { ac = 13, hp = 44, init = 1, speed = 30, cr = \"2\", xp = 450, saves = { Strength = 0, Dexterity = 1, Constitution = 1, Intelligence = 1, Wisdom = 3, Charisma = 0 }, attacks = {{ name = \"Vine Staff\", hit = 5, dmg = \"1d8+3+1d4\" }, { name = \"Verdant Wisp\", hit = 5, dmg = \"3d6\", k = \"r\", type = \"Radiant\" }}, pp = 15, pi = 13, stealth = 1, hab = {\"Forest\"}, ctypes = {\"Pure Humanoid\"}, pb = 2, conm = 1, ab = {10, 12, 13, 12, 16, 11}, ko = \"드루이드\", sfx = {{ n = \"Thunderwave\", s = \"Constitution\", dc = 13, d = \"2d8\", o = \"spell\", t = \"Thunder\", h = true }, { n = \"Moonbeam\", s = \"Constitution\", dc = 13, d = \"2d10\", o = \"spell\", t = \"Radiant\", h = true }}, multi = \"The druid makes two attacks, using Vine Staff or Verdant Wisp in any combination.\", acts = \"Spellcasting\", what = \"Medium or Small Humanoid (Druid)\" },\r\n[\"Dryad\"] = { ac = 16, hp = 22, init = 1, speed = 30, cr = \"1\", xp = 200, saves = { Strength = 0, Dexterity = 1, Constitution = 0, Intelligence = 2, Wisdom = 2, Charisma = 4 }, attacks = {{ name = \"Vine Lash\", hit = 6, dmg = \"1d8+4\", type = \"Slashing\" }, { name = \"Thorn Burst\", hit = 6, dmg = \"1d6+4\", k = \"r\", type = \"Piercing\" }}, pp = 14, pi = 12, stealth = 5, hab = {\"Forest\"}, ctypes = {\"Fey\"}, pb = 2, conm = 0, ab = {10, 12, 11, 14, 15, 18}, ko = \"드라이어드\", mres = 1, multi = \"The dryad makes one Vine Lash or Thorn Burst attack, and it can use Spellcasting to cast Charm Monster.\", acts = \"Spellcasting, Tree Stride (Bonus Action)\", what = \"Medium Fey\" },\r\n[\"Earth Elemental\"] = { ac = 17, hp = 147, init = -1, speed = 30, cr = \"5\", xp = 1800, saves = { Strength = 5, Dexterity = -1, Constitution = 5, Intelligence = -3, Wisdom = 0, Charisma = -3 }, attacks = {{ name = \"Slam\", hit = 8, dmg = \"2d8+5\", type = \"Bludgeoning\" }, { name = \"Rock Launch\", hit = 8, dmg = \"1d6+5\", k = \"r\", type = \"Bludgeoning\" }}, pp = 10, pi = 10, stealth = -1, vul = {\"Thunder\"}, imm = {\"Poison\"}, cimm = {\"Exhaustion\", \"Paralyzed\", \"Petrified\", \"Poisoned\", \"Unconscious\"}, hab = {\"Desert\", \"Mountain\", \"Planar\", \"Underdark\"}, ctypes = {\"Elemental\"}, pb = 3, conm = 5, ab = {20, 8, 20, 5, 10, 5}, ko = \"대지 정령\", multi = \"The elemental makes two attacks, using Slam or Rock Launch in any combination.\", what = \"Large Elemental\" },\r\n[\"Efreeti\"] = { ac = 17, hp = 212, init = 1, speed = 40, cr = \"11\", xp = 7200, saves = { Strength = 6, Dexterity = 1, Constitution = 7, Intelligence = 3, Wisdom = 6, Charisma = 8 }, attacks = {{ name = \"Heated Blade\", hit = 10, dmg = \"2d6+6+2d12\" }, { name = \"Hurl Flame\", hit = 8, dmg = \"7d6\", k = \"r\", type = \"Fire\" }}, pp = 12, pi = 12, stealth = 1, imm = {\"Fire\"}, hab = {\"Desert\", \"Planar\"}, ctypes = {\"Elemental\"}, pb = 4, conm = 7, ab = {22, 12, 24, 16, 15, 19}, fly = true, ko = \"이프리트\", sfx = {{ n = \"Wall of Fire\", s = \"Dexterity\", dc = 16, d = \"8d8\", o = \"spell\", t = \"Fire\", h = true }}, mres = 1, multi = \"The efreeti makes three attacks, using Heated Blade or Hurl Flame in any combination.\", acts = \"Spellcasting\", what = \"Large Elemental (Genie)\" },\r\n[\"Erinyes\"] = { ac = 18, hp = 178, init = 7, speed = 30, cr = \"12\", xp = 8400, saves = { Strength = 4, Dexterity = 7, Constitution = 8, Intelligence = 2, Wisdom = 2, Charisma = 8 }, attacks = {{ name = \"Withering Sword\", hit = 8, dmg = \"2d8+4+2d10\" }}, pp = 16, pi = 12, stealth = 3, res = {\"Cold\"}, imm = {\"Fire\", \"Poison\"}, cimm = {\"Poisoned\"}, hab = {\"Planar\"}, ctypes = {\"Fiend\"}, pb = 4, conm = 4, ab = {18, 16, 18, 14, 14, 18}, unholy = true, fly = true, ko = \"에리니에스\", sfx = {{ n = \"Entangling Rope\", s = \"Strength\", dc = 16, d = \"4d6\", t = \"Force\", o = \"Requires Magic Rope\" }}, mres = 1, react = { n = 4, name = \"Parry\", melee = true }, multi = \"The erinyes makes three Withering Sword attacks and can use Entangling Rope.\", acts = \"Parry (Reaction)\", what = \"Medium Fiend (Devil)\" },\r\n[\"Ettercap\"] = { ac = 13, hp = 44, init = 2, speed = 30, cr = \"2\", xp = 450, saves = { Strength = 2, Dexterity = 2, Constitution = 1, Intelligence = -2, Wisdom = 1, Charisma = -1 }, attacks = {{ name = \"Bite\", hit = 4, dmg = \"1d6+2\", type = \"Piercing\" }, { name = \"Claw\", hit = 4, dmg = \"2d4+2\", type = \"Slashing\" }}, pp = 13, pi = 11, stealth = 4, hab = {\"Forest\", \"Swamp\"}, ctypes = {\"Monstrosity\"}, pb = 2, conm = 1, ab = {14, 15, 13, 7, 12, 8}, ko = \"에터캡\", sfx = {{ n = \"Web Strand\", s = \"Dexterity\", dc = 12, o = \"Recharge 5-6\" }}, multi = \"The ettercap makes one Bite attack and one Claw attack.\", acts = \"Reel (Bonus Action)\", what = \"Medium Monstrosity\" },\r\n[\"Ettin\"] = { ac = 12, hp = 85, init = -1, speed = 40, cr = \"4\", xp = 1100, saves = { Strength = 5, Dexterity = -1, Constitution = 3, Intelligence = -2, Wisdom = 0, Charisma = -1 }, attacks = {{ name = \"Battleaxe\", hit = 7, dmg = \"2d8+5\", type = \"Slashing\" }, { name = \"Morningstar\", hit = 7, dmg = \"2d8+5\", type = \"Piercing\" }}, pp = 14, pi = 10, stealth = -1, cimm = {\"Blinded\", \"Charmed\", \"Deafened\", \"Frightened\", \"Stunned\", \"Unconscious\"}, hab = {\"Hill\", \"Mountain\"}, ctypes = {\"Giant\"}, pb = 2, conm = 3, ab = {21, 8, 17, 6, 10, 8}, ko = \"에틴\", multi = \"The ettin makes one Battleaxe attack and one Morningstar attack.\", what = \"Large Giant\" },\r\n[\"Fire Elemental\"] = { ac = 13, hp = 93, init = 3, speed = 50, cr = \"5\", xp = 1800, saves = { Strength = 0, Dexterity = 3, Constitution = 3, Intelligence = -2, Wisdom = 0, Charisma = -2 }, attacks = {{ name = \"Burn\", hit = 6, dmg = \"2d6+3\", type = \"Fire\" }}, pp = 10, pi = 10, stealth = 3, res = {\"Bludgeoning\", \"Piercing\", \"Slashing\"}, imm = {\"Fire\", \"Poison\"}, cimm = {\"Exhaustion\", \"Grappled\", \"Paralyzed\", \"Petrified\", \"Poisoned\", \"Prone\", \"Restrained\", \"Unconscious\"}, hab = {\"Mountain\", \"Planar\"}, ctypes = {\"Elemental\"}, pb = 3, conm = 3, ab = {10, 17, 16, 6, 10, 7}, ko = \"불 정령\", sfx = {{ n = \"Fire Aura\", d = \"1d10\", t = \"Fire\" }, { n = \"Fire Form\", d = \"1d10\", t = \"Fire\" }}, hurts = {{ n = \"Water Susceptibility\", d = \"1d6\", t = \"Cold\" }}, multi = \"The elemental makes two Burn attacks.\", auto = {\"Fire Aura. At the end of each of the elemental's turns, each creature in a 10-foot Emanation originating from the elemental takes 5 (1d10) Fire damage. Creatures and flammable objects in the Emanation start burning.\"}, what = \"Large Elemental\" },\r\n[\"Fire Giant\"] = { ac = 18, hp = 162, init = 3, speed = 30, cr = \"9\", xp = 5000, saves = { Strength = 7, Dexterity = 3, Constitution = 10, Intelligence = 0, Wisdom = 2, Charisma = 5 }, attacks = {{ name = \"Flame Sword\", hit = 11, dmg = \"4d6+7+3d6\" }, { name = \"Hammer Throw\", hit = 11, dmg = \"3d10+7\", k = \"r\", type = \"Bludgeoning\" }}, pp = 16, pi = 12, stealth = -1, imm = {\"Fire\"}, hab = {\"Mountain\", \"Underdark\"}, ctypes = {\"Giant\"}, pb = 4, conm = 6, ab = {25, 9, 23, 10, 14, 13}, ko = \"불 거인\", multi = \"The giant makes two attacks, using Flame Sword or Hammer Throw in any combination.\", what = \"Huge Giant\" },\r\n[\"Flesh Golem\"] = { ac = 9, hp = 127, init = -1, speed = 30, cr = \"5\", xp = 1800, saves = { Strength = 4, Dexterity = -1, Constitution = 4, Intelligence = -2, Wisdom = 0, Charisma = -3 }, attacks = {{ name = \"Slam\", hit = 7, dmg = \"2d8+4+1d8\" }}, pp = 10, pi = 10, stealth = -1, imm = {\"Lightning\", \"Poison\"}, cimm = {\"Charmed\", \"Exhaustion\", \"Frightened\", \"Paralyzed\", \"Petrified\", \"Poisoned\"}, hab = {\"Ruins\"}, ctypes = {\"Construct\"}, pb = 3, conm = 4, ab = {19, 9, 18, 6, 10, 5}, ko = \"살덩이 골렘\", mres = 1, absorb = { n = \"Lightning Absorption\", t = \"Lightning\" }, multi = \"The golem makes two Slam attacks.\", auto = {\"Berserk. Whenever the golem starts its turn Bloodied, roll 1d6. On a 6, the golem goes berserk. On each of its turns while berserk, the golem attacks the nearest creature it can see. If no creature is near enough to move to and attack, the golem attacks an object. Once the golem goes berserk, it remains so until it is destroyed or it is no longer Bloodied. The golem's creator, if within 60 feet of the berserk golem, can try to calm it by taking an action to make a DC 15 Charisma (Persuasion) check; the golem must be able to hear its creator. (the rest: its stat block)\"}, what = \"Medium Construct\" },\r\n[\"Frost Giant\"] = { ac = 15, hp = 149, init = 2, speed = 40, cr = \"8\", xp = 3900, saves = { Strength = 6, Dexterity = -1, Constitution = 8, Intelligence = -1, Wisdom = 3, Charisma = 4 }, attacks = {{ name = \"Frost Axe\", hit = 9, dmg = \"2d12+6+2d8\" }, { name = \"Great Bow\", hit = 9, dmg = \"2d10+6\", k = \"r\", type = \"Piercing\" }}, pp = 13, pi = 10, stealth = -1, imm = {\"Cold\"}, hab = {\"Arctic\", \"Mountain\"}, ctypes = {\"Giant\"}, pb = 3, conm = 5, ab = {23, 9, 21, 9, 10, 12}, ko = \"서리 거인\", thps = {{ n = \"War Cry\", d = \"2d10+5\" }}, multi = \"The giant makes two attacks, using Frost Axe or Great Bow in any combination.\", acts = \"War Cry (Recharge 5–6) (Bonus Action)\", what = \"Huge Giant\" },\r\n[\"Shrieker Fungus\"] = { ac = 5, hp = 13, init = -5, speed = 5, cr = \"0\", xp = 0, saves = { Strength = -5, Dexterity = -5, Constitution = 0, Intelligence = -5, Wisdom = -4, Charisma = -5 }, attacks = {}, pp = 6, pi = 6, stealth = -5, cimm = {\"Blinded\", \"Charmed\", \"Deafened\", \"Frightened\"}, hab = {\"Ruins\", \"Underdark\"}, ctypes = {\"Plant\"}, pb = 2, conm = 0, ab = {1, 1, 10, 1, 3, 1}, ko = \"비명 버섯\", acts = \"Shriek (Reaction)\", what = \"Medium Plant\" },\r\n[\"Violet Fungus\"] = { ac = 5, hp = 18, init = -5, speed = 5, cr = \"1/4\", xp = 50, saves = { Strength = -4, Dexterity = -5, Constitution = 0, Intelligence = -5, Wisdom = -4, Charisma = -5 }, attacks = {{ name = \"Rotting Touch\", hit = 2, dmg = \"1d8\", type = \"Necrotic\" }}, pp = 6, pi = 6, stealth = -5, cimm = {\"Blinded\", \"Charmed\", \"Deafened\", \"Frightened\"}, hab = {\"Forest\", \"Ruins\", \"Underdark\"}, ctypes = {\"Plant\"}, pb = 2, conm = 0, ab = {3, 1, 10, 1, 3, 1}, ko = \"보라 버섯\", multi = \"The fungus makes two Rotting Touch attacks.\", what = \"Medium Plant\" },\r\n[\"Gargoyle\"] = { ac = 15, hp = 67, init = 2, speed = 30, cr = \"2\", xp = 450, saves = { Strength = 2, Dexterity = 0, Constitution = 3, Intelligence = -2, Wisdom = 0, Charisma = -2 }, attacks = {{ name = \"Claw\", hit = 4, dmg = \"2d4+2\", type = \"Slashing\" }}, pp = 10, pi = 10, stealth = 4, imm = {\"Poison\"}, cimm = {\"Exhaustion\", \"Petrified\", \"Poisoned\"}, hab = {\"Mountain\", \"Ruins\"}, ctypes = {\"Elemental\"}, pb = 2, conm = 3, ab = {15, 11, 16, 6, 11, 7}, fly = true, ko = \"가고일\", multi = \"The gargoyle makes two Claw attacks.\", what = \"Medium Elemental\" },\r\n[\"Gelatinous Cube\"] = { ac = 6, hp = 63, init = -4, speed = 15, cr = \"2\", xp = 450, saves = { Strength = 2, Dexterity = -4, Constitution = 5, Intelligence = -5, Wisdom = -2, Charisma = -5 }, attacks = {{ name = \"Pseudopod\", hit = 4, dmg = \"3d6+2\", type = \"Acid\" }}, pp = 8, pi = 8, stealth = -4, imm = {\"Acid\"}, cimm = {\"Blinded\", \"Charmed\", \"Deafened\", \"Exhaustion\", \"Frightened\", \"Prone\"}, hab = {\"Ruins\", \"Underdark\"}, ctypes = {\"Ooze\"}, pb = 2, conm = 5, ab = {14, 3, 20, 1, 6, 1}, ko = \"젤라틴 큐브\", sfx = {{ n = \"Ooze Cube\", d = \"3d6\", t = \"Acid\" }, { n = \"Engulf\", s = \"Dexterity\", dc = 12, d = \"3d6\", t = \"Acid\", h = true }, { n = \"Engulf (each turn)\", d = \"3d6\", t = \"Acid\" }}, what = \"Large Ooze\" },\r\n[\"Ghast\"] = { ac = 13, hp = 36, init = 3, speed = 30, cr = \"2\", xp = 450, saves = { Strength = 3, Dexterity = 3, Constitution = 0, Intelligence = 0, Wisdom = 2, Charisma = -1 }, attacks = {{ name = \"Bite\", hit = 5, dmg = \"1d8+3+2d8\" }, { name = \"Claw\", hit = 5, dmg = \"2d6+3\", type = \"Slashing\" }}, pp = 10, pi = 10, stealth = 3, res = {\"Necrotic\"}, imm = {\"Poison\"}, cimm = {\"Charmed\", \"Exhaustion\", \"Poisoned\"}, hab = {\"Ruins\", \"Swamp\"}, ctypes = {\"Undead\"}, pb = 2, conm = 0, ab = {16, 17, 10, 11, 10, 8}, unholy = true, undead = true, ko = \"가스트\", sfx = {{ n = \"Stench\", s = \"Constitution\", dc = 10 }}, auto = {\"Stench. Constitution Saving Throw: DC 10, any creature that starts its turn in a 5-foot Emanation originating from the ghast. Failure: The target has the Poisoned condition until the start of its next turn. Success: The target is immune to this ghast's Stench for 24 hours.\"}, what = \"Medium Undead\" },\r\n[\"Ghost\"] = { ac = 11, hp = 45, init = 1, speed = 5, cr = \"4\", xp = 1100, saves = { Strength = -2, Dexterity = 1, Constitution = 0, Intelligence = 0, Wisdom = 1, Charisma = 3 }, attacks = {{ name = \"Withering Touch\", hit = 5, dmg = \"3d10+3\", type = \"Necrotic\" }}, pp = 11, pi = 11, stealth = 1, res = {\"Acid\", \"Bludgeoning\", \"Cold\", \"Fire\", \"Lightning\", \"Piercing\", \"Slashing\", \"Thunder\"}, imm = {\"Necrotic\", \"Poison\"}, cimm = {\"Charmed\", \"Exhaustion\", \"Frightened\", \"Grappled\", \"Paralyzed\", \"Petrified\", \"Poisoned\", \"Prone\", \"Restrained\"}, hab = {\"Ruins\", \"Urban\"}, ctypes = {\"Undead\"}, pb = 2, conm = 0, ab = {7, 13, 10, 10, 12, 17}, unholy = true, undead = true, fly = true, ko = \"유령\", sfx = {{ n = \"Horrific Visage\", s = \"Wisdom\", dc = 13, d = \"2d6+3\", t = \"Psychic\" }, { n = \"Possession\", s = \"Charisma\", dc = 13, o = \"Recharge 6\" }}, hurts = {{ n = \"Incorporeal Movement\", d = \"1d10\", t = \"Force\" }}, multi = \"The ghost makes two Withering Touch attacks.\", acts = \"Etherealness\", what = \"Medium Undead\" },\r\n[\"Ghoul\"] = { ac = 12, hp = 22, init = 2, speed = 30, cr = \"1\", xp = 200, saves = { Strength = 1, Dexterity = 2, Constitution = 0, Intelligence = -2, Wisdom = 0, Charisma = -2 }, attacks = {{ name = \"Bite\", hit = 4, dmg = \"1d6+2+1d6\" }, { name = \"Claw\", hit = 4, dmg = \"1d4+2\", type = \"Slashing\" }}, pp = 10, pi = 10, stealth = 2, imm = {\"Poison\"}, cimm = {\"Charmed\", \"Exhaustion\", \"Poisoned\"}, hab = {\"Ruins\", \"Swamp\", \"Urban\"}, ctypes = {\"Undead\"}, pb = 2, conm = 0, ab = {13, 15, 10, 7, 10, 6}, unholy = true, undead = true, ko = \"구울\", multi = \"The ghoul makes two Bite attacks.\", what = \"Medium Undead\" },\r\n[\"Gibbering Mouther\"] = { ac = 9, hp = 52, init = -1, speed = 20, cr = \"2\", xp = 450, saves = { Strength = 0, Dexterity = -1, Constitution = 3, Intelligence = -4, Wisdom = 0, Charisma = -2 }, attacks = {{ name = \"Bite\", hit = 2, dmg = \"2d6\", type = \"Piercing\" }}, pp = 10, pi = 10, stealth = -1, cimm = {\"Prone\"}, hab = {\"Underdark\"}, ctypes = {\"Aberration\"}, pb = 2, conm = 3, ab = {10, 8, 16, 3, 10, 6}, swim = true, ko = \"지껄이는 입\", sfx = {{ n = \"Gibbering\", s = \"Wisdom\", dc = 10 }, { n = \"Blinding Spittle\", s = \"Dexterity\", dc = 10, d = \"2d6\", t = \"Radiant\", o = \"Recharge 5-6\" }}, auto = {\"Aberrant Ground. The ground in a 10-foot Emanation originating from the mouther is Difficult Terrain.\", \"Gibbering. The mouther babbles incoherently while it doesn't have the Incapacitated condition. Wisdom Saving Throw: DC 10, any creature that starts its turn within 20 feet of the mouther while it is babbling. Failure: The target rolls 1d8 to determine what it does during the current turn: 1–4. The target does nothing. 5–6. The target takes no action or Bonus Action and uses all its movement to move in a random direction. 7–8. The target makes a melee attack against a randomly determined creature within its reach or does nothing if it can't make such an attack.\"}, what = \"Medium Aberration\" },\r\n[\"Glabrezu\"] = { ac = 17, hp = 189, init = 6, speed = 40, cr = \"9\", xp = 5000, saves = { Strength = 9, Dexterity = 2, Constitution = 9, Intelligence = 4, Wisdom = 7, Charisma = 7 }, attacks = {{ name = \"Pincer\", hit = 9, dmg = \"2d10+5\", type = \"Slashing\" }}, pp = 17, pi = 13, stealth = 2, res = {\"Cold\", \"Fire\", \"Lightning\"}, imm = {\"Poison\"}, cimm = {\"Poisoned\"}, hab = {\"Planar\"}, ctypes = {\"Fiend\"}, pb = 4, conm = 5, ab = {20, 15, 21, 19, 17, 16}, unholy = true, ko = \"글라브레주\", sfx = {{ n = \"Pummel\", s = \"Dexterity\", dc = 17, d = \"3d6+5\", t = \"Bludgeoning\", h = true }}, mres = 1, multi = \"The glabrezu makes two Pincer attacks and uses Pummel or Spellcasting.\", acts = \"Spellcasting\", what = \"Large Fiend (Demon)\" },\r\n[\"Gladiator\"] = { ac = 16, hp = 112, init = 5, speed = 30, cr = \"5\", xp = 1800, saves = { Strength = 7, Dexterity = 5, Constitution = 6, Intelligence = 0, Wisdom = 4, Charisma = 2 }, attacks = {{ name = \"Spear\", hit = 7, dmg = \"2d6+4\", k = \"b\", type = \"Piercing\" }}, pp = 11, pi = 11, stealth = 2, hab = {\"Urban\"}, ctypes = {\"Pure Humanoid\"}, pb = 3, conm = 3, ab = {18, 15, 16, 10, 12, 15}, ko = \"검투사\", sfx = {{ n = \"Shield Bash\", s = \"Strength\", dc = 15, d = \"2d4+4\", t = \"Bludgeoning\" }}, react = { n = 3, name = \"Parry\", melee = true }, multi = \"The gladiator makes three Spear attacks. It can replace one attack with a use of Shield Bash.\", acts = \"Parry (Reaction)\", what = \"Medium or Small Humanoid\" },\r\n[\"Gnoll Warrior\"] = { ac = 15, hp = 27, init = 1, speed = 30, cr = \"1/2\", xp = 100, saves = { Strength = 2, Dexterity = 1, Constitution = 0, Intelligence = -2, Wisdom = 0, Charisma = -2 }, attacks = {{ name = \"Rend\", hit = 4, dmg = \"1d6+2\", type = \"Piercing\" }, { name = \"Bone Bow\", hit = 3, dmg = \"1d10+1\", k = \"r\", type = \"Piercing\" }}, pp = 10, pi = 10, stealth = 1, hab = {\"Desert\", \"Grassland\"}, ctypes = {\"Fiend\"}, pb = 2, conm = 0, ab = {14, 12, 11, 6, 10, 7}, unholy = true, ko = \"놀 전사\", acts = \"Rampage (1/Day) (Bonus Action)\", what = \"Medium Fiend\" },\r\n[\"Goblin Minion\"] = { ac = 12, hp = 7, init = 2, speed = 30, cr = \"1/8\", xp = 25, saves = { Strength = -1, Dexterity = 2, Constitution = 0, Intelligence = 0, Wisdom = -1, Charisma = -1 }, attacks = {{ name = \"Dagger\", hit = 4, dmg = \"1d4+2\", k = \"b\", type = \"Piercing\" }}, pp = 9, pi = 9, stealth = 6, hab = {\"Forest\", \"Hill\", \"Ruins\"}, ctypes = {\"Fey\", \"Goblinoid\"}, pb = 2, conm = 0, ab = {8, 15, 10, 10, 8, 8}, ko = \"고블린 졸개\", acts = \"Nimble Escape (Bonus Action)\", what = \"Small Fey (Goblinoid)\" },\r\n[\"Goblin Warrior\"] = { ac = 15, hp = 10, init = 2, speed = 30, cr = \"1/4\", xp = 50, saves = { Strength = -1, Dexterity = 2, Constitution = 0, Intelligence = 0, Wisdom = -1, Charisma = -1 }, attacks = {{ name = \"Scimitar\", hit = 4, dmg = \"1d6+2\", adv = \"1d6+2+1d4\", type = \"Slashing\" }, { name = \"Shortbow\", hit = 4, dmg = \"1d6+2\", k = \"r\", adv = \"1d6+2+1d4\", type = \"Piercing\" }}, pp = 9, pi = 9, stealth = 6, hab = {\"Forest\", \"Grassland\", \"Hill\", \"Ruins\", \"Underdark\"}, ctypes = {\"Fey\", \"Goblinoid\"}, pb = 2, conm = 0, ab = {8, 15, 10, 10, 8, 8}, ko = \"고블린 전사\", acts = \"Nimble Escape (Bonus Action)\", what = \"Small Fey (Goblinoid)\" },\r\n[\"Goblin Boss\"] = { ac = 17, hp = 21, init = 2, speed = 30, cr = \"1\", xp = 200, saves = { Strength = 0, Dexterity = 2, Constitution = 0, Intelligence = 0, Wisdom = -1, Charisma = 0 }, attacks = {{ name = \"Scimitar\", hit = 4, dmg = \"1d6+2\", adv = \"1d6+2+1d4\", type = \"Slashing\" }, { name = \"Shortbow\", hit = 4, dmg = \"1d6+2\", k = \"r\", adv = \"1d6+2+1d4\", type = \"Piercing\" }}, pp = 9, pi = 9, stealth = 6, hab = {\"Forest\", \"Hill\", \"Ruins\"}, ctypes = {\"Fey\", \"Goblinoid\"}, pb = 2, conm = 0, ab = {10, 15, 10, 10, 8, 10}, ko = \"고블린 두목\", multi = \"The goblin makes two attacks, using Scimitar or Shortbow in any combination.\", acts = \"Nimble Escape (Bonus Action), Redirect Attack (Reaction)\", what = \"Small Fey (Goblinoid)\" },\r\n[\"Gold Dragon Wyrmling\"] = { ac = 17, hp = 60, init = 4, speed = 30, cr = \"3\", xp = 700, saves = { Strength = 4, Dexterity = 4, Constitution = 3, Intelligence = 2, Wisdom = 2, Charisma = 3 }, attacks = {{ name = \"Rend\", hit = 6, dmg = \"1d10+4\", type = \"Slashing\" }}, pp = 14, pi = 10, stealth = 4, imm = {\"Fire\"}, hab = {\"Grassland\", \"Hill\"}, ctypes = {\"Dragon\"}, pb = 2, conm = 3, ab = {19, 14, 17, 14, 11, 16}, fly = true, swim = true, ko = \"새끼 금룡\", sfx = {{ n = \"Fire Breath\", s = \"Dexterity\", dc = 13, d = \"4d10\", t = \"Fire\", h = true, o = \"Recharge 5-6\" }, { n = \"Weakening Breath\", s = \"Strength\", dc = 13 }}, multi = \"The dragon makes two Rend attacks.\", what = \"Medium Dragon (Metallic)\" },\r\n[\"Young Gold Dragon\"] = { ac = 18, hp = 178, init = 6, speed = 40, cr = \"10\", xp = 5900, saves = { Strength = 6, Dexterity = 6, Constitution = 5, Intelligence = 3, Wisdom = 5, Charisma = 5 }, attacks = {{ name = \"Rend\", hit = 10, dmg = \"2d10+6\", type = \"Slashing\" }}, pp = 19, pi = 15, stealth = 6, imm = {\"Fire\"}, hab = {\"Forest\", \"Grassland\"}, ctypes = {\"Dragon\"}, pb = 4, conm = 5, ab = {23, 14, 21, 16, 13, 20}, fly = true, swim = true, ko = \"젊은 금룡\", sfx = {{ n = \"Fire Breath\", s = \"Dexterity\", dc = 17, d = \"10d10\", t = \"Fire\", h = true, o = \"Recharge 5-6\" }, { n = \"Weakening Breath\", s = \"Strength\", dc = 17 }}, multi = \"The dragon makes three Rend attacks. It can replace one attack with a use of Weakening Breath.\", what = \"Large Dragon (Metallic)\" },\r\n[\"Adult Gold Dragon\"] = { ac = 19, hp = 243, init = 14, speed = 40, cr = \"17\", xp = 18000, saves = { Strength = 8, Dexterity = 8, Constitution = 7, Intelligence = 3, Wisdom = 8, Charisma = 7 }, attacks = {{ name = \"Rend\", hit = 14, dmg = \"2d8+8+1d8\" }, { name = \"Guiding Bolt (spell)\", hit = 13, dmg = \"5d6\", type = \"Radiant\", srange = \"ranged\" }}, pp = 24, pi = 18, stealth = 8, imm = {\"Fire\"}, hab = {\"Forest\", \"Grassland\"}, ctypes = {\"Dragon\"}, pb = 6, conm = 7, ab = {27, 14, 25, 16, 15, 24}, fly = true, swim = true, ko = \"성체 금룡\", sfx = {{ n = \"Fire Breath\", s = \"Dexterity\", dc = 21, d = \"12d10\", t = \"Fire\", h = true, o = \"Recharge 5-6\" }, { n = \"Weakening Breath\", s = \"Strength\", dc = 21 }, { n = \"Banish\", s = \"Charisma\", dc = 21, d = \"3d6\", t = \"Force\", lg = true }, { n = \"Flame Strike\", s = \"Dexterity\", dc = 21, d = \"5d6+5d6\", o = \"spell\", t = \"Fire and Radiant\", h = true }}, lr = 3, la = 3, lacts = {\"Banish\", \"Guiding Light\", \"Pounce\"}, multi = \"The dragon makes three Rend attacks. It can replace one attack with a use of (A) Spellcasting to cast Guiding Bolt (level 2 version) or (B) Weakening Breath.\", acts = \"Spellcasting\", what = \"Huge Dragon (Metallic)\" },\r\n[\"Ancient Gold Dragon\"] = { ac = 22, hp = 546, init = 16, speed = 40, cr = \"24\", xp = 62000, saves = { Strength = 10, Dexterity = 9, Constitution = 9, Intelligence = 4, Wisdom = 10, Charisma = 9 }, attacks = {{ name = \"Rend\", hit = 17, dmg = \"2d8+10+2d8\" }, { name = \"Guiding Bolt (spell)\", hit = 16, dmg = \"7d6\", type = \"Radiant\", srange = \"ranged\" }}, pp = 27, pi = 20, stealth = 9, imm = {\"Fire\"}, hab = {\"Forest\", \"Grassland\"}, ctypes = {\"Dragon\"}, pb = 7, conm = 9, ab = {30, 14, 29, 18, 17, 28}, fly = true, swim = true, ko = \"고룡 금룡\", sfx = {{ n = \"Fire Breath\", s = \"Dexterity\", dc = 24, d = \"13d10\", t = \"Fire\", h = true, o = \"Recharge 5-6\" }, { n = \"Weakening Breath\", s = \"Strength\", dc = 24 }, { n = \"Banish\", s = \"Charisma\", dc = 24, d = \"7d6\", t = \"Force\", lg = true }, { n = \"Flame Strike\", s = \"Dexterity\", dc = 24, d = \"7d6+5d6\", o = \"spell\", t = \"Fire and Radiant\", h = true }}, lr = 4, la = 3, lacts = {\"Banish\", \"Guiding Light\", \"Pounce\"}, multi = \"The dragon makes three Rend attacks. It can replace one attack with a use of (A) Spellcasting to cast Guiding Bolt (level 4 version) or (B) Weakening Breath.\", acts = \"Spellcasting\", what = \"Gargantuan Dragon (Metallic)\" },\r\n[\"Gorgon\"] = { ac = 19, hp = 114, init = 0, speed = 40, cr = \"5\", xp = 1800, saves = { Strength = 5, Dexterity = 0, Constitution = 4, Intelligence = -4, Wisdom = 1, Charisma = -2 }, attacks = {{ name = \"Gore\", hit = 8, dmg = \"2d12+5\", type = \"Piercing\" }}, pp = 17, pi = 11, stealth = 0, cimm = {\"Exhaustion\", \"Petrified\"}, hab = {\"Hill\"}, ctypes = {\"Construct\"}, pb = 3, conm = 4, ab = {20, 11, 18, 2, 12, 7}, ko = \"고르곤\", sfx = {{ n = \"Petrifying Breath\", s = \"Constitution\", dc = 15, o = \"Recharge 5-6\" }, { n = \"Trample\", s = \"Dexterity\", dc = 16, d = \"2d10+5\", t = \"Bludgeoning\", h = true }}, what = \"Large Construct\" },\r\n[\"Gray Ooze\"] = { ac = 9, hp = 22, init = -2, speed = 10, cr = \"1/2\", xp = 100, saves = { Strength = 1, Dexterity = -2, Constitution = 3, Intelligence = -5, Wisdom = -2, Charisma = -4 }, attacks = {{ name = \"Pseudopod\", hit = 3, dmg = \"2d8+1\", type = \"Acid\" }}, pp = 8, pi = 8, stealth = 2, res = {\"Acid\", \"Cold\", \"Fire\"}, cimm = {\"Blinded\", \"Charmed\", \"Deafened\", \"Exhaustion\", \"Frightened\", \"Grappled\", \"Prone\", \"Restrained\"}, hab = {\"Ruins\", \"Underdark\"}, ctypes = {\"Ooze\"}, pb = 2, conm = 3, ab = {12, 6, 16, 1, 6, 2}, ko = \"회색 우즈\", wear = true, what = \"Medium Ooze\" },\r\n[\"Green Dragon Wyrmling\"] = { ac = 17, hp = 38, init = 3, speed = 30, cr = \"2\", xp = 450, saves = { Strength = 2, Dexterity = 3, Constitution = 1, Intelligence = 2, Wisdom = 2, Charisma = 1 }, attacks = {{ name = \"Rend\", hit = 4, dmg = \"1d10+2+1d6\" }}, pp = 14, pi = 10, stealth = 3, imm = {\"Poison\"}, cimm = {\"Poisoned\"}, hab = {\"Forest\"}, ctypes = {\"Dragon\"}, pb = 2, conm = 1, ab = {15, 12, 13, 14, 11, 13}, fly = true, swim = true, ko = \"새끼 녹룡\", sfx = {{ n = \"Poison Breath\", s = \"Constitution\", dc = 11, d = \"6d6\", t = \"Poison\", h = true, o = \"Recharge 5-6\" }}, multi = \"The dragon makes two Rend attacks.\", what = \"Medium Dragon (Chromatic)\" },\r\n[\"Young Green Dragon\"] = { ac = 18, hp = 136, init = 4, speed = 40, cr = \"8\", xp = 3900, saves = { Strength = 4, Dexterity = 4, Constitution = 3, Intelligence = 3, Wisdom = 4, Charisma = 2 }, attacks = {{ name = \"Rend\", hit = 7, dmg = \"2d6+4+2d6\" }}, pp = 17, pi = 11, stealth = 4, imm = {\"Poison\"}, cimm = {\"Poisoned\"}, hab = {\"Forest\"}, ctypes = {\"Dragon\"}, pb = 3, conm = 3, ab = {19, 12, 17, 16, 13, 15}, fly = true, swim = true, ko = \"젊은 녹룡\", sfx = {{ n = \"Poison Breath\", s = \"Constitution\", dc = 14, d = \"12d6\", t = \"Poison\", h = true, o = \"Recharge 5-6\" }}, multi = \"The dragon makes three Rend attacks.\", what = \"Large Dragon (Chromatic)\" },\r\n[\"Adult Green Dragon\"] = { ac = 19, hp = 207, init = 11, speed = 40, cr = \"15\", xp = 13000, saves = { Strength = 6, Dexterity = 6, Constitution = 5, Intelligence = 4, Wisdom = 7, Charisma = 4 }, attacks = {{ name = \"Rend\", hit = 11, dmg = \"2d8+6+2d6\" }}, pp = 22, pi = 12, stealth = 6, imm = {\"Poison\"}, cimm = {\"Poisoned\"}, hab = {\"Forest\"}, ctypes = {\"Dragon\"}, pb = 5, conm = 5, ab = {23, 12, 21, 18, 15, 18}, fly = true, swim = true, ko = \"성체 녹룡\", sfx = {{ n = \"Poison Breath\", s = \"Constitution\", dc = 18, d = \"16d6\", t = \"Poison\", h = true, o = \"Recharge 5-6\" }, { n = \"Noxious Miasma\", s = \"Constitution\", dc = 17, d = \"2d6\", t = \"Poison\", lg = true }, { n = \"Mind Spike\", s = \"Wisdom\", dc = 17, d = \"4d8\", o = \"spell\", t = \"Psychic\", h = true }}, lr = 3, la = 3, lacts = {\"Mind Invasion\", \"Noxious Miasma\", \"Pounce\"}, multi = \"The dragon makes three Rend attacks. It can replace one attack with a use of Spellcasting to cast Mind Spike (level 3 version).\", acts = \"Spellcasting\", what = \"Huge Dragon (Chromatic)\" },\r\n[\"Ancient Green Dragon\"] = { ac = 21, hp = 402, init = 15, speed = 40, cr = \"22\", xp = 41000, saves = { Strength = 8, Dexterity = 8, Constitution = 7, Intelligence = 5, Wisdom = 10, Charisma = 6 }, attacks = {{ name = \"Rend\", hit = 15, dmg = \"2d8+8+3d6\" }}, pp = 27, pi = 13, stealth = 8, imm = {\"Poison\"}, cimm = {\"Poisoned\"}, hab = {\"Forest\"}, ctypes = {\"Dragon\"}, pb = 7, conm = 7, ab = {27, 12, 25, 20, 17, 22}, fly = true, swim = true, ko = \"고룡 녹룡\", sfx = {{ n = \"Poison Breath\", s = \"Constitution\", dc = 22, d = \"22d6\", t = \"Poison\", h = true, o = \"Recharge 5-6\" }, { n = \"Noxious Miasma\", s = \"Constitution\", dc = 21, d = \"5d6\", t = \"Poison\", lg = true }, { n = \"Mind Spike\", s = \"Wisdom\", dc = 21, d = \"6d8\", o = \"spell\", t = \"Psychic\", h = true }}, lr = 4, la = 3, lacts = {\"Mind Invasion\", \"Noxious Miasma\", \"Pounce\"}, multi = \"The dragon makes three Rend attacks. It can replace one attack with a use of Spellcasting to cast Mind Spike (level 5 version).\", acts = \"Spellcasting\", what = \"Gargantuan Dragon (Chromatic)\" },\r\n[\"Green Hag\"] = { ac = 17, hp = 82, init = 1, speed = 30, cr = \"3\", xp = 700, saves = { Strength = 4, Dexterity = 1, Constitution = 3, Intelligence = 1, Wisdom = 2, Charisma = 2 }, attacks = {{ name = \"Claw\", hit = 6, dmg = \"1d8+4+1d6\" }, { name = \"Ray of Sickness (spell)\", hit = 4, dmg = \"4d8\", type = \"Poison\", srange = \"ranged\" }}, pp = 14, pi = 12, stealth = 3, hab = {\"Forest\", \"Swamp\"}, ctypes = {\"Fey\"}, pb = 2, conm = 3, ab = {18, 12, 16, 13, 14, 14}, swim = true, ko = \"녹색 마귀할멈\", multi = \"The hag makes two Claw attacks.\", acts = \"Spellcasting\", what = \"Medium Fey\" },\r\n[\"Grick\"] = { ac = 14, hp = 54, init = 2, speed = 30, cr = \"2\", xp = 450, saves = { Strength = 2, Dexterity = 2, Constitution = 0, Intelligence = -4, Wisdom = 2, Charisma = -3 }, attacks = {{ name = \"Beak\", hit = 4, dmg = \"2d6+2\", type = \"Piercing\" }, { name = \"Tentacles\", hit = 4, dmg = \"1d10+2\", type = \"Slashing\" }}, pp = 12, pi = 12, stealth = 4, hab = {\"Ruins\", \"Underdark\"}, ctypes = {\"Aberration\"}, pb = 2, conm = 0, ab = {14, 14, 11, 3, 14, 5}, ko = \"그릭\", multi = \"The grick makes one Beak attack and one Tentacles attack.\", what = \"Medium Aberration\" },\r\n[\"Griffon\"] = { ac = 12, hp = 59, init = 2, speed = 30, cr = \"2\", xp = 450, saves = { Strength = 4, Dexterity = 2, Constitution = 3, Intelligence = -4, Wisdom = 1, Charisma = -1 }, attacks = {{ name = \"Rend\", hit = 6, dmg = \"1d8+4\", type = \"Piercing\" }}, pp = 15, pi = 11, stealth = 2, hab = {\"Grassland\", \"Hill\", \"Mountain\"}, ctypes = {\"Monstrosity\"}, pb = 2, conm = 3, ab = {18, 15, 16, 2, 13, 8}, fly = true, ko = \"그리폰\", multi = \"The griffon makes two Rend attacks.\", what = \"Large Monstrosity\" },\r\n[\"Grimlock\"] = { ac = 11, hp = 11, init = 1, speed = 30, cr = \"1/4\", xp = 50, saves = { Strength = 3, Dexterity = 1, Constitution = 1, Intelligence = -1, Wisdom = -1, Charisma = -2 }, attacks = {{ name = \"Bone Cudgel\", hit = 5, dmg = \"1d6+3+1d4\" }}, pp = 13, pi = 9, stealth = 5, hab = {\"Underdark\"}, ctypes = {\"Aberration\"}, pb = 2, conm = 1, ab = {16, 12, 12, 9, 8, 6}, ko = \"그림록\", what = \"Medium Aberration\" },\r\n[\"Guardian Naga\"] = { ac = 18, hp = 136, init = 4, speed = 40, cr = \"10\", xp = 5900, saves = { Strength = 4, Dexterity = 8, Constitution = 7, Intelligence = 7, Wisdom = 8, Charisma = 8 }, attacks = {{ name = \"Bite\", hit = 8, dmg = \"2d12+4+4d10\" }}, pp = 14, pi = 14, stealth = 4, imm = {\"Poison\"}, cimm = {\"Charmed\", \"Paralyzed\", \"Poisoned\", \"Restrained\"}, hab = {\"Ruins\"}, ctypes = {\"Celestial\"}, pb = 4, conm = 3, ab = {19, 18, 16, 16, 19, 18}, swim = true, ko = \"수호 나가\", sfx = {{ n = \"Poisonous Spittle\", s = \"Constitution\", dc = 16, d = \"7d8\", t = \"Poison\", h = true }, { n = \"Flame Strike\", s = \"Dexterity\", dc = 16, d = \"7d6+5d6\", o = \"spell\", t = \"Fire and Radiant\", h = true }}, multi = \"The naga makes two Bite attacks. It can replace any attack with a use of Poisonous Spittle.\", acts = \"Spellcasting\", what = \"Large Celestial\" },\r\n[\"Guard\"] = { ac = 16, hp = 11, init = 1, speed = 30, cr = \"1/8\", xp = 25, saves = { Strength = 1, Dexterity = 1, Constitution = 1, Intelligence = 0, Wisdom = 0, Charisma = 0 }, attacks = {{ name = \"Spear\", hit = 3, dmg = \"1d6+1\", k = \"b\", type = \"Piercing\" }}, pp = 12, pi = 10, stealth = 1, hab = {\"Urban\"}, ctypes = {\"Pure Humanoid\"}, pb = 2, conm = 1, ab = {13, 12, 12, 10, 11, 10}, ko = \"경비병\", what = \"Medium or Small Humanoid\" },\r\n[\"Guard Captain\"] = { ac = 18, hp = 75, init = 4, speed = 30, cr = \"4\", xp = 1100, saves = { Strength = 4, Dexterity = 2, Constitution = 3, Intelligence = 1, Wisdom = 2, Charisma = 1 }, attacks = {{ name = \"Javelin\", hit = 6, dmg = \"3d6+4\", k = \"b\", type = \"Piercing\" }, { name = \"Longsword\", hit = 6, dmg = \"2d10+4\", type = \"Slashing\" }}, pp = 14, pi = 12, stealth = 2, hab = {\"Urban\"}, ctypes = {\"Pure Humanoid\"}, pb = 2, conm = 3, ab = {18, 14, 16, 12, 14, 13}, ko = \"경비대장\", multi = \"The guard makes two attacks, using Javelin or Longsword in any combination.\", what = \"Medium or Small Humanoid\" },\r\n[\"Half-Dragon\"] = { ac = 18, hp = 105, init = 5, speed = 40, cr = \"5\", xp = 1800, saves = { Strength = 4, Dexterity = 5, Constitution = 3, Intelligence = 0, Wisdom = 5, Charisma = 2 }, attacks = {{ name = \"Claw\", hit = 7, dmg = \"1d4+4\", type = \"Slashing\" }}, pp = 15, pi = 12, stealth = 5, hab = {\"Mountain\"}, ctypes = {\"Dragon\"}, pb = 3, conm = 3, ab = {19, 14, 16, 10, 15, 14}, ko = \"하프 드래곤\", sfx = {{ n = \"Dragon's Breath\", s = \"Dexterity\", dc = 14, o = \"Recharge 5-6\" }}, multi = \"The half-dragon makes two Claw attacks.\", acts = \"Leap (Bonus Action)\", what = \"Medium Dragon\" },\r\n[\"Harpy\"] = { ac = 11, hp = 38, init = 1, speed = 20, cr = \"1\", xp = 200, saves = { Strength = 1, Dexterity = 1, Constitution = 1, Intelligence = -2, Wisdom = 0, Charisma = 1 }, attacks = {{ name = \"Claw\", hit = 3, dmg = \"2d4+1\", type = \"Slashing\" }}, pp = 10, pi = 10, stealth = 1, hab = {\"Coastal\"}, ctypes = {\"Monstrosity\"}, pb = 2, conm = 1, ab = {12, 13, 12, 7, 10, 13}, fly = true, ko = \"하피\", sfx = {{ n = \"Luring Song\", s = \"Wisdom\", dc = 11 }}, what = \"Medium Monstrosity\" },\r\n[\"Hell Hound\"] = { ac = 15, hp = 58, init = 1, speed = 50, cr = \"3\", xp = 700, saves = { Strength = 3, Dexterity = 1, Constitution = 2, Intelligence = -2, Wisdom = 1, Charisma = -2 }, attacks = {{ name = \"Bite\", hit = 5, dmg = \"1d8+3+1d6\" }}, pp = 15, pi = 11, stealth = 1, imm = {\"Fire\"}, hab = {\"Planar\"}, ctypes = {\"Fiend\"}, pb = 2, conm = 2, ab = {17, 12, 14, 6, 13, 6}, unholy = true, ko = \"지옥견\", sfx = {{ n = \"Fire Breath\", s = \"Dexterity\", dc = 12, d = \"5d6\", t = \"Fire\", h = true, o = \"Recharge 5-6\" }}, multi = \"The hound makes two Bite attacks.\", what = \"Medium Fiend\" },\r\n[\"Hezrou\"] = { ac = 18, hp = 157, init = 6, speed = 30, cr = \"8\", xp = 3900, saves = { Strength = 7, Dexterity = 3, Constitution = 8, Intelligence = -3, Wisdom = 4, Charisma = 1 }, attacks = {{ name = \"Rend\", hit = 7, dmg = \"1d4+4+2d8\" }}, pp = 11, pi = 11, stealth = 3, res = {\"Cold\", \"Fire\", \"Lightning\"}, imm = {\"Poison\"}, cimm = {\"Poisoned\"}, hab = {\"Planar\", \"Swamp\"}, ctypes = {\"Fiend\"}, pb = 3, conm = 5, ab = {19, 17, 20, 5, 12, 13}, unholy = true, ko = \"헤즈로우\", sfx = {{ n = \"Stench\", s = \"Constitution\", dc = 16 }}, mres = 1, multi = \"The hezrou makes three Rend attacks.\", acts = \"Leap (Bonus Action)\", auto = {\"Stench. Constitution Saving Throw: DC 16, any creature that starts its turn in a 10-foot Emanation originating from the hezrou. Failure: The target has the Poisoned condition until the start of its next turn.\"}, what = \"Large Fiend (Demon)\" },\r\n[\"Hill Giant\"] = { ac = 13, hp = 105, init = 2, speed = 40, cr = \"5\", xp = 1800, saves = { Strength = 5, Dexterity = -1, Constitution = 4, Intelligence = -3, Wisdom = -1, Charisma = -2 }, attacks = {{ name = \"Tree Club\", hit = 8, dmg = \"3d8+5\", type = \"Bludgeoning\" }, { name = \"Trash Lob\", hit = 8, dmg = \"2d10+5\", k = \"r\", type = \"Bludgeoning\" }}, pp = 12, pi = 9, stealth = -1, hab = {\"Hill\", \"Mountain\"}, ctypes = {\"Giant\"}, pb = 3, conm = 4, ab = {21, 8, 19, 5, 9, 6}, ko = \"언덕 거인\", multi = \"The giant makes two attacks, using Tree Club or Trash Lob in any combination.\", what = \"Huge Giant\" },\r\n[\"Hippogriff\"] = { ac = 11, hp = 26, init = 1, speed = 40, cr = \"1\", xp = 200, saves = { Strength = 3, Dexterity = 1, Constitution = 1, Intelligence = -4, Wisdom = 1, Charisma = -1 }, attacks = {{ name = \"Rend\", hit = 5, dmg = \"1d8+3\", type = \"Slashing\" }}, pp = 15, pi = 11, stealth = 1, hab = {\"Grassland\", \"Hill\"}, ctypes = {\"Monstrosity\"}, pb = 2, conm = 1, ab = {17, 13, 13, 2, 12, 8}, fly = true, ko = \"히포그리프\", multi = \"The hippogriff makes two Rend attacks.\", what = \"Large Monstrosity\" },\r\n[\"Hobgoblin Warrior\"] = { ac = 18, hp = 11, init = 3, speed = 30, cr = \"1/2\", xp = 100, saves = { Strength = 1, Dexterity = 1, Constitution = 1, Intelligence = 0, Wisdom = 0, Charisma = -1 }, attacks = {{ name = \"Longsword\", hit = 3, dmg = \"2d10+1\", type = \"Slashing\" }, { name = \"Longbow\", hit = 3, dmg = \"1d8+1+3d4\", k = \"r\" }}, pp = 10, pi = 10, stealth = 1, hab = {\"Forest\", \"Grassland\", \"Hill\"}, ctypes = {\"Fey\", \"Goblinoid\"}, pb = 2, conm = 1, ab = {13, 12, 12, 10, 10, 9}, ko = \"홉고블린 전사\", what = \"Medium Fey (Goblinoid)\" },\r\n[\"Hobgoblin Captain\"] = { ac = 17, hp = 58, init = 4, speed = 30, cr = \"3\", xp = 700, saves = { Strength = 2, Dexterity = 2, Constitution = 2, Intelligence = 1, Wisdom = 0, Charisma = 1 }, attacks = {{ name = \"Greatsword\", hit = 4, dmg = \"2d6+2+1d6\" }, { name = \"Longbow\", hit = 4, dmg = \"1d8+2+2d4\", k = \"r\" }}, pp = 10, pi = 10, stealth = 2, hab = {\"Forest\", \"Grassland\", \"Hill\"}, ctypes = {\"Fey\", \"Goblinoid\"}, pb = 2, conm = 2, ab = {15, 14, 14, 12, 10, 13}, ko = \"홉고블린 대장\", multi = \"The hobgoblin makes two attacks, using Greatsword or Longbow in any combination.\", auto = {\"Aura of Authority. While in a 10-foot Emanation originating from the hobgoblin, the hobgoblin and its allies have Advantage on attack rolls and saving throws, provided the hobgoblin doesn't have the Incapacitated condition.\"}, what = \"Medium Fey (Goblinoid)\" },\r\n[\"Homunculus\"] = { ac = 13, hp = 4, init = 2, speed = 20, cr = \"0\", xp = 10, saves = { Strength = -3, Dexterity = 2, Constitution = 2, Intelligence = 0, Wisdom = 2, Charisma = 0 }, attacks = {{ name = \"Bite\", hit = 4, dmg = \"1\", type = \"Piercing\" }}, pp = 10, pi = 10, stealth = 2, imm = {\"Poison\"}, cimm = {\"Charmed\", \"Poisoned\"}, hab = {\"Ruins\", \"Urban\"}, ctypes = {\"Construct\"}, pb = 2, conm = 2, ab = {4, 15, 14, 10, 10, 7}, fly = true, ko = \"호문쿨루스\", what = \"Tiny Construct\" },\r\n[\"Horned Devil\"] = { ac = 18, hp = 199, init = 7, speed = 30, cr = \"11\", xp = 7200, saves = { Strength = 10, Dexterity = 7, Constitution = 5, Intelligence = 1, Wisdom = 7, Charisma = 8 }, attacks = {{ name = \"Searing Fork\", hit = 10, dmg = \"2d8+6+2d8\" }, { name = \"Hurl Flame\", hit = 8, dmg = \"5d8+4\", k = \"r\", type = \"Fire\" }}, pp = 13, pi = 13, stealth = 3, res = {\"Cold\"}, imm = {\"Fire\", \"Poison\"}, cimm = {\"Poisoned\"}, hab = {\"Planar\"}, ctypes = {\"Fiend\"}, pb = 4, conm = 5, ab = {22, 17, 21, 12, 16, 18}, unholy = true, fly = true, ko = \"뿔 악마\", sfx = {{ n = \"Infernal Tail\", s = \"Dexterity\", dc = 17, d = \"1d8+6\", t = \"Necrotic\" }}, mres = 1, multi = \"The devil makes three attacks, using Searing Fork or Hurl Flame in any combination. It can replace one attack with a use of Infernal Tail.\", what = \"Large Fiend (Devil)\" },\r\n[\"Hydra\"] = { ac = 15, hp = 184, init = 4, speed = 40, cr = \"8\", xp = 3900, saves = { Strength = 5, Dexterity = 1, Constitution = 5, Intelligence = -4, Wisdom = 0, Charisma = -2 }, attacks = {{ name = \"Bite\", hit = 8, dmg = \"1d10+5\", type = \"Piercing\" }}, pp = 16, pi = 10, stealth = 1, cimm = {\"Blinded\", \"Charmed\", \"Deafened\", \"Frightened\", \"Stunned\", \"Unconscious\"}, hab = {\"Swamp\"}, ctypes = {\"Monstrosity\"}, pb = 3, conm = 5, ab = {20, 12, 20, 2, 10, 7}, swim = true, ko = \"히드라\", multi = \"The hydra makes as many Bite attacks as it has heads.\", auto = {\"Multiple Heads. The hydra has five heads. Whenever the hydra takes 25 damage or more on a single turn, one of its heads dies. The hydra dies if all its heads are dead. At the end of each of its turns when it has at least one living head, the hydra grows two heads for each of its heads that died since its last turn, unless it has taken Fire damage since its last turn. The hydra regains 20 Hit Points when it grows new heads.\"}, what = \"Huge Monstrosity\" },\r\n[\"Ice Devil\"] = { ac = 18, hp = 228, init = 7, speed = 40, cr = \"14\", xp = 11500, saves = { Strength = 5, Dexterity = 7, Constitution = 9, Intelligence = 4, Wisdom = 7, Charisma = 9 }, attacks = {{ name = \"Ice Spear\", hit = 10, dmg = \"2d8+5+3d6\", k = \"b\" }, { name = \"Tail\", hit = 10, dmg = \"3d6+5+4d8\" }}, pp = 17, pi = 17, stealth = 2, imm = {\"Cold\", \"Fire\", \"Poison\"}, cimm = {\"Poisoned\"}, hab = {\"Planar\"}, ctypes = {\"Fiend\"}, pb = 5, conm = 4, ab = {21, 14, 18, 18, 15, 18}, unholy = true, ko = \"얼음 악마\", mres = 1, multi = \"The devil makes three Ice Spear attacks. It can replace one attack with a Tail attack.\", acts = \"Ice Wall (Recharge 6)\", what = \"Large Fiend (Devil)\" },\r\n[\"Imp\"] = { ac = 13, hp = 21, init = 3, speed = 20, cr = \"1\", xp = 200, saves = { Strength = -2, Dexterity = 3, Constitution = 1, Intelligence = 0, Wisdom = 1, Charisma = 2 }, attacks = {{ name = \"Sting\", hit = 5, dmg = \"1d6+3+2d6\" }}, pp = 11, pi = 13, stealth = 5, res = {\"Cold\"}, imm = {\"Fire\", \"Poison\"}, cimm = {\"Poisoned\"}, hab = {\"Planar\", \"Urban\"}, ctypes = {\"Fiend\"}, pb = 2, conm = 1, ab = {6, 17, 13, 11, 12, 14}, unholy = true, fly = true, ko = \"임프\", mres = 1, acts = \"Invisibility, Shape-Shift\", what = \"Tiny Fiend (Devil)\" },\r\n[\"Incubus\"] = { ac = 15, hp = 66, init = 3, speed = 30, cr = \"4\", xp = 1100, saves = { Strength = -1, Dexterity = 3, Constitution = 1, Intelligence = 2, Wisdom = 1, Charisma = 5 }, attacks = {{ name = \"Restless Touch\", hit = 7, dmg = \"3d6+5\", type = \"Psychic\" }}, pp = 15, pi = 15, stealth = 7, res = {\"Cold\", \"Fire\", \"Poison\", \"Psychic\"}, hab = {\"Planar\", \"Urban\"}, ctypes = {\"Fiend\"}, pb = 2, conm = 1, ab = {8, 17, 13, 15, 12, 20}, unholy = true, fly = true, ko = \"인큐버스\", sfx = {{ n = \"Nightmare\", s = \"Wisdom\", dc = 15, d = \"4d8\", t = \"Psychic\", o = \"Recharge 6\" }}, multi = \"The incubus makes two Restless Touch attacks.\", acts = \"Spellcasting\", what = \"Medium Fiend\" },\r\n[\"Invisible Stalker\"] = { ac = 14, hp = 97, init = 7, speed = 50, cr = \"6\", xp = 2300, saves = { Strength = 3, Dexterity = 4, Constitution = 2, Intelligence = 0, Wisdom = 2, Charisma = 0 }, attacks = {{ name = \"Wind Swipe\", hit = 7, dmg = \"2d6+4\", type = \"Force\" }}, pp = 18, pi = 12, stealth = 10, res = {\"Bludgeoning\", \"Piercing\", \"Slashing\"}, imm = {\"Poison\"}, cimm = {\"Exhaustion\", \"Grappled\", \"Paralyzed\", \"Petrified\", \"Poisoned\", \"Prone\", \"Restrained\", \"Unconscious\"}, hab = {\"Planar\"}, ctypes = {\"Elemental\"}, pb = 3, conm = 2, ab = {16, 19, 14, 10, 15, 11}, fly = true, ko = \"보이지 않는 추적자\", sfx = {{ n = \"Vortex\", s = \"Constitution\", dc = 14, d = \"1d8+3\", t = \"Thunder\" }, { n = \"Vortex (each turn)\", d = \"2d6\", t = \"Thunder\" }}, multi = \"The stalker makes three Wind Swipe attacks. It can replace one attack with a use of Vortex.\", what = \"Large Elemental\" },\r\n[\"Iron Golem\"] = { ac = 20, hp = 252, init = 9, speed = 30, cr = \"16\", xp = 15000, saves = { Strength = 7, Dexterity = -1, Constitution = 5, Intelligence = -4, Wisdom = 0, Charisma = -5 }, attacks = {{ name = \"Bladed Arm\", hit = 12, dmg = \"3d8+7+3d6\" }, { name = \"Fiery Bolt\", hit = 10, dmg = \"8d8\", k = \"r\", type = \"Fire\" }}, pp = 10, pi = 10, stealth = -1, imm = {\"Fire\", \"Poison\", \"Psychic\"}, cimm = {\"Charmed\", \"Exhaustion\", \"Frightened\", \"Paralyzed\", \"Petrified\", \"Poisoned\"}, hab = {\"Ruins\", \"Urban\"}, ctypes = {\"Construct\"}, pb = 5, conm = 5, ab = {24, 9, 20, 3, 11, 1}, ko = \"철 골렘\", sfx = {{ n = \"Poison Breath\", s = \"Constitution\", dc = 18, d = \"10d10\", t = \"Poison\", h = true, o = \"Recharge 6\" }}, mres = 1, absorb = { n = \"Fire Absorption\", t = \"Fire\" }, multi = \"The golem makes two attacks, using Bladed Arm or Fiery Bolt in any combination.\", what = \"Large Construct\" },\r\n[\"Knight\"] = { ac = 18, hp = 52, init = 0, speed = 30, cr = \"3\", xp = 700, saves = { Strength = 3, Dexterity = 0, Constitution = 4, Intelligence = 0, Wisdom = 2, Charisma = 2 }, attacks = {{ name = \"Greatsword\", hit = 5, dmg = \"2d6+3+1d8\" }, { name = \"Heavy Crossbow\", hit = 2, dmg = \"2d10+1d8\", k = \"r\" }}, pp = 10, pi = 10, stealth = 0, cimm = {\"Frightened\"}, hab = {\"Grassland\", \"Urban\"}, ctypes = {\"Pure Humanoid\"}, pb = 2, conm = 2, ab = {16, 11, 14, 11, 11, 15}, ko = \"기사\", react = { n = 2, name = \"Parry\", melee = true }, multi = \"The knight makes two attacks, using Greatsword or Heavy Crossbow in any combination.\", acts = \"Parry (Reaction)\", what = \"Medium or Small Humanoid\" },\r\n[\"Kobold Warrior\"] = { ac = 14, hp = 7, init = 2, speed = 30, cr = \"1/8\", xp = 25, saves = { Strength = -2, Dexterity = 2, Constitution = -1, Intelligence = -1, Wisdom = -2, Charisma = -1 }, attacks = {{ name = \"Dagger\", hit = 4, dmg = \"1d4+2\", k = \"b\", type = \"Piercing\" }}, pp = 8, pi = 8, stealth = 2, hab = {\"Hill\", \"Mountain\", \"Ruins\", \"Underdark\"}, ctypes = {\"Dragon\"}, pb = 2, conm = -1, ab = {7, 15, 9, 8, 7, 8}, ko = \"코볼트 전사\", what = \"Small Dragon\" },\r\n[\"Kraken\"] = { ac = 18, hp = 481, init = 14, speed = 30, cr = \"23\", xp = 50000, saves = { Strength = 17, Dexterity = 7, Constitution = 15, Intelligence = 6, Wisdom = 11, Charisma = 5 }, attacks = {{ name = \"Tentacle\", hit = 17, dmg = \"4d6+10\", type = \"Bludgeoning\" }}, pp = 21, pi = 14, stealth = 0, imm = {\"Cold\", \"Lightning\"}, cimm = {\"Frightened\", \"Grappled\", \"Paralyzed\", \"Restrained\"}, hab = {\"Coastal\", \"Underwater\"}, ctypes = {\"Monstrosity\"}, pb = 7, conm = 8, ab = {30, 11, 26, 22, 18, 20}, swim = true, ko = \"크라켄\", sfx = {{ n = \"Fling\", s = \"Dexterity\", dc = 25, d = \"4d8\", t = \"Bludgeoning\", h = true }, { n = \"Lightning Strike\", s = \"Dexterity\", dc = 23, d = \"6d10\", t = \"Lightning\", h = true }, { n = \"Swallow\", s = \"Dexterity\", dc = 25, d = \"3d8+10\", t = \"Piercing\" }, { n = \"Swallow (each turn)\", d = \"7d6\", t = \"Acid\" }, { n = \"Toxic Ink\", s = \"Constitution\", dc = 23, lg = true }}, lr = 4, la = 3, lacts = {\"Storm Bolt\", \"Toxic Ink\"}, multi = \"The kraken makes two Tentacle attacks and uses Fling, Lightning Strike, or Swallow.\", what = \"Gargantuan Monstrosity (Titan)\" },\r\n[\"Lamia\"] = { ac = 13, hp = 97, init = 1, speed = 40, cr = \"4\", xp = 1100, saves = { Strength = 3, Dexterity = 1, Constitution = 2, Intelligence = 2, Wisdom = 2, Charisma = 3 }, attacks = {{ name = \"Claw\", hit = 5, dmg = \"1d8+3+2d6\" }}, pp = 12, pi = 14, stealth = 5, hab = {\"Desert\"}, ctypes = {\"Fiend\"}, pb = 2, conm = 2, ab = {16, 13, 15, 14, 15, 16}, unholy = true, ko = \"라미아\", sfx = {{ n = \"Corrupting Touch\", s = \"Wisdom\", dc = 13, d = \"3d8\", t = \"Psychic\" }}, multi = \"The lamia makes two Claw attacks. It can replace one attack with a use of Corrupting Touch.\", acts = \"Spellcasting, Leap (Bonus Action)\", what = \"Large Fiend\" },\r\n[\"Lemure\"] = { ac = 9, hp = 9, init = -3, speed = 20, cr = \"0\", xp = 10, saves = { Strength = 0, Dexterity = -3, Constitution = 0, Intelligence = -5, Wisdom = 0, Charisma = -4 }, attacks = {{ name = \"Vile Slime\", hit = 2, dmg = \"1d4\", type = \"Poison\" }}, pp = 10, pi = 10, stealth = -3, res = {\"Cold\"}, imm = {\"Fire\", \"Poison\"}, cimm = {\"Charmed\", \"Frightened\", \"Poisoned\"}, hab = {\"Planar\"}, ctypes = {\"Fiend\"}, pb = 2, conm = 0, ab = {10, 5, 11, 1, 11, 3}, unholy = true, ko = \"레뮤어\", what = \"Medium Fiend (Devil)\" },\r\n[\"Lich\"] = { ac = 20, hp = 315, init = 17, speed = 30, cr = \"21\", xp = 33000, saves = { Strength = 0, Dexterity = 10, Constitution = 10, Intelligence = 12, Wisdom = 9, Charisma = 3 }, attacks = {{ name = \"Eldritch Burst\", hit = 12, dmg = \"4d12+5\", k = \"b\", type = \"Force\" }, { name = \"Paralyzing Touch\", hit = 12, dmg = \"3d6+5\", type = \"Cold\" }}, pp = 19, pi = 19, stealth = 3, res = {\"Cold\", \"Lightning\"}, imm = {\"Necrotic\", \"Poison\"}, cimm = {\"Charmed\", \"Exhaustion\", \"Frightened\", \"Paralyzed\", \"Poisoned\"}, hab = {\"Ruins\", \"Underdark\"}, ctypes = {\"Undead\"}, pb = 7, conm = 3, ab = {11, 16, 16, 21, 14, 16}, unholy = true, undead = true, ko = \"리치\", sfx = {{ n = \"Deathly Teleport\", d = \"2d10\", t = \"Necrotic\", lg = true }, { n = \"Disrupt Life\", s = \"Constitution\", dc = 20, d = \"9d6\", t = \"Necrotic\", h = true, lg = true }, { n = \"Fireball\", s = \"Dexterity\", dc = 20, d = \"10d6\", o = \"spell\", t = \"Fire\", h = true }, { n = \"Lightning Bolt\", s = \"Dexterity\", dc = 20, d = \"10d6\", o = \"spell\", t = \"Lightning\", h = true }, { n = \"Chain Lightning\", s = \"Dexterity\", dc = 20, d = \"10d8\", o = \"spell\", t = \"Lightning\", h = true }, { n = \"Finger of Death\", s = \"Constitution\", dc = 20, d = \"7d8+30\", o = \"spell\", t = \"Necrotic\", h = true }}, shield = { n = 5 }, lr = 4, la = 3, lacts = {\"Deathly Teleport\", \"Disrupt Life\", \"Frightening Gaze\"}, multi = \"The lich makes three attacks, using Eldritch Burst or Paralyzing Touch in any combination.\", acts = \"Spellcasting, Protective Magic (Reaction)\", what = \"Medium Undead (Wizard)\" },\r\n[\"Mage\"] = { ac = 15, hp = 81, init = 2, speed = 30, cr = \"6\", xp = 2300, saves = { Strength = -1, Dexterity = 2, Constitution = 0, Intelligence = 6, Wisdom = 4, Charisma = 0 }, attacks = {{ name = \"Arcane Burst\", hit = 6, dmg = \"3d8+3\", k = \"b\", type = \"Force\" }}, pp = 14, pi = 11, stealth = 2, hab = {\"Ruins\", \"Urban\"}, ctypes = {\"Pure Humanoid\"}, pb = 3, conm = 0, ab = {9, 14, 11, 17, 12, 11}, ko = \"마법사\", sfx = {{ n = \"Fireball\", s = \"Dexterity\", dc = 14, d = \"9d6\", o = \"spell\", t = \"Fire\", h = true }, { n = \"Cone of Cold\", s = \"Constitution\", dc = 14, d = \"8d8\", o = \"spell\", t = \"Cold\", h = true }}, shield = { n = 5, uses = 3 }, multi = \"The mage makes three Arcane Burst attacks.\", acts = \"Spellcasting, Misty Step (3/Day) (Bonus Action), Protective Magic (3/Day) (Reaction)\", what = \"Medium or Small Humanoid (Wizard)\" },\r\n[\"Archmage\"] = { ac = 17, hp = 170, init = 7, speed = 30, cr = \"12\", xp = 8000, saves = { Strength = 0, Dexterity = 2, Constitution = 1, Intelligence = 9, Wisdom = 6, Charisma = 3 }, attacks = {{ name = \"Arcane Burst\", hit = 9, dmg = \"4d10+5\", k = \"b\", type = \"Force\" }}, pp = 16, pi = 12, stealth = 2, imm = {\"Psychic\"}, cimm = {\"Charmed (with Mind Blank)\"}, hab = {\"Urban\"}, ctypes = {\"Pure Humanoid\"}, pb = 4, conm = 1, ab = {10, 14, 12, 20, 15, 16}, ko = \"대마법사\", sfx = {{ n = \"Lightning Bolt\", s = \"Dexterity\", dc = 17, d = \"12d6\", o = \"spell\", t = \"Lightning\", h = true }, { n = \"Cone of Cold\", s = \"Constitution\", dc = 17, d = \"12d8\", o = \"spell\", t = \"Cold\", h = true }}, mres = 1, shield = { n = 5, uses = 3 }, multi = \"The archmage makes four Arcane Burst attacks.\", acts = \"Spellcasting, Misty Step (3/Day) (Bonus Action), Protective Magic (3/Day) (Reaction)\", what = \"Medium or Small Humanoid (Wizard)\" },\r\n[\"Magmin\"] = { ac = 14, hp = 13, init = 2, speed = 30, cr = \"1/2\", xp = 100, saves = { Strength = -2, Dexterity = 2, Constitution = 1, Intelligence = -1, Wisdom = 0, Charisma = 0 }, attacks = {{ name = \"Touch\", hit = 4, dmg = \"2d4+2\", type = \"Fire\" }}, pp = 10, pi = 10, stealth = 2, imm = {\"Fire\"}, hab = {\"Mountain\", \"Planar\"}, ctypes = {\"Elemental\"}, pb = 2, conm = 1, ab = {7, 15, 12, 8, 11, 10}, ko = \"마그민\", sfx = {{ n = \"Death Burst\", s = \"Dexterity\", dc = 11, d = \"2d6\", t = \"Fire\", h = true }}, acts = \"Ignited Illumination (Bonus Action)\", auto = {\"Death Burst. The magmin explodes when it dies. Dexterity Saving Throw: DC 11, each creature in a 10-foot Emanation originating from the magmin. Failure: 7 (2d6) Fire damage. Success: Half damage.\"}, what = \"Small Elemental\" },\r\n[\"Manticore\"] = { ac = 14, hp = 68, init = 3, speed = 30, cr = \"3\", xp = 700, saves = { Strength = 3, Dexterity = 3, Constitution = 3, Intelligence = -2, Wisdom = 1, Charisma = -1 }, attacks = {{ name = \"Rend\", hit = 5, dmg = \"1d8+3\", type = \"Slashing\" }, { name = \"Tail Spike\", hit = 5, dmg = \"1d8+3\", k = \"r\", type = \"Piercing\" }}, pp = 11, pi = 11, stealth = 3, hab = {\"Hill\", \"Mountain\"}, ctypes = {\"Monstrosity\"}, pb = 2, conm = 3, ab = {17, 16, 17, 7, 12, 8}, fly = true, ko = \"맨티코어\", multi = \"The manticore makes three attacks, using Rend or Tail Spike in any combination.\", what = \"Large Monstrosity\" },\r\n[\"Marilith\"] = { ac = 16, hp = 220, init = 10, speed = 40, cr = \"16\", xp = 15000, saves = { Strength = 9, Dexterity = 5, Constitution = 10, Intelligence = 4, Wisdom = 8, Charisma = 10 }, attacks = {{ name = \"Pact Blade\", hit = 10, dmg = \"1d10+5+2d6\" }}, pp = 18, pi = 13, stealth = 5, res = {\"Cold\", \"Fire\", \"Lightning\"}, imm = {\"Poison\"}, cimm = {\"Poisoned\"}, hab = {\"Planar\"}, ctypes = {\"Fiend\"}, pb = 5, conm = 5, ab = {18, 20, 20, 18, 16, 20}, unholy = true, ko = \"마릴리스\", sfx = {{ n = \"Constrict\", s = \"Strength\", dc = 17, d = \"2d10+4\", t = \"Bludgeoning\" }}, mres = 1, react = { n = 5, name = \"Parry\", melee = true }, reactive = true, multi = \"The marilith makes six Pact Blade attacks and uses Constrict.\", acts = \"Teleport (Recharge 5–6) (Bonus Action), Parry (Reaction)\", what = \"Large Fiend (Demon)\" },\r\n[\"Medusa\"] = { ac = 15, hp = 127, init = 6, speed = 30, cr = \"6\", xp = 2300, saves = { Strength = 0, Dexterity = 3, Constitution = 3, Intelligence = 1, Wisdom = 4, Charisma = 2 }, attacks = {{ name = \"Claw\", hit = 6, dmg = \"2d6+3\", type = \"Slashing\" }, { name = \"Snake Hair\", hit = 6, dmg = \"1d4+3+4d6\" }, { name = \"Poison Ray\", hit = 5, dmg = \"2d8+2\", k = \"r\", type = \"Poison\" }}, pp = 14, pi = 11, stealth = 6, hab = {\"Ruins\", \"Underdark\"}, ctypes = {\"Monstrosity\"}, pb = 3, conm = 3, ab = {10, 17, 16, 12, 13, 15}, ko = \"메두사\", sfx = {{ n = \"Petrifying Gaze\", s = \"Constitution\", dc = 13, o = \"Recharge 5-6\" }}, multi = \"The medusa makes two Claw attacks and one Snake Hair attack, or it makes three Poison Ray attacks.\", what = \"Medium Monstrosity\" },\r\n[\"Dust Mephit\"] = { ac = 12, hp = 17, init = 2, speed = 30, cr = \"1/2\", xp = 100, saves = { Strength = -3, Dexterity = 2, Constitution = 0, Intelligence = -1, Wisdom = 0, Charisma = 0 }, attacks = {{ name = \"Claw\", hit = 4, dmg = \"1d4+2\", type = \"Slashing\" }}, pp = 12, pi = 10, stealth = 4, vul = {\"Fire\"}, imm = {\"Poison\"}, cimm = {\"Exhaustion\", \"Poisoned\"}, hab = {\"Desert\", \"Planar\"}, ctypes = {\"Elemental\"}, pb = 2, conm = 0, ab = {5, 14, 10, 9, 11, 10}, fly = true, ko = \"먼지 메피트\", sfx = {{ n = \"Death Burst\", s = \"Dexterity\", dc = 10, d = \"2d4\", t = \"Bludgeoning\", h = true }, { n = \"Blinding Breath\", s = \"Dexterity\", dc = 10, o = \"Recharge 6\" }}, acts = \"Sleep (1/Day)\", auto = {\"Death Burst. The mephit explodes when it dies. Dexterity Saving Throw: DC 10, each creature in a 5-foot Emanation originating from the mephit. Failure: 5 (2d4) Bludgeoning damage. Success: Half damage.\"}, what = \"Small Elemental\" },\r\n[\"Ice Mephit\"] = { ac = 11, hp = 21, init = 1, speed = 30, cr = \"1/2\", xp = 100, saves = { Strength = -2, Dexterity = 1, Constitution = 0, Intelligence = -1, Wisdom = 0, Charisma = 1 }, attacks = {{ name = \"Claw\", hit = 3, dmg = \"1d4+1+1d4\" }}, pp = 12, pi = 10, stealth = 3, vul = {\"Fire\"}, imm = {\"Cold\", \"Poison\"}, cimm = {\"Exhaustion\", \"Poisoned\"}, hab = {\"Arctic\", \"Planar\"}, ctypes = {\"Elemental\"}, pb = 2, conm = 0, ab = {7, 13, 10, 9, 11, 12}, fly = true, ko = \"얼음 메피트\", sfx = {{ n = \"Death Burst\", s = \"Constitution\", dc = 10, d = \"2d4\", t = \"Cold\", h = true }, { n = \"Frost Breath\", s = \"Constitution\", dc = 10, d = \"3d4\", t = \"Cold\", h = true, o = \"Recharge 6\" }}, acts = \"Fog Cloud (1/Day)\", auto = {\"Death Burst. The mephit explodes when it dies. Constitution Saving Throw: DC 10, each creature in a 5-foot Emanation originating from the mephit. Failure: 5 (2d4) Cold damage. Success: Half damage.\"}, what = \"Small Elemental\" },\r\n[\"Magma Mephit\"] = { ac = 11, hp = 18, init = 1, speed = 30, cr = \"1/2\", xp = 100, saves = { Strength = -1, Dexterity = 1, Constitution = 1, Intelligence = -2, Wisdom = 0, Charisma = 0 }, attacks = {{ name = \"Claw\", hit = 3, dmg = \"1d4+1+1d6\" }}, pp = 10, pi = 10, stealth = 3, vul = {\"Cold\"}, imm = {\"Fire\", \"Poison\"}, cimm = {\"Exhaustion\", \"Poisoned\"}, hab = {\"Mountain\", \"Planar\"}, ctypes = {\"Elemental\"}, pb = 2, conm = 1, ab = {8, 12, 12, 7, 10, 10}, fly = true, ko = \"마그마 메피트\", sfx = {{ n = \"Death Burst\", s = \"Dexterity\", dc = 11, d = \"2d6\", t = \"Fire\", h = true }, { n = \"Fire Breath\", s = \"Dexterity\", dc = 11, d = \"2d6\", t = \"Fire\", h = true, o = \"Recharge 6\" }}, auto = {\"Death Burst. The mephit explodes when it dies. Dexterity Saving Throw: DC 11, each creature in a 5-foot Emanation originating from the mephit. Failure: 7 (2d6) Fire damage. Success: Half damage.\"}, what = \"Small Elemental\" },\r\n[\"Steam Mephit\"] = { ac = 10, hp = 17, init = 0, speed = 30, cr = \"1/4\", xp = 50, saves = { Strength = -3, Dexterity = 0, Constitution = 0, Intelligence = 0, Wisdom = 0, Charisma = 1 }, attacks = {{ name = \"Claw\", hit = 2, dmg = \"1d4+1d4\" }}, pp = 10, pi = 10, stealth = 2, imm = {\"Fire\", \"Poison\"}, cimm = {\"Exhaustion\", \"Poisoned\"}, hab = {\"Coastal\", \"Planar\"}, ctypes = {\"Elemental\"}, pb = 2, conm = 0, ab = {5, 11, 10, 11, 10, 12}, fly = true, ko = \"증기 메피트\", sfx = {{ n = \"Death Burst\", s = \"Dexterity\", dc = 10, d = \"2d4\", t = \"Fire\", h = true }, { n = \"Steam Breath\", s = \"Constitution\", dc = 10, d = \"2d4\", t = \"Fire\", h = true, o = \"Recharge 6\" }}, auto = {\"Death Burst. The mephit explodes when it dies. Dexterity Saving Throw: DC 10, each creature in a 5-foot Emanation originating from the mephit. Failure: 5 (2d4) Fire damage. Success: Half damage.\"}, what = \"Small Elemental\" },\r\n[\"Merfolk Skirmisher\"] = { ac = 11, hp = 11, init = 1, speed = 10, cr = \"1/8\", xp = 25, saves = { Strength = 0, Dexterity = 1, Constitution = 1, Intelligence = 0, Wisdom = 2, Charisma = 1 }, attacks = {{ name = \"Ocean Spear\", hit = 2, dmg = \"1d6+1d4\", k = \"b\" }}, pp = 12, pi = 12, stealth = 1, hab = {\"Coastal\", \"Underwater\"}, ctypes = {\"Elemental\"}, pb = 2, conm = 1, ab = {10, 13, 12, 11, 14, 12}, swim = true, ko = \"인어 유격병\", what = \"Medium Elemental\" },\r\n[\"Merrow\"] = { ac = 13, hp = 45, init = 2, speed = 10, cr = \"2\", xp = 450, saves = { Strength = 4, Dexterity = 2, Constitution = 2, Intelligence = -1, Wisdom = 0, Charisma = -1 }, attacks = {{ name = \"Bite\", hit = 6, dmg = \"1d4+4\", type = \"Piercing\" }, { name = \"Claw\", hit = 6, dmg = \"2d4+4\", type = \"Slashing\" }, { name = \"Harpoon\", hit = 6, dmg = \"2d6+4\", k = \"b\", type = \"Piercing\" }}, pp = 10, pi = 10, stealth = 2, hab = {\"Coastal\", \"Underwater\"}, ctypes = {\"Monstrosity\"}, pb = 2, conm = 2, ab = {18, 15, 15, 8, 10, 9}, swim = true, ko = \"메로우\", multi = \"The merrow makes two attacks, using Bite, Claw, or Harpoon in any combination.\", what = \"Large Monstrosity\" },\r\n[\"Mimic\"] = { ac = 12, hp = 58, init = 3, speed = 20, cr = \"2\", xp = 450, saves = { Strength = 3, Dexterity = 1, Constitution = 2, Intelligence = -3, Wisdom = 1, Charisma = -1 }, attacks = {{ name = \"Bite\", hit = 5, dmg = \"1d8+3+1d8\", alt = \"2d8+3+1d8\", altwhy = \"if the target is Grappled by the mimic\" }, { name = \"Pseudopod\", hit = 5, dmg = \"1d8+3+1d8\" }}, pp = 11, pi = 11, stealth = 5, imm = {\"Acid\"}, cimm = {\"Prone\"}, hab = {\"Ruins\", \"Urban\"}, ctypes = {\"Monstrosity\"}, pb = 2, conm = 2, ab = {17, 12, 15, 5, 13, 8}, ko = \"미믹\", acts = \"Shape-Shift (Bonus Action)\", what = \"Medium Monstrosity\" },\r\n[\"Minotaur of Baphomet\"] = { ac = 14, hp = 85, init = 0, speed = 40, cr = \"3\", xp = 700, saves = { Strength = 4, Dexterity = 0, Constitution = 3, Intelligence = -2, Wisdom = 3, Charisma = -1 }, attacks = {{ name = \"Abyssal Glaive\", hit = 6, dmg = \"1d12+4+3d6\" }, { name = \"Gore (Recharge 5–6)\", hit = 6, dmg = \"4d6+4\", type = \"Piercing\" }}, pp = 17, pi = 13, stealth = 0, hab = {\"Ruins\", \"Underdark\"}, ctypes = {\"Monstrosity\"}, pb = 2, conm = 3, ab = {18, 11, 16, 6, 16, 9}, ko = \"바포메트의 미노타우로스\", acts = \"Gore (Recharge 5–6)\", what = \"Large Monstrosity\" },\r\n[\"Mummy\"] = { ac = 11, hp = 58, init = -1, speed = 20, cr = \"3\", xp = 700, saves = { Strength = 3, Dexterity = -1, Constitution = 2, Intelligence = -2, Wisdom = 3, Charisma = 1 }, attacks = {{ name = \"Rotting Fist\", hit = 5, dmg = \"1d10+3+3d6\" }}, pp = 11, pi = 11, stealth = -1, vul = {\"Fire\"}, imm = {\"Necrotic\", \"Poison\"}, cimm = {\"Charmed\", \"Exhaustion\", \"Frightened\", \"Paralyzed\", \"Poisoned\"}, hab = {\"Desert\", \"Ruins\", \"Underdark\"}, ctypes = {\"Undead\"}, pb = 2, conm = 2, ab = {16, 8, 15, 6, 12, 12}, unholy = true, undead = true, ko = \"미라\", sfx = {{ n = \"Dreadful Glare\", s = \"Wisdom\", dc = 11 }}, multi = \"The mummy makes two Rotting Fist attacks and uses Dreadful Glare.\", what = \"Medium or Small Undead\" },\r\n[\"Mummy Lord\"] = { ac = 17, hp = 187, init = 10, speed = 30, cr = \"15\", xp = 13000, saves = { Strength = 4, Dexterity = 0, Constitution = 3, Intelligence = 5, Wisdom = 9, Charisma = 3 }, attacks = {{ name = \"Rotting Fist\", hit = 9, dmg = \"2d10+4+3d6\" }, { name = \"Channel Negative Energy\", hit = 9, dmg = \"6d6+4\", k = \"r\", type = \"Necrotic\" }}, pp = 19, pi = 14, stealth = 0, vul = {\"Fire\"}, imm = {\"Necrotic\", \"Poison\"}, cimm = {\"Charmed\", \"Exhaustion\", \"Frightened\", \"Paralyzed\", \"Poisoned\"}, hab = {\"Desert\", \"Ruins\"}, ctypes = {\"Undead\"}, pb = 5, conm = 3, ab = {18, 10, 17, 11, 19, 16}, unholy = true, undead = true, ko = \"미라 군주\", sfx = {{ n = \"Dreadful Glare\", s = \"Wisdom\", dc = 17, d = \"6d6+4\", t = \"Psychic\" }, { n = \"Harm\", s = \"Constitution\", dc = 17, d = \"14d6\", o = \"spell\", t = \"Necrotic\", h = true }, { n = \"Insect Plague\", s = \"Constitution\", dc = 17, d = \"6d10\", o = \"spell\", t = \"Piercing\", h = true }}, mres = 1, react = { n = 2, name = \"Whirlwind of Sand\" }, lr = 3, la = 3, lacts = {\"Dread Command\", \"Glare\", \"Necrotic Strike\"}, multi = \"The mummy makes one Rotting Fist or Channel Negative Energy attack, and it uses Dreadful Glare.\", acts = \"Spellcasting, Whirlwind of Sand (Reaction)\", what = \"Medium or Small Undead (Cleric)\" },\r\n[\"Nalfeshnee\"] = { ac = 18, hp = 184, init = 5, speed = 20, cr = \"13\", xp = 10000, saves = { Strength = 5, Dexterity = 0, Constitution = 11, Intelligence = 9, Wisdom = 6, Charisma = 7 }, attacks = {{ name = \"Rend\", hit = 10, dmg = \"2d10+5+2d10\" }}, pp = 11, pi = 11, stealth = 0, res = {\"Cold\", \"Fire\", \"Lightning\"}, imm = {\"Poison\"}, cimm = {\"Frightened\", \"Poisoned\"}, hab = {\"Planar\"}, ctypes = {\"Fiend\"}, pb = 5, conm = 6, ab = {21, 10, 22, 19, 12, 15}, unholy = true, fly = true, ko = \"날페쉬니\", sfx = {{ n = \"Horror Nimbus\", s = \"Wisdom\", dc = 15, d = \"8d6\", t = \"Psychic\", o = \"Recharge 5-6\" }}, mres = 1, multi = \"The nalfeshnee makes three Rend attacks.\", acts = \"Teleport, Pursuit (Reaction)\", what = \"Large Fiend (Demon)\" },\r\n[\"Night Hag\"] = { ac = 17, hp = 112, init = 5, speed = 30, cr = \"5\", xp = 1800, saves = { Strength = 4, Dexterity = 2, Constitution = 3, Intelligence = 3, Wisdom = 2, Charisma = 3 }, attacks = {{ name = \"Claw\", hit = 7, dmg = \"2d8+4\", type = \"Slashing\" }}, pp = 15, pi = 15, stealth = 5, res = {\"Cold\", \"Fire\"}, cimm = {\"Charmed\"}, hab = {\"Forest\", \"Planar\", \"Swamp\"}, ctypes = {\"Fiend\"}, pb = 3, conm = 3, ab = {18, 15, 16, 16, 14, 16}, unholy = true, ko = \"밤 마귀할멈\", sfx = {{ n = \"Phantasmal Killer\", s = \"Wisdom\", dc = 14, d = \"4d10\", o = \"spell\", t = \"Psychic\", h = true }}, mres = 1, multi = \"The hag makes two Claw attacks.\", acts = \"Nightmare Haunting (1/Day; Requires Soul Bag), Spellcasting, Shape-Shift (Bonus Action)\", what = \"Medium Fiend\" },\r\n[\"Nightmare\"] = { ac = 13, hp = 68, init = 2, speed = 60, cr = \"3\", xp = 700, saves = { Strength = 4, Dexterity = 2, Constitution = 3, Intelligence = 0, Wisdom = 1, Charisma = 2 }, attacks = {{ name = \"Hooves\", hit = 6, dmg = \"2d8+4+3d6\" }}, pp = 11, pi = 11, stealth = 2, imm = {\"Fire\"}, hab = {\"Planar\"}, ctypes = {\"Fiend\"}, pb = 2, conm = 3, ab = {18, 15, 16, 10, 13, 15}, unholy = true, fly = true, ko = \"나이트메어\", acts = \"Ethereal Stride\", what = \"Large Fiend\" },\r\n[\"Noble\"] = { ac = 15, hp = 9, init = 1, speed = 30, cr = \"1/8\", xp = 25, saves = { Strength = 0, Dexterity = 1, Constitution = 0, Intelligence = 1, Wisdom = 2, Charisma = 3 }, attacks = {{ name = \"Rapier\", hit = 3, dmg = \"1d8+1\", type = \"Piercing\" }}, pp = 12, pi = 14, stealth = 1, hab = {\"Urban\"}, ctypes = {\"Pure Humanoid\"}, pb = 2, conm = 0, ab = {11, 12, 11, 12, 14, 16}, ko = \"귀족\", react = { n = 2, name = \"Parry\", melee = true }, acts = \"Parry (Reaction)\", what = \"Medium or Small Humanoid\" },\r\n[\"Ochre Jelly\"] = { ac = 8, hp = 52, init = -2, speed = 20, cr = \"2\", xp = 450, saves = { Strength = 2, Dexterity = -2, Constitution = 2, Intelligence = -4, Wisdom = -2, Charisma = -5 }, attacks = {{ name = \"Pseudopod\", hit = 4, dmg = \"3d6+2\", type = \"Acid\" }}, pp = 8, pi = 8, stealth = -2, res = {\"Acid\"}, imm = {\"Lightning\", \"Slashing\"}, cimm = {\"Charmed\", \"Deafened\", \"Exhaustion\", \"Frightened\", \"Grappled\", \"Prone\", \"Restrained\"}, hab = {\"Ruins\", \"Swamp\", \"Underdark\"}, ctypes = {\"Ooze\"}, pb = 2, conm = 2, ab = {15, 6, 14, 2, 6, 1}, ko = \"황토 젤리\", split = {\"Lightning\", \"Slashing\"}, acts = \"Split (Reaction)\", what = \"Large Ooze\" },\r\n[\"Ogre\"] = { ac = 11, hp = 68, init = -1, speed = 40, cr = \"2\", xp = 450, saves = { Strength = 4, Dexterity = -1, Constitution = 3, Intelligence = -3, Wisdom = -2, Charisma = -2 }, attacks = {{ name = \"Greatclub\", hit = 6, dmg = \"2d8+4\", type = \"Bludgeoning\" }, { name = \"Javelin\", hit = 6, dmg = \"2d6+4\", k = \"b\", type = \"Piercing\" }}, pp = 8, pi = 8, stealth = -1, hab = {\"Forest\", \"Hill\", \"Mountain\"}, ctypes = {\"Giant\"}, pb = 2, conm = 3, ab = {19, 8, 16, 5, 7, 7}, ko = \"오우거\", what = \"Large Giant\" },\r\n[\"Oni\"] = { ac = 17, hp = 119, init = 0, speed = 30, cr = \"7\", xp = 2900, saves = { Strength = 4, Dexterity = 3, Constitution = 6, Intelligence = 2, Wisdom = 4, Charisma = 5 }, attacks = {{ name = \"Claw\", hit = 7, dmg = \"1d12+4+2d8\" }, { name = \"Nightmare Ray\", hit = 5, dmg = \"2d6+2\", k = \"r\", type = \"Psychic\" }}, pp = 14, pi = 11, stealth = 0, res = {\"Cold\"}, hab = {\"Planar\", \"Urban\"}, ctypes = {\"Fiend\"}, pb = 3, conm = 3, ab = {19, 11, 16, 14, 12, 15}, unholy = true, fly = true, ko = \"오니\", regen = { n = \"Regeneration\", d = \"10\", one = true }, multi = \"The oni makes two Claw or Nightmare Ray attacks. It can replace one attack with a use of Spellcasting.\", acts = \"Shape-Shift, Spellcasting, Invisibility (Bonus Action)\", auto = {\"Regeneration. The oni regains 10 Hit Points at the start of each of its turns if it has at least 1 Hit Point.\"}, what = \"Large Fiend\" },\r\n[\"Otyugh\"] = { ac = 14, hp = 104, init = 0, speed = 30, cr = \"5\", xp = 1800, saves = { Strength = 3, Dexterity = 0, Constitution = 7, Intelligence = -2, Wisdom = 1, Charisma = -2 }, attacks = {{ name = \"Bite\", hit = 6, dmg = \"2d8+3\", type = \"Piercing\" }, { name = \"Tentacle\", hit = 6, dmg = \"2d8+3\", type = \"Piercing\" }}, pp = 11, pi = 11, stealth = 0, hab = {\"Ruins\", \"Swamp\", \"Underdark\", \"Urban\"}, ctypes = {\"Aberration\"}, pb = 3, conm = 4, ab = {16, 11, 19, 6, 13, 6}, ko = \"오티유\", sfx = {{ n = \"Tentacle Slam\", s = \"Constitution\", dc = 14, d = \"3d8+3\", t = \"Bludgeoning\", h = true }}, multi = \"The otyugh makes one Bite attack and two Tentacle attacks.\", what = \"Large Aberration\" },\r\n[\"Owlbear\"] = { ac = 13, hp = 59, init = 1, speed = 40, cr = \"3\", xp = 700, saves = { Strength = 5, Dexterity = 1, Constitution = 3, Intelligence = -4, Wisdom = 1, Charisma = -2 }, attacks = {{ name = \"Rend\", hit = 7, dmg = \"2d8+5\", type = \"Slashing\" }}, pp = 15, pi = 11, stealth = 1, hab = {\"Forest\"}, ctypes = {\"Monstrosity\"}, pb = 2, conm = 3, ab = {20, 12, 17, 3, 12, 7}, ko = \"아울베어\", multi = \"The owlbear makes two Rend attacks.\", what = \"Large Monstrosity\" },\r\n[\"Pegasus\"] = { ac = 12, hp = 59, init = 2, speed = 60, cr = \"2\", xp = 450, saves = { Strength = 4, Dexterity = 4, Constitution = 5, Intelligence = 0, Wisdom = 4, Charisma = 3 }, attacks = {{ name = \"Hooves\", hit = 6, dmg = \"1d6+4+2d4\" }}, pp = 16, pi = 12, stealth = 2, hab = {\"Grassland\", \"Planar\"}, ctypes = {\"Celestial\"}, pb = 2, conm = 3, ab = {18, 15, 16, 10, 15, 13}, fly = true, ko = \"페가수스\", what = \"Large Celestial\" },\r\n[\"Phase Spider\"] = { ac = 14, hp = 45, init = 3, speed = 30, cr = \"3\", xp = 700, saves = { Strength = 2, Dexterity = 3, Constitution = 1, Intelligence = -2, Wisdom = 0, Charisma = -2 }, attacks = {{ name = \"Bite\", hit = 5, dmg = \"1d10+3+2d8\" }}, pp = 10, pi = 10, stealth = 7, hab = {\"Forest\", \"Planar\", \"Underdark\"}, ctypes = {\"Monstrosity\"}, pb = 2, conm = 1, ab = {15, 16, 12, 6, 10, 6}, ko = \"위상 거미\", multi = \"The spider makes two Bite attacks.\", acts = \"Ethereal Jaunt (Bonus Action)\", what = \"Large Monstrosity\" },\r\n[\"Pirate\"] = { ac = 14, hp = 33, init = 5, speed = 30, cr = \"1\", xp = 200, saves = { Strength = 0, Dexterity = 5, Constitution = 1, Intelligence = -1, Wisdom = 1, Charisma = 4 }, attacks = {{ name = \"Dagger\", hit = 5, dmg = \"1d4+3\", k = \"b\", type = \"Piercing\" }}, pp = 11, pi = 11, stealth = 3, hab = {\"Coastal\", \"Urban\"}, ctypes = {\"Pure Humanoid\"}, pb = 2, conm = 1, ab = {10, 16, 12, 8, 12, 14}, ko = \"해적\", sfx = {{ n = \"Enthralling Panache\", s = \"Wisdom\", dc = 12 }}, multi = \"The pirate makes two Dagger attacks. It can replace one attack with a use of Enthralling Panache.\", what = \"Medium or Small Humanoid\" },\r\n[\"Pirate Captain\"] = { ac = 17, hp = 84, init = 7, speed = 30, cr = \"6\", xp = 2300, saves = { Strength = 3, Dexterity = 7, Constitution = 2, Intelligence = 0, Wisdom = 5, Charisma = 6 }, attacks = {{ name = \"Rapier\", hit = 7, dmg = \"2d8+4\", type = \"Piercing\" }, { name = \"Pistol\", hit = 7, dmg = \"2d10+4\", k = \"r\", type = \"Piercing\" }}, pp = 15, pi = 12, stealth = 4, hab = {\"Coastal\", \"Urban\"}, ctypes = {\"Pure Humanoid\"}, pb = 3, conm = 2, ab = {10, 18, 14, 10, 14, 17}, ko = \"해적 선장\", sfx = {{ n = \"Captain's Charm\", s = \"Wisdom\", dc = 14 }}, react = { n = 3, name = \"Riposte\", melee = true, back = true }, multi = \"The pirate makes three attacks, using Rapier or Pistol in any combination.\", acts = \"Riposte (Reaction)\", what = \"Medium or Small Humanoid\" },\r\n[\"Pit Fiend\"] = { ac = 21, hp = 337, init = 14, speed = 30, cr = \"20\", xp = 25000, saves = { Strength = 8, Dexterity = 8, Constitution = 7, Intelligence = 6, Wisdom = 10, Charisma = 7 }, attacks = {{ name = \"Bite\", hit = 14, dmg = \"3d6+8\", type = \"Piercing\" }, { name = \"Devilish Claw\", hit = 14, dmg = \"4d8+8\", type = \"Necrotic\" }, { name = \"Fiery Mace\", hit = 14, dmg = \"4d6+8+6d6\" }}, pp = 20, pi = 14, stealth = 2, res = {\"Cold\"}, imm = {\"Fire\", \"Poison\"}, cimm = {\"Poisoned\"}, hab = {\"Planar\"}, ctypes = {\"Fiend\"}, pb = 6, conm = 7, ab = {26, 14, 24, 22, 18, 24}, unholy = true, fly = true, ko = \"구덩이 마귀\", sfx = {{ n = \"Fear Aura\", s = \"Wisdom\", dc = 21 }}, mres = 1, lr = 4, multi = \"The pit fiend makes one Bite attack, two Devilish Claw attacks, and one Fiery Mace attack.\", acts = \"Hellfire Spellcasting (Recharge 4–6)\", auto = {\"Fear Aura. The pit fiend emanates an aura in a 20foot Emanation while it doesn't have the Incapacitated condition. Wisdom Saving Throw: DC 21, any enemy that starts its turn in the aura. Failure: The target has the Frightened condition until the start of its next turn. Success: The target is immune to this pit fiend's aura for 24 hours.\"}, what = \"Large Fiend (Devil)\" },\r\n[\"Planetar\"] = { ac = 19, hp = 262, init = 10, speed = 40, cr = \"16\", xp = 15000, saves = { Strength = 12, Dexterity = 5, Constitution = 12, Intelligence = 4, Wisdom = 11, Charisma = 12 }, attacks = {{ name = \"Radiant Sword\", hit = 12, dmg = \"2d6+7+4d8\" }}, pp = 21, pi = 16, stealth = 5, res = {\"Radiant\"}, cimm = {\"Charmed\", \"Exhaustion\", \"Frightened\"}, hab = {\"Planar\"}, ctypes = {\"Celestial\"}, pb = 5, conm = 7, ab = {24, 20, 24, 19, 22, 25}, fly = true, ko = \"플라네타\", sfx = {{ n = \"Holy Burst\", s = \"Dexterity\", dc = 20, d = \"7d6\", t = \"Radiant\", h = true }}, mres = 1, multi = \"The planetar makes three Radiant Sword attacks or uses Holy Burst twice.\", acts = \"Spellcasting, Divine Aid (2/Day) (Bonus Action)\", what = \"Large Celestial (Angel)\" },\r\n[\"Priest Acolyte\"] = { ac = 13, hp = 11, init = 0, speed = 30, cr = \"1/4\", xp = 50, saves = { Strength = 2, Dexterity = 0, Constitution = 1, Intelligence = 0, Wisdom = 2, Charisma = 0 }, attacks = {{ name = \"Mace\", hit = 4, dmg = \"1d6+2+1d4\" }, { name = \"Radiant Flame\", hit = 4, dmg = \"2d6\", k = \"r\", type = \"Radiant\" }}, pp = 12, pi = 12, stealth = 0, hab = {\"Urban\"}, ctypes = {\"Pure Humanoid\"}, pb = 2, conm = 1, ab = {14, 10, 12, 10, 14, 11}, ko = \"견습 사제\", acts = \"Spellcasting, Divine Aid (1/Day) (Bonus Action)\", what = \"Medium or Small Humanoid (Cleric)\" },\r\n[\"Priest\"] = { ac = 13, hp = 38, init = 0, speed = 30, cr = \"2\", xp = 450, saves = { Strength = 3, Dexterity = 0, Constitution = 1, Intelligence = 1, Wisdom = 3, Charisma = 1 }, attacks = {{ name = \"Mace\", hit = 5, dmg = \"1d6+3+2d4\" }, { name = \"Radiant Flame\", hit = 5, dmg = \"2d10\", k = \"r\", type = \"Radiant\" }}, pp = 15, pi = 13, stealth = 0, hab = {\"Urban\"}, ctypes = {\"Pure Humanoid\"}, pb = 2, conm = 1, ab = {16, 10, 12, 13, 16, 13}, ko = \"사제\", sfx = {{ n = \"Spirit Guardians\", s = \"Wisdom\", dc = 13, d = \"3d8\", o = \"spell\", t = \"Radiant (Necrotic if evil)\", h = true }}, multi = \"The priest makes two attacks, using Mace or Radiant Flame in any combination.\", acts = \"Spellcasting, Divine Aid (3/Day) (Bonus Action)\", what = \"Medium or Small Humanoid (Cleric)\" },\r\n[\"Pseudodragon\"] = { ac = 14, hp = 10, init = 2, speed = 15, cr = \"1/4\", xp = 50, saves = { Strength = -2, Dexterity = 2, Constitution = 1, Intelligence = 0, Wisdom = 1, Charisma = 0 }, attacks = {{ name = \"Bite\", hit = 4, dmg = \"1d4+2\", type = \"Piercing\" }}, pp = 15, pi = 11, stealth = 4, hab = {\"Forest\"}, ctypes = {\"Dragon\"}, pb = 2, conm = 1, ab = {6, 15, 13, 10, 12, 10}, fly = true, ko = \"슈도드래곤\", sfx = {{ n = \"Sting\", s = \"Constitution\", dc = 12, d = \"2d4\", t = \"Poison\" }}, mres = 1, multi = \"The pseudodragon makes two Bite attacks.\", what = \"Tiny Dragon\" },\r\n[\"Purple Worm\"] = { ac = 18, hp = 247, init = 3, speed = 50, cr = \"15\", xp = 13000, saves = { Strength = 9, Dexterity = -2, Constitution = 11, Intelligence = -5, Wisdom = 4, Charisma = -3 }, attacks = {{ name = \"Bite\", hit = 14, dmg = \"3d8+9\", type = \"Piercing\" }, { name = \"Tail Stinger\", hit = 14, dmg = \"2d6+9+10d6\" }}, pp = 9, pi = 9, stealth = -2, hab = {\"Desert\", \"Underdark\"}, ctypes = {\"Monstrosity\"}, pb = 5, conm = 6, ab = {28, 7, 22, 1, 8, 4}, ko = \"보라 벌레\", sfx = {{ n = \"Swallow\", s = \"Strength\", dc = 19 }, { n = \"Swallow (each turn)\", d = \"5d6\", t = \"Acid\" }}, multi = \"The worm makes one Bite attack and one Tail Stinger attack.\", what = \"Gargantuan Monstrosity\" },\r\n[\"Quasit\"] = { ac = 13, hp = 25, init = 3, speed = 40, cr = \"1\", xp = 200, saves = { Strength = -3, Dexterity = 3, Constitution = 0, Intelligence = -2, Wisdom = 0, Charisma = 0 }, attacks = {{ name = \"Rend\", hit = 5, dmg = \"1d4+3\", type = \"Slashing\" }}, pp = 10, pi = 10, stealth = 5, res = {\"Cold\", \"Fire\", \"Lightning\"}, imm = {\"Poison\"}, cimm = {\"Poisoned\"}, hab = {\"Planar\", \"Urban\"}, ctypes = {\"Fiend\"}, pb = 2, conm = 0, ab = {5, 17, 10, 7, 10, 10}, unholy = true, ko = \"콰짓\", sfx = {{ n = \"Scare\", s = \"Wisdom\", dc = 10, o = \"1/Day\" }}, mres = 1, acts = \"Invisibility, Shape-Shift\", what = \"Tiny Fiend (Demon)\" },\r\n[\"Rakshasa\"] = { ac = 17, hp = 221, init = 8, speed = 40, cr = \"13\", xp = 10000, saves = { Strength = 2, Dexterity = 3, Constitution = 4, Intelligence = 1, Wisdom = 3, Charisma = 5 }, attacks = {{ name = \"Cursed Touch\", hit = 10, dmg = \"2d6+5+3d12\" }}, pp = 18, pi = 18, stealth = 3, cimm = {\"Charmed\", \"Frightened\"}, hab = {\"Urban\"}, ctypes = {\"Fiend\"}, pb = 5, conm = 4, ab = {14, 17, 18, 13, 16, 20}, unholy = true, ko = \"락샤사\", sfx = {{ n = \"Baleful Command\", s = \"Wisdom\", dc = 18, d = \"8d6\", t = \"Psychic\", o = \"Recharge 5-6\" }}, mres = 2, vulbless = {\"Piercing\"}, multi = \"The rakshasa makes three Cursed Touch attacks.\", acts = \"Spellcasting\", what = \"Medium Fiend\" },\r\n[\"Red Dragon Wyrmling\"] = { ac = 17, hp = 75, init = 2, speed = 30, cr = \"4\", xp = 1100, saves = { Strength = 4, Dexterity = 2, Constitution = 3, Intelligence = 1, Wisdom = 2, Charisma = 2 }, attacks = {{ name = \"Rend\", hit = 6, dmg = \"1d10+4+1d6\" }}, pp = 14, pi = 10, stealth = 2, imm = {\"Fire\"}, hab = {\"Hill\", \"Mountain\"}, ctypes = {\"Dragon\"}, pb = 2, conm = 3, ab = {19, 10, 17, 12, 11, 15}, fly = true, ko = \"새끼 적룡\", sfx = {{ n = \"Fire Breath\", s = \"Dexterity\", dc = 13, d = \"7d6\", t = \"Fire\", h = true, o = \"Recharge 5-6\" }}, multi = \"The dragon makes two Rend attacks.\", what = \"Medium Dragon (Chromatic)\" },\r\n[\"Young Red Dragon\"] = { ac = 18, hp = 178, init = 4, speed = 40, cr = \"10\", xp = 5900, saves = { Strength = 6, Dexterity = 4, Constitution = 5, Intelligence = 2, Wisdom = 4, Charisma = 4 }, attacks = {{ name = \"Rend\", hit = 10, dmg = \"2d6+6+1d6\" }}, pp = 18, pi = 10, stealth = 4, imm = {\"Fire\"}, hab = {\"Mountain\", \"Hill\"}, ctypes = {\"Dragon\"}, pb = 4, conm = 5, ab = {23, 10, 21, 14, 11, 19}, fly = true, ko = \"젊은 적룡\", sfx = {{ n = \"Fire Breath\", s = \"Dexterity\", dc = 17, d = \"16d6\", t = \"Fire\", h = true, o = \"Recharge 5-6\" }}, multi = \"The dragon makes three Rend attacks.\", what = \"Large Dragon (Chromatic)\" },\r\n[\"Adult Red Dragon\"] = { ac = 19, hp = 256, init = 12, speed = 40, cr = \"17\", xp = 18000, saves = { Strength = 8, Dexterity = 6, Constitution = 7, Intelligence = 3, Wisdom = 7, Charisma = 6 }, attacks = {{ name = \"Rend\", hit = 14, dmg = \"1d10+8+2d4\" }, { name = \"Scorching Ray (spell)\", hit = 12, dmg = \"2d6\", type = \"Fire\", srange = \"ranged\" }}, pp = 23, pi = 11, stealth = 6, imm = {\"Fire\"}, hab = {\"Hill\", \"Mountain\"}, ctypes = {\"Dragon\"}, pb = 6, conm = 7, ab = {27, 10, 25, 16, 13, 23}, fly = true, ko = \"성체 적룡\", sfx = {{ n = \"Fire Breath\", s = \"Dexterity\", dc = 21, d = \"17d6\", t = \"Fire\", h = true, o = \"Recharge 5-6\" }, { n = \"Fireball\", s = \"Dexterity\", dc = 20, d = \"8d6\", o = \"spell\", t = \"Fire\", h = true }}, lr = 3, la = 3, lacts = {\"Commanding Presence\", \"Fiery Rays\", \"Pounce\"}, multi = \"The dragon makes three Rend attacks. It can replace one attack with a use of Spellcasting to cast Scorching Ray.\", acts = \"Spellcasting\", what = \"Huge Dragon (Chromatic)\" },\r\n[\"Ancient Red Dragon\"] = { ac = 22, hp = 507, init = 14, speed = 40, cr = \"24\", xp = 62000, saves = { Strength = 10, Dexterity = 7, Constitution = 9, Intelligence = 4, Wisdom = 9, Charisma = 8 }, attacks = {{ name = \"Rend\", hit = 17, dmg = \"2d8+10+3d6\" }, { name = \"Scorching Ray (spell)\", hit = 15, dmg = \"2d6\", type = \"Fire\", srange = \"ranged\" }}, pp = 26, pi = 12, stealth = 7, imm = {\"Fire\"}, hab = {\"Hill\", \"Mountain\"}, ctypes = {\"Dragon\"}, pb = 7, conm = 9, ab = {30, 10, 29, 18, 15, 27}, fly = true, ko = \"고룡 적룡\", sfx = {{ n = \"Fire Breath\", s = \"Dexterity\", dc = 24, d = \"26d6\", t = \"Fire\", h = true, o = \"Recharge 5-6\" }, { n = \"Fireball\", s = \"Dexterity\", dc = 23, d = \"11d6\", o = \"spell\", t = \"Fire\", h = true }}, lr = 4, la = 3, lacts = {\"Commanding Presence\", \"Fiery Rays\", \"Pounce\"}, multi = \"The dragon makes three Rend attacks. It can replace one attack with a use of Spellcasting to cast Scorching Ray (level 3 version).\", acts = \"Spellcasting\", what = \"Gargantuan Dragon (Chromatic)\" },\r\n[\"Remorhaz\"] = { ac = 17, hp = 195, init = 5, speed = 40, cr = \"11\", xp = 7200, saves = { Strength = 7, Dexterity = 1, Constitution = 5, Intelligence = -3, Wisdom = 0, Charisma = -3 }, attacks = {{ name = \"Bite\", hit = 11, dmg = \"2d10+7+4d6\" }}, pp = 10, pi = 10, stealth = 1, imm = {\"Cold\", \"Fire\"}, hab = {\"Arctic\"}, ctypes = {\"Monstrosity\"}, pb = 4, conm = 5, ab = {24, 13, 21, 4, 10, 5}, ko = \"레모라즈\", sfx = {{ n = \"Heat Aura\", d = \"3d10\", t = \"Fire\" }, { n = \"Swallow\", s = \"Strength\", dc = 19 }, { n = \"Swallow (each turn)\", d = \"3d6+3d6\", t = \"Acid and Fire\" }}, auto = {\"Heat Aura. At the end of each of the remorhaz's turns, each creature in a 5-foot Emanation originating from the remorhaz takes 16 (3d10) Fire damage.\"}, what = \"Huge Monstrosity\" },\r\n[\"Roc\"] = { ac = 15, hp = 248, init = 8, speed = 20, cr = \"11\", xp = 7200, saves = { Strength = 9, Dexterity = 4, Constitution = 5, Intelligence = -4, Wisdom = 4, Charisma = -1 }, attacks = {{ name = \"Beak\", hit = 13, dmg = \"3d12+9\", type = \"Piercing\" }, { name = \"Talons\", hit = 13, dmg = \"4d6+9\", type = \"Slashing\" }}, pp = 18, pi = 10, stealth = 0, hab = {\"Coastal\", \"Mountain\"}, ctypes = {\"Monstrosity\"}, pb = 4, conm = 5, ab = {28, 10, 20, 3, 10, 9}, fly = true, ko = \"로크\", multi = \"The roc makes two Beak attacks. It can replace one attack with a Talons attack.\", acts = \"Swoop (Recharge 5–6) (Bonus Action)\", what = \"Gargantuan Monstrosity\" },\r\n[\"Roper\"] = { ac = 20, hp = 93, init = 5, speed = 10, cr = \"5\", xp = 1800, saves = { Strength = 4, Dexterity = -1, Constitution = 3, Intelligence = -2, Wisdom = 3, Charisma = -2 }, attacks = {{ name = \"Bite\", hit = 7, dmg = \"3d8+4\", type = \"Piercing\" }}, pp = 16, pi = 13, stealth = 5, hab = {\"Underdark\"}, ctypes = {\"Aberration\"}, pb = 3, conm = 3, ab = {18, 8, 17, 7, 16, 6}, ko = \"로퍼\", multi = \"The roper makes two Tentacle attacks, uses Reel, and makes two Bite attacks.\", acts = \"Tentacle, Reel\", what = \"Large Aberration\" },\r\n[\"Rust Monster\"] = { ac = 14, hp = 33, init = 1, speed = 40, cr = \"1/2\", xp = 100, saves = { Strength = 1, Dexterity = 1, Constitution = 1, Intelligence = -4, Wisdom = 1, Charisma = -2 }, attacks = {{ name = \"Bite\", hit = 3, dmg = \"1d8+1\", type = \"Piercing\" }}, pp = 11, pi = 11, stealth = 1, hab = {\"Ruins\", \"Underdark\"}, ctypes = {\"Monstrosity\"}, pb = 2, conm = 1, ab = {13, 12, 13, 2, 13, 6}, ko = \"녹 괴물\", wear = true, sfx = {{ n = \"Antennae\", s = \"Dexterity\", dc = 11 }}, multi = \"The rust monster makes one Bite attack and uses Antennae twice.\", acts = \"Destroy Metal, Reflexive Antennae (Reaction)\", what = \"Medium Monstrosity\" },\r\n[\"Sahuagin Warrior\"] = { ac = 12, hp = 22, init = 0, speed = 30, cr = \"1/2\", xp = 100, saves = { Strength = 1, Dexterity = 0, Constitution = 1, Intelligence = 1, Wisdom = 1, Charisma = -1 }, attacks = {{ name = \"Claw\", hit = 3, dmg = \"1d6+1\", type = \"Slashing\" }}, pp = 15, pi = 11, stealth = 0, res = {\"Acid\", \"Cold\"}, hab = {\"Coastal\", \"Underwater\"}, ctypes = {\"Fiend\"}, pb = 2, conm = 1, ab = {13, 11, 12, 12, 13, 9}, unholy = true, swim = true, ko = \"사후아긴 전사\", multi = \"The sahuagin makes two Claw attacks.\", acts = \"Aquatic Charge (Bonus Action)\", what = \"Medium Fiend\" },\r\n[\"Salamander\"] = { ac = 15, hp = 90, init = 2, speed = 30, cr = \"5\", xp = 1800, saves = { Strength = 4, Dexterity = 2, Constitution = 2, Intelligence = 0, Wisdom = 0, Charisma = 1 }, attacks = {{ name = \"Flame Spear\", hit = 7, dmg = \"2d8+4+2d6\", k = \"b\" }}, pp = 10, pi = 10, stealth = 2, vul = {\"Cold\"}, imm = {\"Fire\"}, hab = {\"Mountain\", \"Planar\"}, ctypes = {\"Elemental\"}, pb = 3, conm = 2, ab = {18, 14, 15, 11, 10, 12}, ko = \"샐러맨더\", sfx = {{ n = \"Fire Aura\", d = \"2d6\", t = \"Fire\" }, { n = \"Constrict\", s = \"Strength\", dc = 15, d = \"2d6+4+2d6\", t = \"Bludgeoning and Fire\" }}, multi = \"The salamander makes two Flame Spear attacks. It can replace one attack with a use of Constrict.\", auto = {\"Fire Aura. At the end of each of the salamander's turns, each creature of the salamander's choice in a 5-foot Emanation originating from the salamander takes 7 (2d6) Fire damage.\"}, what = \"Large Elemental\" },\r\n[\"Satyr\"] = { ac = 13, hp = 31, init = 3, speed = 40, cr = \"1/2\", xp = 100, saves = { Strength = 1, Dexterity = 3, Constitution = 0, Intelligence = 1, Wisdom = 0, Charisma = 2 }, attacks = {{ name = \"Hooves\", hit = 5, dmg = \"1d4+3\", type = \"Bludgeoning\" }}, pp = 12, pi = 10, stealth = 5, hab = {\"Forest\"}, ctypes = {\"Fey\"}, pb = 2, conm = 0, ab = {12, 16, 11, 12, 10, 14}, ko = \"사티로스\", sfx = {{ n = \"Mockery\", s = \"Wisdom\", dc = 12, d = \"1d6+2\", t = \"Psychic\" }}, mres = 1, what = \"Medium Fey\" },\r\n[\"Scout\"] = { ac = 13, hp = 16, init = 2, speed = 30, cr = \"1/2\", xp = 100, saves = { Strength = 0, Dexterity = 2, Constitution = 1, Intelligence = 0, Wisdom = 1, Charisma = 0 }, attacks = {{ name = \"Shortsword\", hit = 4, dmg = \"1d6+2\", type = \"Piercing\" }, { name = \"Longbow\", hit = 4, dmg = \"1d8+2\", k = \"r\", type = \"Piercing\" }}, pp = 15, pi = 11, stealth = 6, hab = {\"Forest\", \"Grassland\"}, ctypes = {\"Pure Humanoid\"}, pb = 2, conm = 1, ab = {11, 14, 12, 11, 13, 11}, ko = \"척후병\", multi = \"The scout makes two attacks, using Shortsword and Longbow in any combination.\", what = \"Medium or Small Humanoid\" },\r\n[\"Sea Hag\"] = { ac = 14, hp = 52, init = 1, speed = 30, cr = \"2\", xp = 450, saves = { Strength = 3, Dexterity = 1, Constitution = 3, Intelligence = 1, Wisdom = 1, Charisma = 1 }, attacks = {{ name = \"Claw\", hit = 5, dmg = \"2d6+3\", type = \"Slashing\" }}, pp = 11, pi = 11, stealth = 1, hab = {\"Coastal\", \"Swamp\", \"Underwater\"}, ctypes = {\"Fey\"}, pb = 2, conm = 3, ab = {16, 13, 16, 12, 12, 13}, swim = true, ko = \"바다 마귀할멈\", sfx = {{ n = \"Vile Appearance\", s = \"Wisdom\", dc = 11 }, { n = \"Death Glare\", s = \"Wisdom\", dc = 11, d = \"3d8\", t = \"Psychic\", o = \"Recharge 5-6\" }}, acts = \"Illusory Appearance\", auto = {\"Vile Appearance. Wisdom Saving Throw: DC 11, any Beast or Humanoid that starts its turn within 30 feet of the hag and can see the hag's true form. Failure: The target has the Frightened condition until the start of its next turn. Success: The target is immune to this hag's Vile Appearance for 24 hours.\"}, what = \"Medium Fey\" },\r\n[\"Shadow\"] = { ac = 12, hp = 27, init = 2, speed = 40, cr = \"1/2\", xp = 100, saves = { Strength = -2, Dexterity = 2, Constitution = 1, Intelligence = -2, Wisdom = 0, Charisma = -1 }, attacks = {{ name = \"Draining Swipe\", hit = 4, dmg = \"1d6+2\", type = \"Necrotic\" }}, pp = 10, pi = 10, stealth = 6, vul = {\"Radiant\"}, res = {\"Acid\", \"Cold\", \"Fire\", \"Lightning\", \"Thunder\"}, imm = {\"Necrotic\", \"Poison\"}, cimm = {\"Exhaustion\", \"Frightened\", \"Grappled\", \"Paralyzed\", \"Petrified\", \"Poisoned\", \"Prone\", \"Restrained\", \"Unconscious\"}, hab = {\"Ruins\", \"Urban\"}, ctypes = {\"Undead\"}, pb = 2, conm = 1, ab = {6, 14, 13, 6, 10, 8}, unholy = true, undead = true, ko = \"그림자\", acts = \"Shadow Stealth (Bonus Action)\", what = \"Medium Undead\" },\r\n[\"Shambling Mound\"] = { ac = 15, hp = 110, init = -1, speed = 30, cr = \"5\", xp = 1800, saves = { Strength = 4, Dexterity = -1, Constitution = 3, Intelligence = -3, Wisdom = 0, Charisma = -3 }, attacks = {{ name = \"Charged Tendril\", hit = 7, dmg = \"1d6+4+2d4\" }}, pp = 10, pi = 10, stealth = 3, res = {\"Cold\", \"Fire\"}, imm = {\"Lightning\"}, cimm = {\"Deafened\", \"Exhaustion\"}, hab = {\"Forest\", \"Swamp\"}, ctypes = {\"Plant\"}, pb = 3, conm = 3, ab = {18, 8, 16, 5, 10, 5}, swim = true, ko = \"비틀대는 풀더미\", sfx = {{ n = \"Engulf\", s = \"Strength\", dc = 15 }, { n = \"Engulf (each turn)\", d = \"3d6\", t = \"Lightning\" }}, absorb = { n = \"Lightning Absorption\", t = \"Lightning\" }, multi = \"The shambling mound makes three Charged Tendril attacks. It can replace one attack with a use of Engulf.\", what = \"Large Plant\" },\r\n[\"Shield Guardian\"] = { ac = 17, hp = 142, init = -1, speed = 30, cr = \"7\", xp = 2900, saves = { Strength = 4, Dexterity = -1, Constitution = 4, Intelligence = -2, Wisdom = 0, Charisma = -4 }, attacks = {{ name = \"Fist\", hit = 7, dmg = \"2d6+4+2d6\" }}, pp = 10, pi = 10, stealth = -1, imm = {\"Poison\"}, cimm = {\"Charmed\", \"Exhaustion\", \"Frightened\", \"Paralyzed\", \"Petrified\", \"Poisoned\"}, hab = {\"Ruins\", \"Urban\"}, ctypes = {\"Construct\"}, pb = 3, conm = 4, ab = {18, 8, 18, 7, 10, 3}, ko = \"방패 수호자\", regen = { n = \"Regeneration\", d = \"10\", one = true }, multi = \"The guardian makes two Fist attacks.\", acts = \"Protection (Reaction)\", auto = {\"Regeneration. The guardian regains 10 Hit Points at the start of each of its turns if it has at least 1 Hit Point.\"}, what = \"Large Construct\" },\r\n[\"Silver Dragon Wyrmling\"] = { ac = 17, hp = 45, init = 2, speed = 30, cr = \"2\", xp = 450, saves = { Strength = 4, Dexterity = 2, Constitution = 3, Intelligence = 1, Wisdom = 2, Charisma = 2 }, attacks = {{ name = \"Rend\", hit = 6, dmg = \"1d10+4\", type = \"Piercing\" }}, pp = 14, pi = 10, stealth = 2, imm = {\"Cold\"}, hab = {\"Mountain\"}, ctypes = {\"Dragon\"}, pb = 2, conm = 3, ab = {19, 10, 17, 12, 11, 15}, fly = true, ko = \"새끼 은룡\", sfx = {{ n = \"Cold Breath\", s = \"Constitution\", dc = 13, d = \"4d8\", t = \"Cold\", h = true, o = \"Recharge 5-6\" }, { n = \"Paralyzing Breath\", s = \"Constitution\", dc = 13 }}, multi = \"The dragon makes two Rend attacks.\", what = \"Medium Dragon (Metallic)\" },\r\n[\"Young Silver Dragon\"] = { ac = 18, hp = 168, init = 4, speed = 40, cr = \"9\", xp = 5000, saves = { Strength = 6, Dexterity = 4, Constitution = 5, Intelligence = 2, Wisdom = 4, Charisma = 4 }, attacks = {{ name = \"Rend\", hit = 10, dmg = \"2d8+6\", type = \"Slashing\" }}, pp = 18, pi = 10, stealth = 4, imm = {\"Cold\"}, hab = {\"Mountain\", \"Urban\"}, ctypes = {\"Dragon\"}, pb = 4, conm = 5, ab = {23, 10, 21, 14, 11, 19}, fly = true, ko = \"젊은 은룡\", sfx = {{ n = \"Cold Breath\", s = \"Constitution\", dc = 17, d = \"11d8\", t = \"Cold\", h = true, o = \"Recharge 5-6\" }, { n = \"Paralyzing Breath\", s = \"Constitution\", dc = 17 }}, multi = \"The dragon makes three Rend attacks. It can replace one attack with a use of Paralyzing Breath.\", what = \"Large Dragon (Metallic)\" },\r\n[\"Adult Silver Dragon\"] = { ac = 19, hp = 216, init = 10, speed = 40, cr = \"16\", xp = 15000, saves = { Strength = 8, Dexterity = 5, Constitution = 7, Intelligence = 3, Wisdom = 6, Charisma = 6 }, attacks = {{ name = \"Rend\", hit = 13, dmg = \"2d8+8+1d8\" }, { name = \"Ice Knife (spell)\", hit = 11, dmg = \"1d10\", type = \"Piercing\", srange = \"ranged\" }}, pp = 21, pi = 11, stealth = 5, imm = {\"Cold\"}, hab = {\"Mountain\", \"Urban\"}, ctypes = {\"Dragon\"}, pb = 5, conm = 7, ab = {27, 10, 25, 16, 13, 22}, fly = true, ko = \"성체 은룡\", sfx = {{ n = \"Cold Breath\", s = \"Constitution\", dc = 20, d = \"12d8\", t = \"Cold\", h = true, o = \"Recharge 5-6\" }, { n = \"Paralyzing Breath\", s = \"Constitution\", dc = 20 }, { n = \"Cold Gale\", s = \"Dexterity\", dc = 19, d = \"4d6\", t = \"Cold\", h = true, lg = true }, { n = \"Ice Knife (burst)\", s = \"Dexterity\", dc = 19, d = \"2d6\", o = \"spell\", t = \"Cold\" }, { n = \"Ice Storm\", s = \"Dexterity\", dc = 19, d = \"3d10+4d6\", o = \"spell\", t = \"Bludgeoning and Cold\", h = true }}, lr = 3, la = 3, lacts = {\"Chill\", \"Cold Gale\", \"Pounce\"}, multi = \"The dragon makes three Rend attacks. It can replace one attack with a use of (A) Paralyzing Breath or (B) Spellcasting to cast Ice Knife.\", acts = \"Spellcasting\", what = \"Huge Dragon (Metallic)\" },\r\n[\"Ancient Silver Dragon\"] = { ac = 22, hp = 468, init = 14, speed = 40, cr = \"23\", xp = 50000, saves = { Strength = 10, Dexterity = 7, Constitution = 9, Intelligence = 4, Wisdom = 9, Charisma = 8 }, attacks = {{ name = \"Rend\", hit = 17, dmg = \"2d8+10+2d8\" }, { name = \"Ice Knife (spell)\", hit = 15, dmg = \"1d10\", type = \"Piercing\", srange = \"ranged\" }}, pp = 26, pi = 12, stealth = 7, imm = {\"Cold\"}, hab = {\"Mountain\", \"Urban\"}, ctypes = {\"Dragon\"}, pb = 7, conm = 9, ab = {30, 10, 29, 18, 15, 26}, fly = true, ko = \"고룡 은룡\", sfx = {{ n = \"Cold Breath\", s = \"Constitution\", dc = 24, d = \"15d8\", t = \"Cold\", h = true, o = \"Recharge 5-6\" }, { n = \"Paralyzing Breath\", s = \"Constitution\", dc = 24 }, { n = \"Cold Gale\", s = \"Dexterity\", dc = 23, d = \"4d6\", t = \"Cold\", h = true, lg = true }, { n = \"Ice Knife (burst)\", s = \"Dexterity\", dc = 23, d = \"3d6\", o = \"spell\", t = \"Cold\" }, { n = \"Ice Storm\", s = \"Dexterity\", dc = 23, d = \"5d10+4d6\", o = \"spell\", t = \"Bludgeoning and Cold\", h = true }}, lr = 4, la = 3, lacts = {\"Chill\", \"Cold Gale\", \"Pounce\"}, multi = \"The dragon makes three Rend attacks. It can replace one attack with a use of (A) Paralyzing Breath or (B) Spellcasting to cast Ice Knife (level 2 version).\", acts = \"Spellcasting\", what = \"Gargantuan Dragon (Metallic)\" },\r\n[\"Skeleton\"] = { ac = 14, hp = 13, init = 3, speed = 30, cr = \"1/4\", xp = 50, saves = { Strength = 0, Dexterity = 3, Constitution = 2, Intelligence = -2, Wisdom = -1, Charisma = -3 }, attacks = {{ name = \"Shortsword\", hit = 5, dmg = \"1d6+3\", type = \"Piercing\" }, { name = \"Shortbow\", hit = 5, dmg = \"1d6+3\", k = \"r\", type = \"Piercing\" }}, pp = 9, pi = 9, stealth = 3, vul = {\"Bludgeoning\"}, imm = {\"Poison\"}, cimm = {\"Exhaustion\", \"Poisoned\"}, hab = {\"Ruins\"}, ctypes = {\"Undead\"}, pb = 2, conm = 2, ab = {10, 16, 15, 6, 8, 5}, unholy = true, undead = true, ko = \"스켈레톤\", what = \"Medium Undead\" },\r\n[\"Warhorse Skeleton\"] = { ac = 13, hp = 22, init = 1, speed = 60, cr = \"1/2\", xp = 100, saves = { Strength = 4, Dexterity = 1, Constitution = 2, Intelligence = -4, Wisdom = -1, Charisma = -3 }, attacks = {{ name = \"Hooves\", hit = 6, dmg = \"1d6+4\", type = \"Bludgeoning\" }}, pp = 9, pi = 9, stealth = 1, vul = {\"Bludgeoning\"}, imm = {\"Poison\"}, cimm = {\"Exhaustion\", \"Poisoned\"}, hab = {\"Ruins\"}, ctypes = {\"Undead\"}, pb = 2, conm = 2, ab = {18, 12, 15, 2, 8, 5}, unholy = true, undead = true, ko = \"전투마 스켈레톤\", what = \"Large Undead\" },\r\n[\"Minotaur Skeleton\"] = { ac = 12, hp = 45, init = 0, speed = 40, cr = \"2\", xp = 450, saves = { Strength = 4, Dexterity = 0, Constitution = 2, Intelligence = -2, Wisdom = -1, Charisma = -3 }, attacks = {{ name = \"Gore\", hit = 6, dmg = \"2d6+4\", type = \"Piercing\" }, { name = \"Slam\", hit = 6, dmg = \"2d10+4\", type = \"Bludgeoning\" }}, pp = 9, pi = 9, stealth = 0, vul = {\"Bludgeoning\"}, imm = {\"Poison\"}, cimm = {\"Exhaustion\", \"Poisoned\"}, hab = {\"Ruins\"}, ctypes = {\"Undead\"}, pb = 2, conm = 2, ab = {18, 11, 15, 6, 8, 5}, unholy = true, undead = true, ko = \"미노타우로스 스켈레톤\", what = \"Large Undead\" },\r\n[\"Solar\"] = { ac = 21, hp = 297, init = 20, speed = 50, cr = \"21\", xp = 33000, saves = { Strength = 8, Dexterity = 6, Constitution = 8, Intelligence = 7, Wisdom = 7, Charisma = 10 }, attacks = {{ name = \"Flying Sword\", hit = 15, dmg = \"4d6+8+8d8\", k = \"b\" }}, pp = 24, pi = 17, stealth = 6, imm = {\"Poison\", \"Radiant\"}, cimm = {\"Charmed\", \"Exhaustion\", \"Frightened\", \"Poisoned\"}, hab = {\"Planar\"}, ctypes = {\"Celestial\"}, pb = 7, conm = 8, ab = {26, 22, 26, 25, 25, 30}, fly = true, ko = \"솔라\", sfx = {{ n = \"Slaying Bow\", s = \"Dexterity\", dc = 21, d = \"4d8+6+8d8\", t = \"Piercing and Radiant\", sl = 100 }, { n = \"Blinding Gaze\", s = \"Constitution\", dc = 25, lg = true }, { n = \"Radiant Teleport\", s = \"Dexterity\", dc = 25, d = \"2d10\", t = \"Radiant\", h = true, lg = true }}, mres = 1, lr = 4, la = 3, lacts = {\"Blinding Gaze\", \"Radiant Teleport\"}, multi = \"The solar makes two Flying Sword attacks.\", acts = \"Spellcasting, Divine Aid (3/Day) (Bonus Action)\", what = \"Large Celestial (Angel)\" },\r\n[\"Specter\"] = { ac = 12, hp = 22, init = 2, speed = 30, cr = \"1\", xp = 200, saves = { Strength = -5, Dexterity = 2, Constitution = 0, Intelligence = 0, Wisdom = 0, Charisma = 0 }, attacks = {{ name = \"Life Drain\", hit = 4, dmg = \"2d6\", type = \"Necrotic\" }}, pp = 10, pi = 10, stealth = 2, res = {\"Acid\", \"Bludgeoning\", \"Cold\", \"Fire\", \"Lightning\", \"Piercing\", \"Slashing\", \"Thunder\"}, imm = {\"Necrotic\", \"Poison\"}, cimm = {\"Charmed\", \"Exhaustion\", \"Grappled\", \"Paralyzed\", \"Petrified\", \"Poisoned\", \"Prone\", \"Restrained\", \"Unconscious\"}, hab = {\"Ruins\"}, ctypes = {\"Undead\"}, pb = 2, conm = 0, ab = {1, 14, 11, 10, 10, 11}, unholy = true, undead = true, fly = true, ko = \"스펙터\", hurts = {{ n = \"Incorporeal Movement\", d = \"1d10\", t = \"Force\" }}, what = \"Medium Undead\" },\r\n[\"Sphinx of Wonder\"] = { ac = 13, hp = 24, init = 3, speed = 20, cr = \"1\", xp = 200, saves = { Strength = -2, Dexterity = 3, Constitution = 1, Intelligence = 2, Wisdom = 1, Charisma = 0 }, attacks = {{ name = \"Rend\", hit = 5, dmg = \"1d4+3+2d6\" }}, pp = 11, pi = 11, stealth = 5, res = {\"Necrotic\", \"Psychic\", \"Radiant\"}, hab = {\"Desert\"}, ctypes = {\"Celestial\"}, pb = 2, conm = 1, ab = {6, 17, 13, 15, 12, 11}, fly = true, ko = \"경이의 스핑크스\", mres = 1, acts = \"Burst of Ingenuity (2/Day) (Reaction)\", what = \"Tiny Celestial\" },\r\n[\"Sphinx of Lore\"] = { ac = 17, hp = 170, init = 10, speed = 40, cr = \"11\", xp = 7200, saves = { Strength = 4, Dexterity = 2, Constitution = 3, Intelligence = 4, Wisdom = 4, Charisma = 4 }, attacks = {{ name = \"Claw\", hit = 8, dmg = \"3d6+4\", type = \"Slashing\" }}, pp = 18, pi = 14, stealth = 2, res = {\"Necrotic\", \"Radiant\"}, imm = {\"Psychic\"}, cimm = {\"Charmed\", \"Frightened\"}, hab = {\"Desert\", \"Ruins\"}, ctypes = {\"Celestial\"}, pb = 4, conm = 3, ab = {18, 15, 16, 18, 18, 18}, fly = true, ko = \"지식의 스핑크스\", sfx = {{ n = \"Mind-Rending Roar\", s = \"Wisdom\", dc = 16, d = \"10d6\", t = \"Psychic\", o = \"Recharge 5-6\" }, { n = \"Weight of Years\", s = \"Constitution\", dc = 16, lg = true }}, lr = 3, la = 3, lacts = {\"Arcane Prowl\", \"Weight of Years\"}, multi = \"The sphinx makes three Claw attacks.\", acts = \"Spellcasting\", what = \"Large Celestial\" },\r\n[\"Sphinx of Valor\"] = { ac = 17, hp = 199, init = 12, speed = 40, cr = \"17\", xp = 18000, saves = { Strength = 6, Dexterity = 6, Constitution = 11, Intelligence = 9, Wisdom = 12, Charisma = 4 }, attacks = {{ name = \"Claw\", hit = 12, dmg = \"4d6+6\", type = \"Slashing\" }}, pp = 22, pi = 16, stealth = 0, res = {\"Necrotic\", \"Radiant\"}, imm = {\"Psychic\"}, cimm = {\"Charmed\", \"Frightened\"}, hab = {\"Desert\", \"Ruins\"}, ctypes = {\"Celestial\"}, pb = 6, conm = 5, ab = {22, 10, 20, 16, 23, 18}, fly = true, ko = \"용맹의 스핑크스\", sfx = {{ n = \"Roar\", s = \"Wisdom\", dc = 20, o = \"3/Day\" }, { n = \"Second Roar\", s = \"Wisdom\", dc = 20 }, { n = \"Third Roar\", s = \"Constitution\", dc = 20, d = \"8d10\", t = \"Thunder\", h = true }, { n = \"Weight of Years\", s = \"Constitution\", dc = 16, lg = true }}, lr = 3, la = 3, lacts = {\"Arcane Prowl\", \"Weight of Years\"}, multi = \"The sphinx makes two Claw attacks and uses Roar.\", acts = \"Spellcasting\", what = \"Large Celestial\" },\r\n[\"Spirit Naga\"] = { ac = 17, hp = 135, init = 3, speed = 40, cr = \"8\", xp = 3900, saves = { Strength = 4, Dexterity = 6, Constitution = 5, Intelligence = 3, Wisdom = 5, Charisma = 6 }, attacks = {{ name = \"Bite\", hit = 7, dmg = \"1d6+4+4d6\" }, { name = \"Necrotic Ray\", hit = 6, dmg = \"6d6\", k = \"r\", type = \"Necrotic\" }}, pp = 12, pi = 12, stealth = 3, imm = {\"Poison\"}, cimm = {\"Charmed\", \"Poisoned\"}, hab = {\"Planar\", \"Underdark\"}, ctypes = {\"Fiend\"}, pb = 3, conm = 2, ab = {18, 17, 14, 16, 15, 16}, unholy = true, ko = \"영혼 나가\", sfx = {{ n = \"Lightning Bolt\", s = \"Dexterity\", dc = 14, d = \"9d6\", o = \"spell\", t = \"Lightning\", h = true }}, multi = \"The naga makes three attacks, using Bite or Necrotic Ray in any combination.\", acts = \"Spellcasting\", what = \"Large Fiend\" },\r\n[\"Sprite\"] = { ac = 15, hp = 10, init = 4, speed = 10, cr = \"1/4\", xp = 50, saves = { Strength = -4, Dexterity = 4, Constitution = 0, Intelligence = 2, Wisdom = 1, Charisma = 0 }, attacks = {{ name = \"Needle Sword\", hit = 6, dmg = \"1d4+4\", type = \"Piercing\" }, { name = \"Enchanting Bow\", hit = 6, dmg = \"1\", k = \"r\", type = \"Piercing\" }}, pp = 13, pi = 11, stealth = 8, hab = {\"Forest\"}, ctypes = {\"Fey\"}, pb = 2, conm = 0, ab = {3, 18, 10, 14, 13, 11}, fly = true, ko = \"스프라이트\", sfx = {{ n = \"Heart Sight\", s = \"Charisma\", dc = 10 }}, acts = \"Invisibility\", what = \"Tiny Fey\" },\r\n[\"Spy\"] = { ac = 12, hp = 27, init = 4, speed = 30, cr = \"1\", xp = 200, saves = { Strength = 0, Dexterity = 2, Constitution = 0, Intelligence = 1, Wisdom = 2, Charisma = 3 }, attacks = {{ name = \"Shortsword\", hit = 4, dmg = \"1d6+2+2d6\" }, { name = \"Hand Crossbow\", hit = 4, dmg = \"1d6+2+2d6\", k = \"r\" }}, pp = 16, pi = 14, stealth = 6, hab = {\"Ruins\", \"Urban\"}, ctypes = {\"Pure Humanoid\"}, pb = 2, conm = 0, ab = {10, 15, 10, 12, 14, 16}, ko = \"첩자\", acts = \"Cunning Action (Bonus Action)\", what = \"Medium or Small Humanoid\" },\r\n[\"Stirge\"] = { ac = 13, hp = 5, init = 3, speed = 10, cr = \"1/8\", xp = 25, saves = { Strength = -3, Dexterity = 3, Constitution = 0, Intelligence = -4, Wisdom = -1, Charisma = -2 }, attacks = {{ name = \"Proboscis\", hit = 5, dmg = \"1d6+3\", type = \"Piercing\" }}, pp = 9, pi = 9, stealth = 3, hab = {\"Forest\", \"Ruins\", \"Swamp\"}, ctypes = {\"Monstrosity\"}, pb = 2, conm = 0, ab = {4, 16, 11, 2, 8, 6}, fly = true, ko = \"스터지\", what = \"Tiny Monstrosity\" },\r\n[\"Stone Giant\"] = { ac = 17, hp = 126, init = 5, speed = 40, cr = \"7\", xp = 2900, saves = { Strength = 6, Dexterity = 5, Constitution = 8, Intelligence = 0, Wisdom = 4, Charisma = -1 }, attacks = {{ name = \"Stone Club\", hit = 9, dmg = \"3d10+6\", type = \"Bludgeoning\" }, { name = \"Boulder\", hit = 9, dmg = \"2d8+6\", k = \"r\", type = \"Bludgeoning\" }}, pp = 14, pi = 11, stealth = 5, hab = {\"Mountain\"}, ctypes = {\"Giant\"}, pb = 3, conm = 5, ab = {23, 15, 20, 10, 12, 9}, ko = \"바위 거인\", sfx = {{ n = \"Deflect Missile\", s = \"Dexterity\", dc = 17, d = \"1d10+6\", t = \"Force\", o = \"Recharge 5-6\" }}, multi = \"The giant makes two attacks, using Stone Club or Boulder in any combination.\", what = \"Huge Giant\" },\r\n[\"Stone Golem\"] = { ac = 18, hp = 220, init = 3, speed = 30, cr = \"10\", xp = 5900, saves = { Strength = 6, Dexterity = -1, Constitution = 5, Intelligence = -4, Wisdom = 0, Charisma = -5 }, attacks = {{ name = \"Slam\", hit = 10, dmg = \"2d8+6+2d8\" }, { name = \"Force Bolt\", hit = 9, dmg = \"4d10\", k = \"r\", type = \"Force\" }}, pp = 10, pi = 10, stealth = -1, imm = {\"Poison\", \"Psychic\"}, cimm = {\"Charmed\", \"Exhaustion\", \"Frightened\", \"Paralyzed\", \"Petrified\", \"Poisoned\"}, hab = {\"Ruins\"}, ctypes = {\"Construct\"}, pb = 4, conm = 5, ab = {22, 9, 20, 3, 11, 1}, ko = \"돌 골렘\", mres = 1, multi = \"The golem makes two attacks, using Slam or Force Bolt in any combination.\", acts = \"Slow (Recharge 5–6) (Bonus Action)\", what = \"Large Construct\" },\r\n[\"Storm Giant\"] = { ac = 16, hp = 230, init = 7, speed = 50, cr = \"13\", xp = 10000, saves = { Strength = 14, Dexterity = 2, Constitution = 10, Intelligence = 3, Wisdom = 10, Charisma = 9 }, attacks = {{ name = \"Storm Sword\", hit = 14, dmg = \"4d6+9+3d8\" }, { name = \"Thunderbolt\", hit = 14, dmg = \"2d12+9\", k = \"r\", type = \"Lightning\" }}, pp = 20, pi = 15, stealth = 2, res = {\"Cold\"}, imm = {\"Lightning\", \"Thunder\"}, hab = {\"Coastal\", \"Underwater\"}, ctypes = {\"Giant\"}, pb = 5, conm = 5, ab = {29, 14, 20, 16, 20, 18}, fly = true, swim = true, ko = \"폭풍 거인\", sfx = {{ n = \"Lightning Storm\", s = \"Dexterity\", dc = 18, d = \"10d10\", t = \"Lightning\", h = true, o = \"Recharge 5-6\" }}, multi = \"The giant makes two attacks, using Storm Sword or Thunderbolt in any combination.\", acts = \"Spellcasting\", what = \"Huge Giant\" },\r\n[\"Succubus\"] = { ac = 15, hp = 71, init = 3, speed = 30, cr = \"4\", xp = 1100, saves = { Strength = -1, Dexterity = 3, Constitution = 1, Intelligence = 2, Wisdom = 1, Charisma = 5 }, attacks = {{ name = \"Fiendish Touch\", hit = 7, dmg = \"2d10+5\", type = \"Psychic\" }}, pp = 15, pi = 15, stealth = 7, res = {\"Cold\", \"Fire\", \"Poison\", \"Psychic\"}, hab = {\"Planar\", \"Urban\"}, ctypes = {\"Fiend\"}, pb = 2, conm = 1, ab = {8, 17, 13, 15, 12, 20}, unholy = true, fly = true, ko = \"서큐버스\", sfx = {{ n = \"Draining Kiss\", s = \"Constitution\", dc = 15, d = \"3d8\", t = \"Psychic\", h = true }}, multi = \"The succubus makes one Fiendish Touch attack and uses Charm or Draining Kiss.\", acts = \"Charm, Shape-Shift (Bonus Action)\", what = \"Medium Fiend\" },\r\n[\"Tarrasque\"] = { ac = 25, hp = 697, init = 18, speed = 60, cr = \"30\", xp = 155000, saves = { Strength = 10, Dexterity = 9, Constitution = 10, Intelligence = 5, Wisdom = 9, Charisma = 9 }, attacks = {{ name = \"Bite\", hit = 19, dmg = \"4d12+10\", type = \"Piercing\" }, { name = \"Claw\", hit = 19, dmg = \"4d8+10\", type = \"Slashing\" }, { name = \"Tail\", hit = 19, dmg = \"3d8+10\", type = \"Bludgeoning\" }}, pp = 19, pi = 10, stealth = 0, res = {\"Bludgeoning\", \"Piercing\", \"Slashing\"}, imm = {\"Fire\", \"Poison\"}, cimm = {\"Charmed\", \"Deafened\", \"Frightened\", \"Paralyzed\", \"Poisoned\"}, hab = {\"Grassland\", \"Hill\"}, ctypes = {\"Monstrosity\"}, pb = 9, conm = 10, ab = {30, 11, 30, 3, 11, 11}, ko = \"타라스크\", sfx = {{ n = \"Thunderous Bellow\", s = \"Constitution\", dc = 27, d = \"12d12\", t = \"Thunder\", h = true, o = \"Recharge 5-6\" }, { n = \"Swallow\", s = \"Strength\", dc = 27 }, { n = \"Swallow (each turn)\", d = \"16d6\", t = \"Acid\" }}, mres = 1, reflect = true, lr = 6, la = 3, lacts = {\"Onslaught\", \"World-Shaking Movement\"}, multi = \"The tarrasque makes one Bite attack and three other attacks, using Claw or Tail in any combination.\", what = \"Gargantuan Monstrosity (Titan)\" },\r\n[\"Tough\"] = { ac = 12, hp = 32, init = 1, speed = 30, cr = \"1/2\", xp = 100, saves = { Strength = 2, Dexterity = 1, Constitution = 2, Intelligence = 0, Wisdom = 0, Charisma = 0 }, attacks = {{ name = \"Mace\", hit = 4, dmg = \"1d6+2\", type = \"Bludgeoning\" }, { name = \"Heavy Crossbow\", hit = 3, dmg = \"1d10+1\", k = \"r\", type = \"Piercing\" }}, pp = 10, pi = 10, stealth = 1, hab = {\"Hill\", \"Ruins\", \"Urban\"}, ctypes = {\"Pure Humanoid\"}, pb = 2, conm = 2, ab = {15, 12, 14, 10, 10, 11}, ko = \"불량배\", what = \"Medium or Small Humanoid\" },\r\n[\"Tough Boss\"] = { ac = 16, hp = 82, init = 2, speed = 30, cr = \"4\", xp = 1100, saves = { Strength = 5, Dexterity = 2, Constitution = 5, Intelligence = 0, Wisdom = 0, Charisma = 2 }, attacks = {{ name = \"Warhammer\", hit = 5, dmg = \"2d8+3\", type = \"Bludgeoning\" }, { name = \"Heavy Crossbow\", hit = 4, dmg = \"2d10+2\", k = \"r\", type = \"Piercing\" }}, pp = 10, pi = 10, stealth = 2, hab = {\"Ruins\", \"Urban\"}, ctypes = {\"Pure Humanoid\"}, pb = 2, conm = 3, ab = {17, 14, 16, 11, 10, 11}, ko = \"불량배 두목\", multi = \"The tough makes two attacks, using Warhammer or Heavy Crossbow in any combination.\", what = \"Medium or Small Humanoid\" },\r\n[\"Treant\"] = { ac = 16, hp = 138, init = 3, speed = 30, cr = \"9\", xp = 5000, saves = { Strength = 6, Dexterity = -1, Constitution = 5, Intelligence = 1, Wisdom = 3, Charisma = 1 }, attacks = {{ name = \"Slam\", hit = 10, dmg = \"3d6+6\", type = \"Bludgeoning\" }, { name = \"Hail of Bark\", hit = 10, dmg = \"4d10+6\", k = \"r\", type = \"Piercing\" }}, pp = 13, pi = 13, stealth = -1, vul = {\"Fire\"}, res = {\"Bludgeoning\", \"Piercing\"}, hab = {\"Forest\"}, ctypes = {\"Plant\"}, pb = 4, conm = 5, ab = {23, 8, 21, 12, 16, 12}, ko = \"트렌트\", multi = \"The treant makes two Slam attacks.\", acts = \"Animate Trees (1/Day)\", what = \"Huge Plant\" },\r\n[\"Troll\"] = { ac = 15, hp = 94, init = 1, speed = 30, cr = \"5\", xp = 1800, saves = { Strength = 4, Dexterity = 1, Constitution = 5, Intelligence = -2, Wisdom = -1, Charisma = -2 }, attacks = {{ name = \"Rend\", hit = 7, dmg = \"2d6+4\", type = \"Slashing\" }}, pp = 15, pi = 9, stealth = 1, hab = {\"Forest\", \"Hill\", \"Mountain\", \"Swamp\", \"Underdark\"}, ctypes = {\"Giant\"}, pb = 3, conm = 5, ab = {18, 13, 20, 7, 9, 7}, ko = \"트롤\", limbs = 4, regen = { n = \"Regeneration\", d = \"15\", zero = true, stop = {\"Acid\", \"Fire\"} }, multi = \"The troll makes three Rend attacks.\", acts = \"Charge (Bonus Action)\", auto = {\"Regeneration. The troll regains 15 Hit Points at the start of each of its turns. If the troll takes Acid or Fire damage, this trait doesn't function on the troll's next turn. The troll dies only if it starts its turn with 0 Hit Points and doesn't regenerate.\"}, what = \"Large Giant\" },\r\n[\"Troll Limb\"] = { ac = 13, hp = 14, init = 1, speed = 20, cr = \"1/2\", xp = 100, saves = { Strength = 4, Dexterity = 1, Constitution = 0, Intelligence = -5, Wisdom = -1, Charisma = -5 }, attacks = {{ name = \"Rend\", hit = 6, dmg = \"2d4+4\", type = \"Slashing\" }}, pp = 9, pi = 9, stealth = 1, ctypes = {\"Giant\"}, pb = 2, conm = 0, ab = {18, 12, 10, 1, 9, 1}, ko = \"트롤의 팔다리\", regen = { n = \"Regeneration\", d = \"5\", zero = true, stop = {\"Acid\", \"Fire\"} }, auto = {\"Regeneration. The limb regains 5 Hit Points at the start of each of its turns. If the limb takes Acid or Fire damage, this trait doesn't function on the limb's next turn. The limb dies only if it starts its turn with 0 Hit Points and doesn't regenerate.\"}, what = \"Small Giant\" },\r\n[\"Unicorn\"] = { ac = 12, hp = 97, init = 8, speed = 50, cr = \"5\", xp = 1800, saves = { Strength = 4, Dexterity = 2, Constitution = 2, Intelligence = 0, Wisdom = 3, Charisma = 3 }, attacks = {{ name = \"Hooves\", hit = 7, dmg = \"2d6+4\", type = \"Bludgeoning\" }, { name = \"Radiant Horn\", hit = 7, dmg = \"1d10+4\", type = \"Radiant\" }}, pp = 13, pi = 13, stealth = 2, imm = {\"Poison\"}, cimm = {\"Charmed\", \"Paralyzed\", \"Poisoned\"}, hab = {\"Forest\", \"Planar\"}, ctypes = {\"Celestial\"}, pb = 3, conm = 2, ab = {18, 14, 15, 11, 17, 16}, ko = \"유니콘\", mres = 1, thps = {{ n = \"Shimmering Shield\", d = \"3d6\", ac = 2 }}, lr = 3, la = 3, lacts = {\"Charging Horn\", \"Shimmering Shield\"}, multi = \"The unicorn makes one Hooves attack and one Radiant Horn attack.\", acts = \"Spellcasting, Unicorn's Blessing (3/Day) (Bonus Action)\", what = \"Large Celestial\" },\r\n[\"Vampire Familiar\"] = { ac = 15, hp = 65, init = 5, speed = 30, cr = \"3\", xp = 700, saves = { Strength = 3, Dexterity = 5, Constitution = 2, Intelligence = 0, Wisdom = 2, Charisma = 2 }, attacks = {{ name = \"Umbral Dagger\", hit = 5, dmg = \"1d4+3+3d4\", k = \"b\" }}, pp = 14, pi = 10, stealth = 7, res = {\"Necrotic\"}, hab = {\"Ruins\", \"Urban\"}, ctypes = {\"Pure Humanoid\"}, pb = 2, conm = 2, ab = {17, 16, 15, 10, 10, 14}, ko = \"뱀파이어 종복\", multi = \"The familiar makes two Umbral Dagger attacks.\", acts = \"Deathless Agility (Bonus Action)\", what = \"Medium or Small Humanoid\" },\r\n[\"Vampire Spawn\"] = { ac = 16, hp = 90, init = 3, speed = 30, cr = \"5\", xp = 1800, saves = { Strength = 3, Dexterity = 6, Constitution = 3, Intelligence = 0, Wisdom = 3, Charisma = 1 }, attacks = {{ name = \"Claw\", hit = 6, dmg = \"2d4+3\", type = \"Slashing\" }}, pp = 13, pi = 10, stealth = 6, res = {\"Necrotic\"}, hab = {\"Ruins\", \"Urban\"}, ctypes = {\"Undead\"}, pb = 3, conm = 3, ab = {16, 16, 16, 11, 10, 12}, unholy = true, undead = true, ko = \"뱀파이어 권속\", sfx = {{ n = \"Bite\", s = \"Constitution\", dc = 14, d = \"1d4+3+3d6\", t = \"Piercing and Necrotic\" }}, hurts = {{ n = \"Running Water\", d = \"20\", t = \"Acid\" }, { n = \"Sunlight\", d = \"20\", t = \"Radiant\" }}, multi = \"The vampire makes two Claw attacks and uses Bite.\", acts = \"Deathless Agility (Bonus Action)\", auto = {\"Sunlight. The vampire takes 20 Radiant damage if it starts its turn in sunlight. While in sunlight, it has Disadvantage on attack rolls and ability checks.\"}, what = \"Medium or Small Undead\" },\r\n[\"Vampire\"] = { ac = 16, hp = 195, init = 14, speed = 40, cr = \"13\", xp = 10000, saves = { Strength = 4, Dexterity = 9, Constitution = 9, Intelligence = 3, Wisdom = 7, Charisma = 9 }, attacks = {{ name = \"Grave Strike (Vampire Form Only)\", hit = 9, dmg = \"1d8+4+2d6\" }}, pp = 17, pi = 12, stealth = 9, res = {\"Necrotic\"}, hab = {\"Ruins\", \"Urban\"}, ctypes = {\"Undead\"}, pb = 5, conm = 4, ab = {18, 18, 18, 17, 15, 18}, unholy = true, undead = true, ko = \"뱀파이어\", sfx = {{ n = \"Bite\", s = \"Constitution\", dc = 17, d = \"1d4+4+3d8\", t = \"Piercing and Necrotic\", o = \"Bat or Vampire Form Only\" }}, lr = 3, la = 3, lacts = {\"Beguile\", \"Deathless Strike\"}, hurts = {{ n = \"Running Water\", d = \"20\", t = \"Acid\" }, { n = \"Sunlight\", d = \"20\", t = \"Radiant\" }}, acts = \"Multiattack (Vampire Form Only), Grave Strike (Vampire Form Only), Charm (Recharge 5–6) (Bonus Action), Shape-Shift (Bonus Action), While in bat form, the vampire can't speak (Bonus Action)\", auto = {\"Sunlight. The vampire takes 20 Radiant damage if it starts its turn in sunlight. While in sunlight, it has Disadvantage on attack rolls and ability checks.\"}, what = \"Medium or Small Undead\" },\r\n[\"Vrock\"] = { ac = 15, hp = 152, init = 2, speed = 40, cr = \"6\", xp = 2300, saves = { Strength = 3, Dexterity = 5, Constitution = 4, Intelligence = -1, Wisdom = 4, Charisma = 2 }, attacks = {{ name = \"Shred\", hit = 6, dmg = \"2d6+3+3d6\" }}, pp = 11, pi = 11, stealth = 2, res = {\"Cold\", \"Fire\", \"Lightning\"}, imm = {\"Poison\"}, cimm = {\"Poisoned\"}, hab = {\"Planar\"}, ctypes = {\"Fiend\"}, pb = 3, conm = 4, ab = {17, 15, 18, 8, 13, 8}, unholy = true, fly = true, ko = \"브록\", sfx = {{ n = \"Spores\", s = \"Constitution\", dc = 15, o = \"Recharge 6\" }, { n = \"Spores (each turn)\", d = \"1d10\", t = \"Poison\", o = \"Recharge 6\" }, { n = \"Stunning Screech\", s = \"Constitution\", dc = 15, d = \"3d6\", t = \"Thunder\", o = \"1/Day\" }}, mres = 1, multi = \"The vrock makes two Shred attacks.\", what = \"Large Fiend (Demon)\" },\r\n[\"Warrior Infantry\"] = { ac = 13, hp = 9, init = 0, speed = 30, cr = \"1/8\", xp = 25, saves = { Strength = 1, Dexterity = 0, Constitution = 0, Intelligence = -1, Wisdom = 0, Charisma = -1 }, attacks = {{ name = \"Spear\", hit = 3, dmg = \"1d6+1\", k = \"b\", type = \"Piercing\" }}, pp = 10, pi = 10, stealth = 0, hab = {\"Grassland\", \"Urban\"}, ctypes = {\"Pure Humanoid\"}, pb = 2, conm = 0, ab = {13, 11, 11, 8, 11, 8}, ko = \"보병\", what = \"Medium or Small Humanoid\" },\r\n[\"Warrior Veteran\"] = { ac = 17, hp = 65, init = 3, speed = 30, cr = \"3\", xp = 700, saves = { Strength = 3, Dexterity = 1, Constitution = 2, Intelligence = 0, Wisdom = 0, Charisma = 0 }, attacks = {{ name = \"Greatsword\", hit = 5, dmg = \"2d6+3\", type = \"Slashing\" }, { name = \"Heavy Crossbow\", hit = 3, dmg = \"2d10+1\", k = \"r\", type = \"Piercing\" }}, pp = 12, pi = 10, stealth = 1, hab = {\"Grassland\", \"Urban\"}, ctypes = {\"Pure Humanoid\"}, pb = 2, conm = 2, ab = {16, 13, 14, 10, 11, 10}, ko = \"노련한 전사\", react = { n = 2, name = \"Parry\", melee = true }, multi = \"The warrior makes two Greatsword or Heavy Crossbow attacks.\", acts = \"Parry (Reaction)\", what = \"Medium or Small Humanoid\" },\r\n[\"Water Elemental\"] = { ac = 14, hp = 114, init = 2, speed = 30, cr = \"5\", xp = 1800, saves = { Strength = 4, Dexterity = 2, Constitution = 4, Intelligence = -3, Wisdom = 0, Charisma = -1 }, attacks = {{ name = \"Slam\", hit = 7, dmg = \"2d8+4\", type = \"Bludgeoning\" }}, pp = 10, pi = 10, stealth = 2, res = {\"Acid\", \"Fire\"}, imm = {\"Poison\"}, cimm = {\"Exhaustion\", \"Grappled\", \"Paralyzed\", \"Petrified\", \"Poisoned\", \"Prone\", \"Restrained\", \"Unconscious\"}, hab = {\"Coastal\", \"Planar\", \"Underwater\"}, ctypes = {\"Elemental\"}, pb = 3, conm = 4, ab = {18, 14, 18, 5, 10, 8}, swim = true, ko = \"물 정령\", sfx = {{ n = \"Whelm\", s = \"Strength\", dc = 15, d = \"4d8+4\", t = \"Bludgeoning\", h = true, o = \"Recharge 4-6\" }, { n = \"Whelm (each turn)\", d = \"2d8\", t = \"Bludgeoning\", o = \"Recharge 4-6\" }}, multi = \"The elemental makes two Slam attacks.\", what = \"Large Elemental\" },\r\n[\"Werebear\"] = { ac = 15, hp = 135, init = 3, speed = 30, cr = \"5\", xp = 1800, saves = { Strength = 4, Dexterity = 0, Constitution = 3, Intelligence = 0, Wisdom = 1, Charisma = 1 }, attacks = {{ name = \"Bite (Bear or Hybrid Form Only)\", hit = 7, dmg = \"2d12+4\", type = \"Piercing\" }, { name = \"Handaxe (Humanoid or Hybrid Form Only)\", hit = 7, dmg = \"3d6+4\", k = \"b\", type = \"Slashing\" }, { name = \"Rend (Bear or Hybrid Form Only)\", hit = 7, dmg = \"2d8+4\", type = \"Slashing\" }}, pp = 17, pi = 11, stealth = 0, hab = {\"Arctic\", \"Forest\"}, ctypes = {\"Monstrosity\", \"Shapeshifter\"}, pb = 3, conm = 3, ab = {19, 10, 17, 11, 12, 12}, ko = \"곰인간\", multi = \"The werebear makes two attacks, using Handaxe or Rend in any combination. It can replace one attack with a Bite attack.\", acts = \"Bite (Bear or Hybrid Form Only), Handaxe (Humanoid or Hybrid Form Only), Rend (Bear or Hybrid Form Only), Shape-Shift (Bonus Action)\", what = \"Medium or Small Monstrosity (Lycanthrope)\" },\r\n[\"Wereboar\"] = { ac = 15, hp = 97, init = 2, speed = 30, cr = \"4\", xp = 1100, saves = { Strength = 3, Dexterity = 0, Constitution = 2, Intelligence = 0, Wisdom = 0, Charisma = -1 }, attacks = {{ name = \"Gore (Boar or Hybrid Form Only)\", hit = 5, dmg = \"2d8+3\", type = \"Piercing\" }, { name = \"Javelin (Humanoid or Hybrid Form Only)\", hit = 5, dmg = \"3d6+3\", k = \"b\", type = \"Piercing\" }, { name = \"Tusk (Boar or Hybrid Form Only)\", hit = 5, dmg = \"2d6+3\", type = \"Piercing\" }}, pp = 12, pi = 10, stealth = 0, hab = {\"Forest\", \"Hill\"}, ctypes = {\"Monstrosity\", \"Shapeshifter\"}, pb = 2, conm = 2, ab = {17, 10, 15, 10, 11, 8}, ko = \"멧돼지인간\", multi = \"The wereboar makes two attacks, using Javelin or Tusk in any combination. It can replace one attack with a Gore attack.\", acts = \"Gore (Boar or Hybrid Form Only), Javelin (Humanoid or Hybrid Form Only), Tusk (Boar or Hybrid Form Only), Shape-Shift (Bonus Action)\", what = \"Medium or Small Monstrosity (Lycanthrope)\" },\r\n[\"Wererat\"] = { ac = 13, hp = 60, init = 3, speed = 30, cr = \"2\", xp = 450, saves = { Strength = 0, Dexterity = 3, Constitution = 1, Intelligence = 0, Wisdom = 0, Charisma = -1 }, attacks = {{ name = \"Bite (Rat or Hybrid Form Only)\", hit = 5, dmg = \"2d4+3\", type = \"Piercing\" }, { name = \"Scratch\", hit = 5, dmg = \"1d6+3\", type = \"Slashing\" }}, pp = 14, pi = 10, stealth = 5, hab = {\"Ruins\", \"Urban\"}, ctypes = {\"Monstrosity\", \"Shapeshifter\"}, pb = 2, conm = 1, ab = {10, 16, 12, 11, 10, 8}, ko = \"쥐인간\", multi = \"The wererat makes two attacks, using Scratch or Hand Crossbow in any combination. It can replace one attack with a Bite attack.\", acts = \"Bite (Rat or Hybrid Form Only), Ranged Attack Roll: +5, range 30/120 ft, Shape-Shift (Bonus Action)\", what = \"Medium or Small Monstrosity (Lycanthrope)\" },\r\n[\"Weretiger\"] = { ac = 12, hp = 120, init = 2, speed = 30, cr = \"4\", xp = 1100, saves = { Strength = 3, Dexterity = 2, Constitution = 3, Intelligence = 0, Wisdom = 1, Charisma = 0 }, attacks = {{ name = \"Bite (Tiger or Hybrid Form Only)\", hit = 5, dmg = \"2d8+3\", type = \"Piercing\" }, { name = \"Scratch\", hit = 5, dmg = \"2d6+3\", type = \"Slashing\" }, { name = \"Longbow (Humanoid or Hybrid Form Only)\", hit = 4, dmg = \"2d8+2\", k = \"r\", type = \"Piercing\" }}, pp = 15, pi = 11, stealth = 4, hab = {\"Forest\"}, ctypes = {\"Monstrosity\", \"Shapeshifter\"}, pb = 2, conm = 3, ab = {17, 15, 16, 10, 13, 11}, ko = \"호랑이인간\", multi = \"The weretiger makes two attacks, using Scratch or Longbow in any combination. It can replace one attack with a Bite attack.\", acts = \"Bite (Tiger or Hybrid Form Only), Longbow (Humanoid or Hybrid Form Only), Prowl (Tiger or Hybrid Form Only) (Bonus Action), Shape-Shift (Bonus Action)\", what = \"Medium or Small Monstrosity (Lycanthrope)\" },\r\n[\"Werewolf\"] = { ac = 15, hp = 71, init = 4, speed = 30, cr = \"3\", xp = 700, saves = { Strength = 3, Dexterity = 2, Constitution = 2, Intelligence = 0, Wisdom = 0, Charisma = 0 }, attacks = {{ name = \"Bite (Wolf or Hybrid Form Only)\", hit = 5, dmg = \"2d8+3\", type = \"Piercing\" }, { name = \"Scratch\", hit = 5, dmg = \"2d6+3\", type = \"Slashing\" }, { name = \"Longbow (Humanoid or Hybrid Form Only)\", hit = 4, dmg = \"2d8+2\", k = \"r\", type = \"Piercing\" }}, pp = 14, pi = 10, stealth = 4, hab = {\"Forest\", \"Hill\"}, ctypes = {\"Monstrosity\", \"Shapeshifter\"}, pb = 2, conm = 2, ab = {16, 14, 14, 10, 11, 10}, ko = \"늑대인간\", multi = \"The werewolf makes two attacks, using Scratch or Longbow in any combination. It can replace one attack with a Bite attack.\", acts = \"Bite (Wolf or Hybrid Form Only), Longbow (Humanoid or Hybrid Form Only), Shape-Shift (Bonus Action)\", what = \"Medium or Small Monstrosity (Lycanthrope)\" },\r\n[\"White Dragon Wyrmling\"] = { ac = 16, hp = 32, init = 2, speed = 30, cr = \"2\", xp = 450, saves = { Strength = 2, Dexterity = 2, Constitution = 2, Intelligence = -3, Wisdom = 2, Charisma = 0 }, attacks = {{ name = \"Rend\", hit = 4, dmg = \"1d8+2+1d4\" }}, pp = 14, pi = 10, stealth = 2, imm = {\"Cold\"}, hab = {\"Arctic\"}, ctypes = {\"Dragon\"}, pb = 2, conm = 2, ab = {14, 10, 14, 5, 10, 11}, fly = true, swim = true, ko = \"새끼 백룡\", sfx = {{ n = \"Cold Breath\", s = \"Constitution\", dc = 12, d = \"5d8\", t = \"Cold\", h = true, o = \"Recharge 5-6\" }}, multi = \"The dragon makes two Rend attacks.\", what = \"Medium Dragon (Chromatic)\" },\r\n[\"Young White Dragon\"] = { ac = 17, hp = 123, init = 3, speed = 40, cr = \"6\", xp = 2300, saves = { Strength = 4, Dexterity = 3, Constitution = 4, Intelligence = -2, Wisdom = 3, Charisma = 1 }, attacks = {{ name = \"Rend\", hit = 7, dmg = \"2d4+4+1d4\" }}, pp = 16, pi = 10, stealth = 3, imm = {\"Cold\"}, hab = {\"Arctic\"}, ctypes = {\"Dragon\"}, pb = 3, conm = 4, ab = {18, 10, 18, 6, 11, 12}, fly = true, swim = true, ko = \"젊은 백룡\", sfx = {{ n = \"Cold Breath\", s = \"Constitution\", dc = 15, d = \"9d8\", t = \"Cold\", h = true, o = \"Recharge 5-6\" }}, multi = \"The dragon makes three Rend attacks.\", what = \"Large Dragon (Chromatic)\" },\r\n[\"Adult White Dragon\"] = { ac = 18, hp = 200, init = 10, speed = 40, cr = \"13\", xp = 10000, saves = { Strength = 6, Dexterity = 5, Constitution = 6, Intelligence = -1, Wisdom = 6, Charisma = 1 }, attacks = {{ name = \"Rend\", hit = 11, dmg = \"2d6+6+1d8\" }}, pp = 21, pi = 11, stealth = 5, imm = {\"Cold\"}, hab = {\"Arctic\"}, ctypes = {\"Dragon\"}, pb = 5, conm = 6, ab = {22, 10, 22, 8, 12, 12}, fly = true, swim = true, ko = \"성체 백룡\", sfx = {{ n = \"Cold Breath\", s = \"Constitution\", dc = 19, d = \"12d8\", t = \"Cold\", h = true, o = \"Recharge 5-6\" }, { n = \"Freezing Burst\", s = \"Constitution\", dc = 14, d = \"2d6\", t = \"Cold\", lg = true }}, lr = 3, la = 3, lacts = {\"Freezing Burst\", \"Frightful Presence\", \"Pounce\"}, multi = \"The dragon makes three Rend attacks.\", what = \"Huge Dragon (Chromatic)\" },\r\n[\"Ancient White Dragon\"] = { ac = 20, hp = 333, init = 12, speed = 40, cr = \"20\", xp = 25000, saves = { Strength = 8, Dexterity = 6, Constitution = 8, Intelligence = 0, Wisdom = 7, Charisma = 4 }, attacks = {{ name = \"Rend\", hit = 14, dmg = \"2d8+8+2d6\" }}, pp = 23, pi = 11, stealth = 6, imm = {\"Cold\"}, hab = {\"Arctic\"}, ctypes = {\"Dragon\"}, pb = 6, conm = 8, ab = {26, 10, 26, 10, 13, 18}, fly = true, swim = true, ko = \"고룡 백룡\", sfx = {{ n = \"Cold Breath\", s = \"Constitution\", dc = 22, d = \"14d8\", t = \"Cold\", h = true, o = \"Recharge 5-6\" }, { n = \"Freezing Burst\", s = \"Constitution\", dc = 20, d = \"4d6\", t = \"Cold\", lg = true }}, lr = 4, la = 3, lacts = {\"Freezing Burst\", \"Frightful Presence\", \"Pounce\"}, multi = \"The dragon makes three Rend attacks.\", what = \"Gargantuan Dragon (Chromatic)\" },\r\n[\"Wight\"] = { ac = 14, hp = 82, init = 4, speed = 30, cr = \"3\", xp = 700, saves = { Strength = 2, Dexterity = 2, Constitution = 3, Intelligence = 0, Wisdom = 1, Charisma = 2 }, attacks = {{ name = \"Necrotic Sword\", hit = 4, dmg = \"1d8+2+1d8\" }, { name = \"Necrotic Bow\", hit = 4, dmg = \"1d8+2+1d8\", k = \"r\" }}, pp = 13, pi = 11, stealth = 4, res = {\"Necrotic\"}, imm = {\"Poison\"}, cimm = {\"Exhaustion\", \"Poisoned\"}, hab = {\"Ruins\"}, ctypes = {\"Undead\"}, pb = 2, conm = 3, ab = {15, 14, 16, 10, 13, 15}, unholy = true, undead = true, ko = \"와이트\", sfx = {{ n = \"Life Drain\", s = \"Constitution\", dc = 13, d = \"1d8+2\", t = \"Necrotic\" }}, multi = \"The wight makes two attacks, using Necrotic Sword or Necrotic Bow in any combination. It can replace one attack with a use of Life Drain.\", what = \"Medium Undead\" },\r\n[\"Will-o'-Wisp\"] = { ac = 19, hp = 27, init = 9, speed = 5, cr = \"2\", xp = 450, saves = { Strength = -5, Dexterity = 9, Constitution = 0, Intelligence = 1, Wisdom = 2, Charisma = 0 }, attacks = {{ name = \"Shock\", hit = 4, dmg = \"2d8+2\", type = \"Lightning\" }}, pp = 12, pi = 12, stealth = 9, res = {\"Acid\", \"Bludgeoning\", \"Cold\", \"Fire\", \"Necrotic\", \"Piercing\", \"Slashing\"}, imm = {\"Lightning\", \"Poison\"}, cimm = {\"Exhaustion\", \"Grappled\", \"Paralyzed\", \"Petrified\", \"Poisoned\", \"Prone\", \"Restrained\", \"Unconscious\"}, hab = {\"Forest\", \"Ruins\", \"Swamp\"}, ctypes = {\"Undead\"}, pb = 2, conm = 0, ab = {1, 28, 10, 13, 14, 11}, unholy = true, undead = true, fly = true, ko = \"도깨비불\", sfx = {{ n = \"Consume Life\", s = \"Constitution\", dc = 10 }}, hurts = {{ n = \"Incorporeal Movement\", d = \"1d10\", t = \"Force\" }}, heals = {{ n = \"Consume Life\", d = \"3d6\" }}, acts = \"Vanish (Bonus Action)\", what = \"Tiny Undead\" },\r\n[\"Winter Wolf\"] = { ac = 13, hp = 75, init = 1, speed = 50, cr = \"3\", xp = 700, saves = { Strength = 4, Dexterity = 1, Constitution = 2, Intelligence = -2, Wisdom = 1, Charisma = -1 }, attacks = {{ name = \"Bite\", hit = 6, dmg = \"2d6+4\", type = \"Piercing\" }}, pp = 15, pi = 11, stealth = 5, imm = {\"Cold\"}, hab = {\"Arctic\"}, ctypes = {\"Monstrosity\"}, pb = 2, conm = 2, ab = {18, 13, 14, 7, 12, 8}, ko = \"겨울 늑대\", sfx = {{ n = \"Cold Breath\", s = \"Constitution\", dc = 12, d = \"4d8\", t = \"Cold\", h = true, o = \"Recharge 5-6\" }}, what = \"Large Monstrosity\" },\r\n[\"Worg\"] = { ac = 13, hp = 26, init = 1, speed = 50, cr = \"1/2\", xp = 100, saves = { Strength = 3, Dexterity = 1, Constitution = 1, Intelligence = -2, Wisdom = 0, Charisma = -1 }, attacks = {{ name = \"Bite\", hit = 5, dmg = \"1d8+3\", type = \"Piercing\" }}, pp = 14, pi = 10, stealth = 1, hab = {\"Forest\", \"Grassland\", \"Hill\"}, ctypes = {\"Fey\"}, pb = 2, conm = 1, ab = {16, 13, 13, 7, 11, 8}, ko = \"워그\", what = \"Large Fey\" },\r\n[\"Wraith\"] = { ac = 13, hp = 67, init = 3, speed = 5, cr = \"5\", xp = 1800, saves = { Strength = -2, Dexterity = 3, Constitution = 3, Intelligence = 1, Wisdom = 2, Charisma = 2 }, attacks = {{ name = \"Life Drain\", hit = 6, dmg = \"4d8+3\", type = \"Necrotic\" }}, pp = 12, pi = 12, stealth = 3, res = {\"Acid\", \"Bludgeoning\", \"Cold\", \"Fire\", \"Piercing\", \"Slashing\"}, imm = {\"Necrotic\", \"Poison\"}, cimm = {\"Charmed\", \"Exhaustion\", \"Grappled\", \"Paralyzed\", \"Petrified\", \"Poisoned\", \"Prone\", \"Restrained\", \"Unconscious\"}, hab = {\"Ruins\"}, ctypes = {\"Undead\"}, pb = 3, conm = 3, ab = {6, 16, 16, 12, 14, 15}, unholy = true, undead = true, fly = true, ko = \"레이스\", hurts = {{ n = \"Incorporeal Movement\", d = \"1d10\", t = \"Force\" }}, acts = \"Create Specter\", what = \"Medium or Small Undead\" },\r\n[\"Wyvern\"] = { ac = 14, hp = 127, init = 0, speed = 30, cr = \"6\", xp = 2300, saves = { Strength = 4, Dexterity = 0, Constitution = 3, Intelligence = -3, Wisdom = 1, Charisma = -2 }, attacks = {{ name = \"Bite\", hit = 7, dmg = \"2d8+4\", type = \"Piercing\" }, { name = \"Sting\", hit = 7, dmg = \"2d6+4\", type = \"Piercing\" }}, pp = 14, pi = 11, stealth = 0, hab = {\"Grassland\", \"Hill\", \"Mountain\"}, ctypes = {\"Dragon\"}, pb = 3, conm = 3, ab = {19, 10, 16, 5, 12, 6}, fly = true, ko = \"와이번\", multi = \"The wyvern makes one Bite attack and one Sting attack.\", what = \"Large Dragon\" },\r\n[\"Xorn\"] = { ac = 19, hp = 84, init = 0, speed = 20, cr = \"5\", xp = 1800, saves = { Strength = 3, Dexterity = 0, Constitution = 6, Intelligence = 0, Wisdom = 0, Charisma = 0 }, attacks = {{ name = \"Bite\", hit = 6, dmg = \"4d6+3\", type = \"Piercing\" }, { name = \"Claw\", hit = 6, dmg = \"1d10+3\", type = \"Slashing\" }}, pp = 16, pi = 10, stealth = 6, imm = {\"Poison\"}, cimm = {\"Paralyzed\", \"Petrified\", \"Poisoned\"}, hab = {\"Mountain\", \"Planar\", \"Underdark\"}, ctypes = {\"Elemental\"}, pb = 3, conm = 6, ab = {17, 10, 22, 11, 10, 11}, ko = \"조른\", multi = \"The xorn makes one Bite attack and three Claw attacks.\", acts = \"Charge (Bonus Action)\", what = \"Medium Elemental\" },\r\n[\"Zombie\"] = { ac = 8, hp = 15, init = -2, speed = 20, cr = \"1/4\", xp = 50, saves = { Strength = 1, Dexterity = -2, Constitution = 3, Intelligence = -4, Wisdom = 0, Charisma = -3 }, attacks = {{ name = \"Slam\", hit = 3, dmg = \"1d8+1\", type = \"Bludgeoning\" }}, pp = 8, pi = 8, stealth = -2, imm = {\"Poison\"}, cimm = {\"Exhaustion\", \"Poisoned\"}, hab = {\"Ruins\"}, ctypes = {\"Undead\"}, pb = 2, conm = 3, ab = {13, 6, 16, 3, 6, 5}, unholy = true, undead = true, ko = \"좀비\", fortitude = true, what = \"Medium Undead\" },\r\n[\"Ogre Zombie\"] = { ac = 8, hp = 85, init = -2, speed = 30, cr = \"2\", xp = 450, saves = { Strength = 4, Dexterity = -2, Constitution = 4, Intelligence = -4, Wisdom = 0, Charisma = -3 }, attacks = {{ name = \"Slam\", hit = 6, dmg = \"2d8+4\", type = \"Bludgeoning\" }}, pp = 8, pi = 8, stealth = -2, imm = {\"Poison\"}, cimm = {\"Exhaustion\", \"Poisoned\"}, hab = {\"Ruins\"}, ctypes = {\"Undead\"}, pb = 2, conm = 4, ab = {19, 6, 18, 3, 6, 5}, unholy = true, undead = true, ko = \"오우거 좀비\", fortitude = true, what = \"Large Undead\" },\r\n[\"Allosaurus\"] = { ac = 13, hp = 51, init = 1, speed = 60, cr = \"2\", xp = 450, saves = { Strength = 4, Dexterity = 1, Constitution = 3, Intelligence = -4, Wisdom = 1, Charisma = -3 }, attacks = {{ name = \"Bite\", hit = 6, dmg = \"2d10+4\", type = \"Piercing\" }, { name = \"Claws\", hit = 6, dmg = \"1d8+4\", type = \"Slashing\" }}, pp = 15, pi = 11, stealth = 1, hab = {\"Grassland\"}, ctypes = {\"Beast\"}, pb = 2, conm = 3, ab = {19, 13, 17, 2, 12, 5}, beast = true, sc = { Strength = 19, Dexterity = 13, Constitution = 17 }, sk = { Perception = 5 }, ko = \"알로사우루스\", what = \"Large Beast (Dinosaur)\" },\r\n[\"Ankylosaurus\"] = { ac = 15, hp = 68, init = 0, speed = 30, cr = \"3\", xp = 700, saves = { Strength = 6, Dexterity = 0, Constitution = 2, Intelligence = -4, Wisdom = 1, Charisma = -3 }, attacks = {{ name = \"Tail\", hit = 6, dmg = \"1d10+4\", type = \"Bludgeoning\" }}, pp = 11, pi = 11, stealth = 0, hab = {\"Grassland\"}, ctypes = {\"Beast\"}, pb = 2, conm = 2, ab = {19, 11, 15, 2, 12, 5}, beast = true, sc = { Strength = 19, Dexterity = 11, Constitution = 15 }, ko = \"안킬로사우루스\", multi = \"The ankylosaurus makes two Tail attacks.\", what = \"Huge Beast (Dinosaur)\" },\r\n[\"Ape\"] = { ac = 12, hp = 19, init = 2, speed = 30, cr = \"1/2\", xp = 100, saves = { Strength = 3, Dexterity = 2, Constitution = 2, Intelligence = -2, Wisdom = 1, Charisma = -2 }, attacks = {{ name = \"Fist\", hit = 5, dmg = \"1d4+3\", type = \"Bludgeoning\" }, { name = \"Rock (Recharge 6)\", hit = 5, dmg = \"2d6+3\", k = \"r\", type = \"Bludgeoning\" }}, pp = 13, pi = 11, stealth = 2, hab = {\"Forest\"}, ctypes = {\"Beast\"}, pb = 2, conm = 2, ab = {16, 14, 14, 6, 12, 7}, beast = true, sc = { Strength = 16, Dexterity = 14, Constitution = 14 }, sk = { Athletics = 5, Perception = 3 }, ko = \"유인원\", multi = \"The ape makes two Fist attacks.\", acts = \"Rock (Recharge 6)\", what = \"Medium Beast\" },\r\n[\"Archelon\"] = { ac = 17, hp = 90, init = 3, speed = 20, cr = \"4\", xp = 1100, saves = { Strength = 4, Dexterity = 3, Constitution = 1, Intelligence = -3, Wisdom = 2, Charisma = -2 }, attacks = {{ name = \"Bite\", hit = 6, dmg = \"3d6+4\", type = \"Piercing\" }}, pp = 12, pi = 12, stealth = 5, hab = {\"Coastal\", \"Underwater\"}, ctypes = {\"Beast\"}, pb = 2, conm = 1, ab = {18, 16, 13, 4, 14, 6}, beast = true, sc = { Strength = 18, Dexterity = 16, Constitution = 13 }, sk = { Stealth = 5 }, swim = true, ko = \"아르켈론\", multi = \"The archelon makes two Bite attacks.\", what = \"Huge Beast (Dinosaur)\" },\r\n[\"Baboon\"] = { ac = 12, hp = 3, init = 2, speed = 30, cr = \"0\", xp = 10, saves = { Strength = -1, Dexterity = 2, Constitution = 0, Intelligence = -3, Wisdom = 1, Charisma = -2 }, attacks = {{ name = \"Bite\", hit = 1, dmg = \"1d4-1\", type = \"Piercing\" }}, pp = 11, pi = 11, stealth = 2, hab = {\"Forest\"}, ctypes = {\"Beast\"}, pb = 2, conm = 0, ab = {8, 14, 11, 4, 12, 6}, beast = true, sc = { Strength = 8, Dexterity = 14, Constitution = 11 }, ko = \"개코원숭이\", what = \"Small Beast\" },\r\n[\"Badger\"] = { ac = 11, hp = 5, init = 0, speed = 20, cr = \"0\", xp = 10, saves = { Strength = 0, Dexterity = 0, Constitution = 3, Intelligence = -4, Wisdom = 1, Charisma = -3 }, attacks = {{ name = \"Bite\", hit = 2, dmg = \"1\", type = \"Piercing\" }}, pp = 13, pi = 11, stealth = 0, res = {\"Poison\"}, hab = {\"Forest\"}, ctypes = {\"Beast\"}, pb = 2, conm = 3, ab = {10, 11, 16, 2, 12, 5}, beast = true, sc = { Strength = 10, Dexterity = 11, Constitution = 16 }, sk = { Perception = 3 }, ko = \"오소리\", what = \"Tiny Beast\" },\r\n[\"Bat\"] = { ac = 12, hp = 1, init = 2, speed = 5, cr = \"0\", xp = 10, saves = { Strength = -4, Dexterity = 2, Constitution = -1, Intelligence = -4, Wisdom = 1, Charisma = -3 }, attacks = {{ name = \"Bite\", hit = 4, dmg = \"1\", type = \"Piercing\" }}, pp = 11, pi = 11, stealth = 2, hab = {\"Forest\"}, ctypes = {\"Beast\"}, pb = 2, conm = -1, ab = {2, 15, 8, 2, 12, 4}, beast = true, sc = { Strength = 2, Dexterity = 15, Constitution = 8 }, fly = true, ko = \"박쥐\", what = \"Tiny Beast\" },\r\n[\"Black Bear\"] = { ac = 11, hp = 19, init = 1, speed = 30, cr = \"1/2\", xp = 100, saves = { Strength = 2, Dexterity = 1, Constitution = 2, Intelligence = -4, Wisdom = 1, Charisma = -2 }, attacks = {{ name = \"Rend\", hit = 4, dmg = \"1d6+2\", type = \"Slashing\" }}, pp = 15, pi = 11, stealth = 1, hab = {\"Forest\"}, ctypes = {\"Beast\"}, pb = 2, conm = 2, ab = {15, 12, 14, 2, 12, 7}, beast = true, sc = { Strength = 15, Dexterity = 12, Constitution = 14 }, sk = { Perception = 5 }, swim = true, ko = \"검은 곰\", multi = \"The bear makes two Rend attacks.\", what = \"Medium Beast\" },\r\n[\"Blood Hawk\"] = { ac = 12, hp = 7, init = 2, speed = 10, cr = \"1/8\", xp = 25, saves = { Strength = -2, Dexterity = 2, Constitution = 0, Intelligence = -4, Wisdom = 2, Charisma = -3 }, attacks = {{ name = \"Beak\", hit = 4, dmg = \"1d4+2\", vsb = \"1d8+2\", type = \"Piercing\" }}, pp = 16, pi = 12, stealth = 2, hab = {\"Coastal\", \"Grassland\", \"Mountain\"}, ctypes = {\"Beast\"}, pb = 2, conm = 0, ab = {6, 14, 10, 3, 14, 5}, beast = true, sc = { Strength = 6, Dexterity = 14, Constitution = 10 }, sk = { Perception = 6 }, fly = true, ko = \"피매\", what = \"Small Beast\" },\r\n[\"Boar\"] = { ac = 11, hp = 13, init = 0, speed = 40, cr = \"1/4\", xp = 50, saves = { Strength = 1, Dexterity = 0, Constitution = 2, Intelligence = -4, Wisdom = -1, Charisma = -3 }, attacks = {{ name = \"Gore\", hit = 3, dmg = \"1d6+1\", type = \"Piercing\" }}, pp = 9, pi = 9, stealth = 0, hab = {\"Forest\"}, ctypes = {\"Beast\"}, pb = 2, conm = 2, ab = {13, 11, 14, 2, 9, 5}, beast = true, sc = { Strength = 13, Dexterity = 11, Constitution = 14 }, ko = \"멧돼지\", what = \"Medium Beast\" },\r\n[\"Brown Bear\"] = { ac = 11, hp = 22, init = 1, speed = 40, cr = \"1\", xp = 200, saves = { Strength = 3, Dexterity = 1, Constitution = 2, Intelligence = -4, Wisdom = 1, Charisma = -2 }, attacks = {{ name = \"Bite\", hit = 5, dmg = \"1d8+3\", type = \"Piercing\" }, { name = \"Claw\", hit = 5, dmg = \"1d4+3\", type = \"Slashing\" }}, pp = 13, pi = 11, stealth = 1, hab = {\"Forest\", \"Hill\"}, ctypes = {\"Beast\"}, pb = 2, conm = 2, ab = {17, 12, 15, 2, 13, 7}, beast = true, sc = { Strength = 17, Dexterity = 12, Constitution = 15 }, sk = { Perception = 3 }, ko = \"갈색 곰\", multi = \"The bear makes one Bite attack and one Claw attack.\", what = \"Large Beast\" },\r\n[\"Camel\"] = { ac = 10, hp = 17, init = -1, speed = 50, cr = \"1/8\", xp = 25, saves = { Strength = 2, Dexterity = -1, Constitution = 5, Intelligence = -4, Wisdom = 0, Charisma = -3 }, attacks = {{ name = \"Bite\", hit = 4, dmg = \"1d4+2\", type = \"Bludgeoning\" }}, pp = 10, pi = 10, stealth = -1, hab = {\"Desert\"}, ctypes = {\"Beast\"}, pb = 2, conm = 3, ab = {15, 8, 17, 2, 11, 5}, beast = true, sc = { Strength = 15, Dexterity = 8, Constitution = 17 }, ko = \"낙타\", what = \"Large Beast\" },\r\n[\"Cat\"] = { ac = 12, hp = 2, init = 2, speed = 40, cr = \"0\", xp = 10, saves = { Strength = -4, Dexterity = 4, Constitution = 0, Intelligence = -4, Wisdom = 1, Charisma = -2 }, attacks = {{ name = \"Scratch\", hit = 4, dmg = \"1\", type = \"Slashing\" }}, pp = 13, pi = 11, stealth = 4, hab = {\"Forest\", \"Urban\"}, ctypes = {\"Beast\"}, pb = 2, conm = 0, ab = {3, 15, 10, 3, 12, 7}, beast = true, sc = { Strength = 3, Dexterity = 15, Constitution = 10 }, sk = { Perception = 3, Stealth = 4 }, ko = \"고양이\", what = \"Tiny Beast\" },\r\n[\"Constrictor Snake\"] = { ac = 13, hp = 13, init = 2, speed = 30, cr = \"1/4\", xp = 50, saves = { Strength = 2, Dexterity = 2, Constitution = 1, Intelligence = -5, Wisdom = 0, Charisma = -4 }, attacks = {{ name = \"Bite\", hit = 4, dmg = \"1d8+2\", type = \"Piercing\" }}, pp = 12, pi = 10, stealth = 4, hab = {\"Desert\", \"Swamp\"}, ctypes = {\"Beast\"}, pb = 2, conm = 1, ab = {15, 14, 12, 1, 10, 3}, beast = true, sc = { Strength = 15, Dexterity = 14, Constitution = 12 }, sk = { Perception = 2, Stealth = 4 }, swim = true, ko = \"구렁이\", sfx = {{ n = \"Constrict\", s = \"Strength\", dc = 12, d = \"3d4\", t = \"Bludgeoning\" }}, what = \"Large Beast\" },\r\n[\"Crab\"] = { ac = 11, hp = 3, init = 0, speed = 20, cr = \"0\", xp = 10, saves = { Strength = -2, Dexterity = 0, Constitution = 1, Intelligence = -5, Wisdom = -1, Charisma = -4 }, attacks = {{ name = \"Claw\", hit = 2, dmg = \"1\", type = \"Bludgeoning\" }}, pp = 9, pi = 9, stealth = 2, hab = {\"Coastal\", \"Underwater\"}, ctypes = {\"Beast\"}, pb = 2, conm = 1, ab = {6, 11, 12, 1, 8, 2}, beast = true, sc = { Strength = 6, Dexterity = 11, Constitution = 12 }, sk = { Stealth = 2 }, swim = true, ko = \"게\", what = \"Tiny Beast\" },\r\n[\"Crocodile\"] = { ac = 12, hp = 13, init = 0, speed = 20, cr = \"1/2\", xp = 100, saves = { Strength = 2, Dexterity = 0, Constitution = 3, Intelligence = -4, Wisdom = 0, Charisma = -3 }, attacks = {{ name = \"Bite\", hit = 4, dmg = \"1d8+2\", type = \"Piercing\" }}, pp = 10, pi = 10, stealth = 2, hab = {\"Swamp\"}, ctypes = {\"Beast\"}, pb = 2, conm = 1, ab = {15, 10, 13, 2, 10, 5}, beast = true, sc = { Strength = 15, Dexterity = 10, Constitution = 13 }, sk = { Stealth = 2 }, swim = true, ko = \"악어\", what = \"Large Beast\" },\r\n[\"Deer\"] = { ac = 13, hp = 4, init = 3, speed = 50, cr = \"0\", xp = 10, saves = { Strength = 0, Dexterity = 3, Constitution = 0, Intelligence = -4, Wisdom = 2, Charisma = -3 }, attacks = {{ name = \"Ram\", hit = 2, dmg = \"1d4\", type = \"Bludgeoning\" }}, pp = 14, pi = 12, stealth = 3, hab = {\"Forest\", \"Grassland\"}, ctypes = {\"Beast\"}, pb = 2, conm = 0, ab = {11, 16, 11, 2, 14, 5}, beast = true, sc = { Strength = 11, Dexterity = 16, Constitution = 11 }, sk = { Perception = 4 }, ko = \"사슴\", what = \"Medium Beast\" },\r\n[\"Dire Wolf\"] = { ac = 14, hp = 22, init = 2, speed = 50, cr = \"1\", xp = 200, saves = { Strength = 3, Dexterity = 2, Constitution = 2, Intelligence = -4, Wisdom = 1, Charisma = -2 }, attacks = {{ name = \"Bite\", hit = 5, dmg = \"1d10+3\", type = \"Piercing\" }}, pp = 15, pi = 11, stealth = 4, hab = {\"Forest\", \"Grassland\", \"Hill\"}, ctypes = {\"Beast\"}, pb = 2, conm = 2, ab = {17, 15, 15, 3, 12, 7}, beast = true, sc = { Strength = 17, Dexterity = 15, Constitution = 15 }, sk = { Perception = 5, Stealth = 4 }, ko = \"다이어 울프\", what = \"Large Beast\" },\r\n[\"Draft Horse\"] = { ac = 10, hp = 15, init = 0, speed = 40, cr = \"1/4\", xp = 50, saves = { Strength = 4, Dexterity = 0, Constitution = 2, Intelligence = -4, Wisdom = 0, Charisma = -2 }, attacks = {{ name = \"Hooves\", hit = 6, dmg = \"1d4+4\", type = \"Bludgeoning\" }}, pp = 10, pi = 10, stealth = 0, hab = {\"Grassland\", \"Urban\"}, ctypes = {\"Beast\"}, pb = 2, conm = 2, ab = {18, 10, 15, 2, 11, 7}, beast = true, sc = { Strength = 18, Dexterity = 10, Constitution = 15 }, ko = \"짐말\", what = \"Large Beast\" },\r\n[\"Eagle\"] = { ac = 12, hp = 4, init = 2, speed = 10, cr = \"0\", xp = 10, saves = { Strength = -2, Dexterity = 2, Constitution = 1, Intelligence = -4, Wisdom = 2, Charisma = -2 }, attacks = {{ name = \"Talons\", hit = 4, dmg = \"1d4+2\", type = \"Slashing\" }}, pp = 16, pi = 12, stealth = 2, hab = {\"Grassland\"}, ctypes = {\"Beast\"}, pb = 2, conm = 1, ab = {6, 15, 12, 2, 14, 7}, beast = true, sc = { Strength = 6, Dexterity = 15, Constitution = 12 }, sk = { Perception = 6 }, fly = true, ko = \"독수리\", what = \"Small Beast\" },\r\n[\"Elephant\"] = { ac = 12, hp = 76, init = -1, speed = 40, cr = \"4\", xp = 1100, saves = { Strength = 6, Dexterity = -1, Constitution = 3, Intelligence = -4, Wisdom = 0, Charisma = -2 }, attacks = {{ name = \"Gore\", hit = 8, dmg = \"2d8+6\", type = \"Piercing\" }}, pp = 10, pi = 10, stealth = -1, hab = {\"Grassland\"}, ctypes = {\"Beast\"}, pb = 2, conm = 3, ab = {22, 9, 17, 3, 11, 6}, beast = true, sc = { Strength = 22, Dexterity = 9, Constitution = 17 }, ko = \"코끼리\", sfx = {{ n = \"Trample\", s = \"Dexterity\", dc = 16, d = \"2d10+6\", t = \"Bludgeoning\", h = true }}, multi = \"The elephant makes two Gore attacks.\", what = \"Huge Beast\" },\r\n[\"Elk\"] = { ac = 10, hp = 11, init = 0, speed = 50, cr = \"1/4\", xp = 50, saves = { Strength = 3, Dexterity = 0, Constitution = 0, Intelligence = -4, Wisdom = 0, Charisma = -2 }, attacks = {{ name = \"Ram\", hit = 5, dmg = \"1d6+3\", type = \"Bludgeoning\" }}, pp = 12, pi = 10, stealth = 0, hab = {\"Forest\", \"Grassland\"}, ctypes = {\"Beast\"}, pb = 2, conm = 0, ab = {16, 10, 11, 2, 10, 6}, beast = true, sc = { Strength = 16, Dexterity = 10, Constitution = 11 }, sk = { Perception = 2 }, ko = \"엘크\", what = \"Large Beast\" },\r\n[\"Flying Snake\"] = { ac = 14, hp = 5, init = 2, speed = 30, cr = \"1/8\", xp = 25, saves = { Strength = -3, Dexterity = 2, Constitution = 0, Intelligence = -4, Wisdom = 1, Charisma = -3 }, attacks = {{ name = \"Bite\", hit = 4, dmg = \"1\", type = \"Piercing\" }}, pp = 11, pi = 11, stealth = 2, hab = {\"Desert\", \"Forest\"}, ctypes = {\"Monstrosity\"}, pb = 2, conm = 0, ab = {4, 15, 11, 2, 12, 5}, fly = true, swim = true, ko = \"날뱀\", what = \"Tiny Monstrosity\" },\r\n[\"Frog\"] = { ac = 11, hp = 1, init = 1, speed = 20, cr = \"0\", xp = 10, saves = { Strength = -5, Dexterity = 1, Constitution = -1, Intelligence = -5, Wisdom = -1, Charisma = -4 }, attacks = {{ name = \"Bite\", hit = 3, dmg = \"1\", type = \"Piercing\" }}, pp = 11, pi = 9, stealth = 3, hab = {\"Swamp\"}, ctypes = {\"Beast\"}, pb = 2, conm = -1, ab = {1, 13, 8, 1, 8, 3}, beast = true, sc = { Strength = 1, Dexterity = 13, Constitution = 8 }, sk = { Perception = 1, Stealth = 3 }, swim = true, ko = \"개구리\", what = \"Tiny Beast\" },\r\n[\"Giant Ape\"] = { ac = 12, hp = 168, init = 5, speed = 40, cr = \"7\", xp = 2900, saves = { Strength = 6, Dexterity = 2, Constitution = 4, Intelligence = -3, Wisdom = 1, Charisma = -2 }, attacks = {{ name = \"Fist\", hit = 9, dmg = \"3d10+6\", type = \"Bludgeoning\" }}, pp = 14, pi = 11, stealth = 2, hab = {\"Forest\", \"Mountain\"}, ctypes = {\"Beast\"}, pb = 3, conm = 4, ab = {23, 14, 18, 5, 12, 7}, beast = true, sc = { Strength = 23, Dexterity = 14, Constitution = 18 }, sk = { Athletics = 9, Perception = 4, Survival = 4 }, ko = \"거대 유인원\", sfx = {{ n = \"Boulder Toss\", s = \"Dexterity\", dc = 17, d = \"7d6\", t = \"Bludgeoning\", h = true, o = \"Recharge 6\" }}, multi = \"The ape makes two Fist attacks.\", acts = \"Leap (Bonus Action)\", what = \"Huge Beast\" },\r\n[\"Giant Badger\"] = { ac = 13, hp = 15, init = 0, speed = 30, cr = \"1/4\", xp = 50, saves = { Strength = 1, Dexterity = 0, Constitution = 3, Intelligence = -4, Wisdom = 1, Charisma = -3 }, attacks = {{ name = \"Bite\", hit = 3, dmg = \"2d4+1\", type = \"Piercing\" }}, pp = 13, pi = 11, stealth = 0, res = {\"Poison\"}, hab = {\"Forest\"}, ctypes = {\"Beast\"}, pb = 2, conm = 3, ab = {13, 10, 17, 2, 12, 5}, beast = true, sc = { Strength = 13, Dexterity = 10, Constitution = 17 }, sk = { Perception = 3 }, ko = \"거대 오소리\", what = \"Medium Beast\" },\r\n[\"Giant Bat\"] = { ac = 13, hp = 22, init = 3, speed = 10, cr = \"1/4\", xp = 50, saves = { Strength = 2, Dexterity = 3, Constitution = 0, Intelligence = -4, Wisdom = 1, Charisma = -2 }, attacks = {{ name = \"Bite\", hit = 5, dmg = \"1d6+3\", type = \"Piercing\" }}, pp = 11, pi = 11, stealth = 3, hab = {\"Ruins\", \"Underdark\"}, ctypes = {\"Beast\"}, pb = 2, conm = 0, ab = {15, 16, 11, 2, 12, 6}, beast = true, sc = { Strength = 15, Dexterity = 16, Constitution = 11 }, fly = true, ko = \"거대 박쥐\", what = \"Large Beast\" },\r\n[\"Giant Boar\"] = { ac = 13, hp = 42, init = 0, speed = 40, cr = \"2\", xp = 450, saves = { Strength = 5, Dexterity = 0, Constitution = 3, Intelligence = -4, Wisdom = -2, Charisma = -3 }, attacks = {{ name = \"Gore\", hit = 5, dmg = \"2d6+3\", type = \"Piercing\" }}, pp = 8, pi = 8, stealth = 0, hab = {\"Forest\", \"Hill\"}, ctypes = {\"Beast\"}, pb = 2, conm = 3, ab = {17, 10, 16, 2, 7, 5}, beast = true, sc = { Strength = 17, Dexterity = 10, Constitution = 16 }, ko = \"거대 멧돼지\", what = \"Large Beast\" },\r\n[\"Giant Centipede\"] = { ac = 14, hp = 9, init = 2, speed = 30, cr = \"1/4\", xp = 50, saves = { Strength = -3, Dexterity = 2, Constitution = 1, Intelligence = -5, Wisdom = -2, Charisma = -4 }, attacks = {{ name = \"Bite\", hit = 4, dmg = \"1d4+2\", type = \"Piercing\" }}, pp = 8, pi = 8, stealth = 2, hab = {\"Forest\", \"Ruins\"}, ctypes = {\"Beast\"}, pb = 2, conm = 1, ab = {5, 14, 12, 1, 7, 3}, beast = true, sc = { Strength = 5, Dexterity = 14, Constitution = 12 }, ko = \"거대 지네\", what = \"Small Beast\" },\r\n[\"Giant Constrictor Snake\"] = { ac = 12, hp = 60, init = 2, speed = 30, cr = \"2\", xp = 450, saves = { Strength = 4, Dexterity = 2, Constitution = 1, Intelligence = -5, Wisdom = 0, Charisma = -4 }, attacks = {{ name = \"Bite\", hit = 6, dmg = \"2d6+4\", type = \"Piercing\" }}, pp = 12, pi = 10, stealth = 2, hab = {\"Swamp\"}, ctypes = {\"Beast\"}, pb = 2, conm = 1, ab = {19, 14, 12, 1, 10, 3}, beast = true, sc = { Strength = 19, Dexterity = 14, Constitution = 12 }, sk = { Perception = 2 }, swim = true, ko = \"거대 구렁이\", sfx = {{ n = \"Constrict\", s = \"Strength\", dc = 14, d = \"2d8+4\", t = \"Bludgeoning\" }}, multi = \"The snake makes one Bite attack and uses Constrict.\", what = \"Huge Beast\" },\r\n[\"Giant Crab\"] = { ac = 15, hp = 13, init = 1, speed = 30, cr = \"1/8\", xp = 25, saves = { Strength = 1, Dexterity = 1, Constitution = 0, Intelligence = -5, Wisdom = -1, Charisma = -4 }, attacks = {{ name = \"Claw\", hit = 3, dmg = \"1d6+1\", type = \"Bludgeoning\" }}, pp = 9, pi = 9, stealth = 3, hab = {\"Coastal\", \"Underwater\"}, ctypes = {\"Beast\"}, pb = 2, conm = 0, ab = {13, 13, 11, 1, 9, 3}, beast = true, sc = { Strength = 13, Dexterity = 13, Constitution = 11 }, sk = { Stealth = 3 }, swim = true, ko = \"거대 게\", what = \"Medium Beast\" },\r\n[\"Giant Crocodile\"] = { ac = 14, hp = 85, init = -1, speed = 30, cr = \"5\", xp = 1800, saves = { Strength = 5, Dexterity = -1, Constitution = 3, Intelligence = -4, Wisdom = 0, Charisma = -2 }, attacks = {{ name = \"Bite\", hit = 8, dmg = \"3d10+5\", type = \"Piercing\" }, { name = \"Tail\", hit = 8, dmg = \"3d8+5\", type = \"Bludgeoning\" }}, pp = 10, pi = 10, stealth = 5, hab = {\"Swamp\"}, ctypes = {\"Beast\"}, pb = 3, conm = 3, ab = {21, 9, 17, 2, 10, 7}, beast = true, sc = { Strength = 21, Dexterity = 9, Constitution = 17 }, sk = { Stealth = 5 }, swim = true, ko = \"거대 악어\", multi = \"The crocodile makes one Bite attack and one Tail attack.\", what = \"Huge Beast\" },\r\n[\"Giant Eagle\"] = { ac = 13, hp = 26, init = 3, speed = 10, cr = \"1\", xp = 200, saves = { Strength = 3, Dexterity = 3, Constitution = 1, Intelligence = -1, Wisdom = 2, Charisma = 0 }, attacks = {{ name = \"Rend\", hit = 5, dmg = \"1d4+3+1d6\" }}, pp = 16, pi = 12, stealth = 3, res = {\"Necrotic\", \"Radiant\"}, hab = {\"Coastal\", \"Grassland\", \"Hill\", \"Mountain\"}, ctypes = {\"Celestial\"}, pb = 2, conm = 1, ab = {16, 17, 13, 8, 14, 10}, fly = true, ko = \"거대 독수리\", multi = \"The eagle makes two Rend attacks.\", what = \"Large Celestial\" },\r\n[\"Giant Elk\"] = { ac = 14, hp = 42, init = 6, speed = 60, cr = \"2\", xp = 450, saves = { Strength = 6, Dexterity = 6, Constitution = 2, Intelligence = -2, Wisdom = 2, Charisma = 0 }, attacks = {{ name = \"Ram\", hit = 6, dmg = \"2d6+4+2d4\" }}, pp = 14, pi = 12, stealth = 4, res = {\"Necrotic\", \"Radiant\"}, hab = {\"Forest\"}, ctypes = {\"Celestial\"}, pb = 2, conm = 2, ab = {19, 18, 14, 7, 14, 10}, ko = \"거대 엘크\", what = \"Huge Celestial\" },\r\n[\"Giant Fire Beetle\"] = { ac = 13, hp = 4, init = 0, speed = 30, cr = \"0\", xp = 10, saves = { Strength = -1, Dexterity = 0, Constitution = 1, Intelligence = -5, Wisdom = -2, Charisma = -4 }, attacks = {{ name = \"Bite\", hit = 1, dmg = \"1\", type = \"Fire\" }}, pp = 8, pi = 8, stealth = 0, res = {\"Fire\"}, hab = {\"Ruins\", \"Underdark\"}, ctypes = {\"Beast\"}, pb = 2, conm = 1, ab = {8, 10, 12, 1, 7, 3}, beast = true, sc = { Strength = 8, Dexterity = 10, Constitution = 12 }, ko = \"거대 불딱정벌레\", what = \"Small Beast\" },\r\n[\"Giant Frog\"] = { ac = 11, hp = 18, init = 1, speed = 30, cr = \"1/4\", xp = 50, saves = { Strength = 1, Dexterity = 1, Constitution = 0, Intelligence = -4, Wisdom = 0, Charisma = -4 }, attacks = {{ name = \"Bite\", hit = 3, dmg = \"1d6+2\", type = \"Piercing\" }}, pp = 12, pi = 10, stealth = 4, hab = {\"Swamp\"}, ctypes = {\"Beast\"}, pb = 2, conm = 0, ab = {12, 13, 11, 2, 10, 3}, beast = true, sc = { Strength = 12, Dexterity = 13, Constitution = 11 }, sk = { Perception = 2, Stealth = 4 }, swim = true, ko = \"거대 개구리\", sfx = {{ n = \"Swallow\", d = \"2d4\", t = \"Acid\" }}, what = \"Medium Beast\" },\r\n[\"Giant Goat\"] = { ac = 11, hp = 19, init = 1, speed = 40, cr = \"1/2\", xp = 100, saves = { Strength = 5, Dexterity = 1, Constitution = 1, Intelligence = -4, Wisdom = 1, Charisma = -2 }, attacks = {{ name = \"Ram\", hit = 5, dmg = \"1d6+3\", type = \"Bludgeoning\" }}, pp = 13, pi = 11, stealth = 1, hab = {\"Hill\", \"Mountain\"}, ctypes = {\"Beast\"}, pb = 2, conm = 1, ab = {17, 13, 12, 3, 12, 6}, beast = true, sc = { Strength = 17, Dexterity = 13, Constitution = 12 }, sk = { Perception = 3 }, ko = \"거대 염소\", what = \"Large Beast\" },\r\n[\"Giant Hyena\"] = { ac = 12, hp = 45, init = 2, speed = 50, cr = \"1\", xp = 200, saves = { Strength = 3, Dexterity = 2, Constitution = 2, Intelligence = -4, Wisdom = 1, Charisma = -2 }, attacks = {{ name = \"Bite\", hit = 5, dmg = \"2d6+3\", type = \"Piercing\" }}, pp = 13, pi = 11, stealth = 2, hab = {\"Desert\", \"Grassland\"}, ctypes = {\"Beast\"}, pb = 2, conm = 2, ab = {16, 14, 14, 2, 12, 7}, beast = true, sc = { Strength = 16, Dexterity = 14, Constitution = 14 }, sk = { Perception = 3 }, ko = \"거대 하이에나\", acts = \"Rampage (1/Day) (Bonus Action)\", what = \"Large Beast\" },\r\n[\"Giant Lizard\"] = { ac = 12, hp = 19, init = 1, speed = 40, cr = \"1/4\", xp = 50, saves = { Strength = 2, Dexterity = 3, Constitution = 1, Intelligence = -4, Wisdom = 0, Charisma = -3 }, attacks = {{ name = \"Bite\", hit = 4, dmg = \"1d8+2\", type = \"Piercing\" }}, pp = 10, pi = 10, stealth = 1, hab = {\"Desert\"}, ctypes = {\"Beast\"}, pb = 2, conm = 1, ab = {15, 12, 13, 2, 10, 5}, beast = true, sc = { Strength = 15, Dexterity = 12, Constitution = 13 }, ko = \"거대 도마뱀\", what = \"Large Beast\" },\r\n[\"Giant Octopus\"] = { ac = 11, hp = 45, init = 1, speed = 10, cr = \"1\", xp = 200, saves = { Strength = 3, Dexterity = 1, Constitution = 1, Intelligence = -3, Wisdom = 0, Charisma = -3 }, attacks = {{ name = \"Tentacles\", hit = 5, dmg = \"2d6+3\", type = \"Bludgeoning\" }}, pp = 14, pi = 10, stealth = 5, hab = {\"Underwater\"}, ctypes = {\"Beast\"}, pb = 2, conm = 1, ab = {17, 13, 13, 5, 10, 4}, beast = true, sc = { Strength = 17, Dexterity = 13, Constitution = 13 }, sk = { Perception = 4, Stealth = 5 }, swim = true, ko = \"거대 문어\", acts = \"Ink Cloud (1/Day) (Reaction)\", what = \"Large Beast\" },\r\n[\"Giant Owl\"] = { ac = 12, hp = 19, init = 2, speed = 5, cr = \"1/4\", xp = 50, saves = { Strength = 1, Dexterity = 2, Constitution = 1, Intelligence = 0, Wisdom = 4, Charisma = 0 }, attacks = {{ name = \"Talons\", hit = 4, dmg = \"1d10+2\", type = \"Slashing\" }}, pp = 16, pi = 12, stealth = 6, res = {\"Necrotic\", \"Radiant\"}, hab = {\"Forest\"}, ctypes = {\"Celestial\"}, pb = 2, conm = 1, ab = {13, 15, 12, 10, 14, 10}, fly = true, ko = \"거대 올빼미\", acts = \"Spellcasting\", what = \"Large Celestial\" },\r\n[\"Giant Rat\"] = { ac = 13, hp = 7, init = 3, speed = 30, cr = \"1/8\", xp = 25, saves = { Strength = -2, Dexterity = 5, Constitution = 0, Intelligence = -4, Wisdom = 0, Charisma = -3 }, attacks = {{ name = \"Bite\", hit = 5, dmg = \"1d4+3\", type = \"Piercing\" }}, pp = 12, pi = 10, stealth = 3, hab = {\"Ruins\", \"Urban\"}, ctypes = {\"Beast\"}, pb = 2, conm = 0, ab = {7, 16, 11, 2, 10, 4}, beast = true, sc = { Strength = 7, Dexterity = 16, Constitution = 11 }, sk = { Perception = 2 }, ko = \"거대 쥐\", what = \"Small Beast\" },\r\n[\"Giant Scorpion\"] = { ac = 15, hp = 52, init = 1, speed = 40, cr = \"3\", xp = 700, saves = { Strength = 3, Dexterity = 1, Constitution = 2, Intelligence = -5, Wisdom = -1, Charisma = -4 }, attacks = {{ name = \"Claw\", hit = 5, dmg = \"1d6+3\", type = \"Bludgeoning\" }, { name = \"Sting\", hit = 5, dmg = \"1d8+3+2d10\" }}, pp = 9, pi = 9, stealth = 1, hab = {\"Desert\"}, ctypes = {\"Beast\"}, pb = 2, conm = 2, ab = {16, 13, 15, 1, 9, 3}, beast = true, sc = { Strength = 16, Dexterity = 13, Constitution = 15 }, ko = \"거대 전갈\", multi = \"The scorpion makes two Claw attacks and one Sting attack.\", what = \"Large Beast\" },\r\n[\"Giant Seahorse\"] = { ac = 14, hp = 16, init = 1, speed = 5, cr = \"1/2\", xp = 100, saves = { Strength = 2, Dexterity = 1, Constitution = 0, Intelligence = -4, Wisdom = 1, Charisma = -3 }, attacks = {{ name = \"Ram\", hit = 4, dmg = \"2d6+2\", alt = \"2d8+2\", altwhy = \"if the seahorse moved 20+ feet straight toward the target immediately before the hit\", type = \"Bludgeoning\" }}, pp = 11, pi = 11, stealth = 1, hab = {\"Underwater\"}, ctypes = {\"Beast\"}, pb = 2, conm = 0, ab = {15, 12, 11, 2, 12, 5}, beast = true, sc = { Strength = 15, Dexterity = 12, Constitution = 11 }, swim = true, ko = \"거대 해마\", acts = \"Bubble Dash (Bonus Action)\", what = \"Large Beast\" },\r\n[\"Giant Shark\"] = { ac = 13, hp = 92, init = 3, speed = 5, cr = \"5\", xp = 1800, saves = { Strength = 6, Dexterity = 0, Constitution = 5, Intelligence = -5, Wisdom = 0, Charisma = -3 }, attacks = {{ name = \"Bite\", hit = 9, dmg = \"3d10+6\", type = \"Piercing\" }}, pp = 13, pi = 10, stealth = 0, hab = {\"Underwater\"}, ctypes = {\"Beast\"}, pb = 3, conm = 5, ab = {23, 11, 21, 1, 10, 5}, beast = true, sc = { Strength = 23, Dexterity = 11, Constitution = 21 }, sk = { Perception = 3 }, swim = true, ko = \"거대 상어\", multi = \"The shark makes two Bite attacks.\", what = \"Huge Beast\" },\r\n[\"Giant Spider\"] = { ac = 14, hp = 26, init = 3, speed = 30, cr = \"1\", xp = 200, saves = { Strength = 2, Dexterity = 3, Constitution = 1, Intelligence = -4, Wisdom = 0, Charisma = -3 }, attacks = {{ name = \"Bite\", hit = 5, dmg = \"1d8+3+2d6\" }}, pp = 14, pi = 10, stealth = 7, hab = {\"Forest\", \"Ruins\", \"Swamp\", \"Underdark\"}, ctypes = {\"Beast\"}, pb = 2, conm = 1, ab = {14, 16, 12, 2, 11, 4}, beast = true, sc = { Strength = 14, Dexterity = 16, Constitution = 12 }, sk = { Perception = 4, Stealth = 7 }, ko = \"거대 거미\", sfx = {{ n = \"Web\", s = \"Dexterity\", dc = 13, o = \"Recharge 5-6\" }}, what = \"Large Beast\" },\r\n[\"Giant Toad\"] = { ac = 11, hp = 39, init = 1, speed = 30, cr = \"1\", xp = 200, saves = { Strength = 2, Dexterity = 1, Constitution = 1, Intelligence = -4, Wisdom = 0, Charisma = -4 }, attacks = {{ name = \"Bite\", hit = 4, dmg = \"1d6+2+2d4\" }}, pp = 10, pi = 10, stealth = 1, hab = {\"Swamp\"}, ctypes = {\"Beast\"}, pb = 2, conm = 1, ab = {15, 13, 13, 2, 10, 3}, beast = true, sc = { Strength = 15, Dexterity = 13, Constitution = 13 }, swim = true, ko = \"거대 두꺼비\", sfx = {{ n = \"Swallow\", d = \"3d6\", t = \"Acid\" }}, what = \"Large Beast\" },\r\n[\"Giant Venomous Snake\"] = { ac = 14, hp = 11, init = 4, speed = 40, cr = \"1/4\", xp = 50, saves = { Strength = 0, Dexterity = 4, Constitution = 1, Intelligence = -4, Wisdom = 0, Charisma = -4 }, attacks = {{ name = \"Bite\", hit = 6, dmg = \"1d4+4+1d8\" }}, pp = 12, pi = 10, stealth = 4, hab = {\"Swamp\"}, ctypes = {\"Beast\"}, pb = 2, conm = 1, ab = {10, 18, 13, 2, 10, 3}, beast = true, sc = { Strength = 10, Dexterity = 18, Constitution = 13 }, sk = { Perception = 2 }, swim = true, ko = \"거대 독사\", what = \"Medium Beast\" },\r\n[\"Giant Vulture\"] = { ac = 10, hp = 25, init = 0, speed = 10, cr = \"1\", xp = 200, saves = { Strength = 2, Dexterity = 0, Constitution = 3, Intelligence = -2, Wisdom = 1, Charisma = -2 }, attacks = {{ name = \"Gouge\", hit = 4, dmg = \"2d6+2\", type = \"Piercing\" }}, pp = 13, pi = 11, stealth = 0, res = {\"Necrotic\"}, hab = {\"Desert\", \"Grassland\"}, ctypes = {\"Monstrosity\"}, pb = 2, conm = 3, ab = {15, 10, 16, 6, 12, 7}, fly = true, ko = \"거대 대머리수리\", what = \"Large Monstrosity\" },\r\n[\"Giant Wasp\"] = { ac = 13, hp = 22, init = 2, speed = 10, cr = \"1/2\", xp = 100, saves = { Strength = 0, Dexterity = 2, Constitution = 0, Intelligence = -5, Wisdom = 0, Charisma = -4 }, attacks = {{ name = \"Sting\", hit = 4, dmg = \"1d6+2+2d4\" }}, pp = 10, pi = 10, stealth = 2, hab = {\"Forest\", \"Grassland\"}, ctypes = {\"Beast\"}, pb = 2, conm = 0, ab = {10, 14, 10, 1, 10, 3}, beast = true, sc = { Strength = 10, Dexterity = 14, Constitution = 10 }, fly = true, ko = \"거대 말벌\", what = \"Medium Beast\" },\r\n[\"Giant Weasel\"] = { ac = 13, hp = 9, init = 3, speed = 40, cr = \"1/8\", xp = 25, saves = { Strength = 0, Dexterity = 3, Constitution = 0, Intelligence = -3, Wisdom = 1, Charisma = -3 }, attacks = {{ name = \"Bite\", hit = 5, dmg = \"1d4+3\", type = \"Piercing\" }}, pp = 13, pi = 11, stealth = 5, hab = {\"Forest\"}, ctypes = {\"Beast\"}, pb = 2, conm = 0, ab = {11, 17, 10, 4, 12, 5}, beast = true, sc = { Strength = 11, Dexterity = 17, Constitution = 10 }, sk = { Acrobatics = 5, Perception = 3, Stealth = 5 }, ko = \"거대 족제비\", what = \"Medium Beast\" },\r\n[\"Giant Wolf Spider\"] = { ac = 13, hp = 11, init = 3, speed = 40, cr = \"1/4\", xp = 50, saves = { Strength = 1, Dexterity = 3, Constitution = 1, Intelligence = -4, Wisdom = 1, Charisma = -3 }, attacks = {{ name = \"Bite\", hit = 5, dmg = \"1d4+3+2d4\" }}, pp = 13, pi = 11, stealth = 7, hab = {\"Forest\"}, ctypes = {\"Beast\"}, pb = 2, conm = 1, ab = {12, 16, 13, 3, 12, 4}, beast = true, sc = { Strength = 12, Dexterity = 16, Constitution = 13 }, sk = { Perception = 3, Stealth = 7 }, ko = \"거대 늑대거미\", what = \"Medium Beast\" },\r\n[\"Goat\"] = { ac = 10, hp = 4, init = 0, speed = 40, cr = \"0\", xp = 10, saves = { Strength = 2, Dexterity = 0, Constitution = 0, Intelligence = -4, Wisdom = 0, Charisma = -3 }, attacks = {{ name = \"Ram\", hit = 2, dmg = \"1\", alt = \"1d4\", altwhy = \"if the goat moved 20+ feet straight toward the target immediately before the hit\", type = \"Bludgeoning\" }}, pp = 12, pi = 10, stealth = 0, hab = {\"Hill\", \"Mountain\"}, ctypes = {\"Beast\"}, pb = 2, conm = 0, ab = {11, 10, 11, 2, 10, 5}, beast = true, sc = { Strength = 11, Dexterity = 10, Constitution = 11 }, sk = { Perception = 2 }, ko = \"염소\", what = \"Medium Beast\" },\r\n[\"Hawk\"] = { ac = 13, hp = 1, init = 3, speed = 10, cr = \"0\", xp = 10, saves = { Strength = -3, Dexterity = 3, Constitution = -1, Intelligence = -4, Wisdom = 2, Charisma = -2 }, attacks = {{ name = \"Talons\", hit = 5, dmg = \"1\", type = \"Slashing\" }}, pp = 16, pi = 12, stealth = 3, hab = {\"Forest\"}, ctypes = {\"Beast\"}, pb = 2, conm = -1, ab = {5, 16, 8, 2, 14, 6}, beast = true, sc = { Strength = 5, Dexterity = 16, Constitution = 8 }, sk = { Perception = 6 }, fly = true, ko = \"매\", what = \"Tiny Beast\" },\r\n[\"Hippopotamus\"] = { ac = 14, hp = 82, init = -2, speed = 30, cr = \"4\", xp = 1100, saves = { Strength = 7, Dexterity = -2, Constitution = 2, Intelligence = -4, Wisdom = 1, Charisma = -3 }, attacks = {{ name = \"Bite\", hit = 7, dmg = \"2d10+5\", type = \"Piercing\" }}, pp = 13, pi = 11, stealth = -2, hab = {\"Swamp\"}, ctypes = {\"Beast\"}, pb = 2, conm = 2, ab = {21, 7, 15, 2, 12, 4}, beast = true, sc = { Strength = 21, Dexterity = 7, Constitution = 15 }, sk = { Perception = 3 }, swim = true, ko = \"하마\", multi = \"The hippopotamus makes two Bite attacks.\", what = \"Large Beast\" },\r\n[\"Hunter Shark\"] = { ac = 12, hp = 45, init = 2, speed = 5, cr = \"2\", xp = 450, saves = { Strength = 4, Dexterity = 2, Constitution = 2, Intelligence = -5, Wisdom = 0, Charisma = -3 }, attacks = {{ name = \"Bite\", hit = 6, dmg = \"3d6+4\", type = \"Piercing\" }}, pp = 12, pi = 10, stealth = 2, hab = {\"Coastal\", \"Underwater\"}, ctypes = {\"Beast\"}, pb = 2, conm = 2, ab = {18, 14, 15, 1, 10, 4}, beast = true, sc = { Strength = 18, Dexterity = 14, Constitution = 15 }, sk = { Perception = 2 }, swim = true, ko = \"사냥 상어\", what = \"Large Beast\" },\r\n[\"Hyena\"] = { ac = 11, hp = 5, init = 1, speed = 50, cr = \"0\", xp = 10, saves = { Strength = 0, Dexterity = 1, Constitution = 1, Intelligence = -4, Wisdom = 1, Charisma = -3 }, attacks = {{ name = \"Bite\", hit = 2, dmg = \"1d6\", type = \"Piercing\" }}, pp = 13, pi = 11, stealth = 1, hab = {\"Desert\", \"Grassland\"}, ctypes = {\"Beast\"}, pb = 2, conm = 1, ab = {11, 13, 12, 2, 12, 5}, beast = true, sc = { Strength = 11, Dexterity = 13, Constitution = 12 }, sk = { Perception = 3 }, ko = \"하이에나\", what = \"Medium Beast\" },\r\n[\"Jackal\"] = { ac = 12, hp = 3, init = 2, speed = 40, cr = \"0\", xp = 10, saves = { Strength = -1, Dexterity = 2, Constitution = 0, Intelligence = -4, Wisdom = 1, Charisma = -2 }, attacks = {{ name = \"Bite\", hit = 1, dmg = \"1d4-1\", type = \"Piercing\" }}, pp = 15, pi = 11, stealth = 4, hab = {\"Desert\"}, ctypes = {\"Beast\"}, pb = 2, conm = 0, ab = {8, 15, 11, 3, 12, 6}, beast = true, sc = { Strength = 8, Dexterity = 15, Constitution = 11 }, sk = { Perception = 5, Stealth = 4 }, ko = \"자칼\", what = \"Small Beast\" },\r\n[\"Killer Whale\"] = { ac = 12, hp = 90, init = 2, speed = 5, cr = \"3\", xp = 700, saves = { Strength = 4, Dexterity = 2, Constitution = 1, Intelligence = -4, Wisdom = 1, Charisma = -2 }, attacks = {{ name = \"Bite\", hit = 6, dmg = \"5d6+4\", type = \"Piercing\" }}, pp = 13, pi = 11, stealth = 4, hab = {\"Arctic\", \"Underwater\"}, ctypes = {\"Beast\"}, pb = 2, conm = 1, ab = {19, 14, 13, 3, 12, 7}, beast = true, sc = { Strength = 19, Dexterity = 14, Constitution = 13 }, sk = { Perception = 3, Stealth = 4 }, swim = true, ko = \"범고래\", what = \"Huge Beast\" },\r\n[\"Lion\"] = { ac = 12, hp = 22, init = 2, speed = 50, cr = \"1\", xp = 200, saves = { Strength = 3, Dexterity = 2, Constitution = 0, Intelligence = -4, Wisdom = 1, Charisma = -1 }, attacks = {{ name = \"Rend\", hit = 5, dmg = \"1d8+3\", type = \"Slashing\" }}, pp = 13, pi = 11, stealth = 4, hab = {\"Grassland\"}, ctypes = {\"Beast\"}, pb = 2, conm = 0, ab = {17, 15, 11, 3, 12, 8}, beast = true, sc = { Strength = 17, Dexterity = 15, Constitution = 11 }, sk = { Perception = 3, Stealth = 4 }, ko = \"사자\", sfx = {{ n = \"Roar\", s = \"Wisdom\", dc = 11 }}, multi = \"The lion makes two Rend attacks. It can replace one attack with a use of Roar.\", what = \"Large Beast\" },\r\n[\"Lizard\"] = { ac = 10, hp = 2, init = 0, speed = 20, cr = \"0\", xp = 10, saves = { Strength = -4, Dexterity = 0, Constitution = 0, Intelligence = -5, Wisdom = -1, Charisma = -4 }, attacks = {{ name = \"Bite\", hit = 2, dmg = \"1\", type = \"Piercing\" }}, pp = 9, pi = 9, stealth = 0, hab = {\"Desert\", \"Forest\"}, ctypes = {\"Beast\"}, pb = 2, conm = 0, ab = {2, 11, 10, 1, 8, 3}, beast = true, sc = { Strength = 2, Dexterity = 11, Constitution = 10 }, ko = \"도마뱀\", what = \"Tiny Beast\" },\r\n[\"Mammoth\"] = { ac = 13, hp = 126, init = 2, speed = 50, cr = \"6\", xp = 2300, saves = { Strength = 10, Dexterity = -1, Constitution = 8, Intelligence = -4, Wisdom = 0, Charisma = -2 }, attacks = {{ name = \"Gore\", hit = 10, dmg = \"2d10+7\", type = \"Piercing\" }}, pp = 10, pi = 10, stealth = -1, hab = {\"Arctic\"}, ctypes = {\"Beast\"}, pb = 3, conm = 5, ab = {24, 9, 21, 3, 11, 6}, beast = true, sc = { Strength = 24, Dexterity = 9, Constitution = 21 }, ko = \"매머드\", sfx = {{ n = \"Trample\", s = \"Dexterity\", dc = 18, d = \"4d10+7\", t = \"Bludgeoning\", h = true }}, multi = \"The mammoth makes two Gore attacks.\", what = \"Huge Beast\" },\r\n[\"Mastiff\"] = { ac = 12, hp = 5, init = 2, speed = 40, cr = \"1/8\", xp = 25, saves = { Strength = 1, Dexterity = 2, Constitution = 1, Intelligence = -4, Wisdom = 3, Charisma = -2 }, attacks = {{ name = \"Bite\", hit = 3, dmg = \"1d6+1\", type = \"Piercing\" }}, pp = 15, pi = 11, stealth = 2, hab = {\"Urban\"}, ctypes = {\"Beast\"}, pb = 2, conm = 1, ab = {13, 14, 12, 3, 12, 7}, beast = true, sc = { Strength = 13, Dexterity = 14, Constitution = 12 }, sk = { Perception = 5 }, ko = \"마스티프\", what = \"Medium Beast\" },\r\n[\"Mule\"] = { ac = 10, hp = 11, init = 0, speed = 40, cr = \"1/8\", xp = 25, saves = { Strength = 4, Dexterity = 0, Constitution = 1, Intelligence = -4, Wisdom = 0, Charisma = -3 }, attacks = {{ name = \"Hooves\", hit = 4, dmg = \"1d4+2\", type = \"Bludgeoning\" }}, pp = 10, pi = 10, stealth = 0, hab = {\"Grassland\", \"Urban\"}, ctypes = {\"Beast\"}, pb = 2, conm = 1, ab = {14, 10, 13, 2, 10, 5}, beast = true, sc = { Strength = 14, Dexterity = 10, Constitution = 13 }, ko = \"노새\", what = \"Medium Beast\" },\r\n[\"Octopus\"] = { ac = 12, hp = 3, init = 2, speed = 5, cr = \"0\", xp = 10, saves = { Strength = -3, Dexterity = 2, Constitution = 0, Intelligence = -4, Wisdom = 0, Charisma = -3 }, attacks = {{ name = \"Tentacles\", hit = 4, dmg = \"1\", type = \"Bludgeoning\" }}, pp = 12, pi = 10, stealth = 6, hab = {\"Underwater\"}, ctypes = {\"Beast\"}, pb = 2, conm = 0, ab = {4, 15, 11, 3, 10, 4}, beast = true, sc = { Strength = 4, Dexterity = 15, Constitution = 11 }, sk = { Perception = 2, Stealth = 6 }, swim = true, ko = \"문어\", acts = \"Ink Cloud (1/Day) (Reaction)\", what = \"Small Beast\" },\r\n[\"Owl\"] = { ac = 11, hp = 1, init = 1, speed = 5, cr = \"0\", xp = 10, saves = { Strength = -4, Dexterity = 1, Constitution = -1, Intelligence = -4, Wisdom = 1, Charisma = -2 }, attacks = {{ name = \"Talons\", hit = 3, dmg = \"1\", type = \"Slashing\" }}, pp = 15, pi = 11, stealth = 5, hab = {\"Forest\"}, ctypes = {\"Beast\"}, pb = 2, conm = -1, ab = {3, 13, 8, 2, 12, 7}, beast = true, sc = { Strength = 3, Dexterity = 13, Constitution = 8 }, sk = { Perception = 5, Stealth = 5 }, fly = true, ko = \"올빼미\", what = \"Tiny Beast\" },\r\n[\"Panther\"] = { ac = 13, hp = 13, init = 3, speed = 50, cr = \"1/4\", xp = 50, saves = { Strength = 2, Dexterity = 3, Constitution = 0, Intelligence = -4, Wisdom = 2, Charisma = -2 }, attacks = {{ name = \"Rend\", hit = 5, dmg = \"1d6+3\", type = \"Slashing\" }}, pp = 14, pi = 12, stealth = 7, hab = {\"Forest\"}, ctypes = {\"Beast\"}, pb = 2, conm = 0, ab = {14, 16, 10, 3, 14, 7}, beast = true, sc = { Strength = 14, Dexterity = 16, Constitution = 10 }, sk = { Perception = 4, Stealth = 7 }, ko = \"팬서\", acts = \"Nimble Escape (Bonus Action)\", what = \"Medium Beast\" },\r\n[\"Piranha\"] = { ac = 13, hp = 1, init = 3, speed = 5, cr = \"0\", xp = 10, saves = { Strength = -4, Dexterity = 3, Constitution = -1, Intelligence = -5, Wisdom = -2, Charisma = -4 }, attacks = {{ name = \"Bite\", hit = 5, dmg = \"1\", type = \"Piercing\" }}, pp = 8, pi = 8, stealth = 3, hab = {\"Underwater\"}, ctypes = {\"Beast\"}, pb = 2, conm = -1, ab = {2, 16, 9, 1, 7, 2}, beast = true, sc = { Strength = 2, Dexterity = 16, Constitution = 9 }, swim = true, ko = \"피라냐\", what = \"Tiny Beast\" },\r\n[\"Plesiosaurus\"] = { ac = 13, hp = 68, init = 2, speed = 20, cr = \"2\", xp = 450, saves = { Strength = 4, Dexterity = 2, Constitution = 3, Intelligence = -4, Wisdom = 1, Charisma = -3 }, attacks = {{ name = \"Bite\", hit = 6, dmg = \"2d6+4\", type = \"Piercing\" }}, pp = 13, pi = 11, stealth = 4, hab = {\"Coastal\", \"Underwater\"}, ctypes = {\"Beast\"}, pb = 2, conm = 3, ab = {18, 15, 16, 2, 12, 5}, beast = true, sc = { Strength = 18, Dexterity = 15, Constitution = 16 }, sk = { Perception = 3, Stealth = 4 }, swim = true, ko = \"플레시오사우루스\", what = \"Large Beast (Dinosaur)\" },\r\n[\"Polar Bear\"] = { ac = 12, hp = 42, init = 2, speed = 40, cr = \"2\", xp = 450, saves = { Strength = 5, Dexterity = 2, Constitution = 3, Intelligence = -4, Wisdom = 1, Charisma = -2 }, attacks = {{ name = \"Rend\", hit = 7, dmg = \"1d8+5\", type = \"Slashing\" }}, pp = 15, pi = 11, stealth = 4, res = {\"Cold\"}, hab = {\"Arctic\", \"Mountain\"}, ctypes = {\"Beast\"}, pb = 2, conm = 3, ab = {20, 14, 16, 2, 13, 7}, beast = true, sc = { Strength = 20, Dexterity = 14, Constitution = 16 }, sk = { Perception = 5, Stealth = 4 }, swim = true, ko = \"북극곰\", multi = \"The bear makes two Rend attacks.\", what = \"Large Beast\" },\r\n[\"Pony\"] = { ac = 10, hp = 11, init = 0, speed = 40, cr = \"1/8\", xp = 25, saves = { Strength = 4, Dexterity = 0, Constitution = 1, Intelligence = -4, Wisdom = 0, Charisma = -2 }, attacks = {{ name = \"Hooves\", hit = 4, dmg = \"1d4+2\", type = \"Bludgeoning\" }}, pp = 10, pi = 10, stealth = 0, hab = {\"Grassland\"}, ctypes = {\"Beast\"}, pb = 2, conm = 1, ab = {15, 10, 13, 2, 11, 7}, beast = true, sc = { Strength = 15, Dexterity = 10, Constitution = 13 }, ko = \"조랑말\", what = \"Medium Beast\" },\r\n[\"Pteranodon\"] = { ac = 13, hp = 13, init = 2, speed = 10, cr = \"1/4\", xp = 50, saves = { Strength = 1, Dexterity = 2, Constitution = 0, Intelligence = -4, Wisdom = -1, Charisma = -3 }, attacks = {{ name = \"Bite\", hit = 4, dmg = \"1d8+2\", type = \"Piercing\" }}, pp = 11, pi = 9, stealth = 2, hab = {\"Coastal\", \"Grassland\", \"Mountain\"}, ctypes = {\"Beast\"}, pb = 2, conm = 0, ab = {12, 15, 10, 2, 9, 5}, beast = true, sc = { Strength = 12, Dexterity = 15, Constitution = 10 }, sk = { Perception = 1 }, fly = true, ko = \"프테라노돈\", what = \"Medium Beast (Dinosaur)\" },\r\n[\"Rat\"] = { ac = 10, hp = 1, init = 0, speed = 20, cr = \"0\", xp = 10, saves = { Strength = -4, Dexterity = 0, Constitution = -1, Intelligence = -4, Wisdom = 0, Charisma = -3 }, attacks = {{ name = \"Bite\", hit = 2, dmg = \"1\", type = \"Piercing\" }}, pp = 12, pi = 10, stealth = 0, hab = {\"Ruins\", \"Urban\"}, ctypes = {\"Beast\"}, pb = 2, conm = -1, ab = {2, 11, 9, 2, 10, 4}, beast = true, sc = { Strength = 2, Dexterity = 11, Constitution = 9 }, sk = { Perception = 2 }, ko = \"쥐\", what = \"Tiny Beast\" },\r\n[\"Raven\"] = { ac = 12, hp = 2, init = 2, speed = 10, cr = \"0\", xp = 10, saves = { Strength = -4, Dexterity = 2, Constitution = 0, Intelligence = -3, Wisdom = 1, Charisma = -2 }, attacks = {{ name = \"Beak\", hit = 4, dmg = \"1\", type = \"Piercing\" }}, pp = 13, pi = 11, stealth = 2, hab = {\"Forest\", \"Urban\"}, ctypes = {\"Beast\"}, pb = 2, conm = 0, ab = {2, 14, 10, 5, 13, 6}, beast = true, sc = { Strength = 2, Dexterity = 14, Constitution = 10 }, sk = { Perception = 3 }, fly = true, ko = \"까마귀\", what = \"Tiny Beast\" },\r\n[\"Reef Shark\"] = { ac = 12, hp = 22, init = 2, speed = 5, cr = \"1/2\", xp = 100, saves = { Strength = 2, Dexterity = 2, Constitution = 1, Intelligence = -5, Wisdom = 0, Charisma = -3 }, attacks = {{ name = \"Bite\", hit = 4, dmg = \"2d4+2\", type = \"Piercing\" }}, pp = 12, pi = 10, stealth = 2, hab = {\"Coastal\", \"Underwater\"}, ctypes = {\"Beast\"}, pb = 2, conm = 1, ab = {14, 15, 13, 1, 10, 4}, beast = true, sc = { Strength = 14, Dexterity = 15, Constitution = 13 }, sk = { Perception = 2 }, swim = true, ko = \"산호 상어\", what = \"Medium Beast\" },\r\n[\"Rhinoceros\"] = { ac = 13, hp = 45, init = -1, speed = 40, cr = \"2\", xp = 450, saves = { Strength = 5, Dexterity = -1, Constitution = 2, Intelligence = -4, Wisdom = 1, Charisma = -2 }, attacks = {{ name = \"Gore\", hit = 7, dmg = \"2d8+5\", type = \"Piercing\" }}, pp = 11, pi = 11, stealth = -1, hab = {\"Grassland\"}, ctypes = {\"Beast\"}, pb = 2, conm = 2, ab = {21, 8, 15, 2, 12, 6}, beast = true, sc = { Strength = 21, Dexterity = 8, Constitution = 15 }, ko = \"코뿔소\", what = \"Large Beast\" },\r\n[\"Riding Horse\"] = { ac = 11, hp = 13, init = 1, speed = 60, cr = \"1/4\", xp = 50, saves = { Strength = 3, Dexterity = 1, Constitution = 1, Intelligence = -4, Wisdom = 0, Charisma = -2 }, attacks = {{ name = \"Hooves\", hit = 5, dmg = \"1d8+3\", type = \"Bludgeoning\" }}, pp = 10, pi = 10, stealth = 1, hab = {\"Grassland\", \"Urban\"}, ctypes = {\"Beast\"}, pb = 2, conm = 1, ab = {16, 13, 12, 2, 11, 7}, beast = true, sc = { Strength = 16, Dexterity = 13, Constitution = 12 }, ko = \"승용마\", what = \"Large Beast\" },\r\n[\"Saber-Toothed Tiger\"] = { ac = 13, hp = 52, init = 3, speed = 40, cr = \"2\", xp = 450, saves = { Strength = 6, Dexterity = 5, Constitution = 2, Intelligence = -4, Wisdom = 1, Charisma = -1 }, attacks = {{ name = \"Rend\", hit = 6, dmg = \"2d6+4\", type = \"Slashing\" }}, pp = 15, pi = 11, stealth = 7, hab = {\"Arctic\", \"Mountain\"}, ctypes = {\"Beast\"}, pb = 2, conm = 2, ab = {18, 17, 15, 3, 12, 8}, beast = true, sc = { Strength = 18, Dexterity = 17, Constitution = 15 }, sk = { Perception = 5, Stealth = 7 }, ko = \"검치호\", multi = \"The tiger makes two Rend attacks.\", acts = \"Nimble Escape (Bonus Action)\", what = \"Large Beast\" },\r\n[\"Scorpion\"] = { ac = 11, hp = 1, init = 0, speed = 10, cr = \"0\", xp = 10, saves = { Strength = -4, Dexterity = 0, Constitution = -1, Intelligence = -5, Wisdom = -1, Charisma = -4 }, attacks = {{ name = \"Sting\", hit = 2, dmg = \"1\", type = \"Piercing\" }}, pp = 9, pi = 9, stealth = 0, hab = {\"Desert\"}, ctypes = {\"Beast\"}, pb = 2, conm = -1, ab = {2, 11, 8, 1, 8, 2}, beast = true, sc = { Strength = 2, Dexterity = 11, Constitution = 8 }, ko = \"전갈\", what = \"Tiny Beast\" },\r\n[\"Seahorse\"] = { ac = 12, hp = 1, init = 1, speed = 5, cr = \"0\", xp = 0, saves = { Strength = -5, Dexterity = 1, Constitution = -1, Intelligence = -5, Wisdom = 0, Charisma = -4 }, attacks = {}, pp = 12, pi = 10, stealth = 5, hab = {\"Underwater\"}, ctypes = {\"Beast\"}, pb = 2, conm = -1, ab = {1, 12, 8, 1, 10, 2}, beast = true, sc = { Strength = 1, Dexterity = 12, Constitution = 8 }, sk = { Perception = 2, Stealth = 5 }, swim = true, ko = \"해마\", acts = \"Bubble Dash\", what = \"Tiny Beast\" },\r\n[\"Spider\"] = { ac = 12, hp = 1, init = 2, speed = 20, cr = \"0\", xp = 10, saves = { Strength = -4, Dexterity = 2, Constitution = -1, Intelligence = -5, Wisdom = 0, Charisma = -4 }, attacks = {{ name = \"Bite\", hit = 4, dmg = \"1\", type = \"Piercing\" }}, pp = 10, pi = 10, stealth = 4, hab = {\"Forest\"}, ctypes = {\"Beast\"}, pb = 2, conm = -1, ab = {2, 14, 8, 1, 10, 2}, beast = true, sc = { Strength = 2, Dexterity = 14, Constitution = 8 }, sk = { Stealth = 4 }, ko = \"거미\", what = \"Tiny Beast\" },\r\n[\"Swarm of Bats\"] = { ac = 12, hp = 11, init = 2, speed = 5, cr = \"1/4\", xp = 50, saves = { Strength = -3, Dexterity = 2, Constitution = 0, Intelligence = -4, Wisdom = 1, Charisma = -3 }, attacks = {{ name = \"Bites\", hit = 4, dmg = \"2d4\", bloodied = \"1d4\", type = \"Piercing\" }}, pp = 11, pi = 11, stealth = 2, res = {\"Bludgeoning\", \"Piercing\", \"Slashing\"}, cimm = {\"Charmed\", \"Frightened\", \"Grappled\", \"Paralyzed\", \"Petrified\", \"Prone\", \"Restrained\", \"Stunned\"}, hab = {\"Ruins\", \"Underdark\"}, ctypes = {\"Swarm\"}, pb = 2, conm = 0, ab = {5, 15, 10, 2, 12, 4}, beast = true, sc = { Strength = 5, Dexterity = 15, Constitution = 10 }, fly = true, ko = \"박쥐 떼\", what = \"Large Swarm of Tiny Beasts\" },\r\n[\"Swarm of Insects\"] = { ac = 11, hp = 19, init = 1, speed = 20, cr = \"1/2\", xp = 100, saves = { Strength = -4, Dexterity = 1, Constitution = 2, Intelligence = -5, Wisdom = -2, Charisma = -5 }, attacks = {{ name = \"Bites\", hit = 3, dmg = \"2d4+1\", bloodied = \"1d4+1\", type = \"Poison\" }}, pp = 8, pi = 8, stealth = 1, res = {\"Bludgeoning\", \"Piercing\", \"Slashing\"}, cimm = {\"Charmed\", \"Frightened\", \"Grappled\", \"Paralyzed\", \"Petrified\", \"Prone\", \"Restrained\", \"Stunned\"}, hab = {\"Forest\", \"Grassland\", \"Swamp\"}, ctypes = {\"Swarm\"}, pb = 2, conm = 2, ab = {3, 13, 14, 1, 7, 1}, beast = true, sc = { Strength = 3, Dexterity = 13, Constitution = 14 }, fly = true, ko = \"벌레 떼\", what = \"Medium Swarm of Tiny Beasts\" },\r\n[\"Swarm of Piranhas\"] = { ac = 13, hp = 28, init = 3, speed = 5, cr = \"1\", xp = 200, saves = { Strength = 1, Dexterity = 3, Constitution = -1, Intelligence = -5, Wisdom = -2, Charisma = -4 }, attacks = {{ name = \"Bites\", hit = 5, dmg = \"2d4+3\", bloodied = \"1d4+3\", type = \"Piercing\" }}, pp = 8, pi = 8, stealth = 3, res = {\"Bludgeoning\", \"Piercing\", \"Slashing\"}, cimm = {\"Charmed\", \"Frightened\", \"Grappled\", \"Paralyzed\", \"Petrified\", \"Prone\", \"Restrained\", \"Stunned\"}, hab = {\"Underwater\"}, ctypes = {\"Swarm\"}, pb = 2, conm = -1, ab = {13, 16, 9, 1, 7, 2}, beast = true, sc = { Strength = 13, Dexterity = 16, Constitution = 9 }, swim = true, ko = \"피라냐 떼\", what = \"Medium Swarm of Tiny Beasts\" },\r\n[\"Swarm of Rats\"] = { ac = 10, hp = 14, init = 0, speed = 30, cr = \"1/4\", xp = 50, saves = { Strength = -1, Dexterity = 2, Constitution = -1, Intelligence = -4, Wisdom = 0, Charisma = -4 }, attacks = {{ name = \"Bites\", hit = 2, dmg = \"2d4\", bloodied = \"1d4\", type = \"Piercing\" }}, pp = 10, pi = 10, stealth = 0, res = {\"Bludgeoning\", \"Piercing\", \"Slashing\"}, cimm = {\"Charmed\", \"Frightened\", \"Grappled\", \"Paralyzed\", \"Petrified\", \"Prone\", \"Restrained\", \"Stunned\"}, hab = {\"Ruins\", \"Urban\"}, ctypes = {\"Swarm\"}, pb = 2, conm = -1, ab = {9, 11, 9, 2, 10, 3}, beast = true, sc = { Strength = 9, Dexterity = 11, Constitution = 9 }, ko = \"쥐 떼\", what = \"Medium Swarm of Tiny Beasts\" },\r\n[\"Swarm of Ravens\"] = { ac = 12, hp = 11, init = 2, speed = 10, cr = \"1/4\", xp = 50, saves = { Strength = -2, Dexterity = 2, Constitution = 1, Intelligence = -3, Wisdom = 1, Charisma = -2 }, attacks = {{ name = \"Beaks\", hit = 4, dmg = \"1d6+2\", bloodied = \"1d4\", type = \"Piercing\" }}, pp = 15, pi = 11, stealth = 2, res = {\"Bludgeoning\", \"Piercing\", \"Slashing\"}, cimm = {\"Charmed\", \"Frightened\", \"Grappled\", \"Paralyzed\", \"Petrified\", \"Prone\", \"Restrained\", \"Stunned\"}, hab = {\"Coastal\", \"Forest\", \"Urban\"}, ctypes = {\"Swarm\"}, pb = 2, conm = 1, ab = {6, 14, 12, 5, 12, 6}, beast = true, sc = { Strength = 6, Dexterity = 14, Constitution = 12 }, sk = { Perception = 5 }, fly = true, ko = \"까마귀 떼\", sfx = {{ n = \"Cacophony\", s = \"Wisdom\", dc = 10, o = \"Recharge 6\" }}, what = \"Medium Swarm of Tiny Beasts\" },\r\n[\"Swarm of Venomous Snakes\"] = { ac = 14, hp = 36, init = 4, speed = 30, cr = \"2\", xp = 450, saves = { Strength = -1, Dexterity = 4, Constitution = 0, Intelligence = -5, Wisdom = 0, Charisma = -4 }, attacks = {{ name = \"Bites\", hit = 6, dmg = \"1d8+4+3d6\", bloodied = \"1d4+4+3d6\" }}, pp = 10, pi = 10, stealth = 4, res = {\"Bludgeoning\", \"Piercing\", \"Slashing\"}, cimm = {\"Charmed\", \"Frightened\", \"Grappled\", \"Paralyzed\", \"Petrified\", \"Prone\", \"Restrained\", \"Stunned\"}, hab = {\"Swamp\"}, ctypes = {\"Swarm\"}, pb = 2, conm = 0, ab = {8, 18, 11, 1, 10, 3}, beast = true, sc = { Strength = 8, Dexterity = 18, Constitution = 11 }, swim = true, ko = \"독사 떼\", what = \"Medium Swarm of Tiny Beasts\" },\r\n[\"Tiger\"] = { ac = 13, hp = 30, init = 3, speed = 40, cr = \"1\", xp = 200, saves = { Strength = 3, Dexterity = 3, Constitution = 2, Intelligence = -4, Wisdom = 1, Charisma = -1 }, attacks = {{ name = \"Rend\", hit = 5, dmg = \"2d6+3\", type = \"Slashing\" }}, pp = 13, pi = 11, stealth = 7, hab = {\"Forest\"}, ctypes = {\"Beast\"}, pb = 2, conm = 2, ab = {17, 16, 14, 3, 12, 8}, beast = true, sc = { Strength = 17, Dexterity = 16, Constitution = 14 }, sk = { Perception = 3, Stealth = 7 }, ko = \"호랑이\", acts = \"Nimble Escape (Bonus Action)\", what = \"Large Beast\" },\r\n[\"Triceratops\"] = { ac = 14, hp = 114, init = -1, speed = 50, cr = \"5\", xp = 1800, saves = { Strength = 6, Dexterity = -1, Constitution = 3, Intelligence = -4, Wisdom = 0, Charisma = -3 }, attacks = {{ name = \"Gore\", hit = 9, dmg = \"2d12+6\", type = \"Piercing\" }}, pp = 10, pi = 10, stealth = -1, hab = {\"Grassland\"}, ctypes = {\"Beast\"}, pb = 3, conm = 3, ab = {22, 9, 17, 2, 11, 5}, beast = true, sc = { Strength = 22, Dexterity = 9, Constitution = 17 }, ko = \"트리케라톱스\", multi = \"The triceratops makes two Gore attacks.\", what = \"Huge Beast (Dinosaur)\" },\r\n[\"Tyrannosaurus Rex\"] = { ac = 13, hp = 136, init = 3, speed = 50, cr = \"8\", xp = 3900, saves = { Strength = 10, Dexterity = 0, Constitution = 4, Intelligence = -4, Wisdom = 4, Charisma = -1 }, attacks = {{ name = \"Bite\", hit = 10, dmg = \"4d12+7\", type = \"Piercing\" }, { name = \"Tail\", hit = 10, dmg = \"4d8+7\", type = \"Bludgeoning\" }}, pp = 14, pi = 11, stealth = 0, hab = {\"Grassland\"}, ctypes = {\"Beast\"}, pb = 3, conm = 4, ab = {25, 10, 19, 2, 12, 9}, beast = true, sc = { Strength = 25, Dexterity = 10, Constitution = 19 }, sk = { Perception = 4 }, ko = \"티라노사우루스\", multi = \"The tyrannosaurus makes one Bite attack and one Tail attack.\", what = \"Huge Beast (Dinosaur)\" },\r\n[\"Venomous Snake\"] = { ac = 12, hp = 5, init = 2, speed = 30, cr = \"1/8\", xp = 25, saves = { Strength = -4, Dexterity = 2, Constitution = 0, Intelligence = -5, Wisdom = 0, Charisma = -4 }, attacks = {{ name = \"Bite\", hit = 4, dmg = \"1d4+2+1d6\" }}, pp = 10, pi = 10, stealth = 2, hab = {\"Desert\", \"Swamp\"}, ctypes = {\"Beast\"}, pb = 2, conm = 0, ab = {2, 15, 11, 1, 10, 3}, beast = true, sc = { Strength = 2, Dexterity = 15, Constitution = 11 }, swim = true, ko = \"독사\", what = \"Tiny Beast\" },\r\n[\"Vulture\"] = { ac = 10, hp = 5, init = 0, speed = 10, cr = \"0\", xp = 10, saves = { Strength = -2, Dexterity = 0, Constitution = 1, Intelligence = -4, Wisdom = 1, Charisma = -3 }, attacks = {{ name = \"Beak\", hit = 2, dmg = \"1d4\", type = \"Piercing\" }}, pp = 13, pi = 11, stealth = 0, hab = {\"Desert\", \"Grassland\"}, ctypes = {\"Beast\"}, pb = 2, conm = 1, ab = {7, 10, 13, 2, 12, 4}, beast = true, sc = { Strength = 7, Dexterity = 10, Constitution = 13 }, sk = { Perception = 3 }, fly = true, ko = \"대머리수리\", what = \"Medium Beast\" },\r\n[\"Warhorse\"] = { ac = 11, hp = 19, init = 1, speed = 60, cr = \"1/2\", xp = 100, saves = { Strength = 4, Dexterity = 1, Constitution = 1, Intelligence = -4, Wisdom = 3, Charisma = -2 }, attacks = {{ name = \"Hooves\", hit = 6, dmg = \"2d4+4\", type = \"Bludgeoning\" }}, pp = 11, pi = 11, stealth = 1, hab = {\"Grassland\"}, ctypes = {\"Beast\"}, pb = 2, conm = 1, ab = {18, 12, 13, 2, 12, 7}, beast = true, sc = { Strength = 18, Dexterity = 12, Constitution = 13 }, ko = \"전투마\", what = \"Large Beast\" },\r\n[\"Weasel\"] = { ac = 13, hp = 1, init = 3, speed = 30, cr = \"0\", xp = 10, saves = { Strength = -4, Dexterity = 3, Constitution = -1, Intelligence = -4, Wisdom = 1, Charisma = -4 }, attacks = {{ name = \"Bite\", hit = 5, dmg = \"1\", type = \"Piercing\" }}, pp = 13, pi = 11, stealth = 5, hab = {\"Forest\"}, ctypes = {\"Beast\"}, pb = 2, conm = -1, ab = {3, 16, 8, 2, 12, 3}, beast = true, sc = { Strength = 3, Dexterity = 16, Constitution = 8 }, sk = { Acrobatics = 5, Perception = 3, Stealth = 5 }, ko = \"족제비\", what = \"Tiny Beast\" },\r\n[\"Wolf\"] = { ac = 12, hp = 11, init = 2, speed = 40, cr = \"1/4\", xp = 50, saves = { Strength = 2, Dexterity = 2, Constitution = 1, Intelligence = -4, Wisdom = 1, Charisma = -2 }, attacks = {{ name = \"Bite\", hit = 4, dmg = \"1d6+2\", type = \"Piercing\" }}, pp = 15, pi = 11, stealth = 4, hab = {\"Forest\", \"Grassland\", \"Hill\"}, ctypes = {\"Beast\"}, pb = 2, conm = 1, ab = {14, 15, 12, 3, 12, 6}, beast = true, sc = { Strength = 14, Dexterity = 15, Constitution = 12 }, sk = { Perception = 5, Stealth = 4 }, ko = \"늑대\", what = \"Medium Beast\" },\r\n}\r\n\r\nlocal SPELLS = {\r\n[\"Acid Arrow\"] = { level = 2, classes = {\"Wizard\"}, attack = \"ranged\", damage = \"4d4\", damage_type = \"Acid\", school = \"방출학파\", time = \"행동\", range = \"90피트\", dur = \"즉시\", cmp = \"VS\", ko = \"90피트 안의 대상에게 반짝이는 초록 화살을 쏘아 원거리 주문 공격을 합니다. 맞으면 산성 피해 4d4를 주고, 대상의 다음 턴이 끝날 때 산성 피해 2d4를 더 줍니다. 빗나가도 산성이 튀어 처음 피해의 절반은 주지만, 나중 피해는 없습니다. 높은 레벨로 시전하면 한 단계마다 처음 피해와 나중 피해가 모두 1d4씩 늘어납니다.\", m = { cast = \"action\", kind = \"attack\", attack = \"ranged\", damage = \"4d4\", type = \"Acid\", upcast = { dice = \"1d4\" } } },\r\n[\"Acid Splash\"] = { level = 0, classes = {\"Sorcerer\", \"Wizard\"}, save = \"Dexterity\", damage = \"1d6\", damage_type = \"Acid\", school = \"방출학파\", time = \"행동\", range = \"60피트\", dur = \"즉시\", cmp = \"VS\", ko = \"60피트 안의 한 지점에 산성 거품을 만들어 터뜨립니다. 그 지점을 중심으로 반경 5피트 안의 생물은 모두 민첩 내성 굴림을 하고, 실패하면 산성 피해 1d6을 받습니다. 5·11·17레벨에 피해 주사위가 하나씩 늘어납니다.\", m = { cast = \"action\", kind = \"save\", save = \"Dexterity\", on_save = \"none\", damage = \"1d6\", type = \"Acid\", cantrip = true, area = true } },\r\n[\"Aid\"] = { level = 2, classes = {\"Bard\", \"Cleric\", \"Druid\", \"Paladin\", \"Ranger\"}, school = \"방호학파\", time = \"행동\", range = \"30피트\", dur = \"8시간\", cmp = \"VS\", ko = \"30피트 안의 생물을 셋까지 고릅니다. 8시간 동안 대상마다 최대 생명력과 현재 생명력이 5씩 오릅니다. 높은 레벨로 시전하면 한 단계마다 오르는 양이 5씩 늘어납니다.\", bmins = 480, m = { cast = \"action\", kind = \"buff\", hp_bonus = 5, upcast = { hp_bonus = 5 }, dur_mins = 480, targets = 3 } },\r\n[\"Alarm\"] = { level = 1, classes = {\"Ranger\", \"Wizard\"}, ritual = true, school = \"방호학파\", time = \"1분 · 의식 가능\", range = \"30피트\", dur = \"8시간\", cmp = \"VS\", ko = \"30피트 안의 문 하나, 창문 하나, 또는 20피트 정육면체 이하의 구역에 8시간 동안 경보를 겁니다. 생물이 그곳을 건드리거나 안으로 들어오면 경보가 울립니다. 시전할 때 경보를 울리지 않을 생물을 정해 둘 수 있습니다. 경보는 두 가지 가운데 고릅니다. 소리로 고르면 그곳 60피트 안에 손종 소리가 10초 동안 울리고, 마음으로 고르면 내가 1마일 안에 있을 때 머릿속으로 신호가 옵니다(자고 있으면 깨어남). 시전에 1분이 걸리고, 의식으로 시전할 수 있습니다.\", m = { cast = \"1 minute\", kind = \"utility\" } },\r\n[\"Alter Self\"] = { level = 2, classes = {\"Sorcerer\", \"Wizard\"}, concentration = true, school = \"변환학파\", time = \"행동\", range = \"자신\", dur = \"집중, 최대 1시간\", cmp = \"VS\", mins = 60, ko = \"내 몸을 바꿉니다. 셋 가운데 하나를 고르고, 주문이 이어지는 동안 마법 행동으로 다른 것으로 바꿀 수 있습니다. 아가미와 물갈퀴가 생겨 물속에서 숨 쉬고 속도만큼 헤엄치거나, 키·몸무게·얼굴·목소리 같은 생김새를 바꾸거나(크기와 기본 몸꼴은 그대로), 발톱·송곳니·뿔·발굽 같은 자연 무기를 기릅니다. 자연 무기로 맨손 공격을 하면 근력 대신 주문시전 능력치로 명중을 굴리고, 피해는 1d6 + 주문시전 능력치 수정치입니다. 집중, 최대 1시간.\", m = { cast = \"action\", kind = \"utility\", concentration = true } },\r\n[\"Animal Friendship\"] = { level = 1, classes = {\"Bard\", \"Druid\", \"Ranger\"}, save = \"Wisdom\", school = \"환혹학파\", time = \"행동\", range = \"30피트\", dur = \"24시간\", cmp = \"VS\", ko = \"30피트 안에 보이는 야수 하나를 고릅니다. 대상은 지혜 내성 굴림을 하고, 실패하면 24시간 동안 매혹 상태가 됩니다. 나나 내 동료가 대상에게 피해를 주면 주문이 끝납니다. 높은 레벨로 시전하면 한 단계마다 야수를 하나씩 더 고를 수 있습니다.\", m = { puts = {\"Charmed\"}, cast = \"action\", kind = \"save\", save = \"Wisdom\", on_save = \"none\", upcast = { targets = 1 }, lrfx = {\"Charmed\"}, fail = \"a Beast is Charmed for 24 hours\" } },\r\n[\"Animal Messenger\"] = { level = 2, classes = {\"Bard\", \"Druid\", \"Ranger\"}, save = \"Charisma\", ritual = true, school = \"환혹학파\", time = \"행동 · 의식 가능\", range = \"30피트\", dur = \"24시간\", cmp = \"VS\", ko = \"30피트 안에 보이는 초소형 야수 하나가 매력 내성 굴림을 합니다(도전 지수가 0이 아니면 자동으로 성공). 실패하면 그 야수가 내 전갈을 전하러 갑니다. 내가 가 본 장소와 대강의 생김새로 받는 이를 정하고 스물다섯 단어까지의 말을 맡기면, 야수는 24시간 동안 약 25마일(날 수 있으면 50마일)을 가서 그 말을 전합니다. 그 안에 닿지 못하면 전갈은 사라지고 야수는 시전한 곳으로 돌아옵니다. 높은 레벨로 시전하면 한 단계마다 지속 시간이 48시간씩 늘어납니다. 의식으로 시전할 수 있습니다.\", m = { cast = \"action\", kind = \"utility\" } },\r\n[\"Animal Shapes\"] = { level = 8, classes = {\"Druid\"}, school = \"변환학파\", time = \"행동\", range = \"30피트\", dur = \"24시간\", cmp = \"VS\", ko = \"30피트 안에 보이는 동의한 생물을 원하는 만큼 골라, 24시간 동안 대형 이하이고 도전 지수 4 이하인 야수로 바꿉니다. 야수는 내가 고르고, 대상마다 달라도 됩니다. 이후 내 턴에 마법 행동으로 대상들을 다른 야수로 다시 바꿀 수 있습니다. 대상의 능력치는 그 야수의 것이 되지만 생물 유형·생명력·성향·말하는 능력·지능·지혜·매력은 그대로이고, 처음 변한 야수의 생명력만큼 임시 생명력을 얻습니다(주문이 끝날 때 남은 것은 사라짐). 그 몸으로 할 수 있는 일만 할 수 있고 주문을 쓰지 못하며, 장비는 몸에 녹아들어 쓸 수 없습니다. 대상은 추가 행동으로 언제든 원래 모습으로 돌아올 수 있습니다.\", m = { cast = \"action\", kind = \"utility\" } },\r\n[\"Animate Dead\"] = { level = 3, classes = {\"Cleric\", \"Wizard\"}, school = \"사령학파\", time = \"1분\", range = \"10피트\", dur = \"즉시\", cmp = \"VS\", ko = \"10피트 안의 뼈 더미나, 중형·소형 인간형의 시체 하나를 언데드로 일으킵니다. 뼈는 스켈레톤, 시체는 좀비가 됩니다. 내 턴마다 추가 행동으로 60피트 안에 있는, 이 주문으로 만든 언데드에게 마음속으로 명령을 내립니다. 다음 턴에 할 행동과 움직일 곳을 정하거나, 방이나 복도 지키기 같은 큰 명령을 줄 수 있습니다. 명령이 없으면 회피 행동만 하고 위험을 피해서만 움직입니다. 24시간이 지나면 명령을 듣지 않으므로, 그 전에 이 주문을 다시 걸어야 계속 부릴 수 있습니다(새로 일으키는 대신 넷까지 다시 부림). 시전에 1분이 걸립니다. 높은 레벨로 시전하면 한 단계마다 언데드를 둘씩 더 일으키거나 다시 부릴 수 있습니다.\", m = { cast = \"1 minute\", kind = \"utility\" } },\r\n[\"Animate Objects\"] = { level = 5, classes = {\"Bard\", \"Sorcerer\", \"Wizard\"}, concentration = true, school = \"변환학파\", time = \"행동\", range = \"120피트\", dur = \"집중, 최대 1분\", cmp = \"VS\", mins = 1, ko = \"120피트 안에서 마법이 아닌 물건을 골라 움직이게 합니다. 아무도 들거나 입지 않았고, 어디에 붙박이지 않았으며, 초대형이 아닌 물건이어야 합니다. 고를 수 있는 수는 주문시전 능력치 수정치까지이고, 중형 이하는 하나, 대형은 둘, 거대형은 셋으로 셉니다. 물건마다 다리가 돋아나 '움직이는 물체' 능력치를 쓰는 구조물이 됩니다. 이 생물들은 나와 동료의 편이고, 싸움에서는 내 턴 바로 뒤에 움직입니다. 추가 행동으로 500피트 안의 이 생물들에게 마음속으로 명령을 내리며, 명령이 없으면 회피 행동만 하고 위험을 피해서만 움직입니다. 생명력이 0이 되면 물건으로 돌아가고, 남은 피해는 물건이 받습니다. 집중, 최대 1분. 높은 레벨로 시전하면 한 단계마다 강타 피해가 늘어납니다(중형 이하 1d4, 대형 1d6, 거대형 1d12).\", m = { cast = \"action\", kind = \"attack\", attack = \"melee\", damage = \"1d4+3\", type = \"Force\", concentration = true, upcast = { dice = \"1d4\" } } },\r\n[\"Antimagic Field\"] = { level = 8, classes = {\"Cleric\", \"Wizard\"}, concentration = true, school = \"방호학파\", time = \"행동\", range = \"자신\", dur = \"집중, 최대 1시간\", cmp = \"VS\", mins = 60, ko = \"나를 중심으로 10피트에 반마법의 기운이 퍼집니다. 그 안에서는 누구도 주문을 쓰거나, 마법 행동을 하거나, 다른 마법 효과를 만들 수 없고, 그런 것들은 기운 안에 있는 대상을 노리거나 건드리지도 못합니다. 마법 물건의 마법도 그 안에서는 듣지 않습니다. 주문이나 마법으로 만든 범위는 기운 안으로 뻗어 들어오지 못하고, 순간이동이나 다른 세계로 가는 이동으로 드나들 수 없으며, 관문은 그 안에 있는 동안 닫힙니다. 이미 걸려 있던 주문은 그 안에서 효과가 멈추지만(유물이나 신이 건 것은 빼고), 멈춘 동안에도 지속 시간은 흐릅니다. 마법 무효화는 이 기운에 통하지 않고, 이 주문으로 만든 기운끼리는 서로 지우지 않습니다. 집중, 최대 1시간.\", m = { cast = \"action\", kind = \"utility\", concentration = true } },\r\n[\"Antipathy/Sympathy\"] = { level = 8, classes = {\"Bard\", \"Druid\", \"Wizard\"}, save = \"Wisdom\", school = \"환혹학파\", time = \"1시간\", range = \"60피트\", dur = \"10일\", cmp = \"VS\", ko = \"60피트 안의 거대형 이하 생물이나 물건 하나를 고르고, 반감과 호감 가운데 하나를 정한 다음 붉은 용·고블린·뱀파이어 같은 생물 종류 하나를 정합니다. 주문은 10일 동안 이어집니다. 그 종류의 생물이 대상 120피트 안에 들어오면 지혜 내성 굴림을 합니다. 반감이면 실패한 생물은 공포 상태가 되어, 자기 턴마다 가장 안전한 길로 대상에게서 최대한 멀어져야 합니다. 호감이면 실패한 생물은 매혹 상태가 되어, 자기 턴마다 가장 안전한 길로 대상에게 최대한 다가가야 하고, 5피트 안에 들어오면 스스로 떠나지 못합니다(대상에게 피해를 받으면 지혜 내성 굴림으로 벗어날 기회가 생김). 걸린 생물이 대상에게서 120피트 넘게 떨어진 곳에서 턴을 끝내면 지혜 내성 굴림을 하고, 성공하면 풀려나 1분 동안 다시 걸리지 않습니다. 시전에 1시간이 걸립니다.\", m = { puts = {\"Charmed\", \"Frightened\"}, cast = \"1 hour\", kind = \"save\", save = \"Wisdom\", on_save = \"none\", lrfx = {\"Charmed\", \"Frightened\"}, fail = \"lasts 10 days; a creature of that kind within 120 ft saves: Antipathy = Frightened, flees; Sympathy = Charmed, comes close\" } },\r\n[\"Antilife Shell\"] = { level = 5, classes = {\"Druid\"}, save = \"Wisdom\", concentration = true, school = \"방호학파\", time = \"행동\", range = \"자신\", dur = \"집중, 최대 1시간\", cmp = \"VS\", mins = 60, ko = \"나를 중심으로 10피트에 막이 생겨, 주문이 이어지는 동안 나를 따라다닙니다. 구조물과 언데드가 아닌 생물은 이 막을 지나가거나 막 너머로 손을 뻗을 수 없습니다. 다만 막 너머로 주문을 쓰거나 원거리 무기·간격 무기로 공격하는 것은 막지 못합니다. 내가 움직여서 그런 생물이 억지로 막을 지나가게 되면 주문이 끝납니다. 집중, 최대 1시간.\", m = { cast = \"action\", kind = \"utility\", concentration = true } },\r\n[\"Arcane Eye\"] = { level = 4, classes = {\"Wizard\"}, concentration = true, school = \"예지학파\", time = \"행동\", range = \"30피트\", dur = \"집중, 최대 1시간\", cmp = \"VS\", mins = 60, ko = \"30피트 안에 보이지 않고 부서지지 않는 눈을 만들어 띄웁니다. 눈은 사방을 볼 수 있고 30피트까지 보는 암시야도 있으며, 눈이 보는 것은 내 머릿속에 그대로 보입니다. 추가 행동으로 눈을 어느 방향으로든 30피트까지 옮길 수 있습니다. 단단한 벽은 지나가지 못하지만 지름 1인치만 한 틈은 지나갑니다. 집중, 최대 1시간.\", m = { cast = \"action\", kind = \"utility\", concentration = true } },\r\n[\"Arcane Hand\"] = { level = 5, classes = {\"Sorcerer\", \"Wizard\"}, attack = \"melee\", save = \"Strength\", damage = \"5d8\", damage_type = \"Force\", concentration = true, school = \"방출학파\", time = \"행동\", range = \"120피트\", dur = \"집중, 최대 1분\", cmp = \"VS\", mins = 1, ko = \"120피트 안에 보이는 빈 곳에, 내 손짓을 그대로 따라 하는 대형 마법 손을 만듭니다(방어도 20, 생명력은 내 최대 생명력과 같고, 0이 되면 주문이 끝남). 시전할 때와 이후 내 턴마다 추가 행동으로 손을 60피트까지 옮긴 뒤 다음 효과 가운데 하나를 씁니다. 꽉 쥔 주먹은 손 5피트 안의 대상에게 근접 주문 공격을 해서, 맞으면 역장 피해 5d8을 줍니다. 미는 손은 5피트 안의 거대형 이하 생물이 근력 내성 굴림에 실패하면 5피트 + 주문시전 능력치 수정치의 다섯 배만큼 밀어내고, 손도 따라갑니다. 움켜쥐는 손은 5피트 안의 거대형 이하 생물이 민첩 내성 굴림에 실패하면 붙잡고(탈출 난이도는 내 주문 내성 난이도), 붙잡은 동안 추가 행동으로 쥐어짜 타격 피해 4d6 + 주문시전 능력치 수정치를 줍니다. 가로막는 손은 손이 있는 칸에서 오거나 그 칸을 지나는 공격과 효과에 대해 나에게 절반 엄폐를 주고, 그 칸을 적에게 어려운 지형으로 만듭니다. 집중, 최대 1분. 높은 레벨로 시전하면 한 단계마다 주먹 피해가 2d8씩, 움켜쥐기 피해가 2d6씩 늘어납니다.\", m = { cast = \"action\", kind = \"attack\", attack = \"melee\", damage = \"5d8\", type = \"Force\", concentration = true, upcast = { dice = \"2d8\" } } },\r\n[\"Arcane Lock\"] = { level = 2, classes = {\"Wizard\"}, school = \"방호학파\", time = \"행동\", range = \"접촉\", dur = \"해제될 때까지\", cmp = \"VS\", ko = \"닫힌 문·창문·대문·상자·뚜껑 하나를 만져 마법으로 잠급니다. 이 자물쇠는 마법이 아닌 방법으로는 열 수 없지만, 나와 시전할 때 정한 생물은 자유롭게 열고 닫을 수 있습니다. 암호를 정해 두면, 누구든 5피트 안에서 그 암호를 말할 때 1분 동안 열립니다. 주문은 해제될 때까지 이어집니다.\", cost = \"gold dust worth 25+ GP, consumed\", cost_ko = \"25 GP 이상의 금가루 (시전하면 사라짐)\", m = { cast = \"action\", kind = \"utility\" } },\r\n[\"Arcane Sword\"] = { level = 7, classes = {\"Bard\", \"Wizard\"}, attack = \"melee\", concentration = true, school = \"방출학파\", time = \"행동\", range = \"90피트\", dur = \"집중, 최대 1분\", cmp = \"VS\", mins = 1, ko = \"90피트 안에 떠다니는 유령 검을 만듭니다. 검이 나타날 때 검 5피트 안의 대상 하나에게 근접 주문 공격을 해서, 맞으면 역장 피해 4d12 + 주문시전 능력치 수정치를 줍니다. 이후 내 턴마다 추가 행동으로 검을 보이는 곳으로 30피트까지 옮기고, 같은 대상이나 다른 대상에게 다시 공격할 수 있습니다. 집중, 최대 1분.\", cost = \"a miniature sword worth 250+ GP\", cost_ko = \"250 GP 이상의 작은 검 모형\", m = { cast = \"action\", kind = \"attack\", attack = \"melee\", damage = \"4d12+MOD\", type = \"Force\", concentration = true } },\r\n[\"Arcanist's Magic Aura\"] = { level = 2, classes = {\"Wizard\"}, school = \"환영학파\", time = \"행동\", range = \"접촉\", dur = \"24시간\", cmp = \"VS\", ko = \"동의한 생물 하나나, 아무도 들거나 입지 않은 물건 하나를 만져 24시간 동안 환영을 씌웁니다. 생물에게 걸면 실제와 다른 생물 유형을 하나 고르고, 주문과 마법 효과는 그 생물을 고른 유형으로 여깁니다. 물건에 걸면 마법 탐지처럼 마법의 기운을 알아보는 주문에 비치는 모습을 바꿔, 평범한 물건을 마법 물건처럼, 마법 물건을 평범한 물건처럼 보이게 하거나, 기운이 내가 고른 학파의 것처럼 보이게 합니다. 30일 동안 매일 같은 대상에 걸면 해제될 때까지 이어집니다.\", m = { cast = \"action\", kind = \"utility\" } },\r\n[\"Astral Projection\"] = { level = 9, classes = {\"Cleric\", \"Warlock\", \"Wizard\"}, school = \"사령학파\", time = \"1시간\", range = \"10피트\", dur = \"해제될 때까지\", cmp = \"VS\", ko = \"나와, 10피트 안에서 함께 가려는 생물 여덟까지가 아스트랄계로 영체를 보냅니다(이미 아스트랄계에 있으면 주문이 바로 끝남). 몸은 그 자리에 남아 가사 상태가 됩니다. 무의식 상태이고, 음식이나 공기가 필요 없으며, 늙지 않습니다. 영체는 몸과 거의 똑같아 능력치와 지닌 것도 같고, 어깨뼈 사이에서 은빛 끈이 이어집니다. 끈을 끊는 효과를 받으면 몸과 영체가 함께 죽습니다. 영체가 아스트랄계를 떠나 다른 세계로 들어가는 순간, 몸과 지닌 것이 끈을 따라 그 세계로 와서 대상은 몸으로 돌아갑니다. 영체가 받은 피해나 효과는 몸에 미치지 않고, 그 반대도 마찬가지입니다. 몸이나 영체의 생명력이 0이 되면 그 대상의 주문이 끝나고, 내가 마법 행동으로 모두의 주문을 끝낼 수도 있습니다. 주문이 끝난 대상은 죽지 않았다면 몸으로 돌아와 깨어납니다. 시전에 1시간이 걸립니다.\", cost = \"for each of the spell's targets, one jacinth worth 1,000+ GP and one silver bar worth 100+ GP, all consumed\", cost_ko = \"대상마다 1,000 GP 이상의 히아신스석과 100 GP 이상의 은괴 (시전하면 사라짐)\", m = { cast = \"1 hour\", kind = \"utility\" } },\r\n[\"Augury\"] = { level = 2, classes = {\"Cleric\", \"Druid\", \"Wizard\"}, ritual = true, school = \"예지학파\", time = \"1분 · 의식 가능\", range = \"자신\", dur = \"즉시\", cmp = \"VS\", ko = \"앞으로 30분 안에 하려는 일이 어떤 결과를 낳을지, 저 너머의 존재에게 징조를 받습니다. GM이 길함(좋음)·흉함(나쁨)·길함과 흉함(좋기도 나쁘기도 함)·아무것도 아님(좋지도 나쁘지도 않음) 가운데 하나를 알려 줍니다. 결과를 바꿀 수 있는 다른 주문 같은 사정은 따지지 않습니다. 긴 휴식을 마치기 전에 두 번 이상 시전하면, 두 번째부터 시전할 때마다 25%씩 쌓이는 확률로 답을 받지 못합니다. 시전에 1분이 걸리고, 의식으로 시전할 수 있습니다.\", cost = \"specially marked sticks, bones, cards, or other divinatory tokens worth 25+ GP\", cost_ko = \"25 GP 이상의 점술 도구 (표시한 막대·뼈·카드 같은 것)\", m = { cast = \"1 minute\", kind = \"utility\" } },\r\n[\"Aura of Life\"] = { level = 4, classes = {\"Cleric\", \"Paladin\"}, concentration = true, school = \"방호학파\", time = \"행동\", range = \"자신\", dur = \"집중, 최대 10분\", cmp = \"V\", mins = 10, ko = \"나를 중심으로 30피트에 생명의 기운이 퍼집니다. 그 안에 있는 동안 나와 내 동료는 사령 피해에 저항하고, 최대 생명력이 줄어들지 않습니다. 생명력이 0인 동료가 그 안에서 턴을 시작하면 생명력 1을 되찾습니다. 집중, 최대 10분.\", m = { cast = \"action\", kind = \"buff\", concentration = true, resist = {\"Necrotic\"}, btargets = 12, revive = true } },\r\n[\"Awaken\"] = { level = 5, classes = {\"Bard\", \"Druid\"}, school = \"변환학파\", time = \"8시간\", range = \"접촉\", dur = \"즉시\", cmp = \"VS\", ko = \"8시간에 걸쳐 값비싼 보석 속에 마법의 길을 새긴 뒤, 대상 하나를 만집니다. 대상은 지능 3 이하인 야수나 식물 생물, 또는 생물이 아닌 자연 식물이어야 합니다. 대상은 지능이 10이 되고, 내가 아는 언어 하나로 말할 수 있게 됩니다. 자연 식물이면 식물 생물이 되어 가지·뿌리·덩굴을 움직일 수 있고, 사람과 비슷한 감각을 얻습니다. 깨어난 대상은 30일 동안, 또는 나나 내 동료가 피해를 줄 때까지 매혹 상태이고, 그 뒤로는 나를 어떻게 대할지 스스로 정합니다.\", cost = \"an agate worth 1,000+ GP, consumed\", cost_ko = \"1,000 GP 이상의 마노 (시전하면 사라짐)\", m = { cast = \"8 hours\", kind = \"utility\" } },\r\n[\"Bane\"] = { level = 1, classes = {\"Bard\", \"Cleric\", \"Warlock\"}, save = \"Charisma\", concentration = true, school = \"환혹학파\", time = \"행동\", range = \"30피트\", dur = \"집중, 최대 1분\", cmp = \"VS\", mins = 1, ko = \"30피트 안에 보이는 생물을 셋까지 고르면, 대상마다 매력 내성 굴림을 합니다. 실패한 대상은 주문이 끝날 때까지 명중 굴림이나 내성 굴림을 할 때마다 그 값에서 1d4를 뺍니다. 집중, 최대 1분. 높은 레벨로 시전하면 한 단계마다 대상이 하나씩 늘어납니다.\", m = { foe_fx = { bane = true }, cast = \"action\", kind = \"save\", save = \"Charisma\", on_save = \"none\", concentration = true, upcast = { targets = 1 }, lrfx = {}, fail = \"subtract 1d4 from attack rolls and saving throws\" } },\r\n[\"Banishment\"] = { level = 4, classes = {\"Cleric\", \"Paladin\", \"Sorcerer\", \"Warlock\", \"Wizard\"}, save = \"Charisma\", concentration = true, school = \"방호학파\", time = \"행동\", range = \"30피트\", dur = \"집중, 최대 1분\", cmp = \"VS\", mins = 1, ko = \"30피트 안에 보이는 생물 하나가 매력 내성 굴림을 합니다. 실패하면 주문이 이어지는 동안 해가 없는 반차원으로 쫓겨나, 그곳에서 행동불능 상태가 됩니다. 주문이 끝나면 떠났던 자리로 돌아오고, 그 자리가 막혀 있으면 가장 가까운 빈 곳에 나타납니다. 대상이 이형체·천상체·원소·요정·악마이고 주문이 1분 내내 이어지면, 대상은 돌아오지 않고 자기 종류와 이어진 세계 어딘가로 보내집니다(GM이 정함). 집중, 최대 1분. 높은 레벨로 시전하면 한 단계마다 대상이 하나씩 늘어납니다.\", m = { cast = \"action\", kind = \"save\", save = \"Charisma\", on_save = \"none\", concentration = true, upcast = { targets = 1 }, lrfx = {\"Incapacitated\"}, fail = \"sent to a harmless demiplane, Incapacitated; an extraplanar creature doesn't come back if it lasts 1 minute\" } },\r\n[\"Barkskin\"] = { level = 2, classes = {\"Druid\", \"Ranger\"}, school = \"변환학파\", time = \"추가 행동\", range = \"접촉\", dur = \"1시간\", ko = \"추가 행동으로 동의한 생물 하나를 만집니다. 1시간 동안 그 생물의 피부가 나무껍질처럼 바뀌고, 방어도가 17보다 낮으면 17이 됩니다.\", bmins = 60, m = { cast = \"bonus\", kind = \"buff\", ac_floor = 17, targets = 1 } },\r\n[\"Beacon of Hope\"] = { level = 3, classes = {\"Cleric\"}, save = \"Wisdom\", concentration = true, school = \"방호학파\", time = \"행동\", range = \"30피트\", dur = \"집중, 최대 1분\", cmp = \"VS\", mins = 1, ko = \"30피트 안의 생물을 원하는 만큼 고릅니다. 주문이 이어지는 동안 대상은 지혜 내성 굴림과 죽음 내성 굴림에 이점을 받고, 생명력을 회복할 때는 언제나 나올 수 있는 최대치만큼 회복합니다. 집중, 최대 1분.\", m = { cast = \"action\", kind = \"buff\", concentration = true, maxheal = true, btargets = 12, tell = \"Advantage on Wisdom saves and Death Saving Throws\" } },\r\n[\"Befuddlement\"] = { level = 8, classes = {\"Bard\", \"Druid\", \"Warlock\", \"Wizard\"}, save = \"Intelligence\", half_on_save = true, damage = \"10d12\", damage_type = \"Psychic\", school = \"환혹학파\", time = \"행동\", range = \"150피트\", dur = \"즉시\", cmp = \"VS\", ko = \"150피트 안에 보이는 생물 하나의 정신을 강타합니다. 대상은 지능 내성 굴림을 하고, 실패하면 정신 피해 10d12를 받으며 주문을 쓰거나 마법 행동을 할 수 없게 됩니다. 대상은 30일이 지날 때마다 다시 굴려 성공하면 풀려나고, 상급 회복·치유·소원으로도 풀 수 있습니다. 내성에 성공하면 피해만 절반 받습니다.\", m = { cast = \"action\", kind = \"save\", save = \"Intelligence\", on_save = \"half\", damage = \"10d12\", type = \"Psychic\", lrfx = {} } },\r\n[\"Bestow Curse\"] = { level = 3, classes = {\"Bard\", \"Cleric\", \"Wizard\"}, save = \"Wisdom\", damage = \"1d8\", damage_type = \"Necrotic\", concentration = true, school = \"사령학파\", time = \"행동\", range = \"접촉\", dur = \"집중, 최대 1분\", cmp = \"VS\", mins = 1, ko = \"생물 하나를 만지면, 그 생물이 지혜 내성 굴림을 하고 실패할 때 주문이 이어지는 동안 저주에 걸립니다. 저주는 넷 가운데 하나를 고릅니다. 고른 능력치 하나로 하는 능력 판정과 내성 굴림에 불리점을 받거나, 나를 노리는 명중 굴림에 불리점을 받거나, 싸움 중 자기 턴이 시작될 때마다 지혜 내성 굴림에 실패하면 그 턴에 회피 행동만 하거나, 내가 명중 굴림이나 주문으로 피해를 줄 때마다 사령 피해 1d8을 더 받습니다. 집중, 최대 1분. 높은 레벨로 시전하면 더 오래갑니다(4레벨은 집중 10분, 5~6레벨은 집중 없이 8시간, 7~8레벨은 24시간, 9레벨은 해제될 때까지).\", m = { rider = \"1d8\", rider_type = \"Necrotic\", rider_each = true, cast = \"action\", kind = \"save\", save = \"Wisdom\", on_save = \"none\", concentration = true, lrfx = {}, effect = \"one curse: Disadvantage with an ability / on attacks vs you / Dodge each turn / +1d8 Necrotic from your hits\", fail = \"one curse: Disadvantage with an ability / on attacks vs you / Dodge each turn / +1d8 Necrotic from your hits\" } },\r\n[\"Black Tentacles\"] = { level = 4, classes = {\"Wizard\"}, save = \"Strength\", damage = \"3d6\", damage_type = \"Bludgeoning\", concentration = true, school = \"조형학파\", time = \"행동\", range = \"90피트\", dur = \"집중, 최대 1분\", cmp = \"VS\", mins = 1, ko = \"90피트 안에 보이는 땅의 20피트 정사각형에 꿈틀거리는 검은 촉수가 가득 솟아, 주문이 이어지는 동안 그곳이 어려운 지형이 됩니다. 그 안의 생물은 근력 내성 굴림을 하고, 실패하면 타격 피해 3d6을 받고 주문이 끝날 때까지 포박 상태가 됩니다. 그곳에 들어오거나 그 안에서 턴을 끝내는 생물도 같은 내성 굴림을 합니다(턴마다 한 번). 포박된 생물은 행동을 써서 근력(운동) 판정을 하고, 내 주문 내성 난이도 이상이 나오면 풀려납니다. 집중, 최대 1분.\", m = { cast = \"action\", kind = \"save\", save = \"Strength\", on_save = \"none\", damage = \"3d6\", type = \"Bludgeoning\", concentration = true, lrfx = {\"Restrained\"}, area = true } },\r\n[\"Blade Barrier\"] = { level = 6, classes = {\"Cleric\"}, save = \"Dexterity\", half_on_save = true, damage = \"6d10\", damage_type = \"Force\", concentration = true, school = \"방출학파\", time = \"행동\", range = \"90피트\", dur = \"집중, 최대 10분\", cmp = \"VS\", mins = 10, ko = \"90피트 안에 마법 칼날이 휘몰아치는 벽을 세웁니다. 길이 100피트·높이 20피트·두께 5피트의 곧은 벽이나, 지름 60피트·높이 20피트·두께 5피트의 고리 모양 벽 가운데 고릅니다. 벽은 3/4 엄폐가 되고, 벽이 있는 곳은 어려운 지형입니다. 벽 안에 있는 생물은 민첩 내성 굴림을 해서, 실패하면 역장 피해 6d10, 성공하면 그 절반을 받습니다. 벽 안으로 들어오거나 그 안에서 턴을 끝내는 생물도 같은 내성 굴림을 합니다(턴마다 한 번). 집중, 최대 10분.\", m = { cast = \"action\", kind = \"save\", save = \"Dexterity\", on_save = \"half\", damage = \"6d10\", type = \"Force\", concentration = true, area = true } },\r\n[\"Bless\"] = { level = 1, classes = {\"Cleric\", \"Paladin\"}, concentration = true, school = \"환혹학파\", time = \"행동\", range = \"30피트\", dur = \"집중, 최대 1분\", cmp = \"VS\", mins = 1, ko = \"30피트 안의 생물을 셋까지 축복합니다. 주문이 끝날 때까지 대상은 명중 굴림이나 내성 굴림을 할 때마다 1d4를 더합니다. 집중, 최대 1분. 높은 레벨로 시전하면 한 단계마다 대상이 하나씩 늘어납니다.\", cost = \"a Holy Symbol worth 5+ GP\", cost_ko = \"5 GP 이상의 성표\", m = { cast = \"action\", kind = \"buff\", concentration = true, upcast = { targets = 1 }, targets = 3 } },\r\n[\"Blight\"] = { level = 4, classes = {\"Druid\", \"Sorcerer\", \"Warlock\", \"Wizard\"}, save = \"Constitution\", half_on_save = true, damage = \"8d8\", damage_type = \"Necrotic\", school = \"사령학파\", time = \"행동\", range = \"30피트\", dur = \"즉시\", cmp = \"VS\", ko = \"30피트 안에 보이는 생물 하나가 건강 내성 굴림을 해서, 실패하면 사령 피해 8d8, 성공하면 그 절반을 받습니다. 식물 생물은 자동으로 실패합니다. 생물 대신 나무나 덤불 같은 평범한 식물을 노리면, 그 식물은 내성 굴림 없이 시들어 죽습니다. 높은 레벨로 시전하면 한 단계마다 피해가 1d8씩 늘어납니다.\", m = { cast = \"action\", kind = \"save\", save = \"Constitution\", on_save = \"half\", damage = \"8d8\", type = \"Necrotic\", upcast = { dice = \"1d8\" } } },\r\n[\"Blindness/Deafness\"] = { level = 2, classes = {\"Bard\", \"Cleric\", \"Sorcerer\", \"Wizard\"}, save = \"Constitution\", school = \"변환학파\", time = \"행동\", range = \"120피트\", dur = \"1분\", cmp = \"V\", ko = \"120피트 안에 보이는 생물 하나가 건강 내성 굴림을 합니다. 실패하면 1분 동안 장님 상태나 귀머거리 상태 가운데 내가 고른 상태가 됩니다. 대상은 자기 턴이 끝날 때마다 다시 굴려, 성공하면 풀려납니다. 높은 레벨로 시전하면 한 단계마다 대상이 하나씩 늘어납니다.\", m = { puts = {\"Blinded\", \"Deafened\"}, cast = \"action\", kind = \"save\", save = \"Constitution\", on_save = \"none\", upcast = { targets = 1 }, lrfx = {\"Blinded\", \"Deafened\"}, fail = \"Blinded or Deafened, repeats the save each turn\" } },\r\n[\"Blink\"] = { level = 3, classes = {\"Sorcerer\", \"Wizard\"}, school = \"변환학파\", time = \"행동\", range = \"자신\", dur = \"1분\", cmp = \"VS\", ko = \"1분 동안 내 턴이 끝날 때마다 1d6을 굴려, 4~6이 나오면 지금 세계에서 사라져 에테르계로 옮겨 갑니다(이미 에테르계에 있으면 주문이 바로 끝남). 에테르계에서는 떠나온 세계가 잿빛으로 60피트까지만 보이고, 에테르계에 있는 생물과만 서로 영향을 주고받으며, 원래 세계의 생물은 특별한 능력이 없으면 나를 알아채지 못합니다. 다음 내 턴이 시작될 때(또는 주문이 끝날 때) 원래 세계로 돌아와, 떠났던 곳 10피트 안의 보이는 빈 곳에 나타납니다.\", bmins = 1, m = { cast = \"action\", kind = \"buff\" } },\r\n[\"Blur\"] = { level = 2, classes = {\"Sorcerer\", \"Wizard\"}, concentration = true, school = \"환영학파\", time = \"행동\", range = \"자신\", dur = \"집중, 최대 1분\", cmp = \"V\", mins = 1, ko = \"내 몸이 흐릿하게 번져 보입니다. 주문이 이어지는 동안 나를 노리는 명중 굴림은 모두 불리점을 받습니다. 맹안시야나 진시야로 나를 보는 공격자에게는 통하지 않습니다. 집중, 최대 1분.\", m = { cast = \"action\", kind = \"buff\", concentration = true, self = true, tell = \"attack rolls against them have Disadvantage (not from an attacker with Blindsight or Truesight)\" } },\r\n[\"Burning Hands\"] = { level = 1, classes = {\"Sorcerer\", \"Wizard\"}, save = \"Dexterity\", half_on_save = true, damage = \"3d6\", damage_type = \"Fire\", school = \"방출학파\", time = \"행동\", range = \"자신\", dur = \"즉시\", cmp = \"VS\", ko = \"내게서 얇은 불길이 뿜어져 나갑니다. 15피트 원뿔 안의 생물은 모두 민첩 내성 굴림을 하고, 실패하면 화염 피해 3d6, 성공하면 그 절반을 받습니다. 원뿔 안에서 아무도 들거나 입지 않은 물건 가운데 타는 것에는 불이 붙습니다. 높은 레벨로 시전하면 한 단계마다 피해가 1d6씩 늘어납니다.\", m = { cast = \"action\", kind = \"save\", save = \"Dexterity\", on_save = \"half\", damage = \"3d6\", type = \"Fire\", upcast = { dice = \"1d6\" }, area = true } },\r\n[\"Call Lightning\"] = { level = 3, classes = {\"Druid\"}, save = \"Dexterity\", half_on_save = true, damage = \"3d10\", damage_type = \"Lightning\", concentration = true, school = \"조형학파\", time = \"행동\", range = \"120피트\", dur = \"집중, 최대 10분\", cmp = \"VS\", mins = 10, ko = \"120피트 안, 내 머리 위로 보이는 곳에 높이 10피트·반경 60피트 원기둥 모양의 먹구름이 나타납니다. 시전할 때 구름 아래에 보이는 한 지점을 골라 번개를 내리꽂으면, 그 지점 5피트 안의 생물은 모두 민첩 내성 굴림을 해서 실패하면 번개 피해 3d10, 성공하면 그 절반을 받습니다. 주문이 이어지는 동안 마법 행동으로 같은 곳이나 다른 곳에 번개를 다시 내릴 수 있습니다. 바깥에서 폭풍이 치는 중에 시전하면 새 구름 대신 그 폭풍을 부리게 되고, 피해가 1d10 늘어납니다. 집중, 최대 10분. 높은 레벨로 시전하면 한 단계마다 피해가 1d10씩 늘어납니다.\", m = { cast = \"action\", kind = \"save\", save = \"Dexterity\", on_save = \"half\", damage = \"3d10\", type = \"Lightning\", concentration = true, upcast = { dice = \"1d10\" }, area = true } },\r\n[\"Calm Emotions\"] = { level = 2, classes = {\"Bard\", \"Cleric\"}, save = \"Charisma\", concentration = true, school = \"환혹학파\", time = \"행동\", range = \"60피트\", dur = \"집중, 최대 1분\", cmp = \"VS\", mins = 1, ko = \"60피트 안의 한 지점을 중심으로 반경 20피트 안의 인간형은 모두 매력 내성 굴림을 합니다. 실패한 생물마다 둘 가운데 하나를 고릅니다. 하나는 주문이 끝날 때까지 매혹·공포 상태에 면역이 되는 것으로, 이미 걸려 있었다면 그동안 효과가 멈춥니다. 다른 하나는 그 생물이 적대하던 생물 가운데 내가 고른 생물들에게 무관심해지는 것으로, 그 생물이 피해를 받거나 동료가 피해를 받는 것을 보면 끝납니다. 주문이 끝나면 원래 태도로 돌아옵니다. 집중, 최대 1분.\", m = { cast = \"action\", kind = \"save\", save = \"Charisma\", on_save = \"none\", concentration = true, lrfx = {\"Charmed\", \"Frightened\"}, area = true, fail = \"no Charmed/Frightened, or Indifferent toward chosen creatures\" } },\r\n[\"Chain Lightning\"] = { level = 6, classes = {\"Sorcerer\", \"Wizard\"}, save = \"Dexterity\", half_on_save = true, damage = \"10d8\", damage_type = \"Lightning\", school = \"방출학파\", time = \"행동\", range = \"150피트\", dur = \"즉시\", cmp = \"VS\", ko = \"150피트 안에 보이는 대상 하나에게 번개를 쏩니다. 번개는 그 대상에서 셋으로 갈라져, 첫 대상 30피트 안에서 내가 고른 다른 대상을 셋까지 칩니다. 생물도 물건도 대상이 될 수 있고, 한 대상은 번개 하나만 맞습니다. 각 대상은 민첩 내성 굴림을 해서, 실패하면 번개 피해 10d8, 성공하면 그 절반을 받습니다. 높은 레벨로 시전하면 한 단계마다 첫 대상에서 갈라지는 번개가 하나씩 늘어납니다.\", m = { cast = \"action\", kind = \"save\", save = \"Dexterity\", on_save = \"half\", damage = \"10d8\", type = \"Lightning\", upcast = { targets = 1 } } },\r\n[\"Charm Monster\"] = { level = 4, classes = {\"Bard\", \"Druid\", \"Sorcerer\", \"Warlock\", \"Wizard\"}, save = \"Wisdom\", school = \"환혹학파\", time = \"행동\", range = \"30피트\", dur = \"1시간\", cmp = \"VS\", ko = \"30피트 안에 보이는 생물 하나가 지혜 내성 굴림을 합니다(나나 내 동료와 싸우는 중이면 이점). 실패하면 1시간 동안, 또는 나나 내 동료가 대상에게 피해를 줄 때까지 매혹 상태가 되어 나를 우호적으로 대합니다. 주문이 끝나면 대상은 내가 자기를 매혹했다는 것을 알게 됩니다. 높은 레벨로 시전하면 한 단계마다 대상이 하나씩 늘어납니다.\", m = { puts = {\"Charmed\"}, cast = \"action\", kind = \"save\", save = \"Wisdom\", on_save = \"none\", upcast = { targets = 1 }, lrfx = {\"Charmed\"}, fail = \"Charmed and Friendly for 1 hour or until you or your allies damage it; Advantage on the save if you are fighting it\" } },\r\n[\"Charm Person\"] = { level = 1, classes = {\"Bard\", \"Druid\", \"Sorcerer\", \"Warlock\", \"Wizard\"}, save = \"Wisdom\", school = \"환혹학파\", time = \"행동\", range = \"30피트\", dur = \"1시간\", cmp = \"VS\", ko = \"30피트 안에 보이는 인간형 하나가 지혜 내성 굴림을 합니다(나나 내 동료와 싸우는 중이면 이점). 실패하면 1시간 동안, 또는 나나 내 동료가 대상에게 피해를 줄 때까지 매혹 상태가 되어 나를 우호적으로 대합니다. 주문이 끝나면 대상은 내가 자기를 매혹했다는 것을 알게 됩니다. 높은 레벨로 시전하면 한 단계마다 대상이 하나씩 늘어납니다.\", m = { puts = {\"Charmed\"}, cast = \"action\", kind = \"save\", save = \"Wisdom\", on_save = \"none\", upcast = { targets = 1 }, lrfx = {\"Charmed\"}, fail = \"Charmed (Advantage on the save if you are fighting it)\" } },\r\n[\"Chill Touch\"] = { level = 0, classes = {\"Sorcerer\", \"Warlock\", \"Wizard\"}, attack = \"melee\", damage = \"1d10\", damage_type = \"Necrotic\", school = \"사령학파\", time = \"행동\", range = \"접촉\", dur = \"즉시\", cmp = \"VS\", ko = \"무덤의 한기를 실어, 손이 닿는 거리의 대상에게 근접 주문 공격을 합니다. 맞으면 사령 피해 1d10을 주고, 대상은 다음 내 턴이 끝날 때까지 생명력을 되찾지 못합니다. 5·11·17레벨에 피해 주사위가 하나씩 늘어납니다.\", m = { cast = \"action\", kind = \"attack\", attack = \"melee\", damage = \"1d10\", type = \"Necrotic\", cantrip = true } },\r\n[\"Chromatic Orb\"] = { level = 1, classes = {\"Sorcerer\", \"Wizard\"}, attack = \"ranged\", school = \"방출학파\", time = \"행동\", range = \"90피트\", dur = \"즉시\", cmp = \"VS\", ko = \"산성·냉기·화염·번개·독성·천둥 가운데 하나를 골라, 90피트 안의 대상에게 에너지 구슬을 던져 원거리 주문 공격을 합니다. 맞으면 고른 종류의 피해 3d8을 줍니다. 피해 주사위에서 같은 숫자가 둘 이상 나오면, 구슬이 대상 30피트 안의 다른 대상에게 튀어 가고 새로 명중과 피해를 굴립니다(1레벨로 시전하면 한 번만 튐). 높은 레벨로 시전하면 한 단계마다 피해가 1d8씩 늘고, 구슬은 시전한 레벨의 수만큼까지 튈 수 있습니다(한 생물은 한 번만 맞음).\", cost = \"a diamond worth 50+ GP\", cost_ko = \"50 GP 이상의 다이아몬드\", m = { cast = \"action\", kind = \"attack\", attack = \"ranged\", damage = \"3d8\", type = \"choice (Acid, Cold, Fire, Lightning, Poison, Thunder)\", upcast = { dice = \"1d8\" } } },\r\n[\"Circle of Death\"] = { level = 6, classes = {\"Sorcerer\", \"Warlock\", \"Wizard\"}, save = \"Constitution\", half_on_save = true, damage = \"8d8\", damage_type = \"Necrotic\", school = \"사령학파\", time = \"행동\", range = \"150피트\", dur = \"즉시\", cmp = \"VS\", ko = \"150피트 안의 고른 지점에서 죽음의 기운이 반경 60피트 구체로 퍼져 나갑니다. 그 안의 생물은 모두 건강 내성 굴림을 해서, 실패하면 사령 피해 8d8, 성공하면 그 절반을 받습니다. 높은 레벨로 시전하면 한 단계마다 피해가 2d8씩 늘어납니다.\", cost = \"the powder of a crushed black pearl worth 500+ GP\", cost_ko = \"500 GP 이상의 흑진주를 빻은 가루\", m = { cast = \"action\", kind = \"save\", save = \"Constitution\", on_save = \"half\", damage = \"8d8\", type = \"Necrotic\", upcast = { dice = \"2d8\" }, area = true } },\r\n[\"Clairvoyance\"] = { level = 3, classes = {\"Bard\", \"Cleric\", \"Sorcerer\", \"Wizard\"}, concentration = true, school = \"예지학파\", time = \"10분\", range = \"1마일\", dur = \"집중, 최대 10분\", cmp = \"VS\", mins = 10, ko = \"1마일 안에서 가 보았거나 본 적 있는 곳, 또는 문 뒤·모퉁이 너머·숲속처럼 몰라도 짐작할 수 있는 곳에 보이지 않는 감지점을 만듭니다. 감지점은 만질 수도 부술 수도 없고, 주문이 이어지는 동안 그 자리에 있습니다. 시전할 때 보기나 듣기 가운데 하나를 골라 감지점에 있는 것처럼 그 감각을 쓰고, 추가 행동으로 다른 쪽으로 바꿀 수 있습니다. 투명체 감지나 진시야로 보면 감지점은 주먹만 한 빛 구슬로 보입니다. 시전에 10분이 걸립니다. 집중, 최대 10분.\", cost = \"a focus worth 100+ GP, either a jeweled horn for hearing or a glass eye for seeing\", cost_ko = \"100 GP 이상의 초점 (듣기에는 보석 박힌 뿔, 보기에는 유리 눈)\", m = { cast = \"10 minutes\", kind = \"utility\", concentration = true } },\r\n[\"Clone\"] = { level = 8, classes = {\"Wizard\"}, school = \"사령학파\", time = \"1시간\", range = \"접촉\", dur = \"즉시\", cmp = \"VS\", ko = \"생물 하나나 그 생물의 살점(1세제곱인치 이상)을 만지면, 시전에 쓴 그릇 안에서 그 생물의 복제 몸이 자라기 시작해 120일 뒤에 다 자랍니다. 복제 몸은 움직이지 않으며, 원래 생물과 같은 나이로 할지 더 어리게 할지는 내가 고릅니다. 그릇을 건드리지 않는 한 복제 몸은 언제까지나 그대로 남습니다. 복제 몸이 다 자란 뒤 원래 생물이 죽으면, 영혼이 자유롭고 돌아오려 할 때 복제 몸으로 옮겨 갑니다. 복제 몸은 몸이 똑같고 성격·기억·능력도 같지만 원래 생물의 장비는 없습니다. 원래 몸은 영혼이 떠났으므로 되살릴 수 없습니다. 시전에 1시간이 걸립니다.\", cost = \"a diamond worth 1,000+ GP, consumed, and a sealable vessel worth 2,000+ GP that is large enough to hold the creature being cloned\", cost_ko = \"1,000 GP 이상의 다이아몬드 (시전하면 사라짐)와, 대상이 들어갈 만큼 크고 밀봉되는 2,000 GP 이상의 그릇\", m = { cast = \"1 hour\", kind = \"utility\" } },\r\n[\"Cloudkill\"] = { level = 5, classes = {\"Sorcerer\", \"Wizard\"}, save = \"Constitution\", half_on_save = true, damage = \"5d8\", damage_type = \"Poison\", concentration = true, school = \"조형학파\", time = \"행동\", range = \"120피트\", dur = \"집중, 최대 10분\", cmp = \"VS\", mins = 10, ko = \"120피트 안의 한 지점을 중심으로 반경 20피트 구체의 누르스름한 초록 독안개를 만듭니다. 안개 속은 완전히 가려지고, 돌풍 같은 강한 바람이 불면 흩어지며 주문이 끝납니다. 그 안의 생물은 건강 내성 굴림을 해서, 실패하면 독성 피해 5d8, 성공하면 그 절반을 받습니다. 안개가 생물이 있는 곳으로 옮겨 가거나, 생물이 안개에 들어오거나 그 안에서 턴을 끝낼 때도 같은 내성 굴림을 합니다(턴마다 한 번). 안개는 내 턴이 시작될 때마다 나에게서 10피트씩 멀어집니다. 집중, 최대 10분. 높은 레벨로 시전하면 한 단계마다 피해가 1d8씩 늘어납니다.\", m = { cast = \"action\", kind = \"save\", save = \"Constitution\", on_save = \"half\", damage = \"5d8\", type = \"Poison\", concentration = true, upcast = { dice = \"1d8\" }, area = true } },\r\n[\"Color Spray\"] = { level = 1, classes = {\"Bard\", \"Sorcerer\", \"Wizard\"}, save = \"Constitution\", school = \"환영학파\", time = \"행동\", range = \"자신\", dur = \"즉시\", cmp = \"VS\", ko = \"내게서 번쩍이는 색색의 빛이 뻗어 나갑니다. 15피트 원뿔 안의 생물은 모두 건강 내성 굴림을 하고, 실패하면 다음 내 턴이 끝날 때까지 장님 상태가 됩니다.\", m = { puts = {\"Blinded\"}, cast = \"action\", kind = \"save\", save = \"Constitution\", on_save = \"none\", lrfx = {\"Blinded\"}, area = true, fail = \"Blinded until the end of your next turn\" } },\r\n[\"Command\"] = { level = 1, classes = {\"Bard\", \"Cleric\", \"Paladin\"}, save = \"Wisdom\", school = \"환혹학파\", time = \"행동\", range = \"60피트\", dur = \"즉시\", cmp = \"V\", ko = \"60피트 안에 보이는 생물 하나에게 한 단어로 명령합니다. 대상은 지혜 내성 굴림을 하고, 실패하면 자기 다음 턴에 그 명령을 따릅니다. 명령은 다가와(가장 짧은 길로 나에게 다가오고, 5피트 안에 들어오면 턴을 끝냄), 버려(들고 있는 것을 떨어뜨리고 턴을 끝냄), 도망쳐(그 턴 내내 할 수 있는 가장 빠른 방법으로 나에게서 멀어짐), 엎드려(넘어진 상태가 되고 턴을 끝냄), 멈춰(움직이지 않고 행동도 추가 행동도 하지 않음) 가운데 하나입니다. 높은 레벨로 시전하면 한 단계마다 대상이 하나씩 늘어납니다.\", m = { puts = {\"Prone\"}, cast = \"action\", kind = \"save\", save = \"Wisdom\", on_save = \"none\", upcast = { targets = 1 }, lrfx = {}, fail = \"obeys a one-word command on its next turn (Approach, Drop, Flee, Grovel, Halt)\" } },\r\n[\"Commune\"] = { level = 5, classes = {\"Cleric\"}, ritual = true, school = \"예지학파\", time = \"1분 · 의식 가능\", range = \"자신\", dur = \"1분\", cmp = \"VS\", ko = \"신이나 신의 대리자와 이어져, 예나 아니오로 답할 수 있는 질문을 셋까지 묻습니다. 질문은 주문이 끝나기 전(1분 안)에 모두 해야 합니다. 질문마다 옳은 답을 받지만, 신도 모르는 일이면 '분명하지 않음'이라는 답이 올 수 있고, 한 단어로 답하면 오해를 사거나 신의 뜻에 어긋날 때는 짧은 말로 답이 올 수도 있습니다. 긴 휴식을 마치기 전에 두 번 이상 시전하면, 두 번째부터 시전할 때마다 25%씩 쌓이는 확률로 답을 받지 못합니다. 시전에 1분이 걸리고, 의식으로 시전할 수 있습니다.\", m = { cast = \"1 minute\", kind = \"utility\" } },\r\n[\"Commune with Nature\"] = { level = 5, classes = {\"Druid\", \"Ranger\"}, ritual = true, school = \"예지학파\", time = \"1분 · 의식 가능\", range = \"자신\", dur = \"즉시\", cmp = \"VS\", ko = \"자연의 정령과 교감해 주변에 대해 알아냅니다. 바깥에서는 내 둘레 3마일, 동굴 같은 자연 지하에서는 300피트까지 알 수 있고, 성이나 마을처럼 자연이 건물로 바뀐 곳에서는 통하지 않습니다. 정착지의 위치, 다른 세계로 가는 관문의 위치, 도전 지수 10 이상인 천상체·원소·요정·악마·언데드 하나의 위치(GM이 고름), 가장 흔한 식물·광물·야수(어느 쪽을 알지는 내가 고름), 물이 있는 곳의 위치 가운데 셋을 골라 그 범위 안에서 알아냅니다. 시전에 1분이 걸리고, 의식으로 시전할 수 있습니다.\", m = { cast = \"1 minute\", kind = \"utility\" } },\r\n[\"Comprehend Languages\"] = { level = 1, classes = {\"Bard\", \"Sorcerer\", \"Warlock\", \"Wizard\"}, ritual = true, school = \"예지학파\", time = \"행동 · 의식 가능\", range = \"자신\", dur = \"1시간\", cmp = \"VS\", ko = \"1시간 동안 귀로 듣거나 수어로 보는 모든 언어를 글자 그대로의 뜻으로 알아듣습니다. 쓰인 글도 읽을 수 있지만, 글이 적힌 면에 손을 대고 있어야 하고 한 쪽을 읽는 데 1분쯤 걸립니다. 기호나 암호 같은 숨은 메시지는 풀지 못합니다. 의식으로 시전할 수 있습니다.\", m = { cast = \"action\", kind = \"utility\" } },\r\n[\"Compulsion\"] = { level = 4, classes = {\"Bard\"}, save = \"Wisdom\", concentration = true, school = \"환혹학파\", time = \"행동\", range = \"30피트\", dur = \"집중, 최대 1분\", cmp = \"VS\", mins = 1, ko = \"30피트 안에 보이는 생물을 원하는 만큼 고르면, 대상마다 지혜 내성 굴림을 하고 실패하면 주문이 이어지는 동안 매혹 상태가 됩니다. 그동안 나는 추가 행동으로 수평 방향 하나를 가리킬 수 있고, 매혹된 대상은 자기 다음 턴에 가장 안전한 길로 그 방향을 향해 이동을 최대한 써서 움직여야 합니다. 그렇게 움직인 뒤 대상은 다시 굴려, 성공하면 풀려납니다. 집중, 최대 1분.\", m = { cast = \"action\", kind = \"save\", save = \"Wisdom\", on_save = \"none\", concentration = true, lrfx = {\"Charmed\"}, fail = \"Charmed; each must move the way you point (Bonus Action), then repeats the save\" } },\r\n[\"Cone of Cold\"] = { level = 5, classes = {\"Druid\", \"Sorcerer\", \"Wizard\"}, save = \"Constitution\", half_on_save = true, damage = \"8d8\", damage_type = \"Cold\", school = \"방출학파\", time = \"행동\", range = \"자신\", dur = \"즉시\", cmp = \"VS\", ko = \"내게서 60피트 원뿔로 매서운 찬바람을 뿜어냅니다. 그 안의 생물은 모두 건강 내성 굴림을 해서, 실패하면 냉기 피해 8d8, 성공하면 그 절반을 받습니다. 이 주문으로 죽은 생물은 녹을 때까지 얼어붙은 조각상이 됩니다. 높은 레벨로 시전하면 한 단계마다 피해가 1d8씩 늘어납니다.\", m = { cast = \"action\", kind = \"save\", save = \"Constitution\", on_save = \"half\", damage = \"8d8\", type = \"Cold\", upcast = { dice = \"1d8\" }, area = true } },\r\n[\"Confusion\"] = { level = 4, classes = {\"Bard\", \"Druid\", \"Sorcerer\", \"Wizard\"}, save = \"Wisdom\", concentration = true, school = \"환혹학파\", time = \"행동\", range = \"90피트\", dur = \"집중, 최대 1분\", cmp = \"VS\", mins = 1, ko = \"90피트 안의 고른 지점을 중심으로 반경 10피트 구체 안의 생물은 모두 지혜 내성 굴림을 합니다. 실패하면 추가 행동과 반응행동을 할 수 없고, 자기 턴이 시작될 때마다 1d10을 굴려 그 턴에 할 일을 정합니다. 1이면 행동 없이 무작위 방향(1d4로 정함)으로 이동을 모두 쓰고, 2~6이면 움직이지도 행동하지도 않으며, 7~8이면 움직이지 않고 손 닿는 거리의 무작위 생물 하나를 근접 공격하고(닿는 생물이 없으면 아무것도 하지 않음), 9~10이면 하고 싶은 대로 합니다. 대상은 자기 턴이 끝날 때마다 다시 굴려, 성공하면 풀려납니다. 집중, 최대 1분. 높은 레벨로 시전하면 한 단계마다 반경이 5피트씩 늘어납니다.\", m = { cast = \"action\", kind = \"save\", save = \"Wisdom\", on_save = \"none\", concentration = true, upcast = { note = \"radius +5 ft per slot level above 4\" }, lrfx = {}, area = true, fail = \"no Bonus Actions or Reactions; rolls 1d10 each turn for what it does; repeats the save at the end of its turns\" } },\r\n[\"Conjure Animals\"] = { level = 3, classes = {\"Druid\", \"Ranger\"}, save = \"Strength\", damage = \"3d10\", damage_type = \"Slashing\", concentration = true, school = \"조형학파\", time = \"행동\", range = \"60피트\", dur = \"집중, 최대 10분\", cmp = \"VS\", mins = 10, ko = \"60피트 안에 보이는 빈 곳에, 늑대·뱀·새처럼 내가 고른 동물 모습을 한 자연의 영들을 대형 무리로 부릅니다. 무리는 만질 수 없습니다. 무리 5피트 안에 있는 동안 나는 근력 내성 굴림에 이점을 받고, 내 턴에 움직일 때 무리도 보이는 빈 곳으로 30피트까지 옮길 수 있습니다. 무리가 보이는 생물의 10피트 안으로 움직이거나, 보이는 생물이 무리 10피트 안에 들어오거나 그 안에서 턴을 끝내면, 그 생물에게 민첩 내성 굴림을 시켜 실패하면 참격 피해 3d10을 줄 수 있습니다(턴마다 한 번). 집중, 최대 10분. 높은 레벨로 시전하면 한 단계마다 피해가 1d10씩 늘어납니다.\", m = { cast = \"action\", kind = \"save\", save = \"Dexterity\", on_save = \"none\", damage = \"3d10\", type = \"Slashing\", concentration = true, upcast = { dice = \"1d10\" } } },\r\n[\"Conjure Celestial\"] = { level = 7, classes = {\"Cleric\"}, save = \"Dexterity\", half_on_save = true, damage = \"6d12\", damage_type = \"Radiant\", heal = \"4d12\", concentration = true, school = \"조형학파\", time = \"행동\", range = \"90피트\", dur = \"집중, 최대 10분\", cmp = \"VS\", mins = 10, ko = \"90피트 안의 한 지점을 중심으로, 반경 10피트·높이 40피트 원기둥 모양의 빛기둥이 되어 나타나는 천상의 영혼을 부릅니다. 원기둥 안에 보이는 생물마다 두 빛 가운데 하나를 비춥니다. 치유의 빛을 받은 생물은 생명력을 4d12 + 주문시전 능력치 수정치만큼 되찾고, 작열의 빛을 받은 생물은 민첩 내성 굴림을 해서 실패하면 광휘 피해 6d12, 성공하면 그 절반을 받습니다. 주문이 이어지는 동안 원기둥 안은 밝은 빛으로 차고, 내 턴에 내가 움직일 때 원기둥도 30피트까지 옮길 수 있습니다. 원기둥이 보이는 생물이 있는 곳으로 옮겨 가거나, 보이는 생물이 원기둥에 들어오거나 그 안에서 턴을 끝낼 때도 빛 하나를 비출 수 있습니다(한 생물은 턴마다 한 번만). 집중, 최대 10분. 높은 레벨로 시전하면 한 단계마다 회복량과 피해가 1d12씩 늘어납니다.\", m = { cast = \"action\", kind = \"save\", save = \"Dexterity\", on_save = \"half\", damage = \"6d12\", type = \"Radiant\", concentration = true, upcast = { dice = \"1d12\" }, area = true } },\r\n[\"Conjure Elemental\"] = { level = 5, classes = {\"Druid\", \"Wizard\"}, save = \"Dexterity\", concentration = true, school = \"조형학파\", time = \"행동\", range = \"60피트\", dur = \"집중, 최대 10분\", cmp = \"VS\", mins = 10, ko = \"60피트 안의 빈 곳에, 원소계에서 온 만질 수 없는 대형 정령을 부릅니다. 바람(번개)·흙(천둥)·불(화염)·물(냉기) 가운데 하나를 고르면, 괄호 안의 것이 정령의 피해 종류가 됩니다. 정령이 포박한 생물이 없는 동안, 보이는 생물이 정령이 있는 곳에 들어오거나 정령 5피트 안에서 턴을 시작하면 그 생물에게 민첩 내성 굴림을 시킬 수 있습니다. 실패하면 그 종류의 피해 8d8을 받고 주문이 끝날 때까지 포박 상태가 됩니다. 포박된 생물은 자기 턴이 시작될 때마다 다시 굴려, 실패하면 피해 4d8을 받고 성공하면 풀려납니다. 집중, 최대 10분. 높은 레벨로 시전하면 한 단계마다 피해가 1d8씩 늘어납니다.\", m = { cast = \"action\", kind = \"save\", save = \"Dexterity\", on_save = \"none\", damage = \"8d8\", type = \"choice (Lightning, Thunder, Fire, Cold)\", concentration = true, upcast = { dice = \"1d8\" }, lrfx = {\"Restrained\"} } },\r\n[\"Conjure Fey\"] = { level = 6, classes = {\"Druid\"}, attack = \"melee\", concentration = true, school = \"조형학파\", time = \"행동\", range = \"60피트\", dur = \"집중, 최대 10분\", cmp = \"VS\", mins = 10, ko = \"60피트 안에 보이는 빈 곳에, 내가 고른 요정의 모습을 한 요정계의 중형 영혼을 부릅니다. 영혼이 나타날 때 영혼 5피트 안의 생물 하나에게 근접 주문 공격을 해서, 맞으면 정신 피해 3d12 + 주문시전 능력치 수정치를 주고, 대상은 다음 내 턴이 시작될 때까지 나와 영혼을 두려워하는 공포 상태가 됩니다. 이후 내 턴마다 추가 행동으로 영혼을, 떠난 자리 30피트 안의 보이는 빈 곳으로 순간이동시키고 다시 공격할 수 있습니다. 집중, 최대 10분. 높은 레벨로 시전하면 한 단계마다 피해가 1d12씩 늘어납니다.\", m = { cast = \"action\", kind = \"attack\", attack = \"melee\", damage = \"3d12+MOD\", type = \"Psychic\", concentration = true, upcast = { dice = \"1d12\" } } },\r\n[\"Conjure Minor Elementals\"] = { level = 4, classes = {\"Druid\", \"Wizard\"}, concentration = true, school = \"조형학파\", time = \"행동\", range = \"자신\", dur = \"집중, 최대 10분\", cmp = \"VS\", mins = 10, ko = \"원소계의 정령들을 불러, 주문이 이어지는 동안 내 주위 15피트를 맴돌게 합니다. 그 범위 안의 생물을 내 공격으로 맞힐 때마다 피해 2d8을 더 주며, 피해 종류는 공격할 때마다 산성·냉기·화염·번개 가운데 고릅니다. 그 범위의 땅은 내 적에게 어려운 지형입니다. 집중, 최대 10분. 높은 레벨로 시전하면 한 단계마다 피해가 1d8씩 늘어납니다.\", m = { cast = \"action\", kind = \"buff\", concentration = true, rider = \"2d8\", rider_type = \"choice (Acid, Cold, Fire, Lightning)\", rider_each = true, upcast = { dice = \"1d8\" }, effect = \"+2d8 on every hit you make against a creature in your 15-ft emanation; Difficult Terrain for enemies\" } },\r\n[\"Conjure Woodland Beings\"] = { level = 4, classes = {\"Druid\", \"Ranger\"}, save = \"Wisdom\", half_on_save = true, damage = \"5d8\", damage_type = \"Force\", concentration = true, school = \"조형학파\", time = \"행동\", range = \"자신\", dur = \"집중, 최대 10분\", cmp = \"VS\", mins = 10, ko = \"자연의 정령들을 불러, 주문이 이어지는 동안 내 주위 10피트를 맴돌게 합니다. 내가 움직여 이 범위가 보이는 생물에게 닿거나, 보이는 생물이 범위에 들어오거나 그 안에서 턴을 끝내면, 그 생물에게 지혜 내성 굴림을 시켜 실패하면 역장 피해 5d8, 성공하면 그 절반을 줄 수 있습니다(턴마다 한 번). 주문이 이어지는 동안 이탈 행동을 추가 행동으로 할 수 있습니다. 집중, 최대 10분. 높은 레벨로 시전하면 한 단계마다 피해가 1d8씩 늘어납니다.\", m = { cast = \"action\", kind = \"save\", save = \"Wisdom\", on_save = \"half\", damage = \"5d8\", type = \"Force\", concentration = true, upcast = { dice = \"1d8\" } } },\r\n[\"Contact Other Plane\"] = { level = 5, classes = {\"Warlock\", \"Wizard\"}, save = \"Intelligence\", damage = \"6d6\", damage_type = \"Psychic\", ritual = true, school = \"예지학파\", time = \"1분 · 의식 가능\", range = \"자신\", dur = \"1분\", cmp = \"V\", ko = \"다른 세계의 반신이나 오래전에 죽은 현자의 영혼처럼 많은 것을 아는 존재와 마음으로 이어집니다. 그런 존재와 닿으면 정신이 망가질 수 있어, 시전할 때 난이도 15 지능 내성 굴림을 합니다. 성공하면 주문이 끝나기 전(1분 안)에 질문을 다섯까지 할 수 있고, GM이 '예', '아니오', '아마도', '결코', '상관없음', '분명하지 않음' 같은 한 단어로 답합니다(한 단어가 오해를 사면 짧은 말로). 실패하면 정신 피해 6d6을 받고 긴 휴식을 마칠 때까지 행동불능 상태가 됩니다(상급 회복으로 풀림). 시전에 1분이 걸리고, 의식으로 시전할 수 있습니다.\", m = { cast = \"1 minute\", kind = \"utility\" } },\r\n[\"Contagion\"] = { level = 5, classes = {\"Cleric\", \"Druid\"}, save = \"Constitution\", damage = \"11d8\", damage_type = \"Necrotic\", school = \"사령학파\", time = \"행동\", range = \"접촉\", dur = \"7일\", ko = \"손으로 만진 생물에게 마법 역병을 옮깁니다. 대상은 건강 내성 굴림을 하고, 실패하면 사령 피해 11d8을 받고 중독 상태가 됩니다. 시전할 때 능력치 하나를 고르며, 대상은 중독인 동안 그 능력치의 내성 굴림에 불리점을 받습니다. 대상은 자기 턴이 끝날 때마다 다시 굴려 성공이나 실패가 세 번 쌓일 때까지 계속합니다. 성공이 세 번이면 주문이 끝나고, 실패가 세 번이면 주문이 그 대상에게 7일 동안 이어집니다. 그동안 중독을 끝내는 효과를 받아도, 건강 내성 굴림에 성공해야 중독이 끝납니다.\", m = { puts = {\"Poisoned\"}, cast = \"action\", kind = \"save\", save = \"Constitution\", on_save = \"none\", damage = \"11d8\", type = \"Necrotic\", lrfx = {\"Poisoned\"} } },\r\n[\"Contingency\"] = { level = 6, classes = {\"Wizard\"}, school = \"방호학파\", time = \"10분\", range = \"자신\", dur = \"10일\", cmp = \"VS\", ko = \"내가 시전할 수 있는 5레벨 이하 주문 가운데, 시전 시간이 행동이고 나를 목표로 삼을 수 있는 주문 하나를 고릅니다. 대비책을 시전하면서 그 주문도 함께 시전해 두는데(두 주문 몫을 모두 씀), 그 주문은 바로 일어나지 않습니다. 대신 시전할 때 정한 조건이 처음 일어나는 순간, 내가 원하든 원하지 않든 나에게만 발동하고 대비책이 끝납니다(예: 물에 잠기면 수중 호흡이 발동). 대비책은 한 번에 하나만 걸어 둘 수 있어 다시 시전하면 앞의 것이 끝나고, 재료인 조각상을 몸에 지니지 않아도 끝납니다. 시전에 10분이 걸리고, 10일 동안 이어집니다.\", cost = \"a gem-encrusted statuette of yourself worth 1,500+ GP\", cost_ko = \"1,500 GP 이상의, 보석 박힌 내 조각상\", m = { cast = \"10 minutes\", kind = \"utility\" } },\r\n[\"Continual Flame\"] = { level = 2, classes = {\"Cleric\", \"Druid\", \"Wizard\"}, school = \"방출학파\", time = \"행동\", range = \"접촉\", dur = \"해제될 때까지\", cmp = \"VS\", ko = \"내가 만진 물건에서 불꽃이 피어나, 반경 20피트를 밝게, 그 바깥 20피트를 희미하게 비춥니다. 보통 불처럼 보이지만 열이 나지 않고 연료도 쓰지 않습니다. 덮어 가릴 수는 있어도 숨을 막거나 물을 부어 끌 수는 없으며, 해제될 때까지 이어집니다.\", cost = \"ruby dust worth 50+ GP, consumed\", cost_ko = \"50 GP 이상의 루비 가루 (시전하면 사라짐)\", m = { cast = \"action\", kind = \"utility\" } },\r\n[\"Control Water\"] = { level = 4, classes = {\"Cleric\", \"Druid\", \"Wizard\"}, save = \"Strength\", half_on_save = true, damage = \"2d8\", damage_type = \"Bludgeoning\", concentration = true, school = \"변환학파\", time = \"행동\", range = \"300피트\", dur = \"집중, 최대 10분\", cmp = \"VS\", mins = 10, ko = \"300피트 안에서 한 변 100피트까지의 정육면체를 골라, 주문이 이어지는 동안 그 안의 물을 다룹니다. 다음 가운데 하나를 고르고, 이후 내 턴에 마법 행동으로 같은 효과를 되풀이하거나 다른 효과로 바꿀 수 있습니다. 범람은 고인 물의 높이를 20피트까지 올리고, 큰 물에서는 20피트 높이의 파도를 일으켜 거대형 이하의 배를 휩쓸고 25% 확률로 뒤집습니다. 물 가르기는 물을 갈라 양쪽에 물벽이 선 도랑을 냅니다. 물길 돌리기는 흐르는 물을 원하는 방향으로 흐르게 합니다. 소용돌이는 가로세로 50피트·깊이 25피트 이상인 물에서만 만들 수 있고, 25피트 안의 물속 생물을 10피트씩 끌어당기며, 소용돌이에 들어오거나 그 안에서 턴을 끝내는 생물은 근력 내성 굴림을 해서 실패하면 타격 피해 2d8, 성공하면 그 절반을 받습니다. 집중, 최대 10분.\", m = { cast = \"action\", kind = \"utility\", concentration = true } },\r\n[\"Control Weather\"] = { level = 8, classes = {\"Cleric\", \"Druid\", \"Wizard\"}, concentration = true, school = \"변환학파\", time = \"10분\", range = \"자신\", dur = \"집중, 최대 8시간\", cmp = \"VS\", mins = 480, ko = \"바깥에서만 시전할 수 있으며, 주문이 이어지는 동안 내 둘레 5마일의 날씨를 다룹니다(건물 안에 들어가면 끝남). 시전할 때 지금 날씨(GM이 정함)의 강수·기온·바람을 각각 한 단계씩 올리거나 내릴 수 있고, 바람은 방향도 바꿀 수 있습니다. 바뀐 날씨가 자리 잡는 데 1d4×10분이 걸리고, 자리 잡은 뒤에는 다시 바꿀 수 있습니다. 강수는 맑음부터 폭우·우박·눈보라까지, 기온은 폭염부터 혹한까지, 바람은 고요부터 폭풍까지 단계가 있습니다. 주문이 끝나면 날씨는 천천히 원래대로 돌아갑니다. 시전에 10분이 걸립니다. 집중, 최대 8시간.\", m = { cast = \"10 minutes\", kind = \"utility\", concentration = true } },\r\n[\"Counterspell\"] = { level = 3, classes = {\"Sorcerer\", \"Warlock\", \"Wizard\"}, save = \"Constitution\", school = \"방호학파\", time = \"반응행동\", range = \"60피트\", dur = \"즉시\", cmp = \"S\", ko = \"60피트 안에서 음성·동작·물질 요소가 있는 주문을 시전하는 생물을 보면, 반응행동으로 씁니다. 그 생물은 건강 내성 굴림을 하고, 실패하면 그 주문은 아무 효과 없이 흩어지며 시전에 쓴 행동·추가 행동·반응행동도 헛되이 쓴 것이 됩니다. 다만 그 주문에 쓴 몫은 쓰지 않은 것으로 칩니다.\", m = { cast = \"reaction\", kind = \"save\", save = \"Constitution\", on_save = \"none\", lrfx = {}, fail = \"the spell being cast fails; its slot is not spent\" } },\r\n[\"Create Food and Water\"] = { level = 3, classes = {\"Cleric\", \"Paladin\"}, school = \"조형학파\", time = \"행동\", range = \"30피트\", dur = \"즉시\", cmp = \"VS\", ko = \"30피트 안의 땅이나 그릇에 음식 45파운드와 깨끗한 물 30갤런을 만듭니다. 음식은 맛이 밋밋해도 배를 든든히 채워 주고 내가 고른 음식처럼 보이며, 먹지 않으면 24시간 뒤에 상합니다.\", m = { cast = \"action\", kind = \"utility\" } },\r\n[\"Create or Destroy Water\"] = { level = 1, classes = {\"Cleric\", \"Druid\"}, school = \"변환학파\", time = \"행동\", range = \"30피트\", dur = \"즉시\", cmp = \"VS\", ko = \"물 만들기와 물 없애기 가운데 하나를 합니다. 물 만들기는 30피트 안의 열린 그릇에 깨끗한 물을 10갤런까지 만들거나, 30피트 정육면체 안에 비를 뿌려 드러난 불을 끕니다. 물 없애기는 30피트 안의 열린 그릇에 든 물을 10갤런까지 없애거나, 30피트 정육면체 안의 안개를 걷어 냅니다. 높은 레벨로 시전하면 한 단계마다 물이 10갤런씩 늘거나 정육면체가 5피트씩 커집니다.\", m = { cast = \"action\", kind = \"utility\" } },\r\n[\"Create Undead\"] = { level = 6, classes = {\"Cleric\", \"Warlock\", \"Wizard\"}, school = \"사령학파\", time = \"1분\", range = \"10피트\", dur = \"즉시\", cmp = \"VS\", ko = \"밤에만 시전할 수 있습니다. 10피트 안의 중형·소형 인간형 시체를 셋까지 골라 구울로 일으키고 부립니다. 내 턴마다 추가 행동으로 120피트 안의 이 언데드들에게 마음속으로 명령을 내리며(여럿이면 같은 명령을 한꺼번에), 명령이 없으면 회피 행동만 하고 위험을 피해서만 움직입니다. 명령을 받으면 그 일을 마칠 때까지 따릅니다. 24시간이 지나면 더는 따르지 않으므로, 그 전에 다시 시전하면 새로 일으키는 대신 셋까지 24시간 더 부릴 수 있습니다. 시전에 1분이 걸립니다. 높은 레벨로 시전하면 더 많이, 더 강한 언데드를 부립니다(7레벨은 구울 넷, 8레벨은 구울 다섯이나 가스트·와이트 둘, 9레벨은 구울 여섯이나 가스트·와이트 셋이나 미라 둘).\", cost = \"one 150+ GP black onyx stone for each corpse\", cost_ko = \"시체마다 150 GP 이상의 흑마노 하나\", m = { cast = \"1 minute\", kind = \"utility\", upcast = { note = \"level 7: four Ghouls; level 8: five Ghouls or two Ghasts or Wights; level 9: six Ghouls, three Ghasts or Wights, or two Mummies\" } } },\r\n[\"Creation\"] = { level = 5, classes = {\"Sorcerer\", \"Wizard\"}, school = \"환영학파\", time = \"1분\", range = \"30피트\", dur = \"특수\", cmp = \"VS\", ko = \"어둠의 세계에서 그림자 재료를 끌어와, 30피트 안에 5피트 정육면체 이하의 물건 하나를 만듭니다. 천·밧줄·나무 같은 식물성 재료나 돌·수정·금속 같은 광물성 재료로 만들 수 있고, 본 적 있는 모양과 재료여야 합니다. 물건이 남아 있는 시간은 재료에 따라 다릅니다(식물성 24시간, 돌·수정 12시간, 귀금속 1시간, 보석 10분, 아다만틴·미스릴 1분, 여러 재료면 가장 짧은 것). 이렇게 만든 물건을 다른 주문의 물질 요소로 쓰면 그 주문은 실패합니다. 시전에 1분이 걸립니다. 높은 레벨로 시전하면 한 단계마다 정육면체가 5피트씩 커집니다.\", m = { cast = \"1 minute\", kind = \"utility\" } },\r\n[\"Cure Wounds\"] = { level = 1, classes = {\"Bard\", \"Cleric\", \"Druid\", \"Paladin\", \"Ranger\"}, heal = \"2d8\", school = \"방호학파\", time = \"행동\", range = \"접촉\", dur = \"즉시\", cmp = \"VS\", ko = \"내가 만진 생물이 생명력을 2d8 + 내 주문시전 능력치 수정치만큼 회복합니다. 높은 레벨로 시전하면 한 단계마다 회복량이 2d8씩 늘어납니다.\", m = { cast = \"action\", kind = \"heal\", heal = \"2d8+MOD\", upcast = { dice = \"2d8\" }, htargets = 1 } },\r\n[\"Dancing Lights\"] = { level = 0, classes = {\"Bard\", \"Sorcerer\", \"Wizard\"}, concentration = true, school = \"환영학파\", time = \"행동\", range = \"120피트\", dur = \"집중, 최대 1분\", cmp = \"VS\", mins = 1, ko = \"120피트 안에 횃불·등불·빛나는 구슬처럼 보이는 횃불만 한 빛을 넷까지 띄웁니다. 넷을 합쳐 어렴풋한 사람 모양의 중형 빛 하나로 만들 수도 있습니다. 어느 쪽이든 빛마다 반경 10피트를 희미하게 비추고, 추가 행동으로 빛을 60피트까지 옮길 수 있습니다. 빛끼리는 20피트 안에 있어야 하고, 사거리를 벗어난 빛은 사라집니다. 집중, 최대 1분.\", m = { cast = \"action\", kind = \"utility\", concentration = true } },\r\n[\"Darkness\"] = { level = 2, classes = {\"Sorcerer\", \"Warlock\", \"Wizard\"}, concentration = true, school = \"방출학파\", time = \"행동\", range = \"60피트\", dur = \"집중, 최대 10분\", cmp = \"V\", mins = 10, ko = \"60피트 안의 한 지점에서 마법의 어둠이 퍼져 반경 15피트 구체를 채웁니다. 이 어둠은 암시야로도 꿰뚫어 보지 못하고, 마법이 아닌 빛으로는 밝힐 수 없습니다. 아무도 들거나 입지 않은 물건에 걸면 그 물건을 중심으로 15피트에 어둠이 퍼지고, 그릇이나 투구 같은 것으로 덮으면 어둠이 막힙니다. 2레벨 이하 주문이 만든 빛과 겹치면 그 주문은 해제됩니다. 집중, 최대 10분.\", m = { cast = \"action\", kind = \"utility\", concentration = true, area = true } },\r\n[\"Darkvision\"] = { level = 2, classes = {\"Druid\", \"Ranger\", \"Sorcerer\", \"Wizard\"}, school = \"변환학파\", time = \"행동\", range = \"접촉\", dur = \"8시간\", cmp = \"VS\", ko = \"동의한 생물 하나를 만지면, 그 생물이 8시간 동안 150피트까지 보는 암시야를 얻습니다.\", bmins = 480, m = { cast = \"action\", kind = \"buff\", targets = 1 } },\r\n[\"Daylight\"] = { level = 3, classes = {\"Cleric\", \"Druid\", \"Paladin\", \"Ranger\", \"Sorcerer\"}, school = \"방출학파\", time = \"행동\", range = \"60피트\", dur = \"1시간\", cmp = \"VS\", ko = \"60피트 안의 한 지점에서 햇빛이 퍼져, 1시간 동안 반경 60피트를 밝게, 그 바깥 60피트를 희미하게 비춥니다. 아무도 들거나 입지 않은 물건에 걸면 그 물건을 중심으로 햇빛이 퍼지고, 그릇이나 투구 같은 것으로 덮으면 가려집니다. 3레벨 이하 주문이 만든 어둠과 겹치면 그 주문은 해제됩니다.\", m = { cast = \"action\", kind = \"utility\", area = true } },\r\n[\"Death Ward\"] = { level = 4, classes = {\"Cleric\", \"Paladin\"}, school = \"방호학파\", time = \"행동\", range = \"접촉\", dur = \"8시간\", cmp = \"VS\", ko = \"내가 만진 생물을 죽음으로부터 지켜 줍니다. 8시간 안에 생명력이 처음 0으로 떨어질 때 대신 1이 되고 주문이 끝납니다. 그 전에 피해 없이 바로 죽게 만드는 효과를 받으면, 그 효과가 듣지 않고 주문이 끝납니다.\", bmins = 480, m = { cast = \"action\", kind = \"buff\", ward = true, targets = 1 } },\r\n[\"Delayed Blast Fireball\"] = { level = 7, classes = {\"Sorcerer\", \"Wizard\"}, save = \"Dexterity\", half_on_save = true, concentration = true, school = \"방출학파\", time = \"행동\", range = \"150피트\", dur = \"집중, 최대 1분\", cmp = \"VS\", mins = 1, ko = \"나에게서 노란 빛줄기가 뻗어 나가, 150피트 안의 고른 지점에 빛나는 구슬로 맺힙니다. 주문이 끝날 때 구슬이 터지고, 그 지점을 중심으로 반경 20피트 구체 안의 생물은 민첩 내성 굴림을 해서 실패하면 쌓인 화염 피해를 모두, 성공하면 그 절반을 받습니다. 기본 피해는 12d6이고, 주문이 끝나지 않은 채 내 턴이 끝날 때마다 1d6씩 더 쌓입니다. 주문이 끝나기 전에 누가 구슬을 만지면 그 생물은 민첩 내성 굴림을 하고, 실패하면 구슬이 그 자리에서 터지며, 성공하면 구슬을 40피트까지 던질 수 있습니다(던진 구슬이 생물이 있는 곳이나 단단한 것에 닿으면 터짐). 폭발 범위 안에서 아무도 들거나 입지 않은 물건 가운데 타는 것에는 불이 붙습니다. 집중, 최대 1분. 높은 레벨로 시전하면 한 단계마다 기본 피해가 1d6씩 늘어납니다.\", m = { cast = \"action\", kind = \"save\", save = \"Dexterity\", on_save = \"half\", damage = \"12d6\", type = \"Fire\", concentration = true, upcast = { dice = \"1d6\" }, area = true } },\r\n[\"Demiplane\"] = { level = 8, classes = {\"Sorcerer\", \"Warlock\", \"Wizard\"}, school = \"조형학파\", time = \"행동\", range = \"60피트\", dur = \"1시간\", cmp = \"S\", ko = \"60피트 안에 보이는 평평하고 단단한 면에 중형 그림자 문을 만들어 1시간 동안 둡니다. 문은 여닫을 수 있고, 가로·세로·높이가 모두 30피트인 빈방으로 된 반차원으로 이어집니다(벽은 나무나 돌 가운데 내가 고름). 주문이 끝나면 문이 사라지고, 안의 물건은 그대로 남습니다. 안의 생물도 남지만, 원하면 문이 사라질 때 밖으로 밀려 나와 문이 있던 곳에서 가장 가까운 빈 곳에 넘어진 상태로 떨어집니다. 시전할 때마다 새 반차원을 만들거나 전에 만든 반차원에 문을 다시 이을 수 있고, 다른 이가 만든 반차원의 생김새와 안에 든 것을 알면 그곳에 이을 수도 있습니다.\", m = { cast = \"action\", kind = \"utility\" } },\r\n[\"Detect Evil and Good\"] = { level = 1, classes = {\"Cleric\", \"Paladin\"}, concentration = true, school = \"예지학파\", time = \"행동\", range = \"자신\", dur = \"집중, 최대 10분\", cmp = \"VS\", mins = 10, ko = \"주문이 이어지는 동안 30피트 안에 있는 이형체·천상체·원소·요정·악마·언데드의 위치를 느낍니다. 그 범위에 신성화 주문이 걸려 있는지, 걸려 있다면 어디인지도 압니다. 두께 1피트의 돌·흙·나무, 1인치의 금속, 얇은 납판에 막힙니다. 집중, 최대 10분.\", m = { cast = \"action\", kind = \"utility\", concentration = true } },\r\n[\"Detect Magic\"] = { level = 1, classes = {\"Bard\", \"Cleric\", \"Druid\", \"Paladin\", \"Ranger\", \"Sorcerer\", \"Warlock\", \"Wizard\"}, concentration = true, ritual = true, school = \"예지학파\", time = \"행동 · 의식 가능\", range = \"자신\", dur = \"집중, 최대 10분\", cmp = \"VS\", mins = 10, ko = \"주문이 이어지는 동안 30피트 안에 마법 효과가 있는지 느낍니다. 느껴지면 마법 행동으로, 그 범위에서 보이는 생물이나 물건 가운데 마법이 깃든 것의 둘레에 희미한 기운을 볼 수 있고, 주문으로 생긴 효과라면 그 주문의 학파도 압니다. 두께 1피트의 돌·흙·나무, 1인치의 금속, 얇은 납판에 막힙니다. 집중, 최대 10분. 의식으로 시전할 수 있습니다.\", m = { cast = \"action\", kind = \"utility\", concentration = true } },\r\n[\"Detect Poison and Disease\"] = { level = 1, classes = {\"Cleric\", \"Druid\", \"Paladin\", \"Ranger\"}, concentration = true, ritual = true, school = \"예지학파\", time = \"행동 · 의식 가능\", range = \"자신\", dur = \"집중, 최대 10분\", cmp = \"VS\", mins = 10, ko = \"주문이 이어지는 동안 30피트 안에 있는 독, 독이 있는 생물, 마법 질병의 위치를 느끼고, 저마다 무슨 종류인지도 압니다. 두께 1피트의 돌·흙·나무, 1인치의 금속, 얇은 납판에 막힙니다. 집중, 최대 10분. 의식으로 시전할 수 있습니다.\", m = { cast = \"action\", kind = \"utility\", concentration = true } },\r\n[\"Detect Thoughts\"] = { level = 2, classes = {\"Bard\", \"Sorcerer\", \"Wizard\"}, save = \"Wisdom\", concentration = true, school = \"예지학파\", time = \"행동\", range = \"자신\", dur = \"집중, 최대 1분\", cmp = \"VS\", mins = 1, ko = \"생각 느끼기와 생각 읽기 가운데 하나를 쓰고, 주문이 이어지는 동안 이후 내 턴에 마법 행동으로 어느 쪽이든 다시 쓸 수 있습니다. 생각 느끼기는 30피트 안에 말을 알거나 텔레파시를 쓰는 생물의 생각이 있는지를 느낍니다(생각을 읽지는 못함, 두께 1피트의 돌·흙·나무, 1인치의 금속, 얇은 납판에 막힘). 생각 읽기는 30피트 안의 생물 하나가 지금 가장 마음에 두고 있는 것을 알아냅니다. 다음 턴에 마법 행동으로 더 깊이 파고들면 대상이 지혜 내성 굴림을 하고, 실패하면 그 생물의 생각의 흐름과 감정, 마음에 크게 걸린 것(걱정·사랑·미움 같은 것)까지 알아냅니다. 성공하면 주문이 끝납니다. 어느 쪽이든 대상은 내가 마음을 들여다본다는 것을 알게 되고, 행동을 써서 지능(비전학) 판정을 해 내 주문 내성 난이도 이상이 나오면 주문을 끝낼 수 있습니다. 집중, 최대 1분.\", m = { cast = \"action\", kind = \"utility\", concentration = true } },\r\n[\"Dimension Door\"] = { level = 4, classes = {\"Bard\", \"Sorcerer\", \"Warlock\", \"Wizard\"}, damage = \"4d6\", damage_type = \"Force\", school = \"조형학파\", time = \"행동\", range = \"500피트\", dur = \"즉시\", cmp = \"V\", ko = \"500피트 안에서 원하는 지점으로 정확히 순간이동합니다. 보이는 곳, 머릿속에 그릴 수 있는 곳, 또는 '곧장 아래로 200피트'처럼 거리와 방향으로 말할 수 있는 곳이면 됩니다. 5피트 안에서 함께 가려는 생물 하나를 데려갈 수 있고, 그 생물은 내가 도착한 곳 5피트 안에 나타납니다. 나나 그 생물이 도착할 자리에 다른 생물이 있거나 물건으로 꽉 차 있으면, 나와 데려가던 생물 모두 역장 피해 4d6을 받고 순간이동은 실패합니다.\", m = { cast = \"action\", kind = \"utility\" } },\r\n[\"Disguise Self\"] = { level = 1, classes = {\"Bard\", \"Sorcerer\", \"Wizard\"}, school = \"환영학파\", time = \"행동\", range = \"자신\", dur = \"1시간\", cmp = \"VS\", ko = \"1시간 동안 옷·갑옷·무기·소지품까지 포함해 내 모습을 다르게 보이게 합니다. 키를 1피트까지 크거나 작게, 몸집을 더 무겁거나 가볍게 보이게 할 수 있지만, 팔다리의 기본 배치는 그대로여야 합니다. 환영이라 만져 보면 들통나고(모자를 더하면 물건이 그 모자를 그냥 통과함), 누가 탐구 행동으로 내 모습을 살펴 지능(조사) 판정에서 내 주문 내성 난이도 이상이 나와도 변장임을 알아챕니다.\", m = { cast = \"action\", kind = \"utility\" } },\r\n[\"Disintegrate\"] = { level = 6, classes = {\"Sorcerer\", \"Wizard\"}, save = \"Dexterity\", damage = \"10d6+40\", damage_type = \"Force\", school = \"변환학파\", time = \"행동\", range = \"60피트\", dur = \"즉시\", cmp = \"VS\", ko = \"60피트 안에 보이는 대상에게 초록 광선을 쏩니다. 대상은 생물, 마법이 아닌 물건, 또는 역장 벽 같은 마법 역장일 수 있습니다. 생물은 민첩 내성 굴림을 해서, 실패하면 역장 피해 10d6 + 40을 받고, 성공하면 피해를 받지 않습니다. 이 피해로 생명력이 0이 되면 그 생물과 몸에 지닌 마법 아닌 것이 모두 잿빛 먼지가 되고, 진정한 부활이나 소원으로만 되살릴 수 있습니다. 대형 이하의 마법 아닌 물건이나 마법 역장은 내성 없이 분해되고, 거대형 이상이면 10피트 정육면체만큼만 분해됩니다. 높은 레벨로 시전하면 한 단계마다 피해가 3d6씩 늘어납니다.\", m = { cast = \"action\", kind = \"save\", save = \"Dexterity\", on_save = \"none\", damage = \"10d6+40\", type = \"Force\", upcast = { dice = \"3d6\" } } },\r\n[\"Dispel Evil and Good\"] = { level = 5, classes = {\"Cleric\", \"Paladin\"}, save = \"Charisma\", concentration = true, school = \"방호학파\", time = \"행동\", range = \"자신\", dur = \"집중, 최대 1분\", cmp = \"VS\", mins = 1, ko = \"주문이 이어지는 동안 천상체·원소·요정·악마·언데드는 나를 공격할 때 불리점을 받습니다. 또 다음 둘 가운데 하나를 쓸 수 있으며, 쓰면 주문이 끝납니다. 하나는 마법 행동으로, 그런 존재에게 빙의되었거나 그런 존재 때문에 매혹·공포 상태인 생물을 만져 풀어 주는 것입니다. 다른 하나는 마법 행동으로, 5피트 안에 보이는 그런 존재 하나에게 매력 내성 굴림을 시켜 실패하면 고향 세계로 돌려보내는 것입니다(언데드는 어둠의 세계로, 요정은 요정계로). 집중, 최대 1분.\", m = { cast = \"action\", kind = \"buff\", concentration = true } },\r\n[\"Dispel Magic\"] = { level = 3, classes = {\"Bard\", \"Cleric\", \"Druid\", \"Paladin\", \"Ranger\", \"Sorcerer\", \"Warlock\", \"Wizard\"}, school = \"방호학파\", time = \"행동\", range = \"120피트\", dur = \"즉시\", cmp = \"VS\", ko = \"120피트 안의 생물·물건·마법 효과 하나를 고릅니다. 대상에 걸려 있는 3레벨 이하 주문은 모두 끝납니다. 4레벨 이상 주문은 하나마다 주문시전 능력치로 능력 판정을 하고, 10 + 그 주문의 레벨 이상이 나오면 그 주문이 끝납니다. 높은 레벨로 시전하면, 시전한 레벨 이하의 주문은 판정 없이 끝납니다.\", m = { cast = \"action\", kind = \"utility\" } },\r\n[\"Dissonant Whispers\"] = { level = 1, classes = {\"Bard\"}, save = \"Wisdom\", half_on_save = true, damage = \"3d6\", damage_type = \"Psychic\", school = \"환혹학파\", time = \"행동\", range = \"60피트\", dur = \"즉시\", cmp = \"V\", ko = \"60피트 안에 보이는 생물 하나의 머릿속에 불협화음이 울립니다. 대상은 지혜 내성 굴림을 하고, 실패하면 정신 피해 3d6을 받으며, 반응행동이 남아 있으면 곧바로 반응행동을 써서 가장 안전한 길로 나에게서 최대한 멀리 달아나야 합니다. 성공하면 피해만 절반 받습니다. 높은 레벨로 시전하면 한 단계마다 피해가 1d6씩 늘어납니다.\", m = { cast = \"action\", kind = \"save\", save = \"Wisdom\", on_save = \"half\", damage = \"3d6\", type = \"Psychic\", upcast = { dice = \"1d6\" } } },\r\n[\"Divination\"] = { level = 4, classes = {\"Cleric\", \"Druid\", \"Wizard\"}, ritual = true, school = \"예지학파\", time = \"행동 · 의식 가능\", range = \"자신\", dur = \"즉시\", cmp = \"VS\", ko = \"신이나 신의 종과 이어져, 7일 안에 일어날 특정한 목표·사건·활동 하나에 대해 질문을 하나 합니다. GM은 짧은 말이나 알쏭달쏭한 시구로 참된 답을 줍니다. 답을 바꿀 수 있는 다른 주문 같은 사정은 따지지 않습니다. 긴 휴식을 마치기 전에 두 번 이상 시전하면, 두 번째부터 시전할 때마다 25%씩 쌓이는 확률로 답을 받지 못합니다. 의식으로 시전할 수 있습니다.\", cost = \"incense worth 25+ GP, consumed\", cost_ko = \"25 GP 이상의 향 (시전하면 사라짐)\", m = { cast = \"action\", kind = \"utility\" } },\r\n[\"Divine Favor\"] = { level = 1, classes = {\"Paladin\"}, damage = \"1d4\", damage_type = \"Radiant\", school = \"변환학파\", time = \"추가 행동\", range = \"자신\", dur = \"1분\", cmp = \"VS\", ko = \"추가 행동으로 1분 동안 무기에 신성한 힘을 깃들입니다. 그동안 내가 무기로 공격해 맞힐 때마다 광휘 피해 1d4를 더 줍니다.\", bmins = 1, m = { cast = \"bonus\", kind = \"buff\", lasting = true, rider = \"1d4\", rider_type = \"Radiant\", rider_each = true, effect = \"weapon hits deal +1d4 Radiant for 1 minute\" } },\r\n[\"Divine Smite\"] = { level = 1, classes = {\"Paladin\"}, damage = \"2d8\", damage_type = \"Radiant\", school = \"방출학파\", time = \"추가 행동 (무기로 맞힌 직후)\", range = \"자신\", dur = \"즉시\", ko = \"근접 무기나 맨손 공격으로 대상을 맞힌 직후 추가 행동으로 씁니다. 그 공격에 광휘 피해 2d8을 더하고, 대상이 악마나 언데드면 1d8을 더 줍니다. 높은 레벨로 시전하면 한 단계마다 피해가 1d8씩 늘어납니다.\", m = { cast = \"bonus\", kind = \"buff\", rider = \"2d8\", rider_type = \"Radiant\", upcast = { dice = \"1d8\" }, effect = \"+2d8 Radiant on the melee hit (+1d8 against a Fiend or an Undead)\" } },\r\n[\"Divine Word\"] = { level = 7, classes = {\"Cleric\"}, save = \"Charisma\", school = \"방출학파\", time = \"추가 행동\", range = \"30피트\", dur = \"즉시\", cmp = \"V\", ko = \"추가 행동으로 천상의 힘이 깃든 말을 외칩니다. 30피트 안에서 고른 생물은 모두 매력 내성 굴림을 하고, 실패한 대상 가운데 지금 생명력이 50 이하인 대상은 남은 생명력에 따라 효과를 받습니다. 20 이하면 죽고, 21~30이면 1시간 동안 장님·귀머거리·충격 상태, 31~40이면 10분 동안 장님·귀머거리 상태, 41~50이면 1분 동안 귀머거리 상태가 됩니다. 또 생명력과 상관없이, 실패한 천상체·원소·요정·악마는 고향 세계로 쫓겨나 24시간 동안 소원이 아니면 어떤 방법으로도 돌아오지 못합니다.\", m = { puts = {\"Blinded\", \"Deafened\", \"Stunned\"}, cast = \"bonus\", kind = \"save\", save = \"Charisma\", on_save = \"none\", lrfx = {\"Blinded\", \"Deafened\", \"Stunned\"}, fail = \"on a failure, by current HP: 0-20 dies; 21-30 Blinded, Deafened, Stunned 1 hour; 31-40 Blinded, Deafened 10 minutes; 41-50 Deafened 1 minute; a Celestial, Elemental, Fey or Fiend is sent home for 24 hours\" } },\r\n[\"Dominate Beast\"] = { level = 4, classes = {\"Druid\", \"Ranger\", \"Sorcerer\"}, save = \"Wisdom\", concentration = true, school = \"환혹학파\", time = \"행동\", range = \"60피트\", dur = \"집중, 최대 1분\", cmp = \"VS\", mins = 1, ko = \"60피트 안에 보이는 야수 하나가 지혜 내성 굴림을 합니다(나나 내 동료와 싸우는 중이면 이점). 실패하면 주문이 이어지는 동안 매혹 상태가 되고, 둘이 같은 세계에 있는 동안 나와 텔레파시로 이어집니다. 내 턴에 행동을 쓰지 않고 '저것을 공격해', '저리 가', '저걸 가져와' 같은 명령을 내리면, 대상은 자기 턴에 힘껏 따릅니다. 명령을 마친 뒤 새 명령이 없으면 자기를 지키며 마음대로 움직입니다. 대상에게 반응행동을 시키려면 나도 반응행동을 써야 합니다. 대상은 피해를 받을 때마다 다시 굴려, 성공하면 풀려납니다. 집중, 최대 1분. 높은 레벨로 시전하면 집중을 더 오래 이어 갈 수 있습니다(5레벨은 10분, 6레벨은 1시간, 7레벨 이상은 8시간).\", m = { cast = \"action\", kind = \"save\", save = \"Wisdom\", on_save = \"none\", concentration = true, lrfx = {\"Charmed\"}, fail = \"Charmed and obeys your commands; Advantage on the save if you are fighting it; saves again when damaged\" } },\r\n[\"Dominate Monster\"] = { level = 8, classes = {\"Bard\", \"Sorcerer\", \"Warlock\", \"Wizard\"}, save = \"Wisdom\", concentration = true, school = \"환혹학파\", time = \"행동\", range = \"60피트\", dur = \"집중, 최대 1시간\", cmp = \"VS\", mins = 60, ko = \"60피트 안에 보이는 생물 하나가 지혜 내성 굴림을 합니다(나나 내 동료와 싸우는 중이면 이점). 실패하면 주문이 이어지는 동안 매혹 상태가 되고, 둘이 같은 세계에 있는 동안 나와 텔레파시로 이어집니다. 내 턴에 행동을 쓰지 않고 '저것을 공격해', '저리 가', '저걸 가져와' 같은 명령을 내리면, 대상은 자기 턴에 힘껏 따릅니다. 명령을 마친 뒤 새 명령이 없으면 자기를 지키며 마음대로 움직입니다. 대상에게 반응행동을 시키려면 나도 반응행동을 써야 합니다. 대상은 피해를 받을 때마다 다시 굴려, 성공하면 풀려납니다. 집중, 최대 1시간. 높은 레벨로 시전하면 집중을 더 오래 이어 갈 수 있습니다(9레벨은 8시간).\", m = { cast = \"action\", kind = \"save\", save = \"Wisdom\", on_save = \"none\", concentration = true, lrfx = {\"Charmed\"}, fail = \"Charmed and obeys your commands; Advantage on the save if you are fighting it; saves again when it takes damage\" } },\r\n[\"Dominate Person\"] = { level = 5, classes = {\"Bard\", \"Sorcerer\", \"Wizard\"}, save = \"Wisdom\", concentration = true, school = \"환혹학파\", time = \"행동\", range = \"60피트\", dur = \"집중, 최대 1분\", cmp = \"VS\", mins = 1, ko = \"60피트 안에 보이는 인간형 하나가 지혜 내성 굴림을 합니다(나나 내 동료와 싸우는 중이면 이점). 실패하면 주문이 이어지는 동안 매혹 상태가 되고, 둘이 같은 세계에 있는 동안 나와 텔레파시로 이어집니다. 내 턴에 행동을 쓰지 않고 '저것을 공격해', '저리 가', '저걸 가져와' 같은 명령을 내리면, 대상은 자기 턴에 힘껏 따릅니다. 명령을 마친 뒤 새 명령이 없으면 자기를 지키며 마음대로 움직입니다. 대상에게 반응행동을 시키려면 나도 반응행동을 써야 합니다. 대상은 피해를 받을 때마다 다시 굴려, 성공하면 풀려납니다. 집중, 최대 1분. 높은 레벨로 시전하면 집중을 더 오래 이어 갈 수 있습니다(6레벨은 10분, 7레벨은 1시간, 8레벨 이상은 8시간).\", m = { cast = \"action\", kind = \"save\", save = \"Wisdom\", on_save = \"none\", concentration = true, lrfx = {\"Charmed\"}, fail = \"Charmed and obeys your commands; Advantage on the save if you are fighting it; saves again when damaged\" } },\r\n[\"Dragon's Breath\"] = { level = 2, classes = {\"Sorcerer\", \"Wizard\"}, save = \"Dexterity\", half_on_save = true, concentration = true, school = \"변환학파\", time = \"추가 행동\", range = \"접촉\", dur = \"집중, 최대 1분\", cmp = \"VS\", mins = 1, ko = \"추가 행동으로 동의한 생물 하나를 만지고 산성·냉기·화염·번개·독성 가운데 하나를 고릅니다. 주문이 끝날 때까지 그 생물은 마법 행동으로 15피트 원뿔 모양의 숨결을 내뿜을 수 있습니다. 그 안의 생물은 민첩 내성 굴림을 해서, 실패하면 고른 종류의 피해 3d6, 성공하면 그 절반을 받습니다. 집중, 최대 1분. 높은 레벨로 시전하면 한 단계마다 피해가 1d6씩 늘어납니다.\", m = { cast = \"bonus\", kind = \"buff\", concentration = true, damage = \"3d6\", type = \"choice (Acid, Cold, Fire, Lightning, Poison)\", save = \"Dexterity\", on_save = \"half\", upcast = { dice = \"1d6\" }, targets = 1 } },\r\n[\"Dream\"] = { level = 5, classes = {\"Bard\", \"Warlock\", \"Wizard\"}, save = \"Wisdom\", damage = \"3d6\", damage_type = \"Psychic\", school = \"환영학파\", time = \"1분\", range = \"특수\", dur = \"8시간\", cmp = \"VS\", ko = \"같은 세계에 있는, 내가 아는 생물 하나를 대상으로 고릅니다. 나, 또는 내가 만진 동의한 생물 하나가 꿈 전령이 되어 무아지경에 빠집니다(그동안 행동불능 상태이고 속도가 0). 대상이 자고 있으면 전령은 그 꿈에 나타나, 대상이 잠든 동안 8시간까지 이야기를 나누고 꿈속 풍경과 물건을 빚을 수 있습니다. 전령은 언제든 무아지경에서 깨어나 주문을 끝낼 수 있고, 대상은 깨어난 뒤에도 꿈을 또렷이 기억합니다. 대상이 깨어 있으면 전령은 그 사실을 알고, 주문을 끝내거나 대상이 잠들 때까지 기다릴 수 있습니다. 전령을 무서운 모습으로 나타나게 하면 열 단어까지 말을 전한 뒤 대상이 지혜 내성 굴림을 하고, 실패하면 그 휴식의 효과를 얻지 못하며 깨어날 때 정신 피해 3d6을 받습니다. 시전에 1분이 걸립니다.\", m = { cast = \"1 minute\", kind = \"utility\" } },\r\n[\"Druidcraft\"] = { level = 0, classes = {\"Druid\"}, school = \"변환학파\", time = \"행동\", range = \"30피트\", dur = \"즉시\", cmp = \"VS\", ko = \"자연의 정령에게 속삭여, 30피트 안에 다음 가운데 하나를 일으킵니다. 앞으로 24시간 동안 이곳의 날씨를 알려 주는 작은 징조를 1라운드 동안 만들거나(맑으면 금빛 구슬, 비가 오면 구름 같은 것), 꽃이나 씨앗 꼬투리, 잎눈을 바로 피우거나, 떨어지는 낙엽·산들바람·동물 소리 같은 해 없는 감각 효과를 5피트 정육면체 안에 내거나, 촛불·횃불·모닥불을 켜거나 끕니다.\", m = { cast = \"action\", kind = \"utility\" } },\r\n[\"Earthquake\"] = { level = 8, classes = {\"Cleric\", \"Druid\", \"Sorcerer\"}, save = \"Dexterity\", half_on_save = true, damage = \"12d6\", damage_type = \"Bludgeoning\", concentration = true, school = \"변환학파\", time = \"행동\", range = \"500피트\", dur = \"집중, 최대 1분\", cmp = \"VS\", mins = 1, ko = \"500피트 안에 보이는 땅 위의 한 지점을 중심으로, 반경 100피트 원 안에 주문이 이어지는 동안 거센 지진을 일으킵니다. 그 땅은 어려운 지형이 됩니다. 시전할 때와 이후 내 턴이 끝날 때마다, 범위 안 땅 위의 생물은 민첩 내성 굴림을 해서 실패하면 넘어진 상태가 되고 집중이 깨집니다. 원하면 갈라진 틈도 냅니다. 시전한 턴이 끝날 때 1d6개의 틈이 내가 고른 곳(건물 아래는 안 됨)에 열리고, 틈마다 깊이 1d10×10피트, 너비 10피트로 범위의 한쪽 끝에서 다른 쪽 끝까지 이어집니다. 틈이 생기는 자리의 생물은 민첩 내성 굴림에 실패하면 빠집니다. 또 범위 안에서 땅에 닿아 있는 건물은 시전할 때와 내 턴이 끝날 때마다 타격 피해 50을 받고, 생명력이 0이 되면 무너집니다. 무너지는 건물에서 그 높이의 절반 거리 안에 있는 생물은 민첩 내성 굴림을 해서, 실패하면 타격 피해 12d6을 받고 넘어진 채 잔해에 묻히며(행동을 써서 난이도 20 근력(운동) 판정에 성공해야 빠져나옴), 성공하면 피해만 절반 받습니다. 집중, 최대 1분.\", m = { cast = \"action\", kind = \"save\", save = \"Dexterity\", on_save = \"none\", concentration = true, lrfx = {\"Prone\"}, area = true, fail = \"Prone and Concentration broken; the save again at the end of each of your turns\" } },\r\n[\"Eldritch Blast\"] = { level = 0, classes = {\"Warlock\"}, attack = \"ranged\", damage = \"1d10\", damage_type = \"Force\", school = \"방출학파\", time = \"행동\", range = \"120피트\", dur = \"즉시\", cmp = \"VS\", ko = \"120피트 안의 생물이나 물체 하나에게 지지직거리는 에너지 광선을 쏘아 원거리 주문 공격을 합니다. 맞으면 역장 피해 1d10을 줍니다. 5·11·17레벨에 광선이 하나씩 늘어나고(최대 넷), 광선은 한 대상에게 모두 쏘거나 여러 대상에게 나눠 쏠 수 있으며, 광선마다 따로 명중 굴림을 합니다.\", m = { cast = \"action\", kind = \"attack\", attack = \"ranged\", damage = \"1d10\", type = \"Force\", cantrip = true, beams = true } },\r\n[\"Elementalism\"] = { level = 0, classes = {\"Druid\", \"Sorcerer\", \"Wizard\"}, school = \"변환학파\", time = \"행동\", range = \"30피트\", dur = \"즉시\", cmp = \"VS\", ko = \"30피트 안에서 원소를 부립니다. 5피트 정육면체에 천을 흔들고 열린 문을 닫을 만한 바람을 일으키거나, 5피트 정사각형 바닥을 먼지나 모래로 덮거나 흙에 낱말 하나를 쓰거나, 해 없는 불티와 색깔 연기를 피우거나(불티로 초나 횃불을 켤 수 있음), 시원한 안개를 뿌리거나 물 한 컵을 만들거나, 1피트 정육면체만 한 흙·불·연기·물을 1시간 동안 대강의 모양으로 빚습니다.\", m = { cast = \"action\", kind = \"utility\", say = \"a small elemental effect within 30 ft, no damage: a breeze (Air), a thin layer of dust or sand (Earth), harmless embers that light things (Fire), a mist or a cup of water (Water), or shaping an element for an hour\" } },\r\n[\"Enhance Ability\"] = { level = 2, classes = {\"Bard\", \"Cleric\", \"Druid\", \"Ranger\", \"Sorcerer\", \"Wizard\"}, concentration = true, school = \"변환학파\", time = \"행동\", range = \"접촉\", dur = \"집중, 최대 1시간\", cmp = \"VS\", mins = 60, ko = \"생물 하나를 만지고 근력·민첩·지능·지혜·매력 가운데 하나를 고르면, 주문이 이어지는 동안 그 생물이 그 능력치로 하는 능력 판정에 이점을 받습니다. 집중, 최대 1시간. 높은 레벨로 시전하면 한 단계마다 대상이 하나씩 늘고, 대상마다 다른 능력치를 고를 수 있습니다.\", m = { cast = \"action\", kind = \"buff\", concentration = true, upcast = { targets = 1 }, pick = {\"Strength\", \"Dexterity\", \"Intelligence\", \"Wisdom\", \"Charisma\"}, tell = \"Advantage on {PICK} checks\", targets = 1 } },\r\n[\"Enlarge/Reduce\"] = { level = 2, classes = {\"Bard\", \"Druid\", \"Sorcerer\", \"Wizard\"}, save = \"Constitution\", concentration = true, school = \"변환학파\", time = \"행동\", range = \"30피트\", dur = \"집중, 최대 1분\", cmp = \"VS\", mins = 1, ko = \"30피트 안에 보이는 생물이나, 아무도 들거나 입지 않은 물건 하나를 주문이 이어지는 동안 크게 하거나 작게 합니다. 원치 않는 생물은 건강 내성 굴림을 해서 성공하면 효과가 없습니다. 생물이 입고 든 것도 함께 커지거나 작아집니다. 커지면 크기가 한 단계 오르고, 근력 판정과 근력 내성 굴림에 이점을 받으며, 커진 무기나 맨손 공격이 맞을 때 피해가 1d4 늘어납니다. 작아지면 크기가 한 단계 내려가고, 근력 판정과 근력 내성 굴림에 불리점을 받으며, 작아진 무기나 맨손 공격의 피해가 1d4 줄어듭니다(1보다 낮아지지는 않음). 집중, 최대 1분.\", m = { pick = {\"Enlarge\", \"Reduce\"}, pick_what = \"Enlarge or Reduce\", size_dice = \"1d4\", extra_save = { save = \"Constitution\", on_save = \"none\", foe_fx = { wdmg = \"1d4\" }, lrfx = {} }, cast = \"action\", kind = \"buff\", concentration = true, targets = 1 } },\r\n[\"Ensnaring Strike\"] = { level = 1, classes = {\"Ranger\"}, save = \"Strength\", damage = \"1d6\", damage_type = \"Piercing\", concentration = true, school = \"조형학파\", time = \"추가 행동 (무기로 맞힌 직후)\", range = \"자신\", dur = \"집중, 최대 1분\", cmp = \"V\", mins = 1, ko = \"무기로 생물을 맞힌 직후 추가 행동으로 씁니다. 대상에게 붙잡는 덩굴이 돋아나고, 대상은 근력 내성 굴림을 합니다(대형 이상은 이점). 실패하면 주문이 끝날 때까지 포박 상태가 되고, 포박된 동안 자기 턴이 시작될 때마다 관통 피해 1d6을 받습니다. 성공하면 덩굴이 시들고 주문이 끝납니다. 대상이나 대상에게 손이 닿는 생물이 행동을 써서 근력(운동) 판정을 하고, 내 주문 내성 난이도 이상이 나오면 주문이 끝납니다. 집중, 최대 1분. 높은 레벨로 시전하면 한 단계마다 피해가 1d6씩 늘어납니다.\", m = { cast = \"bonus\", kind = \"save\", save = \"Strength\", on_save = \"none\", concentration = true, upcast = { dice = \"1d6\" }, lrfx = {\"Restrained\"}, fail = \"Restrained, 1d6 Piercing at the start of each of its turns\" } },\r\n[\"Entangle\"] = { level = 1, classes = {\"Druid\", \"Ranger\"}, save = \"Strength\", concentration = true, school = \"조형학파\", time = \"행동\", range = \"90피트\", dur = \"집중, 최대 1분\", cmp = \"VS\", mins = 1, ko = \"90피트 안의 20피트 정사각형에서 붙잡는 덩굴이 솟아, 주문이 이어지는 동안 그곳이 어려운 지형이 됩니다. 시전할 때 그 안에 있던 생물(나 말고)은 근력 내성 굴림을 하고, 실패하면 주문이 끝날 때까지 포박 상태가 됩니다. 포박된 생물은 행동을 써서 근력(운동) 판정을 하고, 내 주문 내성 난이도 이상이 나오면 덩굴에서 빠져나옵니다. 주문이 끝나면 덩굴도 사라집니다. 집중, 최대 1분.\", m = { cast = \"action\", kind = \"save\", save = \"Strength\", on_save = \"none\", concentration = true, lrfx = {\"Restrained\"}, area = true, fail = \"Restrained; Difficult Terrain\" } },\r\n[\"Enthrall\"] = { level = 2, classes = {\"Bard\", \"Warlock\"}, save = \"Wisdom\", concentration = true, school = \"환혹학파\", time = \"행동\", range = \"60피트\", dur = \"집중, 최대 1분\", cmp = \"VS\", mins = 1, ko = \"주의를 흩뜨리는 말을 늘어놓습니다. 60피트 안에 보이는 생물을 원하는 만큼 고르면 대상마다 지혜 내성 굴림을 하고(나나 내 동료와 싸우고 있는 생물은 자동으로 성공), 실패하면 주문이 끝날 때까지 지혜(감지) 판정과 상시 감지가 10 낮아집니다. 집중, 최대 1분.\", m = { cast = \"action\", kind = \"save\", save = \"Wisdom\", on_save = \"none\", concentration = true, lrfx = {}, fail = \"-10 to Perception\" } },\r\n[\"Etherealness\"] = { level = 7, classes = {\"Bard\", \"Cleric\", \"Sorcerer\", \"Warlock\", \"Wizard\"}, school = \"조형학파\", time = \"행동\", range = \"자신\", dur = \"최대 8시간\", cmp = \"VS\", ko = \"최대 8시간 동안, 지금 있는 세계와 겹친 에테르계의 경계로 들어갑니다. 그동안 어느 방향으로든 움직일 수 있지만 위나 아래로 움직이면 1피트마다 1피트가 더 들고, 떠나온 세계는 잿빛으로 60피트까지만 보입니다. 에테르계에 있는 생물·물건·효과와만 서로 영향을 주고받으며, 에테르계에 있지 않은 생물은 그럴 수 있게 해 주는 능력이 없으면 나를 알아채거나 건드리지 못합니다. 주문이 끝나면 떠나온 세계의 같은 자리로 돌아옵니다. 그 자리에 무언가 있으면 가장 가까운 빈 곳으로 밀려나고, 밀려난 거리(피트)의 두 배만큼 역장 피해를 받습니다. 에테르계나, 에테르계와 맞닿지 않은 세계에서 시전하면 주문이 바로 끝납니다. 높은 레벨로 시전하면 한 단계마다, 나를 포함해 10피트 안에서 함께 가려는 생물을 셋까지 대상으로 삼을 수 있습니다.\", m = { cast = \"action\", kind = \"utility\", upcast = { note = \"three more willing creatures per slot level above 7\" } } },\r\n[\"Expeditious Retreat\"] = { level = 1, classes = {\"Sorcerer\", \"Warlock\", \"Wizard\"}, concentration = true, school = \"변환학파\", time = \"추가 행동\", range = \"자신\", dur = \"집중, 최대 10분\", cmp = \"VS\", mins = 10, ko = \"추가 행동으로 시전하면서 곧바로 질주 행동을 하고, 주문이 이어지는 동안 질주 행동을 추가 행동으로 할 수 있습니다. 집중, 최대 10분.\", m = { cast = \"bonus\", kind = \"buff\", concentration = true } },\r\n[\"Eyebite\"] = { level = 6, classes = {\"Bard\", \"Sorcerer\", \"Warlock\", \"Wizard\"}, save = \"Wisdom\", concentration = true, school = \"사령학파\", time = \"행동\", range = \"자신\", dur = \"집중, 최대 1분\", cmp = \"VS\", mins = 1, ko = \"주문이 이어지는 동안 내 눈이 먹물처럼 새까만 구멍이 됩니다. 60피트 안에 보이는 생물 하나가 지혜 내성 굴림을 하고, 실패하면 주문이 이어지는 동안 내가 고른 효과 하나를 받습니다. 잠듦: 무의식 상태가 되고, 피해를 받거나 누가 행동을 써서 흔들면 깨어납니다. 공황: 공포 상태가 되어, 자기 턴마다 질주 행동을 하고 가장 안전하고 짧은 길로 나에게서 달아나야 합니다. 나에게서 60피트 이상 떨어져 나를 볼 수 없는 곳에 가면 풀립니다. 병듦: 중독 상태가 됩니다. 이후 내 턴마다 마법 행동으로 다른 생물을 노릴 수 있지만, 이번 시전의 내성에 한 번 성공한 생물은 다시 노리지 못합니다. 집중, 최대 1분.\", m = { cast = \"action\", kind = \"save\", save = \"Wisdom\", on_save = \"none\", concentration = true, lrfx = {\"Frightened\", \"Poisoned\", \"Unconscious\"}, fail = \"your choice: Asleep (Unconscious until damaged or shaken), Panicked (Frightened, runs), Sickened (Poisoned)\" } },\r\n[\"Fabricate\"] = { level = 4, classes = {\"Wizard\"}, school = \"변환학파\", time = \"10분\", range = \"120피트\", dur = \"즉시\", cmp = \"VS\", ko = \"120피트 안에 보이는 원재료를 같은 재료의 완성품으로 바꿉니다. 나무 몇 그루로 나무다리를, 삼으로 밧줄을, 아마나 양털로 옷을 만드는 식입니다. 재료가 넉넉하면 대형 이하(10피트 정육면체나, 이어 붙인 5피트 정육면체 여덟 개 안에 드는 크기)의 물건을 만들 수 있지만, 금속·돌 같은 광물이면 중형 이하(5피트 정육면체 안)까지입니다. 완성품의 품질은 재료의 품질에 따릅니다. 생물이나 마법 물건은 만들지 못하고, 무기·갑옷처럼 높은 솜씨가 필요한 물건은 그런 물건을 만드는 장인 도구에 숙련이 있어야 만들 수 있습니다. 시전에 10분이 걸립니다.\", m = { cast = \"10 minutes\", kind = \"utility\" } },\r\n[\"Faerie Fire\"] = { level = 1, classes = {\"Bard\", \"Druid\"}, save = \"Dexterity\", concentration = true, school = \"방출학파\", time = \"행동\", range = \"60피트\", dur = \"집중, 최대 1분\", cmp = \"V\", mins = 1, ko = \"60피트 안의 20피트 정육면체에 있는 물건은 파랑·초록·보라 가운데 내가 고른 빛으로 윤곽이 빛납니다. 그 안의 생물은 민첩 내성 굴림을 하고, 실패하면 그 생물도 윤곽이 빛납니다. 주문이 이어지는 동안 윤곽이 빛나는 대상은 반경 10피트를 희미하게 비추고, 투명 상태여도 그 이점을 얻지 못합니다. 그 대상을 볼 수 있는 공격자는 그 대상을 공격할 때 이점을 받습니다. 집중, 최대 1분.\", m = { cast = \"action\", kind = \"save\", save = \"Dexterity\", on_save = \"none\", concentration = true, lrfx = {}, area = true, fail = \"outlined: attacks against it have Advantage, no Invisible\" } },\r\n[\"Faithful Hound\"] = { level = 4, classes = {\"Wizard\"}, save = \"Dexterity\", damage = \"4d8\", damage_type = \"Force\", school = \"조형학파\", time = \"행동\", range = \"30피트\", dur = \"8시간\", cmp = \"VS\", ko = \"30피트 안에 보이는 빈 곳에 유령 경비견을 불러 8시간 동안 둡니다. 경비견은 나만 볼 수 있고, 만질 수도 다치게 할 수도 없으며, 나와 300피트 넘게 떨어지면 사라집니다. 소형 이상의 생물이 내가 정해 둔 암호를 말하지 않고 경비견 30피트 안에 들어오면 크게 짖으며, 경비견은 30피트까지 보는 진시야가 있습니다. 내 턴이 시작될 때마다 경비견은 5피트 안의 적 하나를 물려 하고, 그 적은 민첩 내성 굴림에 실패하면 역장 피해 4d8을 받습니다. 이후 내 턴에 마법 행동으로 경비견을 30피트까지 옮길 수 있습니다.\", m = { cast = \"action\", kind = \"save\", save = \"Dexterity\", on_save = \"none\", damage = \"4d8\", type = \"Force\", lasting = true } },\r\n[\"False Life\"] = { level = 1, classes = {\"Sorcerer\", \"Wizard\"}, school = \"사령학파\", time = \"행동\", range = \"자신\", dur = \"즉시\", cmp = \"VS\", ko = \"임시 생명력 2d4 + 4를 얻습니다. 높은 레벨로 시전하면 한 단계마다 임시 생명력이 5씩 늘어납니다.\", m = { cast = \"action\", kind = \"buff\", temp_hp = \"2d4+4\", upcast = { temp_hp = 5 }, self = true } },\r\n[\"Fear\"] = { level = 3, classes = {\"Bard\", \"Sorcerer\", \"Warlock\", \"Wizard\"}, save = \"Wisdom\", concentration = true, school = \"환영학파\", time = \"행동\", range = \"자신\", dur = \"집중, 최대 1분\", cmp = \"VS\", mins = 1, ko = \"내게서 30피트 원뿔로 무서운 환영을 펼칩니다. 그 안의 생물은 모두 지혜 내성 굴림을 하고, 실패하면 들고 있던 것을 떨어뜨리고 주문이 이어지는 동안 공포 상태가 됩니다. 공포에 질린 생물은 자기 턴마다 질주 행동을 하고 가장 안전한 길로 나에게서 달아납니다(달아날 곳이 없으면 그러지 않음). 나를 볼 수 없는 곳에서 턴을 끝내면 지혜 내성 굴림을 하고, 성공하면 그 생물에게는 주문이 끝납니다. 집중, 최대 1분.\", m = { cast = \"action\", kind = \"save\", save = \"Wisdom\", on_save = \"none\", concentration = true, lrfx = {\"Frightened\"}, area = true, fail = \"drops what it holds, Frightened, Dashes away each turn\" } },\r\n[\"Feather Fall\"] = { level = 1, classes = {\"Bard\", \"Sorcerer\", \"Wizard\"}, school = \"변환학파\", time = \"반응행동\", range = \"60피트\", dur = \"1분\", cmp = \"V\", ko = \"나나 60피트 안에 보이는 생물이 떨어질 때 반응행동으로 씁니다. 60피트 안에서 떨어지고 있는 생물을 다섯까지 골라, 1분 동안 떨어지는 속도를 라운드마다 60피트로 늦춥니다. 그동안 땅에 닿은 생물은 낙하 피해를 받지 않고, 그 생물에게는 주문이 끝납니다.\", m = { cast = \"reaction\", kind = \"utility\" } },\r\n[\"Find Familiar\"] = { level = 1, classes = {\"Wizard\"}, ritual = true, school = \"조형학파\", time = \"1시간 · 의식 가능\", range = \"10피트\", dur = \"즉시\", cmp = \"VS\", ko = \"박쥐·고양이·개구리·매·올빼미·까마귀처럼 도전 지수 0인 야수의 모습을 한 영을 10피트 안에 불러 패밀리어로 둡니다. 패밀리어는 그 야수의 능력치를 쓰지만 종류는 천상체·요정·악마 가운데 내가 고른 것이고, 스스로 움직이되 내 명령을 따릅니다. 100피트 안에서는 텔레파시로 이야기할 수 있고, 추가 행동으로 다음 내 턴이 시작될 때까지 패밀리어의 눈과 귀로 보고 들을 수 있습니다. 내가 접촉 주문을 시전할 때 100피트 안의 패밀리어가 반응행동으로 대신 손을 대 줄 수 있습니다. 싸움에서는 우선권을 따로 굴려 자기 턴에 움직이고, 공격은 하지 못합니다. 생명력이 0이 되면 사라지고, 다시 시전하면 돌아옵니다. 마법 행동으로 잠시 주머니 차원에 보내 두었다가, 다시 마법 행동으로 30피트 안의 빈 곳에 불러낼 수 있습니다. 패밀리어는 한 번에 하나만 둘 수 있습니다. 시전에 1시간이 걸리고, 의식으로 시전할 수 있습니다.\", cost = \"burning incense worth 10+ GP, consumed\", cost_ko = \"10 GP 이상의 피우는 향 (시전하면 사라짐)\", m = { cast = \"1 hour\", kind = \"utility\" } },\r\n[\"Find Steed\"] = { level = 2, classes = {\"Paladin\"}, school = \"조형학파\", time = \"행동\", range = \"30피트\", dur = \"즉시\", ko = \"30피트 안의 빈 곳에, 충직한 탈것의 모습을 한 이계의 존재를 부릅니다. 말·낙타·다이어 울프·엘크처럼 내가 고른, 탈 수 있는 대형 동물의 모습이고, 종류는 시전할 때마다 천상체·요정·악마 가운데 고릅니다(그에 따라 능력이 조금 다름). 탈것은 나와 동료의 편이며, 싸움에서는 나와 같은 우선권 순서에 움직이고, 내가 타면 내가 조종하는 탈것이 됩니다. 내가 행동불능 상태이면 내 턴 바로 뒤에 스스로 움직이며 나를 지킵니다. 생명력이 0이 되거나 내가 죽으면 사라지고, 다시 시전하면 사라졌던 그 탈것을 부를지 다른 탈것을 부를지 고릅니다. 이미 탈것이 있을 때 시전하면 새 탈것으로 바뀝니다. 높은 레벨로 시전하면 능력치 블록에 그 레벨을 써서 더 강해집니다.\", m = { cast = \"action\", kind = \"utility\" } },\r\n[\"Find Traps\"] = { level = 2, classes = {\"Cleric\", \"Druid\", \"Ranger\"}, school = \"예지학파\", time = \"행동\", range = \"120피트\", dur = \"즉시\", cmp = \"VS\", ko = \"120피트 안에서 시야에 들어오는 함정이 있는지 느낍니다. 여기서 함정은 해를 끼치거나 위험하게 하려고 만든 장치나 주문(경보, 보호의 문양, 구덩이 함정 같은 것)을 말하고, 약해진 바닥이나 무너지려는 천장, 숨은 싱크홀 같은 자연적인 위험은 들지 않습니다. 함정이 있다는 것과 대강 어떤 위험인지는 알지만, 정확한 위치는 모릅니다.\", m = { cast = \"action\", kind = \"utility\" } },\r\n[\"Finger of Death\"] = { level = 7, classes = {\"Sorcerer\", \"Warlock\", \"Wizard\"}, save = \"Constitution\", half_on_save = true, damage = \"7d8+30\", damage_type = \"Necrotic\", school = \"사령학파\", time = \"행동\", range = \"60피트\", dur = \"즉시\", cmp = \"VS\", ko = \"60피트 안에 보이는 생물 하나에게 죽음의 기운을 쏟습니다. 대상은 건강 내성 굴림을 해서, 실패하면 사령 피해 7d8 + 30, 성공하면 그 절반을 받습니다. 이 주문으로 죽은 인간형은 다음 내 턴이 시작될 때 좀비로 일어나, 내가 말로 내리는 명령을 따릅니다.\", m = { cast = \"action\", kind = \"save\", save = \"Constitution\", on_save = \"half\", damage = \"7d8+30\", type = \"Necrotic\" } },\r\n[\"Fireball\"] = { level = 3, classes = {\"Sorcerer\", \"Wizard\"}, save = \"Dexterity\", half_on_save = true, damage = \"8d6\", damage_type = \"Fire\", school = \"방출학파\", time = \"행동\", range = \"150피트\", dur = \"즉시\", cmp = \"VS\", ko = \"나에게서 150피트 안의 고른 지점으로 밝은 빛줄기가 날아가, 낮은 굉음과 함께 불덩이가 터집니다. 그 지점을 중심으로 반경 20피트 구체 안의 생물은 모두 민첩 내성 굴림을 해서, 실패하면 화염 피해 8d6, 성공하면 그 절반을 받습니다. 그 안에서 아무도 들거나 입지 않은 물건 가운데 타는 것에는 불이 붙습니다. 높은 레벨로 시전하면 한 단계마다 피해가 1d6씩 늘어납니다.\", m = { cast = \"action\", kind = \"save\", save = \"Dexterity\", on_save = \"half\", damage = \"8d6\", type = \"Fire\", upcast = { dice = \"1d6\" }, area = true } },\r\n[\"Find the Path\"] = { level = 6, classes = {\"Bard\", \"Cleric\", \"Druid\"}, concentration = true, school = \"예지학파\", time = \"1분\", range = \"자신\", dur = \"집중, 최대 1일\", cmp = \"VS\", mins = 1440, ko = \"내가 잘 아는 장소 하나를 말하면, 그곳까지 가는 가장 곧은 길을 마법으로 느낍니다. 목적지가 다른 세계에 있거나, 움직이거나(움직이는 요새 같은 곳), 막연하면('녹색 용의 둥지' 같은 곳) 주문이 실패합니다. 주문이 이어지는 동안 목적지와 같은 세계에 있는 한 그곳까지의 거리와 방향을 알고, 갈림길을 만날 때마다 어느 길이 가장 곧은지 압니다. 시전에 1분이 걸립니다. 집중, 최대 1일.\", cost = \"a set of divination tools—such as cards or runes—worth 100+ GP\", cost_ko = \"100 GP 이상의 점술 도구 (카드나 룬 같은 것)\", m = { cast = \"1 minute\", kind = \"utility\", concentration = true } },\r\n[\"Fire Bolt\"] = { level = 0, classes = {\"Sorcerer\", \"Wizard\"}, attack = \"ranged\", damage = \"1d10\", damage_type = \"Fire\", school = \"방출학파\", time = \"행동\", range = \"120피트\", dur = \"즉시\", cmp = \"VS\", ko = \"120피트 안의 생물이나 물체에 불티를 던져 원거리 주문 공격을 합니다. 맞으면 화염 피해 1d10을 주고, 맞은 것이 아무도 들거나 입지 않은 타는 물건이면 불이 붙습니다. 5·11·17레벨에 피해 주사위가 하나씩 늘어납니다.\", m = { cast = \"action\", kind = \"attack\", attack = \"ranged\", damage = \"1d10\", type = \"Fire\", cantrip = true } },\r\n[\"Fire Shield\"] = { level = 4, classes = {\"Druid\", \"Sorcerer\", \"Wizard\"}, damage = \"2d8\", damage_type = \"Fire\", school = \"방출학파\", time = \"행동\", range = \"자신\", dur = \"10분\", cmp = \"VS\", ko = \"10분 동안 가느다란 불꽃이 몸을 휘감아, 반경 10피트를 밝게, 그 바깥 10피트를 희미하게 비춥니다. 따뜻한 방패(냉기 피해에 저항)와 차가운 방패(화염 피해에 저항) 가운데 하나를 고릅니다. 5피트 안의 생물이 근접 명중 굴림으로 나를 맞힐 때마다 방패에서 불길이 터져, 그 공격자는 따뜻한 방패면 화염 피해 2d8을, 차가운 방패면 냉기 피해 2d8을 받습니다.\", m = { cast = \"action\", kind = \"auto\", damage = \"1d8\", type = \"Fire (warm shield) or Cold (chill shield)\", darts = 200, lasting = true, say = \"for 10 minutes, a creature within 5 ft that hits the caster with a melee attack takes 2d8 Fire (warm shield) or Cold (chill shield), no roll: [DAMAGE|Attacker|2d8|dice|damage]; Resistance to Cold (warm) or Fire (chill) is narrated\" } },\r\n[\"Fire Storm\"] = { level = 7, classes = {\"Cleric\", \"Druid\", \"Sorcerer\"}, save = \"Dexterity\", half_on_save = true, damage = \"7d10\", damage_type = \"Fire\", school = \"방출학파\", time = \"행동\", range = \"150피트\", dur = \"즉시\", cmp = \"VS\", ko = \"150피트 안에 불의 폭풍을 일으킵니다. 범위는 10피트 정육면체 열 개까지이고, 정육면체마다 다른 정육면체 하나 이상과 맞닿게 원하는 모양으로 놓습니다. 그 안의 생물은 모두 민첩 내성 굴림을 해서, 실패하면 화염 피해 7d10, 성공하면 그 절반을 받습니다. 범위 안에서 아무도 들거나 입지 않은 물건 가운데 타는 것에는 불이 붙습니다.\", m = { cast = \"action\", kind = \"save\", save = \"Dexterity\", on_save = \"half\", damage = \"7d10\", type = \"Fire\", area = true } },\r\n[\"Flame Blade\"] = { level = 2, classes = {\"Druid\", \"Sorcerer\"}, attack = \"melee\", concentration = true, school = \"방출학파\", time = \"추가 행동\", range = \"자신\", dur = \"집중, 최대 10분\", cmp = \"VS\", mins = 10, ko = \"추가 행동으로 빈손에 시미터만 한 불꽃 칼날을 만듭니다. 칼날을 놓으면 사라지지만, 주문이 이어지는 동안 추가 행동으로 다시 만들 수 있습니다. 마법 행동으로 칼날을 휘둘러 근접 주문 공격을 하고, 맞으면 화염 피해 3d6 + 주문시전 능력치 수정치를 줍니다. 칼날은 반경 10피트를 밝게, 그 바깥 10피트를 희미하게 비춥니다. 집중, 최대 10분. 높은 레벨로 시전하면 한 단계마다 피해가 1d6씩 늘어납니다.\", m = { cast = \"bonus\", kind = \"attack\", attack = \"melee\", damage = \"3d6+MOD\", type = \"Fire\", concentration = true, upcast = { dice = \"1d6\" } } },\r\n[\"Flame Strike\"] = { level = 5, classes = {\"Cleric\"}, save = \"Dexterity\", half_on_save = true, damage = \"5d6\", damage_type = \"Fire\", school = \"방출학파\", time = \"행동\", range = \"60피트\", dur = \"즉시\", cmp = \"VS\", ko = \"하늘에서 눈부신 불기둥이 세차게 내리꽂힙니다. 60피트 안의 한 지점을 중심으로 반경 10피트·높이 40피트 원기둥 안의 생물은 모두 민첩 내성 굴림을 해서, 실패하면 화염 피해 5d6과 광휘 피해 5d6을, 성공하면 그 절반을 받습니다. 높은 레벨로 시전하면 한 단계마다 화염 피해와 광휘 피해가 각각 1d6씩 늘어납니다.\", m = { cast = \"action\", kind = \"save\", save = \"Dexterity\", on_save = \"half\", damage = \"5d6+5d6\", type = \"Fire and Radiant\", upcast = { dice = \"2d6\" }, area = true } },\r\n[\"Flaming Sphere\"] = { level = 2, classes = {\"Druid\", \"Sorcerer\", \"Wizard\"}, save = \"Dexterity\", half_on_save = true, damage = \"2d6\", damage_type = \"Fire\", concentration = true, school = \"조형학파\", time = \"행동\", range = \"60피트\", dur = \"집중, 최대 1분\", cmp = \"VS\", mins = 1, ko = \"60피트 안의 땅 위 빈 곳에 지름 5피트의 불덩이를 만듭니다. 불덩이 5피트 안에서 턴을 끝내는 생물은 민첩 내성 굴림을 해서, 실패하면 화염 피해 2d6, 성공하면 그 절반을 받습니다. 추가 행동으로 불덩이를 땅 위로 30피트까지 굴릴 수 있고, 생물이 있는 곳으로 굴리면 그 생물이 같은 내성 굴림을 하며 불덩이는 그 턴에 멈춥니다. 굴릴 때 높이 5피트까지의 장애물을 넘고 폭 10피트까지의 구덩이를 건너뛸 수 있습니다. 불덩이에 닿은, 아무도 들거나 입지 않은 타는 물건에는 불이 붙고, 불덩이는 반경 20피트를 밝게, 그 바깥 20피트를 희미하게 비춥니다. 집중, 최대 1분. 높은 레벨로 시전하면 한 단계마다 피해가 1d6씩 늘어납니다.\", m = { cast = \"action\", kind = \"save\", save = \"Dexterity\", on_save = \"half\", damage = \"2d6\", type = \"Fire\", concentration = true, upcast = { dice = \"1d6\" } } },\r\n[\"Flesh to Stone\"] = { level = 6, classes = {\"Druid\", \"Sorcerer\", \"Wizard\"}, save = \"Constitution\", concentration = true, school = \"변환학파\", time = \"행동\", range = \"60피트\", dur = \"집중, 최대 1분\", cmp = \"VS\", mins = 1, ko = \"60피트 안에 보이는 생물 하나를 돌로 바꾸려 합니다. 대상은 건강 내성 굴림을 해서, 실패하면 주문이 이어지는 동안 포박 상태가 되고, 성공하면 다음 내 턴이 시작될 때까지 속도가 0이 됩니다. 구조물은 자동으로 성공합니다. 포박된 대상은 자기 턴이 끝날 때마다 다시 굴립니다. 성공이 세 번 쌓이면 주문이 끝나고, 실패가 세 번 쌓이면 돌로 변해 주문이 이어지는 동안 석화 상태가 됩니다(성공과 실패는 연달아 나오지 않아도 셉니다). 1분 내내 집중을 이어 가면, 상급 회복 같은 마법으로 풀 때까지 석화된 채 남습니다. 집중, 최대 1분.\", m = { cast = \"action\", kind = \"save\", save = \"Constitution\", on_save = \"none\", concentration = true, lrfx = {\"Petrified\", \"Restrained\"}, fail = \"Restrained (Speed 0 until your next turn on a success); it saves at the end of each of its turns: three failures = Petrified, three successes = the spell ends\" } },\r\n[\"Floating Disk\"] = { level = 1, classes = {\"Wizard\"}, ritual = true, school = \"조형학파\", time = \"행동 · 의식 가능\", range = \"30피트\", dur = \"1시간\", cmp = \"VS\", ko = \"30피트 안에 보이는 빈 곳에, 지름 3피트·두께 1인치의 둥글고 평평한 역장 원반을 바닥 3피트 위에 1시간 동안 띄웁니다. 원반에는 500파운드까지 실을 수 있고, 더 실으면 주문이 끝나 실린 것이 모두 떨어집니다. 내가 20피트 안에 있는 동안 원반은 움직이지 않고, 20피트 넘게 멀어지면 20피트 안에 있도록 따라옵니다. 울퉁불퉁한 땅이나 계단·비탈은 오르내리지만, 높이가 10피트 이상 달라지는 곳은 건너지 못합니다. 내가 원반에서 100피트 넘게 멀어지면 주문이 끝납니다. 의식으로 시전할 수 있습니다.\", m = { cast = \"action\", kind = \"utility\" } },\r\n[\"Fly\"] = { level = 3, classes = {\"Sorcerer\", \"Warlock\", \"Wizard\"}, concentration = true, school = \"변환학파\", time = \"행동\", range = \"접촉\", dur = \"집중, 최대 10분\", cmp = \"VS\", mins = 10, ko = \"동의한 생물 하나를 만지면, 주문이 이어지는 동안 그 생물이 비행 속도 60피트를 얻고 공중에 떠 있을 수 있습니다. 주문이 끝날 때 아직 공중에 있으면, 떨어지는 것을 막을 방법이 없는 한 떨어집니다. 집중, 최대 10분. 높은 레벨로 시전하면 한 단계마다 대상이 하나씩 늘어납니다.\", m = { fly = 60, cast = \"action\", kind = \"buff\", concentration = true, upcast = { targets = 1 }, targets = 1 } },\r\n[\"Fog Cloud\"] = { level = 1, classes = {\"Druid\", \"Ranger\", \"Sorcerer\", \"Wizard\"}, concentration = true, school = \"조형학파\", time = \"행동\", range = \"120피트\", dur = \"집중, 최대 1시간\", cmp = \"VS\", mins = 60, ko = \"120피트 안의 한 지점을 중심으로 반경 20피트의 안개 구체를 만듭니다. 안개 속은 완전히 가려지고, 주문이 끝나거나 돌풍 같은 강한 바람이 불어 흩어질 때까지 남습니다. 집중, 최대 1시간. 높은 레벨로 시전하면 한 단계마다 반경이 20피트씩 늘어납니다.\", m = { cast = \"action\", kind = \"utility\", concentration = true, area = true } },\r\n[\"Forbiddance\"] = { level = 6, classes = {\"Cleric\"}, ritual = true, school = \"방호학파\", time = \"10분 · 의식 가능\", range = \"접촉\", dur = \"1일\", cmp = \"VS\", ko = \"바닥 넓이 40,000제곱피트, 바닥에서 높이 30피트까지의 구역을 하루 동안 마법 이동으로부터 지킵니다. 그 안으로는 순간이동하거나 관문 같은 문으로 들어올 수 없고, 아스트랄계·에테르계·요정계·어둠의 세계를 거치거나 차원 이동으로 들어오지도 못합니다. 또 이형체·천상체·원소·요정·악마·언데드 가운데 시전할 때 고른 종류의 생물이 턴 중 처음 그 안에 들어오거나 그 안에서 턴을 끝내면, 광휘나 사령 피해 5d10을 받습니다(어느 쪽인지는 시전할 때 고름). 암호를 정해 두면, 그 암호를 말하며 들어오는 생물은 피해를 받지 않습니다. 다른 금단 구역과 겹칠 수 없고, 같은 곳에 30일 동안 매일 시전하면 해제될 때까지 이어집니다. 시전에 10분이 걸리고, 의식으로 시전할 수 있습니다.\", cost = \"ruby dust worth 1,000+ GP\", cost_ko = \"1,000 GP 이상의 루비 가루\", m = { cast = \"10 minutes\", kind = \"utility\" } },\r\n[\"Forcecage\"] = { level = 7, classes = {\"Bard\", \"Warlock\", \"Wizard\"}, save = \"Charisma\", concentration = true, school = \"방출학파\", time = \"행동\", range = \"100피트\", dur = \"집중, 최대 1시간\", cmp = \"VS\", mins = 60, ko = \"100피트 안에서 고른 곳 둘레에, 움직이지 않고 보이지 않는 정육면체 역장 감옥이 생깁니다. 한 변 20피트까지의 창살 우리(창살 굵기와 사이 1/2인치)와 한 변 10피트까지의 꽉 막힌 상자 가운데 고릅니다. 상자는 어떤 물질도 지나가지 못하고, 안팎으로 시전하는 주문도 막습니다. 시전할 때 범위 안에 온전히 든 생물은 갇히고, 일부만 걸치거나 너무 커서 들어가지 못하는 생물은 밖으로 밀려납니다. 갇힌 생물은 마법이 아닌 방법으로는 나오지 못하고, 순간이동이나 다른 세계로 가는 이동으로 나가려면 먼저 매력 내성 굴림에 성공해야 합니다(실패하면 나가지 못하고 그 주문이나 효과만 헛되이 씁니다). 감옥은 에테르계까지 막고, 마법 무효화로 없앨 수 없습니다. 집중, 최대 1시간.\", cost = \"ruby dust worth 1,500+ GP, consumed\", cost_ko = \"1,500 GP 이상의 루비 가루 (시전하면 사라짐)\", m = { cast = \"action\", kind = \"utility\", concentration = true } },\r\n[\"Foresight\"] = { level = 9, classes = {\"Bard\", \"Druid\", \"Warlock\", \"Wizard\"}, school = \"예지학파\", time = \"1분\", range = \"접촉\", dur = \"8시간\", cmp = \"VS\", ko = \"동의한 생물 하나를 만져, 바로 앞의 미래를 내다보는 힘을 줍니다. 8시간 동안 그 생물은 d20 판정에 이점을 받고, 다른 생물이 그 생물을 노리는 명중 굴림에는 불리점이 붙습니다. 이 주문을 다시 시전하면 앞의 것은 끝납니다. 시전에 1분이 걸립니다.\", bmins = 480, m = { cast = \"1 minute\", kind = \"buff\", tell = \"Advantage on every D20 Test; attack rolls against them have Disadvantage\", targets = 1 } },\r\n[\"Freedom of Movement\"] = { level = 4, classes = {\"Bard\", \"Cleric\", \"Druid\", \"Ranger\"}, school = \"방호학파\", time = \"행동\", range = \"접촉\", dur = \"1시간\", cmp = \"VS\", ko = \"동의한 생물 하나를 만지면, 1시간 동안 그 생물은 어려운 지형에서도 이동이 느려지지 않고, 주문이나 마법 효과로 속도가 줄거나 마비·포박 상태가 되지 않습니다. 또 속도만큼의 수영 속도를 얻고, 이동 5피트를 써서 수갑이나 붙잡힘처럼 마법이 아닌 구속에서 자동으로 빠져나올 수 있습니다. 높은 레벨로 시전하면 한 단계마다 대상이 하나씩 늘어납니다.\", bmins = 60, m = { cast = \"action\", kind = \"buff\", upcast = { targets = 1 }, cimm = {\"Paralyzed\", \"Restrained\"}, targets = 1 } },\r\n[\"Freezing Sphere\"] = { level = 6, classes = {\"Sorcerer\", \"Wizard\"}, save = \"Constitution\", half_on_save = true, damage = \"10d6\", damage_type = \"Cold\", school = \"방출학파\", time = \"행동\", range = \"300피트\", dur = \"즉시\", cmp = \"VS\", ko = \"나에게서 차가운 구슬이 날아가 300피트 안의 고른 지점에서 반경 60피트 구체로 터집니다. 그 안의 생물은 모두 건강 내성 굴림을 해서, 실패하면 냉기 피해 10d6, 성공하면 그 절반을 받습니다. 구슬이 물에 맞으면 30피트 정사각형 넓이의 물을 6인치 깊이까지 1분 동안 얼리고, 그 수면에서 헤엄치던 생물은 얼음에 갇혀 포박 상태가 됩니다(행동을 써서 근력(운동) 판정을 하고 내 주문 내성 난이도 이상이 나오면 빠져나옴). 시전을 마친 뒤 구슬을 쏘지 않고, 투석 탄환만 한 차가운 구슬로 손에 남겨 둘 수도 있습니다. 나나 내가 구슬을 건넨 생물이 구슬을 던지거나(40피트까지) 투석구로 쏘면 부딪힌 곳에서 똑같이 터지고, 깨지 않고 내려놓을 수도 있지만 1분이 지나면 저절로 터집니다. 높은 레벨로 시전하면 한 단계마다 피해가 1d6씩 늘어납니다.\", m = { cast = \"action\", kind = \"save\", save = \"Constitution\", on_save = \"half\", damage = \"10d6\", type = \"Cold\", upcast = { dice = \"1d6\" }, area = true } },\r\n[\"Gaseous Form\"] = { level = 3, classes = {\"Sorcerer\", \"Warlock\", \"Wizard\"}, save = \"Constitution\", concentration = true, school = \"변환학파\", time = \"행동\", range = \"접촉\", dur = \"집중, 최대 1시간\", cmp = \"VS\", mins = 60, ko = \"동의한 생물 하나를 만지면, 주문이 이어지는 동안 그 생물이 입고 든 것과 함께 안개구름으로 변합니다. 그 모습으로는 비행 속도 10피트로만 움직이고 떠 있을 수 있으며, 다른 생물이 있는 칸에 들어가 머물 수 있습니다. 좁은 틈을 지나갈 수 있지만, 액체는 단단한 바닥처럼 여깁니다. 타격·관통·참격 피해에 저항하고, 넘어진 상태에 면역이며, 근력·민첩·건강 내성 굴림에 이점을 받습니다. 말하거나 물건을 다루지 못하고, 지닌 물건을 떨어뜨리거나 쓰지도 못하며, 공격하거나 주문을 쓸 수 없습니다. 생명력이 0이 되거나 대상이 마법 행동으로 끝내면 그 대상에게는 주문이 끝납니다. 집중, 최대 1시간. 높은 레벨로 시전하면 한 단계마다 대상이 하나씩 늘어납니다.\", m = { cast = \"action\", kind = \"buff\", concentration = true, resist = {\"Bludgeoning\", \"Piercing\", \"Slashing\"}, targets = 1 } },\r\n[\"Gate\"] = { level = 9, classes = {\"Cleric\", \"Sorcerer\", \"Warlock\", \"Wizard\"}, concentration = true, school = \"조형학파\", time = \"행동\", range = \"60피트\", dur = \"집중, 최대 1분\", cmp = \"VS\", mins = 1, ko = \"60피트 안에 보이는 빈 곳에, 다른 세계의 정확한 장소로 이어지는 지름 5~20피트의 둥근 문을 엽니다. 문은 원하는 방향으로 둘 수 있고, 문 너머로 목적지가 보입니다. 문의 앞면으로 들어가야만 건너갈 수 있고, 들어간 것은 곧바로 반대편 세계에서 문과 가장 가까운 빈 곳에 나타납니다. 신이나 세계의 지배자는 자기 앞이나 자기 영역 안에서 이 문이 열리지 못하게 막을 수 있습니다. 시전할 때 다른 세계에 있는 특정 생물의 이름(가명·칭호·별명은 안 됨)을 부르면, 그 생물 바로 옆에 문이 열려 그 생물이 이쪽으로 끌려옵니다. 그 생물을 부릴 힘은 생기지 않으며, 끌려온 생물은 GM이 정하는 대로 떠나거나, 나를 공격하거나, 나를 도울 수 있습니다. 집중, 최대 1분.\", cost = \"a diamond worth 5,000+ GP\", cost_ko = \"5,000 GP 이상의 다이아몬드\", m = { cast = \"action\", kind = \"utility\", concentration = true } },\r\n[\"Geas\"] = { level = 5, classes = {\"Bard\", \"Cleric\", \"Druid\", \"Paladin\", \"Wizard\"}, save = \"Wisdom\", damage = \"5d10\", damage_type = \"Psychic\", school = \"환혹학파\", time = \"1분\", range = \"60피트\", dur = \"30일\", cmp = \"V\", ko = \"60피트 안에 보이는 생물 하나에게, 어떤 일을 해내거나 어떤 행동을 하지 말라고 말로 명령합니다. 대상은 지혜 내성 굴림을 하고(명령을 알아듣지 못하면 자동으로 성공), 실패하면 30일 동안 매혹 상태가 됩니다. 매혹된 동안 명령을 정면으로 거스르는 행동을 하면 정신 피해 5d10을 받습니다(하루에 한 번까지). 틀림없이 죽게 될 일만 아니면 어떤 명령이든 할 수 있고, 죽으라는 명령을 하면 주문이 끝납니다. 저주 해제·상급 회복·소원으로 이 주문을 끝낼 수 있습니다. 시전에 1분이 걸립니다. 높은 레벨로 시전하면 더 오래갑니다(7~8레벨은 365일, 9레벨은 그 주문들로 끝낼 때까지).\", m = { puts = {\"Charmed\"}, cast = \"1 minute\", kind = \"save\", save = \"Wisdom\", on_save = \"none\", lrfx = {\"Charmed\"}, fail = \"Charmed for 30 days; 5d10 Psychic (once a day) when it acts against your command\" } },\r\n[\"Gentle Repose\"] = { level = 2, classes = {\"Cleric\", \"Paladin\", \"Wizard\"}, ritual = true, school = \"사령학파\", time = \"행동 · 의식 가능\", range = \"접촉\", dur = \"10일\", cmp = \"VS\", ko = \"시체나 유해를 만져, 10일 동안 썩지 않고 언데드가 되지 않게 지킵니다. 이 주문이 걸려 있던 날은 사자 소생 같은 주문의 시간 제한에 들어가지 않습니다. 의식으로 시전할 수 있습니다.\", mcons = true, m = { cast = \"action\", kind = \"utility\" } },\r\n[\"Giant Insect\"] = { level = 4, classes = {\"Druid\"}, concentration = true, school = \"조형학파\", time = \"행동\", range = \"60피트\", dur = \"집중, 최대 10분\", cmp = \"VS\", mins = 10, ko = \"60피트 안에 보이는 빈 곳에 거대 지네·거미·말벌 가운데 시전할 때 고른 하나를 부릅니다. 이 생물은 나와 동료의 편이고, 싸움에서는 내 턴 바로 뒤에 움직입니다. 내가 말로 명령하면 따르고(내 행동은 들지 않음), 명령이 없으면 회피 행동을 하고 위험을 피해 움직입니다. 생명력이 0이 되거나 주문이 끝나면 사라집니다. 집중, 최대 10분. 높은 레벨로 시전하면 능력치 블록에 그 레벨을 써서 더 강해집니다.\", m = { cast = \"action\", kind = \"attack\", attack = \"melee\", damage = \"1d6+1d4+3+LVL\", type = \"Piercing and Poison\", concentration = true } },\r\n[\"Glibness\"] = { level = 8, classes = {\"Bard\", \"Warlock\"}, school = \"환혹학파\", time = \"행동\", range = \"자신\", dur = \"1시간\", cmp = \"V\", ko = \"1시간 동안 매력 판정을 할 때마다, 굴린 주사위 값을 15로 바꿀 수 있습니다. 또 내가 무슨 말을 하든, 참말인지 가려내는 마법에는 내가 참말을 하는 것으로 나옵니다.\", bmins = 60, m = { cast = \"action\", kind = \"buff\" } },\r\n[\"Globe of Invulnerability\"] = { level = 6, classes = {\"Sorcerer\", \"Wizard\"}, concentration = true, school = \"방호학파\", time = \"행동\", range = \"자신\", dur = \"집중, 최대 1분\", cmp = \"VS\", mins = 1, ko = \"내 둘레 10피트에 움직이지 않는 반짝이는 막이 생겨, 주문이 이어지는 동안 남습니다. 막 밖에서 시전한 5레벨 이하 주문은 막 안의 것에 아무 영향도 주지 못합니다. 막 안의 생물이나 물건을 목표로 삼을 수는 있지만 효과가 없고, 그런 주문의 범위에서도 막 안은 빠집니다. 집중, 최대 1분. 높은 레벨로 시전하면 한 단계마다 막아 내는 주문의 레벨이 하나씩 올라갑니다.\", m = { cast = \"action\", kind = \"utility\", concentration = true, upcast = { note = \"one level higher blocked per slot level above 6\" } } },\r\n[\"Glyph of Warding\"] = { level = 3, classes = {\"Bard\", \"Cleric\", \"Wizard\"}, save = \"Dexterity\", half_on_save = true, school = \"방호학파\", time = \"1시간\", range = \"접촉\", dur = \"해제·발동될 때까지\", cmp = \"VS\", ko = \"1시간에 걸쳐, 탁자나 바닥 같은 면, 또는 책이나 상자처럼 닫히는 물건 안에 지름 10피트 이하의 문양을 새깁니다. 새길 때 문양을 건드리거나 밟기, 덮개를 치우기, 물건을 열기 같은 발동 조건을 정하고, 특정 종류의 생물만 발동시키거나 암호를 말하는 생물은 발동시키지 않게 할 수도 있습니다. 문양은 거의 보이지 않아서, 지혜(감지) 판정으로 내 주문 내성 난이도 이상이 나와야 찾을 수 있습니다. 폭발하는 룬으로 새기면, 발동할 때 문양을 중심으로 반경 20피트 안의 생물이 민첩 내성 굴림을 해서 실패하면 산성·냉기·화염·번개·천둥 가운데 새길 때 고른 종류의 피해 5d8, 성공하면 그 절반을 받습니다. 주문 문양으로 새기면, 준비해 둔 3레벨 이하 주문 하나를 담아 두었다가 발동할 때 발동시킨 생물을 노려 터뜨립니다. 새긴 면이나 물건이 10피트 넘게 옮겨지면 문양이 깨지고 주문이 끝납니다. 해제되거나 발동할 때까지 이어집니다. 높은 레벨로 시전하면 한 단계마다 룬 피해가 1d8씩 늘고, 담는 주문도 시전한 레벨까지 됩니다.\", cost = \"powdered diamond worth 200+ GP, consumed\", cost_ko = \"200 GP 이상의 다이아몬드 가루 (시전하면 사라짐)\", m = { cast = \"1 hour\", kind = \"save\", save = \"Dexterity\", on_save = \"half\", damage = \"5d8\", type = \"choice (Acid, Cold, Fire, Lightning, Thunder)\", upcast = { dice = \"1d8\" }, area = true } },\r\n[\"Goodberry\"] = { level = 1, classes = {\"Druid\", \"Ranger\"}, school = \"조형학파\", time = \"행동\", range = \"자신\", dur = \"24시간\", cmp = \"VS\", ko = \"손에 마법이 깃든 열매 열 개가 생겨 24시간 동안 남습니다. 누구든 추가 행동으로 하나를 먹으면 생명력 1을 되찾고, 열매 하나로 하루를 버틸 만큼 배를 채웁니다. 먹지 않은 열매는 주문이 끝나면 사라집니다.\", m = { cast = \"action\", kind = \"utility\" } },\r\n[\"Grease\"] = { level = 1, classes = {\"Sorcerer\", \"Wizard\"}, save = \"Dexterity\", school = \"조형학파\", time = \"행동\", range = \"60피트\", dur = \"1분\", cmp = \"VS\", ko = \"60피트 안의 한 지점을 중심으로 10피트 정사각형의 바닥을 불붙지 않는 기름이 1분 동안 덮어, 그곳이 어려운 지형이 됩니다. 기름이 생길 때 그 위에 서 있던 생물은 민첩 내성 굴림을 하고, 실패하면 넘어진 상태가 됩니다. 그곳에 들어오거나 그 안에서 턴을 끝내는 생물도 같은 내성 굴림을 하고, 실패하면 넘어집니다.\", m = { puts = {\"Prone\"}, cast = \"action\", kind = \"save\", save = \"Dexterity\", on_save = \"none\", warn = \"the grease is nonflammable (SRD 5.2.1, unlike older editions): fire does not ignite it\", lrfx = {\"Prone\"}, area = true, fail = \"Prone; Difficult Terrain for 1 minute\" } },\r\n[\"Greater Invisibility\"] = { level = 4, classes = {\"Bard\", \"Sorcerer\", \"Wizard\"}, concentration = true, school = \"환영학파\", time = \"행동\", range = \"접촉\", dur = \"집중, 최대 1분\", cmp = \"VS\", mins = 1, ko = \"내가 만진 생물이 주문이 이어지는 동안 투명 상태가 됩니다. 투명화와 달리 공격하거나 주문을 써도 풀리지 않습니다. 투명한 동안 그 생물을 노리는 공격은 불리점을 받고, 그 생물의 공격은 이점을 받습니다(그 생물을 볼 수 있는 상대에게는 해당하지 않음). 집중, 최대 1분.\", m = { cast = \"action\", kind = \"buff\", concentration = true, tell = \"Invisible even while attacking or casting: attack rolls against them have Disadvantage, theirs Advantage (not against a creature that sees them)\", targets = 1 } },\r\n[\"Greater Restoration\"] = { level = 5, classes = {\"Bard\", \"Cleric\", \"Druid\", \"Paladin\", \"Ranger\"}, school = \"방호학파\", time = \"행동\", range = \"접촉\", dur = \"즉시\", cmp = \"VS\", ko = \"내가 만진 생물에게서 탈진 1단계, 매혹이나 석화 상태, 저주(저주받은 마법 물건과의 조율 포함), 깎인 능력치, 줄어든 최대 생명력 가운데 하나를 마법으로 없앱니다.\", cost = \"diamond dust worth 100+ GP, consumed\", cost_ko = \"100 GP 이상의 다이아몬드 가루 (시전하면 사라짐)\", m = { cast = \"action\", kind = \"utility\" } },\r\n[\"Guardian of Faith\"] = { level = 4, classes = {\"Cleric\"}, save = \"Dexterity\", half_on_save = true, school = \"조형학파\", time = \"행동\", range = \"30피트\", dur = \"8시간\", cmp = \"V\", ko = \"30피트 안에 보이는 빈 곳에, 내 신이나 신들에 어울리는 모습의 대형 유령 수호자가 나타나 8시간 동안 떠 있습니다. 수호자는 그 자리를 차지하고, 어떤 피해도 받지 않습니다. 적이 턴 중 처음 수호자 10피트 안으로 들어오거나 그 안에서 턴을 시작하면 민첩 내성 굴림을 해서, 실패하면 광휘 피해 20, 성공하면 그 절반을 받습니다. 수호자는 모두 합쳐 60의 피해를 주면 사라집니다.\", m = { cast = \"action\", kind = \"save\", save = \"Dexterity\", on_save = \"half\", damage = \"20\", type = \"Radiant\", lasting = true } },\r\n[\"Guards and Wards\"] = { level = 6, classes = {\"Bard\", \"Wizard\"}, school = \"방호학파\", time = \"1시간\", range = \"접촉\", dur = \"24시간\", cmp = \"VS\", ko = \"바닥 넓이 2,500제곱피트, 높이 20피트까지의 구역을 24시간 동안 지킵니다. 구역은 50피트 정사각형 하나, 이어진 5피트 칸 백 개, 이어진 10피트 칸 스물다섯 개 가운데 하나로 정합니다. 영향받지 않을 사람을 정하거나, 구역 5피트 안에서 소리 내어 말하면 영향받지 않는 암호를 정할 수 있습니다. 복도는 짙은 안개로 완전히 가려지고, 갈림길마다 나 말고는 50% 확률로 고른 쪽과 반대로 간다고 믿게 됩니다. 문은 모두 비전 자물쇠처럼 잠기고, 열 개까지는 환영을 씌워 평범한 벽처럼 보이게 합니다. 계단에는 거미줄 주문 같은 거미줄이 위아래로 가득 찹니다(끊어도 10분이면 다시 자람). 여기에 춤추는 빛·마법의 입·악취 구름·돌풍·암시 가운데 하나를 더 둡니다. 이 주문 자체는 마법 무효화로 없앨 수 없지만 효과는 하나씩 없앨 수 있고, 넷 다 없애면 주문이 끝납니다. 같은 곳에 365일 동안 매일 시전하면 효과가 모두 해제될 때까지 이어집니다. 시전에 1시간이 걸립니다.\", cost = \"a silver rod worth 10+ GP\", cost_ko = \"10 GP 이상의 은 막대\", m = { cast = \"1 hour\", kind = \"utility\" } },\r\n[\"Guidance\"] = { level = 0, classes = {\"Cleric\", \"Druid\"}, concentration = true, school = \"예지학파\", time = \"행동\", range = \"접촉\", dur = \"집중, 최대 1분\", mins = 1, ko = \"동의한 생물 하나를 만지고 기술 하나를 고릅니다. 주문이 끝날 때까지 그 생물은 고른 기술로 하는 능력 판정마다 1d4를 더합니다. 집중, 최대 1분.\", m = { cast = \"action\", kind = \"buff\", concentration = true, cantrip = false, say = \"the creature touched adds 1d4 to ability checks with one skill chosen at casting (Lua adds the d4 to any check: write it only on that skill)\", targets = 1 } },\r\n[\"Guiding Bolt\"] = { level = 1, classes = {\"Cleric\"}, attack = \"ranged\", damage = \"4d6\", damage_type = \"Radiant\", school = \"방출학파\", time = \"행동\", range = \"120피트\", dur = \"1라운드\", cmp = \"VS\", ko = \"120피트 안의 생물 하나에게 빛의 화살을 쏘아 원거리 주문 공격을 합니다. 맞으면 광휘 피해 4d6을 주고, 다음 내 턴이 끝나기 전에 그 대상을 노리는 다음 명중 굴림은 이점을 받습니다. 높은 레벨로 시전하면 한 단계마다 피해가 1d6씩 늘어납니다.\", m = { cast = \"action\", kind = \"attack\", attack = \"ranged\", damage = \"4d6\", type = \"Radiant\", upcast = { dice = \"1d6\" } } },\r\n[\"Gust of Wind\"] = { level = 2, classes = {\"Druid\", \"Ranger\", \"Sorcerer\", \"Wizard\"}, save = \"Strength\", concentration = true, school = \"방출학파\", time = \"행동\", range = \"자신\", dur = \"집중, 최대 1분\", cmp = \"VS\", mins = 1, ko = \"주문이 이어지는 동안 나에게서 고른 방향으로, 길이 60피트·폭 10피트의 일직선으로 거센 바람이 붑니다. 그 안의 생물은 근력 내성 굴림을 해서, 실패하면 바람을 따라 나에게서 15피트 밀려나고, 그 안에서 턴을 끝내는 생물도 같은 내성 굴림을 합니다. 그 안에서 나에게 다가오려면 1피트마다 이동 2피트가 듭니다. 바람은 기체와 증기를 흩어 버리고, 촛불 같은 드러난 불을 끄며, 랜턴처럼 가린 불은 세차게 흔들어 50% 확률로 끕니다. 이후 내 턴에 추가 행동으로 바람의 방향을 바꿀 수 있습니다. 집중, 최대 1분.\", m = { cast = \"action\", kind = \"save\", save = \"Strength\", on_save = \"none\", concentration = true, lrfx = {}, area = true, fail = \"pushed 15 ft away; moving toward you costs double\" } },\r\n[\"Hallow\"] = { level = 5, classes = {\"Cleric\"}, school = \"방호학파\", time = \"24시간\", range = \"접촉\", dur = \"해제될 때까지\", cmp = \"VS\", ko = \"한 지점을 만져, 그 둘레 반경 60피트까지를 거룩하거나 불경한 힘으로 채웁니다(이미 신성화가 걸린 곳과 겹치면 실패). 이형체·천상체·원소·요정·악마·언데드 가운데 고른 종류의 생물은 그곳에 스스로 들어오지 못하고, 그곳 안에서는 그런 생물에게 받은 빙의·매혹·공포가 듣지 않습니다. 여기에 용기(고른 종류는 공포 상태가 되지 않음), 어둠, 햇빛, 평온한 안식(묻힌 시체가 언데드가 되지 않음), 차원 간섭(고른 종류는 순간이동이나 다른 세계로의 이동으로 드나들지 못함), 공포(고른 종류는 공포 상태가 됨), 저항이나 취약(고른 종류가 고른 피해 하나에), 침묵, 언어(고른 종류는 말이 달라도 서로 통함) 가운데 하나를 추가 효과로 묶습니다. 시전에 24시간이 걸리고, 해제될 때까지 이어집니다.\", cost = \"incense worth 1,000+ GP, consumed\", cost_ko = \"1,000 GP 이상의 향 (시전하면 사라짐)\", m = { cast = \"24 hours\", kind = \"utility\" } },\r\n[\"Hallucinatory Terrain\"] = { level = 4, classes = {\"Bard\", \"Druid\", \"Warlock\", \"Wizard\"}, school = \"환영학파\", time = \"10분\", range = \"300피트\", dur = \"24시간\", cmp = \"VS\", ko = \"300피트 안의 150피트 정육면체 안에 있는 자연 지형을, 24시간 동안 다른 자연 지형처럼 보이고 들리고 냄새 나게 합니다. 들판이나 길을 늪·언덕·갈라진 틈으로, 연못을 풀밭으로, 낭떠러지를 완만한 비탈로 보이게 하는 식입니다. 사람이 지은 건물이나 장비, 생물은 바뀌지 않습니다. 손으로 만진 느낌은 그대로라 그곳에 들어가는 생물은 환영임을 눈치채기 쉽고, 만져서 모르겠으면 탐구 행동으로 살펴 지능(조사) 판정에서 내 주문 내성 난이도 이상이 나와야 알아챕니다. 환영임을 알아챈 생물에게는 진짜 지형 위에 흐릿한 상이 겹쳐 보입니다. 시전에 10분이 걸립니다.\", m = { cast = \"10 minutes\", kind = \"utility\" } },\r\n[\"Harm\"] = { level = 6, classes = {\"Cleric\"}, save = \"Constitution\", half_on_save = true, damage = \"14d6\", damage_type = \"Necrotic\", school = \"사령학파\", time = \"행동\", range = \"60피트\", dur = \"즉시\", cmp = \"VS\", ko = \"60피트 안에 보이는 생물 하나에게 독한 마법을 퍼붓습니다. 대상은 건강 내성 굴림을 해서, 실패하면 사령 피해 14d6을 받고 받은 사령 피해만큼 최대 생명력도 줄어듭니다(1 아래로는 줄지 않음). 성공하면 피해만 절반 받습니다.\", m = { cast = \"action\", kind = \"save\", save = \"Constitution\", on_save = \"half\", damage = \"14d6\", type = \"Necrotic\" } },\r\n[\"Haste\"] = { level = 3, classes = {\"Sorcerer\", \"Wizard\"}, save = \"Dexterity\", concentration = true, school = \"변환학파\", time = \"행동\", range = \"30피트\", dur = \"집중, 최대 1분\", cmp = \"VS\", mins = 1, ko = \"30피트 안에 보이는 동의한 생물 하나를 고릅니다. 주문이 이어지는 동안 그 생물은 속도가 두 배가 되고, 방어도가 2 오르며, 민첩 내성 굴림에 이점을 받고, 자기 턴마다 행동을 하나 더 얻습니다. 더 얻은 행동으로는 공격(한 번만)·질주·이탈·숨기·물건 사용 행동만 할 수 있습니다. 주문이 끝나면 무기력이 덮쳐, 그 생물은 자기 다음 턴이 끝날 때까지 행동불능 상태가 되고 속도가 0이 됩니다. 집중, 최대 1분.\", m = { cast = \"action\", kind = \"buff\", concentration = true, ac_bonus = 2, tell = \"Speed doubled; Advantage on Dexterity saves; one extra action each turn (Attack with one attack only, Dash, Disengage, Hide or Utilize); when it ends, a turn without moving or acting\", targets = 1 } },\r\n[\"Heal\"] = { level = 6, classes = {\"Cleric\", \"Druid\"}, school = \"방호학파\", time = \"행동\", range = \"60피트\", dur = \"즉시\", cmp = \"VS\", ko = \"60피트 안에 보이는 생물 하나를 골라, 생명력을 70 되찾게 하고 장님·귀머거리·중독 상태를 풀어 줍니다. 높은 레벨로 시전하면 한 단계마다 회복량이 10씩 늘어납니다.\", m = { cast = \"action\", kind = \"heal\", heal = \"70\", upcast = { dice = \"10\" }, htargets = 1 } },\r\n[\"Healing Word\"] = { level = 1, classes = {\"Bard\", \"Cleric\", \"Druid\"}, heal = \"2d4\", school = \"방호학파\", time = \"추가 행동\", range = \"60피트\", dur = \"즉시\", cmp = \"V\", ko = \"추가 행동으로 60피트 안에 보이는 생물 하나를 골라, 2d4 + 내 주문시전 능력치 수정치만큼 생명력을 회복하게 합니다. 높은 레벨로 시전하면 한 단계마다 회복량이 2d4씩 늘어납니다.\", m = { cast = \"bonus\", kind = \"heal\", heal = \"2d4+MOD\", upcast = { dice = \"2d4\" }, htargets = 1 } },\r\n[\"Heat Metal\"] = { level = 2, classes = {\"Bard\", \"Druid\"}, save = \"Constitution\", damage = \"2d8\", damage_type = \"Fire\", concentration = true, school = \"변환학파\", time = \"행동\", range = \"60피트\", dur = \"집중, 최대 1분\", cmp = \"VS\", mins = 1, ko = \"60피트 안에 보이는, 사람이 만든 금속 물건 하나(금속 무기나 금속으로 된 평갑·중갑 같은 것)를 시뻘겋게 달굽니다. 시전할 때 그 물건에 닿아 있는 생물은 화염 피해 2d8을 받고, 주문이 끝날 때까지 이후 내 턴마다 추가 행동으로 이 피해를 다시 줄 수 있습니다(물건이 60피트 안에 있을 때). 그 물건을 쥐고 있거나 입은 생물이 이 피해를 받으면 건강 내성 굴림을 하고, 실패하면 떨어뜨릴 수 있을 때는 그 물건을 떨어뜨립니다. 떨어뜨리지 않으면 다음 내 턴이 시작될 때까지 명중 굴림과 능력 판정에 불리점을 받습니다. 집중, 최대 1분. 높은 레벨로 시전하면 한 단계마다 피해가 1d8씩 늘어납니다.\", m = { cast = \"action\", kind = \"save\", save = \"Constitution\", on_save = \"full\", damage = \"2d8\", type = \"Fire\", concentration = true, upcast = { dice = \"1d8\" } } },\r\n[\"Hellish Rebuke\"] = { level = 1, classes = {\"Warlock\"}, save = \"Dexterity\", half_on_save = true, damage = \"2d10\", damage_type = \"Fire\", school = \"방출학파\", time = \"반응행동\", range = \"60피트\", dur = \"즉시\", cmp = \"VS\", ko = \"60피트 안에 보이는 생물에게 피해를 받았을 때 반응행동으로 씁니다. 그 생물이 초록 불길에 휩싸여 민첩 내성 굴림을 하고, 실패하면 화염 피해 2d10, 성공하면 그 절반을 받습니다. 높은 레벨로 시전하면 한 단계마다 피해가 1d10씩 늘어납니다.\", m = { cast = \"reaction\", kind = \"save\", save = \"Dexterity\", on_save = \"half\", damage = \"2d10\", type = \"Fire\", upcast = { dice = \"1d10\" } } },\r\n[\"Heroes' Feast\"] = { level = 6, classes = {\"Bard\", \"Cleric\", \"Druid\"}, school = \"조형학파\", time = \"10분\", range = \"자신\", dur = \"즉시\", cmp = \"VS\", ko = \"내 옆의 비어 있는 10피트 정육면체에 잔치를 차립니다. 다 먹는 데 1시간이 걸리고, 그 1시간이 지나야 효과가 나타나며 음식은 사라집니다. 열둘까지 함께 먹을 수 있고, 먹은 생물은 24시간 동안 독성 피해에 저항하고 공포·중독 상태에 면역이 되며, 최대 생명력이 2d10 늘고 생명력도 그만큼 얻습니다. 시전에 10분이 걸립니다.\", cost = \"a gem-encrusted bowl worth 1,000+ GP, consumed\", cost_ko = \"1,000 GP 이상의 보석 박힌 그릇 (시전하면 사라짐)\", m = { cast = \"10 minutes\", kind = \"buff\", hp_bonus = \"2d10\", dur_mins = 1440, resist = {\"Poison\"}, cimm = {\"Frightened\", \"Poisoned\"}, targets = 12 } },\r\n[\"Heroism\"] = { level = 1, classes = {\"Bard\", \"Paladin\"}, concentration = true, school = \"환혹학파\", time = \"행동\", range = \"접촉\", dur = \"집중, 최대 1분\", cmp = \"VS\", mins = 1, ko = \"동의한 생물 하나를 만져 용기를 불어넣습니다. 주문이 끝날 때까지 그 생물은 공포 상태에 걸리지 않고, 자기 턴이 시작될 때마다 내 주문시전 능력치 수정치만큼 임시 생명력을 얻습니다. 집중, 최대 1분. 높은 레벨로 시전하면 한 단계마다 대상이 하나씩 늘어납니다.\", m = { cast = \"action\", kind = \"buff\", concentration = true, cimm = {\"Frightened\"}, turn_thp = true, upcast = { targets = 1 }, targets = 1 } },\r\n[\"Hex\"] = { level = 1, classes = {\"Warlock\"}, damage = \"1d6\", damage_type = \"Necrotic\", concentration = true, school = \"환혹학파\", time = \"추가 행동\", range = \"90피트\", dur = \"집중, 최대 1시간\", cmp = \"VS\", mins = 60, ko = \"추가 행동으로 90피트 안에 보이는 생물 하나에게 저주를 겁니다. 주문이 끝날 때까지 내가 그 대상을 명중 굴림으로 맞힐 때마다 사령 피해 1d6을 더 주고, 대상은 시전할 때 고른 능력치 하나로 하는 능력 판정에 불리점을 받습니다. 주문이 끝나기 전에 대상의 생명력이 0이 되면, 이후 내 턴에 추가 행동으로 새 생물에게 저주를 옮길 수 있습니다. 집중, 최대 1시간. 높은 레벨로 시전하면 집중을 더 오래 이어 갈 수 있습니다(2레벨은 4시간, 3~4레벨은 8시간, 5레벨 이상은 24시간).\", m = { cast = \"bonus\", kind = \"buff\", concentration = true, rider = \"1d6\", rider_type = \"Necrotic\", rider_each = true, effect = \"+1d6 Necrotic on every hit against the target; Disadvantage on checks with one ability\" } },\r\n[\"Hideous Laughter\"] = { level = 1, classes = {\"Bard\", \"Warlock\", \"Wizard\"}, save = \"Wisdom\", concentration = true, school = \"환혹학파\", time = \"행동\", range = \"30피트\", dur = \"집중, 최대 1분\", cmp = \"VS\", mins = 1, ko = \"30피트 안에 보이는 생물 하나가 지혜 내성 굴림을 합니다. 실패하면 주문이 이어지는 동안 넘어진 상태와 행동불능 상태가 되어, 웃을 수 있는 생물이면 참지 못하고 웃어 대며, 스스로 일어나지 못합니다. 대상은 자기 턴이 끝날 때마다, 그리고 피해를 받을 때마다 다시 지혜 내성 굴림을 하고(피해 때문이면 이점), 성공하면 주문이 끝납니다. 집중, 최대 1분. 높은 레벨로 시전하면 한 단계마다 대상이 하나씩 늘어납니다.\", m = { cast = \"action\", kind = \"save\", save = \"Wisdom\", on_save = \"none\", concentration = true, upcast = { targets = 1 }, lrfx = {\"Incapacitated\", \"Prone\"}, fail = \"Prone and Incapacitated; repeats the save each turn end and when damaged (with Advantage)\" } },\r\n[\"Hold Monster\"] = { level = 5, classes = {\"Bard\", \"Sorcerer\", \"Warlock\", \"Wizard\"}, save = \"Wisdom\", concentration = true, school = \"환혹학파\", time = \"행동\", range = \"90피트\", dur = \"집중, 최대 1분\", cmp = \"VS\", mins = 1, ko = \"90피트 안에 보이는 생물 하나가 지혜 내성 굴림을 합니다. 실패하면 주문이 이어지는 동안 마비 상태가 됩니다. 대상은 자기 턴이 끝날 때마다 다시 굴려, 성공하면 풀려납니다. 집중, 최대 1분. 높은 레벨로 시전하면 한 단계마다 대상이 하나씩 늘어납니다.\", m = { cast = \"action\", kind = \"save\", save = \"Wisdom\", on_save = \"none\", concentration = true, upcast = { targets = 1 }, lrfx = {\"Paralyzed\"}, fail = \"Paralyzed; repeats the save at the end of each of its turns\" } },\r\n[\"Hold Person\"] = { level = 2, classes = {\"Bard\", \"Cleric\", \"Druid\", \"Sorcerer\", \"Warlock\", \"Wizard\"}, save = \"Wisdom\", concentration = true, school = \"환혹학파\", time = \"행동\", range = \"60피트\", dur = \"집중, 최대 1분\", cmp = \"VS\", mins = 1, ko = \"60피트 안에 보이는 인간형 하나가 지혜 내성 굴림을 합니다. 실패하면 주문이 이어지는 동안 마비 상태가 됩니다. 대상은 자기 턴이 끝날 때마다 다시 굴려, 성공하면 풀려납니다. 집중, 최대 1분. 높은 레벨로 시전하면 한 단계마다 인간형 대상이 하나씩 늘어납니다.\", m = { cast = \"action\", kind = \"save\", save = \"Wisdom\", on_save = \"none\", concentration = true, upcast = { targets = 1 }, lrfx = {\"Paralyzed\"}, fail = \"Paralyzed; repeats the save each turn end\" } },\r\n[\"Holy Aura\"] = { level = 8, classes = {\"Cleric\"}, save = \"Constitution\", concentration = true, school = \"방호학파\", time = \"행동\", range = \"자신\", dur = \"집중, 최대 1분\", cmp = \"VS\", mins = 1, ko = \"주문이 이어지는 동안 내 둘레 30피트에 신성한 기운이 퍼집니다. 그 안에 있는 동안 내가 고른 생물은 모든 내성 굴림에 이점을 받고, 다른 생물이 그들을 노리는 명중 굴림은 불리점을 받습니다. 또 악마나 언데드가 근접 명중 굴림으로 그들을 맞히면, 그 공격자는 건강 내성 굴림을 해서 실패하면 자기 다음 턴이 끝날 때까지 장님 상태가 됩니다. 집중, 최대 1분.\", cost = \"a reliquary worth 1,000+ GP\", cost_ko = \"1,000 GP 이상의 성물함\", m = { cast = \"action\", kind = \"buff\", concentration = true, btargets = 12, tell = \"Advantage on all saving throws; attack rolls against them have Disadvantage; a Fiend or Undead that hits them in melee makes a Constitution save or is Blinded\" } },\r\n[\"Hunter's Mark\"] = { level = 1, classes = {\"Ranger\"}, damage = \"1d6\", damage_type = \"Force\", concentration = true, school = \"예지학파\", time = \"추가 행동\", range = \"90피트\", dur = \"집중, 최대 1시간\", cmp = \"V\", mins = 60, ko = \"추가 행동으로 90피트 안에 보이는 생물 하나를 마법으로 사냥감 삼아 표식을 남깁니다. 주문이 끝날 때까지 내가 그 대상을 명중 굴림으로 맞힐 때마다 역장 피해 1d6을 더 주고, 그 대상을 찾는 지혜(감지·생존) 판정에 이점을 받습니다. 주문이 끝나기 전에 대상의 생명력이 0이 되면, 추가 행동으로 표식을 90피트 안에 보이는 새 생물에게 옮길 수 있습니다. 집중, 최대 1시간. 높은 레벨로 시전하면 집중을 더 오래 이어 갈 수 있습니다(3~4레벨은 8시간, 5레벨 이상은 24시간).\", m = { cast = \"bonus\", kind = \"buff\", concentration = true, rider = \"1d6\", rider_type = \"Force\", rider_each = true, effect = \"+1d6 Force on every hit against the marked creature\" } },\r\n[\"Hypnotic Pattern\"] = { level = 3, classes = {\"Bard\", \"Sorcerer\", \"Warlock\", \"Wizard\"}, save = \"Wisdom\", concentration = true, school = \"환영학파\", time = \"행동\", range = \"120피트\", dur = \"집중, 최대 1분\", cmp = \"S\", mins = 1, ko = \"120피트 안의 30피트 정육면체에 소용돌이치는 빛깔 무늬가 잠깐 나타났다 사라집니다. 그 안에서 무늬를 본 생물은 지혜 내성 굴림을 하고, 실패하면 주문이 이어지는 동안 매혹 상태가 됩니다. 매혹된 동안에는 행동불능 상태이고 속도가 0입니다. 걸린 생물이 피해를 받거나, 다른 누군가가 행동을 써서 흔들어 정신 차리게 하면 그 생물에게는 주문이 끝납니다. 집중, 최대 1분.\", m = { cast = \"action\", kind = \"save\", save = \"Wisdom\", on_save = \"none\", concentration = true, lrfx = {\"Charmed\", \"Incapacitated\"}, area = true, fail = \"Charmed, Incapacitated, Speed 0 until damaged or shaken awake\" } },\r\n[\"Ice Knife\"] = { level = 1, classes = {\"Druid\", \"Sorcerer\", \"Wizard\"}, attack = \"ranged\", save = \"Dexterity\", damage = \"1d10\", damage_type = \"Piercing\", school = \"조형학파\", time = \"행동\", range = \"60피트\", dur = \"즉시\", cmp = \"S\", ko = \"얼음 조각을 만들어 60피트 안의 생물 하나에게 던져 원거리 주문 공격을 합니다. 맞으면 관통 피해 1d10을 줍니다. 맞든 빗나가든 얼음 조각은 터지고, 대상과 그 5피트 안의 생물은 모두 민첩 내성 굴림을 해서 실패하면 냉기 피해 2d6을 받습니다. 높은 레벨로 시전하면 한 단계마다 냉기 피해가 1d6씩 늘어납니다.\", m = { cast = \"action\", kind = \"attack\", attack = \"ranged\", damage = \"1d10\", type = \"Piercing\", extra_save = { save = \"Dexterity\", on_save = \"none\", damage = \"2d6\", type = \"Cold\", targets = \"the target and each creature within 5 ft\" }, upcast = { dice = \"1d6\", applies_to = \"Cold\" } } },\r\n[\"Ice Storm\"] = { level = 4, classes = {\"Druid\", \"Sorcerer\", \"Wizard\"}, save = \"Dexterity\", half_on_save = true, damage = \"2d10\", damage_type = \"Bludgeoning\", school = \"방출학파\", time = \"행동\", range = \"300피트\", dur = \"즉시\", cmp = \"VS\", ko = \"300피트 안의 한 지점을 중심으로 반경 20피트·높이 40피트 원기둥에 우박이 쏟아집니다. 그 안의 생물은 모두 민첩 내성 굴림을 해서, 실패하면 타격 피해 2d10과 냉기 피해 4d6을, 성공하면 그 절반을 받습니다. 쌓인 우박 때문에 다음 내 턴이 끝날 때까지 원기둥 안의 땅은 어려운 지형이 됩니다. 높은 레벨로 시전하면 한 단계마다 타격 피해가 1d10씩 늘어납니다.\", m = { cast = \"action\", kind = \"save\", save = \"Dexterity\", on_save = \"half\", damage = \"2d10+4d6\", type = \"Bludgeoning and Cold\", upcast = { dice = \"1d10\" }, area = true } },\r\n[\"Identify\"] = { level = 1, classes = {\"Bard\", \"Wizard\"}, ritual = true, school = \"예지학파\", time = \"1분 · 의식 가능\", range = \"접촉\", dur = \"즉시\", cmp = \"VS\", ko = \"시전하는 1분 내내 물건 하나를 만지고 있으면, 그 물건이 마법 물건일 때 성질과 쓰는 법, 조율이 필요한지, 충전이 몇 번 남았는지 알게 되고, 그 물건에 걸려 있는 주문과 그 물건을 만든 주문도 알아냅니다. 물건 대신 생물을 만지고 있었다면, 그 생물에게 지금 걸려 있는 주문을 알아냅니다. 의식으로 시전할 수 있습니다.\", cost = \"a pearl worth 100+ GP\", cost_ko = \"100 GP 이상의 진주\", m = { cast = \"1 minute\", kind = \"utility\" } },\r\n[\"Illusory Script\"] = { level = 1, classes = {\"Bard\", \"Warlock\", \"Wizard\"}, ritual = true, school = \"환영학파\", time = \"1분 · 의식 가능\", range = \"접촉\", dur = \"10일\", cmp = \"S\", ko = \"양피지나 종이 같은 것에 글을 쓰고, 10일 동안 이어지는 환영을 씌웁니다. 나와 시전할 때 정한 생물에게는 그 글이 내 글씨로 쓰인 평범한 글로 읽히고, 다른 이에게는 알아볼 수 없는 낯선 문자로 보입니다. 아니면 글의 뜻·글씨체·언어(내가 아는 언어)가 아예 다르게 보이게 할 수도 있습니다. 주문이 해제되면 원래 글과 환영이 함께 사라집니다. 진시야가 있는 생물은 숨긴 내용을 읽을 수 있습니다. 시전에 1분이 걸리고, 의식으로 시전할 수 있습니다.\", cost = \"ink worth 10+ GP, consumed\", cost_ko = \"10 GP 이상의 잉크 (시전하면 사라짐)\", m = { cast = \"1 minute\", kind = \"utility\" } },\r\n[\"Imprisonment\"] = { level = 9, classes = {\"Warlock\", \"Wizard\"}, save = \"Wisdom\", school = \"방호학파\", time = \"1분\", range = \"30피트\", dur = \"해제될 때까지\", cmp = \"VS\", ko = \"30피트 안에 보이는 생물 하나를 마법으로 가두려 합니다. 대상은 지혜 내성 굴림을 하고, 성공하면 아무 영향이 없으며 24시간 동안 이 주문에 면역이 됩니다. 실패하면 갇힙니다. 갇힌 동안에는 숨 쉬거나 먹고 마실 필요가 없고 늙지 않으며, 예지계 주문으로 찾거나 엿볼 수 없고 순간이동도 할 수 없습니다. 가두는 방식은 다섯 가운데 하나를 고릅니다. 매장은 땅속 역장 구체에 묻어 무엇도 드나들지 못하게 하고, 사슬은 땅에 박힌 사슬로 묶어 포박 상태로 두며 어떤 방법으로도 옮길 수 없게 합니다. 울타리 감옥은 순간이동과 다른 세계로의 이동이 막힌 반차원(미궁·우리·탑 같은 곳)에 가두고, 축소 감금은 1인치로 줄여 부서지지 않는 보석 같은 것 속에 가두며(빛만 드나듦), 잠은 무의식 상태로 만들어 깨어나지 못하게 합니다. 시전할 때 주문이 끝날 계기(10년 안에 일어날 법한, 눈으로 볼 수 있는 일)를 정해야 하고, 마법 무효화는 9레벨로 시전해 감옥이나 재료를 노려야만 이 주문을 끝낼 수 있습니다. 시전에 1분이 걸립니다.\", cost = \"a statuette of the target worth 5,000+ GP\", cost_ko = \"5,000 GP 이상의 대상 조각상\", m = { cast = \"1 minute\", kind = \"save\", save = \"Wisdom\", on_save = \"none\", lrfx = {\"Restrained\", \"Unconscious\"}, fail = \"a failure imprisons it until a trigger you name (Burial, Chaining = Restrained, Hedged Prison, Minimus Containment, Slumber = Unconscious); a success: immune for 24 hours\" } },\r\n[\"Incendiary Cloud\"] = { level = 8, classes = {\"Druid\", \"Sorcerer\", \"Wizard\"}, save = \"Dexterity\", half_on_save = true, damage = \"10d8\", damage_type = \"Fire\", concentration = true, school = \"조형학파\", time = \"행동\", range = \"150피트\", dur = \"집중, 최대 1분\", cmp = \"VS\", mins = 1, ko = \"150피트 안의 한 지점을 중심으로, 소용돌이치는 불티와 연기 구름이 반경 20피트 구체를 채웁니다. 구름 속은 완전히 가려지고, 돌풍 같은 강한 바람이 불면 흩어지며 주문이 끝납니다. 구름이 나타날 때 그 안의 생물은 민첩 내성 굴림을 해서, 실패하면 화염 피해 10d8, 성공하면 그 절반을 받습니다. 구름이 생물이 있는 곳으로 옮겨 가거나, 생물이 구름에 들어오거나 그 안에서 턴을 끝낼 때도 같은 내성 굴림을 합니다(턴마다 한 번). 구름은 내 턴이 시작될 때마다 내가 고른 방향으로, 나에게서 멀어지게 10피트씩 움직입니다. 집중, 최대 1분.\", m = { cast = \"action\", kind = \"save\", save = \"Dexterity\", on_save = \"half\", damage = \"10d8\", type = \"Fire\", concentration = true, area = true } },\r\n[\"Inflict Wounds\"] = { level = 1, classes = {\"Cleric\"}, save = \"Constitution\", half_on_save = true, damage = \"2d10\", damage_type = \"Necrotic\", school = \"사령학파\", time = \"행동\", range = \"접촉\", dur = \"즉시\", cmp = \"VS\", ko = \"내가 만진 생물이 건강 내성 굴림을 해서, 실패하면 사령 피해 2d10, 성공하면 그 절반을 받습니다. 높은 레벨로 시전하면 한 단계마다 피해가 1d10씩 늘어납니다.\", m = { cast = \"action\", kind = \"save\", save = \"Constitution\", on_save = \"half\", damage = \"2d10\", type = \"Necrotic\", upcast = { dice = \"1d10\" } } },\r\n[\"Insect Plague\"] = { level = 5, classes = {\"Cleric\", \"Druid\", \"Sorcerer\"}, save = \"Constitution\", half_on_save = true, damage = \"4d10\", damage_type = \"Piercing\", concentration = true, school = \"조형학파\", time = \"행동\", range = \"300피트\", dur = \"집중, 최대 10분\", cmp = \"VS\", mins = 10, ko = \"300피트 안의 고른 지점을 중심으로, 반경 20피트 구체를 들끓는 메뚜기 떼로 채웁니다. 주문이 이어지는 동안 그 안은 살짝 가려지고 어려운 지형이 됩니다. 떼가 나타날 때 그 안의 생물은 건강 내성 굴림을 해서, 실패하면 관통 피해 4d10, 성공하면 그 절반을 받습니다. 턴 중 처음 그곳에 들어오거나 그 안에서 턴을 끝내는 생물도 같은 내성 굴림을 합니다(턴마다 한 번). 집중, 최대 10분. 높은 레벨로 시전하면 한 단계마다 피해가 1d10씩 늘어납니다.\", m = { cast = \"action\", kind = \"save\", save = \"Constitution\", on_save = \"half\", damage = \"4d10\", type = \"Piercing\", concentration = true, upcast = { dice = \"1d10\" }, area = true } },\r\n[\"Instant Summons\"] = { level = 6, classes = {\"Wizard\"}, ritual = true, school = \"조형학파\", time = \"1분 · 의식 가능\", range = \"접촉\", dur = \"해제될 때까지\", cmp = \"VS\", ko = \"시전에 쓰는 사파이어와, 무게 10파운드 이하이고 가장 긴 쪽이 6피트 이하인 물건 하나를 만집니다. 물건에는 보이지 않는 표시가 남고, 사파이어에는 물건의 이름이 보이지 않게 새겨집니다(시전할 때마다 다른 사파이어를 씀). 그 뒤 마법 행동으로 물건의 이름을 말하며 사파이어를 부수면, 거리나 세계와 상관없이 물건이 곧바로 내 손에 나타나고 주문이 끝납니다. 다른 생물이 물건을 들고 있거나 지니고 있으면 물건은 오지 않고, 대신 그 생물이 누구이며 지금 어디 있는지 알게 됩니다. 시전에 1분이 걸리고, 의식으로 시전할 수 있습니다.\", cost = \"a sapphire worth 1,000+ GP\", cost_ko = \"1,000 GP 이상의 사파이어 (물건을 부를 때 부숨)\", m = { cast = \"1 minute\", kind = \"utility\" } },\r\n[\"Irresistible Dance\"] = { level = 6, classes = {\"Bard\", \"Wizard\"}, save = \"Wisdom\", concentration = true, school = \"환혹학파\", time = \"행동\", range = \"30피트\", dur = \"집중, 최대 1분\", cmp = \"V\", mins = 1, ko = \"30피트 안에 보이는 생물 하나가 지혜 내성 굴림을 합니다. 성공해도 자기 다음 턴이 끝날 때까지 우스꽝스럽게 춤을 추며, 그동안 이동을 모두 제자리에서 춤추는 데 써야 합니다. 실패하면 주문이 이어지는 동안 매혹 상태가 되어 우스꽝스럽게 춤추고, 이동을 모두 제자리 춤에 쓰며, 민첩 내성 굴림과 명중 굴림에 불리점을 받고, 다른 생물이 대상을 노리는 명중 굴림은 이점을 받습니다. 대상은 자기 턴마다 행동을 써서 정신을 가다듬고 다시 굴릴 수 있고, 성공하면 풀려납니다. 집중, 최대 1분.\", m = { cast = \"action\", kind = \"save\", save = \"Wisdom\", on_save = \"none\", concentration = true, lrfx = {\"Charmed\"}, fail = \"Charmed and dancing: Disadvantage on Dexterity saves and attack rolls, attacks against it have Advantage; an action repeats the save (on a success it only dances until the end of its next turn)\" } },\r\n[\"Invisibility\"] = { level = 2, classes = {\"Bard\", \"Sorcerer\", \"Warlock\", \"Wizard\"}, concentration = true, school = \"환영학파\", time = \"행동\", range = \"접촉\", dur = \"집중, 최대 1시간\", cmp = \"VS\", mins = 60, ko = \"내가 만진 생물이 주문이 이어지는 동안 투명 상태가 됩니다. 대상이 명중 굴림을 하거나, 피해를 주거나, 주문을 시전하면 그 직후 주문이 끝납니다. 집중, 최대 1시간. 높은 레벨로 시전하면 한 단계마다 대상이 하나씩 늘어납니다.\", m = { cast = \"action\", kind = \"buff\", concentration = true, upcast = { targets = 1 }, targets = 1 } },\r\n[\"Jump\"] = { level = 1, classes = {\"Druid\", \"Ranger\", \"Sorcerer\", \"Wizard\"}, school = \"변환학파\", time = \"추가 행동\", range = \"접촉\", dur = \"1분\", ko = \"추가 행동으로 동의한 생물 하나를 만집니다. 1분 동안 그 생물은 자기 턴마다 한 번, 이동 10피트를 써서 30피트까지 뛸 수 있습니다. 높은 레벨로 시전하면 한 단계마다 대상이 하나씩 늘어납니다.\", bmins = 1, m = { cast = \"bonus\", kind = \"buff\", upcast = { targets = 1 }, say = \"once on each of its turns the target jumps up to 30 ft by spending 10 ft of movement\", targets = 1 } },\r\n[\"Knock\"] = { level = 2, classes = {\"Bard\", \"Sorcerer\", \"Wizard\"}, school = \"변환학파\", time = \"행동\", range = \"60피트\", dur = \"즉시\", cmp = \"V\", ko = \"60피트 안에 보이는 문·상자·궤짝·수갑·자물쇠처럼, 무언가로 잠겨 열리지 않는 물건 하나를 고릅니다. 평범한 자물쇠로 잠겼거나, 꽉 끼었거나, 빗장이 걸렸다면 풀립니다(자물쇠가 여럿이면 하나만). 비전 자물쇠로 잠긴 것은 그 주문이 10분 동안 멈춰, 그동안 열고 닫을 수 있습니다. 시전할 때 대상에서 300피트까지 들리는 큰 노크 소리가 납니다.\", m = { cast = \"action\", kind = \"utility\" } },\r\n[\"Legend Lore\"] = { level = 5, classes = {\"Bard\", \"Cleric\", \"Wizard\"}, school = \"예지학파\", time = \"10분\", range = \"자신\", dur = \"즉시\", cmp = \"VS\", ko = \"이름난 사람·장소·물건 하나를 말하거나 묘사하면, 그에 얽힌 중요한 전승의 요약이 머릿속에 떠오릅니다(GM이 들려줌). 중요한 사실이나 뜻밖의 이야기, 널리 알려지지 않은 비밀일 수도 있고, 미리 아는 것이 많을수록 더 정확하고 자세해집니다. 정보는 참이지만 비유나 시로 전해질 수 있습니다. 고른 것이 사실 이름나지 않은 것이면 트롬본의 슬픈 소리가 들리고 주문이 실패합니다. 시전에 10분이 걸립니다.\", cost = \"incense worth 250+ GP, consumed, and four ivory strips worth 50+ GP each\", cost_ko = \"250 GP 이상의 향 (시전하면 사라짐)과 하나에 50 GP 이상인 상아 조각 넷\", m = { cast = \"10 minutes\", kind = \"utility\" } },\r\n[\"Lesser Restoration\"] = { level = 2, classes = {\"Bard\", \"Cleric\", \"Druid\", \"Paladin\", \"Ranger\"}, school = \"방호학파\", time = \"추가 행동\", range = \"접촉\", dur = \"즉시\", cmp = \"VS\", ko = \"추가 행동으로 생물 하나를 만져 장님·귀머거리·마비·중독 상태 가운데 하나를 끝냅니다.\", m = { cast = \"bonus\", kind = \"buff\", targets = 1 } },\r\n[\"Levitate\"] = { level = 2, classes = {\"Sorcerer\", \"Wizard\"}, save = \"Constitution\", concentration = true, school = \"변환학파\", time = \"행동\", range = \"60피트\", dur = \"집중, 최대 10분\", cmp = \"VS\", mins = 10, ko = \"60피트 안에 보이는 생물이나, 어디에도 고정되지 않은 물건 하나(500파운드까지)를 20피트까지 곧게 띄워 주문이 이어지는 동안 그대로 머물게 합니다. 원치 않는 생물은 건강 내성 굴림을 해서 성공하면 영향받지 않습니다. 떠 있는 대상은 손이 닿는 벽이나 천장을 밀고 당겨서만, 기어오르듯 움직일 수 있습니다. 내 턴에 대상의 높이를 위아래로 20피트까지 바꿀 수 있습니다(내가 대상이면 이동하면서, 아니면 마법 행동으로). 주문이 끝날 때 아직 떠 있으면 천천히 땅으로 내려옵니다. 집중, 최대 10분.\", m = { cast = \"action\", kind = \"utility\", concentration = true } },\r\n[\"Light\"] = { level = 0, classes = {\"Bard\", \"Cleric\", \"Sorcerer\", \"Wizard\"}, school = \"방출학파\", time = \"행동\", range = \"접촉\", dur = \"1시간\", cmp = \"V\", ko = \"남이 들고 있거나 입고 있지 않은 대형 이하 물건 하나를 만지면, 1시간 동안 그 물건이 반경 20피트를 밝게, 그 바깥 20피트를 희미하게 비춥니다. 빛의 색은 원하는 대로 고를 수 있고, 불투명한 것으로 덮으면 빛이 가려집니다. 다시 시전하면 앞의 주문은 끝납니다.\", m = { cast = \"action\", kind = \"utility\" } },\r\n[\"Lightning Bolt\"] = { level = 3, classes = {\"Sorcerer\", \"Wizard\"}, save = \"Dexterity\", half_on_save = true, damage = \"8d6\", damage_type = \"Lightning\", school = \"방출학파\", time = \"행동\", range = \"자신\", dur = \"즉시\", cmp = \"VS\", ko = \"내게서 고른 방향으로 길이 100피트, 폭 5피트의 일직선 번개가 뻗어 나갑니다. 그 선 위의 생물은 모두 민첩 내성 굴림을 해서, 실패하면 번개 피해 8d6, 성공하면 그 절반을 받습니다. 높은 레벨로 시전하면 한 단계마다 피해가 1d6씩 늘어납니다.\", m = { cast = \"action\", kind = \"save\", save = \"Dexterity\", on_save = \"half\", damage = \"8d6\", type = \"Lightning\", upcast = { dice = \"1d6\" }, area = true } },\r\n[\"Locate Animals or Plants\"] = { level = 2, classes = {\"Bard\", \"Druid\", \"Ranger\"}, ritual = true, school = \"예지학파\", time = \"행동 · 의식 가능\", range = \"자신\", dur = \"즉시\", cmp = \"VS\", ko = \"특정 종류의 야수나 식물 생물, 마법이 아닌 식물을 말하거나 묘사하면, 5마일 안에 그런 것이 있을 때 가장 가까운 것의 방향과 거리를 압니다. 의식으로 시전할 수 있습니다.\", m = { cast = \"action\", kind = \"utility\" } },\r\n[\"Locate Creature\"] = { level = 4, classes = {\"Bard\", \"Cleric\", \"Druid\", \"Paladin\", \"Ranger\", \"Wizard\"}, concentration = true, school = \"예지학파\", time = \"행동\", range = \"자신\", dur = \"집중, 최대 1시간\", cmp = \"VS\", mins = 60, ko = \"내가 잘 아는 생물을 말하거나 묘사하면, 그 생물이 1,000피트 안에 있을 때 그쪽 방향을 느끼고, 움직이고 있으면 움직이는 방향도 압니다. 내가 아는 특정 생물을 찾거나, 인간·유니콘 같은 종류 가운데 가장 가까운 것을 찾을 수 있는데, 그런 생물을 30피트 안에서 가까이 본 적이 있어야 합니다. 석화나 변신 주문처럼 다른 모습이 된 생물은 찾지 못하고, 둘 사이를 조금이라도 납이 가로막아도 찾지 못합니다. 집중, 최대 1시간.\", m = { cast = \"action\", kind = \"utility\", concentration = true } },\r\n[\"Locate Object\"] = { level = 2, classes = {\"Bard\", \"Cleric\", \"Druid\", \"Paladin\", \"Ranger\", \"Wizard\"}, concentration = true, school = \"예지학파\", time = \"행동\", range = \"자신\", dur = \"집중, 최대 10분\", cmp = \"VS\", mins = 10, ko = \"내가 잘 아는 물건을 말하거나 묘사하면, 그 물건이 1,000피트 안에 있을 때 그쪽 방향을 느끼고, 움직이고 있으면 움직이는 방향도 압니다. 30피트 안에서 가까이 본 적 있는 특정 물건을 찾거나, 옷·장신구·가구·도구·무기처럼 어떤 종류 가운데 가장 가까운 것을 찾을 수 있습니다. 둘 사이를 조금이라도 납이 가로막으면 찾지 못합니다. 집중, 최대 10분.\", m = { cast = \"action\", kind = \"utility\", concentration = true } },\r\n[\"Longstrider\"] = { level = 1, classes = {\"Bard\", \"Druid\", \"Ranger\", \"Wizard\"}, school = \"변환학파\", time = \"행동\", range = \"접촉\", dur = \"1시간\", cmp = \"VS\", ko = \"내가 만진 생물의 속도가 1시간 동안 10피트 늘어납니다. 높은 레벨로 시전하면 한 단계마다 대상이 하나씩 늘어납니다.\", bmins = 60, m = { speed_add = 10, cast = \"action\", kind = \"buff\", upcast = { targets = 1 }, targets = 1 } },\r\n[\"Mage Armor\"] = { level = 1, classes = {\"Sorcerer\", \"Wizard\"}, school = \"방호학파\", time = \"행동\", range = \"접촉\", dur = \"8시간\", cmp = \"VS\", ko = \"갑옷을 입지 않은 동의한 생물 하나를 만지면, 8시간 동안 그 생물의 기본 방어도가 13 + 민첩 수정치가 됩니다. 그 생물이 갑옷을 입으면 주문이 끝납니다.\", bmins = 480, m = { cast = \"action\", kind = \"buff\", ac_base = 13, targets = 1 } },\r\n[\"Mage Hand\"] = { level = 0, classes = {\"Bard\", \"Sorcerer\", \"Warlock\", \"Wizard\"}, school = \"조형학파\", time = \"행동\", range = \"30피트\", dur = \"1분\", cmp = \"VS\", ko = \"30피트 안의 고른 곳에 떠다니는 유령 손을 1분 동안 만듭니다. 시전할 때 손으로 물건을 다루거나, 잠기지 않은 문이나 상자를 열거나, 열린 상자에 물건을 넣고 빼거나, 병에 든 것을 쏟을 수 있습니다. 이후 내 턴에 마법 행동으로 손을 다시 이렇게 부릴 수 있고, 그때 손을 30피트까지 옮길 수 있습니다. 손은 공격하거나 마법 물건을 쓰지 못하고, 10파운드보다 무거운 것은 나르지 못합니다. 손이 나에게서 30피트 넘게 떨어지거나 이 주문을 다시 시전하면 손은 사라집니다.\", m = { cast = \"action\", kind = \"utility\" } },\r\n[\"Magic Circle\"] = { level = 3, classes = {\"Cleric\", \"Paladin\", \"Warlock\", \"Wizard\"}, save = \"Charisma\", school = \"방호학파\", time = \"1분\", range = \"10피트\", dur = \"1시간\", cmp = \"VS\", ko = \"10피트 안에 보이는 땅 위의 한 지점을 중심으로 반경 10피트, 높이 20피트의 마법 원기둥을 만들고, 원기둥이 바닥이나 다른 면과 만나는 곳마다 빛나는 룬이 나타납니다. 천상체·원소·요정·악마·언데드 가운데 하나 이상을 고르면, 그 종류의 생물은 마법이 아닌 방법으로는 원기둥 안에 스스로 들어오지 못하고(순간이동이나 다른 세계를 거치는 이동으로 들어오려면 먼저 매력 내성 굴림에 성공해야 함), 원기둥 안의 대상을 공격할 때 불리점을 받으며, 안의 대상에게 빙의하거나 대상을 매혹·공포 상태로 만들지 못합니다. 시전할 때 거꾸로 걸면, 그 종류의 생물이 원기둥 밖으로 나오지 못하게 가두고 밖에 있는 대상을 지킵니다. 주문은 1시간 동안 이어지고, 시전에 1분이 걸립니다. 높은 레벨로 시전하면 한 단계마다 지속 시간이 1시간씩 늘어납니다.\", cost = \"salt and powdered silver worth 100+ GP, consumed\", cost_ko = \"100 GP 이상의 소금과 은가루 (시전하면 사라짐)\", m = { cast = \"1 minute\", kind = \"utility\" } },\r\n[\"Magic Jar\"] = { level = 6, classes = {\"Wizard\"}, save = \"Charisma\", school = \"사령학파\", time = \"1분\", range = \"자신\", dur = \"해제될 때까지\", cmp = \"VS\", ko = \"내 영혼이 몸을 빠져나와 재료로 쓴 그릇(보석·수정·성물함)에 들어가고, 몸은 넋이 나간 채 굳습니다. 영혼이 그릇에 있는 동안 그 자리에 있는 것처럼 주변을 알 수 있지만, 움직이거나 반응행동을 할 수 없습니다. 할 수 있는 행동은 영혼을 100피트까지 내보내, 내 몸으로 돌아가거나(주문이 끝남) 인간형의 몸을 빼앗으려 하는 것뿐입니다. 100피트 안에 보이는 인간형을 노리면 그 생물이 매력 내성 굴림을 하고, 실패하면 내 영혼이 그 몸에 들어가며 그 생물의 영혼은 그릇에 갇힙니다(악과 선으로부터의 보호나 마법의 원이 지키는 생물은 빼앗을 수 없음). 성공하면 24시간 동안 그 생물을 다시 노릴 수 없습니다. 빼앗은 몸은 내가 움직이며, 생명력·근력·민첩·건강·속도·감각은 그 몸의 것을, 나머지는 내 것을 씁니다. 그릇이 100피트 안에 있으면 마법 행동으로 그릇에 돌아갈 수 있고, 그러면 원래 영혼은 제 몸으로 돌아갑니다. 내가 들어가 있는 동안 그 몸이 죽으면 그 생물은 죽고, 나는 내 주문 내성 난이도로 매력 내성 굴림을 해서 성공하면 100피트 안의 그릇으로 돌아가고 실패하면 죽습니다. 그릇이 부서지거나 주문이 끝나면 내 영혼은 내 몸으로 돌아가는데, 몸이 100피트 넘게 떨어져 있거나 죽어 있으면 나는 죽습니다. 주문이 끝나면 그릇은 부서집니다. 시전에 1분이 걸립니다.\", cost = \"a gem, crystal, or reliquary worth 500+ GP\", cost_ko = \"500 GP 이상의 보석·수정·성물함 (영혼이 들어갈 그릇)\", m = { cast = \"1 minute\", kind = \"save\", save = \"Charisma\", on_save = \"none\", lrfx = {}, fail = \"your soul waits in a container and can possess a Humanoid within 100 ft that fails the save\" } },\r\n[\"Magic Missile\"] = { level = 1, classes = {\"Sorcerer\", \"Wizard\"}, damage = \"1d4+1\", damage_type = \"Force\", school = \"방출학파\", time = \"행동\", range = \"120피트\", dur = \"즉시\", cmp = \"VS\", ko = \"빛나는 역장 화살 셋을 만들어, 120피트 안에 보이는 생물에게 쏩니다. 화살은 모두 동시에 반드시 맞고, 한 발마다 역장 피해 1d4 + 1을 줍니다. 셋을 한 대상에게 모두 쏘거나 여러 대상에게 나눠 쏠 수 있습니다. 높은 레벨로 시전하면 한 단계마다 화살이 하나씩 늘어납니다.\", m = { cast = \"action\", kind = \"auto\", damage = \"1d4+1\", type = \"Force\", darts = 3, upcast = { darts = 1 } } },\r\n[\"Magic Mouth\"] = { level = 2, classes = {\"Bard\", \"Wizard\"}, ritual = true, school = \"환영학파\", time = \"1분 · 의식 가능\", range = \"30피트\", dur = \"해제될 때까지\", cmp = \"VS\", ko = \"30피트 안에 보이고, 남이 들고 있거나 입고 있지 않은 물건 하나에 스물다섯 단어까지의 말(10분에 걸쳐 말해도 됨)을 심고, 그 말이 나올 조건을 정합니다. 조건은 물건 30피트 안에서 보이거나 들리는 일이어야 합니다(예: 누가 30피트 안으로 다가오면, 은종이 울리면). 조건이 되면 물건에 마법의 입이 생겨 내 목소리와 같은 크기로 말하고, 석상처럼 입 모양이 있는 물건이면 그 입에서 말이 나옵니다. 한 번 말하고 끝낼지, 조건이 될 때마다 되풀이할지 시전할 때 정합니다. 시전에 1분이 걸리고, 의식으로 시전할 수 있습니다.\", cost = \"jade dust worth 10+ GP, consumed\", cost_ko = \"10 GP 이상의 비취 가루 (시전하면 사라짐)\", m = { cast = \"1 minute\", kind = \"utility\" } },\r\n[\"Magic Weapon\"] = { level = 2, classes = {\"Paladin\", \"Ranger\", \"Sorcerer\", \"Wizard\"}, school = \"변환학파\", time = \"추가 행동\", range = \"접촉\", dur = \"1시간\", cmp = \"VS\", ko = \"추가 행동으로 마법이 아닌 무기 하나를 만지면, 1시간 동안 그 무기가 명중 굴림과 피해 굴림에 +1이 붙는 마법 무기가 됩니다. 다시 시전하면 앞의 주문은 끝납니다. 높은 레벨로 시전하면 보너스가 커집니다(3~5레벨은 +2, 6레벨 이상은 +3).\", bmins = 60, m = { cast = \"bonus\", kind = \"buff\", wplus = true, targets = 1 } },\r\n[\"Magnificent Mansion\"] = { level = 7, classes = {\"Bard\", \"Wizard\"}, school = \"조형학파\", time = \"1분\", range = \"300피트\", dur = \"24시간\", cmp = \"VS\", ko = \"300피트 안에 반짝이는 문(너비 5피트, 높이 10피트)을 만들어 24시간 동안 두고, 그 너머로 다른 차원의 저택이 이어집니다. 문이 열려 있는 동안 나와 시전할 때 정한 생물만 들어갈 수 있고, 나는 문 30피트 안에서 행동 없이 문을 여닫을 수 있습니다(닫힌 문은 알아챌 수 없음). 안은 깨끗하고 상쾌하며 따뜻하고, 이어진 10피트 정육면체 50개까지 원하는 구조와 꾸밈으로 만들 수 있으며, 100명이 아홉 코스 잔치를 할 만큼 음식이 있습니다. 거의 투명한 하인 100명이 시중을 드는데, 다치지 않고 내 명령을 따르며 사람이 할 만한 일은 하지만, 공격하거나 남을 해치는 일은 하지 못하고 저택 밖으로 나가지 못합니다. 저택에서 만든 가구와 물건은 밖으로 가지고 나가면 연기로 사라지고, 주문이 끝나면 안에 남은 생물과 물건은 입구에서 가장 가까운 빈 곳으로 밀려납니다. 시전에 1분이 걸립니다.\", cost = \"a miniature door worth 15+ GP\", cost_ko = \"15 GP 이상의 작은 문 모형\", m = { cast = \"1 minute\", kind = \"utility\" } },\r\n[\"Major Image\"] = { level = 3, classes = {\"Bard\", \"Sorcerer\", \"Warlock\", \"Wizard\"}, concentration = true, school = \"환영학파\", time = \"행동\", range = \"120피트\", dur = \"집중, 최대 10분\", cmp = \"VS\", mins = 10, ko = \"120피트 안에 보이는 곳에, 20피트 정육면체 이하 크기의 물건이나 생물, 또는 다른 눈에 보이는 현상의 환영을 만듭니다. 환영은 어울리는 소리·냄새·온도까지 갖춰 진짜 같지만, 피해를 주거나 상태를 걸지는 못합니다. 내가 사거리 안에 있으면 마법 행동으로 환영을 사거리 안의 다른 곳으로 옮길 수 있고, 걷는 것처럼 자연스럽게 움직이게 하거나, 때마다 다른 소리를 내거나 대화하는 것처럼 꾸밀 수도 있습니다. 만지면 몸이 통과해 환영임이 드러나고, 탐구 행동으로 살펴 지능(조사) 판정에서 내 주문 내성 난이도 이상이 나와도 알아챕니다. 환영임을 알아챈 생물에게는 환영이 비쳐 보이고, 소리나 냄새도 희미해집니다. 집중, 최대 10분. 높은 레벨로 시전하면(4레벨 이상) 집중 없이 해제될 때까지 이어집니다.\", m = { cast = \"action\", kind = \"utility\", concentration = true } },\r\n[\"Mass Cure Wounds\"] = { level = 5, classes = {\"Bard\", \"Cleric\", \"Druid\"}, heal = \"5d8\", school = \"방호학파\", time = \"행동\", range = \"60피트\", dur = \"즉시\", cmp = \"VS\", ko = \"60피트 안에 보이는 한 지점에서 치유의 물결이 퍼져 나갑니다. 그 지점을 중심으로 반경 30피트 구체 안의 생물을 여섯까지 골라, 각각 생명력을 5d8 + 주문시전 능력치 수정치만큼 되찾게 합니다. 높은 레벨로 시전하면 한 단계마다 회복량이 1d8씩 늘어납니다.\", m = { cast = \"action\", kind = \"heal\", heal = \"5d8+MOD\", upcast = { dice = \"1d8\" }, htargets = 6 } },\r\n[\"Mass Heal\"] = { level = 9, classes = {\"Cleric\"}, school = \"방호학파\", time = \"행동\", range = \"60피트\", dur = \"즉시\", cmp = \"VS\", ko = \"나에게서 치유의 기운이 흘러넘칩니다. 60피트 안에 보이는 생물들을 원하는 만큼 골라, 모두 합쳐 700까지의 생명력을 원하는 대로 나눠 되찾게 합니다. 이 주문으로 회복한 생물은 장님·귀머거리·중독 상태도 풀립니다.\", m = { cast = \"action\", kind = \"heal\", heal_share = 700 } },\r\n[\"Mass Healing Word\"] = { level = 3, classes = {\"Bard\", \"Cleric\"}, heal = \"2d4\", school = \"방호학파\", time = \"추가 행동\", range = \"60피트\", dur = \"즉시\", cmp = \"V\", ko = \"추가 행동으로 60피트 안에 보이는 생물을 여섯까지 골라, 각자 2d4 + 내 주문시전 능력치 수정치만큼 생명력을 회복하게 합니다. 높은 레벨로 시전하면 한 단계마다 회복량이 1d4씩 늘어납니다.\", m = { cast = \"bonus\", kind = \"heal\", heal = \"2d4+MOD\", upcast = { dice = \"1d4\" }, htargets = 6 } },\r\n[\"Mass Suggestion\"] = { level = 6, classes = {\"Bard\", \"Sorcerer\", \"Wizard\"}, save = \"Wisdom\", school = \"환혹학파\", time = \"행동\", range = \"60피트\", dur = \"24시간\", cmp = \"V\", ko = \"60피트 안에 보이고 내 말을 듣고 알아듣는 생물을 열둘까지 골라, 할 일을 25단어 이내로 제안합니다. 해낼 수 있을 것처럼 들려야 하고, 대상이나 그 동료가 다칠 게 뻔한 일은 안 됩니다(예: '저 길로 마을에 가서 해 질 때까지 수확을 도와라'). 각 대상은 지혜 내성 굴림을 해서, 실패하면 24시간 동안, 또는 나나 내 동료가 그 대상에게 피해를 줄 때까지 매혹 상태가 되어 힘껏 그 제안을 따릅니다. 제안한 일을 더 일찍 마치면 그 대상에게는 주문이 끝납니다. 높은 레벨로 시전하면 더 오래갑니다(7레벨은 10일, 8레벨은 30일, 9레벨은 366일).\", m = { puts = {\"Charmed\"}, cast = \"action\", kind = \"save\", save = \"Wisdom\", on_save = \"none\", upcast = { note = \"level 7: 10 days, level 8: 30 days, level 9: 366 days\" }, lrfx = {\"Charmed\"}, fail = \"Charmed for 24 hours and following a suggested activity (25 words, nothing harmful) until damaged\" } },\r\n[\"Maze\"] = { level = 8, classes = {\"Wizard\"}, concentration = true, school = \"조형학파\", time = \"행동\", range = \"60피트\", dur = \"집중, 최대 10분\", cmp = \"VS\", mins = 10, ko = \"60피트 안에 보이는 생물 하나를, 내성 굴림 없이 미궁 같은 반차원으로 쫓아냅니다. 대상은 주문이 끝나거나 미궁을 빠져나올 때까지 그곳에 갇힙니다. 대상은 탐구 행동으로 난이도 20 지능(조사) 판정을 해서, 성공하면 빠져나오고 주문이 끝납니다. 주문이 끝나면 대상은 떠났던 자리에 다시 나타나고, 그 자리가 막혀 있으면 가장 가까운 빈 곳에 나타납니다. 집중, 최대 10분.\", m = { cast = \"action\", kind = \"utility\", concentration = true } },\r\n[\"Meld into Stone\"] = { level = 3, classes = {\"Cleric\", \"Druid\", \"Ranger\"}, damage = \"6d6\", damage_type = \"Force\", ritual = true, school = \"변환학파\", time = \"행동 · 의식 가능\", range = \"접촉\", dur = \"8시간\", cmp = \"VS\", ko = \"몸이 다 들어갈 만한 돌이나 돌 벽을 만지고, 장비째 그 속으로 녹아들어 8시간 동안 머뭅니다. 밖에서는 마법이 아닌 감각으로 내가 있다는 것을 알아챌 수 없습니다. 돌 속에서는 바깥을 볼 수 없고, 바깥 소리를 듣는 지혜(감지) 판정에 불리점을 받지만, 시간이 흐르는 것은 알고 나에게 주문을 시전할 수 있습니다. 이동 5피트를 써서 들어간 곳으로 나오면 주문이 끝나고, 그 밖에는 움직일 수 없습니다. 돌이 조금 상하는 것으로는 다치지 않지만, 일부가 부서지거나 모양이 바뀌어 내가 들어갈 수 없게 되면 튕겨 나오며 역장 피해 6d6을 받고, 통째로 부서지면 역장 피해 50을 받습니다. 튕겨 나오면 처음 들어간 곳에서 가장 가까운 빈 곳으로 나와 넘어진 상태가 됩니다. 의식으로 시전할 수 있습니다.\", m = { cast = \"action\", kind = \"utility\" } },\r\n[\"Mending\"] = { level = 0, classes = {\"Bard\", \"Cleric\", \"Druid\", \"Sorcerer\", \"Wizard\"}, school = \"변환학파\", time = \"1분\", range = \"접촉\", dur = \"즉시\", cmp = \"VS\", ko = \"내가 만진 물건의 부서지거나 찢어진 곳 하나(어느 쪽으로든 1피트 이내)를 흔적 없이 고칩니다. 끊어진 사슬 고리, 두 동강 난 열쇠, 찢어진 망토, 새는 가죽 술부대 같은 것입니다. 마법 물건도 몸체는 고칠 수 있지만, 잃은 마력은 되살리지 못합니다. 시전에 1분이 걸립니다.\", m = { cast = \"1 minute\", kind = \"utility\" } },\r\n[\"Message\"] = { level = 0, classes = {\"Bard\", \"Druid\", \"Sorcerer\", \"Wizard\"}, school = \"변환학파\", time = \"행동\", range = \"120피트\", dur = \"1라운드\", cmp = \"S\", ko = \"120피트 안의 생물 하나를 가리키며 말을 속삭이면 그 대상만 그 말을 듣고, 대상은 나에게만 들리게 속삭여 답할 수 있습니다. 잘 아는 대상이 벽 같은 것 너머에 있는 줄 알면 그 너머로도 보낼 수 있습니다. 다만 마법적 침묵, 두께 1피트의 돌·금속·나무, 얇은 납판은 뚫지 못합니다.\", m = { cast = \"action\", kind = \"utility\" } },\r\n[\"Meteor Swarm\"] = { level = 9, classes = {\"Sorcerer\", \"Wizard\"}, save = \"Dexterity\", half_on_save = true, damage = \"20d6\", damage_type = \"Fire\", school = \"방출학파\", time = \"행동\", range = \"1마일\", dur = \"즉시\", cmp = \"VS\", ko = \"1마일 안에 보이는 서로 다른 네 지점에 불타는 유성이 떨어집니다. 각 지점을 중심으로 반경 40피트 구체 안의 생물은 민첩 내성 굴림을 해서, 실패하면 화염 피해 20d6과 타격 피해 20d6을, 성공하면 그 절반을 받습니다. 구체 여럿에 걸친 생물도 피해는 한 번만 받습니다. 범위 안에서 아무도 들거나 입지 않은 마법 아닌 물건도 피해를 받고, 타는 것이면 불이 붙습니다.\", m = { cast = \"action\", kind = \"save\", save = \"Dexterity\", on_save = \"half\", damage = \"20d6+20d6\", type = \"Fire and Bludgeoning\", area = true } },\r\n[\"Mind Blank\"] = { level = 8, classes = {\"Bard\", \"Wizard\"}, school = \"방호학파\", time = \"행동\", range = \"접촉\", dur = \"24시간\", cmp = \"VS\", ko = \"동의한 생물 하나를 만지면, 24시간 동안 그 생물은 정신 피해와 매혹 상태에 면역이 됩니다. 감정이나 성향을 느끼거나, 생각을 읽거나, 위치를 마법으로 찾아내는 효과도 그 생물에게는 통하지 않습니다. 소원을 포함한 어떤 주문으로도 그 생물에 대해 알아내거나, 멀리서 지켜보거나, 정신을 조종할 수 없습니다.\", bmins = 1440, m = { cast = \"action\", kind = \"buff\", imm = {\"Psychic\"}, cimm = {\"Charmed\"}, targets = 1 } },\r\n[\"Mind Spike\"] = { level = 2, classes = {\"Sorcerer\", \"Warlock\", \"Wizard\"}, save = \"Wisdom\", half_on_save = true, damage = \"3d8\", damage_type = \"Psychic\", concentration = true, school = \"예지학파\", time = \"행동\", range = \"120피트\", dur = \"집중, 최대 1시간\", cmp = \"S\", mins = 60, ko = \"120피트 안에 보이는 생물 하나의 머릿속에 정신 에너지 가시를 박습니다. 대상은 지혜 내성 굴림을 해서, 실패하면 정신 피해 3d8, 성공하면 그 절반을 받습니다. 실패한 대상의 위치는 주문이 끝날 때까지, 둘이 같은 세계에 있는 한 늘 내가 압니다. 그동안 대상은 나에게서 숨을 수 없고, 투명 상태여도 나에게는 그 이점을 얻지 못합니다. 집중, 최대 1시간. 높은 레벨로 시전하면 한 단계마다 피해가 1d8씩 늘어납니다.\", m = { cast = \"action\", kind = \"save\", save = \"Wisdom\", on_save = \"half\", damage = \"3d8\", type = \"Psychic\", concentration = true, upcast = { dice = \"1d8\" } } },\r\n[\"Minor Illusion\"] = { level = 0, classes = {\"Bard\", \"Sorcerer\", \"Warlock\", \"Wizard\"}, school = \"환영학파\", time = \"행동\", range = \"30피트\", dur = \"1분\", cmp = \"S\", ko = \"30피트 안에 소리 하나나 물건 하나의 환영을 1분 동안 만듭니다. 소리는 속삭임부터 비명까지 크기를 고를 수 있고, 내 목소리나 남의 목소리, 사자의 포효, 북소리 같은 것을 내내 내거나 때때로 낼 수 있습니다. 물건은 의자·진흙 발자국·작은 상자처럼 5피트 정육면체에 들어가는 크기까지이고, 소리·빛·냄새가 없으며 만지면 통과해서 환영임이 드러납니다. 누가 탐구 행동으로 살펴 지능(조사) 판정에서 내 주문 내성 난이도 이상이 나와도 환영임을 알아채고, 그 생물에게는 환영이 희미해집니다. 다시 시전하면 앞의 환영은 사라집니다.\", m = { cast = \"action\", kind = \"utility\" } },\r\n[\"Mirage Arcane\"] = { level = 7, classes = {\"Bard\", \"Druid\", \"Wizard\"}, school = \"환영학파\", time = \"10분\", range = \"시야 안\", dur = \"10일\", cmp = \"VS\", ko = \"보이는 곳의 1제곱마일까지의 지형을, 10일 동안 다른 지형처럼 보이고 들리고 냄새 나며 만져지게까지 합니다. 들판이나 길을 늪·언덕·갈라진 틈처럼, 연못을 풀밭처럼, 낭떠러지를 완만한 비탈처럼 꾸미고, 건물의 겉모습을 바꾸거나 없던 건물을 더할 수도 있습니다. 생물은 감추거나 바꾸거나 더하지 못합니다. 손으로 만져지는 환영이라 트인 땅을 어려운 지형으로 만들거나 그 반대로 할 수 있고, 환영의 조각(돌이나 나뭇가지 같은 것)을 범위 밖으로 가져가면 곧바로 사라집니다. 진시야가 있는 생물은 본래 지형을 알아보지만, 환영은 여전히 만져지고 부딪칩니다. 시전에 10분이 걸립니다.\", m = { cast = \"10 minutes\", kind = \"utility\" } },\r\n[\"Mirror Image\"] = { level = 2, classes = {\"Bard\", \"Sorcerer\", \"Warlock\", \"Wizard\"}, school = \"환영학파\", time = \"행동\", range = \"자신\", dur = \"1분\", cmp = \"VS\", ko = \"내 자리에 나를 닮은 환영 분신 셋이 1분 동안 나타나, 나와 함께 움직이고 내 행동을 흉내 내며 자리를 바꿔 어느 쪽이 진짜인지 알 수 없게 합니다. 누가 명중 굴림으로 나를 맞힐 때마다 남은 분신 수만큼 d6을 굴리고, 하나라도 3 이상이 나오면 나 대신 분신 하나가 맞아 사라집니다. 분신은 그 밖의 피해나 효과는 받지 않고, 셋이 모두 사라지면 주문이 끝납니다. 장님 상태이거나 맹안시야·진시야가 있는 생물에게는 통하지 않습니다.\", bmins = 1, m = { cast = \"action\", kind = \"buff\", lasting = true, decoys = 3, say = \"three illusory duplicates; when an attack roll hits the caster, roll a d6 for each duplicate left: on any 3 or higher a duplicate is hit and destroyed instead, so write no ATTACK tag for that attack (Lua would count it on the caster)\" } },\r\n[\"Mislead\"] = { level = 5, classes = {\"Bard\", \"Warlock\", \"Wizard\"}, concentration = true, school = \"환영학파\", time = \"행동\", range = \"자신\", dur = \"집중, 최대 1시간\", cmp = \"S\", mins = 60, ko = \"내가 투명 상태가 되는 동시에, 내가 서 있던 자리에 내 환영 분신이 나타납니다. 분신은 주문이 이어지는 동안 남지만, 투명 상태는 내가 명중 굴림을 하거나 피해를 주거나 주문을 시전하면 그 직후 풀립니다. 마법 행동으로 분신을 내 속도의 두 배까지 옮기고, 원하는 대로 몸짓하고 말하고 행동하게 할 수 있습니다. 분신은 만질 수 없고 다치지도 않으며, 나는 분신이 있는 곳에 있는 것처럼 분신의 눈과 귀로 보고 들을 수 있습니다. 집중, 최대 1시간.\", m = { cast = \"action\", kind = \"buff\", concentration = true } },\r\n[\"Misty Step\"] = { level = 2, classes = {\"Sorcerer\", \"Warlock\", \"Wizard\"}, school = \"조형학파\", time = \"추가 행동\", range = \"자신\", dur = \"즉시\", cmp = \"V\", ko = \"추가 행동으로 은빛 안개에 잠깐 싸였다가, 보이는 빈 곳으로 30피트까지 순간이동합니다.\", m = { cast = \"bonus\", kind = \"utility\" } },\r\n[\"Modify Memory\"] = { level = 5, classes = {\"Bard\", \"Wizard\"}, save = \"Wisdom\", concentration = true, school = \"환혹학파\", time = \"행동\", range = \"30피트\", dur = \"집중, 최대 1분\", cmp = \"VS\", mins = 1, ko = \"30피트 안에 보이는 생물 하나의 기억을 고쳐 쓰려 합니다. 대상은 지혜 내성 굴림을 하고(나와 싸우는 중이면 이점), 실패하면 주문이 이어지는 동안 매혹 상태가 됩니다. 그동안 대상은 행동불능 상태이고 주변을 알아채지 못하지만, 내 말은 들을 수 있습니다. 대상이 피해를 받거나 다른 주문의 목표가 되면 주문이 끝나고 기억은 바뀌지 않습니다. 매혹이 이어지는 동안, 대상이 지난 24시간 안에 겪은 10분 이하의 일 하나에 대한 기억을 영영 지우거나, 또렷이 떠올리게 하거나, 세부를 바꾸거나, 다른 일의 기억을 만들어 넣을 수 있습니다. 대상이 알아듣는 말로 기억이 어떻게 바뀌는지 설명해야 하고, 설명을 마치기 전에 주문이 끝나면 기억은 바뀌지 않습니다. 고친 기억이 대상의 성향이나 믿음과 어긋나면 행동이 꼭 바뀌지는 않고, 말이 안 되는 기억은 나쁜 꿈으로 여깁니다. 저주 해제나 상급 회복을 받으면 진짜 기억이 돌아옵니다. 집중, 최대 1분. 높은 레벨로 시전하면 더 오래된 일도 고칠 수 있습니다(6레벨은 7일, 7레벨은 30일, 8레벨은 365일, 9레벨은 언제든).\", m = { cast = \"action\", kind = \"save\", save = \"Wisdom\", on_save = \"none\", concentration = true, lrfx = {\"Charmed\", \"Incapacitated\"}, fail = \"Charmed and Incapacitated while you rewrite a memory from the last 24 hours (10 minutes long at most)\" } },\r\n[\"Moonbeam\"] = { level = 2, classes = {\"Druid\"}, save = \"Constitution\", half_on_save = true, damage = \"2d10\", damage_type = \"Radiant\", concentration = true, school = \"방출학파\", time = \"행동\", range = \"120피트\", dur = \"집중, 최대 1분\", cmp = \"VS\", mins = 1, ko = \"120피트 안의 한 지점을 중심으로 반경 5피트·높이 40피트 원기둥 모양의 은빛 달빛이 내려, 주문이 이어지는 동안 그 안을 희미하게 비춥니다. 원기둥이 나타날 때 그 안의 생물은 건강 내성 굴림을 해서, 실패하면 광휘 피해 2d10을 받고, 변신 주문 등으로 모습을 바꾼 상태면 본모습으로 돌아가 원기둥을 벗어날 때까지 다시 모습을 바꾸지 못합니다. 성공하면 피해만 절반 받습니다. 원기둥이 생물이 있는 곳으로 옮겨 가거나, 생물이 원기둥에 들어오거나 그 안에서 턴을 끝낼 때도 같은 내성 굴림을 합니다(턴마다 한 번). 이후 내 턴에 마법 행동으로 원기둥을 60피트까지 옮길 수 있습니다. 집중, 최대 1분. 높은 레벨로 시전하면 한 단계마다 피해가 1d10씩 늘어납니다.\", m = { cast = \"action\", kind = \"save\", save = \"Constitution\", on_save = \"half\", damage = \"2d10\", type = \"Radiant\", concentration = true, upcast = { dice = \"1d10\" }, area = true } },\r\n[\"Move Earth\"] = { level = 6, classes = {\"Druid\", \"Sorcerer\", \"Wizard\"}, concentration = true, school = \"변환학파\", time = \"행동\", range = \"120피트\", dur = \"집중, 최대 2시간\", cmp = \"VS\", mins = 120, ko = \"120피트 안에서 한 변 40피트 이하의 땅을 골라, 주문이 이어지는 동안 그 안의 흙·모래·진흙을 마음대로 빚습니다. 땅을 높이거나 낮추고, 도랑을 파거나 메우고, 둑을 쌓거나 허물고, 기둥을 세울 수 있으며, 높이나 깊이는 구역의 가장 긴 변의 절반까지 바꿀 수 있습니다(40피트 정사각형이면 20피트 높이의 기둥이나 20피트 깊이의 도랑). 바뀌는 데 10분이 걸려 천천히 움직이므로, 그 안의 생물이 땅에 갇히거나 다치는 일은 보통 없습니다. 집중한 채 10분이 지날 때마다 새 구역을 고를 수 있습니다. 자연석이나 돌로 지은 건물은 바꾸지 못하고, 바위와 건물은 바뀐 땅에 맞춰 자리를 옮기며, 땅이 바뀌어 건물이 불안해지면 무너질 수 있습니다. 식물은 흙과 함께 옮겨집니다. 집중, 최대 2시간.\", m = { cast = \"action\", kind = \"utility\", concentration = true } },\r\n[\"Nondetection\"] = { level = 3, classes = {\"Bard\", \"Ranger\", \"Wizard\"}, school = \"방호학파\", time = \"행동\", range = \"접촉\", dur = \"8시간\", cmp = \"VS\", ko = \"내가 만진 대상을 8시간 동안 예지계 주문으로부터 숨깁니다. 대상은 동의한 생물이거나, 어느 쪽으로도 10피트를 넘지 않는 장소나 물건입니다. 대상은 예지계 주문의 목표가 될 수 없고, 마법으로 멀리서 엿보는 감지점에도 보이지 않습니다.\", cost = \"a pinch of diamond dust worth 25+ GP, consumed\", cost_ko = \"25 GP 이상의 다이아몬드 가루 한 줌 (시전하면 사라짐)\", m = { cast = \"action\", kind = \"utility\" } },\r\n[\"Passwall\"] = { level = 5, classes = {\"Wizard\"}, school = \"변환학파\", time = \"행동\", range = \"30피트\", dur = \"1시간\", cmp = \"VS\", ko = \"30피트 안에 보이는 나무·회반죽·돌 표면(벽·천장·바닥 같은 곳)에 1시간 동안 통로를 냅니다. 크기는 너비 5피트, 높이 8피트, 깊이 20피트까지 내가 정합니다. 통로 때문에 둘레 구조물이 불안해지지는 않고, 통로가 사라질 때 안에 남아 있던 생물과 물건은 시전한 표면에서 가장 가까운 빈 곳으로 안전하게 밀려납니다.\", m = { cast = \"action\", kind = \"utility\" } },\r\n[\"Pass without Trace\"] = { level = 2, classes = {\"Druid\", \"Ranger\"}, concentration = true, school = \"방호학파\", time = \"행동\", range = \"자신\", dur = \"집중, 최대 1시간\", cmp = \"VS\", mins = 60, ko = \"나를 중심으로 30피트에 몸을 감추는 기운을 퍼뜨립니다. 그 안에 있는 동안 나와 내가 고른 생물은 민첩(은신) 판정에 +10을 받고 흔적을 남기지 않습니다. 집중, 최대 1시간.\", m = { cast = \"action\", kind = \"buff\", concentration = true, party_skill = { Stealth = 10 } } },\r\n[\"Phantasmal Force\"] = { level = 2, classes = {\"Bard\", \"Sorcerer\", \"Wizard\"}, save = \"Intelligence\", damage = \"2d8\", damage_type = \"Psychic\", concentration = true, school = \"환영학파\", time = \"행동\", range = \"60피트\", dur = \"집중, 최대 1분\", cmp = \"VS\", mins = 1, ko = \"60피트 안에 보이는 생물 하나의 머릿속에 환영을 지어내려 합니다. 대상은 지능 내성 굴림을 하고, 실패하면 주문이 이어지는 동안 그 생물에게만 보이고 들리고 느껴지는, 10피트 정육면체 이하의 환영(물건·생물·다른 현상)이 생깁니다. 대상은 환영을 진짜로 여기고, 앞뒤가 맞지 않는 일도 그럴듯하게 꿰어 맞춥니다(환영 다리를 건너다 떨어지면 다른 까닭으로 떨어졌다고 믿는 식). 위험한 생물이나 위험한 것을 흉내 낸 환영이면, 내 턴마다 대상이 환영 안이나 그 5피트 안에 있을 때 정신 피해 2d8을 줄 수 있고, 대상은 그 피해를 환영에 어울리는 종류로 느낍니다. 대상이 탐구 행동으로 살펴 지능(조사) 판정에서 내 주문 내성 난이도 이상이 나오면 환영임을 알아채고 주문이 끝납니다. 집중, 최대 1분.\", m = { cast = \"action\", kind = \"save\", save = \"Intelligence\", on_save = \"none\", concentration = true, damage = \"2d8\", type = \"Psychic\" } },\r\n[\"Phantasmal Killer\"] = { level = 4, classes = {\"Bard\", \"Wizard\"}, save = \"Wisdom\", half_on_save = true, damage = \"4d10\", damage_type = \"Psychic\", concentration = true, school = \"환영학파\", time = \"행동\", range = \"120피트\", dur = \"집중, 최대 1분\", cmp = \"VS\", mins = 1, ko = \"120피트 안에 보이는 생물 하나의 악몽 속으로 파고들어, 그 생물이 가장 두려워하는 것의 환영을 그 생물에게만 보여 줍니다. 대상은 지혜 내성 굴림을 하고, 실패하면 정신 피해 4d10을 받고 주문이 이어지는 동안 능력 판정과 명중 굴림에 불리점을 받습니다. 성공하면 피해만 절반 받고 주문이 끝납니다. 대상은 자기 턴이 끝날 때마다 다시 지혜 내성 굴림을 해서, 실패하면 정신 피해를 또 받고 성공하면 주문이 끝납니다. 집중, 최대 1분. 높은 레벨로 시전하면 한 단계마다 피해가 1d10씩 늘어납니다.\", m = { cast = \"action\", kind = \"save\", save = \"Wisdom\", on_save = \"half\", damage = \"4d10\", type = \"Psychic\", concentration = true, upcast = { dice = \"1d10\" } } },\r\n[\"Phantom Steed\"] = { level = 3, classes = {\"Wizard\"}, ritual = true, school = \"환영학파\", time = \"1분 · 의식 가능\", range = \"30피트\", dur = \"1시간\", cmp = \"VS\", ko = \"30피트 안의 땅 위 빈 곳에, 반쯤 실체인 대형 말 모양 생물을 1시간 동안 부릅니다. 생김새는 내가 정하고, 안장·재갈·고삐가 달려 있습니다(말에게서 10피트 넘게 가져가면 연기처럼 사라짐). 나나 내가 고른 생물이 탈 수 있고, 승용마 능력치를 쓰되 속도는 100피트이며 한 시간에 13마일을 갑니다. 말이 피해를 조금이라도 받으면 주문이 일찍 끝나고, 주문이 끝날 때 말이 1분에 걸쳐 천천히 흐려지므로 내릴 여유가 있습니다. 시전에 1분이 걸리고, 의식으로 시전할 수 있습니다.\", m = { cast = \"1 minute\", kind = \"utility\" } },\r\n[\"Planar Ally\"] = { level = 6, classes = {\"Cleric\"}, school = \"조형학파\", time = \"10분\", range = \"60피트\", dur = \"즉시\", cmp = \"VS\", ko = \"내가 아는 신이나 마왕처럼 우주적인 힘을 지닌 존재에게 도움을 청하면, 그 존재가 자기를 따르는 천상체·원소·악마 하나를 60피트 안의 빈 곳에 보냅니다. 이름을 알면 특정 생물을 청할 수 있지만, 그래도 다른 생물이 올 수 있습니다(GM이 정함). 온 생물은 꼭 따를 의무가 없으므로, 대가를 주고 일을 맡아 달라고 흥정해야 하며, 그러려면 말이 통해야 합니다. 대가는 몇 분짜리 일이면 분당 100 GP, 몇 시간짜리면 시간당 1,000 GP, 며칠짜리(10일까지)면 하루 10,000 GP쯤입니다. 그 생물의 뜻에 맞는 일이면 절반이나 공짜가 될 수 있고, 위험하지 않은 일은 보통 절반, 아주 위험한 일은 더 비쌉니다. 죽으러 가는 것 같은 일은 좀처럼 맡지 않습니다. 일을 마치거나 약속한 기간이 끝나면, 또는 값이 맞지 않으면 고향 세계로 돌아갑니다. 시전에 10분이 걸립니다.\", m = { cast = \"10 minutes\", kind = \"utility\" } },\r\n[\"Planar Binding\"] = { level = 5, classes = {\"Bard\", \"Cleric\", \"Druid\", \"Warlock\", \"Wizard\"}, save = \"Charisma\", school = \"방호학파\", time = \"1시간\", range = \"60피트\", dur = \"24시간\", cmp = \"VS\", ko = \"천상체·원소·요정·악마 하나를 내 일에 묶어 두려 합니다. 대상은 시전하는 내내 60피트 안에 있어야 합니다(보통 거꾸로 건 마법의 원 가운데에 미리 불러 가둬 둡니다). 시전을 마치면 대상은 매력 내성 굴림을 하고, 실패하면 24시간 동안 묶여 내 명령을 힘껏 따릅니다. 다른 주문으로 불려 오거나 만들어진 존재면, 그 주문도 이 주문만큼 이어집니다. 적대적인 존재는 명령을 비틀어 제 목적을 이루려 합니다. 주문이 끝나기 전에 명령을 다 마치면, 같은 세계에 있을 때는 나에게 와서 알리고, 다른 세계에 있을 때는 묶인 곳으로 돌아가 주문이 끝날 때까지 머뭅니다. 시전에 1시간이 걸립니다. 높은 레벨로 시전하면 더 오래 묶습니다(6레벨은 10일, 7레벨은 30일, 8레벨은 180일, 9레벨은 366일).\", cost = \"a jewel worth 1,000+ GP, consumed\", cost_ko = \"1,000 GP 이상의 보석 (시전하면 사라짐)\", m = { cast = \"1 hour\", kind = \"utility\" } },\r\n[\"Plane Shift\"] = { level = 7, classes = {\"Cleric\", \"Druid\", \"Sorcerer\", \"Warlock\", \"Wizard\"}, school = \"조형학파\", time = \"행동\", range = \"접촉\", dur = \"즉시\", cmp = \"VS\", ko = \"나와, 함께 가려는 생물 여덟까지가 손을 잡고 둥글게 서면 모두 다른 세계로 옮겨 갑니다. 목적지는 '불의 원소계의 어느 도시'나 '구층지옥 두 번째 층의 궁전'처럼 대략 말하면 되고, GM이 정하는 대로 그곳이나 그 근처에 나타납니다. 다른 세계에 있는 순간이동 원의 문양 순서를 알면 그 원으로 갈 수도 있습니다(원이 작아 다 들어가지 못하면 원 둘레의 빈 곳에 나타남).\", cost = \"a forked, metal rod worth 250+ GP and attuned to a plane of existence\", cost_ko = \"250 GP 이상의, 갈 세계에 맞춘 두 갈래 금속 막대\", m = { cast = \"action\", kind = \"utility\" } },\r\n[\"Plant Growth\"] = { level = 3, classes = {\"Bard\", \"Druid\", \"Ranger\"}, school = \"변환학파\", time = \"행동 또는 8시간\", range = \"150피트\", dur = \"즉시\", cmp = \"VS\", ko = \"식물에 생기를 불어넣습니다. 시전 시간에 따라 두 효과 가운데 하나가 됩니다. 행동으로 시전하면 무성하게 자라기가 되어, 150피트 안의 한 지점을 중심으로 반경 100피트 구체 안의 평범한 식물이 빽빽하게 우거지고, 그곳을 지나는 생물은 1피트 갈 때마다 이동 4피트를 씁니다(범위 안에서 영향받지 않을 곳을 얼마든지 뺄 수 있음). 8시간에 걸쳐 시전하면 비옥하게 하기가 되어, 150피트 안의 한 지점을 중심으로 반경 반 마일 안의 식물이 365일 동안 거둘 때마다 두 배의 열매를 맺습니다(식물마다 한 해에 한 번만).\", m = { cast = \"action\", kind = \"utility\" } },\r\n[\"Poison Spray\"] = { level = 0, classes = {\"Druid\", \"Sorcerer\", \"Warlock\", \"Wizard\"}, attack = \"ranged\", damage = \"1d12\", damage_type = \"Poison\", school = \"사령학파\", time = \"행동\", range = \"30피트\", dur = \"즉시\", cmp = \"VS\", ko = \"30피트 안의 생물 하나에게 독 안개를 뿌려 원거리 주문 공격을 합니다. 맞으면 독성 피해 1d12를 줍니다. 5·11·17레벨에 피해 주사위가 하나씩 늘어납니다.\", m = { cast = \"action\", kind = \"attack\", attack = \"ranged\", damage = \"1d12\", type = \"Poison\", cantrip = true } },\r\n[\"Polymorph\"] = { level = 4, classes = {\"Bard\", \"Druid\", \"Sorcerer\", \"Wizard\"}, save = \"Wisdom\", concentration = true, school = \"변환학파\", time = \"행동\", range = \"60피트\", dur = \"집중, 최대 1시간\", cmp = \"VS\", mins = 60, ko = \"60피트 안에 보이는 생물 하나가 지혜 내성 굴림에 실패하면 내가 고른 야수 모습으로 변합니다. 야수의 도전 지수는 대상의 도전 지수 이하여야 하며, 대상에게 도전 지수가 없으면 대상의 레벨 이하여야 합니다. 대상의 능력과 수치는 고른 야수의 것으로 바뀌지만, 성향·성격·생물 유형·생명력은 그대로 유지합니다. 대상은 야수의 생명력만큼 임시 생명력을 얻으며, 이 임시 생명력이 모두 없어지면 주문이 일찍 끝납니다. 주문이 끝나면 남은 임시 생명력도 사라집니다. 대상은 새 몸으로 가능한 행동만 할 수 있고, 말을 하거나 주문을 시전할 수 없습니다. 장비는 새 몸에 흡수되어 사용할 수 없으며 장비의 혜택도 받지 못합니다. 집중, 최대 1시간.\", m = { form_beast = true, cast = \"action\", kind = \"save\", save = \"Wisdom\", on_save = \"none\", concentration = true, lrfx = {}, fail = \"becomes a Beast of CR up to its own (or its level), with Temporary HP equal to the Beast's HP; can't speak or cast\" } },\r\n[\"Power Word Heal\"] = { level = 9, classes = {\"Bard\", \"Cleric\"}, school = \"환혹학파\", time = \"행동\", range = \"60피트\", dur = \"즉시\", ko = \"60피트 안에 보이는 생물 하나를 치유의 기운으로 감쌉니다. 대상은 생명력을 모두 되찾고, 매혹·공포·마비·중독·충격 상태가 풀립니다. 넘어져 있으면 반응행동으로 일어설 수 있습니다.\", m = { cast = \"action\", kind = \"heal\", heal_all = true } },\r\n[\"Power Word Kill\"] = { level = 9, classes = {\"Bard\", \"Sorcerer\", \"Warlock\", \"Wizard\"}, damage = \"12d12\", damage_type = \"Psychic\", school = \"환혹학파\", time = \"행동\", range = \"60피트\", dur = \"즉시\", ko = \"60피트 안에 보이는 생물 하나에게 죽으라고 명합니다. 대상의 생명력이 100 이하면 내성 굴림 없이 죽고, 넘으면 정신 피해 12d12를 받습니다.\", m = { cast = \"action\", kind = \"auto\", damage = \"1d12\", darts = 12, type = \"Psychic\", slay = 100, say = \"no roll or save: a target with 100 HP or fewer dies (Lua applies it); one with more takes 12d12 Psychic: [DAMAGE|Target|12d12|dice|damage]\" } },\r\n[\"Power Word Stun\"] = { level = 8, classes = {\"Bard\", \"Sorcerer\", \"Warlock\", \"Wizard\"}, save = \"Constitution\", school = \"환혹학파\", time = \"행동\", range = \"60피트\", dur = \"즉시\", cmp = \"V\", ko = \"60피트 안에 보이는 생물 하나의 정신을 짓누릅니다. 대상의 생명력이 150 이하면 내성 굴림 없이 충격 상태가 되고, 넘으면 다음 내 턴이 시작될 때까지 속도가 0이 됩니다. 충격 상태가 된 대상은 자기 턴이 끝날 때마다 건강 내성 굴림을 해서, 성공하면 풀려납니다.\", m = { puts = {\"Stunned\"}, puts_hp = 150, end_save = \"Constitution\", cast = \"action\", kind = \"control\", say = \"no save: a creature with 150 HP or fewer is Stunned (a Constitution save at the end of each of its turns ends it); one with more has Speed 0 until the start of the caster's next turn (Lua checks the HP: [COND|Target|+Stunned|-|Power Word Stun] right after the CAST; its save's success: [COND|Target|-Stunned])\" } },\r\n[\"Prayer of Healing\"] = { level = 2, classes = {\"Cleric\", \"Paladin\"}, school = \"방호학파\", time = \"10분\", range = \"30피트\", dur = \"즉시\", cmp = \"V\", ko = \"10분 동안 기도합니다. 시전 내내 30피트 안에 머문 생물을 다섯까지 고르면, 그들은 짧은 휴식 효과를 받고 생명력을 2d8 되찾습니다. 이 주문을 받은 생물은 긴 휴식을 마칠 때까지 다시 받을 수 없습니다. 높은 레벨로 시전하면 한 단계마다 회복량이 1d8씩 늘어납니다.\", m = { cast = \"10 minutes\", kind = \"heal\", heal = \"2d8\", upcast = { dice = \"1d8\" }, htargets = 5 } },\r\n[\"Prestidigitation\"] = { level = 0, classes = {\"Bard\", \"Sorcerer\", \"Warlock\", \"Wizard\"}, school = \"변환학파\", time = \"행동\", range = \"10피트\", dur = \"최대 1시간\", cmp = \"VS\", ko = \"10피트 안에 작은 마술 하나를 부립니다. 불티·바람·희미한 음악·이상한 냄새 같은 해 없는 감각 효과를 내거나, 촛불·횃불·작은 모닥불을 켜거나 끄거나, 1세제곱피트 이하의 물건 하나를 깨끗하게 하거나 더럽히거나, 살아 있지 않은 것 1세제곱피트까지를 1시간 동안 차갑게·따뜻하게 하거나 맛을 내거나, 물건이나 면에 1시간 동안 남는 색이나 작은 표식을 그리거나, 손에 들어가는 장신구나 환영을 다음 내 턴이 끝날 때까지 만듭니다. 바로 끝나지 않는 효과는 셋까지 함께 둘 수 있습니다.\", m = { cast = \"action\", kind = \"utility\" } },\r\n[\"Prismatic Spray\"] = { level = 7, classes = {\"Bard\", \"Sorcerer\", \"Wizard\"}, save = \"Dexterity\", damage = \"12d6\", damage_type = \"Fire\", school = \"방출학파\", time = \"행동\", range = \"자신\", dur = \"즉시\", cmp = \"VS\", ko = \"내게서 60피트 원뿔로 여덟 줄기의 빛이 번쩍입니다. 원뿔 안의 생물은 모두 민첩 내성 굴림을 하고, 대상마다 1d8을 굴려 어느 빛을 맞는지 정합니다. 1 빨강은 화염, 2 주황은 산성, 3 노랑은 번개, 4 초록은 독성, 5 파랑은 냉기로, 실패하면 그 종류의 피해 12d6, 성공하면 그 절반을 받습니다. 6 남색은 실패하면 포박 상태가 되어 자기 턴이 끝날 때마다 건강 내성 굴림을 하고, 성공이 세 번 쌓이면 풀리지만 실패가 세 번 쌓이면 상급 회복 같은 효과로 풀 때까지 석화 상태가 됩니다. 7 보라는 실패하면 장님 상태가 되어 다음 내 턴이 시작될 때 지혜 내성 굴림을 하고, 성공하면 풀리지만 실패하면 장님이 풀리는 대신 다른 세계로 순간이동합니다(GM이 정함). 8은 두 빛을 맞습니다(두 번 굴리고, 8이 나오면 다시 굴림).\", m = { prism = true, end_save = { Restrained = \"Constitution\", Blinded = \"Wisdom\" }, cast = \"action\", kind = \"save\", save = \"Dexterity\", on_save = \"half\", damage = \"12d6\", type = \"1d8 per creature: 1 Fire, 2 Acid, 3 Lightning, 4 Poison, 5 Cold\", lrfx = \"pick\", area = true } },\r\n[\"Prismatic Wall\"] = { level = 9, classes = {\"Bard\", \"Wizard\"}, save = \"Constitution\", damage = \"12d6\", damage_type = \"Fire\", school = \"방호학파\", time = \"행동\", range = \"60피트\", dur = \"10분\", cmp = \"VS\", ko = \"60피트 안의 한 지점을 중심으로, 길이 90피트·높이 30피트·두께 1인치까지의 불투명한 일곱 빛깔 벽이나, 지름 30피트까지의 구를 10분 동안 세웁니다(생물이 있는 자리에 세우면 아무 효과 없이 끝남). 벽은 100피트까지 밝게, 그 바깥 100피트를 희미하게 비춥니다. 나와 시전할 때 정한 생물은 다치지 않고 벽을 지나가거나 곁에 있을 수 있습니다. 벽을 볼 수 있는 다른 생물이 벽 20피트 안에 들어오거나 그곳에서 턴을 시작하면 건강 내성 굴림을 하고, 실패하면 1분 동안 장님 상태가 됩니다. 벽 속으로 손을 뻗거나 벽을 지나가면 일곱 층을 차례로 거치며, 층마다 민첩 내성 굴림을 합니다. 빨강(화염)·주황(산성)·노랑(번개)·초록(독성)·파랑(냉기) 층은 실패하면 그 종류의 피해 12d6, 성공하면 그 절반을 줍니다. 남색 층은 실패하면 포박 상태로 만들고, 그 생물은 자기 턴이 끝날 때마다 건강 내성 굴림을 해서 성공이 세 번 쌓이면 풀리지만 실패가 세 번 쌓이면 상급 회복 같은 효과로 풀 때까지 석화 상태가 됩니다. 보라 층은 실패하면 장님 상태로 만들고, 그 생물은 다음 내 턴이 시작될 때 지혜 내성 굴림을 해서 성공하면 풀리지만 실패하면 장님이 풀리는 대신 다른 세계로 순간이동합니다. 빨강 층은 마법이 아닌 원거리 공격을, 주황 층은 마법 원거리 공격을, 남색 층은 주문을 막아 지나가지 못하게 합니다. 벽(방어도 10)은 빨강부터 보라 순서로 층마다 정해진 방법으로만 하나씩 부술 수 있고(빨강은 냉기 피해 25 이상, 주황은 돌풍 같은 강한 바람, 노랑은 역장 피해 60 이상, 초록은 벽 통과 주문, 파랑은 화염 피해 25 이상, 남색은 태양광 주문의 빛, 보라는 마법 무효화), 반마법 장은 통하지 않습니다.\", m = { cast = \"action\", kind = \"save\", save = \"Dexterity\", on_save = \"half\", damage = \"12d6\", type = \"layer by layer: Fire, Acid, Lightning, Poison, Cold\", area = true } },\r\n[\"Private Sanctum\"] = { level = 4, classes = {\"Wizard\"}, school = \"방호학파\", time = \"10분\", range = \"120피트\", dur = \"24시간\", cmp = \"VS\", ko = \"120피트 안에서 한 변 5피트부터 100피트까지의 정육면체 구역을 24시간 동안 마법으로 지킵니다. 시전할 때 소리가 경계를 넘지 못하게 하기, 경계를 어둡고 뿌옇게 만들어 암시야로도 들여다보지 못하게 하기, 예지계 주문의 감지점이 안에 생기거나 경계를 지나지 못하게 하기, 안의 생물이 예지계 주문의 목표가 되지 않게 하기, 순간이동으로 드나들지 못하게 하기, 안에서 다른 세계로의 이동을 막기 가운데 원하는 것을 모두 고릅니다. 같은 곳에 365일 동안 매일 시전하면 해제될 때까지 이어집니다. 시전에 10분이 걸립니다. 높은 레벨로 시전하면 한 단계마다 정육면체가 100피트씩 커집니다.\", m = { cast = \"10 minutes\", kind = \"utility\" } },\r\n[\"Produce Flame\"] = { level = 0, classes = {\"Druid\"}, attack = \"ranged\", damage = \"1d8\", damage_type = \"Fire\", school = \"조형학파\", time = \"추가 행동\", range = \"자신\", dur = \"10분\", cmp = \"VS\", ko = \"추가 행동으로 손에 일렁이는 불꽃을 10분 동안 피웁니다. 불꽃은 뜨겁지 않고 아무것도 태우지 않으며, 반경 20피트를 밝게, 그 바깥 20피트를 희미하게 비춥니다. 주문이 이어지는 동안 마법 행동으로 60피트 안의 생물이나 물체에 불을 던져 원거리 주문 공격을 할 수 있고, 맞으면 화염 피해 1d8을 줍니다. 다시 시전하면 앞의 주문은 끝납니다. 5·11·17레벨에 피해 주사위가 하나씩 늘어납니다.\", m = { cast = \"bonus\", kind = \"attack\", attack = \"ranged\", damage = \"1d8\", type = \"Fire\", cantrip = true } },\r\n[\"Programmed Illusion\"] = { level = 6, classes = {\"Bard\", \"Wizard\"}, school = \"환영학파\", time = \"행동\", range = \"120피트\", dur = \"해제될 때까지\", cmp = \"VS\", ko = \"120피트 안에 물건이나 생물, 또는 다른 눈에 보이는 현상의 환영을 만들어 두고, 정한 계기가 일어날 때 나타나게 합니다. 그 전까지 환영은 보이지 않습니다. 크기는 30피트 정육면체까지이고, 어떻게 움직이고 어떤 소리를 낼지 시전할 때 정한 공연이 5분까지 이어집니다. 공연이 끝나면 사라졌다가 10분이 지나면 다시 나타날 수 있습니다. 계기는 그 구역 30피트 안에서 보이거나 들리는 일이어야 합니다(예: 누가 덫이 걸린 문을 열려 하면 내 모습이 나타나 경고하기). 만지면 몸이 통과해 환영임이 드러나고, 탐구 행동으로 살펴 지능(조사) 판정에서 내 주문 내성 난이도 이상이 나오면 환영임을 알아채며, 그 생물에게는 환영이 비쳐 보이고 소리도 공허하게 들립니다. 해제될 때까지 이어집니다.\", cost = \"jade dust worth 25+ GP\", cost_ko = \"25 GP 이상의 비취 가루\", m = { cast = \"action\", kind = \"utility\" } },\r\n[\"Project Image\"] = { level = 7, classes = {\"Bard\", \"Wizard\"}, concentration = true, school = \"환영학파\", time = \"행동\", range = \"500마일\", dur = \"집중, 최대 1일\", cmp = \"VS\", mins = 1440, ko = \"500마일 안에서 전에 본 적 있는 곳이면, 사이에 무엇이 가로막든 그곳에 나와 똑같이 생기고 똑같이 들리는 환영을 만듭니다. 환영은 만질 수 없고, 피해를 조금이라도 받으면 사라지며 주문이 끝납니다. 나는 환영이 있는 곳에 있는 것처럼 환영의 눈과 귀로 보고 들을 수 있고, 마법 행동으로 환영을 60피트까지 옮기며 원하는 대로 몸짓하고 말하고 행동하게 할 수 있습니다(내 버릇까지 똑같이 따라 함). 만지면 몸이 통과해 환영임이 드러나고, 탐구 행동으로 살펴 지능(조사) 판정에서 내 주문 내성 난이도 이상이 나오면 환영임을 알아채며, 그 생물에게는 환영이 비쳐 보이고 소리도 공허하게 들립니다. 집중, 최대 1일.\", cost = \"a statuette of yourself worth 5+ GP\", cost_ko = \"5 GP 이상의 내 조각상\", m = { cast = \"action\", kind = \"utility\", concentration = true } },\r\n[\"Protection from Energy\"] = { level = 3, classes = {\"Cleric\", \"Druid\", \"Ranger\", \"Sorcerer\", \"Wizard\"}, concentration = true, school = \"방호학파\", time = \"행동\", range = \"접촉\", dur = \"집중, 최대 1시간\", cmp = \"VS\", mins = 60, ko = \"동의한 생물 하나를 만지면, 주문이 이어지는 동안 그 생물이 산성·냉기·화염·번개·천둥 가운데 내가 고른 피해 종류 하나에 저항을 얻습니다. 집중, 최대 1시간.\", m = { cast = \"action\", kind = \"buff\", concentration = true, resist_pick = {\"Acid\", \"Cold\", \"Fire\", \"Lightning\", \"Thunder\"}, targets = 1 } },\r\n[\"Protection from Evil and Good\"] = { level = 1, classes = {\"Cleric\", \"Druid\", \"Paladin\", \"Warlock\", \"Wizard\"}, concentration = true, school = \"방호학파\", time = \"행동\", range = \"접촉\", dur = \"집중, 최대 10분\", cmp = \"VS\", mins = 10, ko = \"동의한 생물 하나를 만져, 주문이 끝날 때까지 이형체·천상체·원소·요정·악마·언데드로부터 지켜 줍니다. 그런 생물은 대상을 공격할 때 불리점을 받고, 대상에게 빙의하거나 대상을 매혹·공포 상태로 만들지 못합니다. 대상이 이미 그런 생물에게 빙의되었거나 매혹·공포 상태라면, 그 효과에 맞서는 새 내성 굴림에 이점을 받습니다. 집중, 최대 10분.\", cost = \"a flask of Holy Water worth 25+ GP, consumed\", cost_ko = \"25 GP 이상의 성수 한 병 (시전하면 사라짐)\", m = { cast = \"action\", kind = \"buff\", concentration = true, tell = \"Aberrations, Celestials, Elementals, Fey, Fiends and Undead have Disadvantage on attack rolls against them and cannot charm, frighten or possess them\", targets = 1 } },\r\n[\"Protection from Poison\"] = { level = 2, classes = {\"Cleric\", \"Druid\", \"Paladin\", \"Ranger\"}, school = \"방호학파\", time = \"행동\", range = \"접촉\", dur = \"1시간\", cmp = \"VS\", ko = \"생물 하나를 만져 중독 상태를 끝냅니다. 1시간 동안 그 생물은 중독을 피하거나 끝내는 내성 굴림에 이점을 받고, 독성 피해에 저항합니다.\", bmins = 60, m = { cast = \"action\", kind = \"buff\", resist = {\"Poison\"}, targets = 1 } },\r\n[\"Purify Food and Drink\"] = { level = 1, classes = {\"Cleric\", \"Druid\", \"Paladin\"}, ritual = true, school = \"변환학파\", time = \"행동 · 의식 가능\", range = \"10피트\", dur = \"즉시\", cmp = \"VS\", ko = \"10피트 안의 한 지점을 중심으로 반경 5피트 안에 있는, 마법이 아닌 음식과 마실 것에서 독과 부패를 없앱니다. 의식으로 시전할 수 있습니다.\", m = { cast = \"action\", kind = \"utility\" } },\r\n[\"Raise Dead\"] = { level = 5, classes = {\"Bard\", \"Cleric\", \"Paladin\"}, school = \"사령학파\", time = \"1시간\", range = \"접촉\", dur = \"즉시\", cmp = \"VS\", ko = \"죽은 지 10일이 안 된 생물을 만져 되살립니다. 죽을 때 언데드였다면 되살릴 수 없습니다. 생명력 1로 돌아오고, 죽을 때 몸에 있던 독이 사라지며 치명상도 모두 아물지만, 잃은 신체 부위는 돌아오지 않습니다. 머리처럼 살아가는 데 꼭 필요한 부위가 없으면 주문이 실패합니다. 되살아난 생물은 d20 판정에 -4 벌칙을 받고, 벌칙은 긴 휴식을 마칠 때마다 1씩 줄어듭니다. 시전에 1시간이 걸립니다.\", cost = \"a diamond worth 500+ GP, consumed\", cost_ko = \"500 GP 이상의 다이아몬드 (시전하면 사라짐)\", m = { cast = \"1 hour\", kind = \"utility\", raise = { hp = 1, within = 14400, ordeal = 4 } } },\r\n[\"Ray of Enfeeblement\"] = { level = 2, classes = {\"Warlock\", \"Wizard\"}, save = \"Constitution\", concentration = true, school = \"사령학파\", time = \"행동\", range = \"60피트\", dur = \"집중, 최대 1분\", cmp = \"VS\", mins = 1, ko = \"60피트 안의 생물 하나에게 기운을 빼앗는 광선을 쏩니다. 대상은 건강 내성 굴림을 합니다. 성공하면 다음 내 턴이 시작되기 전에 하는 다음 명중 굴림 하나에 불리점을 받습니다. 실패하면 주문이 이어지는 동안 근력으로 하는 d20 판정에 불리점을 받고, 모든 피해 굴림에서 1d8을 뺍니다. 대상은 자기 턴이 끝날 때마다 다시 굴려, 성공하면 주문이 끝납니다. 집중, 최대 1분.\", m = { foe_fx = { dmg = \"1d8\" }, cast = \"action\", kind = \"save\", save = \"Constitution\", on_save = \"none\", concentration = true, lrfx = {}, fail = \"Disadvantage on Strength D20 Tests, -1d8 to its damage rolls; success: Disadvantage on its next attack\" } },\r\n[\"Ray of Frost\"] = { level = 0, classes = {\"Sorcerer\", \"Wizard\"}, attack = \"ranged\", damage = \"1d8\", damage_type = \"Cold\", school = \"방출학파\", time = \"행동\", range = \"60피트\", dur = \"즉시\", cmp = \"VS\", ko = \"60피트 안의 생물 하나에게 푸른빛 냉기 광선을 쏘아 원거리 주문 공격을 합니다. 맞으면 냉기 피해 1d8을 주고, 다음 내 턴이 시작될 때까지 대상의 속도가 10피트 줄어듭니다. 5·11·17레벨에 피해 주사위가 하나씩 늘어납니다.\", m = { cast = \"action\", kind = \"attack\", attack = \"ranged\", damage = \"1d8\", type = \"Cold\", cantrip = true } },\r\n[\"Regenerate\"] = { level = 7, classes = {\"Bard\", \"Cleric\", \"Druid\"}, school = \"변환학파\", time = \"1분\", range = \"접촉\", dur = \"1시간\", cmp = \"VS\", ko = \"내가 만진 생물이 생명력을 4d8 + 15만큼 되찾습니다. 그 뒤 1시간 동안 그 생물은 자기 턴이 시작될 때마다 생명력 1을 되찾고, 잘려 나간 신체 부위는 2분 뒤에 다시 자랍니다. 시전에 1분이 걸립니다.\", m = { cast = \"1 minute\", kind = \"heal\", heal = \"4d8+15\", htargets = 1 } },\r\n[\"Ray of Sickness\"] = { level = 1, classes = {\"Sorcerer\", \"Wizard\"}, attack = \"ranged\", damage = \"2d8\", damage_type = \"Poison\", school = \"사령학파\", time = \"행동\", range = \"60피트\", dur = \"즉시\", cmp = \"VS\", ko = \"60피트 안의 생물 하나에게 초록빛 광선을 쏘아 원거리 주문 공격을 합니다. 맞으면 독성 피해 2d8을 주고, 대상은 다음 내 턴이 끝날 때까지 중독 상태가 됩니다. 높은 레벨로 시전하면 한 단계마다 피해가 1d8씩 늘어납니다.\", m = { cast = \"action\", kind = \"attack\", attack = \"ranged\", damage = \"2d8\", type = \"Poison\", upcast = { dice = \"1d8\" } } },\r\n[\"Reincarnate\"] = { level = 5, classes = {\"Druid\"}, school = \"사령학파\", time = \"1시간\", range = \"접촉\", dur = \"즉시\", cmp = \"VS\", ko = \"죽은 인간형이나 그 몸의 일부를 만집니다. 죽은 지 10일이 안 되었다면 새 몸을 빚고 그 영혼을 불러들입니다. 새 몸의 종족은 1d10으로 정하고(1이면 다시 굴림, 2부터 차례로 드래곤본·드워프·엘프·노움·골리앗·하플링·인간·오크·티플링), GM이 다른 종족을 정할 수도 있습니다. 되살아난 생물은 예전 삶을 기억하고 원래 능력도 그대로 지니지만, 옛 종족의 특성은 잃고 새 종족의 특성을 얻습니다. 시전에 1시간이 걸립니다.\", cost = \"rare oils worth 1,000+ GP, consumed\", cost_ko = \"1,000 GP 이상의 희귀한 기름 (시전하면 사라짐)\", m = { cast = \"1 hour\", kind = \"utility\", raise = { hp = \"max\", within = 14400, species = true } } },\r\n[\"Remove Curse\"] = { level = 3, classes = {\"Cleric\", \"Paladin\", \"Warlock\", \"Wizard\"}, school = \"방호학파\", time = \"행동\", range = \"접촉\", dur = \"즉시\", cmp = \"VS\", ko = \"내가 만진 생물이나 물건에 걸린 저주가 모두 끝납니다. 저주받은 마법 물건이면 저주 자체는 남지만, 주인과의 조율이 끊어져 떼어 내거나 버릴 수 있게 됩니다.\", m = { cast = \"action\", kind = \"utility\" } },\r\n[\"Resilient Sphere\"] = { level = 4, classes = {\"Wizard\"}, save = \"Dexterity\", concentration = true, school = \"방호학파\", time = \"행동\", range = \"30피트\", dur = \"집중, 최대 1분\", cmp = \"VS\", mins = 1, ko = \"30피트 안의 대형 이하 생물이나 물건 하나를 반짝이는 구체로 감쌉니다. 원치 않는 생물은 민첩 내성 굴림을 해서 성공하면 피합니다. 주문이 이어지는 동안 물건·에너지·다른 주문 효과 무엇도 구체를 안팎으로 지나가지 못하지만, 안에서 숨은 쉴 수 있습니다. 구체는 어떤 피해도 받지 않고, 안의 것은 바깥의 공격이나 효과에 다치지 않으며, 안의 생물도 바깥의 무엇도 해칠 수 없습니다. 구체는 무게가 없고, 안의 생물은 행동을 써서 구체 벽을 밀어 속도의 절반까지 굴릴 수 있으며, 다른 생물이 들어 옮길 수도 있습니다. 분해 주문을 맞으면 안의 것은 다치지 않고 구체만 부서집니다. 집중, 최대 1분.\", m = { cast = \"action\", kind = \"save\", save = \"Dexterity\", on_save = \"none\", concentration = true, lrfx = {}, fail = \"enclosed in a sphere that nothing passes in or out of\" } },\r\n[\"Resistance\"] = { level = 0, classes = {\"Cleric\", \"Druid\"}, concentration = true, school = \"방호학파\", time = \"행동\", range = \"접촉\", dur = \"집중, 최대 1분\", mins = 1, ko = \"동의한 생물 하나를 만지고 피해 종류 하나(산성·타격·냉기·화염·번개·사령·관통·독성·광휘·참격·천둥)를 고릅니다. 주문이 끝나기 전에 그 생물이 고른 종류의 피해를 받으면, 받는 피해가 1d4만큼 줄어듭니다. 이 효과는 턴마다 한 번만 받을 수 있습니다. 집중, 최대 1분.\", m = { pick = {\"Acid\", \"Bludgeoning\", \"Cold\", \"Fire\", \"Lightning\", \"Necrotic\", \"Piercing\", \"Poison\", \"Radiant\", \"Slashing\", \"Thunder\"}, pick_what = \"the damage type\", res_d4 = true, cast = \"action\", kind = \"buff\", concentration = true, say = \"the creature touched reduces damage of one type chosen at casting (Acid, Bludgeoning, Cold, Fire, Lightning, Necrotic, Piercing, Poison, Radiant, Slashing or Thunder) by 1d4, once per turn\", targets = 1 } },\r\n[\"Resurrection\"] = { level = 7, classes = {\"Bard\", \"Cleric\"}, school = \"사령학파\", time = \"1시간\", range = \"접촉\", dur = \"즉시\", cmp = \"VS\", ko = \"죽은 지 100년이 안 된 생물을 만져 되살립니다. 늙어 죽었거나 죽을 때 언데드였다면 되살릴 수 없습니다. 생명력을 모두 채운 채 돌아오고, 죽을 때 몸에 있던 독이 사라지며, 치명상이 모두 아물고 잃은 신체 부위도 돌아옵니다. 되살아난 생물은 d20 판정에 -4 벌칙을 받고, 벌칙은 긴 휴식을 마칠 때마다 1씩 줄어듭니다. 죽은 지 365일 이상 된 생물을 되살리면 나도 크게 지쳐서, 긴 휴식을 마칠 때까지 주문을 시전할 수 없고 d20 판정에 불리점을 받습니다. 시전에 1시간이 걸립니다.\", cost = \"a diamond worth 1,000+ GP, consumed\", cost_ko = \"1,000 GP 이상의 다이아몬드 (시전하면 사라짐)\", m = { cast = \"1 hour\", kind = \"utility\", raise = { hp = \"max\", within = 52560000, ordeal = 4, tax = 525600 } } },\r\n[\"Reverse Gravity\"] = { level = 7, classes = {\"Druid\", \"Sorcerer\", \"Wizard\"}, save = \"Dexterity\", concentration = true, school = \"변환학파\", time = \"행동\", range = \"100피트\", dur = \"집중, 최대 1분\", cmp = \"VS\", mins = 1, ko = \"100피트 안의 한 지점을 중심으로 반경 50피트·높이 100피트 원기둥 안의 중력을 뒤집습니다. 땅에 고정되지 않은 생물과 물건은 모두 위로 떨어져 원기둥 꼭대기까지 올라갑니다. 생물은 민첩 내성 굴림을 해서, 성공하면 손 닿는 고정된 것을 붙잡고 버팁니다. 올라가다 천장이나 고정된 것에 부딪히면 땅으로 떨어진 것과 똑같이 낙하 피해를 받고, 아무것에도 부딪히지 않으면 주문이 이어지는 동안 꼭대기에 떠 있습니다. 주문이 끝나면 모두 아래로 떨어집니다. 집중, 최대 1분.\", m = { cast = \"action\", kind = \"save\", save = \"Dexterity\", on_save = \"none\", concentration = true, lrfx = {}, area = true, fail = \"creatures and objects fall upward unless a successful save grabs something fixed; they fall when it ends\" } },\r\n[\"Revivify\"] = { level = 3, classes = {\"Cleric\", \"Druid\", \"Paladin\", \"Ranger\"}, school = \"사령학파\", time = \"행동\", range = \"접촉\", dur = \"즉시\", cmp = \"VS\", ko = \"죽은 지 1분이 안 된 생물을 만지면, 그 생물이 생명력 1로 되살아납니다. 늙어 죽은 생물은 되살리지 못하고, 잃은 신체 부위도 되돌리지 못합니다.\", cost = \"a diamond worth 300+ GP, consumed\", cost_ko = \"300 GP 이상의 다이아몬드 (시전하면 사라짐)\", m = { cast = \"action\", kind = \"utility\", raise = { hp = 1, within = 1 } } },\r\n[\"Rope Trick\"] = { level = 2, classes = {\"Wizard\"}, school = \"변환학파\", time = \"행동\", range = \"접촉\", dur = \"1시간\", cmp = \"VS\", ko = \"밧줄 하나를 만지면 한쪽 끝이 위로 떠올라, 밧줄이 바닥과 수직으로 늘어지거나 천장에 닿습니다. 밧줄 위 끝에는 보이지 않는 가로 3피트·세로 5피트 입구가 1시간 동안 열리고, 그 너머는 다른 차원의 공간입니다. 밧줄을 타고 올라 그 공간에 들어갈 수 있고, 밧줄은 안으로 끌어올리거나 밖으로 늘어뜨릴 수 있습니다. 공간에는 중형 이하 생물이 여덟까지 들어가고, 공격·주문·다른 효과는 입구를 드나들지 못하지만 안에서는 입구로 밖을 내다볼 수 있습니다. 주문이 끝나면 안에 있던 것은 모두 밖으로 떨어집니다.\", m = { cast = \"action\", kind = \"utility\" } },\r\n[\"Sacred Flame\"] = { level = 0, classes = {\"Cleric\"}, save = \"Dexterity\", damage = \"1d8\", damage_type = \"Radiant\", school = \"방출학파\", time = \"행동\", range = \"60피트\", dur = \"즉시\", cmp = \"VS\", ko = \"60피트 안에 보이는 생물 하나에게 불꽃 같은 광채가 내립니다. 대상은 민첩 내성 굴림을 하고, 실패하면 광휘 피해 1d8을 받습니다. 절반 엄폐나 3/4 엄폐도 이 내성 굴림에는 도움이 되지 않습니다. 5·11·17레벨에 피해 주사위가 하나씩 늘어납니다.\", m = { cast = \"action\", kind = \"save\", save = \"Dexterity\", on_save = \"none\", damage = \"1d8\", type = \"Radiant\", cantrip = true, nocover = true } },\r\n[\"Sanctuary\"] = { level = 1, classes = {\"Cleric\"}, save = \"Wisdom\", school = \"방호학파\", time = \"추가 행동\", range = \"30피트\", dur = \"1분\", cmp = \"VS\", ko = \"추가 행동으로 30피트 안의 생물 하나를 1분 동안 보호합니다. 그동안 보호받는 생물을 명중 굴림이나 피해를 주는 주문으로 노리는 자는 지혜 내성 굴림을 하고, 실패하면 새 대상을 고르거나, 그 공격이나 주문을 헛되이 씁니다. 범위 효과는 막지 못합니다. 보호받는 생물이 명중 굴림을 하거나, 주문을 시전하거나, 피해를 주면 주문이 끝납니다.\", bmins = 1, m = { attacker_save = \"Wisdom\", cast = \"bonus\", kind = \"buff\", targets = 1 } },\r\n[\"Scorching Ray\"] = { level = 2, classes = {\"Sorcerer\", \"Wizard\"}, attack = \"ranged\", damage = \"2d6\", damage_type = \"Fire\", school = \"방출학파\", time = \"행동\", range = \"120피트\", dur = \"즉시\", cmp = \"VS\", ko = \"불 광선 셋을 쏘아, 120피트 안의 한 대상에게 모두 쏘거나 여러 대상에게 나눠 쏩니다. 광선마다 원거리 주문 공격을 하고, 맞으면 화염 피해 2d6을 줍니다. 높은 레벨로 시전하면 한 단계마다 광선이 하나씩 늘어납니다.\", m = { cast = \"action\", kind = \"attack\", attack = \"ranged\", damage = \"2d6\", type = \"Fire\", rays = 3, upcast = { rays = 1 } } },\r\n[\"Scrying\"] = { level = 5, classes = {\"Bard\", \"Cleric\", \"Druid\", \"Warlock\", \"Wizard\"}, save = \"Wisdom\", concentration = true, school = \"예지학파\", time = \"10분\", range = \"자신\", dur = \"집중, 최대 10분\", cmp = \"VS\", mins = 10, ko = \"같은 세계에 있는 생물 하나를 골라 그 생물을 보고 들으려 합니다. 대상은 지혜 내성 굴림을 하는데, 내가 대상을 얼마나 잘 아는지와 대상과 이어진 물건을 가졌는지에 따라 수정치가 붙습니다(소문만 들음 +5, 만나 봄 +0, 잘 앎 -5, 초상 -2, 소지품 -4, 머리카락·손톱 같은 몸의 일부 -10). 대상은 무엇에 맞서는 내성인지 모르고, 그저 불안한 기분만 느낍니다. 성공하면 아무 일도 없고, 24시간 동안 그 대상에게 이 주문을 다시 쓸 수 없습니다. 실패하면 대상 10피트 안에 보이지 않고 만질 수 없는 감지점이 생겨 대상을 따라다니고, 나는 감지점이 있는 곳에 있는 것처럼 보고 들을 수 있습니다(감지점을 볼 수 있는 이에게는 주먹만 한 빛 구슬로 보임). 생물 대신 본 적 있는 장소를 노리면 감지점이 그 자리에 머뭅니다. 시전에 10분이 걸립니다. 집중, 최대 10분.\", cost = \"a focus worth 1,000+ GP, such as a crystal ball, mirror, or water-filled font\", cost_ko = \"1,000 GP 이상의 초점 (수정 구슬·거울·물 채운 수반 같은 것)\", m = { cast = \"10 minutes\", kind = \"utility\", concentration = true } },\r\n[\"Searing Smite\"] = { level = 1, classes = {\"Paladin\"}, save = \"Constitution\", damage = \"1d6\", damage_type = \"Fire\", school = \"방출학파\", time = \"추가 행동 (무기로 맞힌 직후)\", range = \"자신\", dur = \"1분\", ko = \"근접 무기나 맨손 공격으로 대상을 맞힌 직후 추가 행동으로 씁니다. 그 공격에 화염 피해 1d6을 더하고, 1분 동안 대상은 자기 턴이 시작될 때마다 화염 피해 1d6을 받은 뒤 건강 내성 굴림을 합니다. 성공하면 주문이 끝나고, 실패하면 이어집니다. 높은 레벨로 시전하면 한 단계마다 모든 피해가 1d6씩 늘어납니다.\", bmins = 1, m = { cast = \"bonus\", kind = \"buff\", rider = \"1d6\", rider_type = \"Fire\", upcast = { dice = \"1d6\" }, effect = \"+1d6 Fire on the melee hit, then burns each turn until a Constitution save\" } },\r\n[\"Secret Chest\"] = { level = 4, classes = {\"Wizard\"}, school = \"조형학파\", time = \"행동\", range = \"접촉\", dur = \"해제될 때까지\", cmp = \"VS\", ko = \"물질 요소인 상자와 작은 모형을 만지고, 상자와 그 안에 든 것(살아 있지 않은 것 12세제곱피트까지)을 에테르계에 숨깁니다. 상자가 에테르계에 있는 동안 마법 행동으로 모형을 만지면 상자가 내 5피트 안 땅 위의 빈 곳으로 돌아오고, 마법 행동으로 상자와 모형을 함께 만지면 상자를 다시 에테르계로 보냅니다. 60일이 지나면 하루가 끝날 때마다 5%씩 쌓이는 확률로 주문이 끝나고, 이 주문을 다시 시전하거나 모형이 부서져도 끝납니다. 주문이 끝날 때 상자가 에테르계에 있으면 상자는 그곳에 그대로 남아, 누군가 찾아낼 때까지 있습니다.\", cost = \"a chest, 3 feet by 2 feet by 2 feet, constructed from rare materials worth 5,000+ GP, and a Tiny replica of the chest made from the same materi- als worth 50+ GP\", cost_ko = \"희귀한 재료로 만든 5,000 GP 이상의 상자(3×2×2피트)와, 같은 재료로 만든 50 GP 이상의 작은 모형\", m = { cast = \"action\", kind = \"utility\" } },\r\n[\"See Invisibility\"] = { level = 2, classes = {\"Bard\", \"Sorcerer\", \"Wizard\"}, school = \"예지학파\", time = \"행동\", range = \"자신\", dur = \"1시간\", cmp = \"VS\", ko = \"1시간 동안 투명 상태인 생물과 물건을 보이는 것처럼 보고, 에테르계도 들여다봅니다. 에테르계의 것은 유령처럼 흐릿하게 보입니다.\", m = { cast = \"action\", kind = \"utility\" } },\r\n[\"Seeming\"] = { level = 5, classes = {\"Bard\", \"Sorcerer\", \"Wizard\"}, save = \"Charisma\", school = \"환영학파\", time = \"행동\", range = \"30피트\", dur = \"8시간\", cmp = \"VS\", ko = \"30피트 안에 보이는 생물을 원하는 만큼 골라, 8시간 동안 환영으로 겉모습을 바꿉니다. 원치 않는 생물은 매력 내성 굴림을 해서 성공하면 영향받지 않습니다. 대상마다 같은 모습이나 다른 모습을 줄 수 있고, 몸과 장비의 겉모습을 바꾸며, 키를 1피트까지 크거나 작게, 몸집을 더 무겁거나 가볍게 보이게 할 수 있습니다. 다만 팔다리의 기본 배치는 그대로여야 합니다. 만져 보면 들통나고(환영 모자를 씌우면 물건이 모자를 그냥 통과함), 누가 탐구 행동으로 대상을 살펴 지능(조사) 판정에서 내 주문 내성 난이도 이상이 나오면 변장임을 알아챕니다.\", m = { cast = \"action\", kind = \"utility\" } },\r\n[\"Sending\"] = { level = 3, classes = {\"Bard\", \"Cleric\", \"Wizard\"}, school = \"예지학파\", time = \"행동\", range = \"무제한\", dur = \"즉시\", cmp = \"VS\", ko = \"내가 만난 생물이나, 직접 만난 사람이 내게 설명한 생물 하나에게 25단어 이하의 말을 마음속으로 전합니다. 대상은 말의 뜻을 이해하며, 나를 아는 사이라면 누가 보냈는지 알아보고 즉시 같은 방식으로 답할 수 있습니다. 거리 제한 없이 다른 세계에도 전할 수 있지만, 대상이 다른 세계에 있으면 5% 확률로 전달에 실패합니다. 실패하면 내가 알게 됩니다. 말을 받은 대상은 이후 8시간 동안 내가 전음으로 연락하지 못하게 막을 수 있습니다. 그동안 다시 시도하면 차단되었다는 사실을 알게 되고 주문은 실패합니다.\", m = { cast = \"action\", kind = \"utility\" } },\r\n[\"Sequester\"] = { level = 7, classes = {\"Wizard\"}, school = \"변환학파\", time = \"행동\", range = \"접촉\", dur = \"해제될 때까지\", cmp = \"VS\", ko = \"물건 하나나 동의한 생물 하나를 만져 마법으로 감춥니다. 해제될 때까지 대상은 투명 상태가 되고, 예지계 주문의 목표가 되지 않으며, 마법으로 탐지되거나 멀리서 엿보이지도 않습니다. 대상이 생물이면 가사 상태에 빠집니다. 무의식 상태가 되고, 늙지 않으며, 음식·물·공기가 필요 없습니다. 주문이 일찍 끝날 조건을 정할 수 있는데, 대상 1마일 안에서 일어나거나 보이는 일이어야 합니다(예: '1,000년 뒤', '타라스크가 깨어날 때'). 대상이 피해를 받아도 주문이 끝납니다.\", cost = \"gem dust worth 5,000+ GP, consumed\", cost_ko = \"5,000 GP 이상의 보석 가루 (시전하면 사라짐)\", m = { cast = \"action\", kind = \"utility\" } },\r\n[\"Shapechange\"] = { level = 9, classes = {\"Druid\", \"Wizard\"}, concentration = true, school = \"변환학파\", time = \"행동\", range = \"자신\", dur = \"집중, 최대 1시간\", cmp = \"VS\", mins = 60, ko = \"주문이 이어지는 동안 다른 생물로 변하고, 마법 행동으로 다른 형태로 다시 바꿀 수 있습니다. 새 형태는 전에 본 적 있는 종류의 생물로, 도전 지수가 내 레벨(또는 도전 지수) 이하여야 하며 구조물이나 언데드는 안 됩니다. 시전할 때 처음 변한 형태의 생명력만큼 임시 생명력을 얻습니다(주문이 끝날 때 남은 것은 사라짐). 내 능력치는 그 형태의 것이 되지만 생물 유형·성향·성격·지능·지혜·매력·생명력·숙련·말하는 능력은 그대로이고, 주문시전 기능도 그대로 남습니다. 변할 때마다 장비를 바닥에 떨굴지, 새 몸에 맞게 바뀌게 할지 고릅니다. 집중, 최대 1시간.\", cost = \"a jade circlet worth 1,500+ GP\", cost_ko = \"1,500 GP 이상의 비취 머리띠\", m = { cast = \"action\", kind = \"utility\", concentration = true } },\r\n[\"Shatter\"] = { level = 2, classes = {\"Bard\", \"Sorcerer\", \"Wizard\"}, save = \"Constitution\", half_on_save = true, damage = \"3d8\", damage_type = \"Thunder\", school = \"방출학파\", time = \"행동\", range = \"60피트\", dur = \"즉시\", cmp = \"VS\", ko = \"60피트 안의 고른 지점에서 귀를 찢는 굉음이 터집니다. 그 지점을 중심으로 반경 10피트 구체 안의 생물은 모두 건강 내성 굴림을 해서, 실패하면 천둥 피해 3d8, 성공하면 그 절반을 받습니다. 구조물은 이 내성 굴림에 불리점을 받습니다. 범위 안에서 아무도 들거나 입지 않은, 마법이 아닌 물건도 피해를 받습니다. 높은 레벨로 시전하면 한 단계마다 피해가 1d8씩 늘어납니다.\", m = { cast = \"action\", kind = \"save\", save = \"Constitution\", on_save = \"half\", damage = \"3d8\", type = \"Thunder\", upcast = { dice = \"1d8\" }, area = true } },\r\n[\"Shield\"] = { level = 1, classes = {\"Sorcerer\", \"Wizard\"}, school = \"방호학파\", time = \"반응행동\", range = \"자신\", dur = \"1라운드\", cmp = \"VS\", ko = \"명중 굴림에 맞았거나 마법 화살 주문의 목표가 되었을 때 반응행동으로 씁니다. 다음 내 턴이 시작될 때까지 보이지 않는 역장이 나를 지켜 방어도가 5 오르고(방금 나를 맞힌 공격에도 적용), 마법 화살 피해를 받지 않습니다.\", bmins = 1, m = { cast = \"reaction\", kind = \"buff\", ac_bonus = 5 } },\r\n[\"Shield of Faith\"] = { level = 1, classes = {\"Cleric\", \"Paladin\"}, concentration = true, school = \"방호학파\", time = \"추가 행동\", range = \"60피트\", dur = \"집중, 최대 10분\", cmp = \"VS\", mins = 10, ko = \"추가 행동으로 60피트 안의 생물 하나를 반짝이는 막으로 감싸, 주문이 이어지는 동안 방어도를 2 올립니다. 집중, 최대 10분.\", m = { cast = \"bonus\", kind = \"buff\", concentration = true, ac_bonus = 2, targets = 1 } },\r\n[\"Shillelagh\"] = { level = 0, classes = {\"Druid\"}, school = \"변환학파\", time = \"추가 행동\", range = \"자신\", dur = \"1분\", cmp = \"VS\", ko = \"추가 행동으로 들고 있는 곤봉이나 쿼터스태프에 1분 동안 자연의 힘을 깃들입니다. 그 무기로 근접 공격할 때는 근력 대신 주문시전 능력치로 명중과 피해를 굴리고, 피해 주사위가 d8이 되며, 피해를 역장 피해로 바꿀 수도 있습니다. 무기를 손에서 놓거나 다시 시전하면 주문이 끝납니다. 5·11·17레벨에 피해 주사위가 d10·d12·2d6으로 커집니다.\", bmins = 1, m = { cast = \"bonus\", kind = \"buff\", lasting = true, say = \"a held Club or Quarterstaff uses the spellcasting ability for attack and damage, its die becomes a d8 (d10 at character level 5, d12 at 11, 2d6 at 17) and it may deal Force; Lua does not count it yet, so write the weapon's own ATTACK\" } },\r\n[\"Shining Smite\"] = { level = 2, classes = {\"Paladin\"}, damage = \"2d6\", damage_type = \"Radiant\", concentration = true, school = \"변환학파\", time = \"추가 행동 (무기로 맞힌 직후)\", range = \"자신\", dur = \"집중, 최대 1분\", mins = 1, ko = \"근접 무기나 맨손 공격으로 생물을 맞힌 직후 추가 행동으로 씁니다. 그 공격에 광휘 피해 2d6을 더하고, 주문이 끝날 때까지 대상은 반경 5피트를 밝게 비추며, 대상을 노리는 명중 굴림은 이점을 받고, 대상은 투명 상태여도 그 이점을 얻지 못합니다. 집중, 최대 1분. 높은 레벨로 시전하면 한 단계마다 피해가 1d6씩 늘어납니다.\", m = { cast = \"bonus\", kind = \"buff\", concentration = true, rider = \"2d6\", rider_type = \"Radiant\", upcast = { dice = \"1d6\" }, effect = \"+2d6 Radiant on the melee hit; attacks against it have Advantage\" } },\r\n[\"Shocking Grasp\"] = { level = 0, classes = {\"Sorcerer\", \"Wizard\"}, attack = \"melee\", damage = \"1d8\", damage_type = \"Lightning\", school = \"방출학파\", time = \"행동\", range = \"접촉\", dur = \"즉시\", cmp = \"VS\", ko = \"손이 닿는 거리의 생물에게 번개를 튀겨 근접 주문 공격을 합니다. 맞으면 번개 피해 1d8을 주고, 대상은 자기 다음 턴이 시작될 때까지 기회공격을 하지 못합니다. 5·11·17레벨에 피해 주사위가 하나씩 늘어납니다.\", m = { cast = \"action\", kind = \"attack\", attack = \"melee\", damage = \"1d8\", type = \"Lightning\", cantrip = true } },\r\n[\"Silence\"] = { level = 2, classes = {\"Bard\", \"Cleric\", \"Ranger\"}, concentration = true, ritual = true, school = \"환영학파\", time = \"행동 · 의식 가능\", range = \"120피트\", dur = \"집중, 최대 10분\", cmp = \"VS\", mins = 10, ko = \"120피트 안의 고른 지점을 중심으로 반경 20피트 구체 안에서는, 주문이 이어지는 동안 소리가 생기지도 드나들지도 않습니다. 그 안에 완전히 들어가 있는 생물과 물건은 천둥 피해에 면역이고, 생물은 귀머거리 상태가 되며, 음성 요소가 있는 주문을 시전할 수 없습니다. 집중, 최대 10분. 의식으로 시전할 수 있습니다.\", m = { cast = \"action\", kind = \"utility\", concentration = true, area = true } },\r\n[\"Silent Image\"] = { level = 1, classes = {\"Bard\", \"Sorcerer\", \"Wizard\"}, concentration = true, school = \"환영학파\", time = \"행동\", range = \"60피트\", dur = \"집중, 최대 10분\", cmp = \"VS\", mins = 10, ko = \"60피트 안에, 15피트 정육면체 이하 크기의 물건이나 생물, 또는 다른 눈에 보이는 현상의 환영을 만듭니다. 환영은 눈에만 보이고 소리·냄새 같은 것은 없습니다. 마법 행동으로 환영을 사거리 안의 다른 곳으로 옮길 수 있고, 걷는 것처럼 자연스럽게 움직이게 꾸밀 수 있습니다. 만지면 몸이 통과해 환영임이 드러나고, 탐구 행동으로 살펴 지능(조사) 판정에서 내 주문 내성 난이도 이상이 나와도 알아채며, 그 생물에게는 환영이 비쳐 보입니다. 집중, 최대 10분.\", m = { cast = \"action\", kind = \"utility\", concentration = true } },\r\n[\"Simulacrum\"] = { level = 7, classes = {\"Wizard\"}, school = \"환영학파\", time = \"12시간\", range = \"접촉\", dur = \"해제될 때까지\", cmp = \"VS\", ko = \"시전하는 내내 10피트 안에 있는 야수나 인간형 하나의 분신을 만듭니다. 시전을 마칠 때 그 생물과, 그 생물만 한 얼음이나 눈 더미를 함께 만지면 더미가 분신이라는 생물이 됩니다. 분신은 시전할 때 원본이 가진 능력치를 쓰지만, 종류는 구조물이고 최대 생명력이 절반이며 이 주문을 쓸 수 없습니다. 분신은 나와 내가 정한 생물에게 우호적이고, 내 명령을 따르며 싸움에서는 내 턴에 움직입니다. 레벨이 오르지 않고 휴식도 하지 못합니다. 다친 분신은 내가 긴 휴식을 하는 동안 5피트 안에 두고, 되찾는 생명력 1마다 100 GP어치 재료를 써서 고쳐야만 회복합니다. 생명력이 0이 되면 눈으로 돌아가 녹아 버리고, 이 주문을 다시 시전하면 전에 만든 분신은 곧바로 사라집니다. 시전에 12시간이 걸립니다.\", cost = \"powdered ruby worth 1,500+ GP, consumed\", cost_ko = \"1,500 GP 이상의 루비 가루 (시전하면 사라짐)\", m = { cast = \"12 hours\", kind = \"utility\" } },\r\n[\"Sleep\"] = { level = 1, classes = {\"Bard\", \"Sorcerer\", \"Wizard\"}, save = \"Wisdom\", concentration = true, school = \"환혹학파\", time = \"행동\", range = \"60피트\", dur = \"집중, 최대 1분\", cmp = \"VS\", mins = 1, ko = \"60피트 안의 한 지점을 중심으로 반경 5피트 구체 안에서 고른 생물들이 지혜 내성 굴림을 합니다. 실패하면 자기 다음 턴이 끝날 때까지 행동불능 상태가 되고, 그때 다시 굴려 또 실패하면 주문이 이어지는 동안 무의식 상태가 되어 잠듭니다. 잠든 생물은 피해를 받거나, 5피트 안의 누군가가 행동을 써서 흔들면 깨어납니다. 엘프처럼 잠을 자지 않거나 탈진 상태에 면역인 생물은 이 주문의 내성 굴림에 자동으로 성공합니다. 집중, 최대 1분.\", m = { cast = \"action\", kind = \"save\", save = \"Wisdom\", on_save = \"none\", concentration = true, lrfx = {\"Incapacitated\", \"Unconscious\"}, area = true, fail = \"Incapacitated, then Unconscious on a second failure; ends when damaged or shaken\" } },\r\n[\"Sleet Storm\"] = { level = 3, classes = {\"Druid\", \"Sorcerer\", \"Wizard\"}, save = \"Dexterity\", concentration = true, school = \"조형학파\", time = \"행동\", range = \"150피트\", dur = \"집중, 최대 1분\", cmp = \"VS\", mins = 1, ko = \"150피트 안의 고른 지점을 중심으로 높이 40피트·반경 20피트 원기둥에 주문이 이어지는 동안 진눈깨비가 내립니다. 그 안은 완전히 가려지고, 드러난 불은 꺼지며, 땅은 어려운 지형이 됩니다. 턴 중 처음 그 안에 들어오거나 그 안에서 턴을 시작하는 생물은 민첩 내성 굴림을 하고, 실패하면 넘어진 상태가 되고 집중이 깨집니다. 집중, 최대 1분.\", m = { cast = \"action\", kind = \"save\", save = \"Dexterity\", on_save = \"none\", concentration = true, lrfx = {\"Prone\"}, area = true, fail = \"Prone and loses Concentration; Heavily Obscured, Difficult Terrain\" } },\r\n[\"Slow\"] = { level = 3, classes = {\"Bard\", \"Sorcerer\", \"Wizard\"}, save = \"Wisdom\", concentration = true, school = \"변환학파\", time = \"행동\", range = \"120피트\", dur = \"집중, 최대 1분\", cmp = \"VS\", mins = 1, ko = \"120피트 안의 40피트 정육면체 안에서 생물을 여섯까지 골라, 그 둘레의 시간을 느리게 바꿉니다. 대상은 지혜 내성 굴림을 하고, 실패하면 주문이 이어지는 동안 속도가 절반이 되고, 방어도와 민첩 내성 굴림이 2 낮아지며, 반응행동을 할 수 없습니다. 자기 턴에는 행동과 추가 행동 가운데 하나만 할 수 있고, 공격 행동을 해도 한 번만 공격합니다. 동작 요소가 있는 주문을 시전하면 손짓이 너무 느려 25% 확률로 주문이 실패합니다. 대상은 자기 턴이 끝날 때마다 다시 굴려, 성공하면 풀려납니다. 집중, 최대 1분.\", m = { foe_fx = { ac = -2, saves = { Dexterity = -2 } }, cast = \"action\", kind = \"save\", save = \"Wisdom\", on_save = \"none\", concentration = true, lrfx = {}, fail = \"Speed halved, -2 AC and Dex saves, no Reactions, action or Bonus Action only, one attack\" } },\r\n[\"Sorcerous Burst\"] = { level = 0, classes = {\"Sorcerer\"}, attack = \"ranged\", school = \"방출학파\", time = \"행동\", range = \"120피트\", dur = \"즉시\", ko = \"120피트 안의 생물이나 물체 하나에 술법 에너지를 던져 원거리 주문 공격을 합니다. 맞으면 산성·냉기·화염·번개·독성·정신·천둥 가운데 고른 종류의 피해 1d8을 줍니다. 이 주문의 d8에서 8이 나오면 d8을 하나 더 굴려 피해에 더할 수 있고, 이렇게 더하는 주사위는 시전마다 주문시전 능력치 수정치만큼까지입니다. 5·11·17레벨에 피해 주사위가 하나씩 늘어납니다.\", m = { cast = \"action\", kind = \"attack\", attack = \"ranged\", damage = \"1d8\", cantrip = true } },\r\n[\"Spare the Dying\"] = { level = 0, classes = {\"Cleric\", \"Druid\"}, school = \"사령학파\", time = \"행동\", range = \"15피트\", dur = \"즉시\", cmp = \"VS\", ko = \"15피트 안에 있는, 생명력이 0이지만 죽지 않은 생물 하나를 안정 상태로 만듭니다. 5·11·17레벨에 사거리가 30·60·120피트로 늘어납니다.\", m = { cast = \"action\", kind = \"utility\", say = \"a creature at 0 HP within 15 ft (30 ft at character level 5, 60 at 11, 120 at 17) becomes Stable\" } },\r\n[\"Speak with Animals\"] = { level = 1, classes = {\"Bard\", \"Druid\", \"Ranger\", \"Warlock\"}, ritual = true, school = \"예지학파\", time = \"행동 · 의식 가능\", range = \"자신\", dur = \"10분\", cmp = \"VS\", ko = \"10분 동안 야수의 말을 알아듣고 대화할 수 있으며, 야수에게 교섭 행동의 기술 판정도 쓸 수 있습니다. 야수는 먹고사는 일이나 무리 이야기 말고는 할 말이 별로 없지만, 적어도 근처의 장소와 괴물, 지난 하루 동안 보고 들은 것은 알려 줍니다. 의식으로 시전할 수 있습니다.\", m = { cast = \"action\", kind = \"utility\" } },\r\n[\"Speak with Dead\"] = { level = 3, classes = {\"Bard\", \"Cleric\", \"Wizard\"}, school = \"사령학파\", time = \"행동\", range = \"10피트\", dur = \"10분\", cmp = \"VS\", ko = \"10피트 안에 있는, 입이 있는 시체 하나에 생명이 깃든 듯한 기운을 불어넣어, 10분 동안 질문을 다섯 개까지 할 수 있게 합니다. 시체는 살아서 알던 것만, 살아서 알던 언어로 대개 짧고 알쏭달쏭하게 답하며, 내가 적대적이거나 나를 적으로 알아보면 참말을 하지 않을 수도 있습니다. 영혼이 돌아오는 것이 아니므로, 죽은 뒤에 일어난 일은 모르고 앞일도 짐작하지 못합니다. 죽을 때 언데드였거나 지난 10일 안에 이 주문을 받은 시체에는 통하지 않습니다.\", m = { cast = \"action\", kind = \"utility\" } },\r\n[\"Speak with Plants\"] = { level = 3, classes = {\"Bard\", \"Druid\", \"Ranger\"}, school = \"변환학파\", time = \"행동\", range = \"자신\", dur = \"10분\", cmp = \"VS\", ko = \"10분 동안 내 둘레 30피트(움직이지 않는 범위) 안의 식물에 약간의 지각과 움직임을 주어, 나와 말이 통하고 간단한 명령을 따르게 합니다. 지난 하루 동안 그곳에서 있었던 일(지나간 생물, 날씨 같은 것)을 물어볼 수 있습니다. 덤불처럼 식물 때문에 생긴 어려운 지형을 주문이 이어지는 동안 보통 지형으로 바꾸거나, 식물이 있는 보통 지형을 어려운 지형으로 바꿀 수도 있습니다. 식물이 뿌리째 뽑혀 돌아다니지는 못하지만, 나를 위해 가지·덩굴·줄기를 움직일 수는 있습니다. 범위 안의 식물 생물과도 같은 언어를 쓰는 것처럼 말이 통합니다.\", m = { cast = \"action\", kind = \"utility\" } },\r\n[\"Spider Climb\"] = { level = 2, classes = {\"Sorcerer\", \"Warlock\", \"Wizard\"}, concentration = true, school = \"변환학파\", time = \"행동\", range = \"접촉\", dur = \"집중, 최대 1시간\", cmp = \"VS\", mins = 60, ko = \"동의한 생물 하나를 만지면, 주문이 이어지는 동안 그 생물이 손을 쓰지 않고도 벽을 오르내리고 천장을 따라 움직일 수 있으며, 속도만큼의 오르기 속도를 얻습니다. 집중, 최대 1시간. 높은 레벨로 시전하면 한 단계마다 대상이 하나씩 늘어납니다.\", m = { cast = \"action\", kind = \"buff\", concentration = true, upcast = { targets = 1 }, targets = 1 } },\r\n[\"Spike Growth\"] = { level = 2, classes = {\"Druid\", \"Ranger\"}, damage = \"2d4\", damage_type = \"Piercing\", concentration = true, school = \"변환학파\", time = \"행동\", range = \"150피트\", dur = \"집중, 최대 10분\", cmp = \"VS\", mins = 10, ko = \"150피트 안의 한 지점을 중심으로 반경 20피트 구체 안의 땅에 단단한 가시와 가시덤불이 돋아, 주문이 이어지는 동안 그곳이 어려운 지형이 됩니다. 그곳으로 들어가거나 그 안에서 움직이는 생물은 5피트를 갈 때마다 관통 피해 2d4를 받습니다. 땅은 자연스러워 보이도록 감춰져서, 시전할 때 그곳을 보지 못한 생물은 들어가기 전에 수색 행동으로 지혜(감지·생존) 판정을 해서 내 주문 내성 난이도 이상이 나와야 위험한 곳인 줄 압니다. 집중, 최대 10분.\", m = { cast = \"action\", kind = \"auto\", damage = \"2d4\", type = \"Piercing\", darts = 20, concentration = true, say = \"2d4 Piercing for every 5 feet a creature moves through the area, no roll: one [DAMAGE|Target|2d4|dice|damage] for each 5 feet\" } },\r\n[\"Spirit Guardians\"] = { level = 3, classes = {\"Cleric\"}, save = \"Wisdom\", half_on_save = true, damage = \"3d8\", damage_type = \"Radiant\", concentration = true, school = \"조형학파\", time = \"행동\", range = \"자신\", dur = \"집중, 최대 10분\", cmp = \"VS\", mins = 10, ko = \"보호하는 영혼들을 불러, 주문이 이어지는 동안 내 주위 15피트를 맴돌게 합니다(내가 선하거나 중립이면 천사나 요정의 모습 가운데 고르고, 악하면 악마의 모습). 시전할 때 영향받지 않을 생물을 지정할 수 있습니다. 지정하지 않은 생물은 그 범위 안에서 속도가 절반이 되고, 이 범위가 그 생물에게 닿거나, 그 생물이 범위에 들어오거나 그 안에서 턴을 끝낼 때마다 지혜 내성 굴림을 합니다. 실패하면 광휘 피해 3d8(내가 악하면 사령 피해), 성공하면 그 절반을 받습니다(턴마다 한 번). 집중, 최대 10분. 높은 레벨로 시전하면 한 단계마다 피해가 1d8씩 늘어납니다.\", m = { cast = \"action\", kind = \"save\", save = \"Wisdom\", on_save = \"half\", damage = \"3d8\", type = \"Radiant (Necrotic if evil)\", concentration = true, upcast = { dice = \"1d8\" }, area = true } },\r\n[\"Spiritual Weapon\"] = { level = 2, classes = {\"Cleric\"}, attack = \"melee\", concentration = true, school = \"방출학파\", time = \"추가 행동\", range = \"60피트\", dur = \"집중, 최대 1분\", cmp = \"VS\", mins = 1, ko = \"추가 행동으로 60피트 안의 고른 곳에, 내가 고른 무기를 닮은 떠다니는 영체 역장을 만들고, 곧바로 역장 5피트 안의 생물 하나에게 근접 주문 공격을 할 수 있습니다. 맞으면 역장 피해 1d8 + 주문시전 능력치 수정치를 줍니다. 이후 내 턴마다 추가 행동으로 역장을 20피트까지 옮기고, 그 5피트 안의 생물에게 다시 공격할 수 있습니다. 집중, 최대 1분. 높은 레벨로 시전하면 한 단계마다 피해가 1d8씩 늘어납니다.\", m = { cast = \"bonus\", kind = \"attack\", attack = \"melee\", damage = \"1d8+MOD\", type = \"Force\", concentration = true, upcast = { dice = \"1d8\" } } },\r\n[\"Starry Wisp\"] = { level = 0, classes = {\"Bard\", \"Druid\"}, attack = \"ranged\", damage = \"1d8\", damage_type = \"Radiant\", school = \"방출학파\", time = \"행동\", range = \"60피트\", dur = \"즉시\", cmp = \"VS\", ko = \"60피트 안의 생물이나 물체 하나에 별빛 한 점을 쏘아 원거리 주문 공격을 합니다. 맞으면 광휘 피해 1d8을 주고, 다음 내 턴이 끝날 때까지 대상은 반경 10피트를 희미하게 비추며, 투명 상태여도 그 이점을 얻지 못합니다. 5·11·17레벨에 피해 주사위가 하나씩 늘어납니다.\", m = { cast = \"action\", kind = \"attack\", attack = \"ranged\", damage = \"1d8\", type = \"Radiant\", cantrip = true } },\r\n[\"Stinking Cloud\"] = { level = 3, classes = {\"Bard\", \"Sorcerer\", \"Wizard\"}, save = \"Constitution\", concentration = true, school = \"조형학파\", time = \"행동\", range = \"90피트\", dur = \"집중, 최대 1분\", cmp = \"VS\", mins = 1, ko = \"90피트 안의 한 지점을 중심으로 반경 20피트 구체의 메스꺼운 노란 가스 구름을 만듭니다. 구름 속은 완전히 가려지고, 주문이 끝나거나 돌풍 같은 강한 바람이 불어 흩어질 때까지 남습니다. 그 안에서 턴을 시작하는 생물은 건강 내성 굴림을 하고, 실패하면 그 턴이 끝날 때까지 중독 상태가 되며, 이렇게 중독된 동안에는 행동도 추가 행동도 할 수 없습니다. 집중, 최대 1분.\", m = { cast = \"action\", kind = \"save\", save = \"Constitution\", on_save = \"none\", concentration = true, lrfx = {\"Poisoned\"}, area = true, fail = \"Poisoned and no action or Bonus Action this turn; Heavily Obscured\" } },\r\n[\"Stone Shape\"] = { level = 4, classes = {\"Cleric\", \"Druid\", \"Wizard\"}, school = \"변환학파\", time = \"행동\", range = \"접촉\", dur = \"즉시\", cmp = \"VS\", ko = \"중형 이하의 돌 물건이나, 어느 쪽으로도 5피트를 넘지 않는 돌 부분을 만져 원하는 모양으로 빚습니다. 큰 바위를 무기·조각상·궤짝으로 만들거나, 두께 5피트 벽에 작은 통로를 뚫거나, 돌문이나 문틀을 빚어 문을 봉할 수 있습니다. 만든 물건에 경첩 둘과 걸쇠 하나까지는 넣을 수 있지만, 그보다 섬세한 장치는 만들 수 없습니다.\", m = { cast = \"action\", kind = \"utility\" } },\r\n[\"Stoneskin\"] = { level = 4, classes = {\"Druid\", \"Ranger\", \"Sorcerer\", \"Wizard\"}, concentration = true, school = \"변환학파\", time = \"행동\", range = \"접촉\", dur = \"집중, 최대 1시간\", cmp = \"VS\", mins = 60, ko = \"동의한 생물 하나를 만지면, 주문이 이어지는 동안 그 생물이 타격·관통·참격 피해에 저항을 얻습니다. 집중, 최대 1시간.\", cost = \"diamond dust worth 100+ GP, consumed\", cost_ko = \"100 GP 이상의 다이아몬드 가루 (시전하면 사라짐)\", m = { cast = \"action\", kind = \"buff\", concentration = true, resist = {\"Bludgeoning\", \"Piercing\", \"Slashing\"}, targets = 1 } },\r\n[\"Storm of Vengeance\"] = { level = 9, classes = {\"Druid\"}, save = \"Constitution\", half_on_save = true, damage = \"2d6\", damage_type = \"Thunder\", concentration = true, school = \"조형학파\", time = \"행동\", range = \"1마일\", dur = \"집중, 최대 1분\", cmp = \"VS\", mins = 1, ko = \"1마일 안의 한 지점을 중심으로, 반경 300피트의 소용돌이치는 폭풍 구름이 생깁니다. 구름이 나타날 때 그 아래의 생물은 건강 내성 굴림을 하고, 실패하면 천둥 피해 2d6을 받고 주문이 이어지는 동안 귀머거리 상태가 됩니다. 이후 내 턴이 시작될 때마다 폭풍이 다른 일을 일으킵니다. 2번째 턴에는 산성비가 내려 구름 아래의 생물과 물건이 산성 피해 4d6을 받습니다. 3번째 턴에는 구름 아래의 서로 다른 생물이나 물건 여섯에 번개가 내리꽂히고, 각 대상은 민첩 내성 굴림을 해서 실패하면 번개 피해 10d6, 성공하면 그 절반을 받습니다. 4번째 턴에는 우박이 쏟아져 구름 아래의 생물이 타격 피해 2d6을 받습니다. 5~10번째 턴에는 돌풍과 얼음비가 몰아쳐 구름 아래의 생물이 냉기 피해 1d6을 받고, 그때부터 주문이 끝날 때까지 그곳은 어려운 지형이 되고 완전히 가려지며, 무기로 원거리 공격을 할 수 없고 강한 바람이 붑니다. 집중, 최대 1분.\", m = { cast = \"action\", kind = \"save\", save = \"Constitution\", on_save = \"none\", damage = \"2d6\", type = \"Thunder\", concentration = true, lrfx = {\"Deafened\"}, area = true } },\r\n[\"Suggestion\"] = { level = 2, classes = {\"Bard\", \"Sorcerer\", \"Warlock\", \"Wizard\"}, save = \"Wisdom\", concentration = true, school = \"환혹학파\", time = \"행동\", range = \"30피트\", dur = \"집중, 최대 8시간\", cmp = \"V\", mins = 480, ko = \"30피트 안에 보이고 내 말을 듣고 알아듣는 생물 하나에게, 할 일을 스물다섯 단어 이내로 제안합니다. 해낼 수 있을 것처럼 들려야 하고, 대상이나 그 동료가 다칠 게 뻔한 일은 안 됩니다(예: '교단 보물 창고의 열쇠를 가져와 나에게 줘라'). 대상은 지혜 내성 굴림을 하고, 실패하면 주문이 끝나거나 나나 내 동료가 대상에게 피해를 줄 때까지 매혹 상태가 되어 힘껏 그 제안을 따릅니다. 제안한 일을 더 일찍 마치면 그 대상에게는 주문이 끝납니다. 집중, 최대 8시간.\", m = { cast = \"action\", kind = \"save\", save = \"Wisdom\", on_save = \"none\", concentration = true, lrfx = {\"Charmed\"}, fail = \"Charmed, follows a reasonable 25-word suggestion\" } },\r\n[\"Summon Dragon\"] = { level = 5, classes = {\"Wizard\"}, concentration = true, school = \"조형학파\", time = \"행동\", range = \"60피트\", dur = \"집중, 최대 1시간\", cmp = \"VS\", mins = 60, ko = \"60피트 안에 보이는 빈 곳에 대형 용의 영혼을 부릅니다(방어도 14 + 주문 레벨, 생명력 50 + 5레벨을 넘는 주문 레벨마다 10, 비행 60피트). 부를 때 산성·냉기·화염·번개·독성 가운데 하나를 영혼의 저항으로 고르면, 주문이 끝날 때까지 나도 그 피해에 저항합니다. 용의 영혼은 나와 동료의 편이고, 싸움에서는 내 턴 바로 뒤에 움직이며, 내가 말로 명령하면 따르고(내 행동은 들지 않음) 명령이 없으면 회피 행동을 하고 위험을 피해 움직입니다. 자기 턴마다 주문 레벨의 절반(내림)만큼 할퀴기(내 주문 명중, 관통 피해 1d6 + 4 + 주문 레벨)를 하고, 30피트 원뿔로 숨결을 내뿜습니다(민첩 내성, 실패하면 고른 저항 종류의 피해 2d6, 성공하면 절반). 생명력이 0이 되거나 주문이 끝나면 사라집니다. 집중, 최대 1시간. 높은 레벨로 시전하면 능력치 블록에 그 레벨을 써서 더 강해집니다.\", cost = \"an object with the image of a dragon engraved on it worth 500+ GP\", cost_ko = \"용이 새겨진 500 GP 이상의 물건\", m = { cast = \"action\", kind = \"attack\", attack = \"melee\", damage = \"1d6+4+LVL\", type = \"Piercing\", concentration = true, extra_save = { save = \"Dexterity\", on_save = \"half\", damage = \"2d6\", type = \"choice (Acid, Cold, Fire, Lightning, Poison)\", targets = \"a 30-ft cone\" } } },\r\n[\"Sunbeam\"] = { level = 6, classes = {\"Cleric\", \"Druid\", \"Sorcerer\", \"Wizard\"}, save = \"Constitution\", half_on_save = true, damage = \"6d8\", damage_type = \"Radiant\", concentration = true, school = \"방출학파\", time = \"행동\", range = \"자신\", dur = \"집중, 최대 1분\", cmp = \"VS\", mins = 1, ko = \"내게서 폭 5피트·길이 60피트의 일직선으로 햇살 광선을 쏩니다. 선 안의 생물은 건강 내성 굴림을 해서, 실패하면 광휘 피해 6d8을 받고 다음 내 턴이 시작될 때까지 장님 상태가 되며, 성공하면 피해만 절반 받습니다. 주문이 이어지는 동안 마법 행동으로 새 광선을 쏠 수 있습니다. 그동안 내 머리 위에 눈부신 빛 덩이가 떠서 반경 30피트를 밝게, 그 바깥 30피트를 희미하게 비추며, 이 빛은 햇빛입니다. 집중, 최대 1분.\", m = { cast = \"action\", kind = \"save\", save = \"Constitution\", on_save = \"half\", damage = \"6d8\", type = \"Radiant\", concentration = true, lrfx = {\"Blinded\"}, area = true } },\r\n[\"Sunburst\"] = { level = 8, classes = {\"Cleric\", \"Druid\", \"Sorcerer\", \"Wizard\"}, save = \"Constitution\", half_on_save = true, damage = \"12d6\", damage_type = \"Radiant\", school = \"방출학파\", time = \"행동\", range = \"150피트\", dur = \"즉시\", cmp = \"VS\", ko = \"150피트 안의 고른 지점을 중심으로 반경 60피트 구체에 눈부신 햇빛이 번쩍입니다. 그 안의 생물은 모두 건강 내성 굴림을 해서, 실패하면 광휘 피해 12d6을 받고 1분 동안 장님 상태가 되며, 성공하면 피해만 절반 받습니다. 이 주문으로 장님이 된 생물은 자기 턴이 끝날 때마다 다시 굴려, 성공하면 풀려납니다. 범위 안에서 주문으로 만든 어둠은 해제됩니다.\", m = { puts = {\"Blinded\"}, cast = \"action\", kind = \"save\", save = \"Constitution\", on_save = \"half\", damage = \"12d6\", type = \"Radiant\", lrfx = {\"Blinded\"}, area = true } },\r\n[\"Symbol\"] = { level = 7, classes = {\"Bard\", \"Cleric\", \"Druid\", \"Wizard\"}, save = \"Constitution\", half_on_save = true, damage = \"10d10\", damage_type = \"Necrotic\", school = \"방호학파\", time = \"1분\", range = \"접촉\", dur = \"해제·발동될 때까지\", cmp = \"VS\", ko = \"바닥이나 벽 같은 면, 또는 책이나 상자처럼 닫을 수 있는 물건 안에 해로운 문양을 새깁니다. 문양은 지름 10피트까지이고, 물건에 새겼다면 그 물건이 10피트 넘게 옮겨질 때 문양이 깨져 발동 없이 주문이 끝납니다. 문양은 거의 보이지 않아, 지혜(감지) 판정으로 내 주문 내성 난이도 이상이 나와야 알아챕니다. 새길 때 발동 조건(만지거나 밟기, 덮개 치우기, 가까이 다가오기, 물건 열기, 문양 보기 같은 것)을 정하고, 특정 종류의 생물만 발동시키게 하거나 암호를 말하는 생물은 발동시키지 않게 할 수도 있습니다. 발동하면 문양이 빛나 반경 60피트 구체를 10분 동안 희미한 빛으로 채운 뒤 주문이 끝나고, 그동안 그 안에 있던 생물과 턴 중 처음 들어오거나 그 안에서 턴을 끝내는 생물이 효과를 받습니다(턴마다 한 번). 효과는 새길 때 하나를 고릅니다. 죽음은 건강 내성 굴림에 실패하면 사령 피해 10d10, 성공하면 그 절반을 줍니다. 불화는 지혜 내성 굴림에 실패하면 1분 동안 다른 생물과 다투느라 제대로 말이 통하지 않게 하고, 명중 굴림과 능력 판정에 불리점을 줍니다. 공포는 지혜 내성 굴림에 실패하면 1분 동안 공포 상태로 만들고, 그 생물은 자기 턴마다 할 수 있으면 문양에서 30피트 이상 멀어져야 합니다. 고통은 건강 내성 굴림에 실패하면 1분 동안 행동불능 상태로 만듭니다. 잠은 지혜 내성 굴림에 실패하면 10분 동안 무의식 상태로 만들고, 피해를 받거나 누가 행동을 써서 흔들면 깨어납니다. 기절은 지혜 내성 굴림에 실패하면 1분 동안 충격 상태로 만듭니다. 시전에 1분이 걸립니다.\", cost = \"powdered diamond worth 1,000+ GP, consumed\", cost_ko = \"1,000 GP 이상의 다이아몬드 가루 (시전하면 사라짐)\", m = { cast = \"1 minute\", kind = \"save\", save = \"Constitution\", on_save = \"half\", damage = \"10d10\", type = \"Necrotic\", lrfx = \"pick\" } },\r\n[\"Telekinesis\"] = { level = 5, classes = {\"Sorcerer\", \"Wizard\"}, save = \"Strength\", concentration = true, school = \"변환학파\", time = \"행동\", range = \"60피트\", dur = \"집중, 최대 10분\", cmp = \"VS\", mins = 10, ko = \"생각만으로 생물이나 물건을 움직이는 힘을 얻습니다. 시전할 때와, 주문이 끝나기 전 이후 내 턴마다 마법 행동으로 60피트 안에 보이는 생물이나 물건 하나에 힘을 쓸 수 있습니다. 거대형 이하 생물은 근력 내성 굴림을 하고, 실패하면 사거리 안에서 원하는 방향으로 30피트까지 옮겨지고 다음 내 턴이 끝날 때까지 포박 상태가 됩니다(공중에 들어 올리면 그때까지 떠 있다가, 다시 이 힘을 써서 내성에 실패시키지 않으면 떨어짐). 거대형 이하 물건은 아무도 들거나 입지 않았으면 그대로 30피트까지 옮기고, 누가 들거나 입고 있으면 그 생물이 근력 내성 굴림에 실패할 때 빼앗아 30피트까지 옮깁니다. 간단한 도구를 다루거나 문이나 상자를 여는 것 같은 섬세한 조작도 할 수 있습니다. 같은 대상을 라운드마다 다시 노리거나 언제든 새 대상을 고를 수 있고, 대상을 바꾸면 이전 대상은 풀려납니다. 집중, 최대 10분.\", m = { cast = \"action\", kind = \"save\", save = \"Strength\", on_save = \"none\", concentration = true, lrfx = {\"Restrained\"}, fail = \"moves a creature up to 30 ft and it is Restrained until the end of your next turn; or moves an object\" } },\r\n[\"Telepathic Bond\"] = { level = 5, classes = {\"Bard\", \"Wizard\"}, ritual = true, school = \"예지학파\", time = \"행동 · 의식 가능\", range = \"30피트\", dur = \"1시간\", cmp = \"VS\", ko = \"30피트 안의 동의한 생물을 여덟까지 골라, 1시간 동안 서로의 마음을 이어 줍니다. 대상들은 쓰는 말이 달라도 텔레파시로 이야기할 수 있고, 거리는 상관없지만 다른 세계까지는 닿지 않습니다. 어떤 언어로도 소통하지 못하는 생물에게는 통하지 않습니다. 의식으로 시전할 수 있습니다.\", m = { cast = \"action\", kind = \"utility\" } },\r\n[\"Teleport\"] = { level = 7, classes = {\"Bard\", \"Sorcerer\", \"Wizard\"}, damage = \"3d10\", damage_type = \"Force\", school = \"조형학파\", time = \"행동\", range = \"10피트\", dur = \"즉시\", cmp = \"V\", ko = \"나와, 10피트 안에 보이고 함께 가려는 생물 여덟까지를 같은 세계의 아는 곳으로 곧장 옮깁니다. 생물 대신 10피트 안에 보이는 물건 하나를 옮길 수도 있습니다(대형 이하이고, 원치 않는 생물이 들고 있거나 지닌 것은 안 됨). 목적지를 얼마나 잘 아느냐에 따라 GM이 1d100을 굴려 결과를 정합니다. 문양 순서를 아는 상설 순간이동 원이나, 6개월 안에 그곳에서 가져온 물건이 있으면 언제나 정확히 도착합니다. 그 밖에는 아주 잘 아는 곳, 몇 번 본 곳, 한 번 보았거나 설명만 들은 곳 순으로 사고가 날 확률이 커집니다. 사고가 나면 옮겨지는 생물(또는 물건)이 저마다 역장 피해 3d10을 받고, GM이 다시 굴립니다. 사고가 아니어도 생김새가 비슷한 다른 곳에 나타나거나, 목적지에서 2d12마일 떨어진 곳에 나타날 수 있습니다. 있지도 않은 곳(환영으로 본 곳이나 이제는 없는 곳)을 노리면 사고가 나거나 비슷한 곳에 나타납니다.\", m = { cast = \"action\", kind = \"utility\" } },\r\n[\"Teleportation Circle\"] = { level = 5, classes = {\"Bard\", \"Sorcerer\", \"Warlock\", \"Wizard\"}, school = \"조형학파\", time = \"1분\", range = \"10피트\", dur = \"1라운드\", cmp = \"V\", ko = \"시전하면서 바닥에 반경 5피트 원을 그리고 문양을 새겨, 문양 순서를 아는 같은 세계의 상설 순간이동 원과 잇습니다. 다음 내 턴이 끝날 때까지 원 안에 반짝이는 문이 열리고, 문에 들어가는 생물은 곧바로 목적지 원 5피트 안에 나타납니다(그 자리가 막혀 있으면 가장 가까운 빈 곳). 이 주문을 처음 익힐 때 물질계 목적지 두 곳의 문양 순서를 GM이 정해 주고, 다른 원의 문양 순서는 1분 동안 살펴보면 외울 수 있습니다. 같은 자리에서 365일 동안 매일 시전하면 그곳에 상설 순간이동 원이 생깁니다. 시전에 1분이 걸립니다.\", cost = \"rare inks worth 50+ GP, consumed\", cost_ko = \"50 GP 이상의 희귀한 잉크 (시전하면 사라짐)\", m = { cast = \"1 minute\", kind = \"utility\" } },\r\n[\"Thaumaturgy\"] = { level = 0, classes = {\"Cleric\"}, school = \"변환학파\", time = \"행동\", range = \"30피트\", dur = \"최대 1분\", cmp = \"V\", ko = \"30피트 안에 작은 기적 하나를 일으킵니다. 1분 동안 눈 모양을 바꾸거나, 1분 동안 목소리를 세 배까지 크게 울리거나(그동안 매력(위협) 판정에 이점), 1분 동안 불꽃을 흔들거나 밝히거나 어둡게 하거나 색을 바꾸거나, 잠기지 않은 문이나 창문을 활짝 열거나 쾅 닫거나, 고른 곳에서 천둥소리·까마귀 울음·불길한 속삭임 같은 소리를 내거나, 1분 동안 땅을 해 없이 흔듭니다. 1분짜리 효과는 셋까지 함께 둘 수 있습니다.\", m = { cast = \"action\", kind = \"utility\" } },\r\n[\"Thunderwave\"] = { level = 1, classes = {\"Bard\", \"Druid\", \"Sorcerer\", \"Wizard\"}, save = \"Constitution\", half_on_save = true, damage = \"2d8\", damage_type = \"Thunder\", school = \"방출학파\", time = \"행동\", range = \"자신\", dur = \"즉시\", cmp = \"VS\", ko = \"나에게서 천둥 파동이 퍼져 나갑니다. 내게서 뻗어 나가는 15피트 정육면체 안의 생물은 모두 건강 내성 굴림을 하고, 실패하면 천둥 피해 2d8을 받고 나에게서 10피트 밀려나며, 성공하면 피해만 절반 받습니다. 정육면체 안에 온전히 들어 있는, 고정되지 않은 물건도 10피트 밀려나고, 굉음이 300피트까지 들립니다. 높은 레벨로 시전하면 한 단계마다 피해가 1d8씩 늘어납니다.\", m = { cast = \"action\", kind = \"save\", save = \"Constitution\", on_save = \"half\", damage = \"2d8\", type = \"Thunder\", upcast = { dice = \"1d8\" }, area = true } },\r\n[\"Time Stop\"] = { level = 9, classes = {\"Sorcerer\", \"Wizard\"}, school = \"변환학파\", time = \"행동\", range = \"자신\", dur = \"즉시\", cmp = \"V\", ko = \"잠깐 동안 나를 뺀 모두의 시간을 멈춥니다. 다른 생물에게는 시간이 흐르지 않는 사이, 나는 1d4 + 1턴을 잇달아 가지며 평소처럼 행동하고 움직입니다. 그동안 내 행동이나 내가 만든 효과가 나 아닌 생물이나 남이 들거나 입은 물건에 영향을 주면 주문이 끝나고, 시전한 곳에서 1,000피트 넘게 떨어진 곳으로 가도 끝납니다.\", m = { cast = \"action\", kind = \"utility\" } },\r\n[\"Tiny Hut\"] = { level = 3, classes = {\"Bard\", \"Wizard\"}, ritual = true, school = \"방출학파\", time = \"1분 · 의식 가능\", range = \"자신\", dur = \"8시간\", cmp = \"VS\", ko = \"나를 중심으로 10피트에 막이 생겨, 8시간 동안 그 자리에 머뭅니다(범위 안의 생물이 다 들어갈 만큼 넓지 않으면 주문이 실패함). 시전할 때 안에 있던 생물과 물건은 자유롭게 드나들 수 있고, 나머지는 막을 통과하지 못합니다. 3레벨 이하 주문은 막 너머로 시전할 수 없고, 그런 주문의 효과도 안으로 들어오지 못합니다. 안은 바깥 날씨와 상관없이 쾌적하고 건조하며, 주문이 이어지는 동안 행동 없이 안을 희미한 빛이나 어둠으로 정할 수 있습니다. 밖에서는 막이 내가 고른 색으로 보여 안이 들여다보이지 않고, 안에서는 밖이 보입니다. 내가 막 밖으로 나가거나 이 주문을 다시 시전하면 주문이 끝납니다. 시전에 1분이 걸리고, 의식으로 시전할 수 있습니다.\", m = { cast = \"1 minute\", kind = \"utility\" } },\r\n[\"Tongues\"] = { level = 3, classes = {\"Bard\", \"Cleric\", \"Sorcerer\", \"Warlock\", \"Wizard\"}, school = \"예지학파\", time = \"행동\", range = \"접촉\", dur = \"1시간\", cmp = \"V\", ko = \"내가 만진 생물이 1시간 동안 듣거나 보는 모든 말과 수어를 알아듣고, 그 생물이 말하거나 수어를 하면 언어를 하나라도 아는 생물은 그 말을 듣거나 수어를 보는 한 모두 알아듣습니다.\", m = { cast = \"action\", kind = \"utility\" } },\r\n[\"Transport via Plants\"] = { level = 6, classes = {\"Druid\"}, school = \"조형학파\", time = \"행동\", range = \"10피트\", dur = \"1분\", cmp = \"VS\", ko = \"10피트 안에 있는 대형 이상의 식물(생물이 아닌 것) 하나를, 같은 세계 어디에 있든 다른 식물 하나와 1분 동안 마법으로 이어 줍니다. 목적지 식물은 전에 한 번이라도 보거나 만진 적이 있어야 합니다. 그동안 누구든 이동 5피트를 써서 이쪽 식물로 들어가 목적지 식물로 나올 수 있습니다.\", m = { cast = \"action\", kind = \"utility\" } },\r\n[\"Tree Stride\"] = { level = 5, classes = {\"Druid\", \"Ranger\"}, concentration = true, school = \"조형학파\", time = \"행동\", range = \"자신\", dur = \"집중, 최대 1분\", cmp = \"VS\", mins = 1, ko = \"주문이 이어지는 동안 나무에 들어가, 500피트 안에 있는 같은 종류의 다른 나무 속으로 옮겨 갈 수 있게 됩니다. 두 나무 모두 살아 있고 적어도 나만큼은 커야 합니다. 이동 5피트를 써서 나무에 들어가면 500피트 안에 있는 같은 종류 나무의 위치를 모두 알게 되고, 그 이동으로 그중 한 나무로 건너가거나 들어간 나무에서 다시 나올 수 있습니다. 건너간 나무에서는 이동 5피트를 더 써서 그 나무 5피트 안의 원하는 곳에 나타나고, 남은 이동이 없으면 들어간 나무 5피트 안에 나타납니다. 이 이동은 내 턴마다 한 번만 쓸 수 있고, 턴은 나무 밖에서 끝내야 합니다. 집중, 최대 1분.\", m = { cast = \"action\", kind = \"utility\", concentration = true } },\r\n[\"True Polymorph\"] = { level = 9, classes = {\"Bard\", \"Warlock\", \"Wizard\"}, save = \"Wisdom\", concentration = true, school = \"변환학파\", time = \"행동\", range = \"30피트\", dur = \"집중, 최대 1시간\", cmp = \"VS\", mins = 60, ko = \"30피트 안에 보이는 생물이나 마법 아닌 물건 하나를 바꿉니다. 생물은 다른 생물이나 마법 아닌 물건으로, 물건(아무도 들거나 입지 않은 것)은 생물로 바꿀 수 있습니다. 원치 않는 생물은 지혜 내성 굴림을 해서 성공하면 영향받지 않습니다. 생물을 다른 생물로 바꾸면, 도전 지수가 대상의 도전 지수(또는 레벨) 이하인 생물 가운데 고른 것이 됩니다. 능력치는 새 형태의 것이 되지만 생명력·성향·성격은 그대로이고, 새 형태의 생명력만큼 임시 생명력을 얻습니다(주문이 끝날 때 남은 것은 사라짐). 그 몸으로 할 수 있는 일만 할 수 있고 말하거나 주문을 쓰지 못하며, 장비는 몸에 녹아들어 쓸 수 없습니다. 물건을 생물로 바꾸면 물건보다 크지 않고 도전 지수 9 이하인 생물이 되며, 나와 동료에게 우호적이고, 싸움에서는 내 턴 바로 뒤에 움직이며 내 명령을 따릅니다(주문이 1시간 넘게 이어지면 더는 부리지 못함). 생물을 물건으로 바꾸면 입고 지닌 것과 함께 생물보다 크지 않은 물건이 되고, 원래대로 돌아온 뒤 그동안의 일을 기억하지 못합니다. 대상이 죽거나 부서지면 주문이 끝나고, 1시간 내내 집중을 이어 가면 해제될 때까지 그대로 남습니다. 집중, 최대 1시간.\", m = { cast = \"action\", kind = \"save\", save = \"Wisdom\", on_save = \"none\", concentration = true, lrfx = {}, fail = \"a creature becomes another creature (CR up to its own or level) or an object, or an object a creature of CR 9 or lower; permanent after a full hour\" } },\r\n[\"True Resurrection\"] = { level = 9, classes = {\"Cleric\", \"Druid\"}, school = \"사령학파\", time = \"1시간\", range = \"접촉\", dur = \"즉시\", cmp = \"VS\", ko = \"죽은 지 200년이 안 된 생물을 만져 되살립니다. 늙어 죽은 것만 아니라면 어떻게 죽었든 됩니다. 생명력을 모두 채운 채 돌아오고, 상처가 모두 아물며, 독과 마법 역병이 사라지고, 죽을 때 걸려 있던 저주도 풀립니다. 다치거나 잃은 장기와 팔다리도 되돌아오고, 언데드였다면 언데드가 아닌 본래 모습으로 돌아옵니다. 원래 몸이 남아 있지 않으면 그 생물의 이름을 불러 새 몸을 줄 수 있고, 그 생물은 내 10피트 안에서 내가 고른 빈 곳에 나타납니다. 시전에 1시간이 걸립니다.\", cost = \"diamonds worth 25,000+ GP, consumed\", cost_ko = \"25,000 GP 이상의 다이아몬드 (시전하면 사라짐)\", m = { cast = \"1 hour\", kind = \"utility\", raise = { hp = \"max\", within = 105120000 } } },\r\n[\"True Seeing\"] = { level = 6, classes = {\"Bard\", \"Cleric\", \"Sorcerer\", \"Warlock\", \"Wizard\"}, school = \"예지학파\", time = \"행동\", range = \"접촉\", dur = \"1시간\", cmp = \"VS\", ko = \"동의한 생물 하나를 만지면, 그 생물이 1시간 동안 120피트까지 보는 진시야를 얻습니다. 진시야로는 보통 어둠과 마법적 어둠 속을 보고, 투명한 것을 보며, 눈에 보이는 환영을 알아채고, 변신한 것의 본모습과 에테르계까지 봅니다.\", cost = \"mushroom powder worth 25+ GP, consumed\", cost_ko = \"25 GP 이상의 버섯 가루 (시전하면 사라짐)\", bmins = 60, m = { cast = \"action\", kind = \"buff\", targets = 1 } },\r\n[\"True Strike\"] = { level = 0, classes = {\"Bard\", \"Sorcerer\", \"Warlock\", \"Wizard\"}, school = \"예지학파\", time = \"행동\", range = \"자신\", dur = \"즉시\", cmp = \"S\", ko = \"번뜩이는 마법의 직감에 이끌려, 시전에 쓴 무기로 공격을 한 번 합니다. 이 공격은 근력이나 민첩 대신 주문시전 능력치로 명중과 피해를 굴리고, 피해를 광휘 피해나 무기의 원래 피해 종류 가운데 골라 줄 수 있습니다. 5·11·17레벨에는 어느 쪽을 골랐든 광휘 피해가 1d6·2d6·3d6 더해집니다.\", m = { cast = \"action\", kind = \"attack\", attack = \"weapon\", cantrip = false, say = \"one attack with the weapon used in the casting, with the spellcasting ability instead of Strength or Dexterity for its attack and damage; it may deal Radiant instead of its type, +1d6 Radiant at character level 5 (2d6 at 11, 3d6 at 17). Write it as that weapon's ATTACK: Lua checks the weapon's own bonus and formula, so the ability swap and the extra Radiant are not counted yet\" } },\r\n[\"Tsunami\"] = { level = 8, classes = {\"Druid\"}, save = \"Strength\", half_on_save = true, damage = \"6d10\", damage_type = \"Bludgeoning\", concentration = true, school = \"조형학파\", time = \"1분\", range = \"1마일\", dur = \"집중, 최대 6라운드\", cmp = \"VS\", mins = 1, ko = \"1마일 안의 고른 지점에 길이 300피트·높이 300피트·두께 50피트까지의 물벽을 세웁니다. 물벽이 나타날 때 그 안의 생물은 근력 내성 굴림을 해서, 실패하면 타격 피해 6d10, 성공하면 그 절반을 받습니다. 그 뒤 내 턴이 시작될 때마다 물벽은 안의 생물과 함께 나에게서 50피트 멀어지고, 물벽 안에 있거나 물벽이 덮치는 거대형 이하 생물은 근력 내성 굴림에 실패하면 타격 피해 5d10을 받습니다(라운드마다 한 번). 그 턴이 끝날 때마다 물벽의 높이가 50피트씩 낮아지고 이후 피해도 1d10씩 줄어들며, 높이가 0이 되면 주문이 끝납니다. 물벽에 휩쓸린 생물은 헤엄쳐 움직일 수 있지만, 물살이 거세서 근력(운동) 판정으로 내 주문 내성 난이도 이상이 나와야 조금이라도 움직일 수 있고, 물벽 밖으로 나가면 땅에 떨어집니다. 시전에 1분이 걸립니다. 집중, 최대 6라운드.\", m = { cast = \"1 minute\", kind = \"save\", save = \"Strength\", on_save = \"half\", damage = \"6d10\", type = \"Bludgeoning\", concentration = true, area = true } },\r\n[\"Unseen Servant\"] = { level = 1, classes = {\"Bard\", \"Warlock\", \"Wizard\"}, ritual = true, school = \"조형학파\", time = \"행동 · 의식 가능\", range = \"60피트\", dur = \"1시간\", cmp = \"VS\", ko = \"60피트 안의 땅 위 빈 곳에, 보이지 않고 생각도 모양도 없는 중형 역장 하인을 불러 1시간 동안 부립니다(방어도 10, 생명력 1, 근력 2, 공격하지 못하고, 생명력이 0이 되면 주문이 끝남). 내 턴마다 한 번 추가 행동으로 마음속 명령을 내리면, 하인은 15피트까지 움직여 물건 나르기·청소·수선·옷 개기·불 피우기·음식 내오기·술 따르기처럼 사람이 할 만한 단순한 일을 합니다. 명령을 받으면 그 일을 마칠 때까지 힘껏 하고, 마친 뒤에는 다음 명령을 기다립니다. 나에게서 60피트 넘게 떨어지게 되는 일을 시키면 주문이 끝납니다. 의식으로 시전할 수 있습니다.\", m = { cast = \"action\", kind = \"utility\" } },\r\n[\"Vampiric Touch\"] = { level = 3, classes = {\"Sorcerer\", \"Warlock\", \"Wizard\"}, attack = \"melee\", damage = \"3d6\", damage_type = \"Necrotic\", concentration = true, school = \"사령학파\", time = \"행동\", range = \"자신\", dur = \"집중, 최대 1분\", cmp = \"VS\", mins = 1, ko = \"그림자에 휘감긴 손으로, 닿는 거리의 생물 하나에게 근접 주문 공격을 합니다. 맞으면 사령 피해 3d6을 주고, 준 사령 피해의 절반만큼 내가 생명력을 되찾습니다. 주문이 이어지는 동안 내 턴마다 마법 행동으로 같은 생물이나 다른 생물에게 다시 공격할 수 있습니다. 집중, 최대 1분. 높은 레벨로 시전하면 한 단계마다 피해가 1d6씩 늘어납니다.\", m = { cast = \"action\", kind = \"attack\", attack = \"melee\", damage = \"3d6\", type = \"Necrotic\", concentration = true, upcast = { dice = \"1d6\" } } },\r\n[\"Vicious Mockery\"] = { level = 0, classes = {\"Bard\"}, save = \"Wisdom\", damage = \"1d6\", damage_type = \"Psychic\", school = \"환혹학파\", time = \"행동\", range = \"60피트\", dur = \"즉시\", cmp = \"V\", ko = \"60피트 안에서 보이거나 들리는 생물 하나에게, 은근한 마법이 실린 욕설을 퍼붓습니다. 대상은 지혜 내성 굴림을 하고, 실패하면 정신 피해 1d6을 받고 자기 다음 턴이 끝나기 전에 하는 다음 명중 굴림에 불리점을 받습니다. 5·11·17레벨에 피해 주사위가 하나씩 늘어납니다.\", m = { cast = \"action\", kind = \"save\", save = \"Wisdom\", on_save = \"none\", damage = \"1d6\", type = \"Psychic\", cantrip = true } },\r\n[\"Vitriolic Sphere\"] = { level = 4, classes = {\"Sorcerer\", \"Wizard\"}, save = \"Dexterity\", damage = \"10d4\", damage_type = \"Acid\", school = \"방출학파\", time = \"행동\", range = \"150피트\", dur = \"즉시\", cmp = \"VS\", ko = \"150피트 안의 한 곳을 가리키면, 지름 1피트의 빛나는 산성 구슬이 날아가 반경 20피트 구체로 터집니다. 그 안의 생물은 모두 민첩 내성 굴림을 해서, 실패하면 산성 피해 10d4를 받고 자기 다음 턴이 끝날 때 산성 피해 5d4를 더 받습니다. 성공하면 처음 피해의 절반만 받고, 나중 피해는 받지 않습니다. 높은 레벨로 시전하면 한 단계마다 처음 피해가 2d4씩 늘어납니다.\", m = { cast = \"action\", kind = \"save\", save = \"Dexterity\", on_save = \"half\", damage = \"10d4\", type = \"Acid\", upcast = { dice = \"2d4\" }, area = true } },\r\n[\"Wall of Fire\"] = { level = 4, classes = {\"Druid\", \"Sorcerer\", \"Wizard\"}, save = \"Dexterity\", half_on_save = true, damage = \"5d8\", damage_type = \"Fire\", concentration = true, school = \"방출학파\", time = \"행동\", range = \"120피트\", dur = \"집중, 최대 1분\", cmp = \"VS\", mins = 1, ko = \"120피트 안의 단단한 면 위에, 길이 60피트·높이 20피트·두께 1피트까지의 불 벽이나, 지름 20피트·높이 20피트·두께 1피트까지의 고리 모양 불 벽을 세웁니다. 벽은 불투명하고 주문이 이어지는 동안 남습니다. 벽이 나타날 때 그 자리의 생물은 민첩 내성 굴림을 해서, 실패하면 화염 피해 5d8, 성공하면 그 절반을 받습니다. 시전할 때 고른 한쪽 면은, 그 면 10피트 안이나 벽 속에서 턴을 끝내는 생물과 턴 중 처음 벽 속에 들어오는 생물에게 화염 피해 5d8을 줍니다. 다른 쪽 면은 피해를 주지 않습니다. 집중, 최대 1분. 높은 레벨로 시전하면 한 단계마다 피해가 1d8씩 늘어납니다.\", m = { cast = \"action\", kind = \"save\", save = \"Dexterity\", on_save = \"half\", damage = \"5d8\", type = \"Fire\", concentration = true, upcast = { dice = \"1d8\" }, area = true } },\r\n[\"Wall of Force\"] = { level = 5, classes = {\"Wizard\"}, concentration = true, school = \"방출학파\", time = \"행동\", range = \"120피트\", dur = \"집중, 최대 10분\", cmp = \"VS\", mins = 10, ko = \"120피트 안의 고른 지점에 보이지 않는 역장 벽을 세웁니다. 벽은 수평·수직·비스듬히 원하는 방향으로 둘 수 있고, 공중에 떠 있게 하거나 단단한 면 위에 세울 수 있습니다. 반경 10피트까지의 반구나 구로 만들거나, 10피트×10피트 판 열 개를 서로 잇대어 평면으로 만듭니다(어느 모양이든 두께 1/4인치). 벽이 나타날 때 생물이 걸쳐 있으면 내가 고른 쪽으로 밀려납니다. 어떤 것도 이 벽을 물리적으로 통과하지 못하고, 벽은 어떤 피해도 받지 않으며 마법 무효화로도 없앨 수 없습니다. 다만 분해 주문을 맞으면 곧바로 사라집니다. 벽은 에테르계까지 뻗어 그쪽으로 지나가는 것도 막습니다. 집중, 최대 10분.\", m = { cast = \"action\", kind = \"utility\", concentration = true } },\r\n[\"Wall of Ice\"] = { level = 6, classes = {\"Wizard\"}, save = \"Dexterity\", half_on_save = true, damage = \"10d6\", damage_type = \"Cold\", concentration = true, school = \"방출학파\", time = \"행동\", range = \"120피트\", dur = \"집중, 최대 10분\", cmp = \"VS\", mins = 10, ko = \"120피트 안의 단단한 면 위에 얼음 벽을 세웁니다. 반경 10피트까지의 반구나 구로 만들거나, 10피트 정사각형 판 열 개를 서로 잇대어 평면으로 만듭니다(어느 모양이든 두께 1피트). 벽이 나타날 때 생물이 걸쳐 있으면 내가 고른 쪽으로 밀려나며 민첩 내성 굴림을 해서, 실패하면 냉기 피해 10d6, 성공하면 그 절반을 받습니다. 벽은 부술 수 있는 물건으로, 10피트 구간마다 방어도 12, 생명력 30이고, 냉기·독성·정신 피해에 면역이며 화염 피해에 취약합니다. 생명력이 0이 된 구간은 부서지고 그 자리에 찬 공기 막이 남으며, 턴 중 처음 그 막을 지나는 생물은 건강 내성 굴림을 해서 실패하면 냉기 피해 5d6, 성공하면 그 절반을 받습니다. 집중, 최대 10분. 높은 레벨로 시전하면 한 단계마다 나타날 때의 피해가 2d6씩, 찬 공기 피해가 1d6씩 늘어납니다.\", m = { cast = \"action\", kind = \"save\", save = \"Dexterity\", on_save = \"half\", damage = \"10d6\", type = \"Cold\", concentration = true, upcast = { dice = \"2d6\" }, area = true } },\r\n[\"Wall of Stone\"] = { level = 5, classes = {\"Druid\", \"Sorcerer\", \"Wizard\"}, save = \"Dexterity\", concentration = true, school = \"방출학파\", time = \"행동\", range = \"120피트\", dur = \"집중, 최대 10분\", cmp = \"VS\", mins = 10, ko = \"120피트 안의 고른 지점에 마법이 아닌 단단한 돌벽을 세웁니다. 두께 6인치짜리 10피트×10피트 판 열 개를 서로 잇대어 만들거나, 두께 3인치짜리 10피트×20피트 판 열 개로 만듭니다. 벽은 원하는 모양으로 만들 수 있지만 생물이나 물건이 있는 곳에는 놓을 수 없고, 수직이거나 단단한 바닥 위에 있을 필요는 없지만 원래 있던 돌과 이어져 단단히 받쳐져야 합니다. 그래서 골짜기에 다리를 놓거나 경사로를 만들 수 있습니다(20피트 넘게 잇는 다리는 받침을 위해 판 크기를 절반으로). 벽이 나타날 때 생물이 걸쳐 있으면 내가 고른 쪽으로 밀려나고, 벽에 사방이 막히게 되는 생물은 민첩 내성 굴림에 성공하면 반응행동으로 속도만큼 움직여 빠져나갈 수 있습니다. 판마다 방어도 15, 두께 1인치마다 생명력 30이고 독성·정신 피해에 면역입니다. 생명력이 0이 된 판은 부서지고, 이어진 판이 함께 무너질 수도 있습니다(GM이 정함). 10분 내내 집중을 이어 가면 벽은 영구히 남고 해제되지 않으며, 그러지 않으면 주문이 끝날 때 사라집니다. 집중, 최대 10분.\", m = { cast = \"action\", kind = \"utility\", concentration = true } },\r\n[\"Wall of Thorns\"] = { level = 6, classes = {\"Druid\"}, save = \"Dexterity\", half_on_save = true, damage = \"7d8\", damage_type = \"Piercing\", concentration = true, school = \"조형학파\", time = \"행동\", range = \"120피트\", dur = \"집중, 최대 10분\", cmp = \"VS\", mins = 10, ko = \"120피트 안의 단단한 면 위에, 바늘 같은 가시가 돋은 엉킨 덤불 벽을 세웁니다. 길이 60피트·높이 10피트·두께 5피트까지의 벽이나, 지름 20피트·높이 20피트·두께 5피트까지의 고리 모양 가운데 고르고, 벽은 시야를 가립니다. 벽이 나타날 때 그 안의 생물은 민첩 내성 굴림을 해서, 실패하면 관통 피해 7d8, 성공하면 그 절반을 받습니다. 벽은 느리고 아프게나마 지나갈 수 있어서, 1피트 나아갈 때마다 이동 4피트가 듭니다. 또 턴 중 처음 벽 안에 들어오거나 그곳에서 턴을 끝내는 생물은 민첩 내성 굴림을 해서, 실패하면 참격 피해 7d8, 성공하면 그 절반을 받습니다(턴마다 한 번). 집중, 최대 10분. 높은 레벨로 시전하면 한 단계마다 두 피해가 모두 1d8씩 늘어납니다.\", m = { cast = \"action\", kind = \"save\", save = \"Dexterity\", on_save = \"half\", damage = \"7d8\", type = \"Piercing\", concentration = true, upcast = { dice = \"1d8\" }, area = true } },\r\n[\"Warding Bond\"] = { level = 2, classes = {\"Cleric\", \"Paladin\"}, school = \"방호학파\", time = \"행동\", range = \"접촉\", dur = \"1시간\", cmp = \"VS\", ko = \"나 말고 동의한 생물 하나를 만져, 1시간 동안 나와 신비로운 유대를 맺습니다. 그 생물은 내 60피트 안에 있는 동안 방어도와 내성 굴림에 +1을 받고 모든 피해에 저항을 얻지만, 그 생물이 피해를 받을 때마다 나도 같은 양의 피해를 받습니다. 내 생명력이 0이 되거나, 둘이 60피트 넘게 떨어지거나, 둘 중 누구에게든 이 주문을 다시 걸면 끝납니다.\", cost = \"a pair of platinum rings worth 50+ GP each, which you and the target must wear for the duration\", cost_ko = \"하나에 50 GP 이상인 백금 반지 한 쌍 (나와 대상이 주문 내내 낌)\", bmins = 60, m = { cast = \"action\", kind = \"buff\", ac_bonus = 1, resist = {\"Acid\", \"Bludgeoning\", \"Cold\", \"Fire\", \"Force\", \"Lightning\", \"Necrotic\", \"Piercing\", \"Poison\", \"Psychic\", \"Radiant\", \"Slashing\", \"Thunder\"}, targets = 1 } },\r\n[\"Water Breathing\"] = { level = 3, classes = {\"Druid\", \"Ranger\", \"Sorcerer\", \"Wizard\"}, ritual = true, school = \"변환학파\", time = \"행동 · 의식 가능\", range = \"30피트\", dur = \"24시간\", cmp = \"VS\", ko = \"30피트 안의 동의한 생물을 열까지 골라, 24시간 동안 물속에서 숨 쉴 수 있게 합니다. 원래 숨 쉬던 방식으로도 그대로 숨 쉽니다. 의식으로 시전할 수 있습니다.\", m = { cast = \"action\", kind = \"utility\" } },\r\n[\"Water Walk\"] = { level = 3, classes = {\"Cleric\", \"Druid\", \"Ranger\", \"Sorcerer\"}, ritual = true, school = \"변환학파\", time = \"행동 · 의식 가능\", range = \"30피트\", dur = \"1시간\", cmp = \"VS\", ko = \"30피트 안의 동의한 생물을 열까지 골라, 1시간 동안 물·산·진흙·눈·모래 늪·용암 같은 액체 위를 안전한 땅처럼 걸을 수 있게 합니다(용암 위에서는 열기 피해를 받을 수 있음). 수면에서 액체 속으로 들어가거나 액체 속에서 수면으로 올라오려면 추가 행동을 써야 하고, 높은 곳에서 떨어지면 수면을 뚫고 그대로 빠집니다. 의식으로 시전할 수 있습니다.\", m = { cast = \"action\", kind = \"utility\" } },\r\n[\"Web\"] = { level = 2, classes = {\"Sorcerer\", \"Wizard\"}, save = \"Dexterity\", damage = \"2d4\", damage_type = \"Fire\", concentration = true, school = \"조형학파\", time = \"행동\", range = \"60피트\", dur = \"집중, 최대 1시간\", cmp = \"VS\", mins = 60, ko = \"60피트 안의 한 지점에 끈적한 거미줄 덩어리를 불러, 주문이 이어지는 동안 20피트 정육면체를 채웁니다. 거미줄은 어려운 지형이고, 그 안은 살짝 가려집니다. 벽이나 나무 같은 두 단단한 것 사이에 걸치거나 바닥·벽·천장에 덮여 있지 않으면, 거미줄은 무너져 다음 내 턴이 시작될 때 주문이 끝납니다(평평한 면에 덮인 거미줄은 깊이 5피트). 턴 중 처음 거미줄에 들어오거나 그 안에서 턴을 시작하는 생물은 민첩 내성 굴림을 하고, 실패하면 거미줄 안에 있는 동안, 또는 빠져나올 때까지 포박 상태가 됩니다. 포박된 생물은 행동을 써서 근력(운동) 판정을 하고, 내 주문 내성 난이도 이상이 나오면 풀려납니다. 거미줄은 불에 타서, 불이 닿은 5피트 정육면체만큼의 거미줄은 1라운드 만에 타 버리고, 그 불 속에서 턴을 시작하는 생물에게 화염 피해 2d4를 줍니다. 집중, 최대 1시간.\", m = { cast = \"action\", kind = \"save\", save = \"Dexterity\", on_save = \"none\", concentration = true, lrfx = {\"Restrained\"}, area = true, fail = \"Restrained; Difficult Terrain, Lightly Obscured; burns (2d4 Fire)\" } },\r\n[\"Weird\"] = { level = 9, classes = {\"Warlock\", \"Wizard\"}, save = \"Wisdom\", half_on_save = true, damage = \"10d10\", damage_type = \"Psychic\", concentration = true, school = \"환영학파\", time = \"행동\", range = \"120피트\", dur = \"집중, 최대 1분\", cmp = \"VS\", mins = 1, ko = \"120피트 안의 한 지점을 중심으로 반경 30피트 구체 안에서 고른 생물들의 머릿속에 무시무시한 환영을 지어냅니다. 각 대상은 지혜 내성 굴림을 해서, 실패하면 정신 피해 10d10을 받고 주문이 이어지는 동안 공포 상태가 되며, 성공하면 피해만 절반 받습니다. 공포 상태인 대상은 자기 턴이 끝날 때마다 지혜 내성 굴림을 해서, 실패하면 정신 피해 5d10을 받고, 성공하면 그 대상에게는 주문이 끝납니다. 집중, 최대 1분.\", m = { cast = \"action\", kind = \"save\", save = \"Wisdom\", on_save = \"half\", damage = \"10d10\", type = \"Psychic\", concentration = true, lrfx = {\"Frightened\"} } },\r\n[\"Wind Walk\"] = { level = 6, classes = {\"Druid\"}, school = \"변환학파\", time = \"1분\", range = \"30피트\", dur = \"8시간\", cmp = \"VS\", ko = \"나와, 30피트 안에서 고른 함께 가려는 생물 열까지가 8시간 동안 구름 같은 기체 모습이 됩니다. 그동안 비행 속도 300피트로 날고 공중에 떠 있을 수 있으며, 넘어진 상태에 면역이고, 타격·관통·참격 피해에 저항합니다. 그 모습으로는 질주 행동, 또는 원래 모습으로 돌아가기 시작하는 마법 행동밖에 할 수 없습니다. 돌아가는 데 1분이 걸리고 그동안 충격 상태가 되며, 주문이 끝나기 전이라면 같은 방법(마법 행동 뒤 1분)으로 다시 구름이 될 수 있습니다. 날고 있는 중에 효과가 끝나면 1분 동안 라운드마다 60피트씩 안전하게 내려앉고, 그래도 땅에 닿지 못하면 남은 높이만큼 떨어집니다. 시전에 1분이 걸립니다.\", bmins = 480, m = { cast = \"1 minute\", kind = \"buff\", resist = {\"Bludgeoning\", \"Piercing\", \"Slashing\"}, btargets = 11 } },\r\n[\"Wind Wall\"] = { level = 3, classes = {\"Druid\", \"Ranger\"}, save = \"Strength\", half_on_save = true, damage = \"4d8\", damage_type = \"Bludgeoning\", concentration = true, school = \"방출학파\", time = \"행동\", range = \"120피트\", dur = \"집중, 최대 1분\", cmp = \"VS\", mins = 1, ko = \"120피트 안의 고른 땅에서, 길이 50피트·높이 15피트·두께 1피트까지의 거센 바람 벽이 솟아 주문이 이어지는 동안 남습니다. 땅을 따라 한 줄로 이어지기만 하면 모양은 마음대로입니다. 벽이 나타날 때 그 자리의 생물은 근력 내성 굴림을 해서, 실패하면 타격 피해 4d8, 성공하면 그 절반을 받습니다. 바람은 안개·연기·다른 기체를 막아 내고, 기체 형상인 생물이나 소형 이하의 날아다니는 생물·물건은 벽을 지나가지 못하며, 벽에 들어온 가벼운 물건은 위로 날려 갑니다. 벽 너머를 노리고 쏜 화살·볼트 같은 평범한 투사체는 위로 휘어 자동으로 빗나가지만, 거인이 던진 바위나 공성 병기의 투사체 같은 것은 영향받지 않습니다. 집중, 최대 1분.\", m = { cast = \"action\", kind = \"save\", save = \"Strength\", on_save = \"half\", damage = \"4d8\", type = \"Bludgeoning\", concentration = true, area = true } },\r\n[\"Wish\"] = { level = 9, classes = {\"Sorcerer\", \"Wizard\"}, damage = \"1d10\", damage_type = \"Necrotic\", school = \"조형학파\", time = \"행동\", range = \"자신\", dur = \"즉시\", cmp = \"V\", ko = \"필멸자가 쓸 수 있는 가장 강한 주문으로, 말만으로 현실을 바꿉니다. 기본으로는 8레벨 이하 주문 하나를 그대로 일으키며, 이때는 값비싼 재료를 포함해 그 주문의 어떤 조건도 갖추지 않아도 됩니다. 아니면 다음 효과 가운데 하나를 고릅니다. 물건 만들기는 마법 물건이 아닌 25,000 GP 이하의 물건 하나(어느 쪽으로도 300피트 이하)를 보이는 땅 위 빈 곳에 만듭니다. 즉시 회복은 나와 보이는 생물 스물까지의 생명력을 모두 되찾게 하고, 상급 회복이 없애는 효과를 모두 풉니다. 저항은 보이는 생물 열까지에게 고른 피해 종류 하나에 대한 영구한 저항을 줍니다. 주문 면역은 보이는 생물 열까지에게 8시간 동안 주문이나 마법 효과 하나에 대한 면역을 줍니다. 갑작스러운 배움은 내 재주 하나를 조건을 갖춘 다른 재주로 바꿉니다(다른 재주나 기능의 전제 조건인 재주는 안 됨). 다시 굴리기는 지난 라운드 안에 굴린 주사위 하나를 다시 굴리게 하고(이점이나 불리점을 붙일 수 있음), 원래 값과 새 값 가운데 하나를 고릅니다. 현실 바꾸기는 그 밖의 소원을 GM에게 되도록 정확히 말하면 GM이 결과를 정하는데, 소원이 클수록 어긋나거나 일부만 이뤄지거나 뜻밖의 대가가 따르기 쉽습니다. 다른 주문을 흉내 내는 것 말고 다른 효과를 내면 그 부담으로 몸이 약해져, 긴 휴식을 마칠 때까지 주문을 시전할 때마다 그 주문 레벨당 사령 피해 1d10을 받고(줄이거나 막을 수 없음), 2d4일 동안 근력이 3이 됩니다(가볍게 쉬며 보낸 날마다 남은 회복 기간이 2일씩 줄어듦). 또 33% 확률로 다시는 소원을 시전하지 못하게 됩니다.\", m = { cast = \"action\", kind = \"utility\" } },\r\n[\"Word of Recall\"] = { level = 6, classes = {\"Cleric\"}, school = \"조형학파\", time = \"행동\", range = \"5피트\", dur = \"즉시\", cmp = \"V\", ko = \"나와, 5피트 안에서 함께 가려는 생물 다섯까지가 미리 정해 둔 성소로 곧바로 순간이동합니다. 모두 성소를 정할 때 지정해 둔 자리에서 가장 가까운 빈 곳에 나타납니다. 성소는 신전 같은 곳에서 이 주문을 시전해 미리 정해 두어야 하며, 정해 둔 성소가 없으면 아무 효과가 없습니다.\", m = { cast = \"action\", kind = \"utility\" } },\r\n[\"Zone of Truth\"] = { level = 2, classes = {\"Bard\", \"Cleric\", \"Paladin\"}, save = \"Charisma\", school = \"환혹학파\", time = \"행동\", range = \"60피트\", dur = \"10분\", cmp = \"VS\", ko = \"60피트 안의 한 지점을 중심으로 반경 15피트 구체에, 거짓을 막는 마법 구역을 10분 동안 만듭니다. 턴 중 처음 그 안에 들어오거나 그 안에서 턴을 시작하는 생물은 매력 내성 굴림을 하고, 실패하면 그 안에 있는 동안 일부러 거짓말을 할 수 없습니다. 나는 각 생물이 내성에 성공했는지 실패했는지 압니다. 걸린 생물은 주문에 걸린 것을 알고, 거짓으로 답할 만한 질문에는 대답을 피하거나 둘러댈 수 있지만, 하는 말은 참이어야 합니다.\", m = { cast = \"action\", kind = \"save\", save = \"Charisma\", on_save = \"none\", lrfx = {}, area = true, fail = \"can't speak a deliberate lie\" } },\r\n}\r\n\r\nlocal ITEMS = { Club = true, Dagger = true, Greatclub = true, Handaxe = true, Javelin = true, [\"Light Hammer\"] = true, Mace = true, Quarterstaff = true, Sickle = true, Spear = true, Dart = true, [\"Light Crossbow\"] = true, Shortbow = true, Sling = true, Battleaxe = true, Flail = true, Glaive = true, Greataxe = true, Greatsword = true, Halberd = true, Lance = true, Longsword = true, Maul = true, Morningstar = true, Pike = true, Rapier = true, Scimitar = true, Shortsword = true, Trident = true, Warhammer = true, [\"War Pick\"] = true, Whip = true, Blowgun = true, [\"Hand Crossbow\"] = true, [\"Heavy Crossbow\"] = true, Longbow = true, Musket = true, Pistol = true, [\"Padded Armor\"] = true, [\"Leather Armor\"] = true, [\"Studded Leather Armor\"] = true, [\"Hide Armor\"] = true, [\"Chain Shirt\"] = true, [\"Scale Mail\"] = true, Breastplate = true, [\"Half Plate Armor\"] = true, [\"Ring Mail\"] = true, [\"Chain Mail\"] = true, [\"Splint Armor\"] = true, [\"Plate Armor\"] = true, Shield = true, [\"Potion of Healing\"] = true, [\"Potion of Greater Healing\"] = true, [\"Potion of Superior Healing\"] = true, [\"Potion of Supreme Healing\"] = true, [\"Healer's Kit\"] = true, Antitoxin = true, [\"Alchemist's Fire\"] = true, Acid = true, [\"Holy Water\"] = true, Arrows = true, Bolts = true, [\"Firearm Bullets\"] = true, [\"Sling Bullets\"] = true, Needles = true, Oil = true, [\"Basic Poison\"] = true }\r\n\r\nlocal WEAPONS = { Club = { dmg = \"1d4\", martial = false, ranged = false, type = \"Bludgeoning\", mastery = \"Slow\", light = true, gloss = \"곤봉\" }, Dagger = { dmg = \"1d4\", martial = false, ranged = false, type = \"Piercing\", mastery = \"Nick\", finesse = true, light = true, thrown = true, gloss = \"단검\" }, Greatclub = { dmg = \"1d8\", martial = false, ranged = false, type = \"Bludgeoning\", mastery = \"Push\", two = true, gloss = \"대곤봉\" }, Handaxe = { dmg = \"1d6\", martial = false, ranged = false, type = \"Slashing\", mastery = \"Vex\", light = true, thrown = true, gloss = \"손도끼\" }, Javelin = { dmg = \"1d6\", martial = false, ranged = false, type = \"Piercing\", mastery = \"Slow\", thrown = true, gloss = \"투창\" }, [\"Light Hammer\"] = { dmg = \"1d4\", martial = false, ranged = false, type = \"Bludgeoning\", mastery = \"Nick\", light = true, thrown = true, gloss = \"경량 망치\" }, Mace = { dmg = \"1d6\", martial = false, ranged = false, type = \"Bludgeoning\", mastery = \"Sap\", gloss = \"철퇴\" }, Quarterstaff = { dmg = \"1d6\", martial = false, ranged = false, type = \"Bludgeoning\", mastery = \"Topple\", vers = \"1d8\", gloss = \"육척봉\" }, Sickle = { dmg = \"1d4\", martial = false, ranged = false, type = \"Slashing\", mastery = \"Nick\", light = true, gloss = \"낫\" }, Spear = { dmg = \"1d6\", martial = false, ranged = false, type = \"Piercing\", mastery = \"Sap\", thrown = true, vers = \"1d8\", gloss = \"창\" }, Dart = { dmg = \"1d4\", martial = false, ranged = true, type = \"Piercing\", mastery = \"Vex\", finesse = true, thrown = true }, [\"Light Crossbow\"] = { dmg = \"1d8\", martial = false, ranged = true, type = \"Piercing\", mastery = \"Slow\", two = true, loading = true, ammo = \"Bolts\", gloss = \"경석궁\" }, Shortbow = { dmg = \"1d6\", martial = false, ranged = true, type = \"Piercing\", mastery = \"Vex\", two = true, ammo = \"Arrows\", gloss = \"단궁\" }, Sling = { dmg = \"1d4\", martial = false, ranged = true, type = \"Bludgeoning\", mastery = \"Slow\", ammo = \"Sling Bullets\", gloss = \"돌팔매\" }, Battleaxe = { dmg = \"1d8\", martial = true, ranged = false, type = \"Slashing\", mastery = \"Topple\", vers = \"1d10\", gloss = \"전투도끼\" }, Flail = { dmg = \"1d8\", martial = true, ranged = false, type = \"Bludgeoning\", mastery = \"Sap\", gloss = \"도리깨\" }, Glaive = { dmg = \"1d10\", martial = true, ranged = false, type = \"Slashing\", mastery = \"Graze\", heavy = true, two = true, reach = true, gloss = \"장도\" }, Greataxe = { dmg = \"1d12\", martial = true, ranged = false, type = \"Slashing\", mastery = \"Cleave\", heavy = true, two = true, gloss = \"대도끼\" }, Greatsword = { dmg = \"2d6\", martial = true, ranged = false, type = \"Slashing\", mastery = \"Graze\", heavy = true, two = true, gloss = \"대검\" }, Halberd = { dmg = \"1d10\", martial = true, ranged = false, type = \"Slashing\", mastery = \"Cleave\", heavy = true, two = true, reach = true, gloss = \"미늘창\" }, Lance = { dmg = \"1d10\", martial = true, ranged = false, type = \"Piercing\", mastery = \"Topple\", heavy = true, two = true, reach = true, gloss = \"거창\" }, Longsword = { dmg = \"1d8\", martial = true, ranged = false, type = \"Slashing\", mastery = \"Sap\", vers = \"1d10\", gloss = \"장검\" }, Maul = { dmg = \"2d6\", martial = true, ranged = false, type = \"Bludgeoning\", mastery = \"Topple\", heavy = true, two = true, gloss = \"거대망치\" }, Morningstar = { dmg = \"1d8\", martial = true, ranged = false, type = \"Piercing\", mastery = \"Sap\" }, Pike = { dmg = \"1d10\", martial = true, ranged = false, type = \"Piercing\", mastery = \"Push\", heavy = true, two = true, reach = true, gloss = \"장창\" }, Rapier = { dmg = \"1d8\", martial = true, ranged = false, type = \"Piercing\", mastery = \"Vex\", finesse = true }, Scimitar = { dmg = \"1d6\", martial = true, ranged = false, type = \"Slashing\", mastery = \"Nick\", finesse = true, light = true, gloss = \"언월도\" }, Shortsword = { dmg = \"1d6\", martial = true, ranged = false, type = \"Piercing\", mastery = \"Vex\", finesse = true, light = true, gloss = \"소검\" }, Trident = { dmg = \"1d8\", martial = true, ranged = false, type = \"Piercing\", mastery = \"Topple\", thrown = true, vers = \"1d10\", gloss = \"삼지창\" }, Warhammer = { dmg = \"1d8\", martial = true, ranged = false, type = \"Bludgeoning\", mastery = \"Push\", vers = \"1d10\", gloss = \"전쟁망치\" }, [\"War Pick\"] = { dmg = \"1d8\", martial = true, ranged = false, type = \"Piercing\", mastery = \"Sap\", vers = \"1d10\", gloss = \"전쟁 곡괭이\" }, Whip = { dmg = \"1d4\", martial = true, ranged = false, type = \"Slashing\", mastery = \"Slow\", finesse = true, reach = true }, Blowgun = { dmg = \"1\", martial = true, ranged = true, type = \"Piercing\", mastery = \"Vex\", loading = true, ammo = \"Needles\", gloss = \"바람총\" }, [\"Hand Crossbow\"] = { dmg = \"1d6\", martial = true, ranged = true, type = \"Piercing\", mastery = \"Vex\", light = true, loading = true, ammo = \"Bolts\", gloss = \"손 석궁\" }, [\"Heavy Crossbow\"] = { dmg = \"1d10\", martial = true, ranged = true, type = \"Piercing\", mastery = \"Push\", heavy = true, two = true, loading = true, ammo = \"Bolts\", gloss = \"중석궁\" }, Longbow = { dmg = \"1d8\", martial = true, ranged = true, type = \"Piercing\", mastery = \"Slow\", heavy = true, two = true, ammo = \"Arrows\", gloss = \"장궁\" }, Musket = { dmg = \"1d12\", martial = true, ranged = true, type = \"Piercing\", mastery = \"Slow\", two = true, loading = true, ammo = \"Firearm Bullets\" }, Pistol = { dmg = \"1d10\", martial = true, ranged = true, type = \"Piercing\", mastery = \"Vex\", loading = true, ammo = \"Firearm Bullets\" } }\r\n\r\nlocal ARMOR = { [\"Padded Armor\"] = { cat = \"light\", base = 11, dex = \"full\", stealth = true }, [\"Leather Armor\"] = { cat = \"light\", base = 11, dex = \"full\" }, [\"Studded Leather Armor\"] = { cat = \"light\", base = 12, dex = \"full\" }, [\"Hide Armor\"] = { cat = \"medium\", base = 12, dex = \"max2\" }, [\"Chain Shirt\"] = { cat = \"medium\", base = 13, dex = \"max2\" }, [\"Scale Mail\"] = { cat = \"medium\", base = 14, dex = \"max2\", stealth = true }, Breastplate = { cat = \"medium\", base = 14, dex = \"max2\" }, [\"Half Plate Armor\"] = { cat = \"medium\", base = 15, dex = \"max2\", stealth = true }, [\"Ring Mail\"] = { cat = \"heavy\", base = 14, dex = \"none\", stealth = true }, [\"Chain Mail\"] = { cat = \"heavy\", base = 16, dex = \"none\", str = 13, stealth = true }, [\"Splint Armor\"] = { cat = \"heavy\", base = 17, dex = \"none\", str = 15, stealth = true }, [\"Plate Armor\"] = { cat = \"heavy\", base = 18, dex = \"none\", str = 15, stealth = true }, Shield = { cat = \"shield\", base = 2, dex = \"none\" } }\r\n\r\nlocal PRICE = { Club = 10, Dagger = 200, Greatclub = 20, Handaxe = 500, Javelin = 50, [\"Light Hammer\"] = 200, Mace = 500, Quarterstaff = 20, Sickle = 100, Spear = 100, Dart = 5, [\"Light Crossbow\"] = 2500, Shortbow = 2500, Sling = 10, Battleaxe = 1000, Flail = 1000, Glaive = 2000, Greataxe = 3000, Greatsword = 5000, Halberd = 2000, Lance = 1000, Longsword = 1500, Maul = 1000, Morningstar = 1500, Pike = 500, Rapier = 2500, Scimitar = 2500, Shortsword = 1000, Trident = 500, Warhammer = 1500, [\"War Pick\"] = 500, Whip = 200, Blowgun = 1000, [\"Hand Crossbow\"] = 7500, [\"Heavy Crossbow\"] = 5000, Longbow = 5000, Musket = 50000, Pistol = 25000, [\"Padded Armor\"] = 500, [\"Leather Armor\"] = 1000, [\"Studded Leather Armor\"] = 4500, [\"Hide Armor\"] = 1000, [\"Chain Shirt\"] = 5000, [\"Scale Mail\"] = 5000, Breastplate = 40000, [\"Half Plate Armor\"] = 75000, [\"Ring Mail\"] = 3000, [\"Chain Mail\"] = 7500, [\"Splint Armor\"] = 20000, [\"Plate Armor\"] = 150000, Shield = 1000, [\"Potion of Healing\"] = 5000, [\"Potion of Greater Healing\"] = 20000, [\"Potion of Superior Healing\"] = 200000, [\"Potion of Supreme Healing\"] = 2000000, [\"Healer's Kit\"] = 500, Antitoxin = 5000, [\"Alchemist's Fire\"] = 5000, Acid = 2500, [\"Holy Water\"] = 2500, Arrows = 5.0, Bolts = 5.0, [\"Firearm Bullets\"] = 30.0, [\"Sling Bullets\"] = 0.2, Needles = 2.0, Oil = 10, [\"Basic Poison\"] = 10000 }\r\n\r\nlocal CONDS = { Blinded = { attacks_against = \"advantage\", own_attacks = \"disadvantage\", fail_checks = \"sight\", en = \"fails checks that need sight; attacks against Player have Advantage; Player's attack rolls have Disadvantage\" }, Charmed = { cant_attack = \"charmer\", charmer_social = \"advantage\", en = \"cannot attack the charmer; the charmer has Advantage on social checks against Player\" }, Deafened = { fail_checks = \"hearing\", en = \"fails checks that need hearing\" }, Exhaustion = { d20_minus_per_level = 2, speed_minus_per_level = 5, dies_at = 6, long_rest_removes = 1, en = \"\" }, Frightened = { own_attacks = \"disadvantage\", own_checks = \"disadvantage\", [\"while\"] = \"source in sight\", cant_approach = true, en = \"Disadvantage on ability checks and attack rolls while the source is in sight; cannot willingly move closer to it\" }, Grappled = { speed = 0, own_attacks = \"disadvantage\", except_vs = \"grappler\", en = \"Speed 0; Disadvantage on attack rolls against anyone but the grappler\" }, Incapacitated = { no_actions = true, breaks_concentration = true, initiative = \"disadvantage\", en = \"no actions, Bonus Actions or Reactions; Concentration breaks\" }, Invisible = { attacks_against = \"disadvantage\", own_attacks = \"advantage\", initiative = \"advantage\", en = \"attacks against Player have Disadvantage; Player's attack rolls have Advantage\" }, Paralyzed = { incapacitated = true, speed = 0, auto_fail_saves = {\"Strength\", \"Dexterity\"}, attacks_against = \"advantage\", auto_crit_within_5ft = true, en = \"Incapacitated, Speed 0; fails Strength and Dexterity saves; attacks against Player have Advantage; a hit from within 5 feet is a Critical Hit\" }, Petrified = { incapacitated = true, speed = 0, auto_fail_saves = {\"Strength\", \"Dexterity\"}, attacks_against = \"advantage\", resist_all = true, en = \"Incapacitated, Speed 0; fails Strength and Dexterity saves; attacks against Player have Advantage; Resistance to all damage\" }, Poisoned = { own_attacks = \"disadvantage\", own_checks = \"disadvantage\", en = \"Disadvantage on attack rolls and ability checks\" }, Prone = { own_attacks = \"disadvantage\", attacks_against_within_5ft = \"advantage\", attacks_against_beyond_5ft = \"disadvantage\", stand_up_cost = \"half speed\", en = \"Disadvantage on attack rolls; attacks against Player have Advantage within 5 feet, Disadvantage beyond; standing up costs half the Speed\" }, Restrained = { speed = 0, attacks_against = \"advantage\", own_attacks = \"disadvantage\", dex_saves = \"disadvantage\", en = \"Speed 0; Disadvantage on attack rolls and Dexterity saves; attacks against Player have Advantage\" }, Stunned = { incapacitated = true, auto_fail_saves = {\"Strength\", \"Dexterity\"}, attacks_against = \"advantage\", en = \"Incapacitated; fails Strength and Dexterity saves; attacks against Player have Advantage\" }, Unconscious = { incapacitated = true, prone = true, speed = 0, auto_fail_saves = {\"Strength\", \"Dexterity\"}, attacks_against = \"advantage\", auto_crit_within_5ft = true, en = \"Incapacitated, Prone, Speed 0; fails Strength and Dexterity saves; attacks against Player have Advantage; a hit from within 5 feet is a Critical Hit\" } }\r\n\r\nK.DICT = { intro = \"SRD 5.2.1 규칙을 짧게 줄였습니다. 묶음을 누르면 펼쳐집니다. 이 탭은 화면에만 있고 AI에게는 보내지 않습니다.\", groups = {{\"한 턴에 할 수 있는 것\", {{\"라운드\", \"Round\", \"모두가 한 번씩 턴을 가지는 약 6초입니다. 순서는 우선권으로 정하고, 라운드가 바뀌어도 그대로입니다.\"}, {\"이동\", \"Movement\", \"속도만큼 움직입니다. 행동 앞뒤로 나눠 써도 됩니다(10피트 가서 공격하고 20피트 더).\"}, {\"행동\", \"Action\", \"턴마다 하나입니다. 아래 \\\"행동 12가지\\\"에서 고르거나, 기능이나 주문이 주는 행동을 씁니다.\"}, {\"추가 행동\", \"Bonus Action\", \"기능이나 주문이 추가 행동으로 하라고 할 때만 쓸 수 있습니다. 턴마다 하나.\"}, {\"반응행동\", \"Reaction\", \"정해진 일이 일어났을 때 남의 턴에도 쓰는 행동입니다. 한 번 쓰면 내 다음 턴이 시작될 때까지 다시 못 씁니다. 기회공격이 대표적입니다.\"}, {\"물건 하나\", \"Interacting with Things\", \"이동이나 행동 중에 물건 하나는 그냥 다룰 수 있습니다(문 열기, 칼 뽑기). 두 번째 물건부터는 물건 사용 행동이 듭니다.\"}, {\"짧은 말\", \"Communicating\", \"짧은 말이나 손짓은 턴을 쓰지 않습니다. 길게 설명하거나 적을 설득하려면 행동(교섭)이 듭니다.\"}, {\"엎드리기\", \"Dropping Prone\", \"내 턴에 행동이나 이동 없이 스스로 엎드릴 수 있습니다(속도가 0이면 못 합니다). 일어날 때는 이동력 절반이 듭니다.\"}}}, {\"행동 12가지\", {{\"공격\", \"Attack\", \"무기나 맨손으로 한 번 공격합니다. 추가 공격이 있으면 그만큼 더 하고, 공격 사이에 이동해도 됩니다. 공격하면서 무기 하나를 꺼내거나 넣을 수 있습니다.\"}, {\"질주\", \"Dash\", \"이번 턴 이동력이 속도만큼 늘어납니다(속도 30피트면 60피트까지).\"}, {\"이탈\", \"Disengage\", \"이번 턴에는 움직여도 기회공격을 받지 않습니다. 퇴각 행동이라고도 합니다.\"}, {\"회피\", \"Dodge\", \"내 다음 턴이 시작될 때까지 내가 보는 상대의 공격은 불리점, 내 민첩 내성은 이점입니다. 행동불능이 되거나 속도가 0이 되면 끝납니다.\"}, {\"돕기\", \"Help\", \"동료의 다음 능력 판정에 이점(내가 숙련된 기술이나 도구로 거들 때), 또는 5피트 안의 적을 흔들어 그 적을 치는 동료의 다음 공격에 이점. 내 다음 턴이 시작되면 사라집니다. 원호 행동이라고도 합니다.\"}, {\"숨기\", \"Hide\", \"짙게 가려진 곳이나 3/4 이상 엄폐 뒤에서, 적의 시야 밖일 때 민첩(은신) 판정 난이도 15. 성공하면 숨어 있는 동안 투명 상태입니다. 찾는 쪽은 지혜(감지)로 내 판정 값 이상을 내야 합니다. 속삭임보다 큰 소리, 명중 굴림, 음성 요소가 있는 주문을 쓰면 들킵니다.\"}, {\"교섭\", \"Influence\", \"괴물이나 NPC가 무언가를 하도록 말로 움직입니다(속이기, 위협, 웃기기, 설득). 바라던 일이면 판정 없이 들어주고, 질색하는 일이면 판정 없이 거절합니다. 망설일 때만 판정하고, 난이도는 15와 상대 지능 점수 중 높은 쪽입니다. 실패하면 하루가 지나야 같은 부탁을 다시 할 수 있습니다.\"}, {\"마법\", \"Magic\", \"시전 시간이 행동인 주문을 쓰거나, 마법 행동이 필요한 기능이나 마법 물건을 씁니다. 1분 이상 걸리는 주문은 매 턴 마법 행동과 집중이 필요합니다(집중이 깨지면 주문은 실패하고 슬롯은 남습니다).\"}, {\"대기\", \"Ready\", \"조건을 정해 두고(고블린이 문으로 들어오면 활을 쏜다), 그 일이 일어나면 반응행동으로 그 행동을 하거나 속도만큼 움직입니다. 주문을 대기하면 슬롯은 지금 쓰고, 내 다음 턴 시작까지 집중으로 붙잡아 둡니다.\"}, {\"수색\", \"Search\", \"지혜 판정으로 눈에 띄지 않는 것을 알아냅니다(통찰, 의학, 감지, 생존).\"}, {\"탐구\", \"Study\", \"지능 판정으로 기억이나 책, 단서에서 중요한 것을 떠올립니다(비전학, 역사학, 수사, 자연학, 종교학).\"}, {\"물건 사용\", \"Utilize\", \"쓰는 데 행동이 드는 물건을 씁니다(그 턴의 두 번째 물건, 행동이 필요하다고 적힌 물건). 마법 물약은 마시거나 먹여 주는 데 추가 행동이 듭니다.\"}}}, {\"판정과 굴림\", {{\"d20 판정\", \"D20 Test\", \"능력 판정, 명중 굴림, 내성 굴림 세 가지입니다. d20에 수정치를 더해 목표 값(난이도나 방어도) 이상이면 성공입니다.\"}, {\"능력 판정\", \"Ability Check\", \"능력치 수정치에, 숙련된 기술이면 숙련 보너스를 더합니다. 기술은 능력치에 딸려 있습니다(은신은 민첩, 감지는 지혜).\"}, {\"난이도\", \"Difficulty Class (DC)\", \"매우 쉬움 5, 쉬움 10, 보통 15, 어려움 20, 매우 어려움 25, 거의 불가능 30.\"}, {\"내성 굴림\", \"Saving Throw\", \"해로운 효과를 버티는 굴림입니다. 능력치 수정치에, 숙련된 내성이면 숙련 보너스를 더합니다. 일부러 실패할 수도 있습니다.\"}, {\"명중 굴림\", \"Attack Roll\", \"d20 + 공격 수정치가 상대 방어도 이상이면 맞습니다. 20이 나오면 치명타, 1이 나오면 무조건 빗나갑니다.\"}, {\"이점\", \"Advantage\", \"d20을 두 번 굴려 높은 쪽을 씁니다. 이점이 여러 개여도 한 번만 치고, 불리점과 같이 있으면 둘 다 없어집니다.\"}, {\"불리점\", \"Disadvantage\", \"d20을 두 번 굴려 낮은 쪽을 씁니다.\"}, {\"숙련 보너스\", \"Proficiency Bonus\", \"숙련된 기술, 무기, 내성, 도구 굴림에 더합니다. 1~4레벨 +2, 5~8레벨 +3, 9~12레벨 +4, 13~16레벨 +5, 17~20레벨 +6.\"}, {\"상시 감지\", \"Passive Perception\", \"굴리지 않고 알아채는지 볼 때 쓰는 값입니다. 10 + 지혜(감지) 판정 수정치.\"}, {\"영웅적 영감\", \"Heroic Inspiration\", \"아무 주사위나 굴린 직후 다시 굴릴 수 있습니다(새 값을 씁니다). 이미 있는데 또 얻으면 사라집니다(영감이 없는 다른 플레이어 캐릭터에게 줄 수는 있습니다).\"}, {\"치명타\", \"Critical Hit\", \"명중 굴림 d20이 20이면 방어도와 상관없이 맞고, 피해 주사위를 두 번 굴려 더합니다(수정치는 한 번만).\"}}}, {\"전투\", {{\"우선권\", \"Initiative\", \"전투가 시작되면 모두 민첩 판정을 굴려 높은 순서대로 행동합니다. 같은 괴물 무리는 한 번만 굴립니다. 이 봇에서는 Lua가 굴립니다.\"}, {\"기습\", \"Surprise\", \"전투가 시작되는 줄 몰랐던 쪽은 우선권 굴림에 불리점입니다.\"}, {\"기회공격\", \"Opportunity Attack\", \"보이는 적이 내 손이 닿는 거리(보통 5피트)를 벗어나면 반응행동으로 근접 공격을 한 번 합니다. 이탈 행동, 순간이동, 밀려나거나 떨어지는 건 기회공격을 부르지 않습니다.\"}, {\"엄폐\", \"Cover\", \"절반 엄폐는 방어도와 민첩 내성 +2, 3/4 엄폐는 +5, 완전 엄폐는 직접 노릴 수 없습니다. 여러 겹이면 가장 좋은 것 하나만 칩니다. 이 봇은 지도가 없어서 엄폐를 원거리 공격과 민첩 내성에만 칩니다(근접으로 붙은 적은 돌아 들어왔다고 봅니다). \\\"바위 뒤로 숨는다\\\"처럼 말하면 AI가 엄폐를 붙이고, 전투 카드의 이름 아래에 표시됩니다.\"}, {\"근접 공격\", \"Melee Attack\", \"손이 닿는 거리(보통 5피트) 안의 상대만 칠 수 있습니다.\"}, {\"원거리 공격\", \"Ranged Attack\", \"보통 사거리 너머는 불리점, 긴 사거리 너머는 쏠 수 없습니다. 5피트 안에 나를 보는 적(행동불능이 아닌)이 있으면 원거리 명중 굴림에 불리점입니다.\"}, {\"맨손 공격\", \"Unarmed Strike\", \"주먹이나 발길질로 피해 주기·붙잡기·밀치기 가운데 하나를 고릅니다. 피해 주기는 명중 굴림(근력 수정치 + 숙련 보너스)을 해서 맞으면 1 + 근력 수정치 타격 피해입니다. 붙잡기와 밀치기는 상대가 근력이나 민첩 내성(난이도 8 + 근력 수정치 + 숙련 보너스)에 실패하면 붙잡히거나, 5피트 밀려나거나 넘어집니다. 나보다 한 단계 넘게 큰 상대에게는 못 하고, 붙잡으려면 손 하나가 비어 있어야 합니다.\"}, {\"붙잡기 풀기\", \"Escaping a Grapple\", \"붙잡힌 쪽이 행동을 써서 근력(운동)이나 민첩(곡예) 판정으로 탈출 난이도 이상을 내면 풀립니다. 붙잡은 쪽이 행동불능이 되거나 거리가 멀어져도 풀립니다.\"}, {\"절반 이하\", \"Bloodied\", \"생명력이 최대치의 절반 이하인 상태입니다. 그 자체로는 효과가 없지만, 이걸 보고 움직이는 기능이나 괴물이 있습니다.\"}}}, {\"피해와 회복\", {{\"생명력\", \"Hit Points\", \"피해를 받으면 줄어듭니다. 0이 되기 전까지는 아무 불이익이 없습니다. 치유는 최대치를 넘지 않습니다.\"}, {\"임시 생명력\", \"Temporary Hit Points\", \"피해를 먼저 받아 주는 완충입니다. 서로 더해지지 않고(새로 받으면 둘 중 하나를 고릅니다), 치유로 채울 수 없고, 긴 휴식이 끝나면 사라집니다.\"}, {\"저항\", \"Resistance\", \"그 종류의 피해를 절반으로 받습니다(내림).\"}, {\"취약\", \"Vulnerability\", \"그 종류의 피해를 두 배로 받습니다.\"}, {\"면역\", \"Immunity\", \"그 피해나 상태가 아예 통하지 않습니다.\"}, {\"적용 순서\", \"Order of Application\", \"보너스나 감소를 먼저, 그다음 저항, 마지막에 취약을 적용합니다. 같은 것이 여러 개여도 한 번만 칩니다.\"}, {\"피해 종류\", \"Damage Types\", \"산성, 타격, 냉기, 화염, 역장, 번개, 사령, 관통, 독성, 정신, 광휘, 참격, 천둥.\"}, {\"여러 대상\", \"Multiple Targets\", \"여럿이 한꺼번에 내성을 굴리는 효과는 피해를 한 번만 굴려 모두에게 씁니다. 내성에 성공하면 보통 절반(내림)입니다.\"}, {\"기절시키기\", \"Knocking Out\", \"근접 공격으로 생명력을 0으로 만들 때 대신 1을 남기고 무의식 상태로 만들 수 있습니다. 짧은 휴식이 끝나거나, 치유를 받거나, 누가 응급처치(지혜(의학) 난이도 10)를 하면 깨어납니다.\"}}}, {\"쓰러짐과 죽음\", {{\"이 채팅에서\", \"\", \"@DEATH@\"}, {\"생명력 0\", \"Dropping to 0 Hit Points\", \"즉사하지 않으면 무의식 상태가 되고, 턴을 시작할 때마다 죽음 내성을 굴립니다. 괴물은 0이 되면 바로 죽습니다.\"}, {\"죽음 내성\", \"Death Saving Throw\", \"d20에 아무것도 더하지 않습니다. 10 이상이면 성공, 성공 3번이면 안정, 실패 3번이면 사망입니다(연달아 나올 필요는 없습니다). 1은 실패 2번, 20은 생명력 1로 깨어납니다.\"}, {\"0에서 피해\", \"Damage at 0 Hit Points\", \"죽음 내성 실패 1번(치명타면 2번)입니다. 그 피해가 최대 생명력 이상이면 바로 사망합니다.\"}, {\"즉사\", \"Massive Damage\", \"생명력이 0이 되고도 남은 피해가 최대 생명력 이상이면 즉사합니다(최대 12, 현재 6일 때 18 피해면 남은 12로 즉사).\"}, {\"안정시키기\", \"Stabilizing\", \"돕기 행동과 지혜(의학) 난이도 10으로 안정시킵니다. 치유사의 키트를 쓰면 판정 없이 됩니다(물건 사용 행동). 안정되면 죽음 내성을 굴리지 않고, 치유가 없으면 1d4시간 뒤 생명력 1로 깨어납니다. 다시 피해를 받으면 다시 굴립니다.\"}}}, {\"휴식\", {{\"짧은 휴식\", \"Short Rest\", \"1시간 동안 읽기, 대화, 식사, 보초 정도만 합니다. 생명력이 1 이상이어야 시작할 수 있습니다. 생명력 주사위를 원하는 만큼 하나씩 굴려(주사위 + 건강 수정치, 최소 1) 회복하고, 일부 기능이 다시 찹니다.\"}, {\"짧은 휴식이 깨질 때\", \"\", \"우선권 굴림, 소마법이 아닌 주문, 피해를 받으면 깨지고 아무 효과가 없습니다.\"}, {\"긴 휴식\", \"Long Rest\", \"8시간(잠 6시간 이상, 가벼운 활동 2시간 이하)입니다. 생명력이 1 이상이어야 시작할 수 있습니다. 끝나면 생명력과 생명력 주사위가 모두 차고, 줄었던 최대 생명력과 능력치가 돌아오고, 탈진이 1단계 줄고, 기능이 다시 찹니다.\"}, {\"긴 휴식 간격\", \"\", \"긴 휴식이 끝나고 16시간이 지나야 다시 시작할 수 있습니다.\"}, {\"긴 휴식이 깨질 때\", \"Interrupting the Rest\", \"우선권 굴림, 소마법이 아닌 주문, 피해, 1시간 동안 걷기 같은 힘든 일. 1시간 이상 쉬었다면 짧은 휴식 효과는 얻습니다. 바로 이어서 쉬면 깨질 때마다 1시간이 더 걸립니다.\"}, {\"생명력 주사위\", \"Hit Point Dice\", \"레벨마다 하나씩 있습니다. 바바리안 d12, 파이터·팔라딘·레인저 d10, 바드·클레릭·드루이드·몽크·로그·워락 d8, 소서러·위저드 d6.\"}}}, {\"주문\", {{\"주문 슬롯\", \"Spell Slots\", \"레벨 1 이상 주문을 쓸 때마다 그 레벨 이상의 슬롯 하나를 씁니다. 높은 레벨로 시전하면 세지는 주문도 있습니다(아래). 긴 휴식으로 다시 찹니다(워락은 짧은 휴식에도).\"}, {\"높은 레벨로 시전\", \"Casting at a Higher Level\", \"주문을 원래 레벨보다 높은 레벨의 슬롯으로 쓰는 것입니다(1레벨 주문을 2레벨 슬롯으로 쓰면 한 단계 높인 것). 더 귀한 슬롯을 쓰는 대신, 주문 설명의 \\\"한 단계마다\\\"만큼 효과가 커집니다(피해·회복 주사위, 대상 수 등). 쓸 때 \\\"2레벨 슬롯으로\\\"처럼 말하면 됩니다.\"}, {\"한 턴에 슬롯 하나\", \"One Slot per Turn\", \"한 턴에 슬롯을 쓰는 주문은 하나뿐입니다. 마법 행동으로 하나 쓰고 추가 행동으로 또 쓸 수는 없습니다. 소마법은 슬롯이 들지 않습니다.\"}, {\"소마법\", \"Cantrip\", \"슬롯 없이 몇 번이든 쓰는 주문입니다.\"}, {\"집중\", \"Concentration\", \"집중이 필요한 효과는 한 번에 하나뿐입니다. 다른 집중 주문을 시작하면 앞의 것이 끝납니다. 피해를 받으면 건강 내성(난이도 10과 받은 피해 절반 중 높은 쪽, 최대 30)에 성공해야 이어집니다. 행동불능이 되거나 죽으면 끝나고, 언제든 스스로 그만둘 수 있습니다.\"}, {\"의식\", \"Ritual\", \"의식 표시가 있는 주문을 준비해 두었다면 10분 더 들여 슬롯 없이 쓸 수 있습니다(더 높은 레벨로는 못 씁니다). 위저드는 주문책에 있기만 하면 준비하지 않아도 됩니다.\"}, {\"구성 요소\", \"Components\", \"음성(V), 동작(S), 물질(M). 하나라도 갖추지 못하면 시전할 수 없습니다.\"}, {\"갑옷과 주문\", \"Casting in Armor\", \"훈련받지 않은 갑옷을 입고 있으면 주문을 쓸 수 없습니다.\"}, {\"주문 내성 난이도\", \"Spell Save DC\", \"8 + 주문 능력치 수정치 + 숙련 보너스. 주문 명중 보너스는 주문 능력치 수정치 + 숙련 보너스입니다.\"}, {\"주문 능력치\", \"Spellcasting Ability\", \"위저드는 지능, 클레릭·드루이드·레인저는 지혜, 바드·팔라딘·소서러·워락은 매력.\"}}}, {\"이동과 환경\", {{\"어려운 지형\", \"Difficult Terrain\", \"1피트 움직일 때마다 1피트를 더 씁니다(잡목, 잔해, 눈, 얼음, 정강이에서 허리 사이 물, 가파른 비탈, 작지 않은 적이 있는 칸). 여러 가지가 겹쳐도 한 번만 칩니다.\"}, {\"오르기와 헤엄치기\", \"Climbing, Swimming\", \"1피트마다 1피트를 더 씁니다(어려운 지형에서는 2피트). 오르기 속도나 헤엄 속도가 있으면 더 들지 않습니다.\"}, {\"멀리뛰기\", \"Long Jump\", \"10피트를 달려와서 뛰면 근력 점수만큼(피트), 제자리에서는 절반입니다. 뛴 거리만큼 이동력을 씁니다.\"}, {\"높이뛰기\", \"High Jump\", \"10피트를 달려와서 뛰면 3 + 근력 수정치(피트), 제자리에서는 절반입니다.\"}, {\"낙하\", \"Falling\", \"10피트마다 1d6 타격 피해(최대 20d6)이고, 피해를 받았다면 넘어진 채 떨어집니다. 물로 떨어질 때 반응행동으로 근력(운동)이나 민첩(곡예) 난이도 15에 성공하면 피해가 절반입니다.\"}, {\"숨 참기와 질식\", \"Suffocation\", \"1 + 건강 수정치 분(최소 30초)만큼 숨을 참을 수 있습니다. 그 뒤로는 턴이 끝날 때마다 탈진 1단계. 다시 숨 쉬면 질식으로 얻은 탈진은 모두 사라집니다.\"}, {\"희미한 빛\", \"Dim Light\", \"가볍게 가려진 곳입니다. 그 안을 보는 지혜(감지) 판정에 불리점.\"}, {\"어둠\", \"Darkness\", \"짙게 가려진 곳입니다. 그 안을 볼 때는 장님 상태와 같습니다.\"}, {\"암시야\", \"Darkvision\", \"범위 안의 희미한 빛은 밝은 빛처럼, 어둠은 희미한 빛처럼 봅니다. 어둠 속에서는 색을 흑백으로만 봅니다.\"}}}, {\"상태이상 15가지\", {{\"장님\", \"Blinded\", \"앞이 안 보입니다. 시각이 필요한 능력 판정은 자동 실패, 나를 치는 공격은 이점, 내 공격은 불리점.\"}, {\"매혹\", \"Charmed\", \"매혹한 상대를 공격하거나 해로운 능력이나 마법의 대상으로 삼을 수 없습니다. 그 상대는 나를 상대로 한 사교 능력 판정에 이점.\"}, {\"귀머거리\", \"Deafened\", \"들을 수 없습니다. 청각이 필요한 능력 판정은 자동 실패.\"}, {\"탈진\", \"Exhaustion\", \"단계가 쌓입니다. d20 판정마다 단계 × 2를 빼고, 속도는 단계 × 5피트 줄어듭니다. 6단계면 사망. 긴 휴식마다 1단계 줄어듭니다.\"}, {\"공포\", \"Frightened\", \"두려움의 원천이 보이는 동안 능력 판정과 명중 굴림에 불리점. 스스로 그쪽으로 다가갈 수 없습니다.\"}, {\"붙잡힘\", \"Grappled\", \"속도 0. 붙잡은 상대가 아닌 대상을 공격하면 불리점. 붙잡은 쪽이 나를 끌고 다닐 수 있습니다.\"}, {\"행동불능\", \"Incapacitated\", \"행동, 추가 행동, 반응행동을 못 하고 말도 못 합니다. 집중이 깨집니다. 이 상태로 우선권을 굴리면 불리점.\"}, {\"투명\", \"Invisible\", \"나를 치는 공격은 불리점, 내 공격은 이점입니다(나를 볼 수 있는 상대에게는 아닙니다). 보여야 걸리는 효과에 걸리지 않고, 우선권 굴림에 이점.\"}, {\"마비\", \"Paralyzed\", \"행동불능, 속도 0. 근력·민첩 내성 자동 실패, 나를 치는 공격은 이점, 5피트 안에서 맞으면 치명타.\"}, {\"석화\", \"Petrified\", \"돌 같은 물체가 됩니다. 행동불능, 속도 0, 근력·민첩 내성 자동 실패, 나를 치는 공격은 이점, 모든 피해에 저항, 중독에 면역.\"}, {\"중독\", \"Poisoned\", \"명중 굴림과 능력 판정에 불리점.\"}, {\"넘어진 상태\", \"Prone\", \"기어가거나, 이동력 절반을 써서 일어나는 것만 할 수 있습니다. 내 공격은 불리점, 5피트 안에서 나를 치는 공격은 이점, 그보다 멀면 불리점.\"}, {\"포박\", \"Restrained\", \"속도 0. 나를 치는 공격은 이점, 내 공격과 민첩 내성은 불리점.\"}, {\"충격\", \"Stunned\", \"행동불능. 근력·민첩 내성 자동 실패, 나를 치는 공격은 이점.\"}, {\"무의식\", \"Unconscious\", \"행동불능에 넘어진 상태가 되고, 들고 있던 것을 떨어뜨립니다. 속도 0, 근력·민첩 내성 자동 실패, 나를 치는 공격은 이점, 5피트 안에서 맞으면 치명타. 주위를 알아채지 못합니다.\"}}}} }\r\n\r\nlocal ITEM_TIP = { Club = \"단순 근접 무기 · 1d4 타격\\n단순 무기: 거의 모든 클래스가 숙련 (누구나 다루기 쉬운 무기)\\n경량\\n은화 1\", Dagger = \"단순 근접 무기 · 1d4 관통\\n단순 무기: 거의 모든 클래스가 숙련 (누구나 다루기 쉬운 무기)\\n교묘함 · 경량 · 투척(사거리 20/60)\\n금화 2\", Greatclub = \"단순 근접 무기 · 1d8 타격\\n단순 무기: 거의 모든 클래스가 숙련 (누구나 다루기 쉬운 무기)\\n양손\\n은화 2\", Handaxe = \"단순 근접 무기 · 1d6 참격\\n단순 무기: 거의 모든 클래스가 숙련 (누구나 다루기 쉬운 무기)\\n경량 · 투척(사거리 20/60)\\n금화 5\", Javelin = \"단순 근접 무기 · 1d6 관통\\n단순 무기: 거의 모든 클래스가 숙련 (누구나 다루기 쉬운 무기)\\n투척(사거리 30/120)\\n은화 5\", [\"Light Hammer\"] = \"단순 근접 무기 · 1d4 타격\\n단순 무기: 거의 모든 클래스가 숙련 (누구나 다루기 쉬운 무기)\\n경량 · 투척(사거리 20/60)\\n금화 2\", Mace = \"단순 근접 무기 · 1d6 타격\\n단순 무기: 거의 모든 클래스가 숙련 (누구나 다루기 쉬운 무기)\\n금화 5\", Quarterstaff = \"단순 근접 무기 · 1d6 타격\\n단순 무기: 거의 모든 클래스가 숙련 (누구나 다루기 쉬운 무기)\\n다용도(1d8)\\n은화 2\", Sickle = \"단순 근접 무기 · 1d4 참격\\n단순 무기: 거의 모든 클래스가 숙련 (누구나 다루기 쉬운 무기)\\n경량\\n금화 1\", Spear = \"단순 근접 무기 · 1d6 관통\\n단순 무기: 거의 모든 클래스가 숙련 (누구나 다루기 쉬운 무기)\\n투척(사거리 20/60) · 다용도(1d8)\\n금화 1\", Dart = \"단순 원거리 무기 · 1d4 관통\\n단순 무기: 거의 모든 클래스가 숙련 (누구나 다루기 쉬운 무기)\\n교묘함 · 투척(사거리 20/60)\\n동화 5\", [\"Light Crossbow\"] = \"단순 원거리 무기 · 1d8 관통\\n단순 무기: 거의 모든 클래스가 숙련 (누구나 다루기 쉬운 무기)\\n탄약(사거리 80/320 · 볼트) · 장전 · 양손\\n금화 25\", Shortbow = \"단순 원거리 무기 · 1d6 관통\\n단순 무기: 거의 모든 클래스가 숙련 (누구나 다루기 쉬운 무기)\\n탄약(사거리 80/320 · 화살) · 양손\\n금화 25\", Sling = \"단순 원거리 무기 · 1d4 타격\\n단순 무기: 거의 모든 클래스가 숙련 (누구나 다루기 쉬운 무기)\\n탄약(사거리 30/120 · 탄환)\\n은화 1\", Battleaxe = \"군용 근접 무기 · 1d8 참격\\n군용 무기: 파이터·바바리안·팔라딘·레인저처럼 무기 훈련을 받은 클래스가 숙련\\n다용도(1d10)\\n금화 10\", Flail = \"군용 근접 무기 · 1d8 타격\\n군용 무기: 파이터·바바리안·팔라딘·레인저처럼 무기 훈련을 받은 클래스가 숙련\\n금화 10\", Glaive = \"군용 근접 무기 · 1d10 참격\\n군용 무기: 파이터·바바리안·팔라딘·레인저처럼 무기 훈련을 받은 클래스가 숙련\\n중량 · 간격 · 양손\\n금화 20\", Greataxe = \"군용 근접 무기 · 1d12 참격\\n군용 무기: 파이터·바바리안·팔라딘·레인저처럼 무기 훈련을 받은 클래스가 숙련\\n중량 · 양손\\n금화 30\", Greatsword = \"군용 근접 무기 · 2d6 참격\\n군용 무기: 파이터·바바리안·팔라딘·레인저처럼 무기 훈련을 받은 클래스가 숙련\\n중량 · 양손\\n금화 50\", Halberd = \"군용 근접 무기 · 1d10 참격\\n군용 무기: 파이터·바바리안·팔라딘·레인저처럼 무기 훈련을 받은 클래스가 숙련\\n중량 · 간격 · 양손\\n금화 20\", Lance = \"군용 근접 무기 · 1d10 관통\\n군용 무기: 파이터·바바리안·팔라딘·레인저처럼 무기 훈련을 받은 클래스가 숙련\\n중량 · 간격 · 양손(탈것 위에선 한 손)\\n금화 10\", Longsword = \"군용 근접 무기 · 1d8 참격\\n군용 무기: 파이터·바바리안·팔라딘·레인저처럼 무기 훈련을 받은 클래스가 숙련\\n다용도(1d10)\\n금화 15\", Maul = \"군용 근접 무기 · 2d6 타격\\n군용 무기: 파이터·바바리안·팔라딘·레인저처럼 무기 훈련을 받은 클래스가 숙련\\n중량 · 양손\\n금화 10\", Morningstar = \"군용 근접 무기 · 1d8 관통\\n군용 무기: 파이터·바바리안·팔라딘·레인저처럼 무기 훈련을 받은 클래스가 숙련\\n금화 15\", Pike = \"군용 근접 무기 · 1d10 관통\\n군용 무기: 파이터·바바리안·팔라딘·레인저처럼 무기 훈련을 받은 클래스가 숙련\\n중량 · 간격 · 양손\\n금화 5\", Rapier = \"군용 근접 무기 · 1d8 관통\\n군용 무기: 파이터·바바리안·팔라딘·레인저처럼 무기 훈련을 받은 클래스가 숙련\\n교묘함\\n금화 25\", Scimitar = \"군용 근접 무기 · 1d6 참격\\n군용 무기: 파이터·바바리안·팔라딘·레인저처럼 무기 훈련을 받은 클래스가 숙련\\n교묘함 · 경량\\n금화 25\", Shortsword = \"군용 근접 무기 · 1d6 관통\\n군용 무기: 파이터·바바리안·팔라딘·레인저처럼 무기 훈련을 받은 클래스가 숙련\\n교묘함 · 경량\\n금화 10\", Trident = \"군용 근접 무기 · 1d8 관통\\n군용 무기: 파이터·바바리안·팔라딘·레인저처럼 무기 훈련을 받은 클래스가 숙련\\n투척(사거리 20/60) · 다용도(1d10)\\n금화 5\", Warhammer = \"군용 근접 무기 · 1d8 타격\\n군용 무기: 파이터·바바리안·팔라딘·레인저처럼 무기 훈련을 받은 클래스가 숙련\\n다용도(1d10)\\n금화 15\", [\"War Pick\"] = \"군용 근접 무기 · 1d8 관통\\n군용 무기: 파이터·바바리안·팔라딘·레인저처럼 무기 훈련을 받은 클래스가 숙련\\n다용도(1d10)\\n금화 5\", Whip = \"군용 근접 무기 · 1d4 참격\\n군용 무기: 파이터·바바리안·팔라딘·레인저처럼 무기 훈련을 받은 클래스가 숙련\\n교묘함 · 간격\\n금화 2\", Blowgun = \"군용 원거리 무기 · 1 관통\\n군용 무기: 파이터·바바리안·팔라딘·레인저처럼 무기 훈련을 받은 클래스가 숙련\\n탄약(사거리 25/100 · 바늘) · 장전\\n금화 10\", [\"Hand Crossbow\"] = \"군용 원거리 무기 · 1d6 관통\\n군용 무기: 파이터·바바리안·팔라딘·레인저처럼 무기 훈련을 받은 클래스가 숙련\\n탄약(사거리 30/120 · 볼트) · 경량 · 장전\\n금화 75\", [\"Heavy Crossbow\"] = \"군용 원거리 무기 · 1d10 관통\\n군용 무기: 파이터·바바리안·팔라딘·레인저처럼 무기 훈련을 받은 클래스가 숙련\\n탄약(사거리 100/400 · 볼트) · 중량 · 장전 · 양손\\n금화 50\", Longbow = \"군용 원거리 무기 · 1d8 관통\\n군용 무기: 파이터·바바리안·팔라딘·레인저처럼 무기 훈련을 받은 클래스가 숙련\\n탄약(사거리 150/600 · 화살) · 중량 · 양손\\n금화 50\", Musket = \"군용 원거리 무기 · 1d12 관통\\n군용 무기: 파이터·바바리안·팔라딘·레인저처럼 무기 훈련을 받은 클래스가 숙련\\n탄약(사거리 40/120 · 탄환) · 장전 · 양손\\n금화 500\", Pistol = \"군용 원거리 무기 · 1d10 관통\\n군용 무기: 파이터·바바리안·팔라딘·레인저처럼 무기 훈련을 받은 클래스가 숙련\\n탄약(사거리 30/90 · 탄환) · 장전\\n금화 250\", [\"Padded Armor\"] = \"경갑 · 방어도 11 + 민첩 수정치\\n은신 판정에 불리점\\n금화 5\", [\"Leather Armor\"] = \"경갑 · 방어도 11 + 민첩 수정치\\n금화 10\", [\"Studded Leather Armor\"] = \"경갑 · 방어도 12 + 민첩 수정치\\n금화 45\", [\"Hide Armor\"] = \"평갑 · 방어도 12 + 민첩 수정치 (최대 2)\\n금화 10\", [\"Chain Shirt\"] = \"평갑 · 방어도 13 + 민첩 수정치 (최대 2)\\n금화 50\", [\"Scale Mail\"] = \"평갑 · 방어도 14 + 민첩 수정치 (최대 2)\\n은신 판정에 불리점\\n금화 50\", Breastplate = \"평갑 · 방어도 14 + 민첩 수정치 (최대 2)\\n금화 400\", [\"Half Plate Armor\"] = \"평갑 · 방어도 15 + 민첩 수정치 (최대 2)\\n은신 판정에 불리점\\n금화 750\", [\"Ring Mail\"] = \"중갑 · 방어도 14\\n은신 판정에 불리점\\n금화 30\", [\"Chain Mail\"] = \"중갑 · 방어도 16\\n근력 13 미만이면 속도 −10피트 · 은신 판정에 불리점\\n금화 75\", [\"Splint Armor\"] = \"중갑 · 방어도 17\\n근력 15 미만이면 속도 −10피트 · 은신 판정에 불리점\\n금화 200\", [\"Plate Armor\"] = \"중갑 · 방어도 18\\n근력 15 미만이면 속도 −10피트 · 은신 판정에 불리점\\n금화 1,500\", Shield = \"방패 · 방어도 +2\\n금화 10\", [\"Potion of Healing\"] = \"마시면 생명력 2d4+2 회복\", [\"Potion of Greater Healing\"] = \"마시면 생명력 4d4+4 회복\", [\"Potion of Superior Healing\"] = \"마시면 생명력 8d4+8 회복\", [\"Potion of Supreme Healing\"] = \"마시면 생명력 10d4+20 회복\", [\"Basic Poison\"] = \"추가 행동으로 무기 하나(탄약이면 셋)에 발라 둡니다. 1분 안에 그 무기가 처음 관통이나 참격 피해를 줄 때 독성 피해 1d4를 더합니다.\", [\"Healer's Kit\"] = \"10회분. 한 번 쓰면 생명력 0으로 쓰러진 생물을 의학 판정 없이 안정시킴\", Antitoxin = \"추가 행동으로 마시면 1시간 동안 중독을 피하거나 끝내는 내성 굴림에 이점\", [\"Alchemist's Fire\"] = \"공격 하나 대신 20피트 안으로 던짐. 대상이 민첩 내성 (난이도 8 + 민첩 수정치 + 숙련 보너스)에 실패하면 1d4 화염 피해와 불붙음\", Acid = \"공격 하나 대신 20피트 안으로 던짐. 대상이 민첩 내성 (난이도 8 + 민첩 수정치 + 숙련 보너스)에 실패하면 2d6 산성 피해\", [\"Holy Water\"] = \"공격 하나 대신 20피트 안으로 던짐. 악마나 언데드가 민첩 내성 (난이도 8 + 민첩 수정치 + 숙련 보너스)에 실패하면 2d8 광휘 피해\", Oil = \"공격 하나 대신 20피트 안으로 던짐. 민첩 내성에 실패하면 1분 동안 기름 범벅 (그동안 화염 피해를 받으면 화염 5 더). 또는 5피트 칸 바닥에 부어 두고 불붙이면 2라운드 동안 들어오거나 턴을 끝내는 생물에게 화염 5\", Arrows = \"활로 공격할 때마다 하나씩 써요 (20개에 금화 1)\", Bolts = \"석궁으로 공격할 때마다 하나씩 써요 (20개에 금화 1)\", [\"Firearm Bullets\"] = \"권총이나 머스킷으로 공격할 때마다 하나씩 써요 (10개에 금화 3)\", [\"Sling Bullets\"] = \"슬링으로 공격할 때마다 하나씩 써요 (20개에 동화 4)\", Needles = \"블로우건으로 공격할 때마다 하나씩 써요 (50개에 금화 1)\" }\r\n\r\nlocal CLASSES = { Fighter = { hit_die = 10, primary = {\"Strength\", \"Dexterity\"}, saves = {\"Strength\", \"Constitution\"}, skills = { choose = 2, from = {\"Acrobatics\", \"Animal Handling\", \"Athletics\", \"History\", \"Insight\", \"Intimidation\", \"Persuasion\", \"Perception\", \"Survival\"} }, weapons = \"all\", armor = { light = true, medium = true, heavy = true, shield = true }, equipment = { A = { items = { [\"Chain Mail\"] = 1, Greatsword = 1, Flail = 1, Javelin = 8 }, gp = 4, other = {\"Dungeoneer's Pack\"} }, B = { items = { [\"Studded Leather Armor\"] = 1, Scimitar = 1, Shortsword = 1, Longbow = 1, Arrows = 20 }, gp = 11, other = {\"Quiver\", \"Dungeoneer's Pack\"} }, C = { items = {  }, gp = 155, other = {} } }, levels = {{ features = {\"Fighting Style\", \"Second Wind\", \"Weapon Mastery\"}, second_wind = 2, weapon_mastery = 3, res = { [\"Second Wind\"] = {2, 1} }, mastery = 3 }, { features = {\"Action Surge (one use)\", \"Tactical Mind\"}, second_wind = 2, weapon_mastery = 3, res = { [\"Second Wind\"] = {2, 1}, [\"Action Surge\"] = {1, 1} }, mastery = 3 }, { features = {\"Fighter Subclass\"}, second_wind = 2, weapon_mastery = 3, res = { [\"Second Wind\"] = {2, 1}, [\"Action Surge\"] = {1, 1} }, mastery = 3 }, { features = {\"Ability Score Improvement\"}, second_wind = 3, weapon_mastery = 4, res = { [\"Second Wind\"] = {3, 1}, [\"Action Surge\"] = {1, 1} }, mastery = 4 }, { features = {\"Extra Attack\", \"Tactical Shift\"}, second_wind = 3, weapon_mastery = 4, res = { [\"Second Wind\"] = {3, 1}, [\"Action Surge\"] = {1, 1} }, mastery = 4 }, { features = {\"Ability Score Improvement\"}, second_wind = 3, weapon_mastery = 4, res = { [\"Second Wind\"] = {3, 1}, [\"Action Surge\"] = {1, 1} }, mastery = 4 }, { features = {\"Subclass feature\"}, second_wind = 3, weapon_mastery = 4, res = { [\"Second Wind\"] = {3, 1}, [\"Action Surge\"] = {1, 1} }, mastery = 4 }, { features = {\"Ability Score Improvement\"}, second_wind = 3, weapon_mastery = 4, res = { [\"Second Wind\"] = {3, 1}, [\"Action Surge\"] = {1, 1} }, mastery = 4 }, { features = {\"Indomitable (one use)\", \"Tactical Master\"}, second_wind = 3, weapon_mastery = 4, res = { [\"Second Wind\"] = {3, 1}, [\"Action Surge\"] = {1, 1}, Indomitable = {1, 0} }, mastery = 4 }, { features = {\"Subclass feature\"}, second_wind = 4, weapon_mastery = 5, res = { [\"Second Wind\"] = {4, 1}, [\"Action Surge\"] = {1, 1}, Indomitable = {1, 0} }, mastery = 5 }, { features = {\"Two Extra Attacks\"}, second_wind = 4, weapon_mastery = 5, res = { [\"Second Wind\"] = {4, 1}, [\"Action Surge\"] = {1, 1}, Indomitable = {1, 0} }, mastery = 5 }, { features = {\"Ability Score Improvement\"}, second_wind = 4, weapon_mastery = 5, res = { [\"Second Wind\"] = {4, 1}, [\"Action Surge\"] = {1, 1}, Indomitable = {1, 0} }, mastery = 5 }, { features = {\"Indomitable (two uses)\", \"Studied Attacks\"}, second_wind = 4, weapon_mastery = 5, res = { [\"Second Wind\"] = {4, 1}, [\"Action Surge\"] = {1, 1}, Indomitable = {2, 0} }, mastery = 5 }, { features = {\"Ability Score Improvement\"}, second_wind = 4, weapon_mastery = 5, res = { [\"Second Wind\"] = {4, 1}, [\"Action Surge\"] = {1, 1}, Indomitable = {2, 0} }, mastery = 5 }, { features = {\"Subclass feature\"}, second_wind = 4, weapon_mastery = 5, res = { [\"Second Wind\"] = {4, 1}, [\"Action Surge\"] = {1, 1}, Indomitable = {2, 0} }, mastery = 5 }, { features = {\"Ability Score Improvement\"}, second_wind = 4, weapon_mastery = 6, res = { [\"Second Wind\"] = {4, 1}, [\"Action Surge\"] = {1, 1}, Indomitable = {2, 0} }, mastery = 6 }, { features = {\"Action Surge (two uses)\", \"Indomitable (three uses)\"}, second_wind = 4, weapon_mastery = 6, res = { [\"Second Wind\"] = {4, 1}, [\"Action Surge\"] = {2, \"all\"}, Indomitable = {3, 0} }, mastery = 6 }, { features = {\"Subclass feature\"}, second_wind = 4, weapon_mastery = 6, res = { [\"Second Wind\"] = {4, 1}, [\"Action Surge\"] = {2, \"all\"}, Indomitable = {3, 0} }, mastery = 6 }, { features = {\"Epic Boon\"}, second_wind = 4, weapon_mastery = 6, res = { [\"Second Wind\"] = {4, 1}, [\"Action Surge\"] = {2, \"all\"}, Indomitable = {3, 0} }, mastery = 6 }, { features = {\"Three Extra Attacks\"}, second_wind = 4, weapon_mastery = 6, res = { [\"Second Wind\"] = {4, 1}, [\"Action Surge\"] = {2, \"all\"}, Indomitable = {3, 0} }, mastery = 6 }}, subclass = { level = 3, name = \"Champion\" }, style_at = 1, mc_gains = { martial = true, light = true, medium = true, shield = true }, mc_need = \"any\", subclasses = { Champion = { levels = { [\"3\"] = {\"Improved Critical\", \"Remarkable Athlete\"}, [\"7\"] = {\"Additional Fighting Style\"}, [\"10\"] = {\"Heroic Warrior\"}, [\"15\"] = {\"Superior Critical\"}, [\"18\"] = {\"Survivor\"} } } } }, Rogue = { hit_die = 8, primary = {\"Dexterity\"}, saves = {\"Dexterity\", \"Intelligence\"}, skills = { choose = 4, from = {\"Acrobatics\", \"Athletics\", \"Deception\", \"Insight\", \"Intimidation\", \"Investigation\", \"Perception\", \"Persuasion\", \"Sleight of Hand\", \"Stealth\"} }, weapons = \"finesse_light\", armor = { light = true }, equipment = { A = { items = { [\"Leather Armor\"] = 1, Dagger = 2, Shortsword = 1, Shortbow = 1, Arrows = 20 }, gp = 8, other = {\"Quiver\", \"Thieves' Tools\", \"Burglar's Pack\"} }, B = { items = {  }, gp = 100, other = {} } }, levels = {{ features = {\"Expertise\", \"Sneak Attack\", \"Thieves' Cant\", \"Weapon Mastery\"}, sneak_attack = \"1d6\", expertise = 2, mastery = 2 }, { features = {\"Cunning Action\"}, sneak_attack = \"1d6\", expertise = 2, mastery = 2 }, { features = {\"Rogue Subclass\", \"Steady Aim\"}, sneak_attack = \"2d6\", expertise = 2, mastery = 2 }, { features = {\"Ability Score Improvement\"}, sneak_attack = \"2d6\", expertise = 2, mastery = 2 }, { features = {\"Cunning Strike\", \"Uncanny Dodge\"}, sneak_attack = \"3d6\", expertise = 2, mastery = 2 }, { features = {\"Expertise\"}, sneak_attack = \"3d6\", expertise = 4, mastery = 2 }, { features = {\"Evasion\", \"Reliable Talent\"}, sneak_attack = \"4d6\", expertise = 4, mastery = 2 }, { features = {\"Ability Score Improvement\"}, sneak_attack = \"4d6\", expertise = 4, mastery = 2 }, { features = {\"Subclass feature\"}, sneak_attack = \"5d6\", expertise = 4, mastery = 2 }, { features = {\"Ability Score Improvement\"}, sneak_attack = \"5d6\", expertise = 4, mastery = 2 }, { features = {\"Improved Cunning Strike\"}, sneak_attack = \"6d6\", expertise = 4, mastery = 2 }, { features = {\"Ability Score Improvement\"}, sneak_attack = \"6d6\", expertise = 4, mastery = 2 }, { features = {\"Subclass feature\"}, sneak_attack = \"7d6\", expertise = 4, mastery = 2 }, { features = {\"Devious Strikes\"}, sneak_attack = \"7d6\", expertise = 4, mastery = 2 }, { features = {\"Slippery Mind\"}, sneak_attack = \"8d6\", expertise = 4, mastery = 2 }, { features = {\"Ability Score Improvement\"}, sneak_attack = \"8d6\", expertise = 4, mastery = 2 }, { features = {\"Subclass feature\"}, sneak_attack = \"9d6\", expertise = 4, mastery = 2 }, { features = {\"Elusive\"}, sneak_attack = \"9d6\", expertise = 4, mastery = 2 }, { features = {\"Epic Boon\"}, sneak_attack = \"10d6\", expertise = 4, mastery = 2 }, { features = {\"Stroke of Luck\"}, sneak_attack = \"10d6\", expertise = 4, mastery = 2, res = { [\"Stroke of Luck\"] = {1, 1} } }}, subclass = { level = 3, name = \"Thief\" }, mc_gains = { light = true, skill = \"class\" }, tools = {\"Thieves' Tools\"}, subclasses = { Thief = { levels = { [\"3\"] = {\"Fast Hands\", \"Second-Story Work\"}, [\"9\"] = {\"Supreme Sneak\"}, [\"13\"] = {\"Use Magic Device\"}, [\"17\"] = {\"Thief's Reflexes\"} } } } }, Cleric = { hit_die = 8, primary = {\"Wisdom\"}, saves = {\"Wisdom\", \"Charisma\"}, skills = { choose = 2, from = {\"History\", \"Insight\", \"Medicine\", \"Persuasion\", \"Religion\"} }, weapons = \"simple\", armor = { light = true, medium = true, shield = true }, equipment = { A = { items = { [\"Chain Shirt\"] = 1, Shield = 1, Mace = 1 }, gp = 7, other = {\"Holy Symbol\", \"Priest's Pack\"} }, B = { items = {  }, gp = 110, other = {} } }, levels = {{ features = {\"Spellcasting\", \"Divine Order\"}, channel_divinity = 0, cantrips = 3, prepared = 4, slots = {2, 0, 0} }, { features = {\"Channel Divinity\"}, channel_divinity = 2, cantrips = 3, prepared = 5, slots = {3, 0, 0}, res = { [\"Channel Divinity\"] = {2, 1} } }, { features = {\"Cleric Subclass\"}, channel_divinity = 2, cantrips = 3, prepared = 6, slots = {4, 2, 0}, res = { [\"Channel Divinity\"] = {2, 1} } }, { features = {\"Ability Score Improvement\"}, channel_divinity = 2, cantrips = 4, prepared = 7, slots = {4, 3, 0}, res = { [\"Channel Divinity\"] = {2, 1} } }, { features = {\"Sear Undead\"}, channel_divinity = 2, cantrips = 4, prepared = 9, slots = {4, 3, 2}, res = { [\"Channel Divinity\"] = {2, 1} } }, { features = {\"Subclass feature\"}, channel_divinity = 3, cantrips = 4, prepared = 10, slots = {4, 3, 3}, res = { [\"Channel Divinity\"] = {3, 1} } }, { features = {\"Blessed Strikes\"}, channel_divinity = 3, cantrips = 4, prepared = 11, slots = {4, 3, 3, 1}, res = { [\"Channel Divinity\"] = {3, 1} } }, { features = {\"Ability Score Improvement\"}, channel_divinity = 3, cantrips = 4, prepared = 12, slots = {4, 3, 3, 2}, res = { [\"Channel Divinity\"] = {3, 1} } }, { features = {}, channel_divinity = 3, cantrips = 4, prepared = 14, slots = {4, 3, 3, 3, 1}, res = { [\"Channel Divinity\"] = {3, 1} } }, { features = {\"Divine Intervention\"}, channel_divinity = 3, cantrips = 5, prepared = 15, slots = {4, 3, 3, 3, 2}, res = { [\"Channel Divinity\"] = {3, 1}, [\"Divine Intervention\"] = {1, 0} } }, { features = {}, channel_divinity = 3, cantrips = 5, prepared = 16, slots = {4, 3, 3, 3, 2, 1}, res = { [\"Channel Divinity\"] = {3, 1}, [\"Divine Intervention\"] = {1, 0} } }, { features = {\"Ability Score Improvement\"}, channel_divinity = 3, cantrips = 5, prepared = 16, slots = {4, 3, 3, 3, 2, 1}, res = { [\"Channel Divinity\"] = {3, 1}, [\"Divine Intervention\"] = {1, 0} } }, { features = {}, channel_divinity = 3, cantrips = 5, prepared = 17, slots = {4, 3, 3, 3, 2, 1, 1}, res = { [\"Channel Divinity\"] = {3, 1}, [\"Divine Intervention\"] = {1, 0} } }, { features = {\"Improved Blessed Strikes\"}, channel_divinity = 3, cantrips = 5, prepared = 17, slots = {4, 3, 3, 3, 2, 1, 1}, res = { [\"Channel Divinity\"] = {3, 1}, [\"Divine Intervention\"] = {1, 0} } }, { features = {}, channel_divinity = 3, cantrips = 5, prepared = 18, slots = {4, 3, 3, 3, 2, 1, 1, 1}, res = { [\"Channel Divinity\"] = {3, 1}, [\"Divine Intervention\"] = {1, 0} } }, { features = {\"Ability Score Improvement\"}, channel_divinity = 3, cantrips = 5, prepared = 18, slots = {4, 3, 3, 3, 2, 1, 1, 1}, res = { [\"Channel Divinity\"] = {3, 1}, [\"Divine Intervention\"] = {1, 0} } }, { features = {\"Subclass feature\"}, channel_divinity = 3, cantrips = 5, prepared = 19, slots = {4, 3, 3, 3, 2, 1, 1, 1, 1}, res = { [\"Channel Divinity\"] = {3, 1}, [\"Divine Intervention\"] = {1, 0} } }, { features = {}, channel_divinity = 4, cantrips = 5, prepared = 20, slots = {4, 3, 3, 3, 3, 1, 1, 1, 1}, res = { [\"Channel Divinity\"] = {4, 1}, [\"Divine Intervention\"] = {1, 0} } }, { features = {\"Epic Boon\"}, channel_divinity = 4, cantrips = 5, prepared = 21, slots = {4, 3, 3, 3, 3, 2, 1, 1, 1}, res = { [\"Channel Divinity\"] = {4, 1}, [\"Divine Intervention\"] = {1, 0} } }, { features = {\"Greater Divine Intervention\"}, channel_divinity = 4, cantrips = 5, prepared = 22, slots = {4, 3, 3, 3, 3, 2, 2, 1, 1}, res = { [\"Channel Divinity\"] = {4, 1}, [\"Divine Intervention\"] = {1, 0} } }}, subclass = { level = 3, name = \"Life Domain\" }, spell_ability = \"Wisdom\", swap = \"long_all\", mc_gains = { light = true, medium = true, shield = true }, caster = \"full\", subclasses = { [\"Life Domain\"] = { levels = { [\"3\"] = {\"Disciple of Life\", \"Life Domain Spells\", \"Preserve Life\"}, [\"6\"] = {\"Blessed Healer\"}, [\"17\"] = {\"Supreme Healing\"} }, always = { [\"3\"] = {\"Aid\", \"Bless\", \"Cure Wounds\", \"Lesser Restoration\"}, [\"5\"] = {\"Mass Healing Word\", \"Revivify\"}, [\"7\"] = {\"Aura of Life\", \"Death Ward\"}, [\"9\"] = {\"Greater Restoration\", \"Mass Cure Wounds\"} } } } }, Wizard = { hit_die = 6, primary = {\"Intelligence\"}, saves = {\"Intelligence\", \"Wisdom\"}, skills = { choose = 2, from = {\"Arcana\", \"History\", \"Insight\", \"Investigation\", \"Medicine\", \"Nature\", \"Religion\"} }, weapons = \"simple\", armor = {  }, equipment = { A = { items = { Dagger = 2, Quarterstaff = 1 }, gp = 5, other = {\"Robe\", \"Spellbook\", \"Scholar's Pack\"} }, B = { items = {  }, gp = 55, other = {} } }, levels = {{ features = {\"Spellcasting\", \"Ritual Adept\", \"Arcane Recovery\"}, cantrips = 3, prepared = 4, slots = {2, 0, 0}, res = { [\"Arcane Recovery\"] = {1, 0} } }, { features = {\"Scholar\"}, cantrips = 3, prepared = 5, slots = {3, 0, 0}, res = { [\"Arcane Recovery\"] = {1, 0} }, expertise = 1 }, { features = {\"Wizard Subclass\"}, cantrips = 3, prepared = 6, slots = {4, 2, 0}, res = { [\"Arcane Recovery\"] = {1, 0} }, expertise = 1 }, { features = {\"Ability Score Improvement\"}, cantrips = 4, prepared = 7, slots = {4, 3, 0}, res = { [\"Arcane Recovery\"] = {1, 0} }, expertise = 1 }, { features = {\"Memorize Spell\"}, cantrips = 4, prepared = 9, slots = {4, 3, 2}, res = { [\"Arcane Recovery\"] = {1, 0} }, expertise = 1 }, { features = {\"Subclass feature\"}, cantrips = 4, prepared = 10, slots = {4, 3, 3}, res = { [\"Arcane Recovery\"] = {1, 0} }, expertise = 1 }, { features = {}, cantrips = 4, prepared = 11, slots = {4, 3, 3, 1}, res = { [\"Arcane Recovery\"] = {1, 0} }, expertise = 1 }, { features = {\"Ability Score Improvement\"}, cantrips = 4, prepared = 12, slots = {4, 3, 3, 2}, res = { [\"Arcane Recovery\"] = {1, 0} }, expertise = 1 }, { features = {}, cantrips = 4, prepared = 14, slots = {4, 3, 3, 3, 1}, res = { [\"Arcane Recovery\"] = {1, 0} }, expertise = 1 }, { features = {\"Subclass feature\"}, cantrips = 5, prepared = 15, slots = {4, 3, 3, 3, 2}, res = { [\"Arcane Recovery\"] = {1, 0} }, expertise = 1 }, { features = {}, cantrips = 5, prepared = 16, slots = {4, 3, 3, 3, 2, 1}, res = { [\"Arcane Recovery\"] = {1, 0} }, expertise = 1 }, { features = {\"Ability Score Improvement\"}, cantrips = 5, prepared = 16, slots = {4, 3, 3, 3, 2, 1}, res = { [\"Arcane Recovery\"] = {1, 0} }, expertise = 1 }, { features = {}, cantrips = 5, prepared = 17, slots = {4, 3, 3, 3, 2, 1, 1}, res = { [\"Arcane Recovery\"] = {1, 0} }, expertise = 1 }, { features = {\"Subclass feature\"}, cantrips = 5, prepared = 18, slots = {4, 3, 3, 3, 2, 1, 1}, res = { [\"Arcane Recovery\"] = {1, 0} }, expertise = 1 }, { features = {}, cantrips = 5, prepared = 19, slots = {4, 3, 3, 3, 2, 1, 1, 1}, res = { [\"Arcane Recovery\"] = {1, 0} }, expertise = 1 }, { features = {\"Ability Score Improvement\"}, cantrips = 5, prepared = 21, slots = {4, 3, 3, 3, 2, 1, 1, 1}, res = { [\"Arcane Recovery\"] = {1, 0} }, expertise = 1 }, { features = {}, cantrips = 5, prepared = 22, slots = {4, 3, 3, 3, 2, 1, 1, 1, 1}, res = { [\"Arcane Recovery\"] = {1, 0} }, expertise = 1 }, { features = {\"Spell Mastery\"}, cantrips = 5, prepared = 23, slots = {4, 3, 3, 3, 3, 1, 1, 1, 1}, res = { [\"Arcane Recovery\"] = {1, 0} }, expertise = 1 }, { features = {\"Epic Boon\"}, cantrips = 5, prepared = 24, slots = {4, 3, 3, 3, 3, 2, 1, 1, 1}, res = { [\"Arcane Recovery\"] = {1, 0} }, expertise = 1 }, { features = {\"Signature Spells\"}, cantrips = 5, prepared = 25, slots = {4, 3, 3, 3, 3, 2, 2, 1, 1}, res = { [\"Arcane Recovery\"] = {1, 0} }, expertise = 1 }}, subclass = { level = 3, name = \"Evoker\" }, spell_ability = \"Intelligence\", spellbook = true, book = { start = 6, per_level = 2 }, swap = \"long_all\", expertise_from = {\"Arcana\", \"History\", \"Investigation\", \"Medicine\", \"Nature\", \"Religion\"}, mc_gains = {  }, caster = \"full\", subclasses = { Evoker = { levels = { [\"3\"] = {\"Evocation Savant\", \"Potent Cantrip\"}, [\"6\"] = {\"Sculpt Spells\"}, [\"10\"] = {\"Empowered Evocation\"}, [\"14\"] = {\"Overchannel\"} } } } }, Barbarian = { hit_die = 12, primary = {\"Strength\"}, saves = {\"Strength\", \"Constitution\"}, skills = { choose = 2, from = {\"Animal Handling\", \"Athletics\", \"Intimidation\", \"Nature\", \"Perception\", \"Survival\"} }, weapons = \"all\", armor = { light = true, medium = true, shield = true }, equipment = { A = { items = { Greataxe = 1, Handaxe = 4 }, gp = 15, other = {\"Explorer's Pack\"} }, B = { items = {  }, gp = 75, other = {} } }, levels = {{ features = {\"Rage\", \"Unarmored Defense\", \"Weapon Mastery\"}, res = { Rage = {2, 1} }, rage = 2, mastery = 2 }, { features = {\"Danger Sense\", \"Reckless Attack\"}, res = { Rage = {2, 1} }, rage = 2, mastery = 2 }, { features = {\"Barbarian Subclass\", \"Primal Knowledge\"}, res = { Rage = {3, 1} }, rage = 2, mastery = 2, extra_skill = 1 }, { features = {\"Ability Score Improvement\"}, res = { Rage = {3, 1} }, rage = 2, mastery = 3, extra_skill = 1 }, { features = {\"Extra Attack\", \"Fast Movement\"}, res = { Rage = {3, 1} }, rage = 2, mastery = 3, extra_skill = 1, speed = 10 }, { features = {\"Subclass feature\"}, res = { Rage = {4, 1} }, rage = 2, mastery = 3, extra_skill = 1, speed = 10 }, { features = {\"Feral Instinct\", \"Instinctive Pounce\"}, res = { Rage = {4, 1} }, rage = 2, mastery = 3, extra_skill = 1, speed = 10 }, { features = {\"Ability Score Improvement\"}, res = { Rage = {4, 1} }, rage = 2, mastery = 3, extra_skill = 1, speed = 10 }, { features = {\"Brutal Strike\"}, res = { Rage = {4, 1} }, rage = 3, mastery = 3, extra_skill = 1, speed = 10 }, { features = {\"Subclass feature\"}, res = { Rage = {4, 1} }, rage = 3, mastery = 4, extra_skill = 1, speed = 10 }, { features = {\"Relentless Rage\"}, res = { Rage = {4, 1} }, rage = 3, mastery = 4, extra_skill = 1, speed = 10 }, { features = {\"Ability Score Improvement\"}, res = { Rage = {5, 1} }, rage = 3, mastery = 4, extra_skill = 1, speed = 10 }, { features = {\"Improved Brutal Strike\"}, res = { Rage = {5, 1} }, rage = 3, mastery = 4, extra_skill = 1, speed = 10 }, { features = {\"Subclass feature\"}, res = { Rage = {5, 1} }, rage = 3, mastery = 4, extra_skill = 1, speed = 10 }, { features = {\"Persistent Rage\"}, res = { Rage = {5, 1} }, rage = 3, mastery = 4, extra_skill = 1, speed = 10 }, { features = {\"Ability Score Improvement\"}, res = { Rage = {5, 1} }, rage = 4, mastery = 4, extra_skill = 1, speed = 10 }, { features = {\"Improved Brutal Strike (2d10)\"}, res = { Rage = {6, 1} }, rage = 4, mastery = 4, extra_skill = 1, speed = 10 }, { features = {\"Indomitable Might\"}, res = { Rage = {6, 1} }, rage = 4, mastery = 4, extra_skill = 1, speed = 10 }, { features = {\"Epic Boon\"}, res = { Rage = {6, 1} }, rage = 4, mastery = 4, extra_skill = 1, speed = 10 }, { features = {\"Primal Champion\"}, res = { Rage = {6, 1} }, rage = 4, mastery = 4, extra_skill = 1, speed = 10 }}, subclass = { level = 3, name = \"Path of the Berserker\" }, unarmored = \"Constitution\", mc_gains = { martial = true, shield = true }, subclasses = { [\"Path of the Berserker\"] = { levels = { [\"3\"] = {\"Frenzy\"}, [\"6\"] = {\"Mindless Rage\"}, [\"10\"] = {\"Retaliation\"}, [\"14\"] = {\"Intimidating Presence\"} } } } }, Bard = { hit_die = 8, primary = {\"Charisma\"}, saves = {\"Dexterity\", \"Charisma\"}, skills = { choose = 3, from = {\"Acrobatics\", \"Animal Handling\", \"Arcana\", \"Athletics\", \"Deception\", \"History\", \"Insight\", \"Intimidation\", \"Investigation\", \"Medicine\", \"Nature\", \"Perception\", \"Performance\", \"Persuasion\", \"Religion\", \"Sleight of Hand\", \"Stealth\", \"Survival\"} }, weapons = \"simple\", armor = { light = true }, equipment = { A = { items = { [\"Leather Armor\"] = 1, Dagger = 2 }, gp = 19, other = {\"Musical Instrument\", \"Entertainer's Pack\"} }, B = { items = {  }, gp = 90, other = {} } }, levels = {{ features = {\"Bardic Inspiration\", \"Spellcasting\"}, res = { [\"Bardic Inspiration\"] = {\"CHA\", 0} }, bi = \"1d6\", cantrips = 2, prepared = 4, slots = {2, 0, 0} }, { features = {\"Expertise\", \"Jack of All Trades\"}, res = { [\"Bardic Inspiration\"] = {\"CHA\", 0} }, bi = \"1d6\", expertise = 2, cantrips = 2, prepared = 5, slots = {3, 0, 0} }, { features = {\"Bard Subclass\"}, res = { [\"Bardic Inspiration\"] = {\"CHA\", 0} }, bi = \"1d6\", expertise = 2, extra_skill = 3, cantrips = 2, prepared = 6, slots = {4, 2, 0} }, { features = {\"Ability Score Improvement\"}, res = { [\"Bardic Inspiration\"] = {\"CHA\", 0} }, bi = \"1d6\", expertise = 2, extra_skill = 3, cantrips = 3, prepared = 7, slots = {4, 3, 0} }, { features = {\"Font of Inspiration\"}, res = { [\"Bardic Inspiration\"] = {\"CHA\", \"all\"} }, bi = \"1d8\", expertise = 2, extra_skill = 3, cantrips = 3, prepared = 9, slots = {4, 3, 2} }, { features = {\"Subclass feature\"}, res = { [\"Bardic Inspiration\"] = {\"CHA\", \"all\"} }, bi = \"1d8\", expertise = 2, extra_skill = 3, cantrips = 3, prepared = 10, slots = {4, 3, 3} }, { features = {\"Countercharm\"}, res = { [\"Bardic Inspiration\"] = {\"CHA\", \"all\"} }, bi = \"1d8\", expertise = 2, extra_skill = 3, cantrips = 3, prepared = 11, slots = {4, 3, 3, 1} }, { features = {\"Ability Score Improvement\"}, res = { [\"Bardic Inspiration\"] = {\"CHA\", \"all\"} }, bi = \"1d8\", expertise = 2, extra_skill = 3, cantrips = 3, prepared = 12, slots = {4, 3, 3, 2} }, { features = {\"Expertise\"}, res = { [\"Bardic Inspiration\"] = {\"CHA\", \"all\"} }, bi = \"1d8\", expertise = 4, extra_skill = 3, cantrips = 3, prepared = 14, slots = {4, 3, 3, 3, 1} }, { features = {\"Magical Secrets\"}, res = { [\"Bardic Inspiration\"] = {\"CHA\", \"all\"} }, bi = \"1d10\", expertise = 4, extra_skill = 3, cantrips = 4, prepared = 15, slots = {4, 3, 3, 3, 2} }, { features = {}, res = { [\"Bardic Inspiration\"] = {\"CHA\", \"all\"} }, bi = \"1d10\", expertise = 4, extra_skill = 3, cantrips = 4, prepared = 16, slots = {4, 3, 3, 3, 2, 1} }, { features = {\"Ability Score Improvement\"}, res = { [\"Bardic Inspiration\"] = {\"CHA\", \"all\"} }, bi = \"1d10\", expertise = 4, extra_skill = 3, cantrips = 4, prepared = 16, slots = {4, 3, 3, 3, 2, 1} }, { features = {}, res = { [\"Bardic Inspiration\"] = {\"CHA\", \"all\"} }, bi = \"1d10\", expertise = 4, extra_skill = 3, cantrips = 4, prepared = 17, slots = {4, 3, 3, 3, 2, 1, 1} }, { features = {\"Subclass feature\"}, res = { [\"Bardic Inspiration\"] = {\"CHA\", \"all\"} }, bi = \"1d10\", expertise = 4, extra_skill = 3, cantrips = 4, prepared = 17, slots = {4, 3, 3, 3, 2, 1, 1} }, { features = {}, res = { [\"Bardic Inspiration\"] = {\"CHA\", \"all\"} }, bi = \"1d12\", expertise = 4, extra_skill = 3, cantrips = 4, prepared = 18, slots = {4, 3, 3, 3, 2, 1, 1, 1} }, { features = {\"Ability Score Improvement\"}, res = { [\"Bardic Inspiration\"] = {\"CHA\", \"all\"} }, bi = \"1d12\", expertise = 4, extra_skill = 3, cantrips = 4, prepared = 18, slots = {4, 3, 3, 3, 2, 1, 1, 1} }, { features = {}, res = { [\"Bardic Inspiration\"] = {\"CHA\", \"all\"} }, bi = \"1d12\", expertise = 4, extra_skill = 3, cantrips = 4, prepared = 19, slots = {4, 3, 3, 3, 2, 1, 1, 1, 1} }, { features = {\"Superior Inspiration\"}, res = { [\"Bardic Inspiration\"] = {\"CHA\", \"all\"} }, bi = \"1d12\", expertise = 4, extra_skill = 3, cantrips = 4, prepared = 20, slots = {4, 3, 3, 3, 3, 1, 1, 1, 1} }, { features = {\"Epic Boon\"}, res = { [\"Bardic Inspiration\"] = {\"CHA\", \"all\"} }, bi = \"1d12\", expertise = 4, extra_skill = 3, cantrips = 4, prepared = 21, slots = {4, 3, 3, 3, 3, 2, 1, 1, 1} }, { features = {\"Words of Creation\"}, res = { [\"Bardic Inspiration\"] = {\"CHA\", \"all\"} }, bi = \"1d12\", expertise = 4, extra_skill = 3, cantrips = 4, prepared = 22, slots = {4, 3, 3, 3, 3, 2, 2, 1, 1} }}, subclass = { level = 3, name = \"College of Lore\" }, spell_ability = \"Charisma\", swap = \"level_one\", always = { [\"20\"] = {\"Power Word Heal\", \"Power Word Kill\"} }, mc_gains = { light = true, skill = \"any\" }, tools = {\"Musical Instrument\"}, caster = \"full\", subclasses = { [\"College of Lore\"] = { levels = { [\"3\"] = {\"Bonus Proficiencies\", \"Cutting Words\"}, [\"6\"] = {\"Magical Discoveries\"}, [\"14\"] = {\"Peerless Skill\"} }, row_keys = {\"extra_skill\"} } } }, Druid = { hit_die = 8, primary = {\"Wisdom\"}, saves = {\"Intelligence\", \"Wisdom\"}, skills = { choose = 2, from = {\"Animal Handling\", \"Arcana\", \"Insight\", \"Medicine\", \"Nature\", \"Perception\", \"Religion\", \"Survival\"} }, weapons = \"simple\", armor = { light = true, shield = true }, equipment = { A = { items = { [\"Leather Armor\"] = 1, Shield = 1, Sickle = 1, Quarterstaff = 1 }, gp = 9, other = {\"Explorer's Pack\", \"Herbalism Kit\"} }, B = { items = {  }, gp = 50, other = {} } }, levels = {{ features = {\"Spellcasting\", \"Druidic\", \"Primal Order\"}, cantrips = 2, prepared = 4, slots = {2, 0, 0} }, { features = {\"Wild Shape\", \"Wild Companion\"}, res = { [\"Wild Shape\"] = {2, 1} }, forms = \"1/4\", cantrips = 2, prepared = 5, slots = {3, 0, 0} }, { features = {\"Druid Subclass\"}, res = { [\"Wild Shape\"] = {2, 1} }, forms = \"1/4\", cantrips = 2, prepared = 6, slots = {4, 2, 0} }, { features = {\"Ability Score Improvement\"}, res = { [\"Wild Shape\"] = {2, 1} }, forms = \"1/2\", cantrips = 3, prepared = 7, slots = {4, 3, 0} }, { features = {\"Wild Resurgence\"}, res = { [\"Wild Shape\"] = {2, 1} }, forms = \"1/2\", cantrips = 3, prepared = 9, slots = {4, 3, 2} }, { features = {\"Subclass feature\"}, res = { [\"Wild Shape\"] = {3, 1} }, forms = \"1/2\", fly = false, cantrips = 3, prepared = 10, slots = {4, 3, 3} }, { features = {\"Elemental Fury\"}, res = { [\"Wild Shape\"] = {3, 1} }, forms = \"1/2\", fly = false, cantrips = 3, prepared = 11, slots = {4, 3, 3, 1} }, { features = {\"Ability Score Improvement\"}, res = { [\"Wild Shape\"] = {3, 1} }, forms = \"1\", fly = true, cantrips = 3, prepared = 12, slots = {4, 3, 3, 2} }, { features = {}, res = { [\"Wild Shape\"] = {3, 1} }, forms = \"1\", fly = true, cantrips = 3, prepared = 14, slots = {4, 3, 3, 3, 1} }, { features = {\"Subclass feature\"}, res = { [\"Wild Shape\"] = {3, 1} }, forms = \"1\", fly = true, cantrips = 4, prepared = 15, slots = {4, 3, 3, 3, 2} }, { features = {}, res = { [\"Wild Shape\"] = {3, 1} }, forms = \"1\", fly = true, cantrips = 4, prepared = 16, slots = {4, 3, 3, 3, 2, 1} }, { features = {\"Ability Score Improvement\"}, res = { [\"Wild Shape\"] = {3, 1} }, forms = \"1\", fly = true, cantrips = 4, prepared = 16, slots = {4, 3, 3, 3, 2, 1} }, { features = {}, res = { [\"Wild Shape\"] = {3, 1} }, forms = \"1\", fly = true, cantrips = 4, prepared = 17, slots = {4, 3, 3, 3, 2, 1, 1} }, { features = {\"Subclass feature\"}, res = { [\"Wild Shape\"] = {3, 1} }, forms = \"1\", fly = true, cantrips = 4, prepared = 17, slots = {4, 3, 3, 3, 2, 1, 1} }, { features = {\"Improved Elemental Fury\"}, res = { [\"Wild Shape\"] = {3, 1} }, forms = \"1\", fly = true, cantrips = 4, prepared = 18, slots = {4, 3, 3, 3, 2, 1, 1, 1} }, { features = {\"Ability Score Improvement\"}, res = { [\"Wild Shape\"] = {3, 1} }, forms = \"1\", fly = true, cantrips = 4, prepared = 18, slots = {4, 3, 3, 3, 2, 1, 1, 1} }, { features = {}, res = { [\"Wild Shape\"] = {4, 1} }, forms = \"1\", fly = true, cantrips = 4, prepared = 19, slots = {4, 3, 3, 3, 2, 1, 1, 1, 1} }, { features = {\"Beast Spells\"}, res = { [\"Wild Shape\"] = {4, 1} }, forms = \"1\", fly = true, cantrips = 4, prepared = 20, slots = {4, 3, 3, 3, 3, 1, 1, 1, 1} }, { features = {\"Epic Boon\"}, res = { [\"Wild Shape\"] = {4, 1} }, forms = \"1\", fly = true, cantrips = 4, prepared = 21, slots = {4, 3, 3, 3, 3, 2, 1, 1, 1} }, { features = {\"Archdruid\"}, res = { [\"Wild Shape\"] = {4, 1} }, forms = \"1\", fly = true, cantrips = 4, prepared = 22, slots = {4, 3, 3, 3, 3, 2, 2, 1, 1} }}, subclass = { level = 3, name = \"Circle of the Land\" }, spell_ability = \"Wisdom\", swap = \"long_all\", always = { [\"1\"] = {\"Speak with Animals\"} }, mc_gains = { light = true, shield = true }, tools = {\"Herbalism Kit\"}, caster = \"full\", subclasses = { [\"Circle of the Land\"] = { levels = { [\"3\"] = {\"Circle of the Land Spells\", \"Land's Aid\"}, [\"6\"] = {\"Natural Recovery\"}, [\"10\"] = {\"Nature's Ward\"}, [\"14\"] = {\"Nature's Sanctuary\"} } } } }, Monk = { hit_die = 8, primary = {\"Dexterity\", \"Wisdom\"}, saves = {\"Strength\", \"Dexterity\"}, skills = { choose = 2, from = {\"Acrobatics\", \"Athletics\", \"History\", \"Insight\", \"Religion\", \"Stealth\"} }, weapons = \"light\", armor = {  }, equipment = { A = { items = { Spear = 1, Dagger = 5 }, gp = 11, other = {\"Artisan's Tools\", \"Explorer's Pack\"} }, B = { items = {  }, gp = 50, other = {} } }, levels = {{ features = {\"Martial Arts\", \"Unarmored Defense\"}, martial_arts = \"1d6\" }, { features = {\"Monk's Focus\", \"Unarmored Movement\", \"Uncanny Metabolism\"}, martial_arts = \"1d6\", speed = 10, res = { [\"Focus Points\"] = {\"L\", \"all\"}, [\"Uncanny Metabolism\"] = {1, 0} } }, { features = {\"Deflect Attacks\", \"Monk Subclass\"}, martial_arts = \"1d6\", speed = 10, res = { [\"Focus Points\"] = {\"L\", \"all\"}, [\"Uncanny Metabolism\"] = {1, 0} } }, { features = {\"Ability Score Improvement\", \"Slow Fall\"}, martial_arts = \"1d6\", speed = 10, res = { [\"Focus Points\"] = {\"L\", \"all\"}, [\"Uncanny Metabolism\"] = {1, 0} } }, { features = {\"Extra Attack\", \"Stunning Strike\"}, martial_arts = \"1d8\", speed = 10, res = { [\"Focus Points\"] = {\"L\", \"all\"}, [\"Uncanny Metabolism\"] = {1, 0} } }, { features = {\"Empowered Strikes\", \"Subclass feature\"}, martial_arts = \"1d8\", speed = 15, res = { [\"Focus Points\"] = {\"L\", \"all\"}, [\"Uncanny Metabolism\"] = {1, 0} } }, { features = {\"Evasion\"}, martial_arts = \"1d8\", speed = 15, res = { [\"Focus Points\"] = {\"L\", \"all\"}, [\"Uncanny Metabolism\"] = {1, 0} } }, { features = {\"Ability Score Improvement\"}, martial_arts = \"1d8\", speed = 15, res = { [\"Focus Points\"] = {\"L\", \"all\"}, [\"Uncanny Metabolism\"] = {1, 0} } }, { features = {\"Acrobatic Movement\"}, martial_arts = \"1d8\", speed = 15, res = { [\"Focus Points\"] = {\"L\", \"all\"}, [\"Uncanny Metabolism\"] = {1, 0} } }, { features = {\"Heightened Focus\", \"Self-Restoration\"}, martial_arts = \"1d8\", speed = 20, res = { [\"Focus Points\"] = {\"L\", \"all\"}, [\"Uncanny Metabolism\"] = {1, 0} } }, { features = {\"Subclass feature\"}, martial_arts = \"1d10\", speed = 20, res = { [\"Focus Points\"] = {\"L\", \"all\"}, [\"Uncanny Metabolism\"] = {1, 0} } }, { features = {\"Ability Score Improvement\"}, martial_arts = \"1d10\", speed = 20, res = { [\"Focus Points\"] = {\"L\", \"all\"}, [\"Uncanny Metabolism\"] = {1, 0} } }, { features = {\"Deflect Energy\"}, martial_arts = \"1d10\", speed = 20, res = { [\"Focus Points\"] = {\"L\", \"all\"}, [\"Uncanny Metabolism\"] = {1, 0} } }, { features = {\"Disciplined Survivor\"}, martial_arts = \"1d10\", speed = 25, res = { [\"Focus Points\"] = {\"L\", \"all\"}, [\"Uncanny Metabolism\"] = {1, 0} } }, { features = {\"Perfect Focus\"}, martial_arts = \"1d10\", speed = 25, res = { [\"Focus Points\"] = {\"L\", \"all\"}, [\"Uncanny Metabolism\"] = {1, 0} } }, { features = {\"Ability Score Improvement\"}, martial_arts = \"1d10\", speed = 25, res = { [\"Focus Points\"] = {\"L\", \"all\"}, [\"Uncanny Metabolism\"] = {1, 0} } }, { features = {\"Subclass feature\"}, martial_arts = \"1d12\", speed = 25, res = { [\"Focus Points\"] = {\"L\", \"all\"}, [\"Uncanny Metabolism\"] = {1, 0} } }, { features = {\"Superior Defense\"}, martial_arts = \"1d12\", speed = 30, res = { [\"Focus Points\"] = {\"L\", \"all\"}, [\"Uncanny Metabolism\"] = {1, 0} } }, { features = {\"Epic Boon\"}, martial_arts = \"1d12\", speed = 30, res = { [\"Focus Points\"] = {\"L\", \"all\"}, [\"Uncanny Metabolism\"] = {1, 0} } }, { features = {\"Body and Mind\"}, martial_arts = \"1d12\", speed = 30, res = { [\"Focus Points\"] = {\"L\", \"all\"}, [\"Uncanny Metabolism\"] = {1, 0} } }}, subclass = { level = 3, name = \"Warrior of the Open Hand\" }, unarmored = \"Wisdom\", unarmored_no_shield = true, mc_gains = {  }, subclasses = { [\"Warrior of the Open Hand\"] = { levels = { [\"3\"] = {\"Open Hand Technique\"}, [\"6\"] = {\"Wholeness of Body\"}, [\"11\"] = {\"Fleet Step\"}, [\"17\"] = {\"Quivering Palm\"} } } } }, Paladin = { hit_die = 10, primary = {\"Strength\", \"Charisma\"}, saves = {\"Wisdom\", \"Charisma\"}, skills = { choose = 2, from = {\"Athletics\", \"Insight\", \"Intimidation\", \"Medicine\", \"Persuasion\", \"Religion\"} }, weapons = \"all\", armor = { light = true, medium = true, heavy = true, shield = true }, equipment = { A = { items = { [\"Chain Mail\"] = 1, Shield = 1, Longsword = 1, Javelin = 6 }, gp = 9, other = {\"Holy Symbol\", \"Priest's Pack\"} }, B = { items = {  }, gp = 150, other = {} } }, levels = {{ features = {\"Lay On Hands\", \"Spellcasting\", \"Weapon Mastery\"}, res = { [\"Lay On Hands\"] = {\"5L\", 0} }, mastery = 2, cantrips = 0, prepared = 2, slots = {2, 0, 0} }, { features = {\"Fighting Style\", \"Paladin's Smite\"}, res = { [\"Lay On Hands\"] = {\"5L\", 0}, [\"Divine Smite (free)\"] = {1, 0} }, mastery = 2, cantrips = 0, prepared = 3, slots = {2, 0, 0} }, { features = {\"Channel Divinity\", \"Paladin Subclass\"}, res = { [\"Lay On Hands\"] = {\"5L\", 0}, [\"Divine Smite (free)\"] = {1, 0}, [\"Channel Divinity\"] = {2, 1} }, mastery = 2, cantrips = 0, prepared = 4, slots = {3, 0, 0} }, { features = {\"Ability Score Improvement\"}, res = { [\"Lay On Hands\"] = {\"5L\", 0}, [\"Divine Smite (free)\"] = {1, 0}, [\"Channel Divinity\"] = {2, 1} }, mastery = 2, cantrips = 0, prepared = 5, slots = {3, 0, 0} }, { features = {\"Extra Attack\", \"Faithful Steed\"}, res = { [\"Lay On Hands\"] = {\"5L\", 0}, [\"Divine Smite (free)\"] = {1, 0}, [\"Channel Divinity\"] = {2, 1}, [\"Find Steed (free)\"] = {1, 0} }, mastery = 2, cantrips = 0, prepared = 6, slots = {4, 2, 0} }, { features = {\"Aura of Protection\"}, res = { [\"Lay On Hands\"] = {\"5L\", 0}, [\"Divine Smite (free)\"] = {1, 0}, [\"Channel Divinity\"] = {2, 1}, [\"Find Steed (free)\"] = {1, 0} }, mastery = 2, cantrips = 0, prepared = 6, slots = {4, 2} }, { features = {\"Subclass feature\"}, res = { [\"Lay On Hands\"] = {\"5L\", 0}, [\"Divine Smite (free)\"] = {1, 0}, [\"Channel Divinity\"] = {2, 1}, [\"Find Steed (free)\"] = {1, 0} }, mastery = 2, cantrips = 0, prepared = 7, slots = {4, 3} }, { features = {\"Ability Score Improvement\"}, res = { [\"Lay On Hands\"] = {\"5L\", 0}, [\"Divine Smite (free)\"] = {1, 0}, [\"Channel Divinity\"] = {2, 1}, [\"Find Steed (free)\"] = {1, 0} }, mastery = 2, cantrips = 0, prepared = 7, slots = {4, 3} }, { features = {\"Abjure Foes\"}, res = { [\"Lay On Hands\"] = {\"5L\", 0}, [\"Divine Smite (free)\"] = {1, 0}, [\"Channel Divinity\"] = {2, 1}, [\"Find Steed (free)\"] = {1, 0} }, mastery = 2, cantrips = 0, prepared = 9, slots = {4, 3, 2} }, { features = {\"Aura of Courage\"}, res = { [\"Lay On Hands\"] = {\"5L\", 0}, [\"Divine Smite (free)\"] = {1, 0}, [\"Channel Divinity\"] = {2, 1}, [\"Find Steed (free)\"] = {1, 0} }, mastery = 2, cantrips = 0, prepared = 9, slots = {4, 3, 2} }, { features = {\"Radiant Strikes\"}, res = { [\"Lay On Hands\"] = {\"5L\", 0}, [\"Divine Smite (free)\"] = {1, 0}, [\"Channel Divinity\"] = {3, 1}, [\"Find Steed (free)\"] = {1, 0} }, mastery = 2, cantrips = 0, prepared = 10, slots = {4, 3, 3} }, { features = {\"Ability Score Improvement\"}, res = { [\"Lay On Hands\"] = {\"5L\", 0}, [\"Divine Smite (free)\"] = {1, 0}, [\"Channel Divinity\"] = {3, 1}, [\"Find Steed (free)\"] = {1, 0} }, mastery = 2, cantrips = 0, prepared = 10, slots = {4, 3, 3} }, { features = {}, res = { [\"Lay On Hands\"] = {\"5L\", 0}, [\"Divine Smite (free)\"] = {1, 0}, [\"Channel Divinity\"] = {3, 1}, [\"Find Steed (free)\"] = {1, 0} }, mastery = 2, cantrips = 0, prepared = 11, slots = {4, 3, 3, 1} }, { features = {\"Restoring Touch\"}, res = { [\"Lay On Hands\"] = {\"5L\", 0}, [\"Divine Smite (free)\"] = {1, 0}, [\"Channel Divinity\"] = {3, 1}, [\"Find Steed (free)\"] = {1, 0} }, mastery = 2, cantrips = 0, prepared = 11, slots = {4, 3, 3, 1} }, { features = {\"Subclass feature\"}, res = { [\"Lay On Hands\"] = {\"5L\", 0}, [\"Divine Smite (free)\"] = {1, 0}, [\"Channel Divinity\"] = {3, 1}, [\"Find Steed (free)\"] = {1, 0} }, mastery = 2, cantrips = 0, prepared = 12, slots = {4, 3, 3, 2} }, { features = {\"Ability Score Improvement\"}, res = { [\"Lay On Hands\"] = {\"5L\", 0}, [\"Divine Smite (free)\"] = {1, 0}, [\"Channel Divinity\"] = {3, 1}, [\"Find Steed (free)\"] = {1, 0} }, mastery = 2, cantrips = 0, prepared = 12, slots = {4, 3, 3, 2} }, { features = {}, res = { [\"Lay On Hands\"] = {\"5L\", 0}, [\"Divine Smite (free)\"] = {1, 0}, [\"Channel Divinity\"] = {3, 1}, [\"Find Steed (free)\"] = {1, 0} }, mastery = 2, cantrips = 0, prepared = 14, slots = {4, 3, 3, 3, 1} }, { features = {\"Aura Expansion\"}, res = { [\"Lay On Hands\"] = {\"5L\", 0}, [\"Divine Smite (free)\"] = {1, 0}, [\"Channel Divinity\"] = {3, 1}, [\"Find Steed (free)\"] = {1, 0} }, mastery = 2, cantrips = 0, prepared = 14, slots = {4, 3, 3, 3, 1} }, { features = {\"Epic Boon\"}, res = { [\"Lay On Hands\"] = {\"5L\", 0}, [\"Divine Smite (free)\"] = {1, 0}, [\"Channel Divinity\"] = {3, 1}, [\"Find Steed (free)\"] = {1, 0} }, mastery = 2, cantrips = 0, prepared = 15, slots = {4, 3, 3, 3, 2} }, { features = {\"Subclass feature\"}, res = { [\"Lay On Hands\"] = {\"5L\", 0}, [\"Divine Smite (free)\"] = {1, 0}, [\"Channel Divinity\"] = {3, 1}, [\"Find Steed (free)\"] = {1, 0} }, mastery = 2, cantrips = 0, prepared = 15, slots = {4, 3, 3, 3, 2} }}, subclass = { level = 3, name = \"Oath of Devotion\" }, spell_ability = \"Charisma\", swap = \"long_one\", style_at = 2, always = { [\"2\"] = {\"Divine Smite\"}, [\"5\"] = {\"Find Steed\"} }, mc_gains = { martial = true, light = true, medium = true, shield = true }, caster = \"half\", subclasses = { [\"Oath of Devotion\"] = { levels = { [\"3\"] = {\"Oath of Devotion Spells\", \"Sacred Weapon\"}, [\"7\"] = {\"Aura of Devotion\"}, [\"15\"] = {\"Smite of Protection\"}, [\"20\"] = {\"Holy Nimbus\"} }, always = { [\"3\"] = {\"Protection from Evil and Good\", \"Shield of Faith\"}, [\"5\"] = {\"Aid\", \"Zone of Truth\"}, [\"9\"] = {\"Beacon of Hope\", \"Dispel Magic\"}, [\"13\"] = {\"Freedom of Movement\", \"Guardian of Faith\"}, [\"17\"] = {\"Commune\", \"Flame Strike\"} } } } }, Ranger = { hit_die = 10, primary = {\"Dexterity\", \"Wisdom\"}, saves = {\"Strength\", \"Dexterity\"}, skills = { choose = 3, from = {\"Animal Handling\", \"Athletics\", \"Insight\", \"Investigation\", \"Nature\", \"Perception\", \"Stealth\", \"Survival\"} }, weapons = \"all\", armor = { light = true, medium = true, shield = true }, equipment = { A = { items = { [\"Studded Leather Armor\"] = 1, Scimitar = 1, Shortsword = 1, Longbow = 1, Arrows = 20 }, gp = 7, other = {\"Quiver\", \"Druidic Focus (sprig of mistletoe)\", \"Explorer's Pack\"} }, B = { items = {  }, gp = 150, other = {} } }, levels = {{ features = {\"Spellcasting\", \"Favored Enemy\", \"Weapon Mastery\"}, res = { [\"Hunter's Mark (free)\"] = {2, 0} }, mastery = 2, cantrips = 0, prepared = 2, slots = {2, 0, 0} }, { features = {\"Deft Explorer\", \"Fighting Style\"}, res = { [\"Hunter's Mark (free)\"] = {2, 0} }, mastery = 2, expertise = 1, cantrips = 0, prepared = 3, slots = {2, 0, 0} }, { features = {\"Ranger Subclass\"}, res = { [\"Hunter's Mark (free)\"] = {2, 0} }, mastery = 2, expertise = 1, cantrips = 0, prepared = 4, slots = {3, 0, 0} }, { features = {\"Ability Score Improvement\"}, res = { [\"Hunter's Mark (free)\"] = {2, 0} }, mastery = 2, expertise = 1, cantrips = 0, prepared = 5, slots = {3, 0, 0} }, { features = {\"Extra Attack\"}, res = { [\"Hunter's Mark (free)\"] = {3, 0} }, mastery = 2, expertise = 1, cantrips = 0, prepared = 6, slots = {4, 2, 0} }, { features = {\"Roving\"}, res = { [\"Hunter's Mark (free)\"] = {3, 0} }, mastery = 2, expertise = 1, speed = 10, cantrips = 0, prepared = 6, slots = {4, 2} }, { features = {\"Subclass feature\"}, res = { [\"Hunter's Mark (free)\"] = {3, 0} }, mastery = 2, expertise = 1, speed = 10, cantrips = 0, prepared = 7, slots = {4, 3} }, { features = {\"Ability Score Improvement\"}, res = { [\"Hunter's Mark (free)\"] = {3, 0} }, mastery = 2, expertise = 1, speed = 10, cantrips = 0, prepared = 7, slots = {4, 3} }, { features = {\"Expertise\"}, res = { [\"Hunter's Mark (free)\"] = {4, 0} }, mastery = 2, expertise = 3, speed = 10, cantrips = 0, prepared = 9, slots = {4, 3, 2} }, { features = {\"Tireless\"}, res = { [\"Hunter's Mark (free)\"] = {4, 0}, Tireless = {\"WIS\", 0} }, mastery = 2, expertise = 3, speed = 10, cantrips = 0, prepared = 9, slots = {4, 3, 2} }, { features = {\"Subclass feature\"}, res = { [\"Hunter's Mark (free)\"] = {4, 0}, Tireless = {\"WIS\", 0} }, mastery = 2, expertise = 3, speed = 10, cantrips = 0, prepared = 10, slots = {4, 3, 3} }, { features = {\"Ability Score Improvement\"}, res = { [\"Hunter's Mark (free)\"] = {4, 0}, Tireless = {\"WIS\", 0} }, mastery = 2, expertise = 3, speed = 10, cantrips = 0, prepared = 10, slots = {4, 3, 3} }, { features = {\"Relentless Hunter\"}, res = { [\"Hunter's Mark (free)\"] = {5, 0}, Tireless = {\"WIS\", 0} }, mastery = 2, expertise = 3, speed = 10, cantrips = 0, prepared = 11, slots = {4, 3, 3, 1} }, { features = {\"Nature's Veil\"}, res = { [\"Hunter's Mark (free)\"] = {5, 0}, Tireless = {\"WIS\", 0}, [\"Nature's Veil\"] = {\"WIS\", 0} }, mastery = 2, expertise = 3, speed = 10, cantrips = 0, prepared = 11, slots = {4, 3, 3, 1} }, { features = {\"Subclass feature\"}, res = { [\"Hunter's Mark (free)\"] = {5, 0}, Tireless = {\"WIS\", 0}, [\"Nature's Veil\"] = {\"WIS\", 0} }, mastery = 2, expertise = 3, speed = 10, cantrips = 0, prepared = 12, slots = {4, 3, 3, 2} }, { features = {\"Ability Score Improvement\"}, res = { [\"Hunter's Mark (free)\"] = {5, 0}, Tireless = {\"WIS\", 0}, [\"Nature's Veil\"] = {\"WIS\", 0} }, mastery = 2, expertise = 3, speed = 10, cantrips = 0, prepared = 12, slots = {4, 3, 3, 2} }, { features = {\"Precise Hunter\"}, res = { [\"Hunter's Mark (free)\"] = {6, 0}, Tireless = {\"WIS\", 0}, [\"Nature's Veil\"] = {\"WIS\", 0} }, mastery = 2, expertise = 3, speed = 10, cantrips = 0, prepared = 14, slots = {4, 3, 3, 3, 1} }, { features = {\"Feral Senses\"}, res = { [\"Hunter's Mark (free)\"] = {6, 0}, Tireless = {\"WIS\", 0}, [\"Nature's Veil\"] = {\"WIS\", 0} }, mastery = 2, expertise = 3, speed = 10, cantrips = 0, prepared = 14, slots = {4, 3, 3, 3, 1} }, { features = {\"Epic Boon\"}, res = { [\"Hunter's Mark (free)\"] = {6, 0}, Tireless = {\"WIS\", 0}, [\"Nature's Veil\"] = {\"WIS\", 0} }, mastery = 2, expertise = 3, speed = 10, cantrips = 0, prepared = 15, slots = {4, 3, 3, 3, 2} }, { features = {\"Foe Slayer\"}, res = { [\"Hunter's Mark (free)\"] = {6, 0}, Tireless = {\"WIS\", 0}, [\"Nature's Veil\"] = {\"WIS\", 0} }, mastery = 2, expertise = 3, speed = 10, cantrips = 0, prepared = 15, slots = {4, 3, 3, 3, 2} }}, subclass = { level = 3, name = \"Hunter\" }, spell_ability = \"Wisdom\", swap = \"long_one\", style_at = 2, always = { [\"1\"] = {\"Hunter's Mark\"} }, mc_gains = { martial = true, light = true, medium = true, shield = true, skill = \"class\" }, caster = \"half\", subclasses = { Hunter = { levels = { [\"3\"] = {\"Hunter's Lore\", \"Hunter's Prey\"}, [\"7\"] = {\"Defensive Tactics\"}, [\"11\"] = {\"Superior Hunter's Prey\"}, [\"15\"] = {\"Superior Hunter's Defense\"} } } } }, Sorcerer = { hit_die = 6, primary = {\"Charisma\"}, saves = {\"Constitution\", \"Charisma\"}, skills = { choose = 2, from = {\"Arcana\", \"Deception\", \"Insight\", \"Intimidation\", \"Persuasion\", \"Religion\"} }, weapons = \"simple\", armor = {  }, equipment = { A = { items = { Spear = 1, Dagger = 2 }, gp = 28, other = {\"Arcane Focus (crystal)\", \"Dungeoneer's Pack\"} }, B = { items = {  }, gp = 50, other = {} } }, levels = {{ features = {\"Spellcasting\", \"Innate Sorcery\"}, res = { [\"Innate Sorcery\"] = {2, 0} }, cantrips = 4, prepared = 2, slots = {2, 0, 0} }, { features = {\"Font of Magic\", \"Metamagic\"}, res = { [\"Innate Sorcery\"] = {2, 0}, [\"Sorcery Points\"] = {\"L\", 0} }, metamagic = 2, cantrips = 4, prepared = 4, slots = {3, 0, 0} }, { features = {\"Sorcerer Subclass\"}, res = { [\"Innate Sorcery\"] = {2, 0}, [\"Sorcery Points\"] = {\"L\", 0} }, metamagic = 2, hp_bonus = 3, unarmored = \"Charisma\", cantrips = 4, prepared = 6, slots = {4, 2, 0} }, { features = {\"Ability Score Improvement\"}, res = { [\"Innate Sorcery\"] = {2, 0}, [\"Sorcery Points\"] = {\"L\", 0} }, metamagic = 2, hp_bonus = 4, unarmored = \"Charisma\", cantrips = 5, prepared = 7, slots = {4, 3, 0} }, { features = {\"Sorcerous Restoration\"}, res = { [\"Innate Sorcery\"] = {2, 0}, [\"Sorcery Points\"] = {\"L\", 0}, [\"Sorcerous Restoration\"] = {1, 0} }, metamagic = 2, hp_bonus = 5, unarmored = \"Charisma\", cantrips = 5, prepared = 9, slots = {4, 3, 2} }, { features = {\"Subclass feature\"}, res = { [\"Innate Sorcery\"] = {2, 0}, [\"Sorcery Points\"] = {\"L\", 0}, [\"Sorcerous Restoration\"] = {1, 0} }, metamagic = 2, hp_bonus = 6, unarmored = \"Charisma\", cantrips = 5, prepared = 10, slots = {4, 3, 3} }, { features = {\"Sorcery Incarnate\"}, res = { [\"Innate Sorcery\"] = {2, 0}, [\"Sorcery Points\"] = {\"L\", 0}, [\"Sorcerous Restoration\"] = {1, 0} }, metamagic = 2, hp_bonus = 7, unarmored = \"Charisma\", cantrips = 5, prepared = 11, slots = {4, 3, 3, 1} }, { features = {\"Ability Score Improvement\"}, res = { [\"Innate Sorcery\"] = {2, 0}, [\"Sorcery Points\"] = {\"L\", 0}, [\"Sorcerous Restoration\"] = {1, 0} }, metamagic = 2, hp_bonus = 8, unarmored = \"Charisma\", cantrips = 5, prepared = 12, slots = {4, 3, 3, 2} }, { features = {}, res = { [\"Innate Sorcery\"] = {2, 0}, [\"Sorcery Points\"] = {\"L\", 0}, [\"Sorcerous Restoration\"] = {1, 0} }, metamagic = 2, hp_bonus = 9, unarmored = \"Charisma\", cantrips = 5, prepared = 14, slots = {4, 3, 3, 3, 1} }, { features = {\"Metamagic\"}, res = { [\"Innate Sorcery\"] = {2, 0}, [\"Sorcery Points\"] = {\"L\", 0}, [\"Sorcerous Restoration\"] = {1, 0} }, metamagic = 4, hp_bonus = 10, unarmored = \"Charisma\", cantrips = 6, prepared = 15, slots = {4, 3, 3, 3, 2} }, { features = {}, res = { [\"Innate Sorcery\"] = {2, 0}, [\"Sorcery Points\"] = {\"L\", 0}, [\"Sorcerous Restoration\"] = {1, 0} }, metamagic = 4, hp_bonus = 11, unarmored = \"Charisma\", cantrips = 6, prepared = 16, slots = {4, 3, 3, 3, 2, 1} }, { features = {\"Ability Score Improvement\"}, res = { [\"Innate Sorcery\"] = {2, 0}, [\"Sorcery Points\"] = {\"L\", 0}, [\"Sorcerous Restoration\"] = {1, 0} }, metamagic = 4, hp_bonus = 12, unarmored = \"Charisma\", cantrips = 6, prepared = 16, slots = {4, 3, 3, 3, 2, 1} }, { features = {}, res = { [\"Innate Sorcery\"] = {2, 0}, [\"Sorcery Points\"] = {\"L\", 0}, [\"Sorcerous Restoration\"] = {1, 0} }, metamagic = 4, hp_bonus = 13, unarmored = \"Charisma\", cantrips = 6, prepared = 17, slots = {4, 3, 3, 3, 2, 1, 1} }, { features = {\"Subclass feature\"}, res = { [\"Innate Sorcery\"] = {2, 0}, [\"Sorcery Points\"] = {\"L\", 0}, [\"Sorcerous Restoration\"] = {1, 0} }, metamagic = 4, hp_bonus = 14, unarmored = \"Charisma\", cantrips = 6, prepared = 17, slots = {4, 3, 3, 3, 2, 1, 1} }, { features = {}, res = { [\"Innate Sorcery\"] = {2, 0}, [\"Sorcery Points\"] = {\"L\", 0}, [\"Sorcerous Restoration\"] = {1, 0} }, metamagic = 4, hp_bonus = 15, unarmored = \"Charisma\", cantrips = 6, prepared = 18, slots = {4, 3, 3, 3, 2, 1, 1, 1} }, { features = {\"Ability Score Improvement\"}, res = { [\"Innate Sorcery\"] = {2, 0}, [\"Sorcery Points\"] = {\"L\", 0}, [\"Sorcerous Restoration\"] = {1, 0} }, metamagic = 4, hp_bonus = 16, unarmored = \"Charisma\", cantrips = 6, prepared = 18, slots = {4, 3, 3, 3, 2, 1, 1, 1} }, { features = {\"Metamagic\"}, res = { [\"Innate Sorcery\"] = {2, 0}, [\"Sorcery Points\"] = {\"L\", 0}, [\"Sorcerous Restoration\"] = {1, 0} }, metamagic = 6, hp_bonus = 17, unarmored = \"Charisma\", cantrips = 6, prepared = 19, slots = {4, 3, 3, 3, 2, 1, 1, 1, 1} }, { features = {\"Subclass feature\"}, res = { [\"Innate Sorcery\"] = {2, 0}, [\"Sorcery Points\"] = {\"L\", 0}, [\"Sorcerous Restoration\"] = {1, 0}, [\"Summon Dragon (free)\"] = {1, 0} }, metamagic = 6, hp_bonus = 18, unarmored = \"Charisma\", cantrips = 6, prepared = 20, slots = {4, 3, 3, 3, 3, 1, 1, 1, 1} }, { features = {\"Epic Boon\"}, res = { [\"Innate Sorcery\"] = {2, 0}, [\"Sorcery Points\"] = {\"L\", 0}, [\"Sorcerous Restoration\"] = {1, 0}, [\"Summon Dragon (free)\"] = {1, 0} }, metamagic = 6, hp_bonus = 19, unarmored = \"Charisma\", cantrips = 6, prepared = 21, slots = {4, 3, 3, 3, 3, 2, 1, 1, 1} }, { features = {\"Arcane Apotheosis\"}, res = { [\"Innate Sorcery\"] = {2, 0}, [\"Sorcery Points\"] = {\"L\", 0}, [\"Sorcerous Restoration\"] = {1, 0}, [\"Summon Dragon (free)\"] = {1, 0} }, metamagic = 6, hp_bonus = 20, unarmored = \"Charisma\", cantrips = 6, prepared = 22, slots = {4, 3, 3, 3, 3, 2, 2, 1, 1} }}, subclass = { level = 3, name = \"Draconic Sorcery\" }, spell_ability = \"Charisma\", swap = \"level_one\", mc_gains = {  }, caster = \"full\", subclasses = { [\"Draconic Sorcery\"] = { levels = { [\"3\"] = {\"Draconic Resilience\", \"Draconic Spells\"}, [\"6\"] = {\"Elemental Affinity\"}, [\"14\"] = {\"Dragon Wings\"}, [\"18\"] = {\"Dragon Companion\"} }, always = { [\"3\"] = {\"Alter Self\", \"Chromatic Orb\", \"Command\", \"Dragon's Breath\"}, [\"5\"] = {\"Fear\", \"Fly\"}, [\"7\"] = {\"Arcane Eye\", \"Charm Monster\"}, [\"9\"] = {\"Legend Lore\", \"Summon Dragon\"} }, row_keys = {\"hp_bonus\", \"unarmored\"}, row_res = {\"Summon Dragon (free)\"} } } }, Warlock = { hit_die = 8, primary = {\"Charisma\"}, saves = {\"Wisdom\", \"Charisma\"}, skills = { choose = 2, from = {\"Arcana\", \"Deception\", \"History\", \"Intimidation\", \"Investigation\", \"Nature\", \"Religion\"} }, weapons = \"simple\", armor = { light = true }, equipment = { A = { items = { [\"Leather Armor\"] = 1, Sickle = 1, Dagger = 2 }, gp = 15, other = {\"Arcane Focus (orb)\", \"Book (occult lore)\", \"Scholar's Pack\"} }, B = { items = {  }, gp = 100, other = {} } }, levels = {{ features = {\"Eldritch Invocations\", \"Pact Magic\"}, invocations = 1, cantrips = 2, prepared = 2, slots = {1, 0, 0} }, { features = {\"Magical Cunning\"}, res = { [\"Magical Cunning\"] = {1, 0} }, invocations = 3, cantrips = 2, prepared = 3, slots = {2, 0, 0} }, { features = {\"Warlock Subclass\"}, res = { [\"Magical Cunning\"] = {1, 0} }, invocations = 3, cantrips = 2, prepared = 4, slots = {0, 2, 0} }, { features = {\"Ability Score Improvement\"}, res = { [\"Magical Cunning\"] = {1, 0} }, invocations = 3, cantrips = 3, prepared = 5, slots = {0, 2, 0} }, { features = {}, res = { [\"Magical Cunning\"] = {1, 0} }, invocations = 5, cantrips = 3, prepared = 6, slots = {0, 0, 2} }, { features = {\"Subclass feature\"}, res = { [\"Magical Cunning\"] = {1, 0} }, invocations = 5, cantrips = 3, prepared = 7, slots = {0, 0, 2} }, { features = {}, res = { [\"Magical Cunning\"] = {1, 0} }, invocations = 6, cantrips = 3, prepared = 8, slots = {0, 0, 0, 2} }, { features = {\"Ability Score Improvement\"}, res = { [\"Magical Cunning\"] = {1, 0} }, invocations = 6, cantrips = 3, prepared = 9, slots = {0, 0, 0, 2} }, { features = {\"Contact Patron\"}, res = { [\"Magical Cunning\"] = {1, 0}, [\"Contact Patron\"] = {1, 0} }, invocations = 7, cantrips = 3, prepared = 10, slots = {0, 0, 0, 0, 2} }, { features = {\"Subclass feature\"}, res = { [\"Magical Cunning\"] = {1, 0}, [\"Contact Patron\"] = {1, 0} }, invocations = 7, cantrips = 4, prepared = 10, slots = {0, 0, 0, 0, 2} }, { features = {\"Mystic Arcanum (level 6 spell)\"}, res = { [\"Magical Cunning\"] = {1, 0}, [\"Contact Patron\"] = {1, 0}, [\"Mystic Arcanum (6)\"] = {1, 0} }, arcanum = {6}, invocations = 7, cantrips = 4, prepared = 11, slots = {0, 0, 0, 0, 3} }, { features = {\"Ability Score Improvement\"}, res = { [\"Magical Cunning\"] = {1, 0}, [\"Contact Patron\"] = {1, 0}, [\"Mystic Arcanum (6)\"] = {1, 0} }, arcanum = {6}, invocations = 8, cantrips = 4, prepared = 11, slots = {0, 0, 0, 0, 3} }, { features = {\"Mystic Arcanum (level 7 spell)\"}, res = { [\"Magical Cunning\"] = {1, 0}, [\"Contact Patron\"] = {1, 0}, [\"Mystic Arcanum (6)\"] = {1, 0}, [\"Mystic Arcanum (7)\"] = {1, 0} }, arcanum = {6, 7}, invocations = 8, cantrips = 4, prepared = 12, slots = {0, 0, 0, 0, 3} }, { features = {\"Subclass feature\"}, res = { [\"Magical Cunning\"] = {1, 0}, [\"Contact Patron\"] = {1, 0}, [\"Mystic Arcanum (6)\"] = {1, 0}, [\"Mystic Arcanum (7)\"] = {1, 0} }, arcanum = {6, 7}, invocations = 8, cantrips = 4, prepared = 12, slots = {0, 0, 0, 0, 3} }, { features = {\"Mystic Arcanum (level 8 spell)\"}, res = { [\"Magical Cunning\"] = {1, 0}, [\"Contact Patron\"] = {1, 0}, [\"Mystic Arcanum (6)\"] = {1, 0}, [\"Mystic Arcanum (7)\"] = {1, 0}, [\"Mystic Arcanum (8)\"] = {1, 0} }, arcanum = {6, 7, 8}, invocations = 9, cantrips = 4, prepared = 13, slots = {0, 0, 0, 0, 3} }, { features = {\"Ability Score Improvement\"}, res = { [\"Magical Cunning\"] = {1, 0}, [\"Contact Patron\"] = {1, 0}, [\"Mystic Arcanum (6)\"] = {1, 0}, [\"Mystic Arcanum (7)\"] = {1, 0}, [\"Mystic Arcanum (8)\"] = {1, 0} }, arcanum = {6, 7, 8}, invocations = 9, cantrips = 4, prepared = 13, slots = {0, 0, 0, 0, 3} }, { features = {\"Mystic Arcanum (level 9 spell)\"}, res = { [\"Magical Cunning\"] = {1, 0}, [\"Contact Patron\"] = {1, 0}, [\"Mystic Arcanum (6)\"] = {1, 0}, [\"Mystic Arcanum (7)\"] = {1, 0}, [\"Mystic Arcanum (8)\"] = {1, 0}, [\"Mystic Arcanum (9)\"] = {1, 0} }, arcanum = {6, 7, 8, 9}, invocations = 9, cantrips = 4, prepared = 14, slots = {0, 0, 0, 0, 4} }, { features = {}, res = { [\"Magical Cunning\"] = {1, 0}, [\"Contact Patron\"] = {1, 0}, [\"Mystic Arcanum (6)\"] = {1, 0}, [\"Mystic Arcanum (7)\"] = {1, 0}, [\"Mystic Arcanum (8)\"] = {1, 0}, [\"Mystic Arcanum (9)\"] = {1, 0} }, arcanum = {6, 7, 8, 9}, invocations = 10, cantrips = 4, prepared = 14, slots = {0, 0, 0, 0, 4} }, { features = {\"Epic Boon\"}, res = { [\"Magical Cunning\"] = {1, 0}, [\"Contact Patron\"] = {1, 0}, [\"Mystic Arcanum (6)\"] = {1, 0}, [\"Mystic Arcanum (7)\"] = {1, 0}, [\"Mystic Arcanum (8)\"] = {1, 0}, [\"Mystic Arcanum (9)\"] = {1, 0} }, arcanum = {6, 7, 8, 9}, invocations = 10, cantrips = 4, prepared = 15, slots = {0, 0, 0, 0, 4} }, { features = {\"Eldritch Master\"}, res = { [\"Magical Cunning\"] = {1, 0}, [\"Contact Patron\"] = {1, 0}, [\"Mystic Arcanum (6)\"] = {1, 0}, [\"Mystic Arcanum (7)\"] = {1, 0}, [\"Mystic Arcanum (8)\"] = {1, 0}, [\"Mystic Arcanum (9)\"] = {1, 0} }, arcanum = {6, 7, 8, 9}, invocations = 10, cantrips = 4, prepared = 15, slots = {0, 0, 0, 0, 4} }}, subclass = { level = 3, name = \"Fiend Patron\" }, spell_ability = \"Charisma\", swap = \"level_one\", always = { [\"9\"] = {\"Contact Other Plane\"} }, pact = true, mc_gains = { light = true }, caster = \"pact\", subclasses = { [\"Fiend Patron\"] = { levels = { [\"3\"] = {\"Dark One's Blessing\", \"Fiend Spells\"}, [\"6\"] = {\"Dark One's Own Luck\"}, [\"10\"] = {\"Fiendish Resilience\"}, [\"14\"] = {\"Hurl Through Hell\"} }, always = { [\"3\"] = {\"Burning Hands\", \"Command\", \"Scorching Ray\", \"Suggestion\"}, [\"5\"] = {\"Fireball\", \"Stinking Cloud\"}, [\"7\"] = {\"Fire Shield\", \"Wall of Fire\"}, [\"9\"] = {\"Geas\", \"Insect Plague\"} } } } } }\r\n\r\nlocal BACKGROUNDS = { Acolyte = { abilities = {\"Intelligence\", \"Wisdom\", \"Charisma\"}, skills = {\"Insight\", \"Religion\"}, feat = \"Magic Initiate (Cleric)\", equipment = { A = { items = {  }, gp = 8, other = {\"Calligrapher's Supplies\", \"Book (prayers)\", \"Holy Symbol\", \"Parchment (10 sheets)\", \"Robe\"} }, B = { items = {  }, gp = 50, other = {} } }, tool = \"Calligrapher's Supplies\" }, Criminal = { abilities = {\"Dexterity\", \"Constitution\", \"Intelligence\"}, skills = {\"Sleight of Hand\", \"Stealth\"}, feat = \"Alert\", equipment = { A = { items = { Dagger = 2 }, gp = 16, other = {\"Thieves' Tools\", \"Crowbar\", \"2 Pouches\", \"Traveler's Clothes\"} }, B = { items = {  }, gp = 50, other = {} } }, tool = \"Thieves' Tools\" }, Sage = { abilities = {\"Constitution\", \"Intelligence\", \"Wisdom\"}, skills = {\"Arcana\", \"History\"}, feat = \"Magic Initiate (Wizard)\", equipment = { A = { items = { Quarterstaff = 1 }, gp = 8, other = {\"Calligrapher's Supplies\", \"Book (history)\", \"Parchment (8 sheets)\", \"Robe\"} }, B = { items = {  }, gp = 50, other = {} } }, tool = \"Calligrapher's Supplies\" }, Soldier = { abilities = {\"Strength\", \"Dexterity\", \"Constitution\"}, skills = {\"Athletics\", \"Intimidation\"}, feat = \"Savage Attacker\", equipment = { A = { items = { Spear = 1, Shortbow = 1, Arrows = 20, [\"Healer's Kit\"] = 1 }, gp = 14, other = {\"Gaming Set\", \"Quiver\", \"Traveler's Clothes\"} }, B = { items = {  }, gp = 50, other = {} } }, tool = \"Gaming Set\" } }\r\n\r\nlocal SPECIES = { Dragonborn = { speed = 30, darkvision = 60, hp_per_level = 0, size = \"Medium\" }, Dwarf = { speed = 30, darkvision = 120, hp_per_level = 1, size = \"Medium\" }, Elf = { speed = 30, darkvision = 60, hp_per_level = 0, size = \"Medium\" }, Gnome = { speed = 30, darkvision = 60, hp_per_level = 0, size = \"Small\" }, Goliath = { speed = 35, darkvision = 0, hp_per_level = 0, size = \"Medium\" }, Halfling = { speed = 30, darkvision = 0, hp_per_level = 0, size = \"Small\" }, Human = { speed = 30, darkvision = 0, hp_per_level = 0, size = \"Medium or Small\" }, Orc = { speed = 30, darkvision = 120, hp_per_level = 0, size = \"Medium\" }, Tiefling = { speed = 30, darkvision = 60, hp_per_level = 0, size = \"Medium or Small\" } }\r\n\r\nK.FX = { [\"Mindless Rage\"] = { tip = \"격노하는 동안 매혹·공포에 걸리지 않습니다. 걸린 채로 격노하면 풀립니다.\", text = \"Mindless Rage: while raging, immune to Charmed and Frightened (Lua answers such a COND with immune); entering a Rage ends both\", fx = {{ t = \"cond_immune\", conds = {\"Charmed\", \"Frightened\"}, when = \"raging\" }} }, [\"Feral Instinct\"] = { tip = \"우선권 굴림에 이점 (Lua가 굴립니다).\", text = \"Feral Instinct: Advantage on Initiative (Lua rolls it)\", fx = {{ t = \"init_adv\" }} }, [\"Instinctive Pounce\"] = { tip = \"격노하는 추가 행동에 이동 속도 절반만큼 움직일 수 있습니다.\", text = \"Instinctive Pounce: entering a Rage also moves up to half Speed\", fx = {{ t = \"note\" }} }, [\"Brutal Strike\"] = { tip = \"무모한 공격을 할 때 근력 공격 하나의 이점을 포기하면, 맞혔을 때 1d10 추가 피해와 함께 강력한 일격(15피트 밀기)이나 오금 베기(속도 -15피트) 중 하나.\", text = \"Brutal Strike: with Reckless Attack, one Strength attack can give up its Advantage (write that d20 plain, one die); if it hits, add 1d10 to that ATTACK's formula and pick Forceful Blow (pushed 15 ft) or Hamstring Blow (Speed -15 ft)\", fx = {{ t = \"weapon_die\", dice = \"1d10\", str = true, plain = true, unarmed = true }} }, Retaliation = { tip = \"5피트 안의 생물에게 피해를 받으면 반응행동으로 그 생물을 근접 공격합니다.\", text = \"Retaliation: when a creature within 5 ft damages {WHO}, a Reaction melee attack against it (an ordinary ATTACK)\", fx = {{ t = \"note\" }} }, [\"Magical Discoveries\"] = { tip = \"클레릭·드루이드·위저드 목록에서 주문 둘(소마법이나 슬롯이 있는 레벨)을 더 배워 늘 준비합니다. 주문을 고를 때 같이 정합니다.\", text = \"Magical Discoveries: the SPELLS tag may hold two more spells (cantrips, or of a level with slots) from the Cleric, Druid or Wizard lists; they do not count against the cantrip or prepared numbers\", fx = {{ t = \"spell_extra\", count = 2, lists = {\"Cleric\", \"Druid\", \"Wizard\"} }} }, Countercharm = { tip = \"나나 30피트 안의 생물이 매혹·공포 내성에 실패하면, 반응행동으로 그 굴림을 이점을 받아 다시 굴리게 합니다.\", text = \"Countercharm: when {WHO} or a creature within 30 ft fails a save against Charmed or Frightened, a Reaction has it rolled again with Advantage: a new CHECK with \\\"adv A,B\\\"\", fx = {{ t = \"note\" }} }, [\"Magical Secrets\"] = { tip = \"준비하는 주문을 바드·클레릭·드루이드·위저드 목록에서 고를 수 있습니다.\", text = \"Magical Secrets: prepared spells in the SPELLS tag may also come from the Cleric, Druid and Wizard lists\", fx = {{ t = \"spell_lists\", lists = {\"Cleric\", \"Druid\", \"Wizard\"} }} }, [\"Blessed Healer\"] = { tip = \"슬롯을 쓴 주문으로 다른 이를 치유하면 나도 2 + 슬롯 레벨만큼 회복합니다 (Lua가 더합니다).\", text = \"Blessed Healer: when a spell cast with a slot heals someone else, {WHO} regains 2 + the slot level (Lua adds it, once per casting)\", fx = {{ t = \"self_heal_on_heal\", amount = \"2+SLOT\" }} }, [\"Blessed Strikes\"] = { tip = \"신성한 일격(무기 명중에 1d8 사령·광휘, 턴마다 한 번)이나 강화된 주문시전(클레릭 소마법 피해에 지혜 수정치) 중 하나를 고릅니다.\", text = \"\", fx = {{ t = \"choice\", key = \"blessed\", options = {\"Divine Strike\", \"Potent Spellcasting\"}, default = \"Potent Spellcasting\" }} }, [\"Divine Strike\"] = { tip = \"턴마다 한 번, 무기로 맞히면 1d8 사령이나 광휘 피해를 더합니다.\", text = \"Divine Strike: once on each of {WHO}'s turns, a weapon hit adds 1d8 Necrotic or Radiant (in that ATTACK's formula)\", fx = {{ t = \"weapon_die\", dice = \"1d8\", types = \"Necrotic or Radiant\" }} }, [\"Potent Spellcasting\"] = { tip = \"클래스 소마법의 피해에 지혜 수정치를 더합니다 (공식에 들어 있습니다).\", text = \"Potent Spellcasting: the class's cantrips add {WIS} to their damage (in the formulas)\", fx = {{ t = \"cantrip_mod\", ability = \"Wisdom\" }} }, [\"Divine Intervention\"] = { tip = \"긴 휴식마다 한 번, 5레벨 이하 클레릭 주문 아무거나(준비 안 한 것도) 슬롯과 재료 없이 시전합니다.\", text = \"Divine Intervention: once per Long Rest, any Cleric spell of level 5 or lower, prepared or not, without a slot or Material components: [CAST|Spell|free]\", fx = {{ t = \"free_cast\", use = \"Divine Intervention\", list = \"Cleric\", max_level = 5 }} }, [\"Natural Recovery\"] = { tip = \"짧은 휴식 때 Lua가 슬롯을 되찾아 줍니다 (레벨 합 = 드루이드 레벨 절반, 올림, 긴 휴식마다 1회). 준비한 대지 주문 하나는 긴 휴식마다 한 번 슬롯 없이.\", text = \"Natural Recovery: in a Short Rest Lua recovers slots by itself (levels adding up to half the Druid level, once per Long Rest; write no USE); once per Long Rest one Circle of the Land spell without a slot: [CAST|Spell|free]\", fx = {{ t = \"resource\", name = \"Natural Recovery\", max = 1, short = 0 }, { t = \"slot_recovery\", use = \"Natural Recovery\" }, { t = \"resource\", name = \"Circle Spell (free)\", max = 1, short = 0 }, { t = \"free_cast\", use = \"Circle Spell (free)\", land = true }} }, [\"Elemental Fury\"] = { tip = \"강화된 주문시전(드루이드 소마법 피해에 지혜 수정치)이나 원시의 일격(무기·야생 변신 명중에 1d8 원소 피해, 턴마다 한 번) 중 하나를 고릅니다.\", text = \"\", fx = {{ t = \"choice\", key = \"fury\", options = {\"Potent Spellcasting\", \"Primal Strike\"}, default = \"Potent Spellcasting\" }} }, [\"Primal Strike\"] = { tip = \"턴마다 한 번, 무기나 야생 변신 공격으로 맞히면 1d8 냉기·화염·번개·천둥 피해를 더합니다.\", text = \"Primal Strike: once on each of {WHO}'s turns, a weapon or Wild Shape hit adds 1d8 Cold, Fire, Lightning or Thunder (in that ATTACK's formula)\", fx = {{ t = \"weapon_die\", dice = \"1d8\", types = \"Cold, Fire, Lightning or Thunder\", beast = true }} }, [\"Nature's Ward\"] = { tip = \"중독에 걸리지 않고, 고른 땅에 따라 화염(건조 지대)·냉기(극지)·번개(온대)·독성(열대) 피해에 저항합니다.\", text = \"Nature's Ward: immune to Poisoned (Lua answers such a COND with immune); Resistance to {RES} (Lua halves it)\", fx = {{ t = \"cond_immune\", conds = {\"Poisoned\"} }, { t = \"resist\", by_pick = \"land\", map = { Arid = \"Fire\", Polar = \"Cold\", Temperate = \"Lightning\", Tropical = \"Poison\" } }} }, [\"Additional Fighting Style\"] = { tip = \"전투 유파를 하나 더 고릅니다 (캐릭터 탭).\", text = \"\", fx = {{ t = \"style_pick\", key = \"xstyle\" }} }, Indomitable = { tip = \"내성 굴림에 실패하면 파이터 레벨을 더해 다시 굴리고 새 값을 씁니다. 긴 휴식마다 1회(13레벨 2회, 17레벨 3회).\", text = \"Indomitable: a failed save is rolled again with +{LEVEL} (one use each, back on a Long Rest): write its d20 as \\\"indom A,B\\\" (A the failed d20, B the next d20 from the pool); the bonus field stays the usual one, Lua adds {LEVEL} and spends the use\", fx = {{ t = \"reroll_save\", use = \"Indomitable\", mode = \"indom\", bonus = \"LEVEL\" }} }, [\"Tactical Master\"] = { tip = \"통달이 있는 무기로 칠 때 그 통달 대신 밀치기·약화·둔화를 쓸 수 있습니다.\", text = \"Tactical Master: a weapon's mastery can be swapped for Push, Sap or Slow on an attack (narrate it)\", fx = {{ t = \"note\" }} }, [\"Heroic Warrior\"] = { tip = \"싸우는 동안 내 턴을 시작할 때 영웅적 영감이 없으면 Lua가 줍니다 (d20 하나 다시 굴리기).\", text = \"Heroic Warrior: in a fight Lua gives {WHO} Heroic Inspiration at the start of each turn without it (\\\"insp A,B\\\" rerolls a d20)\", fx = {{ t = \"insp_each_turn\" }} }, [\"Empowered Strikes\"] = { tip = \"맨손 공격이 역장 피해를 줍니다 (Lua는 역장으로 계산합니다).\", text = \"Empowered Strikes: Unarmed Strikes deal Force damage (Lua counts it so)\", fx = {{ t = \"unarmed_type\", type = \"Force\" }} }, [\"Wholeness of Body\"] = { tip = \"추가 행동으로 무술 주사위 + 지혜 수정치만큼 회복합니다. 지혜 수정치만큼(최소 1번) 쓰고 긴 휴식에 다시 찹니다.\", text = \"Wholeness of Body: a Bonus Action heals {MA}{WIS}: [HEAL|{WHO}|Wholeness of Body|{MA}{WIS}|dice|amount]; {WIS1} uses per Long Rest\", fx = {{ t = \"resource\", name = \"Wholeness of Body\", max = \"WIS\", short = 0 }, { t = \"heal_source\", name = \"Wholeness of Body\", formula = \"MA+WIS\", use = \"Wholeness of Body\" }} }, Evasion = { tip = \"피해를 반으로 줄이는 민첩 내성에 성공하면 피해 없음, 실패해도 절반만 받습니다.\", text = \"Evasion: a Dexterity save that halves damage takes no damage on a success and half on a failure (write the damage so; Lua checks it)\", fx = {{ t = \"evasion\" }} }, [\"Acrobatic Movement\"] = { tip = \"갑옷·방패 없이 자기 턴에 벽을 타거나 물 위를 달릴 수 있습니다.\", text = \"Acrobatic Movement: without armor or a Shield, runs up walls and across liquids on its turn\", fx = {{ t = \"note\" }} }, [\"Heightened Focus\"] = { tip = \"연타는 맨손 공격 세 번, 인내의 방어는 기 1점으로 무술 주사위 두 개를 굴린 만큼 임시 생명력, 바람 걸음은 한 명을 데려갑니다.\", text = \"Heightened Focus: Flurry of Blows is three Unarmed Strikes; Patient Defense is [USE|Patient Defense] (1 Focus Point; Lua rolls two Martial Arts dice of Temporary HP); Step of the Wind takes one willing creature along\", fx = {{ t = \"temp_hp_use\", use = \"Patient Defense\", formula = \"MA+MA\", costs = { [\"Focus Points\"] = 1 } }} }, [\"Self-Restoration\"] = { tip = \"내 턴이 끝날 때 매혹·공포·중독 중 하나를 스스로 풉니다.\", text = \"Self-Restoration: at the end of each of {WHO}'s turns, {WHO} ends one Charmed, Frightened or Poisoned on {WHO} ([COND|-Condition])\", fx = {{ t = \"note\" }} }, [\"Aura of Protection\"] = { tip = \"나와 동료의 모든 내성 굴림에 매력 수정치(최소 +1)를 더합니다. 팔라딘이 행동불능이거나 쓰러지면 꺼집니다.\", text = \"Aura of Protection: Player and the companions add +{CHA1} to every saving throw while {WHO} is not Incapacitated (already in the save bonuses Lua lists)\", fx = {{ t = \"save_bonus\", amount = \"Charisma\", min = 1, scope = \"party\", off_if = \"Incapacitated\" }} }, [\"Aura of Devotion\"] = { tip = \"팔라딘이 버티는 동안 나와 동료는 매혹에 걸리지 않습니다.\", text = \"Aura of Devotion: Player and the companions are immune to Charmed while {WHO} is not Incapacitated (Lua answers such a COND with immune)\", fx = {{ t = \"cond_immune\", conds = {\"Charmed\"}, scope = \"party\", off_if = \"Incapacitated\" }} }, [\"Abjure Foes\"] = { tip = \"신성 변환 1회: 60피트 안의 생물을 매력 수정치만큼(최소 하나) 고르면, 지혜 내성에 실패한 생물은 1분 동안 공포 (매 턴 이동·행동·추가 행동 중 하나만).\", text = \"Abjure Foes: [USE|Channel Divinity]; up to {CHA1} creatures within 60 ft, one [HAZARD|Name|Abjure Foes|Wisdom|d20|+bonus|{DC}|success/failure|-|-|0] each (a failure: Frightened for 1 minute or until it takes damage, Lua keeps it; each turn only one of move, action or Bonus Action)\", fx = {{ t = \"foe_save\", name = \"Abjure Foes\", save = \"Wisdom\", dc = \"SPELL\", lrfx = {\"Frightened\"}, cond = {\"Frightened\"}, mins = 1, wake = true, magic = true }} }, [\"Aura of Courage\"] = { tip = \"팔라딘이 버티는 동안 나와 동료는 공포에 걸리지 않습니다.\", text = \"Aura of Courage: Player and the companions are immune to Frightened while {WHO} is not Incapacitated (Lua answers such a COND with immune)\", fx = {{ t = \"cond_immune\", conds = {\"Frightened\"}, scope = \"party\", off_if = \"Incapacitated\" }} }, Roving = { tip = \"중갑을 입지 않으면 이동 속도 +10피트, 오르기·헤엄 속도도 같습니다.\", text = \"Roving: Speed +10 ft without Heavy armor (in the Speed), Climb and Swim Speed the same\", fx = {{ t = \"note\" }} }, [\"Defensive Tactics\"] = { tip = \"무리 탈출(나를 향한 기회공격에 불리점)이나 다중공격 방어(나를 맞힌 생물의 이번 턴 다른 공격에 불리점) 중 하나.\", text = \"Defensive Tactics: Escape the Horde (Opportunity Attacks against {WHO} have Disadvantage) or Multiattack Defense (after a creature hits {WHO}, its other attacks this turn have Disadvantage); narrate it\", fx = {{ t = \"note\" }} }, Tireless = { tip = \"마법 행동으로 1d8 + 지혜 수정치만큼 임시 생명력 (지혜 수정치만큼 쓰고 긴 휴식에 다시 찹니다). 짧은 휴식마다 탈진 1단계가 풀립니다.\", text = \"Tireless: a Magic action [USE|Tireless] gives Temporary HP 1d8{WIS} (Lua rolls; {WIS1} uses per Long Rest); a Short Rest also removes one Exhaustion level (Lua)\", fx = {{ t = \"temp_hp_use\", use = \"Tireless\", formula = \"1d8+WIS\" }, { t = \"exhaustion_short_rest\", amount = 1 }} }, [\"Reliable Talent\"] = { tip = \"숙련된 기술 판정에서 d20이 9 이하로 나오면 10으로 칩니다.\", text = \"Reliable Talent: on a check with a skill {WHO} is proficient in, a d20 of 9 or lower counts as 10: write the d20 as rolled and the result with 10 (Lua counts 10)\", fx = {{ t = \"d20_floor\", value = 10, on = \"proficient_check\" }} }, [\"Supreme Sneak\"] = { tip = \"교활한 일격 선택지 '은신 공격'(1d6): 숨기로 얻은 투명 상태에서 공격해도, 3/4 엄폐나 완전 엄폐 뒤에서 턴을 끝내면 투명이 풀리지 않습니다.\", text = \"Supreme Sneak: Cunning Strike option Stealth Attack (cost 1d6): the Invisible condition of Hide stays if the turn ends behind Three-Quarters or Total Cover\", fx = {{ t = \"note\" }} }, [\"Elemental Affinity\"] = { tip = \"고른 피해 종류(산성·냉기·화염·번개·독성)에 저항하고, 그 피해를 주는 주문의 피해 굴림 하나에 매력 수정치를 더합니다.\", text = \"Elemental Affinity: Resistance to {RES} (Lua halves it); a spell dealing {RES} damage adds {CHA} to one damage roll (in the formulas; a spell of rays or darts: one of them, once a casting, Lua lists it)\", fx = {{ t = \"resist\", pick = \"affinity\", opts = {\"Acid\", \"Cold\", \"Fire\", \"Lightning\", \"Poison\"}, default = \"Fire\" }, { t = \"spell_damage_mod\", ability = \"Charisma\", type_pick = \"affinity\" }} }, [\"Sorcery Incarnate\"] = { tip = \"타고난 술법을 다 쓰면 술법 점수 2로 켤 수 있고, 켜진 동안 주문 하나에 마법변형을 둘까지 씁니다.\", text = \"Sorcery Incarnate: with no Innate Sorcery uses left, 2 Sorcery Points start it; while it is on, up to two Metamagic options per spell\", fx = {{ t = \"note\" }} }, [\"Dark One's Own Luck\"] = { tip = \"능력 판정이나 내성 굴림의 결과를 보고, 효과가 나기 전에 1d10을 더합니다(한 굴림에 한 번). 매력 수정치만큼(최소 1번) 쓰고 긴 휴식에 다시 찹니다.\", text = \"Dark One's Own Luck: {CHA1} times per Long Rest add 1d10 to an ability check or saving throw after seeing it: write the d20 as \\\"dol A,B\\\" (A the d20, B the next d10 from the pool); Lua adds B and spends a use\", fx = {{ t = \"resource\", name = \"Dark One's Own Luck\", max = \"CHA\", short = 0 }, { t = \"die_bonus\", use = \"Dark One's Own Luck\", die = 10, mode = \"dol\", on = {\"check\", \"save\"} }} }, [\"Contact Patron\"] = { tip = \"이계 접촉을 늘 준비해 두고, 긴 휴식마다 한 번 슬롯 없이 시전하면 내성은 자동 성공입니다.\", text = \"Contact Patron: Contact Other Plane is always prepared; once per Long Rest [CAST|Contact Other Plane|free] casts it without a slot and its save succeeds\", fx = {{ t = \"free_cast\", use = \"Contact Patron\", spells = {\"Contact Other Plane\"}, auto_save = true }} }, [\"Fiendish Resilience\"] = { tip = \"역장이 아닌 피해 종류 하나에 저항합니다 (캐릭터 탭에서 고릅니다, 휴식을 마칠 때마다 바꿀 수 있습니다).\", text = \"Fiendish Resilience: Resistance to {RES}, the type picked on the character tab, where the user changes it after a rest (Lua halves it)\", fx = {{ t = \"resist\", pick = \"resilience\", opts = {\"Acid\", \"Bludgeoning\", \"Cold\", \"Fire\", \"Lightning\", \"Necrotic\", \"Piercing\", \"Poison\", \"Psychic\", \"Radiant\", \"Slashing\", \"Thunder\"}, default = \"Slashing\" }} }, [\"Sculpt Spells\"] = { tip = \"방출학파 주문을 쓸 때 1 + 주문 레벨만큼의 생물을 골라 내성 자동 성공, 절반 피해도 받지 않게 합니다.\", text = \"Sculpt Spells: an Evocation spell spares 1 + its level chosen creatures (they succeed on the save and take no damage)\", fx = {{ t = \"note\" }} }, [\"Empowered Evocation\"] = { tip = \"위저드 방출학파 주문의 피해 굴림 하나에 지능 수정치를 더합니다 (공식에 들어 있습니다).\", text = \"Empowered Evocation: a Wizard Evocation spell adds {INT} to one damage roll (in the formulas; Magic Missile: the casting's first DAMAGE; Scorching Ray: one ray, Lua lists it)\", fx = {{ t = \"spell_damage_mod\", ability = \"Intelligence\", school = \"Evocation\" }} }, [\"Relentless Rage\"] = { tip = \"격노 중에 0이 되면(즉사가 아니면) 건강 내성 난이도 10, 성공하면 생명력이 바바리안 레벨의 두 배가 됩니다. 쓸 때마다 난이도 +5, 휴식하면 10으로. Lua가 굴립니다.\", text = \"Relentless Rage: dropping to 0 HP while raging (not killed outright), Lua rolls a DC 10 Constitution save (+5 for each use since the last rest); on a success {WHO} is at twice the Barbarian level in HP instead\", fx = {{ t = \"relentless_rage\" }} }, [\"Improved Brutal Strike\"] = { tip = \"잔혹한 일격에 비틀거리는 일격(다음 내성 불리, 기회 공격 못 함)과 가르는 일격(다음 아군 공격 +5)이 더해집니다. 17레벨부터 추가 피해가 2d10이고 효과를 서로 다른 것 둘까지 고릅니다.\", text = \"Improved Brutal Strike: Brutal Strike may also be a Staggering Blow (Disadvantage on its next save, no Opportunity Attacks) or a Sundering Blow (the next attack by someone else against it gets +5); from Barbarian level 17 its damage is 2d10 (in the formula) and one Brutal Strike may use two different effects\", fx = {{ t = \"weapon_die\", dice = \"1d10\", str = true, plain = true, unarmed = true, from = 17 }} }, [\"Intimidating Presence\"] = { tip = \"추가 행동으로 30피트 안의 고른 생물이 지혜 내성(난이도 8 + 근력 + 숙련), 실패하면 1분 공포. 긴 휴식마다 한 번(격노 1회로 다시).\", text = \"Intimidating Presence: a Bonus Action, once per Long Rest (or spend a Rage use to restore it); each creature of {WHO}'s choice within 30 ft makes a Wisdom save, DC {DC}: one [HAZARD|Name|Intimidating Presence|Wisdom|d20|+bonus|{DC}|success/failure|-|-|0] each (a failure: Frightened for 1 minute, Lua keeps it; its save at the end of each of its turns is the same HAZARD, a success ends it)\", fx = {{ t = \"resource\", name = \"Intimidating Presence\", max = 1, short = 0 }, { t = \"foe_save\", name = \"Intimidating Presence\", save = \"Wisdom\", dc = \"8+STR+PB\", use = \"Intimidating Presence\", area = true, lrfx = {\"Frightened\"}, cond = {\"Frightened\"}, mins = 1, end_save = true }} }, [\"Persistent Rage\"] = { tip = \"우선권을 굴릴 때 격노 횟수를 모두 되찾습니다(긴 휴식마다 한 번, Lua가 합니다). 격노는 10분 동안 그대로 이어집니다.\", text = \"Persistent Rage: when a fight starts Lua gives back all Rage uses (once per Long Rest); a Rage lasts 10 minutes without being kept up\", fx = {{ t = \"resource\", name = \"Persistent Rage\", max = 1, short = 0 }, { t = \"init_refill\", res = \"Rage\", use = \"Persistent Rage\" }} }, [\"Peerless Skill\"] = { tip = \"판정이나 명중 굴림에 실패하면 바드의 고양감 1회를 써서 그 주사위를 d20에 더합니다. 그래도 실패하면 그 1회는 쓰지 않은 것이 됩니다.\", text = \"Peerless Skill: after a failed ability check or attack roll, spend a Bardic Inspiration and add its die; still a failure, the use is not spent\", fx = {{ t = \"note\" }} }, [\"Improved Blessed Strikes\"] = { tip = \"신성한 일격은 2d8이 됩니다. 강화된 주문시전이면 클레릭 소마법으로 피해를 준 뒤, 60피트 안의 한 명(나 포함)에게 지혜 수정치 두 배만큼 임시 생명력을 줍니다(시전마다 한 번, Lua가 더합니다).\", text = \"Improved Blessed Strikes: Divine Strike is 2d8 (in the formulas); with Potent Spellcasting, once per casting, after a Cleric cantrip's SAVE dealt damage, someone within 60 ft ({WHO} too) gains Temporary HP equal to twice the Wisdom modifier: [HEAL|target|Potent Spellcasting|{WISx2}|-|{WISx2}] (Lua adds it)\", fx = {{ t = \"weapon_die\", dice = \"1d8\", types = \"Necrotic or Radiant\", if_pick = {\"blessed\", \"Divine Strike\"} }} }, [\"Nature's Sanctuary\"] = { tip = \"마법 행동으로 야생 변신 1회를 써서 120피트 안에 15피트 숲(1분): 우리 편은 절반 엄폐, 동료는 자연의 보호 저항을 함께 받습니다.\", text = \"Nature's Sanctuary: a Magic action and a Wild Shape use, [USE|Nature's Sanctuary] (Lua spends the use): a 15-ft cube of spectral trees for 1 minute; the party there has Half Cover (COVER tags) and the companions share the Nature's Ward Resistance\", fx = {{ t = \"use_pool\", use = \"Nature's Sanctuary\", pool = \"Wild Shape\", n = 1 }} }, [\"Improved Elemental Fury\"] = { tip = \"원시의 일격은 2d8, 강화된 주문시전은 사거리 10피트 이상인 드루이드 소마법의 사거리가 300피트 늡니다.\", text = \"Improved Elemental Fury: Primal Strike is 2d8 (in the formulas); with Potent Spellcasting a Druid cantrip's range of 10 ft or more is 300 ft longer\", fx = {{ t = \"weapon_die\", dice = \"1d8\", types = \"Cold, Fire, Lightning or Thunder\", beast = true, if_pick = {\"fury\", \"Primal Strike\"} }} }, [\"Studied Attacks\"] = { tip = \"공격이 빗나가면 다음 내 턴이 끝나기 전 그 생물을 향한 다음 공격에 이점.\", text = \"Studied Attacks: after a miss, the next attack roll against that creature before the end of {WHO}'s next turn has Advantage\", fx = {{ t = \"note\" }} }, [\"Superior Critical\"] = { tip = \"무기와 맨손 공격이 d20 18~20에서 치명타 (Lua가 판정).\", text = \"Superior Critical: weapon attacks and Unarmed Strikes are Critical Hits on a d20 of 18-20 (Lua checks it)\", fx = {{ t = \"crit_range\", min = 18 }} }, [\"Fleet Step\"] = { tip = \"바람 걸음이 아닌 추가 행동을 하면, 그 직후 바람 걸음도 쓸 수 있습니다.\", text = \"Fleet Step: after a Bonus Action other than Step of the Wind, Step of the Wind right after it too\", fx = {{ t = \"note\" }} }, [\"Deflect Energy\"] = { tip = \"공격 쳐내기가 모든 피해 종류에 통합니다.\", text = \"Deflect Energy: Deflect Attacks works against any damage type\", fx = {{ t = \"note\" }} }, [\"Disciplined Survivor\"] = { tip = \"모든 내성 굴림에 숙련입니다(Lua가 더합니다). 내성 굴림에 실패하면 기 1점으로 다시 굴리고 새 값을 씁니다.\", text = \"Disciplined Survivor: proficient in every saving throw (in the save numbers); after a failed save, 1 Focus Point rerolls it: write the d20 as \\\"surv A,B\\\" (B the next d20, which counts; Lua spends the point)\", fx = {{ t = \"save_prof\", abilities = {\"Strength\", \"Dexterity\", \"Constitution\", \"Intelligence\", \"Wisdom\", \"Charisma\"} }, { t = \"reroll_save\", use = \"Focus Points\", mode = \"surv\" }} }, [\"Perfect Focus\"] = { tip = \"싸움이 시작될 때 기가 3 이하면 4까지 채워집니다 (Lua가 합니다).\", text = \"Perfect Focus: when a fight starts, Lua brings Focus Points up to 4 if they are 3 or fewer\", fx = {{ t = \"init_refill\", res = \"Focus Points\", upto = 4 }} }, [\"Radiant Strikes\"] = { tip = \"근접 무기나 맨손 공격으로 맞히면 1d8 광휘 피해를 더합니다 (공식에 들어 있습니다).\", text = \"Radiant Strikes: every melee weapon or Unarmed Strike hit adds 1d8 Radiant (in that ATTACK's formula)\", fx = {{ t = \"weapon_die\", dice = \"1d8\", types = \"Radiant\", melee = true, unarmed = true, always = true }} }, [\"Restoring Touch\"] = { tip = \"치유의 손길을 쓸 때 5점마다 장님·매혹·귀머거리·공포·마비·충격 가운데 하나를 풉니다(그 점수는 회복에 쓰이지 않습니다).\", text = \"Restoring Touch: Lay On Hands may also end Blinded, Charmed, Deafened, Frightened, Paralyzed or Stunned, 5 points of the pool each (COND -Name); those points heal nothing\", fx = {{ t = \"note\" }} }, [\"Smite of Protection\"] = { tip = \"신성한 강타를 쓰면 다음 턴 시작까지 보호의 오오라 안 사람 모두 절반 엄폐.\", text = \"Smite of Protection: after a Divine Smite, everyone in the Aura of Protection has Half Cover until the start of {WHO}'s next turn (COVER tags)\", fx = {{ t = \"note\" }} }, [\"Superior Hunter's Prey\"] = { tip = \"턴마다 한 번, 사냥꾼의 표식 피해를 줄 때 그 추가 피해(1d6, 20레벨 1d10)를 30피트 안의 다른 생물에게도 줍니다.\", text = \"Superior Hunter's Prey: once per turn, Hunter's Mark's extra {HMD} Force also hits another creature within 30 ft of the first: [HAZARD|Name|Hunter's Mark|-|-|-|-|-|{HMD}|dice|damage]\", fx = {{ t = \"foe_save\", name = \"Hunter's Mark\", dmg = \"1d6\", dmg20 = \"1d10\", type = \"Force\" }} }, [\"Relentless Hunter\"] = { tip = \"피해를 받아도 사냥꾼의 표식 집중이 깨지지 않습니다 (Lua가 집중 내성을 굴리지 않습니다).\", text = \"Relentless Hunter: damage never breaks Concentration on Hunter's Mark (Lua rolls no Concentration save for it)\", fx = {{ t = \"conc_keep\", spells = {\"Hunter's Mark\"} }} }, [\"Nature's Veil\"] = { tip = \"추가 행동으로 다음 턴 끝까지 투명. 지혜 수정치만큼, 긴 휴식에 다시 찹니다.\", text = \"Nature's Veil: a Bonus Action, [USE|Nature's Veil]: Invisible until the end of {WHO}'s next turn ([COND|+Invisible|…])\", fx = {{ t = \"note\" }} }, [\"Superior Hunter's Defense\"] = { tip = \"피해를 받으면 반응행동으로 그 피해와 같은 종류 피해에 이 턴 끝까지 저항합니다.\", text = \"Superior Hunter's Defense: when {WHO} takes damage, a Reaction gives Resistance to it and that type until the end of the turn: write [USE|Superior Hunter's Defense|type] before the tag of that damage (Lua halves it)\", fx = {{ t = \"reaction_resist\", use = \"Superior Hunter's Defense\" }} }, [\"Improved Cunning Strike\"] = { tip = \"암습 피해를 줄 때 교활한 일격 효과를 둘까지 씁니다(주사위 값은 각각).\", text = \"Improved Cunning Strike: up to two Cunning Strike effects on one Sneak Attack, paying the dice for each\", fx = {{ t = \"note\" }} }, [\"Devious Strikes\"] = { tip = \"교활한 일격에 멍하게(2d6, 건강 내성), 기절시키기(6d6, 건강 내성, 1분 무의식), 시야 가리기(3d6, 민첩 내성, 장님)가 더해집니다.\", text = \"Devious Strikes: Cunning Strike may also be Daze (2d6: Constitution save or only one of move, action, Bonus Action next turn), Knock Out (6d6: Constitution save or Unconscious 1 minute, damage or its end-of-turn save ends it) or Obscure (3d6: Dexterity save or Blinded to its next turn's end): the save is [HAZARD|Name|Devious Strikes (Knock Out)|Constitution|d20|+bonus|DC|success/failure|-|-|0] (or (Daze), (Obscure)|Dexterity); Lua keeps Unconscious and Blinded\", fx = {{ t = \"note\" }} }, [\"Slippery Mind\"] = { tip = \"지혜와 매력 내성에 숙련(Lua가 더함).\", text = \"Slippery Mind: proficient in Wisdom and Charisma saving throws (in the save numbers)\", fx = {{ t = \"save_prof\", abilities = {\"Wisdom\", \"Charisma\"} }} }, [\"Use Magic Device\"] = { tip = \"마법 물건 조율 넷, 충전 쓸 때 d6이 6이면 충전 안 씀, 주문 두루마리를 지능으로 씁니다(2레벨 이상은 비전학 판정 난이도 10 + 주문 레벨).\", text = \"Use Magic Device: attune to four magic items; a charge-using property keeps its charge on a d6 roll of 6; any Spell Scroll, with Intelligence (level 2+: Intelligence (Arcana) check DC 10 + spell level, or the scroll crumbles)\", fx = {{ t = \"note\" }} }, [\"Dragon Wings\"] = { tip = \"추가 행동으로 1시간 동안 용의 날개, 비행 속도 60피트. 긴 휴식마다 한 번(술법 점수 3으로 다시).\", text = \"Dragon Wings: a Bonus Action, [USE|Dragon Wings]: Fly Speed 60 ft for 1 hour; once per Long Rest (3 Sorcery Points restore it)\", fx = {{ t = \"resource\", name = \"Dragon Wings\", max = 1, short = 0 }} }, [\"Mystic Arcanum\"] = { tip = \"고른 6·7·8·9레벨 워락 주문을 각각 긴 휴식마다 한 번, 슬롯 없이 시전합니다.\", text = \"Mystic Arcanum: one Warlock spell of each arcanum level (6 at 11, 7 at 13, 8 at 15, 9 at 17) once per Long Rest without a slot: [CAST|Spell|free]; keep to the same spell for each level\", fx = {{ t = \"free_cast\", use = \"Mystic Arcanum (6)\", list = \"Warlock\", min_level = 6, max_level = 6 }, { t = \"free_cast\", use = \"Mystic Arcanum (7)\", list = \"Warlock\", min_level = 7, max_level = 7 }, { t = \"free_cast\", use = \"Mystic Arcanum (8)\", list = \"Warlock\", min_level = 8, max_level = 8 }, { t = \"free_cast\", use = \"Mystic Arcanum (9)\", list = \"Warlock\", min_level = 9, max_level = 9 }} }, [\"Hurl Through Hell\"] = { tip = \"턴마다 한 번 공격이 맞으면 매력 내성(주문 난이도), 실패하면 8d10 정신 피해(악마는 제외)와 다음 턴 끝까지 행동불능. 긴 휴식마다 한 번(계약 슬롯으로 다시).\", text = \"Hurl Through Hell: once per Long Rest (a Pact Magic slot restores it), after an attack hits: [HAZARD|Name|Hurl Through Hell|Charisma|d20|+bonus|{DC}|success/failure|8d10|dice|damage] (spell save DC {DC}; no damage on a success, none to a Fiend; Incapacitated until the end of {WHO}'s next turn on a failure, Lua keeps it)\", fx = {{ t = \"resource\", name = \"Hurl Through Hell\", max = 1, short = 0 }, { t = \"foe_save\", name = \"Hurl Through Hell\", save = \"Charisma\", dc = \"SPELL\", dmg = \"8d10\", type = \"Psychic\", use = \"Hurl Through Hell\", lrfx = {\"Incapacitated\"}, cond = {\"Incapacitated\"}, turn = true }} }, Overchannel = { tip = \"1~5레벨 슬롯의 위저드 피해 주문을 최대 피해로. 긴 휴식마다 한 번(Lua는 두 번째부터를 막습니다).\", text = \"Overchannel: once per Long Rest, [USE|Overchannel] before the CAST of a Wizard damage spell from a level 1-5 slot: that spell's damage dice are at their maximum this reply (write the maximum on each die; Lua takes none from the pool)\", fx = {{ t = \"resource\", name = \"Overchannel\", max = 1, short = 0 }, { t = \"overchannel\", use = \"Overchannel\" }} }, [\"Indomitable Might\"] = { tip = \"근력 판정이나 근력 내성의 합계가 근력 점수보다 낮으면 점수를 합계로 씁니다 (Lua가 합니다).\", text = \"Indomitable Might: a Strength check or Strength save totals at least {WHO}'s Strength score (Lua counts it)\", fx = {{ t = \"total_floor\", ability = \"Strength\" }} }, [\"Primal Champion\"] = { tip = \"근력과 건강이 4씩 오릅니다(최대 25). 20레벨이 될 때 Lua가 올립니다.\", text = \"\", fx = {{ t = \"score_up\", abilities = {\"Strength\", \"Constitution\"}, amount = 4, max = 25 }} }, [\"Superior Inspiration\"] = { tip = \"싸움이 시작될 때 바드의 고양감이 2보다 적으면 2까지 채워집니다 (Lua가 합니다).\", text = \"Superior Inspiration: when a fight starts, Lua brings Bardic Inspiration up to 2 if it is lower\", fx = {{ t = \"init_refill\", res = \"Bardic Inspiration\", upto = 2 }} }, [\"Words of Creation\"] = { tip = \"권능어: 치유와 권능어: 죽음이 늘 준비되어 있고, 첫 대상 10피트 안의 둘째 대상에게도 걸 수 있습니다.\", text = \"Words of Creation: Power Word Heal and Power Word Kill are always prepared; either may also take a second target within 10 ft of the first (its own HEAL or DAMAGE)\", fx = {{ t = \"note\" }} }, [\"Supreme Healing\"] = { tip = \"주문이나 신성 변환으로 생명력을 회복시킬 때 주사위를 굴리지 않고 최댓값으로 칩니다 (Lua가 합니다).\", text = \"Supreme Healing: the healing dice of {WHO}'s spells and Divine Spark are not rolled but at their maximum: write each die as its maximum (Lua takes none from the pool)\", fx = {{ t = \"max_heal\" }} }, [\"Greater Divine Intervention\"] = { tip = \"신의 간섭으로 소원도 고를 수 있습니다. 그러면 긴 휴식을 2d4번 마칠 때까지 신의 간섭을 못 씁니다.\", text = \"Greater Divine Intervention: Divine Intervention may cast Wish ([CAST|Wish|free]); after that Divine Intervention is gone until 2d4 Long Rests have passed (tell the user, and write no Divine Intervention casting until then)\", fx = {{ t = \"free_cast\", use = \"Divine Intervention\", spells = {\"Wish\"} }} }, [\"Beast Spells\"] = { tip = \"야생 변신 중에도 주문을 시전합니다(값이 정해진 재료를 쓰거나 소모하는 주문은 빼고).\", text = \"Beast Spells: {WHO} can cast spells in Wild Shape, except ones with a Material component that has a cost or is consumed\", fx = {{ t = \"note\" }} }, Archdruid = { tip = \"싸움이 시작될 때 야생 변신이 0이면 1회 되찾습니다(Lua가 합니다). 긴 휴식마다 한 번 야생 변신 횟수를 주문 슬롯으로 바꿉니다(1회당 2레벨).\", text = \"Archdruid: when a fight starts with no Wild Shape uses left, Lua gives one back; once per Long Rest Wild Shape uses can become one spell slot, 2 levels each (narrate it; Lua does not add the slot); {WHO} ages 1 year for every 10\", fx = {{ t = \"init_refill\", res = \"Wild Shape\", upto = 1 }} }, Survivor = { tip = \"사망 내성에 이점, 18~20이 나오면 20처럼 칩니다. 생명력이 절반 이하(1 이상)면 내 턴마다 5 + 건강 수정치만큼 회복합니다.\", text = \"Survivor: Advantage on Death Saving Throws (write adv), and Lua counts an 18-20 as a 20; at the start of each of {WHO}'s turns while at half HP or less (and at least 1), [HEAL|{WHO}|Heroic Rally|5{CON}|-|N]\", fx = {{ t = \"death_crit\", min = 18 }} }, [\"Quivering Palm\"] = { tip = \"맨손 공격이 맞으면 기 4점으로 진동을 심습니다. 행동(또는 공격 하나를 포기)으로 터뜨리면 건강 내성, 실패 10d12 역장 피해, 성공 절반.\", text = \"Quivering Palm: on an Unarmed Strike hit, [USE|Focus Points|4] sets lethal vibrations (they last {LEVEL} days); an action, or one attack of the Attack action given up, ends them: [HAZARD|Name|Quivering Palm|Constitution|d20|+bonus|{DC}|success/failure|10d12|dice|damage] (DC {DC}; half on a success)\", fx = {{ t = \"foe_save\", name = \"Quivering Palm\", save = \"Constitution\", dc = \"8+WIS+PB\", dmg = \"10d12\", type = \"Force\", half = true }} }, [\"Superior Defense\"] = { tip = \"내 턴 시작에 기 3점을 쓰면 1분 동안 역장을 뺀 모든 피해에 저항합니다.\", text = \"Superior Defense: at the start of {WHO}'s turn, [USE|Superior Defense] spends 3 Focus Points: Resistance to every damage type but Force for 1 minute (Lua halves that damage)\", fx = {{ t = \"use_resist\", use = \"Superior Defense\", pool = \"Focus Points\", n = 3, except = \"Force\", mins = 1 }} }, [\"Body and Mind\"] = { tip = \"민첩과 지혜가 4씩 오릅니다(최대 25). 20레벨이 될 때 Lua가 올립니다.\", text = \"\", fx = {{ t = \"score_up\", abilities = {\"Dexterity\", \"Wisdom\"}, amount = 4, max = 25 }} }, [\"Aura Expansion\"] = { tip = \"보호의 오오라가 30피트로 넓어집니다.\", text = \"Aura Expansion: the Aura of Protection reaches 30 ft\", fx = {{ t = \"note\" }} }, [\"Holy Nimbus\"] = { tip = \"추가 행동으로 10분 동안 오오라에 성스러운 빛: 악마·언데드가 강요한 내성에 이점, 오오라에서 턴을 시작하는 적은 매력 + 숙련 광휘 피해. 긴 휴식마다 한 번(5레벨 슬롯으로 다시).\", text = \"Holy Nimbus: a Bonus Action, [USE|Holy Nimbus], once per Long Rest (a level 5 slot restores it): 10 minutes; Advantage on saves a Fiend or Undead forces; an enemy starting its turn in the aura takes Charisma + Proficiency Bonus Radiant: [HAZARD|Name|Holy Nimbus|-|-|-|-|-|N|-|N]\", fx = {{ t = \"resource\", name = \"Holy Nimbus\", max = 1, short = 0 }, { t = \"foe_save\", name = \"Holy Nimbus\", dmg = \"CHA+PB\", type = \"Radiant\" }} }, [\"Precise Hunter\"] = { tip = \"사냥꾼의 표식을 건 생물에게 하는 명중 굴림에 이점.\", text = \"Precise Hunter: Advantage on attack rolls against the creature marked by {WHO}'s Hunter's Mark\", fx = {{ t = \"note\" }} }, [\"Feral Senses\"] = { tip = \"30피트 맹안시야.\", text = \"Feral Senses: Blindsight 30 ft\", fx = {{ t = \"note\" }} }, [\"Foe Slayer\"] = { tip = \"사냥꾼의 표식 피해 주사위가 d6 대신 d10 (공식에 들어 있습니다).\", text = \"Foe Slayer: Hunter's Mark's die is a d10 (in the formulas)\", fx = {{ t = \"rider_die\", spell = \"Hunter's Mark\", die = 10 }} }, [\"Thief's Reflexes\"] = { tip = \"싸움의 첫 라운드에 두 번 차례를 갖습니다. 두 번째는 우선권 - 10에.\", text = \"Thief's Reflexes: two turns in the first round of a fight, the second at its Initiative minus 10\", fx = {{ t = \"note\" }} }, Elusive = { tip = \"행동불능이 아니면 어떤 명중 굴림도 나를 상대로 이점을 얻지 못합니다.\", text = \"Elusive: no attack roll against {WHO} has Advantage unless {WHO} is Incapacitated (write the d20 plain)\", fx = {{ t = \"note\" }} }, [\"Stroke of Luck\"] = { tip = \"d20 판정에 실패하면 그 굴림을 20으로 바꿉니다. 짧은 휴식이나 긴 휴식마다 한 번.\", text = \"Stroke of Luck: once per Short or Long Rest a failed D20 Test becomes a 20: write the d20 as \\\"stroke A,20\\\" (A as rolled; Lua spends the use)\", fx = {{ t = \"reroll_save\", use = \"Stroke of Luck\", mode = \"stroke\", fixed = 20, on = {\"attack\", \"check\", \"save\"} }} }, [\"Dragon Companion\"] = { tip = \"용 소환을 재료 없이, 긴 휴식마다 한 번 슬롯 없이 시전합니다. 집중 없이 1분으로 바꿀 수도 있습니다.\", text = \"Dragon Companion: Summon Dragon needs no Material component; once per Long Rest without a slot ([CAST|Summon Dragon|free]); cast it without Concentration and it lasts 1 minute\", fx = {{ t = \"free_cast\", use = \"Summon Dragon (free)\", spells = {\"Summon Dragon\"} }} }, [\"Arcane Apotheosis\"] = { tip = \"타고난 술법이 켜져 있으면 내 턴마다 마법변형 하나를 술법 점수 없이 씁니다.\", text = \"Arcane Apotheosis: while Innate Sorcery is active, one Metamagic option each turn costs no Sorcery Points\", fx = {{ t = \"note\" }} }, [\"Eldritch Master\"] = { tip = \"마법적 교활함이 계약 마법 슬롯을 전부 되찾게 합니다 (Lua가 합니다).\", text = \"\", fx = {{ t = \"cunning_all\" }} }, [\"Spell Mastery\"] = { tip = \"주문서의 1레벨 주문 하나와 2레벨 주문 하나(행동으로 시전)를 늘 준비하고, 가장 낮은 레벨로는 슬롯 없이 마음대로 시전합니다. 캐릭터 탭에서 고릅니다.\", text = \"Spell Mastery: the level 1 and level 2 spells picked on the character tab are always prepared and cast at their own level without a slot, at will: [CAST|Spell|free]; a higher level spends a slot as usual\", fx = {{ t = \"spell_pick\", key = \"mastone\", list = \"Wizard\", level = 1, count = 1, cast = \"action\", always = true }, { t = \"spell_pick\", key = \"masttwo\", list = \"Wizard\", level = 2, count = 1, cast = \"action\", always = true }, { t = \"free_cast\", use = \"Spell Mastery\", pick = \"mastone\", at_will = true }, { t = \"free_cast\", use = \"Spell Mastery\", pick = \"masttwo\", at_will = true }} }, [\"Signature Spells\"] = { tip = \"주문서의 3레벨 주문 둘을 늘 준비하고, 짧은 휴식이나 긴 휴식마다 슬롯 없이 3레벨로 한 번씩 시전합니다. 캐릭터 탭에서 고릅니다.\", text = \"Signature Spells: the two level 3 spells picked on the character tab are always prepared; each once per Short or Long Rest at level 3 without a slot: [CAST|Spell|free]\", fx = {{ t = \"spell_pick\", key = \"sig\", list = \"Wizard\", level = 3, count = 2, always = true }, { t = \"resource\", name = \"Signature Spells\", max = 2, short = \"all\" }, { t = \"free_cast\", use = \"Signature Spells\", pick = \"sig\" }} }, [\"Epic Boon\"] = { tip = \"에픽 은혜 재주 하나를 고르고, 그 은혜가 정한 능력치 하나를 1 올립니다(최대 30). 캐릭터 탭에서 고릅니다.\", text = \"\", fx = {{ t = \"choice\", key = \"boon\", options = {\"Boon of Combat Prowess\", \"Boon of Dimensional Travel\", \"Boon of Fate\", \"Boon of Irresistible Offense\", \"Boon of Spell Recall\", \"Boon of the Night Spirit\", \"Boon of Truesight\"}, default = \"Boon of Combat Prowess\", by_class = { Barbarian = \"Boon of Irresistible Offense\", Bard = \"Boon of Spell Recall\", Cleric = \"Boon of Fate\", Druid = \"Boon of Dimensional Travel\", Fighter = \"Boon of Combat Prowess\", Monk = \"Boon of Irresistible Offense\", Paladin = \"Boon of Truesight\", Ranger = \"Boon of Dimensional Travel\", Rogue = \"Boon of the Night Spirit\", Sorcerer = \"Boon of Dimensional Travel\", Warlock = \"Boon of Fate\", Wizard = \"Boon of Spell Recall\" } }} }, [\"Boon of Combat Prowess\"] = { tip = \"명중 굴림이 빗나가면 맞힌 것으로 바꿉니다. 다음 내 턴 시작까지 한 번.\", text = \"Boon of Combat Prowess: once until the start of {WHO}'s next turn, a missed attack roll hits instead: write that ATTACK's result field as hit (Lua counts it, once a round in a fight) and say Peerless Aim in the prose\", fx = {{ t = \"note\" }} }, [\"Boon of Dimensional Travel\"] = { tip = \"공격 행동이나 마법 행동 직후 보이는 빈 곳으로 30피트까지 순간이동합니다.\", text = \"Boon of Dimensional Travel: right after the Attack or a Magic action, {WHO} may teleport up to 30 ft to a space in sight\", fx = {{ t = \"note\" }} }, [\"Boon of Fate\"] = { tip = \"60피트 안 누군가의 d20 판정이 성공하거나 실패하면 2d4를 굴려 더하거나 뺍니다. 우선권을 굴리거나 휴식할 때까지 한 번.\", text = \"Boon of Fate: once until a fight starts or a Short or Long Rest ends, 2d4 added to or taken from a D20 Test of {WHO} or anyone within 60 ft, after the roll (say so in the prose; the tag's total includes it)\", fx = {{ t = \"note\" }} }, [\"Boon of Irresistible Offense\"] = { abilities = {\"Strength\", \"Dexterity\"}, tip = \"주는 타격·관통·참격 피해는 저항을 무시합니다. 명중 굴림 d20이 20이면 이 재주로 올린 능력치 점수만큼 피해를 더합니다.\", text = \"Boon of Irresistible Offense: {WHO}'s Bludgeoning, Piercing and Slashing damage ignores Resistance (Lua does not halve it); on a d20 of 20 an attack may add the ability score this boon raised to its damage (Overwhelming Strike in the attack list)\", fx = {{ t = \"ignore_resist\", types = {\"Bludgeoning\", \"Piercing\", \"Slashing\"} }, { t = \"nat20_score\" }} }, [\"Boon of Spell Recall\"] = { classes = {\"Bard\", \"Cleric\", \"Druid\", \"Paladin\", \"Ranger\", \"Sorcerer\", \"Wizard\"}, abilities = {\"Intelligence\", \"Wisdom\", \"Charisma\"}, tip = \"1~4레벨 슬롯으로 주문을 시전할 때 1d4를 굴려 슬롯 레벨과 같으면 슬롯을 쓰지 않습니다.\", text = \"Boon of Spell Recall: casting with a level 1-4 slot, roll 1d4; if it equals the slot level the slot is not spent (narrate it; restore the slot with the user's OK)\", fx = {{ t = \"note\" }} }, [\"Boon of the Night Spirit\"] = { tip = \"어둑한 빛이나 어둠 속에서 추가 행동으로 투명해지고(행동·추가 행동·반응행동을 하면 풀림), 정신·광휘 말고 모든 피해에 저항합니다.\", text = \"Boon of the Night Spirit: in Dim Light or Darkness, a Bonus Action makes {WHO} Invisible until {WHO} next takes an action, Bonus Action or Reaction, and {WHO} has Resistance to all damage but Psychic and Radiant there (halve it before writing)\", fx = {{ t = \"note\" }} }, [\"Boon of Truesight\"] = { tip = \"60피트 진시야.\", text = \"Boon of Truesight: Truesight 60 ft\", fx = {{ t = \"note\" }} } }\r\n\r\nK.SCHOOL_EN = { [\"방호학파\"] = \"Abjuration\", [\"조형학파\"] = \"Conjuration\", [\"예지학파\"] = \"Divination\", [\"환혹학파\"] = \"Enchantment\", [\"방출학파\"] = \"Evocation\", [\"환영학파\"] = \"Illusion\", [\"사령학파\"] = \"Necromancy\", [\"변환학파\"] = \"Transmutation\" }\r\n\r\nK.MAGIC_KEYS = {{\"Adamantine Armor\", \"Adamantine Armor\"}, {\"+1 Ammunition\", \"Ammunition, +1, +2, or +3\"}, {\"+2 Ammunition\", \"Ammunition, +1, +2, or +3\"}, {\"+3 Ammunition\", \"Ammunition, +1, +2, or +3\"}, {\"Ammunition of Slaying\", \"Ammunition of Slaying\"}, {\"Amulet of Health\", \"Amulet of Health\"}, {\"Amulet of Proof against Detection and Location\", \"Amulet of Proof against Detection and Location\"}, {\"Amulet of the Planes\", \"Amulet of the Planes\"}, {\"Animated Shield\", \"Animated Shield\"}, {\"Apparatus of the Crab\", \"Apparatus of the Crab\"}, {\"+1 Armor\", \"Armor, +1, +2, or +3\"}, {\"+2 Armor\", \"Armor, +1, +2, or +3\"}, {\"+3 Armor\", \"Armor, +1, +2, or +3\"}, {\"Armor of Invulnerability\", \"Armor of Invulnerability\"}, {\"Armor of Resistance\", \"Armor of Resistance\"}, {\"Armor of Vulnerability\", \"Armor of Vulnerability\"}, {\"Arrow-Catching Shield\", \"Arrow-Catching Shield\"}, {\"Bag of Beans\", \"Bag of Beans\"}, {\"Bag of Devouring\", \"Bag of Devouring\"}, {\"Bag of Holding\", \"Bag of Holding\"}, {\"Bag of Tricks\", \"Bag of Tricks\"}, {\"Bead of Force\", \"Bead of Force\"}, {\"Bead of Nourishment\", \"Bead of Nourishment\"}, {\"Belt of Dwarvenkind\", \"Belt of Dwarvenkind\"}, {\"Belt of Giant Strength\", \"Belt of Giant Strength\"}, {\"Berserker Axe\", \"Berserker Axe\"}, {\"Boots of Elvenkind\", \"Boots of Elvenkind\"}, {\"Boots of Levitation\", \"Boots of Levitation\"}, {\"Boots of Speed\", \"Boots of Speed\"}, {\"Boots of Striding and Springing\", \"Boots of Striding and Springing\"}, {\"Boots of the Winterlands\", \"Boots of the Winterlands\"}, {\"Bowl of Commanding Water Elementals\", \"Bowl of Commanding Water Elementals\"}, {\"Bracers of Archery\", \"Bracers of Archery\"}, {\"Bracers of Defense\", \"Bracers of Defense\"}, {\"Brazier of Commanding Fire Elementals\", \"Brazier of Commanding Fire Elementals\"}, {\"Brooch of Shielding\", \"Brooch of Shielding\"}, {\"Broom of Flying\", \"Broom of Flying\"}, {\"Candle of Invocation\", \"Candle of Invocation\"}, {\"Cape of the Mountebank\", \"Cape of the Mountebank\"}, {\"Carpet of Flying\", \"Carpet of Flying\"}, {\"Censer of Controlling Air Elementals\", \"Censer of Controlling Air Elementals\"}, {\"Chime of Opening\", \"Chime of Opening\"}, {\"Circlet of Blasting\", \"Circlet of Blasting\"}, {\"Cloak of Arachnida\", \"Cloak of Arachnida\"}, {\"Cloak of Displacement\", \"Cloak of Displacement\"}, {\"Cloak of Elvenkind\", \"Cloak of Elvenkind\"}, {\"Cloak of Invisibility\", \"Cloak of Invisibility\"}, {\"Cloak of Protection\", \"Cloak of Protection\"}, {\"Cloak of the Bat\", \"Cloak of the Bat\"}, {\"Cloak of the Manta Ray\", \"Cloak of the Manta Ray\"}, {\"Crystal Ball\", \"Crystal Ball\"}, {\"Crystal Ball of Mind Reading\", \"Crystal Ball of Mind Reading\"}, {\"Crystal Ball of Telepathy\", \"Crystal Ball of Telepathy\"}, {\"Crystal Ball of True Seeing\", \"Crystal Ball of True Seeing\"}, {\"Cube of Force\", \"Cube of Force\"}, {\"Cubic Gate\", \"Cubic Gate\"}, {\"Dagger of Venom\", \"Dagger of Venom\"}, {\"Dancing Sword\", \"Dancing Sword\"}, {\"Decanter of Endless Water\", \"Decanter of Endless Water\"}, {\"Deck of Illusions\", \"Deck of Illusions\"}, {\"Defender\", \"Defender\"}, {\"Demon Armor\", \"Demon Armor\"}, {\"Dimensional Shackles\", \"Dimensional Shackles\"}, {\"Dragon Orb\", \"Dragon Orb\"}, {\"Dragon Scale Mail\", \"Dragon Scale Mail\"}, {\"Dragon Slayer\", \"Dragon Slayer\"}, {\"Dust of Disappearance\", \"Dust of Disappearance\"}, {\"Dust of Dryness\", \"Dust of Dryness\"}, {\"Dust of Sneezing and Choking\", \"Dust of Sneezing and Choking\"}, {\"Dwarven Plate\", \"Dwarven Plate\"}, {\"Dwarven Thrower\", \"Dwarven Thrower\"}, {\"Efficient Quiver\", \"Efficient Quiver\"}, {\"Efreeti Bottle\", \"Efreeti Bottle\"}, {\"Elemental Gem\", \"Elemental Gem\"}, {\"Elixir of Health\", \"Elixir of Health\"}, {\"Elven Chain\", \"Elven Chain\"}, {\"Energy Bow\", \"Energy Bow\"}, {\"Eversmoking Bottle\", \"Eversmoking Bottle\"}, {\"Eyes of Charming\", \"Eyes of Charming\"}, {\"Eyes of Minute Seeing\", \"Eyes of Minute Seeing\"}, {\"Eyes of the Eagle\", \"Eyes of the Eagle\"}, {\"Feather Token\", \"Feather Token\"}, {\"Figurine of Wondrous Power\", \"Figurine of Wondrous Power\"}, {\"Flame Tongue\", \"Flame Tongue\"}, {\"Folding Boat\", \"Folding Boat\"}, {\"Frost Brand\", \"Frost Brand\"}, {\"Gauntlets of Ogre Power\", \"Gauntlets of Ogre Power\"}, {\"Gem of Brightness\", \"Gem of Brightness\"}, {\"Gem of Seeing\", \"Gem of Seeing\"}, {\"Giant Slayer\", \"Giant Slayer\"}, {\"Glamoured Studded Leather\", \"Glamoured Studded Leather\"}, {\"Gloves of Missile Snaring\", \"Gloves of Missile Snaring\"}, {\"Gloves of Swimming and Climbing\", \"Gloves of Swimming and Climbing\"}, {\"Gloves of Thievery\", \"Gloves of Thievery\"}, {\"Goggles of Night\", \"Goggles of Night\"}, {\"Hammer of Thunderbolts\", \"Hammer of Thunderbolts\"}, {\"Handy Haversack\", \"Handy Haversack\"}, {\"Hat of Disguise\", \"Hat of Disguise\"}, {\"Hat of Many Spells\", \"Hat of Many Spells\"}, {\"Headband of Intellect\", \"Headband of Intellect\"}, {\"Helm of Brilliance\", \"Helm of Brilliance\"}, {\"Helm of Comprehending Languages\", \"Helm of Comprehending Languages\"}, {\"Helm of Telepathy\", \"Helm of Telepathy\"}, {\"Helm of Teleportation\", \"Helm of Teleportation\"}, {\"Holy Avenger\", \"Holy Avenger\"}, {\"Horn of Blasting\", \"Horn of Blasting\"}, {\"Horn of Valhalla\", \"Horn of Valhalla\"}, {\"Horseshoes of a Zephyr\", \"Horseshoes of a Zephyr\"}, {\"Horseshoes of Speed\", \"Horseshoes of Speed\"}, {\"Immovable Rod\", \"Immovable Rod\"}, {\"Instant Fortress\", \"Instant Fortress\"}, {\"Ioun Stone\", \"Ioun Stone\"}, {\"Iron Bands\", \"Iron Bands\"}, {\"Iron Flask\", \"Iron Flask\"}, {\"Javelin of Lightning\", \"Javelin of Lightning\"}, {\"Lantern of Revealing\", \"Lantern of Revealing\"}, {\"Luck Blade\", \"Luck Blade\"}, {\"Mace of Disruption\", \"Mace of Disruption\"}, {\"Mace of Smiting\", \"Mace of Smiting\"}, {\"Mace of Terror\", \"Mace of Terror\"}, {\"Mantle of Spell Resistance\", \"Mantle of Spell Resistance\"}, {\"Manual of Bodily Health\", \"Manual of Bodily Health\"}, {\"Manual of Gainful Exercise\", \"Manual of Gainful Exercise\"}, {\"Manual of Golems\", \"Manual of Golems\"}, {\"Manual of Quickness of Action\", \"Manual of Quickness of Action\"}, {\"Marvelous Pigments\", \"Marvelous Pigments\"}, {\"Medallion of Thoughts\", \"Medallion of Thoughts\"}, {\"Mirror of Life Trapping\", \"Mirror of Life Trapping\"}, {\"Mithral Armor\", \"Mithral Armor\"}, {\"Mysterious Deck\", \"Mysterious Deck\"}, {\"Necklace of Adaptation\", \"Necklace of Adaptation\"}, {\"Necklace of Fireballs\", \"Necklace of Fireballs\"}, {\"Necklace of Prayer Beads\", \"Necklace of Prayer Beads\"}, {\"Nine Lives Stealer\", \"Nine Lives Stealer\"}, {\"Oathbow\", \"Oathbow\"}, {\"Oil of Etherealness\", \"Oil of Etherealness\"}, {\"Oil of Sharpness\", \"Oil of Sharpness\"}, {\"Oil of Slipperiness\", \"Oil of Slipperiness\"}, {\"Pearl of Power\", \"Pearl of Power\"}, {\"Periapt of Health\", \"Periapt of Health\"}, {\"Periapt of Proof against Poison\", \"Periapt of Proof against Poison\"}, {\"Periapt of Wound Closure\", \"Periapt of Wound Closure\"}, {\"Philter of Love\", \"Philter of Love\"}, {\"Pipes of Haunting\", \"Pipes of Haunting\"}, {\"Pipes of the Sewers\", \"Pipes of the Sewers\"}, {\"Plate Armor of Etherealness\", \"Plate Armor of Etherealness\"}, {\"Portable Hole\", \"Portable Hole\"}, {\"Potion of Animal Friendship\", \"Potion of Animal Friendship\"}, {\"Potion of Clairvoyance\", \"Potion of Clairvoyance\"}, {\"Potion of Climbing\", \"Potion of Climbing\"}, {\"Potion of Diminution\", \"Potion of Diminution\"}, {\"Potion of Flying\", \"Potion of Flying\"}, {\"Potion of Gaseous Form\", \"Potion of Gaseous Form\"}, {\"Potion of Giant Strength\", \"Potion of Giant Strength\"}, {\"Potion of Growth\", \"Potion of Growth\"}, {\"Potions of Healing\", \"Potions of Healing\"}, {\"Potion of Heroism\", \"Potion of Heroism\"}, {\"Potion of Invisibility\", \"Potion of Invisibility\"}, {\"Potion of Invulnerability\", \"Potion of Invulnerability\"}, {\"Potion of Longevity\", \"Potion of Longevity\"}, {\"Potion of Mind Reading\", \"Potion of Mind Reading\"}, {\"Potion of Poison\", \"Potion of Poison\"}, {\"Potion of Resistance\", \"Potion of Resistance\"}, {\"Potion of Speed\", \"Potion of Speed\"}, {\"Potion of Vitality\", \"Potion of Vitality\"}, {\"Potion of Water Breathing\", \"Potion of Water Breathing\"}, {\"Quarterstaff of the Acrobat\", \"Quarterstaff of the Acrobat\"}, {\"Ring of Animal Influence\", \"Ring of Animal Influence\"}, {\"Ring of Djinni Summoning\", \"Ring of Djinni Summoning\"}, {\"Ring of Elemental Command\", \"Ring of Elemental Command\"}, {\"Ring of Evasion\", \"Ring of Evasion\"}, {\"Ring of Feather Falling\", \"Ring of Feather Falling\"}, {\"Ring of Free Action\", \"Ring of Free Action\"}, {\"Ring of Invisibility\", \"Ring of Invisibility\"}, {\"Ring of Jumping\", \"Ring of Jumping\"}, {\"Ring of Mind Shielding\", \"Ring of Mind Shielding\"}, {\"Ring of Protection\", \"Ring of Protection\"}, {\"Ring of Regeneration\", \"Ring of Regeneration\"}, {\"Ring of Resistance\", \"Ring of Resistance\"}, {\"Ring of Shooting Stars\", \"Ring of Shooting Stars\"}, {\"Ring of Spell Storing\", \"Ring of Spell Storing\"}, {\"Ring of Spell Turning\", \"Ring of Spell Turning\"}, {\"Ring of Swimming\", \"Ring of Swimming\"}, {\"Ring of Telekinesis\", \"Ring of Telekinesis\"}, {\"Ring of the Ram\", \"Ring of the Ram\"}, {\"Ring of Three Wishes\", \"Ring of Three Wishes\"}, {\"Ring of Warmth\", \"Ring of Warmth\"}, {\"Ring of Water Walking\", \"Ring of Water Walking\"}, {\"Ring of X-ray Vision\", \"Ring of X-ray Vision\"}, {\"Robe of Eyes\", \"Robe of Eyes\"}, {\"Robe of Scintillating Colors\", \"Robe of Scintillating Colors\"}, {\"Robe of Stars\", \"Robe of Stars\"}, {\"Robe of the Archmagi\", \"Robe of the Archmagi\"}, {\"Robe of Useful Items\", \"Robe of Useful Items\"}, {\"Rod of Absorption\", \"Rod of Absorption\"}, {\"Rod of Alertness\", \"Rod of Alertness\"}, {\"Rod of Lordly Might\", \"Rod of Lordly Might\"}, {\"Rod of Resurrection\", \"Rod of Resurrection\"}, {\"Rod of Rulership\", \"Rod of Rulership\"}, {\"Rod of Security\", \"Rod of Security\"}, {\"Rope of Climbing\", \"Rope of Climbing\"}, {\"Rope of Entanglement\", \"Rope of Entanglement\"}, {\"Scarab of Protection\", \"Scarab of Protection\"}, {\"Scimitar of Speed\", \"Scimitar of Speed\"}, {\"Sending Stones\", \"Sending Stones\"}, {\"Sentinel Shield\", \"Sentinel Shield\"}, {\"+1 Shield\", \"Shield, +1, +2, or +3\"}, {\"+2 Shield\", \"Shield, +1, +2, or +3\"}, {\"+3 Shield\", \"Shield, +1, +2, or +3\"}, {\"Shield of Missile Attraction\", \"Shield of Missile Attraction\"}, {\"Shield of the Cavalier\", \"Shield of the Cavalier\"}, {\"Slippers of Spider Climbing\", \"Slippers of Spider Climbing\"}, {\"Sovereign Glue\", \"Sovereign Glue\"}, {\"Spellguard Shield\", \"Spellguard Shield\"}, {\"Spell Scroll\", \"Spell Scroll\"}, {\"Sphere of Annihilation\", \"Sphere of Annihilation\"}, {\"Staff of Charming\", \"Staff of Charming\"}, {\"Staff of Fire\", \"Staff of Fire\"}, {\"Staff of Frost\", \"Staff of Frost\"}, {\"Staff of Healing\", \"Staff of Healing\"}, {\"Staff of Power\", \"Staff of Power\"}, {\"Staff of Striking\", \"Staff of Striking\"}, {\"Staff of Swarming Insects\", \"Staff of Swarming Insects\"}, {\"Staff of the Magi\", \"Staff of the Magi\"}, {\"Staff of the Python\", \"Staff of the Python\"}, {\"Staff of the Woodlands\", \"Staff of the Woodlands\"}, {\"Staff of Thunder and Lightning\", \"Staff of Thunder and Lightning\"}, {\"Staff of Withering\", \"Staff of Withering\"}, {\"Stone of Controlling Earth Elementals\", \"Stone of Controlling Earth Elementals\"}, {\"Stone of Good Luck (Luckstone)\", \"Stone of Good Luck (Luckstone)\"}, {\"Sun Blade\", \"Sun Blade\"}, {\"Sword of Life Stealing\", \"Sword of Life Stealing\"}, {\"Sword of Sharpness\", \"Sword of Sharpness\"}, {\"Sword of Wounding\", \"Sword of Wounding\"}, {\"Talisman of Pure Good\", \"Talisman of Pure Good\"}, {\"Talisman of the Sphere\", \"Talisman of the Sphere\"}, {\"Talisman of Ultimate Evil\", \"Talisman of Ultimate Evil\"}, {\"Thunderous Greatclub\", \"Thunderous Greatclub\"}, {\"Tome of Clear Thought\", \"Tome of Clear Thought\"}, {\"Tome of Leadership and Influence\", \"Tome of Leadership and Influence\"}, {\"Tome of Understanding\", \"Tome of Understanding\"}, {\"Trident of Fish Command\", \"Trident of Fish Command\"}, {\"Universal Solvent\", \"Universal Solvent\"}, {\"Vicious Weapon\", \"Vicious Weapon\"}, {\"Vorpal Sword\", \"Vorpal Sword\"}, {\"Wand of Binding\", \"Wand of Binding\"}, {\"Wand of Enemy Detection\", \"Wand of Enemy Detection\"}, {\"Wand of Fear\", \"Wand of Fear\"}, {\"Wand of Fireballs\", \"Wand of Fireballs\"}, {\"Wand of Lightning Bolts\", \"Wand of Lightning Bolts\"}, {\"Wand of Magic Detection\", \"Wand of Magic Detection\"}, {\"Wand of Magic Missiles\", \"Wand of Magic Missiles\"}, {\"Wand of Paralysis\", \"Wand of Paralysis\"}, {\"Wand of Polymorph\", \"Wand of Polymorph\"}, {\"Wand of Secrets\", \"Wand of Secrets\"}, {\"+1 Wand of the War Mage\", \"Wand of the War Mage, +1, +2, or +3\"}, {\"+2 Wand of the War Mage\", \"Wand of the War Mage, +1, +2, or +3\"}, {\"+3 Wand of the War Mage\", \"Wand of the War Mage, +1, +2, or +3\"}, {\"Wand of Web\", \"Wand of Web\"}, {\"Wand of Wonder\", \"Wand of Wonder\"}, {\"+1 Weapon\", \"Weapon, +1, +2, or +3\"}, {\"+2 Weapon\", \"Weapon, +1, +2, or +3\"}, {\"+3 Weapon\", \"Weapon, +1, +2, or +3\"}, {\"Weapon of Warning\", \"Weapon of Warning\"}, {\"Well of Many Worlds\", \"Well of Many Worlds\"}, {\"Wind Fan\", \"Wind Fan\"}, {\"Winged Boots\", \"Winged Boots\"}, {\"Wings of Flying\", \"Wings of Flying\"}, {\"아다만틴 갑옷\", \"Adamantine Armor\"}, {\"학살의 탄약\", \"Ammunition of Slaying\"}, {\"건강의 부적\", \"Amulet of Health\"}, {\"탐지 방지 부적\", \"Amulet of Proof against Detection and Location\"}, {\"차원의 부적\", \"Amulet of the Planes\"}, {\"움직이는 방패\", \"Animated Shield\"}, {\"게 모양 장치\", \"Apparatus of the Crab\"}, {\"무적의 갑옷\", \"Armor of Invulnerability\"}, {\"저항의 갑옷\", \"Armor of Resistance\"}, {\"취약의 갑옷\", \"Armor of Vulnerability\"}, {\"화살 잡는 방패\", \"Arrow-Catching Shield\"}, {\"콩 자루\", \"Bag of Beans\"}, {\"삼키는 자루\", \"Bag of Devouring\"}, {\"보관의 자루\", \"Bag of Holding\"}, {\"묘수 자루\", \"Bag of Tricks\"}, {\"역장 구슬\", \"Bead of Force\"}, {\"영양 구슬\", \"Bead of Nourishment\"}, {\"드워프의 허리띠\", \"Belt of Dwarvenkind\"}, {\"거인의 힘 허리띠\", \"Belt of Giant Strength\"}, {\"광전사의 도끼\", \"Berserker Axe\"}, {\"엘프의 장화\", \"Boots of Elvenkind\"}, {\"부양의 장화\", \"Boots of Levitation\"}, {\"신속의 장화\", \"Boots of Speed\"}, {\"성큼 도약 장화\", \"Boots of Striding and Springing\"}, {\"설원의 장화\", \"Boots of the Winterlands\"}, {\"물 원소 지배의 그릇\", \"Bowl of Commanding Water Elementals\"}, {\"궁술의 팔목 보호대\", \"Bracers of Archery\"}, {\"방어의 팔목 보호대\", \"Bracers of Defense\"}, {\"불 원소 지배의 화로\", \"Brazier of Commanding Fire Elementals\"}, {\"보호막 브로치\", \"Brooch of Shielding\"}, {\"비행 빗자루\", \"Broom of Flying\"}, {\"기원의 양초\", \"Candle of Invocation\"}, {\"협잡꾼의 망토\", \"Cape of the Mountebank\"}, {\"비행 양탄자\", \"Carpet of Flying\"}, {\"공기 원소 조종 향로\", \"Censer of Controlling Air Elementals\"}, {\"열림의 종\", \"Chime of Opening\"}, {\"폭발의 머리띠\", \"Circlet of Blasting\"}, {\"거미의 망토\", \"Cloak of Arachnida\"}, {\"전위의 망토\", \"Cloak of Displacement\"}, {\"엘프의 망토\", \"Cloak of Elvenkind\"}, {\"투명화 망토\", \"Cloak of Invisibility\"}, {\"보호의 망토\", \"Cloak of Protection\"}, {\"박쥐의 망토\", \"Cloak of the Bat\"}, {\"쥐가오리 망토\", \"Cloak of the Manta Ray\"}, {\"수정 구슬\", \"Crystal Ball\"}, {\"독심의 수정 구슬\", \"Crystal Ball of Mind Reading\"}, {\"정신감응의 수정 구슬\", \"Crystal Ball of Telepathy\"}, {\"진시야의 수정 구슬\", \"Crystal Ball of True Seeing\"}, {\"역장 정육면체\", \"Cube of Force\"}, {\"차원문 정육면체\", \"Cubic Gate\"}, {\"독의 대거\", \"Dagger of Venom\"}, {\"춤추는 검\", \"Dancing Sword\"}, {\"끝없는 물병\", \"Decanter of Endless Water\"}, {\"환영 카드\", \"Deck of Illusions\"}, {\"수호의 무기\", \"Defender\"}, {\"악마 갑옷\", \"Demon Armor\"}, {\"차원 족쇄\", \"Dimensional Shackles\"}, {\"용의 구슬\", \"Dragon Orb\"}, {\"용비늘 갑옷\", \"Dragon Scale Mail\"}, {\"용 살해 무기\", \"Dragon Slayer\"}, {\"사라짐 가루\", \"Dust of Disappearance\"}, {\"건조 가루\", \"Dust of Dryness\"}, {\"재채기 가루\", \"Dust of Sneezing and Choking\"}, {\"드워프 판금 갑옷\", \"Dwarven Plate\"}, {\"드워프 투척 망치\", \"Dwarven Thrower\"}, {\"효율적인 화살통\", \"Efficient Quiver\"}, {\"에프리트 병\", \"Efreeti Bottle\"}, {\"원소 보석\", \"Elemental Gem\"}, {\"건강의 영약\", \"Elixir of Health\"}, {\"엘프 사슬 갑옷\", \"Elven Chain\"}, {\"에너지 활\", \"Energy Bow\"}, {\"끝없는 연기 병\", \"Eversmoking Bottle\"}, {\"매혹의 렌즈\", \"Eyes of Charming\"}, {\"세밀 시야 렌즈\", \"Eyes of Minute Seeing\"}, {\"독수리 눈 렌즈\", \"Eyes of the Eagle\"}, {\"깃털 부적\", \"Feather Token\"}, {\"경이로운 힘의 조각상\", \"Figurine of Wondrous Power\"}, {\"화염의 혀\", \"Flame Tongue\"}, {\"접는 배\", \"Folding Boat\"}, {\"서리의 검\", \"Frost Brand\"}, {\"오우거 힘의 건틀릿\", \"Gauntlets of Ogre Power\"}, {\"광휘의 보석\", \"Gem of Brightness\"}, {\"투시의 보석\", \"Gem of Seeing\"}, {\"거인 살해 무기\", \"Giant Slayer\"}, {\"환영 스터디드 레더\", \"Glamoured Studded Leather\"}, {\"투사체 잡는 장갑\", \"Gloves of Missile Snaring\"}, {\"헤엄·등반 장갑\", \"Gloves of Swimming and Climbing\"}, {\"도둑의 장갑\", \"Gloves of Thievery\"}, {\"밤의 고글\", \"Goggles of Night\"}, {\"벼락 망치\", \"Hammer of Thunderbolts\"}, {\"편리한 배낭\", \"Handy Haversack\"}, {\"변장 모자\", \"Hat of Disguise\"}, {\"여러 주문의 모자\", \"Hat of Many Spells\"}, {\"지능의 머리띠\", \"Headband of Intellect\"}, {\"광채의 투구\", \"Helm of Brilliance\"}, {\"언어 이해의 투구\", \"Helm of Comprehending Languages\"}, {\"정신감응 투구\", \"Helm of Telepathy\"}, {\"순간이동 투구\", \"Helm of Teleportation\"}, {\"성스러운 복수자\", \"Holy Avenger\"}, {\"폭음의 뿔피리\", \"Horn of Blasting\"}, {\"발할라의 뿔피리\", \"Horn of Valhalla\"}, {\"산들바람 편자\", \"Horseshoes of a Zephyr\"}, {\"신속의 편자\", \"Horseshoes of Speed\"}, {\"움직이지 않는 막대\", \"Immovable Rod\"}, {\"즉석 요새\", \"Instant Fortress\"}, {\"아이운 돌\", \"Ioun Stone\"}, {\"쇠 띠\", \"Iron Bands\"}, {\"쇠 플라스크\", \"Iron Flask\"}, {\"번개 자벨린\", \"Javelin of Lightning\"}, {\"드러냄의 랜턴\", \"Lantern of Revealing\"}, {\"행운의 검\", \"Luck Blade\"}, {\"붕괴의 메이스\", \"Mace of Disruption\"}, {\"강타의 메이스\", \"Mace of Smiting\"}, {\"공포의 메이스\", \"Mace of Terror\"}, {\"주문 저항의 망토\", \"Mantle of Spell Resistance\"}, {\"신체 건강 교본\", \"Manual of Bodily Health\"}, {\"유익한 운동 교본\", \"Manual of Gainful Exercise\"}, {\"골렘 교본\", \"Manual of Golems\"}, {\"민첩한 동작 교본\", \"Manual of Quickness of Action\"}, {\"경이로운 물감\", \"Marvelous Pigments\"}, {\"생각의 메달\", \"Medallion of Thoughts\"}, {\"생명 가두는 거울\", \"Mirror of Life Trapping\"}, {\"미스릴 갑옷\", \"Mithral Armor\"}, {\"수수께끼의 카드\", \"Mysterious Deck\"}, {\"적응의 목걸이\", \"Necklace of Adaptation\"}, {\"화염구 목걸이\", \"Necklace of Fireballs\"}, {\"기도 염주 목걸이\", \"Necklace of Prayer Beads\"}, {\"아홉 목숨 도둑\", \"Nine Lives Stealer\"}, {\"맹세의 활\", \"Oathbow\"}, {\"에테르화 기름\", \"Oil of Etherealness\"}, {\"예리함의 기름\", \"Oil of Sharpness\"}, {\"미끄러움의 기름\", \"Oil of Slipperiness\"}, {\"힘의 진주\", \"Pearl of Power\"}, {\"건강의 펜던트\", \"Periapt of Health\"}, {\"독 방지 펜던트\", \"Periapt of Proof against Poison\"}, {\"상처 봉합 펜던트\", \"Periapt of Wound Closure\"}, {\"사랑의 묘약\", \"Philter of Love\"}, {\"유령 피리\", \"Pipes of Haunting\"}, {\"하수도 피리\", \"Pipes of the Sewers\"}, {\"에테르화 판금 갑옷\", \"Plate Armor of Etherealness\"}, {\"휴대용 구멍\", \"Portable Hole\"}, {\"동물 친화 물약\", \"Potion of Animal Friendship\"}, {\"투시 물약\", \"Potion of Clairvoyance\"}, {\"등반 물약\", \"Potion of Climbing\"}, {\"축소 물약\", \"Potion of Diminution\"}, {\"비행 물약\", \"Potion of Flying\"}, {\"기체 형태 물약\", \"Potion of Gaseous Form\"}, {\"거인의 힘 물약\", \"Potion of Giant Strength\"}, {\"성장 물약\", \"Potion of Growth\"}, {\"치유의 물약\", \"Potions of Healing\"}, {\"영웅심 물약\", \"Potion of Heroism\"}, {\"투명화 물약\", \"Potion of Invisibility\"}, {\"무적 물약\", \"Potion of Invulnerability\"}, {\"장수 물약\", \"Potion of Longevity\"}, {\"독심 물약\", \"Potion of Mind Reading\"}, {\"독 물약\", \"Potion of Poison\"}, {\"저항 물약\", \"Potion of Resistance\"}, {\"신속 물약\", \"Potion of Speed\"}, {\"활력 물약\", \"Potion of Vitality\"}, {\"수중 호흡 물약\", \"Potion of Water Breathing\"}, {\"곡예사의 쿼터스태프\", \"Quarterstaff of the Acrobat\"}, {\"동물 감화 반지\", \"Ring of Animal Influence\"}, {\"진 소환 반지\", \"Ring of Djinni Summoning\"}, {\"원소 지배 반지\", \"Ring of Elemental Command\"}, {\"회피의 반지\", \"Ring of Evasion\"}, {\"깃털 낙하 반지\", \"Ring of Feather Falling\"}, {\"자유 행동 반지\", \"Ring of Free Action\"}, {\"투명화 반지\", \"Ring of Invisibility\"}, {\"도약의 반지\", \"Ring of Jumping\"}, {\"정신 보호 반지\", \"Ring of Mind Shielding\"}, {\"보호의 반지\", \"Ring of Protection\"}, {\"재생의 반지\", \"Ring of Regeneration\"}, {\"저항의 반지\", \"Ring of Resistance\"}, {\"유성의 반지\", \"Ring of Shooting Stars\"}, {\"주문 저장 반지\", \"Ring of Spell Storing\"}, {\"주문 되돌림 반지\", \"Ring of Spell Turning\"}, {\"헤엄의 반지\", \"Ring of Swimming\"}, {\"염동력 반지\", \"Ring of Telekinesis\"}, {\"숫양의 반지\", \"Ring of the Ram\"}, {\"세 가지 소원 반지\", \"Ring of Three Wishes\"}, {\"온기의 반지\", \"Ring of Warmth\"}, {\"수면 보행 반지\", \"Ring of Water Walking\"}, {\"투시 시야 반지\", \"Ring of X-ray Vision\"}, {\"눈의 로브\", \"Robe of Eyes\"}, {\"현란한 빛깔의 로브\", \"Robe of Scintillating Colors\"}, {\"별의 로브\", \"Robe of Stars\"}, {\"대마법사의 로브\", \"Robe of the Archmagi\"}, {\"쓸모 있는 물건 로브\", \"Robe of Useful Items\"}, {\"흡수의 막대\", \"Rod of Absorption\"}, {\"경계의 막대\", \"Rod of Alertness\"}, {\"군주의 위력 막대\", \"Rod of Lordly Might\"}, {\"부활의 막대\", \"Rod of Resurrection\"}, {\"통치의 막대\", \"Rod of Rulership\"}, {\"안전의 막대\", \"Rod of Security\"}, {\"등반 밧줄\", \"Rope of Climbing\"}, {\"휘감는 밧줄\", \"Rope of Entanglement\"}, {\"보호의 스카라브\", \"Scarab of Protection\"}, {\"신속의 시미터\", \"Scimitar of Speed\"}, {\"전언의 돌\", \"Sending Stones\"}, {\"파수꾼 방패\", \"Sentinel Shield\"}, {\"투사체 끄는 방패\", \"Shield of Missile Attraction\"}, {\"기사의 방패\", \"Shield of the Cavalier\"}, {\"거미 걸음 신발\", \"Slippers of Spider Climbing\"}, {\"만능 접착제\", \"Sovereign Glue\"}, {\"주문 방어 방패\", \"Spellguard Shield\"}, {\"주문 두루마리\", \"Spell Scroll\"}, {\"소멸의 구체\", \"Sphere of Annihilation\"}, {\"매혹의 지팡이\", \"Staff of Charming\"}, {\"화염의 지팡이\", \"Staff of Fire\"}, {\"서리의 지팡이\", \"Staff of Frost\"}, {\"치유의 지팡이\", \"Staff of Healing\"}, {\"권능의 지팡이\", \"Staff of Power\"}, {\"타격의 지팡이\", \"Staff of Striking\"}, {\"벌레 떼의 지팡이\", \"Staff of Swarming Insects\"}, {\"마도사의 지팡이\", \"Staff of the Magi\"}, {\"비단뱀의 지팡이\", \"Staff of the Python\"}, {\"숲의 지팡이\", \"Staff of the Woodlands\"}, {\"천둥 번개의 지팡이\", \"Staff of Thunder and Lightning\"}, {\"시듦의 지팡이\", \"Staff of Withering\"}, {\"대지 원소 조종의 돌\", \"Stone of Controlling Earth Elementals\"}, {\"행운의 돌\", \"Stone of Good Luck (Luckstone)\"}, {\"태양의 검\", \"Sun Blade\"}, {\"생명 강탈의 검\", \"Sword of Life Stealing\"}, {\"예리함의 검\", \"Sword of Sharpness\"}, {\"상처의 검\", \"Sword of Wounding\"}, {\"순수한 선의 부적\", \"Talisman of Pure Good\"}, {\"구체의 부적\", \"Talisman of the Sphere\"}, {\"궁극의 악의 부적\", \"Talisman of Ultimate Evil\"}, {\"천둥의 그레이트클럽\", \"Thunderous Greatclub\"}, {\"명석한 사고의 책\", \"Tome of Clear Thought\"}, {\"지도력과 영향력의 책\", \"Tome of Leadership and Influence\"}, {\"이해의 책\", \"Tome of Understanding\"}, {\"물고기 지배의 트라이던트\", \"Trident of Fish Command\"}, {\"만능 용해제\", \"Universal Solvent\"}, {\"잔혹한 무기\", \"Vicious Weapon\"}, {\"보팔 검\", \"Vorpal Sword\"}, {\"속박의 완드\", \"Wand of Binding\"}, {\"적 탐지 완드\", \"Wand of Enemy Detection\"}, {\"공포의 완드\", \"Wand of Fear\"}, {\"화염구 완드\", \"Wand of Fireballs\"}, {\"번개 완드\", \"Wand of Lightning Bolts\"}, {\"마법 탐지 완드\", \"Wand of Magic Detection\"}, {\"마법 화살 완드\", \"Wand of Magic Missiles\"}, {\"마비의 완드\", \"Wand of Paralysis\"}, {\"변신 완드\", \"Wand of Polymorph\"}, {\"비밀의 완드\", \"Wand of Secrets\"}, {\"전투 마법사의 완드\", \"Wand of the War Mage, +1, +2, or +3\"}, {\"거미줄 완드\", \"Wand of Web\"}, {\"경이의 완드\", \"Wand of Wonder\"}, {\"경고의 무기\", \"Weapon of Warning\"}, {\"여러 세계의 우물\", \"Well of Many Worlds\"}, {\"바람 부채\", \"Wind Fan\"}, {\"날개 달린 장화\", \"Winged Boots\"}, {\"비행의 날개\", \"Wings of Flying\"}}\r\n\r\nK.MAGIC = { [\"Adamantine Armor\"] = { ko = \"아다만틴 갑옷\", base = \"medium_heavy_nohide\", pw = {{ k = \"nocrit\" }}, r = \"B\", cat = \"Armor\" }, [\"Ammunition, +1, +2, or +3\"] = { ko = \"+1·+2·+3 탄약\", pw = {{ t = \"+1/+2/+3 to the attack and damage of a shot with it (written on that ATTACK)\", k = \"tell\" }}, r = {\"B\", \"A\", \"S\"}, cat = \"Weapon\" }, [\"Ammunition of Slaying\"] = { ko = \"학살의 탄약\", var = { Aberration = \"S\", Beast = \"S\", Celestial = \"S\", Construct = \"S\", Dragon = \"S\", Elemental = \"S\", Humanoid = \"S\", Fey = \"S\", Fiend = \"S\", Giant = \"S\", Monstrosity = \"S\", Ooze = \"S\", Plant = \"S\", Undead = \"S\" }, r = \"S\", cat = \"Weapon\" }, [\"Amulet of Health\"] = { ko = \"건강의 부적\", pw = {{ ab = \"Constitution\", n = 19, k = \"set\" }}, r = \"A\", cat = \"Wondrous Item\", att = true }, [\"Amulet of Proof against Detection and Location\"] = { ko = \"탐지 방지 부적\", r = \"B\", cat = \"Wondrous Item\", att = true }, [\"Amulet of the Planes\"] = { ko = \"차원의 부적\", r = \"S\", cat = \"Wondrous Item\", att = true }, [\"Animated Shield\"] = { ko = \"움직이는 방패\", base = \"Shield\", r = \"S\", cat = \"Armor\", att = true }, [\"Apparatus of the Crab\"] = { ko = \"게 모양 장치\", r = \"L\", cat = \"Wondrous Item\" }, [\"Armor, +1, +2, or +3\"] = { ko = \"+1·+2·+3 갑옷\", base = \"any_armor\", r = {\"A\", \"S\", \"L\"}, cat = \"Armor\" }, [\"Armor of Invulnerability\"] = { ko = \"무적의 갑옷\", base = \"Plate Armor\", pw = {{ type = \"Bludgeoning\", k = \"resist\" }, { type = \"Piercing\", k = \"resist\" }, { type = \"Slashing\", k = \"resist\" }}, r = \"L\", cat = \"Armor\", att = true }, [\"Armor of Resistance\"] = { ko = \"저항의 갑옷\", base = \"any_armor\", var = { Acid = \"A\", Cold = \"A\", Fire = \"A\", Force = \"A\", Lightning = \"A\", Necrotic = \"A\", Poison = \"A\", Psychic = \"A\", Radiant = \"A\", Thunder = \"A\" }, pw = {{ type = \"var\", k = \"resist\" }}, r = \"A\", cat = \"Armor\", att = true }, [\"Armor of Vulnerability\"] = { ko = \"취약의 갑옷\", base = \"any_armor\", var = { Bludgeoning = \"A\", Piercing = \"A\", Slashing = \"A\" }, pw = {{ type = \"var\", k = \"resist\" }, { type = \"others\", k = \"vuln\" }}, r = \"A\", cat = \"Armor\", att = true }, [\"Arrow-Catching Shield\"] = { ko = \"화살 잡는 방패\", base = \"Shield\", pw = {{ t = \"+2 AC against ranged attack rolls\", k = \"tell\" }}, r = \"A\", cat = \"Armor\", att = true }, [\"Bag of Beans\"] = { ko = \"콩 자루\", r = \"A\", cat = \"Wondrous Item\" }, [\"Bag of Devouring\"] = { ko = \"삼키는 자루\", r = \"S\", cat = \"Wondrous Item\" }, [\"Bag of Holding\"] = { ko = \"보관의 자루\", r = \"B\", cat = \"Wondrous Item\" }, [\"Bag of Tricks\"] = { ko = \"묘수 자루\", r = \"B\", cat = \"Wondrous Item\" }, [\"Bead of Force\"] = { ko = \"역장 구슬\", r = \"A\", cat = \"Wondrous Item\" }, [\"Bead of Nourishment\"] = { ko = \"영양 구슬\", r = \"C\", cat = \"Wondrous Item\" }, [\"Belt of Dwarvenkind\"] = { ko = \"드워프의 허리띠\", pw = {{ ab = \"Constitution\", n = 2, max = 20, k = \"add\" }}, r = \"A\", cat = \"Wondrous Item\", att = true }, [\"Belt of Giant Strength\"] = { ko = \"거인의 힘 허리띠\", var = { Hill = { r = \"A\", n = 21 }, Frost = { r = \"S\", n = 23 }, Stone = { r = \"S\", n = 23 }, Fire = { r = \"S\", n = 25 }, Cloud = { r = \"L\", n = 27 }, Storm = { r = \"L\", n = 29 } }, pw = {{ ab = \"Strength\", n = \"var\", k = \"set\" }}, cat = \"Wondrous Item\", att = true }, [\"Berserker Axe\"] = { ko = \"광전사의 도끼\", base = {\"Battleaxe\", \"Greataxe\", \"Halberd\"}, plus = 1, pw = {{ n = 1, k = \"maxhp\" }}, r = \"A\", cat = \"Weapon\", att = true }, [\"Boots of Elvenkind\"] = { ko = \"엘프의 장화\", pw = {{ t = \"Advantage on Dexterity (Stealth) checks\", k = \"tell\" }}, r = \"B\", cat = \"Wondrous Item\" }, [\"Boots of Levitation\"] = { ko = \"부양의 장화\", r = \"A\", cat = \"Wondrous Item\", att = true }, [\"Boots of Speed\"] = { ko = \"신속의 장화\", r = \"A\", cat = \"Wondrous Item\", att = true }, [\"Boots of Striding and Springing\"] = { ko = \"성큼 도약 장화\", pw = {{ n = 30, k = \"speedmin\" }}, r = \"B\", cat = \"Wondrous Item\", att = true }, [\"Boots of the Winterlands\"] = { ko = \"설원의 장화\", pw = {{ type = \"Cold\", k = \"resist\" }}, r = \"B\", cat = \"Wondrous Item\", att = true }, [\"Bowl of Commanding Water Elementals\"] = { ko = \"물 원소 지배의 그릇\", r = \"A\", cat = \"Wondrous Item\" }, [\"Bracers of Archery\"] = { ko = \"궁술의 팔목 보호대\", pw = {{ n = 2, bases = {\"Longbow\", \"Shortbow\"}, k = \"dmgbonus\" }}, r = \"B\", cat = \"Wondrous Item\", att = true }, [\"Bracers of Defense\"] = { ko = \"방어의 팔목 보호대\", pw = {{ n = 2, [\"if\"] = \"noarmor_noshield\", k = \"ac\" }}, r = \"A\", cat = \"Wondrous Item\", att = true }, [\"Brazier of Commanding Fire Elementals\"] = { ko = \"불 원소 지배의 화로\", r = \"A\", cat = \"Wondrous Item\" }, [\"Brooch of Shielding\"] = { ko = \"보호막 브로치\", pw = {{ type = \"Force\", k = \"resist\" }, { t = \"no damage from Magic Missile\", k = \"tell\" }}, r = \"B\", cat = \"Wondrous Item\", att = true }, [\"Broom of Flying\"] = { ko = \"비행 빗자루\", r = \"B\", cat = \"Wondrous Item\", att = true }, [\"Candle of Invocation\"] = { ko = \"기원의 양초\", r = \"S\", cat = \"Wondrous Item\", att = true }, [\"Cape of the Mountebank\"] = { ko = \"협잡꾼의 망토\", r = \"A\", cat = \"Wondrous Item\" }, [\"Carpet of Flying\"] = { ko = \"비행 양탄자\", r = \"S\", cat = \"Wondrous Item\" }, [\"Censer of Controlling Air Elementals\"] = { ko = \"공기 원소 조종 향로\", r = \"A\", cat = \"Wondrous Item\" }, [\"Chime of Opening\"] = { ko = \"열림의 종\", r = \"A\", cat = \"Wondrous Item\" }, [\"Circlet of Blasting\"] = { ko = \"폭발의 머리띠\", sp = {{ s = \"Scorching Ray\", day = 1, atk = 5 }}, r = \"B\", cat = \"Wondrous Item\" }, [\"Cloak of Arachnida\"] = { ko = \"거미의 망토\", r = \"S\", cat = \"Wondrous Item\", att = true }, [\"Cloak of Displacement\"] = { ko = \"전위의 망토\", r = \"A\", cat = \"Wondrous Item\", att = true }, [\"Cloak of Elvenkind\"] = { ko = \"엘프의 망토\", pw = {{ t = \"Advantage on Dexterity (Stealth); Perception to see you has Disadvantage\", k = \"tell\" }}, r = \"B\", cat = \"Wondrous Item\", att = true }, [\"Cloak of Invisibility\"] = { ko = \"투명화 망토\", r = \"L\", cat = \"Wondrous Item\", att = true }, [\"Cloak of Protection\"] = { ko = \"보호의 망토\", pw = {{ n = 1, k = \"ac\" }, { n = 1, k = \"save\" }}, r = \"B\", cat = \"Wondrous Item\", att = true }, [\"Cloak of the Bat\"] = { ko = \"박쥐의 망토\", r = \"A\", cat = \"Wondrous Item\", att = true }, [\"Cloak of the Manta Ray\"] = { ko = \"쥐가오리 망토\", r = \"B\", cat = \"Wondrous Item\", att = true }, [\"Crystal Ball\"] = { ko = \"수정 구슬\", r = \"S\", cat = \"Wondrous Item\", att = true }, [\"Crystal Ball of Mind Reading\"] = { ko = \"독심의 수정 구슬\", r = \"L\", cat = \"Wondrous Item\", att = true }, [\"Crystal Ball of Telepathy\"] = { ko = \"정신감응의 수정 구슬\", r = \"L\", cat = \"Wondrous Item\", att = true }, [\"Crystal Ball of True Seeing\"] = { ko = \"진시야의 수정 구슬\", r = \"L\", cat = \"Wondrous Item\", att = true }, [\"Cube of Force\"] = { ko = \"역장 정육면체\", r = \"A\", cat = \"Wondrous Item\", att = true }, [\"Cubic Gate\"] = { ko = \"차원문 정육면체\", r = \"L\", cat = \"Wondrous Item\" }, [\"Dagger of Venom\"] = { ko = \"독의 대거\", base = \"Dagger\", plus = 1, pw = {{ t = \"once per dawn, a Bonus Action coats it: the next hit, DC 15 Constitution save or 2d10 Poison and Poisoned 1 minute\", k = \"tell\" }}, r = \"A\", cat = \"Weapon\" }, [\"Dancing Sword\"] = { ko = \"춤추는 검\", base = {\"Greatsword\", \"Longsword\", \"Rapier\", \"Scimitar\", \"Shortsword\"}, r = \"S\", cat = \"Weapon\", att = true }, [\"Decanter of Endless Water\"] = { ko = \"끝없는 물병\", r = \"B\", cat = \"Wondrous Item\" }, [\"Deck of Illusions\"] = { ko = \"환영 카드\", r = \"B\", cat = \"Wondrous Item\" }, Defender = { ko = \"수호의 무기\", base = \"any_melee\", plus = 3, pw = {{ t = \"on the first attack each turn some of its +3 may move to AC until the next turn\", k = \"tell\" }}, r = \"L\", cat = \"Weapon\", att = true }, [\"Demon Armor\"] = { ko = \"악마 갑옷\", base = \"any_armor\", pw = {{ n = 1, k = \"ac\" }, { dice = \"1d8\", type = \"Slashing\", plus = 1, k = \"unarmed\" }}, r = \"S\", cat = \"Armor\", att = true }, [\"Dimensional Shackles\"] = { ko = \"차원 족쇄\", r = \"A\", cat = \"Wondrous Item\" }, [\"Dragon Orb\"] = { ko = \"용의 구슬\", r = \"X\", cat = \"Wondrous Item\", att = true }, [\"Dragon Scale Mail\"] = { ko = \"용비늘 갑옷\", base = \"Scale Mail\", var = { Acid = \"S\", Cold = \"S\", Fire = \"S\", Lightning = \"S\", Poison = \"S\" }, pw = {{ n = 1, k = \"ac\" }, { type = \"var\", k = \"resist\" }}, r = \"S\", cat = \"Armor\", att = true }, [\"Dragon Slayer\"] = { ko = \"용 살해 무기\", base = \"any_weapon\", plus = 1, pw = {{ dice = \"3d6\", type = \"weapon\", vs = {\"Dragon\"}, k = \"dmg\" }}, r = \"A\", cat = \"Weapon\" }, [\"Dust of Disappearance\"] = { ko = \"사라짐 가루\", r = \"B\", cat = \"Wondrous Item\" }, [\"Dust of Dryness\"] = { ko = \"건조 가루\", r = \"B\", cat = \"Wondrous Item\" }, [\"Dust of Sneezing and Choking\"] = { ko = \"재채기 가루\", r = \"B\", cat = \"Wondrous Item\" }, [\"Dwarven Plate\"] = { ko = \"드워프 판금 갑옷\", base = {\"Plate Armor\", \"Half Plate Armor\"}, pw = {{ n = 2, k = \"ac\" }}, r = \"S\", cat = \"Armor\" }, [\"Dwarven Thrower\"] = { ko = \"드워프 투척 망치\", base = \"Warhammer\", plus = 3, pw = {{ dice = \"1d8\", type = \"Force\", thrown = true, k = \"dmg\" }, { t = \"Thrown 20/60, back to the hand; a thrown hit on a Giant: 2d8 Force instead of 1d8\", k = \"tell\" }}, r = \"S\", cat = \"Weapon\", att = true, by = {\"Dwarf\", \"Belt of Dwarvenkind\", \"Belt of Dwarvenkind\"} }, [\"Efficient Quiver\"] = { ko = \"효율적인 화살통\", r = \"B\", cat = \"Wondrous Item\" }, [\"Efreeti Bottle\"] = { ko = \"에프리트 병\", r = \"S\", cat = \"Wondrous Item\" }, [\"Elemental Gem\"] = { ko = \"원소 보석\", r = \"B\", cat = \"Wondrous Item\" }, [\"Elixir of Health\"] = { ko = \"건강의 영약\", use = { uncond = {\"Blinded\", \"Deafened\", \"Paralyzed\", \"Poisoned\"} }, r = \"A\", cat = \"Potion\" }, [\"Elven Chain\"] = { ko = \"엘프 사슬 갑옷\", base = {\"Chain Shirt\", \"Chain Mail\"}, pw = {{ n = 1, k = \"ac\" }, { k = \"prof\" }}, r = \"A\", cat = \"Armor\" }, [\"Energy Bow\"] = { ko = \"에너지 활\", base = {\"Longbow\", \"Shortbow\"}, plus = 1, pw = {{ type = \"Force\", k = \"dtype\" }, { k = \"noammo\" }}, r = \"S\", cat = \"Weapon\", att = true }, [\"Eversmoking Bottle\"] = { ko = \"끝없는 연기 병\", r = \"B\", cat = \"Wondrous Item\" }, [\"Eyes of Charming\"] = { ko = \"매혹의 렌즈\", r = \"B\", cat = \"Wondrous Item\", att = true }, [\"Eyes of Minute Seeing\"] = { ko = \"세밀 시야 렌즈\", r = \"B\", cat = \"Wondrous Item\" }, [\"Eyes of the Eagle\"] = { ko = \"독수리 눈 렌즈\", pw = {{ t = \"Advantage on Wisdom (Perception) checks that rely on sight\", k = \"tell\" }}, r = \"B\", cat = \"Wondrous Item\" }, [\"Feather Token\"] = { ko = \"깃털 부적\", cat = \"Wondrous Item\" }, [\"Figurine of Wondrous Power\"] = { ko = \"경이로운 힘의 조각상\", cat = \"Wondrous Item\" }, [\"Flame Tongue\"] = { ko = \"화염의 혀\", base = \"any_melee\", pw = {{ dice = \"2d6\", type = \"Fire\", may = true, k = \"dmg\" }}, r = \"A\", cat = \"Weapon\", att = true }, [\"Folding Boat\"] = { ko = \"접는 배\", r = \"A\", cat = \"Wondrous Item\" }, [\"Frost Brand\"] = { ko = \"서리의 검\", base = {\"Glaive\", \"Greatsword\", \"Longsword\", \"Rapier\", \"Scimitar\", \"Shortsword\"}, pw = {{ dice = \"1d6\", type = \"Cold\", k = \"dmg\" }, { type = \"Fire\", k = \"resist\" }}, r = \"S\", cat = \"Weapon\", att = true }, [\"Gauntlets of Ogre Power\"] = { ko = \"오우거 힘의 건틀릿\", pw = {{ ab = \"Strength\", n = 19, k = \"set\" }}, r = \"B\", cat = \"Wondrous Item\", att = true }, [\"Gem of Brightness\"] = { ko = \"광휘의 보석\", r = \"B\", cat = \"Wondrous Item\" }, [\"Gem of Seeing\"] = { ko = \"투시의 보석\", r = \"A\", cat = \"Wondrous Item\", att = true }, [\"Giant Slayer\"] = { ko = \"거인 살해 무기\", base = \"any_weapon\", plus = 1, pw = {{ dice = \"2d6\", type = \"weapon\", vs = {\"Giant\"}, k = \"dmg\" }}, r = \"A\", cat = \"Weapon\" }, [\"Glamoured Studded Leather\"] = { ko = \"환영 스터디드 레더\", base = \"Studded Leather Armor\", pw = {{ n = 1, k = \"ac\" }}, r = \"A\", cat = \"Armor\" }, [\"Gloves of Missile Snaring\"] = { ko = \"투사체 잡는 장갑\", r = \"B\", cat = \"Wondrous Item\", att = true }, [\"Gloves of Swimming and Climbing\"] = { ko = \"헤엄·등반 장갑\", r = \"B\", cat = \"Wondrous Item\", att = true }, [\"Gloves of Thievery\"] = { ko = \"도둑의 장갑\", r = \"B\", cat = \"Wondrous Item\" }, [\"Goggles of Night\"] = { ko = \"밤의 고글\", r = \"B\", cat = \"Wondrous Item\" }, [\"Hammer of Thunderbolts\"] = { ko = \"벼락 망치\", base = {\"Maul\", \"Warhammer\"}, plus = 1, ch = { max = 5, regain = \"1d4+1\" }, pw = {{ t = \"1 charge: thrown 20/60, on a hit the target and all within 30 ft make a DC 17 Constitution save or are Stunned\", k = \"tell\" }}, r = \"L\", cat = \"Weapon\", att = true }, [\"Handy Haversack\"] = { ko = \"편리한 배낭\", r = \"A\", cat = \"Wondrous Item\" }, [\"Hat of Disguise\"] = { ko = \"변장 모자\", r = \"B\", cat = \"Wondrous Item\", att = true }, [\"Hat of Many Spells\"] = { ko = \"여러 주문의 모자\", r = \"S\", cat = \"Wondrous Item\", att = true, by = {\"Wizard\"} }, [\"Headband of Intellect\"] = { ko = \"지능의 머리띠\", pw = {{ ab = \"Intelligence\", n = 19, k = \"set\" }}, r = \"B\", cat = \"Wondrous Item\", att = true }, [\"Helm of Brilliance\"] = { ko = \"광채의 투구\", r = \"S\", cat = \"Wondrous Item\", att = true }, [\"Helm of Comprehending Languages\"] = { ko = \"언어 이해의 투구\", r = \"B\", cat = \"Wondrous Item\" }, [\"Helm of Telepathy\"] = { ko = \"정신감응 투구\", r = \"B\", cat = \"Wondrous Item\", att = true }, [\"Helm of Teleportation\"] = { ko = \"순간이동 투구\", r = \"A\", cat = \"Wondrous Item\", att = true }, [\"Holy Avenger\"] = { ko = \"성스러운 복수자\", base = \"any_weapon\", plus = 3, pw = {{ dice = \"2d10\", type = \"Radiant\", vs = {\"Fiend\", \"Undead\"}, k = \"dmg\" }}, r = \"L\", cat = \"Weapon\", att = true, by = {\"Paladin\"} }, [\"Horn of Blasting\"] = { ko = \"폭음의 뿔피리\", r = \"A\", cat = \"Wondrous Item\" }, [\"Horn of Valhalla\"] = { ko = \"발할라의 뿔피리\", r = {\"A\", \"S\", \"L\"}, cat = \"Wondrous Item\" }, [\"Horseshoes of a Zephyr\"] = { ko = \"산들바람 편자\", r = \"S\", cat = \"Wondrous Item\" }, [\"Horseshoes of Speed\"] = { ko = \"신속의 편자\", r = \"A\", cat = \"Wondrous Item\" }, [\"Immovable Rod\"] = { ko = \"움직이지 않는 막대\", r = \"B\", cat = \"Rod\" }, [\"Instant Fortress\"] = { ko = \"즉석 요새\", r = \"A\", cat = \"Wondrous Item\", att = true }, [\"Ioun Stone\"] = { ko = \"아이운 돌\", var = { Absorption = { r = \"S\" }, Agility = { r = \"S\", pw = {{ ab = \"Dexterity\", n = 2, max = 20, k = \"add\" }} }, Awareness = { r = \"A\", pw = {{ t = \"Advantage on Initiative and Wisdom (Perception) checks\", k = \"tell\" }} }, Fortitude = { r = \"S\", pw = {{ ab = \"Constitution\", n = 2, max = 20, k = \"add\" }} }, [\"Greater Absorption\"] = { r = \"L\" }, Insight = { r = \"S\", pw = {{ ab = \"Wisdom\", n = 2, max = 20, k = \"add\" }} }, Intellect = { r = \"S\", pw = {{ ab = \"Intelligence\", n = 2, max = 20, k = \"add\" }} }, Leadership = { r = \"S\", pw = {{ ab = \"Charisma\", n = 2, max = 20, k = \"add\" }} }, Mastery = { r = \"L\", pw = {{ n = 1, k = \"pb\" }} }, Protection = { r = \"A\", pw = {{ n = 1, k = \"ac\" }} }, Regeneration = { r = \"L\" }, Reserve = { r = \"A\" }, Strength = { r = \"S\", pw = {{ ab = \"Strength\", n = 2, max = 20, k = \"add\" }} }, Sustenance = { r = \"A\" } }, cat = \"Wondrous Item\", att = true }, [\"Iron Bands\"] = { ko = \"쇠 띠\", r = \"A\", cat = \"Wondrous Item\" }, [\"Iron Flask\"] = { ko = \"쇠 플라스크\", r = \"L\", cat = \"Wondrous Item\" }, [\"Javelin of Lightning\"] = { ko = \"번개 자벨린\", base = \"Javelin\", pw = {{ t = \"thrown within 120 ft as a 5-ft Line instead of an attack: DC 13 Dexterity save, 4d6 Lightning, half on a success (+2d6 to the target if hit), once per dawn\", k = \"tell\" }}, r = \"B\", cat = \"Weapon\" }, [\"Lantern of Revealing\"] = { ko = \"드러냄의 랜턴\", r = \"B\", cat = \"Wondrous Item\" }, [\"Luck Blade\"] = { ko = \"행운의 검\", base = {\"Glaive\", \"Greatsword\", \"Longsword\", \"Rapier\", \"Scimitar\", \"Sickle\", \"Shortsword\"}, plus = 1, pw = {{ n = 1, k = \"save\" }}, ch = { max = \"1d3\", regain = 0 }, sp = {{ s = \"Wish\", c = 1 }}, r = \"L\", cat = \"Weapon\", att = true }, [\"Mace of Disruption\"] = { ko = \"붕괴의 메이스\", base = \"Mace\", pw = {{ dice = \"2d6\", type = \"Radiant\", vs = {\"Fiend\", \"Undead\"}, k = \"dmg\" }}, r = \"A\", cat = \"Weapon\", att = true }, [\"Mace of Smiting\"] = { ko = \"강타의 메이스\", base = \"Mace\", plus = 1, pw = {{ dice = \"7\", type = \"Bludgeoning\", nat20 = true, k = \"dmg\" }}, r = \"A\", cat = \"Weapon\" }, [\"Mace of Terror\"] = { ko = \"공포의 메이스\", base = \"Mace\", ch = { max = 3, regain = \"1d3\" }, pw = {{ t = \"1 charge, a Magic action: creatures of your choice within 30 ft make a DC 15 Wisdom save or are Frightened for 1 minute\", k = \"tell\" }}, r = \"A\", cat = \"Weapon\", att = true }, [\"Mantle of Spell Resistance\"] = { ko = \"주문 저항의 망토\", pw = {{ t = \"Advantage on saves against spells\", k = \"tell\" }}, r = \"A\", cat = \"Wondrous Item\", att = true }, [\"Manual of Bodily Health\"] = { ko = \"신체 건강 교본\", use = { perm = \"Constitution\" }, r = \"S\", cat = \"Wondrous Item\" }, [\"Manual of Gainful Exercise\"] = { ko = \"유익한 운동 교본\", use = { perm = \"Strength\" }, r = \"S\", cat = \"Wondrous Item\" }, [\"Manual of Golems\"] = { ko = \"골렘 교본\", r = \"S\", cat = \"Wondrous Item\" }, [\"Manual of Quickness of Action\"] = { ko = \"민첩한 동작 교본\", use = { perm = \"Dexterity\" }, r = \"S\", cat = \"Wondrous Item\" }, [\"Marvelous Pigments\"] = { ko = \"경이로운 물감\", r = \"S\", cat = \"Wondrous Item\" }, [\"Medallion of Thoughts\"] = { ko = \"생각의 메달\", r = \"B\", cat = \"Wondrous Item\", att = true }, [\"Mirror of Life Trapping\"] = { ko = \"생명 가두는 거울\", r = \"S\", cat = \"Wondrous Item\" }, [\"Mithral Armor\"] = { ko = \"미스릴 갑옷\", base = \"medium_heavy_nohide\", pw = {{ k = \"mithral\" }}, r = \"B\", cat = \"Armor\" }, [\"Mysterious Deck\"] = { ko = \"수수께끼의 카드\", r = \"L\", cat = \"Wondrous Item\" }, [\"Necklace of Adaptation\"] = { ko = \"적응의 목걸이\", r = \"B\", cat = \"Wondrous Item\", att = true }, [\"Necklace of Fireballs\"] = { ko = \"화염구 목걸이\", ch = { max = \"1d6+3\", regain = 0 }, sp = {{ s = \"Fireball\", c = 1, dc = 15, up = 9 }}, r = \"A\", cat = \"Wondrous Item\" }, [\"Necklace of Prayer Beads\"] = { ko = \"기도 염주 목걸이\", r = \"A\", cat = \"Wondrous Item\", att = true, by = {\"Cleric\", \"Druid\", \"Paladin\"} }, [\"Nine Lives Stealer\"] = { ko = \"아홉 목숨 도둑\", base = \"any_weapon\", plus = 2, r = \"S\", cat = \"Weapon\", att = true }, Oathbow = { ko = \"맹세의 활\", base = {\"Longbow\", \"Shortbow\"}, pw = {{ dice = \"3d6\", type = \"Piercing\", may = true, vs = {\"sworn enemy\"}, k = \"dmg\" }}, r = \"S\", cat = \"Weapon\", att = true }, [\"Oil of Etherealness\"] = { ko = \"에테르화 기름\", use = { narr = \"Etherealness for 1 hour\" }, r = \"A\", cat = \"Potion\" }, [\"Oil of Sharpness\"] = { ko = \"예리함의 기름\", use = { sharp = 3 }, r = \"S\", cat = \"Potion\" }, [\"Oil of Slipperiness\"] = { ko = \"미끄러움의 기름\", use = { cimm = {\"Paralyzed\", \"Restrained\"}, mins = 480 }, r = \"B\", cat = \"Potion\" }, [\"Pearl of Power\"] = { ko = \"힘의 진주\", use = { slot = 3, day = 1 }, r = \"B\", cat = \"Wondrous Item\", att = true, by = {\"Spellcaster\"} }, [\"Periapt of Health\"] = { ko = \"건강의 펜던트\", use = { heal = \"2d4+2\", day = 1 }, pw = {{ t = \"Advantage on saves to avoid or end Poisoned\", k = \"tell\" }}, r = \"B\", cat = \"Wondrous Item\", att = true }, [\"Periapt of Proof against Poison\"] = { ko = \"독 방지 펜던트\", pw = {{ type = \"Poison\", k = \"imm\" }, { cond = \"Poisoned\", k = \"cimm\" }}, r = \"A\", cat = \"Wondrous Item\", att = true }, [\"Periapt of Wound Closure\"] = { ko = \"상처 봉합 펜던트\", pw = {{ k = \"deathsave\" }}, r = \"B\", cat = \"Wondrous Item\", att = true }, [\"Philter of Love\"] = { ko = \"사랑의 묘약\", use = { narr = \"Charmed by the next creature seen within 10 minutes, for 1 hour\" }, r = \"B\", cat = \"Potion\" }, [\"Pipes of Haunting\"] = { ko = \"유령 피리\", r = \"B\", cat = \"Wondrous Item\" }, [\"Pipes of the Sewers\"] = { ko = \"하수도 피리\", r = \"B\", cat = \"Wondrous Item\", att = true }, [\"Plate Armor of Etherealness\"] = { ko = \"에테르화 판금 갑옷\", base = {\"Plate Armor\", \"Half Plate Armor\"}, r = \"L\", cat = \"Armor\", att = true }, [\"Portable Hole\"] = { ko = \"휴대용 구멍\", r = \"A\", cat = \"Wondrous Item\" }, [\"Potion of Animal Friendship\"] = { ko = \"동물 친화 물약\", use = { narr = \"Animal Friendship (level 3 version, DC 13)\" }, r = \"B\", cat = \"Potion\" }, [\"Potion of Clairvoyance\"] = { ko = \"투시 물약\", use = { narr = \"Clairvoyance, no Concentration\" }, r = \"A\", cat = \"Potion\" }, [\"Potion of Climbing\"] = { ko = \"등반 물약\", use = { narr = \"Climb Speed equal to Speed and Advantage on climbing checks, 1 hour\", mins = 60 }, r = \"C\", cat = \"Potion\" }, [\"Potion of Diminution\"] = { ko = \"축소 물약\", use = { narr = \"Reduce (Enlarge/Reduce) for 1d4 hours\" }, r = \"A\", cat = \"Potion\" }, [\"Potion of Flying\"] = { ko = \"비행 물약\", use = { narr = \"Fly Speed equal to Speed, hover, 1 hour\", mins = 60 }, r = \"S\", cat = \"Potion\" }, [\"Potion of Gaseous Form\"] = { ko = \"기체 형태 물약\", use = { narr = \"Gaseous Form for 1 hour, no Concentration\", mins = 60 }, r = \"A\", cat = \"Potion\" }, [\"Potion of Giant Strength\"] = { ko = \"거인의 힘 물약\", var = { Hill = { r = \"B\", n = 21 }, Frost = { r = \"A\", n = 23 }, Stone = { r = \"A\", n = 23 }, Fire = { r = \"A\", n = 25 }, Cloud = { r = \"S\", n = 27 }, Storm = { r = \"L\", n = 29 } }, use = { set = \"Strength\", n = \"var\", mins = 60 }, cat = \"Potion\" }, [\"Potion of Growth\"] = { ko = \"성장 물약\", use = { narr = \"Enlarge for 10 minutes\", mins = 10 }, r = \"B\", cat = \"Potion\" }, [\"Potions of Healing\"] = { ko = \"치유의 물약\", cat = \"Potion\" }, [\"Potion of Heroism\"] = { ko = \"영웅심 물약\", use = { thp = 10, bless = 60 }, r = \"A\", cat = \"Potion\" }, [\"Potion of Invisibility\"] = { ko = \"투명화 물약\", use = { narr = \"Invisible for 1 hour, ends on an attack, damage or a spell\", mins = 60 }, r = \"A\", cat = \"Potion\" }, [\"Potion of Invulnerability\"] = { ko = \"무적 물약\", use = { resist = \"all\", mins = 1 }, r = \"A\", cat = \"Potion\" }, [\"Potion of Longevity\"] = { ko = \"장수 물약\", use = { narr = \"physical age 1d6 + 6 years younger\" }, r = \"S\", cat = \"Potion\" }, [\"Potion of Mind Reading\"] = { ko = \"독심 물약\", use = { narr = \"Detect Thoughts (DC 13) for 10 minutes, no Concentration\", mins = 10 }, r = \"A\", cat = \"Potion\" }, [\"Potion of Poison\"] = { ko = \"독 물약\", use = { narr = \"4d6 Poison and a DC 13 Constitution save or Poisoned 1 hour (a HAZARD on the drinker)\" }, r = \"B\", cat = \"Potion\" }, [\"Potion of Resistance\"] = { ko = \"저항 물약\", var = { Acid = \"B\", Cold = \"B\", Fire = \"B\", Force = \"B\", Lightning = \"B\", Necrotic = \"B\", Poison = \"B\", Psychic = \"B\", Radiant = \"B\", Thunder = \"B\" }, use = { resist = \"var\", mins = 60 }, r = \"B\", cat = \"Potion\" }, [\"Potion of Speed\"] = { ko = \"신속 물약\", use = { haste = 1 }, r = \"S\", cat = \"Potion\" }, [\"Potion of Vitality\"] = { ko = \"활력 물약\", use = { exh0 = true, uncond = {\"Poisoned\"} }, r = \"S\", cat = \"Potion\" }, [\"Potion of Water Breathing\"] = { ko = \"수중 호흡 물약\", use = { narr = \"breathe underwater for 24 hours\", mins = 1440 }, r = \"B\", cat = \"Potion\" }, [\"Quarterstaff of the Acrobat\"] = { ko = \"곡예사의 쿼터스태프\", base = \"Quarterstaff\", plus = 2, r = \"S\", cat = \"Weapon\", att = true }, [\"Ring of Animal Influence\"] = { ko = \"동물 감화 반지\", ch = { max = 3, regain = \"1d3\" }, sp = {{ s = \"Animal Friendship\", c = 1, dc = 13 }, { s = \"Fear\", c = 1, dc = 13 }, { s = \"Speak with Animals\", c = 1, dc = 13 }}, r = \"A\", cat = \"Ring\" }, [\"Ring of Djinni Summoning\"] = { ko = \"진 소환 반지\", r = \"L\", cat = \"Ring\", att = true }, [\"Ring of Elemental Command\"] = { ko = \"원소 지배 반지\", r = \"L\", cat = \"Ring\", att = true }, [\"Ring of Evasion\"] = { ko = \"회피의 반지\", r = \"A\", cat = \"Ring\", att = true }, [\"Ring of Feather Falling\"] = { ko = \"깃털 낙하 반지\", r = \"A\", cat = \"Ring\", att = true }, [\"Ring of Free Action\"] = { ko = \"자유 행동 반지\", pw = {{ cond = \"Paralyzed\", k = \"cimm\" }, { cond = \"Restrained\", k = \"cimm\" }}, r = \"A\", cat = \"Ring\", att = true }, [\"Ring of Invisibility\"] = { ko = \"투명화 반지\", r = \"L\", cat = \"Ring\", att = true }, [\"Ring of Jumping\"] = { ko = \"도약의 반지\", sp = {{ s = \"Jump\", c = 0 }}, r = \"B\", cat = \"Ring\", att = true }, [\"Ring of Mind Shielding\"] = { ko = \"정신 보호 반지\", r = \"B\", cat = \"Ring\", att = true }, [\"Ring of Protection\"] = { ko = \"보호의 반지\", pw = {{ n = 1, k = \"ac\" }, { n = 1, k = \"save\" }}, r = \"A\", cat = \"Ring\", att = true }, [\"Ring of Regeneration\"] = { ko = \"재생의 반지\", r = \"S\", cat = \"Ring\", att = true }, [\"Ring of Resistance\"] = { ko = \"저항의 반지\", var = { Acid = \"A\", Cold = \"A\", Fire = \"A\", Force = \"A\", Lightning = \"A\", Necrotic = \"A\", Poison = \"A\", Psychic = \"A\", Radiant = \"A\", Thunder = \"A\" }, pw = {{ type = \"var\", k = \"resist\" }}, r = \"A\", cat = \"Ring\" }, [\"Ring of Shooting Stars\"] = { ko = \"유성의 반지\", r = \"S\", cat = \"Ring\", att = true }, [\"Ring of Spell Storing\"] = { ko = \"주문 저장 반지\", r = \"A\", cat = \"Ring\", att = true }, [\"Ring of Spell Turning\"] = { ko = \"주문 되돌림 반지\", r = \"L\", cat = \"Ring\", att = true }, [\"Ring of Swimming\"] = { ko = \"헤엄의 반지\", r = \"B\", cat = \"Ring\" }, [\"Ring of Telekinesis\"] = { ko = \"염동력 반지\", sp = {{ s = \"Telekinesis\", c = 0 }}, r = \"S\", cat = \"Ring\", att = true }, [\"Ring of the Ram\"] = { ko = \"숫양의 반지\", r = \"A\", cat = \"Ring\", att = true }, [\"Ring of Three Wishes\"] = { ko = \"세 가지 소원 반지\", ch = { max = 3, regain = 0 }, sp = {{ s = \"Wish\", c = 1 }}, r = \"L\", cat = \"Ring\" }, [\"Ring of Warmth\"] = { ko = \"온기의 반지\", r = \"B\", cat = \"Ring\", att = true }, [\"Ring of Water Walking\"] = { ko = \"수면 보행 반지\", sp = {{ s = \"Water Walk\", c = 0 }}, r = \"B\", cat = \"Ring\" }, [\"Ring of X-ray Vision\"] = { ko = \"투시 시야 반지\", r = \"A\", cat = \"Ring\", att = true }, [\"Robe of Eyes\"] = { ko = \"눈의 로브\", r = \"A\", cat = \"Wondrous Item\", att = true }, [\"Robe of Scintillating Colors\"] = { ko = \"현란한 빛깔의 로브\", r = \"S\", cat = \"Wondrous Item\", att = true }, [\"Robe of Stars\"] = { ko = \"별의 로브\", pw = {{ n = 1, k = \"save\" }}, ch = { max = 6, regain = \"1d6\" }, sp = {{ s = \"Magic Missile\", c = 1, lvl = 5 }}, r = \"S\", cat = \"Wondrous Item\", att = true }, [\"Robe of the Archmagi\"] = { ko = \"대마법사의 로브\", pw = {{ n = 15, k = \"acbase\" }, { n = 2, k = \"spelldc\" }, { n = 2, k = \"spellatk\" }, { t = \"Advantage on saves against spells and magical effects\", k = \"tell\" }}, r = \"L\", cat = \"Wondrous Item\", att = true, by = {\"Sorcerer\", \"Warlock\", \"Wizard\"} }, [\"Robe of Useful Items\"] = { ko = \"쓸모 있는 물건 로브\", r = \"B\", cat = \"Wondrous Item\" }, [\"Rod of Absorption\"] = { ko = \"흡수의 막대\", r = \"S\", cat = \"Rod\", att = true }, [\"Rod of Alertness\"] = { ko = \"경계의 막대\", r = \"S\", cat = \"Rod\", att = true }, [\"Rod of Lordly Might\"] = { ko = \"군주의 위력 막대\", base = \"Mace\", plus = 3, r = \"L\", cat = \"Rod\", att = true }, [\"Rod of Resurrection\"] = { ko = \"부활의 막대\", ch = { max = 5, regain = \"1\", last = true }, sp = {{ s = \"Heal\", c = 1 }, { s = \"Resurrection\", c = 5 }}, r = \"L\", cat = \"Rod\", att = true }, [\"Rod of Rulership\"] = { ko = \"통치의 막대\", r = \"A\", cat = \"Rod\", att = true }, [\"Rod of Security\"] = { ko = \"안전의 막대\", r = \"S\", cat = \"Rod\" }, [\"Rope of Climbing\"] = { ko = \"등반 밧줄\", r = \"B\", cat = \"Wondrous Item\" }, [\"Rope of Entanglement\"] = { ko = \"휘감는 밧줄\", r = \"A\", cat = \"Wondrous Item\" }, [\"Scarab of Protection\"] = { ko = \"보호의 스카라브\", pw = {{ n = 1, k = \"ac\" }, { t = \"Advantage on saves against spells; 12 charges: a Reaction turns a failed save against Necromancy or an Undead into a success\", k = \"tell\" }}, r = \"L\", cat = \"Wondrous Item\", att = true }, [\"Scimitar of Speed\"] = { ko = \"신속의 시미터\", base = \"Scimitar\", plus = 2, pw = {{ k = \"bonusattack\" }}, r = \"S\", cat = \"Weapon\", att = true }, [\"Sending Stones\"] = { ko = \"전언의 돌\", r = \"B\", cat = \"Wondrous Item\" }, [\"Sentinel Shield\"] = { ko = \"파수꾼 방패\", base = \"Shield\", pw = {{ t = \"Advantage on Initiative and Wisdom (Perception) checks\", k = \"tell\" }}, r = \"B\", cat = \"Armor\" }, [\"Shield, +1, +2, or +3\"] = { ko = \"+1·+2·+3 방패\", base = \"Shield\", r = {\"B\", \"A\", \"S\"}, cat = \"Armor\" }, [\"Shield of Missile Attraction\"] = { ko = \"투사체 끄는 방패\", base = \"Shield\", pw = {{ t = \"Resistance to damage from Ranged weapon attacks; cursed: ranged attacks at anyone within 10 ft target you\", k = \"tell\" }}, r = \"A\", cat = \"Armor\", att = true }, [\"Shield of the Cavalier\"] = { ko = \"기사의 방패\", base = \"Shield\", pw = {{ n = 2, k = \"ac\" }}, r = \"S\", cat = \"Armor\", att = true }, [\"Slippers of Spider Climbing\"] = { ko = \"거미 걸음 신발\", r = \"B\", cat = \"Wondrous Item\", att = true }, [\"Sovereign Glue\"] = { ko = \"만능 접착제\", r = \"L\", cat = \"Wondrous Item\" }, [\"Spellguard Shield\"] = { ko = \"주문 방어 방패\", base = \"Shield\", pw = {{ t = \"Advantage on saves against spells and magical effects; spell attack rolls against you have Disadvantage\", k = \"tell\" }}, r = \"S\", cat = \"Armor\", att = true }, [\"Spell Scroll\"] = { ko = \"주문 두루마리\", cat = \"Scroll\" }, [\"Sphere of Annihilation\"] = { ko = \"소멸의 구체\", r = \"L\", cat = \"Wondrous Item\" }, [\"Staff of Charming\"] = { ko = \"매혹의 지팡이\", ch = { max = 10, regain = \"1d8+2\", last = true }, sp = {{ s = \"Charm Person\", c = 1 }, { s = \"Command\", c = 1 }, { s = \"Comprehend Languages\", c = 1 }}, r = \"A\", cat = \"Staff\", att = true, by = {\"Bard\", \"Cleric\", \"Druid\", \"Sorcerer\", \"Warlock\", \"Wizard\"} }, [\"Staff of Fire\"] = { ko = \"화염의 지팡이\", pw = {{ type = \"Fire\", k = \"resist\" }}, ch = { max = 10, regain = \"1d6+4\", last = true }, sp = {{ s = \"Burning Hands\", c = 1 }, { s = \"Fireball\", c = 3 }, { s = \"Wall of Fire\", c = 4 }}, r = \"S\", cat = \"Staff\", att = true, by = {\"Druid\", \"Sorcerer\", \"Warlock\", \"Wizard\"} }, [\"Staff of Frost\"] = { ko = \"서리의 지팡이\", pw = {{ type = \"Cold\", k = \"resist\" }}, ch = { max = 10, regain = \"1d6+4\", last = true }, sp = {{ s = \"Fog Cloud\", c = 1 }, { s = \"Ice Storm\", c = 4 }, { s = \"Wall of Ice\", c = 4 }, { s = \"Cone of Cold\", c = 5 }}, r = \"S\", cat = \"Staff\", att = true, by = {\"Druid\", \"Sorcerer\", \"Warlock\", \"Wizard\"} }, [\"Staff of Healing\"] = { ko = \"치유의 지팡이\", ch = { max = 10, regain = \"1d6+4\", last = true }, sp = {{ s = \"Cure Wounds\", c = 1, up = 4 }, { s = \"Lesser Restoration\", c = 2 }, { s = \"Mass Cure Wounds\", c = 5 }}, r = \"A\", cat = \"Staff\", att = true, by = {\"Bard\", \"Cleric\", \"Druid\"} }, [\"Staff of Power\"] = { ko = \"권능의 지팡이\", base = \"Quarterstaff\", plus = 2, pw = {{ n = 2, k = \"ac\" }, { n = 2, k = \"save\" }, { n = 2, k = \"spellatk\" }}, ch = { max = 20, regain = \"2d8+4\", last = true }, sp = {{ s = \"Magic Missile\", c = 1 }, { s = \"Ray of Enfeeblement\", c = 1 }, { s = \"Levitate\", c = 2 }, { s = \"Cone of Cold\", c = 5 }, { s = \"Fireball\", c = 5, lvl = 5 }, { s = \"Hold Monster\", c = 5 }, { s = \"Lightning Bolt\", c = 5, lvl = 5 }, { s = \"Wall of Force\", c = 5 }, { s = \"Globe of Invulnerability\", c = 6 }}, r = \"S\", cat = \"Staff\", att = true, by = {\"Sorcerer\", \"Warlock\", \"Wizard\"} }, [\"Staff of Striking\"] = { ko = \"타격의 지팡이\", base = \"Quarterstaff\", plus = 3, ch = { max = 10, regain = \"1d6+4\", last = true }, pw = {{ t = \"on a melee hit up to 3 charges: +1d6 Force each (write USE of the charges, then add the dice)\", k = \"tell\" }}, r = \"S\", cat = \"Staff\", att = true }, [\"Staff of Swarming Insects\"] = { ko = \"벌레 떼의 지팡이\", ch = { max = 10, regain = \"1d6+4\", last = true }, sp = {{ s = \"Giant Insect\", c = 4 }, { s = \"Insect Plague\", c = 5 }}, r = \"A\", cat = \"Staff\", att = true, by = {\"Bard\", \"Cleric\", \"Druid\", \"Sorcerer\", \"Warlock\", \"Wizard\"} }, [\"Staff of the Magi\"] = { ko = \"마도사의 지팡이\", base = \"Quarterstaff\", plus = 2, pw = {{ n = 2, k = \"spellatk\" }, { t = \"Advantage on saves against spells\", k = \"tell\" }}, ch = { max = 50, regain = \"4d6+2\", last = true }, sp = {{ s = \"Arcane Lock\", c = 0 }, { s = \"Detect Magic\", c = 0 }, { s = \"Enlarge/Reduce\", c = 0 }, { s = \"Light\", c = 0 }, { s = \"Mage Hand\", c = 0 }, { s = \"Protection from Evil and Good\", c = 0 }, { s = \"Flaming Sphere\", c = 2 }, { s = \"Invisibility\", c = 2 }, { s = \"Knock\", c = 2 }, { s = \"Web\", c = 2 }, { s = \"Dispel Magic\", c = 3 }, { s = \"Ice Storm\", c = 4 }, { s = \"Wall of Fire\", c = 4 }, { s = \"Passwall\", c = 5 }, { s = \"Telekinesis\", c = 5 }, { s = \"Conjure Elemental\", c = 7 }, { s = \"Fireball\", c = 7, lvl = 7 }, { s = \"Lightning Bolt\", c = 7, lvl = 7 }, { s = \"Plane Shift\", c = 7 }}, r = \"L\", cat = \"Staff\", att = true, by = {\"Sorcerer\", \"Warlock\", \"Wizard\"} }, [\"Staff of the Python\"] = { ko = \"비단뱀의 지팡이\", r = \"B\", cat = \"Staff\", att = true }, [\"Staff of the Woodlands\"] = { ko = \"숲의 지팡이\", base = \"Quarterstaff\", plus = 2, pw = {{ n = 2, k = \"spellatk\" }}, ch = { max = 6, regain = \"1d6\", last = true }, sp = {{ s = \"Animal Friendship\", c = 1 }, { s = \"Speak with Animals\", c = 1 }, { s = \"Barkskin\", c = 2 }, { s = \"Locate Animals or Plants\", c = 2 }, { s = \"Pass without Trace\", c = 2 }, { s = \"Speak with Plants\", c = 3 }, { s = \"Awaken\", c = 5 }, { s = \"Wall of Thorns\", c = 6 }}, r = \"A\", cat = \"Staff\", att = true, by = {\"Druid\"} }, [\"Staff of Thunder and Lightning\"] = { ko = \"천둥 번개의 지팡이\", base = \"Quarterstaff\", plus = 2, pw = {{ t = \"once per dawn each: a melee hit +2d6 Lightning; a hit, DC 17 Constitution save or Stunned; Lightning Strike, Thunderclap, Thunder and Lightning\", k = \"tell\" }}, r = \"S\", cat = \"Staff\", att = true }, [\"Staff of Withering\"] = { ko = \"시듦의 지팡이\", base = \"Quarterstaff\", ch = { max = 3, regain = \"1d3\" }, pw = {{ t = \"on a hit, 1 charge: +2d10 Necrotic and a DC 15 Constitution save or Disadvantage on Strength and Constitution checks and saves for 1 hour\", k = \"tell\" }}, r = \"A\", cat = \"Staff\", att = true }, [\"Stone of Controlling Earth Elementals\"] = { ko = \"대지 원소 조종의 돌\", r = \"A\", cat = \"Wondrous Item\" }, [\"Stone of Good Luck (Luckstone)\"] = { ko = \"행운의 돌\", pw = {{ n = 1, k = \"check\" }, { n = 1, k = \"save\" }}, r = \"B\", cat = \"Wondrous Item\", att = true }, [\"Sun Blade\"] = { ko = \"태양의 검\", base = \"Longsword\", plus = 2, pw = {{ type = \"Radiant\", k = \"dtype\" }, { dice = \"1d8\", type = \"Radiant\", vs = {\"Undead\"}, k = \"dmg\" }}, r = \"A\", cat = \"Weapon\", att = true }, [\"Sword of Life Stealing\"] = { ko = \"생명 강탈의 검\", base = {\"Glaive\", \"Greatsword\", \"Longsword\", \"Rapier\", \"Scimitar\", \"Shortsword\"}, pw = {{ dice = \"15\", type = \"Necrotic\", nat20 = true, k = \"dmg\" }}, r = \"A\", cat = \"Weapon\", att = true }, [\"Sword of Sharpness\"] = { ko = \"예리함의 검\", base = {\"Glaive\", \"Greatsword\", \"Longsword\", \"Scimitar\"}, pw = {{ dice = \"14\", type = \"Slashing\", nat20 = true, k = \"dmg\" }}, r = \"S\", cat = \"Weapon\", att = true }, [\"Sword of Wounding\"] = { ko = \"상처의 검\", base = {\"Glaive\", \"Greatsword\", \"Longsword\", \"Rapier\", \"Scimitar\", \"Shortsword\"}, pw = {{ dice = \"2d6\", type = \"Necrotic\", k = \"dmg\" }}, r = \"A\", cat = \"Weapon\", att = true }, [\"Talisman of Pure Good\"] = { ko = \"순수한 선의 부적\", r = \"L\", cat = \"Wondrous Item\", att = true, by = {\"Cleric\", \"Paladin\"} }, [\"Talisman of the Sphere\"] = { ko = \"구체의 부적\", r = \"L\", cat = \"Wondrous Item\", att = true }, [\"Talisman of Ultimate Evil\"] = { ko = \"궁극의 악의 부적\", r = \"L\", cat = \"Wondrous Item\", att = true }, [\"Thunderous Greatclub\"] = { ko = \"천둥의 그레이트클럽\", base = \"Greatclub\", pw = {{ ab = \"Strength\", n = 20, k = \"set\" }, { dice = \"1d8\", type = \"Thunder\", k = \"dmg\" }}, r = \"S\", cat = \"Weapon\", att = true }, [\"Tome of Clear Thought\"] = { ko = \"명석한 사고의 책\", use = { perm = \"Intelligence\" }, r = \"S\", cat = \"Wondrous Item\" }, [\"Tome of Leadership and Influence\"] = { ko = \"지도력과 영향력의 책\", use = { perm = \"Charisma\" }, r = \"S\", cat = \"Wondrous Item\" }, [\"Tome of Understanding\"] = { ko = \"이해의 책\", use = { perm = \"Wisdom\" }, r = \"S\", cat = \"Wondrous Item\" }, [\"Trident of Fish Command\"] = { ko = \"물고기 지배의 트라이던트\", base = \"Trident\", ch = { max = 3, regain = \"1d3\" }, sp = {{ s = \"Dominate Beast\", c = 1, dc = 15 }}, r = \"B\", cat = \"Weapon\", att = true }, [\"Universal Solvent\"] = { ko = \"만능 용해제\", r = \"L\", cat = \"Wondrous Item\" }, [\"Vicious Weapon\"] = { ko = \"잔혹한 무기\", base = \"any_weapon\", pw = {{ dice = \"2d6\", type = \"weapon\", k = \"dmg\" }}, r = \"A\", cat = \"Weapon\" }, [\"Vorpal Sword\"] = { ko = \"보팔 검\", base = {\"Glaive\", \"Greatsword\", \"Longsword\", \"Scimitar\"}, plus = 3, r = \"L\", cat = \"Weapon\", att = true }, [\"Wand of Binding\"] = { ko = \"속박의 완드\", ch = { max = 7, regain = \"1d6+1\", last = true }, sp = {{ s = \"Hold Person\", c = 2, dc = 17 }, { s = \"Hold Monster\", c = 5, dc = 17 }}, r = \"A\", cat = \"Wand\", att = true }, [\"Wand of Enemy Detection\"] = { ko = \"적 탐지 완드\", r = \"A\", cat = \"Wand\", att = true }, [\"Wand of Fear\"] = { ko = \"공포의 완드\", ch = { max = 7, regain = \"1d6+1\", last = true }, sp = {{ s = \"Command\", c = 1, dc = 15 }, { s = \"Fear\", c = 3, dc = 15 }}, r = \"A\", cat = \"Wand\", att = true }, [\"Wand of Fireballs\"] = { ko = \"화염구 완드\", ch = { max = 7, regain = \"1d6+1\", last = true }, sp = {{ s = \"Fireball\", c = 1, dc = 15, up = 3 }}, r = \"A\", cat = \"Wand\", att = true, by = {\"Spellcaster\"} }, [\"Wand of Lightning Bolts\"] = { ko = \"번개 완드\", ch = { max = 7, regain = \"1d6+1\", last = true }, sp = {{ s = \"Lightning Bolt\", c = 1, dc = 15, up = 3 }}, r = \"A\", cat = \"Wand\", att = true, by = {\"Spellcaster\"} }, [\"Wand of Magic Detection\"] = { ko = \"마법 탐지 완드\", ch = { max = 3, regain = \"1d3\" }, sp = {{ s = \"Detect Magic\", c = 1 }}, r = \"B\", cat = \"Wand\" }, [\"Wand of Magic Missiles\"] = { ko = \"마법 화살 완드\", ch = { max = 7, regain = \"1d6+1\", last = true }, sp = {{ s = \"Magic Missile\", c = 1, up = 3 }}, r = \"B\", cat = \"Wand\" }, [\"Wand of Paralysis\"] = { ko = \"마비의 완드\", ch = { max = 7, regain = \"1d6+1\", last = true }, pw = {{ t = \"1 charge, a Magic action: a creature within 60 ft makes a DC 15 Constitution save or is Paralyzed 1 minute (repeats at the end of its turns)\", k = \"tell\" }}, r = \"A\", cat = \"Wand\", att = true, by = {\"Spellcaster\"} }, [\"Wand of Polymorph\"] = { ko = \"변신 완드\", ch = { max = 7, regain = \"1d6+1\", last = true }, sp = {{ s = \"Polymorph\", c = 1, dc = 15 }}, r = \"S\", cat = \"Wand\", att = true, by = {\"Spellcaster\"} }, [\"Wand of Secrets\"] = { ko = \"비밀의 완드\", r = \"B\", cat = \"Wand\" }, [\"Wand of the War Mage, +1, +2, or +3\"] = { ko = \"전투 마법사의 완드\", var = { [\"+1\"] = { r = \"B\", n = 1 }, [\"+2\"] = { r = \"A\", n = 2 }, [\"+3\"] = { r = \"S\", n = 3 } }, pw = {{ n = \"var\", k = \"spellatk\" }, { t = \"spell attacks ignore Half Cover\", k = \"tell\" }}, r = {\"B\", \"A\", \"S\"}, cat = \"Wand\", att = true, by = {\"Spellcaster\"} }, [\"Wand of Web\"] = { ko = \"거미줄 완드\", ch = { max = 7, regain = \"1d6+1\", last = true }, sp = {{ s = \"Web\", c = 1, dc = 13 }}, r = \"B\", cat = \"Wand\", att = true, by = {\"Spellcaster\"} }, [\"Wand of Wonder\"] = { ko = \"경이의 완드\", r = \"A\", cat = \"Wand\", att = true }, [\"Weapon, +1, +2, or +3\"] = { ko = \"+1·+2·+3 무기\", base = \"any_weapon\", r = {\"B\", \"A\", \"S\"}, cat = \"Weapon\" }, [\"Weapon of Warning\"] = { ko = \"경고의 무기\", base = \"any_weapon\", pw = {{ t = \"you and allies within 30 ft have Advantage on Initiative\", k = \"tell\" }}, r = \"B\", cat = \"Weapon\", att = true }, [\"Well of Many Worlds\"] = { ko = \"여러 세계의 우물\", r = \"L\", cat = \"Wondrous Item\" }, [\"Wind Fan\"] = { ko = \"바람 부채\", r = \"B\", cat = \"Wondrous Item\" }, [\"Winged Boots\"] = { ko = \"날개 달린 장화\", r = \"B\", cat = \"Wondrous Item\", att = true }, [\"Wings of Flying\"] = { ko = \"비행의 날개\", r = \"A\", cat = \"Wondrous Item\", att = true } }\r\n\r\nK.TOOLS = { [\"Alchemist's Supplies\"] = { ab = \"Intelligence\", ko = \"연금술 도구\", util = \"Identify a substance (DC 15), or start a fire (DC 15)\", util_ko = \"물질 알아내기(난이도 15), 불 피우기(15)\", craft = \"Acid, Alchemist's Fire, Component Pouch, Oil, Paper, Perfume\", makes = {\"Acid\", \"Alchemist's Fire\", \"Component Pouch\", \"Oil\", \"Paper\", \"Perfume\"}, cp = 5000, artisan = true }, [\"Brewer's Supplies\"] = { ab = \"Intelligence\", ko = \"양조 도구\", util = \"Detect poisoned drink (DC 15), or identify alcohol (DC 10)\", util_ko = \"독 든 술 알아채기(15), 술 알아보기(10)\", craft = \"Antitoxin\", makes = {\"Antitoxin\"}, cp = 2000, artisan = true }, [\"Calligrapher's Supplies\"] = { ab = \"Dexterity\", ko = \"서예가 도구\", util = \"Write text with impressive flourishes that guard against forgery (DC 15)\", util_ko = \"위조를 막는 화려한 글씨(15)\", craft = \"Ink, Spell Scroll\", makes = {\"Ink\", \"Spell Scroll\"}, cp = 1000, artisan = true }, [\"Carpenter's Tools\"] = { ab = \"Strength\", ko = \"목수 도구\", util = \"Seal or pry open a door or container (DC 20)\", util_ko = \"문이나 상자를 막거나 비틀어 열기(20)\", craft = \"Club, Greatclub, Quarterstaff, Barrel, Chest, Ladder, Pole, Portable Ram, Torch\", makes = {\"Club\", \"Greatclub\", \"Quarterstaff\", \"Barrel\", \"Chest\", \"Ladder\", \"Pole\", \"Portable Ram\", \"Torch\"}, cp = 800, artisan = true }, [\"Cartographer's Tools\"] = { ab = \"Wisdom\", ko = \"지도 제작 도구\", util = \"Draft a map of a small area (DC 15)\", util_ko = \"작은 지역의 지도 그리기(15)\", craft = \"Map\", makes = {\"Map\"}, cp = 1500, artisan = true }, [\"Cobbler's Tools\"] = { ab = \"Dexterity\", ko = \"구두장이 도구\", util = \"Modify footwear to give Advantage on the wearer's next Dexterity (Acrobatics) check (DC 10)\", util_ko = \"신발을 고쳐 다음 민첩(곡예) 판정에 이점(10)\", craft = \"Climber's Kit\", makes = {\"Climber's Kit\"}, cp = 500, artisan = true }, [\"Cook's Utensils\"] = { ab = \"Wisdom\", ko = \"요리 도구\", util = \"Improve food's flavor (DC 10), or detect spoiled or poisoned food (DC 15)\", util_ko = \"음식 맛 내기(10), 상하거나 독 든 음식 알아채기(15)\", craft = \"Rations\", makes = {\"Rations\"}, cp = 100, artisan = true }, [\"Glassblower's Tools\"] = { ab = \"Intelligence\", ko = \"유리 세공 도구\", util = \"Discern what a glass object held in the past 24 hours (DC 15)\", util_ko = \"유리 물건에 24시간 안에 무엇이 담겼는지 알기(15)\", craft = \"Glass Bottle, Magnifying Glass, Spyglass, Vial\", makes = {\"Glass Bottle\", \"Magnifying Glass\", \"Spyglass\", \"Vial\"}, cp = 3000, artisan = true }, [\"Jeweler's Tools\"] = { ab = \"Intelligence\", ko = \"보석 세공 도구\", util = \"Discern a gem's value (DC 15)\", util_ko = \"보석 값 알아보기(15)\", craft = \"Arcane Focus, Holy Symbol\", makes = {\"Arcane Focus\", \"Holy Symbol\"}, cp = 2500, artisan = true }, [\"Leatherworker's Tools\"] = { ab = \"Dexterity\", ko = \"가죽 세공 도구\", util = \"Add a design to a leather item (DC 10)\", util_ko = \"가죽 물건에 무늬 넣기(10)\", craft = \"Sling, Whip, Hide Armor, Leather Armor, Studded Leather Armor, Backpack, Crossbow Bolt Case, Map or Scroll Case, Parchment, Pouch, Quiver, Waterskin\", makes = {\"Sling\", \"Whip\", \"Hide Armor\", \"Leather Armor\", \"Studded Leather Armor\", \"Backpack\", \"Crossbow Bolt Case\", \"Map or Scroll Case\", \"Parchment\", \"Pouch\", \"Quiver\", \"Waterskin\"}, cp = 500, artisan = true }, [\"Mason's Tools\"] = { ab = \"Strength\", ko = \"석공 도구\", util = \"Chisel a symbol or hole in stone (DC 10)\", util_ko = \"돌에 표식이나 구멍 새기기(10)\", craft = \"Block and Tackle\", makes = {\"Block and Tackle\"}, cp = 1000, artisan = true }, [\"Painter's Supplies\"] = { ab = \"Wisdom\", ko = \"화가 도구\", util = \"Paint a recognizable image of something you've seen (DC 10)\", util_ko = \"본 것을 알아볼 수 있게 그리기(10)\", craft = \"Druidic Focus, Holy Symbol\", makes = {\"Druidic Focus\", \"Holy Symbol\"}, cp = 1000, artisan = true }, [\"Potter's Tools\"] = { ab = \"Intelligence\", ko = \"도공 도구\", util = \"Discern what a ceramic object held in the past 24 hours (DC 15)\", util_ko = \"도자기에 24시간 안에 무엇이 담겼는지 알기(15)\", craft = \"Jug, Lamp\", makes = {\"Jug\", \"Lamp\"}, cp = 1000, artisan = true }, [\"Smith's Tools\"] = { ab = \"Strength\", ko = \"대장장이 도구\", util = \"Pry open a door or container (DC 20)\", util_ko = \"문이나 상자를 비틀어 열기(20)\", craft = \"Any Melee weapon (except Club, Greatclub, Quarterstaff, and Whip), Medium armor (except Hide), Heavy armor, Ball Bearings, Bucket, Caltrops, Chain, Crowbar, Firearm Bullets, Grappling Hook, Iron Pot, Iron Spikes, Sling Bullets\", makes = {\"Dagger\", \"Handaxe\", \"Javelin\", \"Light Hammer\", \"Mace\", \"Sickle\", \"Spear\", \"Battleaxe\", \"Flail\", \"Glaive\", \"Greataxe\", \"Greatsword\", \"Halberd\", \"Lance\", \"Longsword\", \"Maul\", \"Morningstar\", \"Pike\", \"Rapier\", \"Scimitar\", \"Shortsword\", \"Trident\", \"Warhammer\", \"War Pick\", \"Chain Shirt\", \"Scale Mail\", \"Breastplate\", \"Half Plate Armor\", \"Ring Mail\", \"Chain Mail\", \"Splint Armor\", \"Plate Armor\", \"Ball Bearings\", \"Bucket\", \"Caltrops\", \"Chain\", \"Crowbar\", \"Firearm Bullets\", \"Grappling Hook\", \"Iron Pot\", \"Iron Spikes\", \"Sling Bullets\"}, cp = 2000, artisan = true }, [\"Tinker's Tools\"] = { ab = \"Dexterity\", ko = \"땜장이 도구\", util = \"Assemble a Tiny item composed of scrap, which falls apart in 1 minute (DC 20)\", util_ko = \"잡동사니로 1분 버티는 아주 작은 물건 만들기(20)\", craft = \"Musket, Pistol, Bell, Bullseye Lantern, Flask, Hooded Lantern, Hunting Trap, Lock, Manacles, Mirror, Shovel, Signal Whistle, Tinderbox\", makes = {\"Bell\", \"Bullseye Lantern\", \"Flask\", \"Hooded Lantern\", \"Hunting Trap\", \"Lock\", \"Manacles\", \"Mirror\", \"Shovel\", \"Signal Whistle\", \"Tinderbox\"}, cp = 5000, artisan = true }, [\"Weaver's Tools\"] = { ab = \"Dexterity\", ko = \"직조 도구\", util = \"Mend a tear in clothing (DC 10), or sew a Tiny design (DC 10)\", util_ko = \"찢어진 옷 깁기(10), 아주 작은 무늬 수놓기(10)\", craft = \"Padded Armor, Basket, Bedroll, Blanket, Fine Clothes, Net, Robe, Rope, Sack, String, Tent, Traveler's Clothes\", makes = {\"Padded Armor\", \"Basket\", \"Bedroll\", \"Blanket\", \"Fine Clothes\", \"Net\", \"Robe\", \"Rope\", \"Sack\", \"String\", \"Tent\", \"Traveler's Clothes\"}, cp = 100, artisan = true }, [\"Woodcarver's Tools\"] = { ab = \"Dexterity\", ko = \"목각 도구\", util = \"Carve a pattern in wood (DC 10)\", util_ko = \"나무에 무늬 새기기(10)\", craft = \"Club, Greatclub, Quarterstaff, Ranged weapons (except Pistol, Musket, and Sling), Arcane Focus, Arrows, Bolts, Druidic Focus, Ink Pen, Needles\", makes = {\"Club\", \"Greatclub\", \"Quarterstaff\", \"Dart\", \"Light Crossbow\", \"Shortbow\", \"Blowgun\", \"Hand Crossbow\", \"Heavy Crossbow\", \"Longbow\", \"Arcane Focus\", \"Arrows\", \"Bolts\", \"Druidic Focus\", \"Ink Pen\", \"Needles\"}, cp = 100, artisan = true }, [\"Disguise Kit\"] = { ab = \"Charisma\", ko = \"변장 키트\", util = \"Apply makeup (DC 10)\", util_ko = \"분장하기(10)\", craft = \"Costume\", makes = {\"Costume\"}, cp = 2500, artisan = false }, [\"Forgery Kit\"] = { ab = \"Dexterity\", ko = \"위조 키트\", util = \"Mimic 10 or fewer words of someone else's handwriting (DC 15), or duplicate a wax seal (DC 20)\", util_ko = \"남의 글씨 열 단어까지 흉내 내기(15), 밀랍 봉인 베끼기(20)\", cp = 1500, artisan = false }, [\"Gaming Set\"] = { ab = \"Wisdom\", ko = \"놀이 도구\", util = \"Discern whether someone is cheating (DC 10), or win the game (DC 20)\", util_ko = \"속임수 알아채기(10), 게임 이기기(20)\", variants = \"Dice (1 SP), dragonchess (1 GP), playing cards (5 SP), three-dragon ante (1 GP)\", artisan = false }, [\"Herbalism Kit\"] = { ab = \"Intelligence\", ko = \"약초학 키트\", util = \"Identify a plant (DC 10)\", util_ko = \"식물 알아보기(10)\", craft = \"Antitoxin, Candle, Healer's Kit, Potion of Healing\", makes = {\"Antitoxin\", \"Candle\", \"Healer's Kit\", \"Potion of Healing\"}, cp = 500, artisan = false }, [\"Musical Instrument\"] = { ab = \"Charisma\", ko = \"악기\", util = \"Play a known tune (DC 10), or improvise a song (DC 15)\", util_ko = \"아는 곡 연주(10), 즉흥곡(15)\", variants = \"Bagpipes (30 GP, 6 lb.), drum (6 GP, 3 lb.), dulcimer (25 GP, 10 lb.), flute (2 GP, 1 lb.), horn (3 GP, 2 lb.), lute (35 GP, 2 lb.), lyre (30 GP, 2 lb.), pan flute (12 GP, 2 lb.), shawm (2 GP, 1 lb.), viol (30 GP, 1 lb.)\", artisan = false }, [\"Navigator's Tools\"] = { ab = \"Wisdom\", ko = \"항해 도구\", util = \"Plot a course (DC 10), or determine position by stargazing (DC 15)\", util_ko = \"항로 잡기(10), 별을 보고 위치 알아내기(15)\", cp = 2500, artisan = false }, [\"Poisoner's Kit\"] = { ab = \"Intelligence\", ko = \"독 제조 키트\", util = \"Detect a poisoned object (DC 10)\", util_ko = \"독 묻은 물건 알아채기(10)\", craft = \"Basic Poison\", makes = {\"Basic Poison\"}, cp = 5000, artisan = false }, [\"Thieves' Tools\"] = { ab = \"Dexterity\", ko = \"도둑 도구\", util = \"Pick a lock (DC 15), or disarm a trap (DC 15)\", util_ko = \"자물쇠 따기(15), 함정 해체(15)\", cp = 2500, artisan = false } }\r\n\r\nlocal NAMES_KO = { Strength = \"근력\", Dexterity = \"민첩\", Constitution = \"건강\", Intelligence = \"지능\", Wisdom = \"지혜\", Charisma = \"매력\", Acrobatics = \"곡예\", [\"Animal Handling\"] = \"동물 조련\", Arcana = \"비전학\", Athletics = \"운동\", Deception = \"기만\", History = \"역사학\", Insight = \"통찰\", Intimidation = \"위협\", Investigation = \"수사\", Medicine = \"의학\", Nature = \"자연학\", Perception = \"감지\", Performance = \"공연\", Persuasion = \"설득\", Religion = \"종교학\", [\"Sleight of Hand\"] = \"손속임\", Stealth = \"은신\", Survival = \"생존\", Blinded = \"장님\", Charmed = \"매혹\", Deafened = \"귀머거리\", Exhaustion = \"탈진\", Frightened = \"공포\", Grappled = \"붙잡힘\", Incapacitated = \"행동불능\", Invisible = \"투명\", Paralyzed = \"마비\", Petrified = \"석화\", Poisoned = \"중독\", Prone = \"넘어진 상태\", Restrained = \"포박\", Stunned = \"충격\", Unconscious = \"무의식\", Dragonborn = \"드래곤본\", Dwarf = \"드워프\", Elf = \"엘프\", Gnome = \"노움\", Goliath = \"골리앗\", Halfling = \"하플링\", Human = \"인간\", Orc = \"오크\", Tiefling = \"티플링\", Fighter = \"파이터\", Rogue = \"로그\", Cleric = \"클레릭\", Wizard = \"위저드\", Barbarian = \"바바리안\", Bard = \"바드\", Druid = \"드루이드\", Monk = \"몽크\", Paladin = \"팔라딘\", Ranger = \"레인저\", Sorcerer = \"소서러\", Warlock = \"워락\", Champion = \"챔피언\", Thief = \"시프\", [\"Life Domain\"] = \"생명 권역\", Evoker = \"방출학파\", [\"Path of the Berserker\"] = \"광전사의 길\", [\"College of Lore\"] = \"전승 학파\", [\"Circle of the Land\"] = \"대지의 회합\", [\"Warrior of the Open Hand\"] = \"열린 손의 길\", [\"Oath of Devotion\"] = \"헌신의 맹세\", Hunter = \"헌터\", [\"Draconic Sorcery\"] = \"용의 혈통\", [\"Fiend Patron\"] = \"악마 후견자\", Acolyte = \"복사\", Criminal = \"범죄자\", Sage = \"학자\", Soldier = \"군인\", [\"Magic Initiate\"] = \"마법 입문자\", Alert = \"경계심\", [\"Savage Attacker\"] = \"야만적인 공격자\", Grappler = \"잡기 전문가\", Club = \"클럽\", Dagger = \"대거\", Greatclub = \"그레이트클럽\", Handaxe = \"핸드액스\", Javelin = \"자벨린\", [\"Light Hammer\"] = \"라이트 해머\", Mace = \"메이스\", Quarterstaff = \"쿼터스태프\", Sickle = \"시클\", Spear = \"스피어\", Dart = \"다트\", [\"Light Crossbow\"] = \"라이트 크로스보우\", Shortbow = \"숏보우\", Sling = \"슬링\", Battleaxe = \"배틀액스\", Flail = \"플레일\", Glaive = \"글레이브\", Greataxe = \"그레이트액스\", Greatsword = \"그레이트소드\", Halberd = \"할버드\", Lance = \"랜스\", Longsword = \"롱소드\", Maul = \"마울\", Morningstar = \"모닝스타\", Pike = \"파이크\", Rapier = \"레이피어\", Scimitar = \"시미터\", Shortsword = \"숏소드\", Trident = \"트라이던트\", Warhammer = \"워해머\", [\"War Pick\"] = \"워 픽\", Whip = \"채찍\", Blowgun = \"블로우건\", [\"Hand Crossbow\"] = \"핸드 크로스보우\", [\"Heavy Crossbow\"] = \"헤비 크로스보우\", Longbow = \"롱보우\", Musket = \"머스킷\", Pistol = \"권총\", [\"Padded Armor\"] = \"패디드 아머\", [\"Leather Armor\"] = \"가죽 갑옷\", [\"Studded Leather Armor\"] = \"스터디드 레더\", [\"Hide Armor\"] = \"하이드 아머\", [\"Chain Shirt\"] = \"체인 셔츠\", [\"Scale Mail\"] = \"비늘 갑옷\", Breastplate = \"흉갑\", [\"Half Plate Armor\"] = \"하프 플레이트\", [\"Ring Mail\"] = \"링 메일\", [\"Chain Mail\"] = \"사슬 갑옷\", [\"Splint Armor\"] = \"스플린트\", [\"Plate Armor\"] = \"판금 갑옷\", Shield = \"방패\", [\"Acid Splash\"] = \"산성 거품\", [\"Chill Touch\"] = \"냉랭한 접촉\", [\"Dancing Lights\"] = \"춤추는 빛\", Elementalism = \"원소술\", [\"Fire Bolt\"] = \"화염 화살\", Guidance = \"안내\", Light = \"빛\", [\"Mage Hand\"] = \"마법사의 손\", Mending = \"수리\", Message = \"전달\", [\"Minor Illusion\"] = \"하급 환영\", [\"Poison Spray\"] = \"독 분사\", Prestidigitation = \"요술\", [\"Ray of Frost\"] = \"서리 광선\", Resistance = \"저항\", [\"Sacred Flame\"] = \"신성한 불길\", [\"Shocking Grasp\"] = \"전격의 손아귀\", [\"Spare the Dying\"] = \"빈사 안정\", Thaumaturgy = \"단순마술\", [\"True Strike\"] = \"참된 일격\", Alarm = \"경보\", Bane = \"억압\", Bless = \"축복\", [\"Burning Hands\"] = \"타오르는 손길\", [\"Charm Person\"] = \"인간형 매혹\", [\"Chromatic Orb\"] = \"오색의 보주\", [\"Color Spray\"] = \"색 분사\", Command = \"명령\", [\"Comprehend Languages\"] = \"언어 변환\", [\"Create or Destroy Water\"] = \"물 창조 또는 파괴\", [\"Cure Wounds\"] = \"상처 치료\", [\"Detect Evil and Good\"] = \"악과 선 탐지\", [\"Detect Magic\"] = \"마법 탐지\", [\"Detect Poison and Disease\"] = \"독과 질병 탐지\", [\"Disguise Self\"] = \"자기 위장\", [\"Expeditious Retreat\"] = \"신속한 후퇴\", [\"False Life\"] = \"거짓 삶\", [\"Feather Fall\"] = \"깃털 낙하\", [\"Find Familiar\"] = \"패밀리어 찾기\", [\"Floating Disk\"] = \"부유 원반\", [\"Fog Cloud\"] = \"안개 구름\", Grease = \"기름칠\", [\"Guiding Bolt\"] = \"유도 화살\", [\"Healing Word\"] = \"치료의 단어\", [\"Hideous Laughter\"] = \"끔찍한 웃음\", [\"Ice Knife\"] = \"얼음 칼날\", Identify = \"식별\", [\"Illusory Script\"] = \"환영 문서\", [\"Inflict Wounds\"] = \"상처 가해\", Jump = \"도약\", Longstrider = \"활보\", [\"Mage Armor\"] = \"마법 갑주\", [\"Magic Missile\"] = \"마법 화살\", [\"Protection from Evil and Good\"] = \"악과 선으로부터의 보호\", [\"Purify Food and Drink\"] = \"음식과 물 정화\", [\"Ray of Sickness\"] = \"통증 광선\", Sanctuary = \"성역화\", [\"Shield of Faith\"] = \"신앙의 방패\", [\"Silent Image\"] = \"조용한 영상\", Sleep = \"수면\", Thunderwave = \"천둥파도\", [\"Unseen Servant\"] = \"보이지 않는 하인\", [\"Acid Arrow\"] = \"산성 화살\", Aid = \"원호\", [\"Alter Self\"] = \"자기 변형\", [\"Arcane Lock\"] = \"비전 자물쇠\", [\"Arcanist's Magic Aura\"] = \"비전술사의 마법 오오라\", Augury = \"점술\", [\"Blindness/Deafness\"] = \"장님화/귀머거리화\", Blur = \"흐려짐\", [\"Calm Emotions\"] = \"감정 진정화\", [\"Continual Flame\"] = \"영속의 불꽃\", Darkness = \"어둠\", Darkvision = \"암시야\", [\"Detect Thoughts\"] = \"생각 탐지\", [\"Dragon's Breath\"] = \"용의 숨결\", [\"Enhance Ability\"] = \"능력 강화\", [\"Enlarge/Reduce\"] = \"거대화/축소화\", [\"Find Traps\"] = \"함정 탐지\", [\"Flaming Sphere\"] = \"화염 구체\", [\"Gentle Repose\"] = \"안온한 처리\", [\"Gust of Wind\"] = \"돌풍\", [\"Hold Person\"] = \"인간형 포박\", Invisibility = \"투명화\", Knock = \"문열기\", [\"Lesser Restoration\"] = \"하급 회복\", Levitate = \"부양\", [\"Locate Object\"] = \"물체 위치파악\", [\"Magic Mouth\"] = \"마법의 입\", [\"Magic Weapon\"] = \"무기 마법화\", [\"Mind Spike\"] = \"정신 가시\", [\"Mirror Image\"] = \"거울 분신\", [\"Misty Step\"] = \"안개 걸음\", [\"Phantasmal Force\"] = \"환영력\", [\"Prayer of Healing\"] = \"치료의 기도\", [\"Protection from Poison\"] = \"독으로부터의 보호\", [\"Ray of Enfeeblement\"] = \"무력화 광선\", [\"Rope Trick\"] = \"로프 속임수\", [\"Scorching Ray\"] = \"타오르는 광선\", [\"See Invisibility\"] = \"투명체 감지\", Shatter = \"분쇄\", Silence = \"침묵\", [\"Spider Climb\"] = \"거미 등반\", [\"Spiritual Weapon\"] = \"영체 무기\", Suggestion = \"암시\", [\"Warding Bond\"] = \"방비의 유대\", Web = \"거미줄\", [\"Zone of Truth\"] = \"진실의 공간\", [\"Animate Dead\"] = \"사체 조종\", [\"Beacon of Hope\"] = \"희망의 봉화\", [\"Bestow Curse\"] = \"저주 부여\", Blink = \"점멸\", Clairvoyance = \"투시\", Counterspell = \"주문반사\", [\"Create Food and Water\"] = \"음식과 물 창조\", Daylight = \"태양광\", [\"Dispel Magic\"] = \"마법 무효화\", Fear = \"공포\", Fireball = \"화염구\", Fly = \"비행\", [\"Gaseous Form\"] = \"가스 형상\", [\"Glyph of Warding\"] = \"보호의 문양\", Haste = \"가속\", [\"Hypnotic Pattern\"] = \"최면 패턴\", [\"Lightning Bolt\"] = \"번개\", [\"Magic Circle\"] = \"마법의 원\", [\"Major Image\"] = \"상급 영상\", [\"Mass Healing Word\"] = \"다중 치료의 단어\", [\"Meld into Stone\"] = \"돌에 녹아들기\", Nondetection = \"탐지방어\", [\"Phantom Steed\"] = \"환영마\", [\"Protection from Energy\"] = \"에너지로부터의 보호\", [\"Remove Curse\"] = \"저주 해제\", Revivify = \"재활성화\", Sending = \"전음\", [\"Sleet Storm\"] = \"진눈깨비 폭풍\", Slow = \"저속화\", [\"Speak with Dead\"] = \"죽은 자와의 대화\", [\"Spirit Guardians\"] = \"영혼 수호자\", [\"Stinking Cloud\"] = \"악취 구름\", [\"Tiny Hut\"] = \"작은 오두막\", Tongues = \"언어 구사\", [\"Vampiric Touch\"] = \"흡혈의 접촉\", [\"Water Breathing\"] = \"수중 호흡\", [\"Water Walk\"] = \"수면 보행\", [\"Animate Objects\"] = \"물체 생명부여\", [\"Antilife Shell\"] = \"반생명 보호막\", [\"Arcane Eye\"] = \"비전의 눈\", [\"Arcane Hand\"] = \"비전의 손\", [\"Aura of Life\"] = \"생명의 오라\", Awaken = \"각성\", Banishment = \"추방\", [\"Black Tentacles\"] = \"검은 촉수\", Blight = \"황폐화\", [\"Charm Monster\"] = \"괴물 매혹\", Cloudkill = \"죽음의 구름\", Commune = \"교감\", [\"Commune with Nature\"] = \"자연과의 교감\", Compulsion = \"강제 이동\", [\"Cone of Cold\"] = \"냉기 원뿔\", Confusion = \"혼란\", [\"Conjure Elemental\"] = \"원소 소환\", [\"Conjure Minor Elementals\"] = \"하급 원소 소환\", [\"Conjure Woodland Beings\"] = \"숲의 정령 소환\", [\"Contact Other Plane\"] = \"이계 접촉\", Contagion = \"전염병\", [\"Control Water\"] = \"물 조종\", Creation = \"창조\", [\"Death Ward\"] = \"죽음 방비\", [\"Dimension Door\"] = \"차원문\", [\"Dispel Evil and Good\"] = \"악과 선 퇴치\", Divination = \"신탁\", [\"Dominate Beast\"] = \"야수 지배\", [\"Dominate Person\"] = \"인간형 지배\", Dream = \"꿈\", Fabricate = \"제작\", [\"Faithful Hound\"] = \"충직한 사냥개\", [\"Fire Shield\"] = \"화염 방패\", [\"Flame Strike\"] = \"화염 강타\", [\"Freedom of Movement\"] = \"이동의 자유\", Geas = \"강제 임무\", [\"Giant Insect\"] = \"거대 곤충\", [\"Greater Invisibility\"] = \"상급 투명화\", [\"Greater Restoration\"] = \"상급 회복\", [\"Guardian of Faith\"] = \"신앙의 수호자\", Hallow = \"신성화\", [\"Hallucinatory Terrain\"] = \"환각 지형\", [\"Hold Monster\"] = \"괴물 포박\", [\"Ice Storm\"] = \"얼음 폭풍\", [\"Insect Plague\"] = \"곤충 떼\", [\"Legend Lore\"] = \"전설 지식\", [\"Locate Creature\"] = \"생물 위치파악\", [\"Mass Cure Wounds\"] = \"다중 상처 치료\", Mislead = \"오도\", [\"Modify Memory\"] = \"기억 조작\", Passwall = \"벽 통과\", [\"Phantasmal Killer\"] = \"환영 살해자\", [\"Planar Binding\"] = \"이계 속박\", Polymorph = \"변신\", [\"Private Sanctum\"] = \"은신처\", [\"Raise Dead\"] = \"사자 소생\", Reincarnate = \"환생\", [\"Resilient Sphere\"] = \"탄성 구체\", Scrying = \"염탐\", [\"Secret Chest\"] = \"비밀 상자\", Seeming = \"겉모습 위장\", [\"Stone Shape\"] = \"바위 형상화\", Stoneskin = \"바위 피부\", [\"Summon Dragon\"] = \"용 소환\", Telekinesis = \"염동력\", [\"Telepathic Bond\"] = \"정신 유대\", [\"Teleportation Circle\"] = \"순간이동의 원\", [\"Tree Stride\"] = \"나무 걸음\", [\"Vitriolic Sphere\"] = \"산성 구체\", [\"Wall of Fire\"] = \"화염 벽\", [\"Wall of Force\"] = \"역장 벽\", [\"Wall of Stone\"] = \"바위 벽\", Druidcraft = \"드루이드 술법\", [\"Eldritch Blast\"] = \"섬뜩한 마탄\", [\"Produce Flame\"] = \"불꽃 생성\", Shillelagh = \"마법 곤봉\", [\"Sorcerous Burst\"] = \"술법 분출\", [\"Starry Wisp\"] = \"별빛 도깨비불\", [\"Vicious Mockery\"] = \"악랄한 조롱\", [\"Animal Friendship\"] = \"동물 친화\", [\"Dissonant Whispers\"] = \"불협화음의 속삭임\", [\"Divine Favor\"] = \"신성한 은총\", [\"Divine Smite\"] = \"신성한 강타\", [\"Ensnaring Strike\"] = \"휘감는 일격\", Entangle = \"휘감기\", [\"Faerie Fire\"] = \"요정불\", Goodberry = \"좋은 열매\", [\"Hellish Rebuke\"] = \"지옥의 질책\", Heroism = \"영웅심\", Hex = \"헥스\", [\"Hunter's Mark\"] = \"사냥꾼의 표식\", [\"Searing Smite\"] = \"작열하는 강타\", [\"Speak with Animals\"] = \"동물과 대화\", [\"Animal Messenger\"] = \"동물 전령\", Barkskin = \"나무껍질 피부\", Enthrall = \"매료\", [\"Find Steed\"] = \"탈것 부르기\", [\"Flame Blade\"] = \"화염 검\", [\"Heat Metal\"] = \"금속 가열\", [\"Locate Animals or Plants\"] = \"동식물 찾기\", Moonbeam = \"달빛 광선\", [\"Pass without Trace\"] = \"흔적 없는 이동\", [\"Shining Smite\"] = \"빛나는 강타\", [\"Spike Growth\"] = \"가시 돋기\", [\"Call Lightning\"] = \"번개 부르기\", [\"Conjure Animals\"] = \"동물 소환\", [\"Plant Growth\"] = \"식물 성장\", [\"Speak with Plants\"] = \"식물과 대화\", [\"Wind Wall\"] = \"바람의 벽\", [\"Animal Shapes\"] = \"동물 형상\", [\"Antimagic Field\"] = \"반마법 장\", [\"Antipathy/Sympathy\"] = \"반감/호감\", [\"Arcane Sword\"] = \"비전의 검\", Befuddlement = \"정신 혼탁\", [\"Blade Barrier\"] = \"칼날 방벽\", [\"Chain Lightning\"] = \"연쇄 번개\", [\"Circle of Death\"] = \"죽음의 원\", Clone = \"복제\", [\"Conjure Celestial\"] = \"천상체 소환\", [\"Conjure Fey\"] = \"요정 소환\", Contingency = \"대비책\", [\"Control Weather\"] = \"날씨 조종\", [\"Create Undead\"] = \"언데드 창조\", [\"Delayed Blast Fireball\"] = \"지연 폭발 화염구\", Demiplane = \"반차원\", Disintegrate = \"분해\", [\"Divine Word\"] = \"신성한 언령\", [\"Dominate Monster\"] = \"괴물 지배\", Earthquake = \"지진\", Etherealness = \"에테르화\", Eyebite = \"눈길 저주\", [\"Find the Path\"] = \"길 찾기\", [\"Finger of Death\"] = \"죽음의 손가락\", [\"Fire Storm\"] = \"화염 폭풍\", [\"Flesh to Stone\"] = \"석화\", Forbiddance = \"금단\", Forcecage = \"역장 감옥\", [\"Freezing Sphere\"] = \"빙결 구체\", Glibness = \"달변\", [\"Globe of Invulnerability\"] = \"무적의 구체\", [\"Guards and Wards\"] = \"경비와 결계\", Harm = \"위해\", Heal = \"치유\", [\"Heroes' Feast\"] = \"영웅들의 만찬\", [\"Holy Aura\"] = \"신성한 오라\", [\"Incendiary Cloud\"] = \"소이 구름\", [\"Instant Summons\"] = \"즉시 소환\", [\"Irresistible Dance\"] = \"거부할 수 없는 춤\", [\"Magic Jar\"] = \"마법 항아리\", [\"Magnificent Mansion\"] = \"장엄한 저택\", [\"Mass Suggestion\"] = \"다중 암시\", Maze = \"미궁\", [\"Mind Blank\"] = \"정신 공백\", [\"Mirage Arcane\"] = \"비전 신기루\", [\"Move Earth\"] = \"흙 옮기기\", [\"Planar Ally\"] = \"이계의 동맹\", [\"Plane Shift\"] = \"차원 이동\", [\"Power Word Stun\"] = \"권능어: 기절\", [\"Prismatic Spray\"] = \"무지갯빛 분사\", [\"Programmed Illusion\"] = \"예약된 환영\", [\"Project Image\"] = \"모습 투영\", Regenerate = \"재생\", Resurrection = \"부활\", [\"Reverse Gravity\"] = \"중력 반전\", Sequester = \"격리\", Simulacrum = \"분신 창조\", Sunbeam = \"햇살 광선\", Sunburst = \"태양 폭발\", Symbol = \"상징\", Teleport = \"순간이동\", [\"Transport via Plants\"] = \"식물을 통한 이동\", [\"True Seeing\"] = \"진시야\", Tsunami = \"해일\", [\"Wall of Ice\"] = \"얼음 벽\", [\"Wall of Thorns\"] = \"가시 벽\", [\"Wind Walk\"] = \"바람 걷기\", [\"Word of Recall\"] = \"귀환의 언령\", [\"Astral Projection\"] = \"아스트랄 투영\", Foresight = \"예지\", Gate = \"관문\", Imprisonment = \"투옥\", [\"Mass Heal\"] = \"대량 치유\", [\"Meteor Swarm\"] = \"유성 폭풍\", [\"Power Word Heal\"] = \"권능어: 치유\", [\"Power Word Kill\"] = \"권능어: 죽음\", [\"Prismatic Wall\"] = \"무지갯빛 벽\", Shapechange = \"형태 변화\", [\"Storm of Vengeance\"] = \"복수의 폭풍\", [\"Time Stop\"] = \"시간 정지\", [\"True Polymorph\"] = \"완전한 변신\", [\"True Resurrection\"] = \"진정한 부활\", Weird = \"기괴한 환영\", Wish = \"소원\", [\"Potion of Healing\"] = \"치유의 물약\", [\"Potion of Greater Healing\"] = \"상급 치유의 물약\", [\"Potion of Superior Healing\"] = \"최상급 치유의 물약\", [\"Potion of Supreme Healing\"] = \"최상위 치유의 물약\", [\"Healer's Kit\"] = \"치유사의 키트\", Antitoxin = \"해독제\", [\"Alchemist's Fire\"] = \"연금술사의 불\", Acid = \"산\", [\"Holy Water\"] = \"성수\", Arrows = \"화살\", Bolts = \"석궁 볼트\", [\"Firearm Bullets\"] = \"총탄\", [\"Sling Bullets\"] = \"슬링 탄환\", Needles = \"블로우건 바늘\", Oil = \"기름\", [\"Basic Poison\"] = \"기본 독\", [\"Fighting Style\"] = \"전투 유파\", Archery = \"궁술\", Defense = \"방어술\", [\"Great Weapon Fighting\"] = \"대형 무기 전투술\", [\"Two-Weapon Fighting\"] = \"쌍수 전투술\", [\"Second Wind\"] = \"재기의 바람\", [\"Action Surge\"] = \"행동 연쇄\", [\"Extra Attack\"] = \"추가 공격\", [\"Improved Critical\"] = \"향상된 치명타\", [\"Remarkable Athlete\"] = \"뛰어난 운동능력\", Expertise = \"숙달\", [\"Sneak Attack\"] = \"암습 공격\", [\"Thieves' Cant\"] = \"도둑의 속어\", [\"Cunning Action\"] = \"교활한 행동\", [\"Uncanny Dodge\"] = \"놀라운 회피\", [\"Fast Hands\"] = \"빠른 손놀림\", [\"Second-Story Work\"] = \"오르내리기\", [\"Channel Divinity\"] = \"신성 변환\", [\"Turn Undead\"] = \"언데드 퇴치\", [\"Disciple of Life\"] = \"생명의 사도\", [\"Preserve Life\"] = \"생명 보존\", [\"Arcane Recovery\"] = \"비전 회복\", [\"Ritual Adept\"] = \"의식 시전\", [\"Evocation Savant\"] = \"방출계 전공\", [\"Potent Cantrip\"] = \"강화된 소마법\", [\"Dwarven Resilience\"] = \"드워프의 탄성\", [\"Dwarven Toughness\"] = \"드워프의 끈기\", Stonecunning = \"돌의 꾀\", [\"Fey Ancestry\"] = \"요정 선조\", Trance = \"망아상태\", [\"Keen Senses\"] = \"예리한 감각\", [\"Gnome Cunning\"] = \"노움의 교활함\", Lucky = \"행운아\", Brave = \"용감함\", [\"Halfling Nimbleness\"] = \"하플링의 기민함\", [\"Relentless Endurance\"] = \"불굴의 인내력\", [\"Breath Weapon\"] = \"브레스 무기\", [\"Damage Resistance\"] = \"피해 저항\", [\"Weapon Mastery\"] = \"무기 통달\", [\"Tactical Mind\"] = \"전술적 사고\", [\"Tactical Shift\"] = \"전술적 이동\", [\"Steady Aim\"] = \"차분한 조준\", [\"Cunning Strike\"] = \"교활한 일격\", [\"Divine Order\"] = \"신성한 소임\", [\"Sear Undead\"] = \"언데드 태우기\", Scholar = \"학자\", [\"Memorize Spell\"] = \"주문 암기\", Spellcasting = \"주문시전\", [\"Ability Score Improvement\"] = \"능력치 점수 상승\", Rage = \"격노\", [\"Unarmored Defense\"] = \"비무장 방어\", [\"Danger Sense\"] = \"위험 감지\", [\"Reckless Attack\"] = \"무모한 공격\", [\"Primal Knowledge\"] = \"원시의 지식\", [\"Fast Movement\"] = \"빠른 이동\", Frenzy = \"광분\", [\"Bardic Inspiration\"] = \"바드의 고양감\", [\"Jack of All Trades\"] = \"팔방미인\", [\"Font of Inspiration\"] = \"고양감의 샘\", [\"Cutting Words\"] = \"날카로운 말\", Druidic = \"드루이드어\", [\"Primal Order\"] = \"원시의 소임\", [\"Wild Shape\"] = \"야생 변신\", [\"Wild Companion\"] = \"야생의 동료\", [\"Wild Resurgence\"] = \"야생의 재기\", [\"Land's Aid\"] = \"대지의 도움\", [\"Martial Arts\"] = \"무술\", [\"Monk's Focus\"] = \"기\", [\"Focus Points\"] = \"기 점수\", [\"Unarmored Movement\"] = \"비무장 이동\", [\"Uncanny Metabolism\"] = \"놀라운 신진대사\", [\"Deflect Attacks\"] = \"공격 쳐내기\", [\"Slow Fall\"] = \"저속 낙하\", [\"Stunning Strike\"] = \"충격의 일격\", [\"Flurry of Blows\"] = \"연타\", [\"Patient Defense\"] = \"인내의 방어\", [\"Step of the Wind\"] = \"바람 걸음\", [\"Lay On Hands\"] = \"치유의 손길\", [\"Paladin's Smite\"] = \"팔라딘의 강타\", [\"Faithful Steed\"] = \"충직한 군마\", [\"Sacred Weapon\"] = \"무기 축성\", [\"Favored Enemy\"] = \"선호하는 적\", [\"Deft Explorer\"] = \"능숙한 탐험가\", [\"Colossus Slayer\"] = \"거체 학살자\", [\"Horde Breaker\"] = \"무리 파쇄자\", [\"Innate Sorcery\"] = \"타고난 술법\", [\"Font of Magic\"] = \"마법력의 샘\", [\"Sorcery Points\"] = \"술법 점수\", Metamagic = \"마법변형\", [\"Sorcerous Restoration\"] = \"술법 회복\", [\"Eldritch Invocations\"] = \"섬뜩한 영창\", [\"Pact Magic\"] = \"계약 마법\", [\"Magical Cunning\"] = \"마법적 교활함\", [\"Mystic Arcanum\"] = \"신비의 비밀\", [\"Dark One's Blessing\"] = \"어두운 이의 축복\", [\"Barbarian Subclass\"] = \"바바리안 하위 직업\", [\"Bard Subclass\"] = \"바드 하위 직업\", [\"Druid Subclass\"] = \"드루이드 하위 직업\", [\"Monk Subclass\"] = \"몽크 하위 직업\", [\"Paladin Subclass\"] = \"팔라딘 하위 직업\", [\"Ranger Subclass\"] = \"레인저 하위 직업\", [\"Sorcerer Subclass\"] = \"소서러 하위 직업\", [\"Warlock Subclass\"] = \"워락 하위 직업\", [\"Careful Spell\"] = \"주문 세심화\", [\"Distant Spell\"] = \"주문 원거리화\", [\"Empowered Spell\"] = \"주문 강력화\", [\"Extended Spell\"] = \"주문 연장화\", [\"Heightened Spell\"] = \"주문 상승화\", [\"Quickened Spell\"] = \"주문 신속화\", [\"Seeking Spell\"] = \"주문 추적화\", [\"Subtle Spell\"] = \"주문 미묘화\", [\"Transmuted Spell\"] = \"주문 변환화\", [\"Twinned Spell\"] = \"주문 이중화\", [\"Agonizing Blast\"] = \"고뇌의 마탄\", [\"Armor of Shadows\"] = \"그림자의 갑옷\", [\"Devil's Sight\"] = \"악마의 눈\", [\"Eldritch Mind\"] = \"섬뜩한 정신\", [\"Fiendish Vigor\"] = \"악마의 활력\", [\"Mask of Many Faces\"] = \"수많은 얼굴의 가면\", [\"Misty Visions\"] = \"안개의 시야\", [\"Pact of the Blade\"] = \"칼날의 계약\", [\"Pact of the Chain\"] = \"사슬의 계약\", [\"Pact of the Tome\"] = \"고서의 계약\", [\"Repelling Blast\"] = \"격퇴의 마탄\", [\"Thirsting Blade\"] = \"목마른 칼날\", [\"One with Shadows\"] = \"그림자의 동행\", [\"Master of Myriad Forms\"] = \"수많은 형태의 주인\", [\"Ascendant Step\"] = \"승천의 발걸음\", [\"Gift of the Depths\"] = \"심연의 선물\", [\"Mindless Rage\"] = \"무아지경의 격노\", [\"Feral Instinct\"] = \"야만의 본능\", [\"Instinctive Pounce\"] = \"본능적 도약\", [\"Brutal Strike\"] = \"잔혹한 일격\", Retaliation = \"앙갚음\", [\"Magical Discoveries\"] = \"마법적 발견\", Countercharm = \"매혹반사\", [\"Magical Secrets\"] = \"마법적 비밀\", [\"Blessed Healer\"] = \"축복받은 치유사\", [\"Blessed Strikes\"] = \"축복받은 일격\", [\"Divine Strike\"] = \"신성한 일격\", [\"Potent Spellcasting\"] = \"강화된 주문시전\", [\"Divine Intervention\"] = \"신의 간섭\", [\"Natural Recovery\"] = \"자연적 회복력\", [\"Elemental Fury\"] = \"원소의 분노\", [\"Primal Strike\"] = \"원시의 일격\", [\"Nature's Ward\"] = \"자연의 보호\", [\"Additional Fighting Style\"] = \"추가 전투 유파\", Indomitable = \"불요불굴\", [\"Tactical Master\"] = \"전술의 달인\", [\"Heroic Warrior\"] = \"영웅적 전사\", [\"Empowered Strikes\"] = \"강기 일격\", [\"Wholeness of Body\"] = \"신체의 완전화\", Evasion = \"회피기동\", [\"Acrobatic Movement\"] = \"곡예 이동\", [\"Heightened Focus\"] = \"고양된 기\", [\"Self-Restoration\"] = \"자기 회복\", [\"Aura of Protection\"] = \"보호의 오오라\", [\"Aura of Devotion\"] = \"헌신의 오오라\", [\"Abjure Foes\"] = \"적 물리치기\", [\"Aura of Courage\"] = \"용기의 오오라\", Roving = \"방랑\", [\"Defensive Tactics\"] = \"방어적 전술\", [\"Escape the Horde\"] = \"무리 탈출\", [\"Multiattack Defense\"] = \"다중공격 방어\", Tireless = \"지치지 않음\", [\"Reliable Talent\"] = \"믿음직한 재능\", [\"Supreme Sneak\"] = \"뛰어난 은신술\", [\"Elemental Affinity\"] = \"원소 친화\", [\"Sorcery Incarnate\"] = \"술법의 화신\", [\"Dark One's Own Luck\"] = \"어두운 이의 명운\", [\"Contact Patron\"] = \"후원자 접촉\", [\"Fiendish Resilience\"] = \"악마의 탄성\", [\"Sculpt Spells\"] = \"주문 조정\", [\"Empowered Evocation\"] = \"강화된 방출\", [\"Relentless Rage\"] = \"끈질긴 격노\", [\"Improved Brutal Strike\"] = \"향상된 잔혹한 일격\", [\"Persistent Rage\"] = \"지속되는 격노\", [\"Intimidating Presence\"] = \"위협적 존재감\", [\"Peerless Skill\"] = \"독보적인 기술\", [\"Improved Blessed Strikes\"] = \"향상된 축복받은 일격\", [\"Nature's Sanctuary\"] = \"자연의 성역\", [\"Improved Elemental Fury\"] = \"향상된 원소의 분노\", [\"Two Extra Attacks\"] = \"추가 공격 두 번\", [\"Indomitable (two uses)\"] = \"불요불굴 (2회)\", [\"Studied Attacks\"] = \"공부한 공격\", [\"Superior Critical\"] = \"우월한 치명타\", [\"Fleet Step\"] = \"날랜 걸음\", [\"Deflect Energy\"] = \"에너지 쳐내기\", [\"Disciplined Survivor\"] = \"단련된 생존자\", [\"Perfect Focus\"] = \"완벽한 집중\", [\"Radiant Strikes\"] = \"광휘의 일격\", [\"Restoring Touch\"] = \"회복의 손길\", [\"Smite of Protection\"] = \"보호의 강타\", [\"Superior Hunter's Prey\"] = \"우월한 사냥꾼의 사냥감\", [\"Relentless Hunter\"] = \"끈질긴 사냥꾼\", [\"Nature's Veil\"] = \"자연의 장막\", [\"Superior Hunter's Defense\"] = \"우월한 사냥꾼의 방어\", [\"Improved Cunning Strike\"] = \"향상된 교활한 일격\", [\"Use Magic Device\"] = \"마법 도구 사용\", [\"Devious Strikes\"] = \"음흉한 일격\", [\"Slippery Mind\"] = \"유연한 마음가짐\", [\"Dragon Wings\"] = \"용의 날개\", [\"Mystic Arcanum (level 6 spell)\"] = \"신비의 비밀 (6레벨 주문)\", [\"Mystic Arcanum (level 7 spell)\"] = \"신비의 비밀 (7레벨 주문)\", [\"Mystic Arcanum (level 8 spell)\"] = \"신비의 비밀 (8레벨 주문)\", [\"Hurl Through Hell\"] = \"지옥너머로 던지기\", Overchannel = \"과전환\", [\"Eldritch Spear\"] = \"섬뜩한 창\", [\"Otherworldly Leap\"] = \"외세계의 도약\", [\"Gaze of Two Minds\"] = \"두 마음의 시선\", [\"Whispers of the Grave\"] = \"무덤의 속삭임\", [\"Visions of Distant Realms\"] = \"머나먼 땅의 영상\", [\"Witch Sight\"] = \"주술 시야\", Lifedrinker = \"생명을 마시는 자\", [\"Devouring Blade\"] = \"탐식의 칼날\", [\"Eldritch Smite\"] = \"섬뜩한 강타\", [\"Gift of the Protectors\"] = \"수호자의 선물\", [\"Investment of the Chain Master\"] = \"사슬 주인의 권능\", [\"Improved Brutal Strike (2d10)\"] = \"향상된 잔혹한 일격 (2d10)\", [\"Indomitable Might\"] = \"불굴의 힘\", [\"Primal Champion\"] = \"원시의 용사\", [\"Superior Inspiration\"] = \"우월한 고양감\", [\"Words of Creation\"] = \"창조의 언령\", [\"Supreme Healing\"] = \"최상의 치유력\", [\"Greater Divine Intervention\"] = \"상위 신의 간섭\", [\"Beast Spells\"] = \"야수 주문\", Archdruid = \"대드루이드\", [\"Action Surge (two uses)\"] = \"행동 연쇄 (2회)\", [\"Indomitable (three uses)\"] = \"불요불굴 (3회)\", Survivor = \"생존의 대가\", [\"Three Extra Attacks\"] = \"추가 공격 세 번\", [\"Quivering Palm\"] = \"진동장\", [\"Superior Defense\"] = \"우월한 방어\", [\"Body and Mind\"] = \"몸과 마음\", [\"Aura Expansion\"] = \"오오라 확장\", [\"Holy Nimbus\"] = \"신성한 후광\", [\"Precise Hunter\"] = \"정밀한 사냥꾼\", [\"Feral Senses\"] = \"야생 감각\", [\"Foe Slayer\"] = \"적 살해자\", [\"Thief's Reflexes\"] = \"도둑의 반사신경\", Elusive = \"회피본능\", [\"Stroke of Luck\"] = \"행운의 한 방\", [\"Dragon Companion\"] = \"용 동료\", [\"Arcane Apotheosis\"] = \"비전의 신격화\", [\"Mystic Arcanum (level 9 spell)\"] = \"신비의 비밀 (9레벨 주문)\", [\"Eldritch Master\"] = \"섬뜩한 대가\", [\"Spell Mastery\"] = \"주문 통달\", [\"Signature Spells\"] = \"대표 주문\", [\"Epic Boon\"] = \"에픽 은혜\", [\"Boon of Combat Prowess\"] = \"전투 기량의 은혜\", [\"Boon of Dimensional Travel\"] = \"차원 여행의 은혜\", [\"Boon of Fate\"] = \"운명의 은혜\", [\"Boon of Irresistible Offense\"] = \"저항할 수 없는 공격의 은혜\", [\"Boon of Spell Recall\"] = \"주문 회상의 은혜\", [\"Boon of the Night Spirit\"] = \"밤의 영혼의 은혜\", [\"Boon of Truesight\"] = \"진시야의 은혜\", [\"Heroic Rally\"] = \"영웅적 재기\", [\"2 Pouches\"] = \"주머니 2개\", [\"Book (history)\"] = \"역사책\", [\"Book (prayers)\"] = \"기도서\", [\"Burglar's Pack\"] = \"도둑 꾸러미\", [\"Calligrapher's Supplies\"] = \"서예가 도구\", Crowbar = \"쇠지렛대\", [\"Dungeoneer's Pack\"] = \"던전 탐험가 꾸러미\", [\"Gaming Set\"] = \"놀이 도구\", [\"Holy Symbol\"] = \"성표\", [\"Parchment (10 sheets)\"] = \"양피지 10장\", [\"Parchment (8 sheets)\"] = \"양피지 8장\", [\"Priest's Pack\"] = \"사제 꾸러미\", Quiver = \"화살통\", Robe = \"로브\", [\"Scholar's Pack\"] = \"학자 꾸러미\", Spellbook = \"주문책\", [\"Thieves' Tools\"] = \"도둑 도구\", [\"Traveler's Clothes\"] = \"여행복\", [\"Explorer's Pack\"] = \"탐험가 꾸러미\", [\"Entertainer's Pack\"] = \"공연가 꾸러미\", [\"Artisan's Tools\"] = \"장인 도구\", [\"Herbalism Kit\"] = \"약초학 키트\", [\"Musical Instrument\"] = \"악기\", [\"Book (occult lore)\"] = \"신비학 서적\", [\"Arcane Focus (crystal)\"] = \"비전 매개체 (수정)\", [\"Arcane Focus (orb)\"] = \"비전 매개체 (구슬)\", [\"Druidic Focus (sprig of mistletoe)\"] = \"드루이드 매개체 (겨우살이 가지)\" }\r\n\r\n\r\n\r\nSPELLS[\"Breath Weapon\"] = { level = 0, classes = {}, m = { kind = \"save\", save = \"Dexterity\", damage = \"1d10\", on_save = \"half\", cantrip = true } }\r\nSPELLS[\"Storm's Thunder\"] = { level = 0, classes = {}, m = { kind = \"auto\", damage = \"1d8\", type = \"Thunder\", darts = 1, cast = \"reaction\" } }\r\n\r\nSPELLS[\"Land's Aid\"] = { level = 0, classes = {}, m = { kind = \"save\", save = \"Constitution\", damage = \"2d6\", type = \"Necrotic\", on_save = \"half\", heal = \"2d6\",\r\ngrow = { at = { 10, 14 }, dice = \"1d6\", cls = \"Druid\" } } }\r\n\r\nif SPELLS[\"Hellish Rebuke\"] and not SPELLS[\"Hellish Rebuke\"].m then\r\nSPELLS[\"Hellish Rebuke\"].m = { kind = \"save\", save = \"Dexterity\", damage = \"2d10\", type = \"Fire\", on_save = \"half\", cast = \"reaction\", upcast = { dice = \"1d10\" } }\r\nend\r\nNAMES_KO[\"Breath Weapon\"] = NAMES_KO[\"Breath Weapon\"] or \"브레스 무기\"\r\nNAMES_KO[\"Storm's Thunder\"] = NAMES_KO[\"Storm's Thunder\"] or \"폭풍의 천둥\"\r\nNAMES_KO[\"Land's Aid\"] = NAMES_KO[\"Land's Aid\"] or \"대지의 도움\"\r\n\r\nfor en, ko in pairs({ [\"Open Hand Technique\"] = \"열린 손의 기법\", Push = \"밀어내기\", Topple = \"넘어뜨리기\", Trip = \"넘어뜨리기\", Daze = \"멍하게 하기\",\r\n[\"Knock Out\"] = \"기절시키기\", Obscure = \"시야 가리기\", Grapple = \"붙잡기\" }) do NAMES_KO[en] = NAMES_KO[en] or ko end\r\nfor en, ko in pairs({ [\"Heroic Inspiration\"] = \"영웅적 영감\", [\"Giant Ancestry\"] = \"거인 혈통\", [\"Adrenaline Rush\"] = \"아드레날린 쇄도\",\r\n[\"Relentless Endurance\"] = \"불굴의 인내력\", [\"Magic Initiate\"] = \"마법 입문자\", [\"Divine Spark\"] = \"신성한 불꽃\",\r\n[\"Stone's Endurance\"] = \"바위의 인내\", [\"Circle Spell\"] = \"대지의 주문\",\r\n\r\n\r\n[\"High Elf\"] = \"하이 엘프\", [\"Wood Elf\"] = \"우드 엘프\", Drow = \"드로우\", Rope = \"밧줄\",\r\nRegeneration = \"재생\", [\"Undead Fortitude\"] = \"언데드의 강인함\", [\"Psychic Drain\"] = \"정신 흡수\",\r\n[\"Consume Life\"] = \"생명 섭취\", [\"Acid Absorption\"] = \"산 흡수\", [\"Lightning Absorption\"] = \"번개 흡수\",\r\n[\"Incorporeal Movement\"] = \"비실체 이동\", [\"Running Water\"] = \"흐르는 물\", [\"Water Susceptibility\"] = \"물 취약\",\r\nSunlight = \"햇빛\", [\"Burning Oil\"] = \"불붙은 기름\", Burning = \"불붙음\",\r\n\r\n[\"Half Cover\"] = \"절반 엄폐\", [\"Three-Quarters Cover\"] = \"3/4 엄폐\",\r\n\r\n[\"Magic Resistance\"] = \"마법 저항\", [\"Greater Magic Resistance\"] = \"상급 마법 저항\", Parry = \"받아넘기기\",\r\nRiposte = \"반격\", [\"Whirlwind of Sand\"] = \"모래 회오리\", [\"Protective Magic\"] = \"보호 마법\",\r\n[\"Reflective Carapace\"] = \"반사 갑각\", Split = \"분열\", [\"Loathsome Limbs\"] = \"끔찍한 사지\",\r\n[\"Bloodied Frenzy\"] = \"피투성이 광란\", [\"War Cry\"] = \"함성\", [\"Shimmering Shield\"] = \"일렁이는 방패\" }) do\r\nNAMES_KO[en] = NAMES_KO[en] or ko\r\nend\r\n\r\n\r\n\r\ndo\r\nlocal used = {}\r\nfor _, ko in pairs(NAMES_KO) do used[ko] = true end\r\nfor en, m in pairs(K.MAGIC or {}) do\r\nif type(m.ko) == \"string\" and not m.ko:find(\"^%+1·\") and not NAMES_KO[en] and not used[m.ko] then\r\nNAMES_KO[en], used[m.ko] = m.ko, true\r\nend\r\nend\r\nend\r\n\r\n\r\nK.FX_MODE = {}\r\nfor name, rec in pairs(K.FX) do\r\nfor _, e in ipairs(rec.fx) do\r\nif e.t == \"heal_source\" and not HEAL_SRC[e.name] then HEAL_SRC[e.name] = { dmg = e.formula, pool = e.use, self = true } end\r\nif (e.t == \"die_bonus\" or e.t == \"reroll_save\") and e.mode then\r\nK.FX_MODE[e.mode] = setmetatable({ src = name }, { __index = e })\r\nend\r\nend\r\nend\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\nK.PACK = { sig = \"\", undo = {}, list = {}, cls = {}, sub = {}, nn = {}, feat = {}, sp = {}, impl = {} }\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\nK.D2 = { mode = \"mild\", perm = \"off\", furry = \"off\", xeno = \"off\", lvdown = \"off\", omega = \"off\" }\r\nK.D2_VALUES = { mild = true, hard = true, perm = true, check = true, furry = true, xeno = true, omega = true }\r\nfunction K.d2list(rec)\r\nlocal v = type(rec) == \"table\" and rec.d2\r\nif v == nil then return {} end\r\nreturn type(v) == \"table\" and v or { v }\r\nend\r\n\r\nfunction K.d2need(rec)\r\nfor _, x in ipairs(K.d2list(rec)) do\r\nif x == \"hard\" and K.D2.mode ~= \"hard\" then return \"hard\" end\r\nif x == \"perm\" and K.D2.perm ~= \"on\" then return \"perm\" end\r\nif x == \"furry\" and K.D2.furry ~= \"on\" then return \"furry\" end\r\nif x == \"xeno\" and K.D2.xeno ~= \"on\" then return \"xeno\" end\r\nif x == \"omega\" and K.D2.omega ~= \"on\" then return \"omega\" end\r\nend\r\nreturn nil\r\nend\r\nfunction K.d2ok(rec) return K.d2need(rec) == nil end\r\n\r\nfunction K.d2check(what, rec)\r\nif type(rec) ~= \"table\" or rec.d2 == nil then return end\r\nif type(rec.d2) ~= \"string\" and type(rec.d2) ~= \"table\" then error(what .. \": d2 is not text or a list\") end\r\nif type(rec.d2) == \"table\" then\r\nlocal n = 0\r\nfor _ in pairs(rec.d2) do n = n + 1 end\r\nif n == 0 or n ~= #rec.d2 then error(what .. \": d2 is not a list of words\") end\r\nend\r\nfor _, x in ipairs(K.d2list(rec)) do\r\nif not K.D2_VALUES[x] then error(what .. \": d2 \" .. tostring(x) .. \" (mild, hard, perm or check)\") end\r\nend\r\nif not K.PACK.d2 then K.packPut(K.PACK, \"d2\", true) end\r\nend\r\nK.D2_WHY = { hard = \"off in this game: hardcore mode only (the settings tab)\", perm = \"off in this game: permanent results are off (the settings tab)\",\r\nfurry = \"off in this game: furry content is off (the settings tab)\", xeno = \"off in this game: xeno content is off (the settings tab)\",\r\nomega = \"off in this game: the omegaverse world is off (the settings tab)\" }\r\n\r\nfunction K.spellOff(n)\r\nlocal sp = SPELLS[n or \"\"]\r\nlocal need = type(sp) == \"table\" and K.d2need(sp)\r\nreturn need and (n .. \" is \" .. K.D2_WHY[need]) or nil\r\nend\r\n\r\nfunction K.d2names(list)\r\nlocal o = {}\r\nfor _, n in ipairs(list or {}) do\r\nlocal r = K.PACK.feat[n] and K.FX[n]\r\nif not (r and K.d2need(r)) then o[#o + 1] = n end\r\nend\r\nreturn o\r\nend\r\n\r\n\r\n\r\nfunction K.clsOn()\r\nlocal o = {}\r\nfor n, r in pairs(CLASSES) do if type(n) == \"string\" and n:sub(1, 1) ~= \"_\" and (type(r) ~= \"table\" or not K.d2need(r)) then o[n] = r end end\r\nreturn o\r\nend\r\nfunction K.spOn()\r\nlocal o = {}\r\nfor n, r in pairs(SPECIES) do if type(r) ~= \"table\" or not K.d2need(r) then o[n] = r end end\r\nreturn o\r\nend\r\nfunction K.bgsOn()\r\nlocal o = {}\r\nfor n, b in pairs(BACKGROUNDS) do if type(b) ~= \"table\" or not K.d2need(b) then o[n] = b end end\r\nreturn o\r\nend\r\n\r\n\r\n\r\n\r\n\r\nfunction K.replCheck(what, rec)\r\nif type(rec) ~= \"table\" or rec.replaces == nil then return end\r\nif type(rec.replaces) ~= \"table\" then error(what .. \": replaces is not a list\") end\r\nfor _, n in ipairs(rec.replaces) do if type(n) ~= \"string\" then error(what .. \": replaces \" .. tostring(n)) end end\r\nend\r\nK.FEAT_OWNS = {\r\n[\"Favored Enemy\"] = { res = { \"Hunter's Mark (free)\" }, always = { \"Hunter's Mark\" } },\r\n}\r\n\r\n\r\n\r\nfunction K.replacedIn(sh, raw, cls)\r\nlocal out = {}\r\nlocal function take(r, cl)\r\nfor _, n in ipairs(type(r) == \"table\" and type(r.replaces) == \"table\" and r.replaces or {}) do\r\nout[n] = out[n] or {}\r\nout[n][cl or \"*\"] = true\r\nend\r\nend\r\nfor _, c in ipairs(cls or K.classes(sh)) do take(K.subRec(c.name, K.subOf(sh, c.name)), c.name) end\r\nlocal p = type(sh.picks) == \"table\" and sh.picks or {}\r\nfor _, x in ipairs(raw) do\r\nlocal r = K.FX[(x.name:gsub(\" %(.-%)$\", \"\"))]\r\nif type(r) == \"table\" then\r\ntake(r, x.class)\r\nfor _, e in ipairs(type(r.fx) == \"table\" and r.fx or {}) do\r\nif e.t == \"choice\" then\r\nfor _, pv in ipairs(type(p[e.key]) == \"table\" and p[e.key] or { p[e.key] }) do\r\nlocal o = type(pv) == \"string\" and K.FX[pv]\r\nif type(o) == \"table\" then take(o, x.class) end\r\nend\r\nend\r\nend\r\nend\r\nend\r\nreturn out\r\nend\r\n\r\nfunction K.replacedSet(sh)\r\nlocal raw, none = {}, {}\r\nlocal cls = K.classes(sh)\r\nfor _, c in ipairs(cls) do\r\nlocal cl = CLASSES[c.name or \"\"]\r\nif cl then\r\nlocal rec = K.subRec(c.name, K.subOf(sh, c.name))\r\nlocal lvs = rec and type(rec.levels) == \"table\" and rec.levels or none\r\nfor lv = 1, math.min(c.level, #cl.levels) do\r\nfor _, x in ipairs((cl.levels[lv] or {}).features or {}) do raw[#raw + 1] = { name = x, class = c.name } end\r\nfor _, n in ipairs(lvs[tostring(lv)] or none) do raw[#raw + 1] = { name = n, class = c.name } end\r\nend\r\nend\r\nend\r\nreturn K.replacedIn(sh, raw, cls)\r\nend\r\nfunction K.replaced(sh, name)\r\nif type(sh) ~= \"table\" or not sh.class then return false end\r\nreturn K.replacedSet(sh)[name] ~= nil\r\nend\r\n\r\n\r\nfunction K.replacedText(sh)\r\nlocal o, have = {}, {}\r\nif type(sh) ~= \"table\" or not sh.class then return nil end\r\nfor _, x in ipairs(Feat.levelFeaturesBy(sh, true)) do have[x.name] = true end\r\nfor n in pairs(K.replacedSet(sh)) do if not have[n] then o[#o + 1] = n end end\r\nif #o == 0 then return nil end\r\ntable.sort(o)\r\nreturn \"Not on this sheet (a pick took their place, whatever the class list says): \" .. table.concat(o, \", \")\r\nend\r\nfunction K.ownedGone(sh)\r\nlocal out = { res = {}, always = {} }\r\nif type(sh) ~= \"table\" or not sh.class then return out end\r\nfor n in pairs(K.replacedSet(sh)) do\r\nlocal o = K.FEAT_OWNS[n]\r\nfor _, k in ipairs(o and o.res or {}) do out.res[k] = true end\r\nfor _, k in ipairs(o and o.always or {}) do out.always[k] = true end\r\nend\r\nreturn out\r\nend\r\n\r\n\r\nK.PACK_V = 1\r\nK.PACK_KEYS = { pack = true, v = true, fx = true, names = true, classes = true, class_defs = true, spells = true, monsters = true, backgrounds = true,\r\nfeats = true, arousal = true, species = true, implements = true, conds = true, preg_compat = true, bonds = true, afflictions = true, adult = true, items = true }\r\n\r\nK.CLASS_NEED = { \"hit_die\", \"primary\", \"saves\", \"skills\", \"weapons\", \"armor\", \"equipment\", \"levels\", \"subclass\" }\r\nfunction K.packNote(s)\r\nif K.PACK.notes then K.PACK.notes[#K.PACK.notes + 1] = s end\r\nend\r\n\r\nfunction K.packPut(t, k, v)\r\n\r\nif k == nil then error(\"a key the pack names is not valid (a level that is not a number?)\") end\r\n\r\n\r\nif t == K.FX and type(k) == \"string\" and k:match(\" %(.-%)$\") then\r\nK.packNote(\"feature \" .. k .. \": a name ending in (...) is read as \" .. k:gsub(\" %(.-%)$\", \"\") .. \"; give it a name of its own\")\r\nend\r\nK.PACK.undo[#K.PACK.undo + 1] = { t, k, t[k] }\r\nt[k] = v\r\nend\r\nfunction K.packUndo(to)\r\nfor i = #K.PACK.undo, (to or 0) + 1, -1 do\r\nlocal u = K.PACK.undo[i]\r\npcall(function() u[1][u[2]] = u[3] end)\r\nK.PACK.undo[i] = nil\r\nend\r\nend\r\n\r\nfunction K.packMerge(d)\r\n\r\n\r\nif tonumber(d.v) and tonumber(d.v) > K.PACK_V then error(\"pack format v\" .. tostring(d.v) .. \" is newer than this bot's v\" .. K.PACK_V) end\r\nfor k in pairs(d) do if not K.PACK_KEYS[k] then K.packNote(\"not read: \" .. tostring(k)) end end\r\n\r\n\r\nlocal lists = {}\r\nfor cl, x in pairs(type(d.class_defs) == \"table\" and d.class_defs or {}) do\r\nif K.LITE then\r\nK.packNote(\"light build: class \" .. cl .. \" not loaded\")\r\nelseif CLASSES[cl] and not K.PACK.cls[cl] then\r\nK.packNote(\"class \" .. cl .. \" is the bot's own (change it under classes)\")\r\nelse\r\nif type(x) ~= \"table\" then error(\"class \" .. cl .. \": not a table\") end\r\nfor _, k in ipairs(K.CLASS_NEED) do if x[k] == nil then error(\"class \" .. cl .. \": no \" .. k) end end\r\nK.d2check(\"class \" .. cl, x)\r\nif type(x.levels) ~= \"table\" or #x.levels < 1 then error(\"class \" .. cl .. \": no level rows\") end\r\n\r\n\r\nif x.caster == \"pact\" then x.pact = true end\r\nif x.pact and x.caster and x.caster ~= \"pact\" then error(\"class \" .. cl .. \": pact, but caster \" .. tostring(x.caster)) end\r\n\r\nif x.spell_ability then\r\nfor lv, row in ipairs(x.levels) do\r\nif type(row) ~= \"table\" or not tonumber(row.cantrips) or not tonumber(row.prepared) or type(row.slots) ~= \"table\" then\r\nerror(\"class \" .. cl .. \": level \" .. lv .. \" needs cantrips, prepared and slots (it casts spells)\")\r\nend\r\nend\r\nend\r\n\r\n\r\nif x.implant ~= nil then\r\nif type(x.implant) ~= \"table\" then error(\"class \" .. cl .. \": implant is a table\") end\r\nfor _, k in ipairs({ \"per_day\", \"hold\" }) do if x.implant[k] ~= nil and type(x.implant[k]) ~= \"string\" then error(\"class \" .. cl .. \": implant \" .. k .. \" is text\") end end\r\n\r\nif x.implant.cond ~= nil and type(x.implant.cond) ~= \"string\" and type(x.implant.cond) ~= \"table\" then error(\"class \" .. cl .. \": implant cond is a name or a list\") end\r\nfor _, k in ipairs({ \"hold_at\", \"per_day_at\" }) do if x.implant[k] ~= nil and type(x.implant[k]) ~= \"table\" then error(\"class \" .. cl .. \": implant \" .. k .. \" is a table\") end end\r\nfor lv, row in ipairs(x.levels) do\r\nif type(row) ~= \"table\" or not tonumber(row.max_spell) then error(\"class \" .. cl .. \": level \" .. lv .. \" needs max_spell (it implants)\") end\r\nend\r\nend\r\n\r\nif type(x.subclass) ~= \"table\" or type(x.subclass.name) ~= \"string\" then error(\"class \" .. cl .. \": subclass needs a name\") end\r\nif type(x.subclasses) ~= \"table\" then\r\nlocal lv = {}\r\nfor i, row in ipairs(x.levels) do\r\nif type(row) == \"table\" and type(row.subclass_features) == \"table\" then lv[tostring(i)] = row.subclass_features end\r\nend\r\nx.subclasses = { [x.subclass.name] = { levels = lv } }\r\nend\r\nif type(x.subclasses[x.subclass.name]) ~= \"table\" then error(\"class \" .. cl .. \": subclass \" .. x.subclass.name .. \" is not under subclasses\") end\r\nfor n, rec in pairs(x.subclasses) do\r\nK.subCheck(cl, n, rec, d)\r\nif rec.ko then K.packPut(NAMES_KO, n, tostring(rec.ko)) end\r\nend\r\nK.packPut(CLASSES, cl, x)\r\nK.packPut(K.PACK.cls, cl, true)\r\nif x.spell_list ~= nil then lists[#lists + 1] = { cl, x.spell_list } end\r\nif x.intro and K.Cg and K.Cg.TIP then K.packPut(K.Cg.TIP.cl, cl, tostring(x.intro)) end\r\nend\r\nend\r\nfor name, rec in pairs(type(d.fx) == \"table\" and d.fx or {}) do\r\n\r\n\r\nK.fxCheck(name, rec)\r\nK.d2check(\"fx \" .. tostring(name), rec)\r\nK.replCheck(\"fx \" .. tostring(name), rec)\r\n\r\n\r\nif rec.with ~= nil then\r\nif type(rec.with) ~= \"table\" then error(\"fx \" .. name .. \": with is a list of feature names\") end\r\nfor _, w in ipairs(rec.with) do if type(w) ~= \"string\" then error(\"fx \" .. name .. \": with \" .. tostring(w)) end end\r\nend\r\nif rec.everyone then K.packPut(K.PACK.feat, name, \"everyone\") end\r\nK.packPut(K.FX, name, rec)\r\nif rec.ko then\r\nK.packPut(NAMES_KO, name, rec.ko)\r\nK.packPut(K.PACK.nn, #K.PACK.nn + 1, name)\r\nend\r\n\r\nfor _, e in ipairs(type(rec) == \"table\" and rec.fx or {}) do\r\n\r\nif e.t == \"heal_source\" then K.packPut(HEAL_SRC, e.name or name, { dmg = e.formula, pool = e.use, packFx = e.name or name, dice_at = e.dice_at, selfOnly = e.self,\r\nafter = e.after, nonmagical = e.nonmagical }) end\r\nif (e.t == \"die_bonus\" or e.t == \"reroll_save\") and e.mode then\r\nK.packPut(K.FX_MODE, e.mode, setmetatable({ src = name }, { __index = e }))\r\nif K.D20_MODE then K.packPut(K.D20_MODE, e.mode, NAMES_KO[name] or name) end\r\nend\r\nif e.t == \"spell_pick\" and type(e.key) == \"string\" and Feat.TITLE and not Feat.TITLE[e.key] then\r\nK.packPut(Feat.TITLE, e.key, e.title or rec.ko or name)\r\nend\r\nif e.t == \"resist\" and type(e.pick) == \"string\" and Feat.TITLE and not Feat.TITLE[e.pick] then\r\nK.packPut(Feat.TITLE, e.pick, e.title or rec.ko or name)\r\nend\r\nif e.t == \"choice\" and Feat.TIP then\r\n\r\nif Feat.TITLE and not Feat.TITLE[e.key] then K.packPut(Feat.TITLE, e.key, e.title or rec.ko or name) end\r\nif not Feat.TIP[e.key] then K.packPut(Feat.TIP, e.key, {}) end\r\nfor _, o in ipairs(e.options or {}) do\r\nlocal orec = (type(d.fx[o]) == \"table\" and d.fx[o]) or K.FX[o]\r\nif orec then K.packPut(Feat.TIP[e.key], o, orec.tip) end\r\nend\r\nend\r\nend\r\nend\r\n\r\n\r\n\r\nfor name, rec in pairs(type(d.feats) == \"table\" and d.feats or {}) do\r\nif type(name) ~= \"string\" or not name:match(\"^%a[%a' %-]*$\") then error(\"feat \" .. tostring(name) .. \": a name of letters and spaces\") end\r\nK.fxCheck(name, rec)\r\n\r\n\r\nfor _, e in ipairs(type(rec.fx) == \"table\" and rec.fx or {}) do\r\nif (e.t == \"choice\" or e.t == \"spell_pick\") and type(e.key) == \"string\" and Feat.TITLE and not Feat.TITLE[e.key] then\r\nK.packPut(Feat.TITLE, e.key, e.title or rec.ko or name)\r\nend\r\nif e.t == \"resist\" and type(e.pick) == \"string\" and Feat.TITLE and not Feat.TITLE[e.pick] then\r\nK.packPut(Feat.TITLE, e.pick, e.title or rec.ko or name)\r\nend\r\n\r\nif e.t == \"heal_source\" then K.packPut(HEAL_SRC, e.name or name, { dmg = e.formula, pool = e.use, packFx = e.name or name, dice_at = e.dice_at, selfOnly = e.self,\r\nafter = e.after, nonmagical = e.nonmagical }) end\r\n\r\nif (e.t == \"die_bonus\" or e.t == \"reroll_save\") and e.mode then\r\nK.packPut(K.FX_MODE, e.mode, setmetatable({ src = name }, { __index = e }))\r\nif K.D20_MODE then K.packPut(K.D20_MODE, e.mode, rec.ko or NAMES_KO[name] or name) end\r\nend\r\nif e.t == \"choice\" and type(e.key) == \"string\" and Feat.TIP and not Feat.TIP[e.key] then\r\nK.packPut(Feat.TIP, e.key, {})\r\nfor _, o in ipairs(e.options or {}) do\r\nlocal orec = (type(d.fx) == \"table\" and type(d.fx[o]) == \"table\" and d.fx[o]) or K.FX[o]\r\nif orec then K.packPut(Feat.TIP[e.key], o, orec.tip) end\r\nend\r\nend\r\nend\r\nK.d2check(\"feat \" .. name, rec)\r\n\r\n\r\nif rec.ko and name:find(\"^%u\") then\r\nK.packPut(K.PACK.nn, #K.PACK.nn + 1, name)\r\nK.PACK.nnw = K.PACK.nnw or {}\r\nK.packPut(K.PACK.nnw, name, true)\r\nend\r\nif rec.cat == \"general\" then\r\n\r\n\r\n\r\nif rec.pre ~= nil and type(rec.pre) ~= \"table\" then error(\"feat \" .. name .. \": pre is a table\") end\r\nif rec.asi ~= nil and type(rec.asi) ~= \"table\" then error(\"feat \" .. name .. \": asi is a list of abilities\") end\r\nif rec[\"repeat\"] ~= nil and rec[\"repeat\"] ~= true and not tonumber(rec[\"repeat\"]) then error(\"feat \" .. name .. \": repeat is true or a count\") end\r\nif K.FX[name] ~= nil then K.packNote(\"feat \" .. name .. \" is the bot's own\")\r\nelse\r\nK.packPut(K.FX, name, rec)\r\nK.packPut(K.PACK.feat, name, \"general\")\r\nif rec.ko then K.packPut(NAMES_KO, name, rec.ko) end\r\nend\r\nelseif rec.cat == \"invocation\" or rec.cat == \"metamagic\" then\r\n\r\n\r\nif rec.level ~= nil and not tonumber(rec.level) then error(\"feat \" .. name .. \": level is a Warlock level\") end\r\nif rec.requires ~= nil and type(rec.requires) ~= \"string\" then error(\"feat \" .. name .. \": requires is an invocation's name\") end\r\nlocal cost = tonumber(rec.cost)\r\nif rec.cat == \"metamagic\" and not (cost and cost >= 0 and cost == math.floor(cost)) then error(\"feat \" .. name .. \": cost (Sorcery Points) is a whole number\") end\r\nif K.FX[name] ~= nil then K.packNote(\"feat \" .. name .. \" is the bot's own\")\r\nelse\r\nK.packPut(K.FX, name, rec)\r\nK.packPut(K.PACK.feat, name, rec.cat)\r\nif rec.ko then K.packPut(NAMES_KO, name, rec.ko) end\r\nlocal key = rec.cat == \"invocation\" and \"invocations\" or \"metamagic\"\r\nif Feat.TIP and Feat.TIP[key] then\r\nK.packPut(Feat.TIP[key], name, (rec.cat == \"metamagic\" and (\"술법 점수 \" .. rec.cost .. \". \") or \"\") .. (rec.tip or \"\"))\r\nend\r\nend\r\nelseif rec.cat == \"origin\" then\r\n\r\n\r\nif K.FX[name] ~= nil then K.packNote(\"feat \" .. name .. \" is the bot's own\")\r\nelse\r\nK.packPut(K.FX, name, rec)\r\nK.packPut(K.PACK.feat, name, \"origin\")\r\nif rec.ko then K.packPut(NAMES_KO, name, rec.ko) end\r\nlocal list = {}\r\nfor _, x in ipairs(Feat.ORIGIN) do list[#list + 1] = x end\r\nlist[#list + 1] = name\r\nK.packPut(Feat, \"ORIGIN\", list)\r\nif Feat.TIP and rec.tip then K.packPut(Feat.TIP.feat, name, rec.tip) end\r\nif Feat.KO and rec.ko then K.packPut(Feat.KO.feat, name, rec.ko) end\r\nend\r\nelseif rec.cat ~= \"style\" then\r\nK.packNote(\"feat \" .. name .. \": \" .. tostring(rec.cat) .. \" is not read yet (style, general, origin, invocation, metamagic)\")\r\nelseif K.FX[name] ~= nil or (Feat.EFFECT and Feat.EFFECT[name] ~= nil) then\r\nK.packNote(\"feat \" .. name .. \" is the bot's own\")\r\nelse\r\nK.packPut(K.FX, name, rec)\r\nK.packPut(K.PACK.feat, name, \"style\")\r\nlocal list = {}\r\nfor _, x in ipairs(Feat.STYLES) do list[#list + 1] = x end\r\nlist[#list + 1] = name\r\nK.packPut(Feat, \"STYLES\", list)\r\nif rec.ko then K.packPut(NAMES_KO, name, rec.ko); K.packPut(Feat.KO.style, name, rec.ko) end\r\nK.packPut(Feat.EFFECT, name, rec.text ~= \"\" and rec.text or \"narrated\")\r\nif Feat.TIP and rec.tip then K.packPut(Feat.TIP.style, name, rec.tip) end\r\nend\r\nend\r\n\r\n\r\n\r\nfor n, row in pairs(type(d.species) == \"table\" and d.species or {}) do\r\nif K.LITE then\r\nK.packNote(\"light build: species \" .. tostring(n) .. \" not loaded\")\r\nelseif type(n) ~= \"string\" or not n:match(\"^%a[%a' %-]*$\") then\r\nerror(\"species \" .. tostring(n) .. \": a name of letters and spaces\")\r\nelseif SPECIES[n] ~= nil and not K.PACK.sp[n] then\r\nK.packNote(\"species \" .. n .. \" is the bot's own\")\r\nelse\r\nif type(row) ~= \"table\" then error(\"species \" .. n .. \": not a table\") end\r\nK.d2check(\"species \" .. n, row)\r\nfor _, k in ipairs({ \"speed\", \"darkvision\", \"hp_per_level\" }) do\r\nif row[k] ~= nil and not tonumber(row[k]) then error(\"species \" .. n .. \": \" .. k .. \" is not a number\") end\r\nend\r\nlocal sz = row.size or \"Medium\"\r\nlocal s1, s2 = tostring(sz):match(\"^(%a+) or (%a+)$\")\r\nif not (K.SIZE_RANK[sz] or (s1 and K.SIZE_RANK[s1] and K.SIZE_RANK[s2])) then error(\"species \" .. n .. \": size \" .. tostring(sz)) end\r\nfor _, k in ipairs({ \"ko\", \"tip\" }) do if row[k] ~= nil and type(row[k]) ~= \"string\" then error(\"species \" .. n .. \": \" .. k .. \" is not text\") end end\r\nif row.fx ~= nil then\r\nif type(row.fx) ~= \"table\" then error(\"species \" .. n .. \": fx is not a list of feature names\") end\r\nfor _, x in ipairs(row.fx) do\r\nif type(x) ~= \"string\" or not ((type(d.fx) == \"table\" and d.fx[x]) or K.FX[x]) then error(\"species \" .. n .. \": no feature record \" .. tostring(x)) end\r\nend\r\nend\r\n\r\nif row.types ~= nil and type(row.types) ~= \"table\" then error(\"species \" .. n .. \": types is a list of creature types\") end\r\nK.packPut(SPECIES, n, { speed = tonumber(row.speed) or 30, darkvision = tonumber(row.darkvision) or 0, hp_per_level = tonumber(row.hp_per_level) or 0,\r\nsize = sz, fx = row.fx, d2 = row.d2, types = row.types })\r\nK.packPut(K.PACK.sp, n, true)\r\nif row.ko then K.packPut(NAMES_KO, n, row.ko) end\r\nif row.tip and K.Cg and K.Cg.TIP and K.Cg.TIP.sp then K.packPut(K.Cg.TIP.sp, n, row.tip) end\r\nend\r\nend\r\n\r\n\r\n\r\nfor n, row in pairs(type(d.implements) == \"table\" and d.implements or {}) do\r\nif type(n) ~= \"string\" or not n:match(\"^%a[%a' %-]*$\") then error(\"implement \" .. tostring(n) .. \": a name of letters and spaces\") end\r\nif type(row) ~= \"table\" then error(\"implement \" .. n .. \": not a table\") end\r\n\r\nif row.kind ~= \"body\" and row.kind ~= \"tool\" and row.kind ~= \"natural\" then error(\"implement \" .. n .. \": kind body, tool or natural\") end\r\nif not (row.ability == \"finesse\" or ({ Strength = 1, Dexterity = 1, Constitution = 1, Intelligence = 1, Wisdom = 1, Charisma = 1 })[row.ability or \"\"]) then\r\nerror(\"implement \" .. n .. \": ability \" .. tostring(row.ability))\r\nend\r\n\r\nif type(row.dice) ~= \"string\" or not row.dice:match(\"^%d*d%d+$\") then error(\"implement \" .. n .. \": dice \" .. tostring(row.dice) .. \" (like 1d4)\") end\r\nif not K.DTYPES[tostring(row.type or \"\"):lower()] then error(\"implement \" .. n .. \": type \" .. tostring(row.type) .. \" (a damage type)\") end\r\nfor _, k in ipairs({ \"ko\", \"tip\" }) do if row[k] ~= nil and type(row[k]) ~= \"string\" then error(\"implement \" .. n .. \": \" .. k .. \" is not text\") end end\r\nif row.magical ~= nil and type(row.magical) ~= \"boolean\" then error(\"implement \" .. n .. \": magical is true or false\") end\r\nif row.phallic ~= nil and type(row.phallic) ~= \"boolean\" then error(\"implement \" .. n .. \": phallic is true or false\") end\r\nif row.reciprocal ~= nil and type(row.reciprocal) ~= \"boolean\" then error(\"implement \" .. n .. \": reciprocal is true or false\") end\r\n\r\n\r\nfor _, k in ipairs({ \"precise\", \"sturdy\" }) do\r\nif row[k] ~= nil and not (type(row[k]) == \"string\" and row[k]:match(\"^%d*d%d+$\")) then error(\"implement \" .. n .. \": \" .. k .. \" is dice like 2d6\") end\r\nend\r\nfor _, k in ipairs({ \"two_handed\", \"persistent\" }) do if row[k] ~= nil and type(row[k]) ~= \"boolean\" then error(\"implement \" .. n .. \": \" .. k .. \" is true or false\") end end\r\nif row.say ~= nil and type(row.say) ~= \"string\" then error(\"implement \" .. n .. \": say is text\") end\r\nK.d2check(\"implement \" .. n, row)\r\nK.packPut(K.PACK.impl, n, row)\r\nif row.ko then K.packPut(NAMES_KO, n, row.ko) end\r\nif row.tip then\r\nif Feat.TIP.imptools == nil then K.packPut(Feat.TIP, \"imptools\", {}) end\r\nK.packPut(Feat.TIP.imptools, n, row.tip)\r\nend\r\nend\r\n\r\n\r\n\r\nfor n, row in pairs(type(d.conds) == \"table\" and d.conds or {}) do\r\nif type(n) ~= \"string\" or not n:match(\"^%a[%a' %-]*$\") then error(\"cond \" .. tostring(n) .. \": a name of letters and spaces\") end\r\nif type(row) ~= \"table\" then error(\"cond \" .. n .. \": not a table\") end\r\nif CONDS[n] and not CONDS[n].pack then error(\"cond \" .. n .. \" is an SRD condition\") end\r\nif row.willing ~= nil and row.willing ~= \"all\" and row.willing ~= \"source\" then error(\"cond \" .. n .. \": willing all or source\") end\r\nif row.climax ~= nil and row.climax ~= \"block\" then error(\"cond \" .. n .. \": climax block\") end\r\nif row.inhib_max ~= nil and not tonumber(row.inhib_max) then error(\"cond \" .. n .. \": inhib_max is a number\") end\r\n\r\nif row.advance_crit ~= nil and type(row.advance_crit) ~= \"boolean\" and type(row.advance_crit) ~= \"table\" then error(\"cond \" .. n .. \": advance_crit is true or { names, kinds }\") end\r\nif row.stim_type ~= nil and not K.DMG_KO[row.stim_type] then error(\"cond \" .. n .. \": stim_type is a damage type\") end\r\n\r\nif row.advance_stim ~= nil and not (type(row.advance_stim) == \"table\" and type(row.advance_stim.dice) == \"string\"\r\nand row.advance_stim.dice:match(\"^%d*d%d+$\") and K.DMG_KO[row.advance_stim.type or \"\"]) then\r\nerror(\"cond \" .. n .. \": advance_stim is { dice = \\\"1d4\\\", type = a damage type }\")\r\nend\r\n\r\nif row.preg ~= nil and row.preg ~= \"adv\" and row.preg ~= \"block\" and row.preg ~= \"auto\" then error(\"cond \" .. n .. \": preg adv, block or auto\") end\r\nif row.preg_ward or row.preg_any then K.packPut(K.PACK, \"preg\", true) end\r\nif row.preg_dc ~= nil and not tonumber(row.preg_dc) then error(\"cond \" .. n .. \": preg_dc is a number\") end\r\nif row.preg or row.preg_dc then K.packPut(K.PACK, \"preg\", true) end\r\nif row.bind then K.packPut(K.PACK, \"bindable\", true) end\r\nfor _, k in ipairs({ \"has\", \"dis_saves\" }) do if row[k] ~= nil and type(row[k]) ~= \"table\" then error(\"cond \" .. n .. \": \" .. k .. \" is a list\") end end\r\n\r\n\r\n\r\nfor _, k in ipairs({ \"auto_fail\", \"dis_checks\" }) do\r\nif row[k] ~= nil and type(row[k]) ~= \"table\" then error(\"cond \" .. n .. \": \" .. k .. \" is a list\") end\r\nfor _, ab in ipairs(row[k] or {}) do if not ({ Strength = 1, Dexterity = 1, Constitution = 1, Intelligence = 1, Wisdom = 1, Charisma = 1 })[ab] then error(\"cond \" .. n .. \": \" .. k .. \": \" .. tostring(ab) .. \" is not an ability\") end end\r\nend\r\nif row.speed ~= nil and not (tonumber(row.speed) and tonumber(row.speed) >= 0) then error(\"cond \" .. n .. \": speed is a number of feet\") end\r\nfor _, k in ipairs({ \"adv_vs\", \"own_dis\", \"no_fly\", \"no_verbal\", \"no_somatic\", \"no_breathe\", \"no_hostile\" }) do if row[k] ~= nil and type(row[k]) ~= \"boolean\" then error(\"cond \" .. n .. \": \" .. k .. \" is true or false\") end end\r\nif row.auto_fail or row.speed or row.no_verbal or row.no_somatic or row.no_breathe or row.adv_vs then K.packPut(K.PACK, \"bind\", true) end\r\nfor _, k in ipairs({ \"ko\", \"tip\", \"text\" }) do if row[k] ~= nil and type(row[k]) ~= \"string\" then error(\"cond \" .. n .. \": \" .. k .. \" is not text\") end end\r\nK.d2check(\"cond \" .. n, row)\r\nK.packPut(CONDS, n, { pack = row, incapacitated = row.incap and true or nil, auto_fail_saves = row.auto_fail,\r\nspeed = tonumber(row.speed) == 0 and 0 or nil, speedCap = tonumber(row.speed), no_hostile = row.no_hostile or nil })\r\nif row.ko then K.packPut(NAMES_KO, n, row.ko) end\r\nend\r\n\r\n\r\n\r\nfor n, row in pairs(type(d.afflictions) == \"table\" and d.afflictions or {}) do\r\nif type(n) ~= \"string\" or not n:match(\"^%a[%a' %-,]*$\") then error(\"affliction \" .. tostring(n) .. \": a name of letters and spaces\") end\r\nif type(row) ~= \"table\" then error(\"affliction \" .. n .. \": not a table\") end\r\nif K.FX[n] and not (K.PACK.afflict and K.PACK.afflict[n]) then error(\"affliction \" .. n .. \": the name of a feature already\") end\r\nlocal kinds = { curse = 1, brand = 1, fetish = 1, vice = 1 }\r\nif not kinds[row.kind or \"\"] then error(\"affliction \" .. n .. \": kind curse, brand, fetish or vice\") end\r\nif row.level ~= nil and not tonumber(row.level) then error(\"affliction \" .. n .. \": level is a number\") end\r\nif row[\"end\"] ~= nil and not ({ remove_curse = 1, wish = 1, never = 1 })[row[\"end\"]] then error(\"affliction \" .. n .. \": end remove_curse, wish or never\") end\r\nfor _, k in ipairs({ \"conds\", \"fx\", \"neg\" }) do if row[k] ~= nil and type(row[k]) ~= \"table\" then error(\"affliction \" .. n .. \": \" .. k .. \" is a list\") end end\r\nif row.vice ~= nil and (type(row.vice) ~= \"table\" or row.kind ~= \"vice\") then error(\"affliction \" .. n .. \": vice { save, dc, type, withdrawal } on a vice\") end\r\nK.d2check(\"affliction \" .. n, row)\r\nlocal rec = {}\r\nfor k, v in pairs(row) do rec[k] = v end\r\n\r\nfor _, part in ipairs({ row.fx or {}, row.neg or {} }) do\r\nfor _, e in ipairs(part) do\r\nif type(e) == \"table\" and e.t == \"heal_source\" then K.packPut(HEAL_SRC, e.name or n, { dmg = e.formula, pool = e.use, packFx = e.name or n, dice_at = e.dice_at,\r\nselfOnly = e.self, after = e.after, nonmagical = e.nonmagical }) end\r\nend\r\nend\r\nrec.fx = type(row.fx) == \"table\" and row.fx or {}\r\nif rec.text == nil then rec.text = \"\" end\r\nif K.PACK.afflict == nil then K.packPut(K.PACK, \"afflict\", {}) end\r\nK.packPut(K.FX, n, rec)\r\nK.packPut(K.PACK.afflict, n, rec)\r\nif row.ko then K.packPut(NAMES_KO, n, row.ko) end\r\nif row.kind == \"fetish\" then\r\nif Feat.TITLE.fetish == nil then\r\nK.packPut(Feat.TITLE, \"fetish\", \"페티시\")\r\nK.packPut(Feat.TITLE, \"fetishon\", \"켠 페티시\")\r\nK.packPut(Feat.WAIT_NAME, \"fetish\", \"Fetishes (the sexual history's)\")\r\nK.packPut(Feat.WAIT_NAME, \"fetishon\", \"Fetishes that are on\")\r\nK.packPut(Feat.TIP, \"fetish\", {})\r\nK.packPut(Feat.TIP, \"fetishon\", {})\r\nend\r\nlocal tip = (row.tip or \"\") .. ((type(row.neg_tip) == \"string\" and row.neg_tip ~= \"\") and (\" 단점: \" .. row.neg_tip) or \"\")\r\nif tip ~= \"\" then K.packPut(Feat.TIP.fetish, n, tip); K.packPut(Feat.TIP.fetishon, n, tip) end\r\nend\r\nend\r\n\r\n\r\n\r\n\r\nlocal RW = { Common = \"C\", Uncommon = \"B\", Rare = \"A\", [\"Very Rare\"] = \"S\", Legendary = \"L\", Artifact = \"X\" }\r\nlocal AB = { STR = 1, DEX = 1, CON = 1, INT = 1, WIS = 1, CHA = 1, Strength = 1, Dexterity = 1, Constitution = 1, Intelligence = 1, Wisdom = 1, Charisma = 1 }\r\nfor n, row in pairs(type(d.items) == \"table\" and d.items or {}) do\r\nif type(n) ~= \"string\" or n == \"\" then error(\"item: a name\") end\r\nif type(row) ~= \"table\" then error(\"item \" .. n .. \": not a table\") end\r\nlocal rec = {}\r\nfor k, v in pairs(row) do rec[k] = v end\r\nrec.pack = true\r\nif rec.r ~= nil then\r\nrec.r = RW[rec.r] or rec.r\r\nif not ({ C = 1, B = 1, A = 1, S = 1, L = 1, X = 1 })[rec.r] then error(\"item \" .. n .. \": r C, B, A, S, L or X\") end\r\nelseif rec.cost ~= nil then\r\nif type(rec.cost) ~= \"string\" then error(\"item \" .. n .. \": cost is text like 5 GP\") end\r\nrec.r, rec.mundane = \"C\", true\r\nelse error(\"item \" .. n .. \": r or cost\") end\r\nif rec.var ~= nil then\r\nif type(rec.var) ~= \"table\" then error(\"item \" .. n .. \": var is a table\") end\r\nlocal v2 = {}\r\nfor k, v in pairs(rec.var) do\r\nif type(v) == \"string\" then v2[k] = RW[v] or v\r\nelseif type(v) == \"table\" then\r\nlocal c2 = {}\r\nfor kk, vv in pairs(v) do c2[kk] = vv end\r\nif c2.r then c2.r = RW[c2.r] or c2.r end\r\nv2[k] = c2\r\nelse error(\"item \" .. n .. \": var \" .. tostring(k)) end\r\nend\r\nrec.var = v2\r\nend\r\nfor _, k in ipairs({ \"pw\", \"sp\", \"fx\", \"wear\" }) do if rec[k] ~= nil and type(rec[k]) ~= \"table\" then error(\"item \" .. n .. \": \" .. k .. \" is a list\") end end\r\nif rec.fx ~= nil then K.fxCheck(\"item \" .. n, { fx = rec.fx }) end\r\nfor _, e in ipairs(type(rec.fx) == \"table\" and rec.fx or {}) do\r\nif type(e) == \"table\" and e.t == \"heal_source\" then K.packPut(HEAL_SRC, e.name or n, { dmg = e.formula, pool = e.use, packFx = e.name or n, dice_at = e.dice_at,\r\nselfOnly = e.self, after = e.after, nonmagical = e.nonmagical }) end\r\nend\r\nfor _, w in ipairs(rec.wear or {}) do if type(w) ~= \"string\" then error(\"item \" .. n .. \": wear is a list of condition names\") end end\r\nif rec.implement ~= nil then\r\nlocal im = rec.implement\r\nif type(im) ~= \"table\" or type(im.as) ~= \"string\" then error(\"item \" .. n .. \": implement { as, plus, dice, type }\") end\r\nif im.plus ~= nil and im.plus ~= \"var\" and not tonumber(im.plus) then error(\"item \" .. n .. \": implement plus is a number or var\") end\r\nif im.dice ~= nil and not (type(im.dice) == \"string\" and im.dice:match(\"^%d*d%d+$\")) then error(\"item \" .. n .. \": implement dice like 1d8\") end\r\nif im.type ~= nil and not K.DTYPES[tostring(im.type):lower()] then error(\"item \" .. n .. \": implement type is a damage type\") end\r\nend\r\nif rec.afflict ~= nil and not (type(rec.afflict) == \"table\" and type(rec.afflict.name) == \"string\" and ({ attune = 1, use = 1, equip = 1 })[rec.afflict.when or \"\"]) then\r\nerror(\"item \" .. n .. \": afflict { name, when attune / use / equip }\")\r\nend\r\nif rec.cursed ~= nil and type(rec.cursed) ~= \"boolean\" then error(\"item \" .. n .. \": cursed is true or false\") end\r\nfor _, sp in ipairs(rec.sp or {}) do\r\n\r\n\r\nif type(sp) == \"table\" and type(sp.s) == \"table\" then\r\nfor _, x in ipairs(sp.s) do if type(x) ~= \"string\" then error(\"item \" .. n .. \": sp s is a spell or a list of spells\") end end\r\nif #sp.s == 0 then error(\"item \" .. n .. \": sp s is an empty list\") end\r\nsp.alts, sp.s = sp.s, sp.s[1]\r\nend\r\nif type(sp) ~= \"table\" or type(sp.s) ~= \"string\" then error(\"item \" .. n .. \": sp is a list of { s = spell }\") end\r\nif sp.ab ~= nil and not AB[sp.ab] then error(\"item \" .. n .. \": sp ab is an ability\") end\r\nif sp.rest ~= nil and sp.rest ~= \"short\" and sp.rest ~= \"long\" then error(\"item \" .. n .. \": sp rest short or long\") end\r\nend\r\nif type(rec.ch) == \"table\" and rec.ch.regain_on ~= nil and rec.ch.regain_on ~= \"climax\" then error(\"item \" .. n .. \": ch regain_on climax\") end\r\nK.d2check(\"item \" .. n, row)\r\nif K.MAGIC == nil then K.MAGIC = {} end\r\nK.packPut(K.MAGIC, n, rec)\r\nif row.ko then K.packPut(NAMES_KO, n, row.ko) end\r\nend\r\n\r\nfor n, row in pairs(type(d.bonds) == \"table\" and d.bonds or {}) do\r\nif type(n) ~= \"string\" or type(row) ~= \"table\" then error(\"bonds: { Name = { cond, escape, break } }\") end\r\nfor _, k in ipairs({ \"escape\", \"break\", \"hp\" }) do if row[k] ~= nil and not tonumber(row[k]) then error(\"bond \" .. n .. \": \" .. k .. \" is a number\") end end\r\nif row.cond ~= nil and type(row.cond) ~= \"string\" then error(\"bond \" .. n .. \": cond is a condition's name\") end\r\nK.d2check(\"bond \" .. n, row)\r\nif K.PACK.bonds == nil then K.packPut(K.PACK, \"bonds\", {}) end\r\nK.packPut(K.PACK.bonds, n, row)\r\nK.packPut(K.PACK, \"bind\", true)\r\nif row.ko then K.packPut(NAMES_KO, n, row.ko) end\r\nend\r\n\r\n\r\nif d.preg_compat ~= nil then\r\nif type(d.preg_compat) ~= \"table\" then error(\"preg_compat is not a table\") end\r\nK.packPut(K.PACK, \"pregCompat\", K.PACK.pregCompat or {})\r\nfor t1, row in pairs(d.preg_compat) do\r\nif type(row) ~= \"table\" then error(\"preg_compat \" .. tostring(t1) .. \": not a table\") end\r\nfor t2, v in pairs(row) do\r\nlocal w = ({ T = \"traditional\", N = \"nontraditional\", traditional = \"traditional\", nontraditional = \"nontraditional\", none = \"none\" })[v]\r\nif not w then error(\"preg_compat \" .. t1 .. \"/\" .. tostring(t2) .. \": T or N\") end\r\nK.PACK.pregCompat[t1 .. \"|\" .. t2] = w\r\nend\r\nend\r\nK.packPut(K.PACK, \"preg\", true)\r\nend\r\n\r\n\r\nif d.arousal ~= nil then\r\nif type(d.arousal) ~= \"table\" then error(\"arousal is not a table\") end\r\nif not K.PACK.ar then\r\nK.packPut(K.PACK, \"ar\", { hist = {} })\r\n\r\nK.packPut(Feat.TITLE, \"sexhist\", \"성적 이력\")\r\nK.packPut(Feat.TITLE, \"imptools\", \"성적 도구 숙련\")\r\nK.packPut(Feat.WAIT_NAME, \"imptools\", \"Implement proficiencies (the sexual history's)\")\r\nif Feat.TIP.imptools == nil then K.packPut(Feat.TIP, \"imptools\", {}) end\r\nK.packPut(Feat.TITLE, \"inhib\", \"억제 능력치\")\r\nK.packPut(Feat.WAIT_NAME, \"inhib\", \"Inhibition ability (the climax save's bonus)\")\r\nK.packPut(Feat.TIP, \"inhib\", { Intelligence = \"지능 수정치가 억제 보너스가 됩니다(절정 내성 등).\", Wisdom = \"지혜 수정치가 억제 보너스가 됩니다(절정 내성 등).\",\r\nCharisma = \"매력 수정치가 억제 보너스가 됩니다(절정 내성 등).\" })\r\nK.packPut(Feat.WAIT_NAME, \"sexhist\", \"Sexual history (the recovery die)\")\r\nK.packPut(Feat.KO, \"sexhist\", {})\r\nK.packPut(Feat.TIP, \"sexhist\", {})\r\nend\r\nfor n, h in pairs(type(d.arousal.histories) == \"table\" and d.arousal.histories or {}) do\r\nif type(n) ~= \"string\" or not n:match(\"^%a[%a' %-]*$\") then error(\"arousal: history \" .. tostring(n) .. \" (letters and spaces)\") end\r\nif type(h) ~= \"table\" or not ({ [6] = true, [8] = true, [10] = true, [12] = true })[tonumber(h.die) or 0] then error(\"arousal: history \" .. n .. \": die 6, 8, 10 or 12\") end\r\nfor _, k in ipairs({ \"ko\", \"tip\" }) do if h[k] ~= nil and type(h[k]) ~= \"string\" then error(\"arousal: history \" .. n .. \": \" .. k .. \" is not text\") end end\r\n\r\n\r\nif h.tools ~= nil and not (tonumber(h.tools) and h.tools >= 0 and h.tools <= 8 and h.tools == math.floor(h.tools)) then error(\"arousal: history \" .. n .. \": tools 0-8\") end\r\nif h.no_body_prof ~= nil and type(h.no_body_prof) ~= \"boolean\" then error(\"arousal: history \" .. n .. \": no_body_prof is true or false\") end\r\nif h.body_prof ~= nil and type(h.body_prof) ~= \"table\" then error(\"arousal: history \" .. n .. \": body_prof is a list of implement names\") end\r\n\r\nif h.fetish ~= nil and (type(h.fetish) ~= \"table\" or not tonumber(h.fetish.n) or (h.fetish.on ~= nil and not tonumber(h.fetish.on))\r\nor (h.fetish.one_of ~= nil and type(h.fetish.one_of) ~= \"table\")) then error(\"arousal: history \" .. n .. \": fetish { n, on, one_of }\") end\r\n\r\nif h.xp ~= nil and not (tonumber(h.xp) and h.xp >= 0) then error(\"arousal: history \" .. n .. \": xp is a number, 0 or more\") end\r\nK.packPut(K.PACK.ar.hist, n, h)\r\nif h.ko then K.packPut(NAMES_KO, n, h.ko); K.packPut(Feat.KO.sexhist, n, h.ko) end\r\nK.packPut(Feat.TIP.sexhist, n, \"회복 주사위 d\" .. tonumber(h.die) .. (h.tip and (\". \" .. h.tip) or \".\"))\r\nend\r\nif d.arousal.text ~= nil then\r\nif type(d.arousal.text) ~= \"string\" then error(\"arousal: text is not text\") end\r\nK.packPut(K.PACK.ar, \"text\", d.arousal.text)\r\nend\r\nend\r\nfor en, ko in pairs(type(d.names) == \"table\" and d.names or {}) do\r\nK.packPut(NAMES_KO, en, ko)\r\n\r\n\r\nif type(en) == \"string\" and en:find(\"%a\") then\r\nK.packPut(K.PACK.nn, #K.PACK.nn + 1, en)\r\nK.PACK.nnw = K.PACK.nnw or {}\r\nK.packPut(K.PACK.nnw, en, true)\r\nend\r\nend\r\nfor cl, x in pairs(type(d.classes) == \"table\" and d.classes or {}) do\r\nlocal c = CLASSES[cl]\r\nif not c then K.packNote(\"class \" .. cl .. \" is not in this bot (a new class goes under class_defs)\") end\r\nif c and type(x) == \"table\" then\r\nfor lv, row in pairs(type(x.levels) == \"table\" and x.levels or {}) do K.packPut(c.levels, tonumber(lv), row) end\r\nif type(x.always) == \"table\" then\r\nif not c.always then K.packPut(c, \"always\", {}) end\r\nfor lv, list in pairs(x.always) do K.packPut(c.always, tostring(lv), list) end\r\nend\r\n\r\nfor n, rec in pairs(type(x.subclasses) == \"table\" and x.subclasses or {}) do\r\nif K.LITE then\r\nK.packNote(\"light build: subclass \" .. tostring(n) .. \" not loaded\")\r\nelseif type(c.subclasses) == \"table\" and c.subclasses[n] ~= nil and not K.PACK.sub[cl .. \"|\" .. tostring(n)] then\r\nK.packNote(\"subclass \" .. tostring(n) .. \" is the bot's own\")\r\nelse\r\nK.subCheck(cl, n, rec, d)\r\n\r\nif rec.spellcasting ~= nil then\r\nlocal sc = rec.spellcasting\r\nif type(sc) ~= \"table\" or not ({ Strength = 1, Dexterity = 1, Constitution = 1, Intelligence = 1, Wisdom = 1, Charisma = 1 })[sc.ability or \"\"] then\r\nerror(\"class \" .. cl .. \": subclass \" .. n .. \": spellcasting { ability, list, caster }\")\r\nend\r\nif type(sc.list) == \"string\" then lists[#lists + 1] = { cl, sc.list } end\r\nend\r\nif type(c.subclasses) ~= \"table\" then K.packPut(c, \"subclasses\", {}) end\r\nK.packPut(c.subclasses, n, rec)\r\nK.packPut(K.PACK.sub, cl .. \"|\" .. n, true)\r\nif rec.ko then K.packPut(NAMES_KO, n, tostring(rec.ko)) end\r\nend\r\nend\r\nend\r\nend\r\nfor _, kind in ipairs({ { \"spells\", SPELLS }, { \"monsters\", MONSTERS }, { \"backgrounds\", BACKGROUNDS } }) do\r\nfor n, row in pairs(type(d[kind[1]]) == \"table\" and d[kind[1]] or {}) do\r\n\r\n\r\nif (kind[1] == \"spells\" or kind[1] == \"backgrounds\") and type(row) == \"table\" then K.d2check(kind[1]:sub(1, -2) .. \" \" .. tostring(n), row) end\r\n\r\n\r\nif kind[1] == \"spells\" and type(row) == \"table\" then row.fromPack, row.fromAdult = true, (K.PACK.curAdult or row.d2 ~= nil) or nil end\r\n\r\nif kind[1] == \"backgrounds\" and type(row) == \"table\" and row.tip ~= nil and type(row.tip) ~= \"string\" then error(\"background \" .. tostring(n) .. \": tip is text\") end\r\nif kind[1] == \"backgrounds\" and type(row) == \"table\" and row.fx ~= nil then\r\n\r\nif type(row.fx) ~= \"table\" then error(\"background \" .. tostring(n) .. \": fx is not a list of feature names\") end\r\nfor _, x in ipairs(row.fx) do\r\nif type(x) ~= \"string\" or not ((type(d.fx) == \"table\" and d.fx[x]) or K.FX[x]) then error(\"background \" .. tostring(n) .. \": no feature record \" .. tostring(x)) end\r\nend\r\nend\r\n\r\nif kind[1] == \"spells\" and type(row) == \"table\" and type(row.m) == \"table\" and row.m.summon ~= nil then\r\nlocal ps = row.m.summon\r\nif type(ps) ~= \"table\" or type(ps.kind) ~= \"string\" or type(ps.st) ~= \"table\" then error(\"spell \" .. tostring(n) .. \": m.summon { kind, st { ac, hp, attacks } }\") end\r\nif ps.choices ~= nil and type(ps.choices) ~= \"table\" then error(\"spell \" .. tostring(n) .. \": m.summon choices is a list\") end\r\n\r\nif ps.by_choice ~= nil and type(ps.by_choice) ~= \"table\" then error(\"spell \" .. tostring(n) .. \": m.summon by_choice { Kind = { ac, hp, attacks ... } }\") end\r\nfor k, v in pairs(type(ps.by_choice) == \"table\" and ps.by_choice or {}) do\r\nif type(v) ~= \"table\" then error(\"spell \" .. tostring(n) .. \": m.summon by_choice \" .. tostring(k) .. \" is not a table\") end\r\nlocal okc = type(ps.choices) ~= \"table\"\r\nfor _, x in ipairs(type(ps.choices) == \"table\" and ps.choices or {}) do if x == k then okc = true end end\r\nif not okc then error(\"spell \" .. tostring(n) .. \": m.summon by_choice \" .. tostring(k) .. \" is not one of its choices\") end\r\nend\r\nK.packPut(K.SUMMON, n, { packSummon = ps, conc = row.m.concentration and true or nil, mins = tonumber(row.mins), one = true })\r\nend\r\nK.packPut(kind[2], n, row)\r\nend\r\nend\r\nreturn lists\r\nend\r\n\r\n\r\n\r\nfunction K.fxCheck(name, rec)\r\nlocal function bad(what) error(\"fx \" .. tostring(name) .. \": \" .. what) end\r\nif type(rec) ~= \"table\" then bad(\"not a table\") end\r\nif rec.fx == nil then rec.fx = {} end\r\nif type(rec.fx) ~= \"table\" then bad(\"fx is not a list\") end\r\n\r\nlocal function num(v) return v == nil or tonumber(v) or (type(v) == \"string\" and v:match(\"^[%u%d+*/| ]+$\")) end\r\nfor i, e in ipairs(rec.fx) do\r\nif type(e) ~= \"table\" or type(e.t) ~= \"string\" then bad(\"fx \" .. i .. \" is not an effect { t = ... }\") end\r\n\r\n\r\nif e[\"while\"] ~= nil and type(e[\"while\"]) ~= \"string\" then bad(\"fx \" .. i .. \": while is a mode's name\") end\r\nif e.t == \"choice\" and e.on_use ~= nil and type(e.on_use) ~= \"string\" then bad(\"fx \" .. i .. \": on_use is a use's name\") end\r\n\r\n\r\nif e.t == \"choice\" and ((e.count ~= nil and not num(e.count)) or (e.count_at ~= nil and type(e.count_at) ~= \"table\") or (e.title ~= nil and type(e.title) ~= \"string\")) then\r\nbad(\"fx \" .. i .. \": choice count (a term), count_at {level = n}, title (text)\")\r\nend\r\n\r\n\r\nif e.to ~= nil and not tonumber(e.to) then bad(\"fx \" .. i .. \": to is a level\") end\r\nif e.t == \"weapon_die\" and e.res ~= nil and type(e.res) ~= \"string\" then bad(\"fx \" .. i .. \": weapon_die res is a use's name\") end\r\nif e.t == \"weapon_die\" and e.cost ~= nil and not tonumber(e.cost) then bad(\"fx \" .. i .. \": weapon_die cost is a number\") end\r\n\r\n\r\nif e.t == \"dmg_add\" and (e.n == nil or not num(e.n)) then bad(\"fx \" .. i .. \": dmg_add n \" .. tostring(e.n)) end\r\n\r\nif e.t == \"d20_floor\" and (not tonumber(e.value) or (e.on ~= nil and not ({ proficient_check = 1, all = 1, checks = 1, saves = 1, attacks = 1, conc = 1 })[e.on])\r\nor (e.abilities ~= nil and type(e.abilities) ~= \"table\")) then\r\nbad(\"fx \" .. i .. \": d20_floor value, on (proficient_check, all, checks, saves, attacks, conc), abilities\")\r\nend\r\nif e.t == \"dtype_swap\" then\r\nlocal tos = type(e.into) == \"table\" and e.into or { e.into }\r\nfor _, ty in ipairs(tos) do if not (type(ty) == \"string\" and K.DTYPES[ty:lower()]) then bad(\"fx \" .. i .. \": dtype_swap into \" .. tostring(ty)) end end\r\nif not (e.spells or e.form or e.unarmed) then bad(\"fx \" .. i .. \": dtype_swap spells (a class's list or names), form or unarmed\") end\r\nif e.spells ~= nil and type(e.spells) ~= \"string\" and type(e.spells) ~= \"table\" then bad(\"fx \" .. i .. \": dtype_swap spells\") end\r\nend\r\nif e.t == \"d20_luck\" and (type(e.dice) ~= \"string\" or not e.dice:match(\"^1?d%d+$\") or (e.word ~= nil and not tostring(e.word):match(\"^%a+$\"))) then\r\nbad(\"fx \" .. i .. \": d20_luck dice 1d4, word (letters)\")\r\nend\r\nif e.t == \"portent\" and ((e.n ~= nil and not tonumber(e.n)) or (e.n_at ~= nil and type(e.n_at) ~= \"table\")) then bad(\"fx \" .. i .. \": portent n, n_at\") end\r\nif e.t == \"up_half\" then e.use = e.use or name end\r\nif e.t == \"armor_prof\" then\r\nif type(e.cats) ~= \"table\" then bad(\"fx \" .. i .. \": armor_prof cats [light, medium, heavy, shield]\") end\r\nfor _, c in ipairs(e.cats) do if not ({ light = 1, medium = 1, heavy = 1, shield = 1 })[c] then bad(\"fx \" .. i .. \": armor_prof cat \" .. tostring(c)) end end\r\nend\r\nif e.t == \"weapon_prof\" and not (e.martial == true or type(e.weapons) == \"table\") then bad(\"fx \" .. i .. \": weapon_prof martial or weapons\") end\r\nif e.t == \"armor_dex\" and (type(e.cat) ~= \"string\" or not tonumber(e.max)) then bad(\"fx \" .. i .. \": armor_dex cat, max\") end\r\nif e.t == \"armor_reduce\" and (e.n == nil or not num(e.n) or (e.types ~= nil and type(e.types) ~= \"table\") or (e.armor ~= nil and type(e.armor) ~= \"string\")) then\r\nbad(\"fx \" .. i .. \": armor_reduce n, armor, types\")\r\nend\r\nif e.t == \"unarmed_die\" and (type(e.dice) ~= \"string\" or (e.ability ~= nil and not ({ STR = 1, DEX = 1, best = 1 })[e.ability])) then\r\nbad(\"fx \" .. i .. \": unarmed_die dice, ability STR / DEX / best\")\r\nend\r\nif e.t == \"feature_weapon\" and (type(e.name) ~= \"string\" or type(e.dice) ~= \"string\" or type(e.type) ~= \"string\" or (e.bonus ~= nil and type(e.bonus) ~= \"table\")\r\nor (e.ability ~= nil and e.ability ~= \"DEX\" and e.ability ~= \"STR\" and e.ability ~= \"SPELL\")) then\r\nbad(\"fx \" .. i .. \": feature_weapon name, dice, type, ability (STR, DEX or SPELL), bonus { dice }\")\r\nend\r\n\r\nlocal function skills(v) if type(v) ~= \"table\" then return false end; for _, x in ipairs(v) do if not SKILL[x] then return false end end; return true end\r\nif e.t == \"check_fail\" and (not skills(e.skills) or (e.story ~= nil and type(e.story) ~= \"boolean\")) then bad(\"fx \" .. i .. \": check_fail skills (a list of skills), story (true)\") end\r\nif e.t == \"self_damage\" and e.type ~= nil and not K.DTYPES[tostring(e.type):lower()] then bad(\"fx \" .. i .. \": self_damage type is a damage type\") end\r\nif e.t == \"use_pick\" and (type(e.use) ~= \"string\" or type(e.key) ~= \"string\" or (e.kind ~= nil and e.kind ~= \"skill\" and e.kind ~= \"spell\")\r\nor (e.max_level ~= nil and not num(e.max_level))) then bad(\"fx \" .. i .. \": use_pick use, key, kind (skill or spell), max_level (a term)\") end\r\nif e.t == \"skill_fix\" and not (skills(e.skills) or type(e.pick) == \"string\") then bad(\"fx \" .. i .. \": skill_fix skills (a list) or pick (a key)\") end\r\nif e.t == \"unskilled_pb\" and ((e.die ~= nil and not tonumber(e.die)) or (e.need ~= nil and not tonumber(e.need))) then bad(\"fx \" .. i .. \": unskilled_pb die, need (numbers)\") end\r\nif e.t == \"ac_bonus\" and (e.n == nil or not num(e.n)) then bad(\"fx \" .. i .. \": ac_bonus n (a number or a term: PB/2)\") end\r\nif e.t == \"ar_die\" and not tonumber(e.die) then bad(\"fx \" .. i .. \": ar_die die (12)\") end\r\nif e.t == \"use_gain\" and (type(e.use) ~= \"string\" or type(e.res) ~= \"string\" or (e.cond ~= nil and type(e.cond) ~= \"string\")) then bad(\"fx \" .. i .. \": use_gain use, res, cond\") end\r\nif e.t == \"rest_no_hp\" and e.rests ~= nil and type(e.rests) ~= \"table\" then bad(\"fx \" .. i .. \": rest_no_hp rests (short, long)\") end\r\nif e.t == \"preg_multi\" and ((e.max ~= nil and not num(e.max)) or (e.distinct ~= nil and type(e.distinct) ~= \"boolean\")) then\r\nbad(\"fx \" .. i .. \": preg_multi max (a number or a term: PB), distinct (true or false)\")\r\nend\r\nif e.t == \"heal_source\" and (e.formula ~= nil or e.name ~= nil) then\r\n\r\n\r\n\r\nif type(e.formula) ~= \"string\" or not e.formula:match(\"^[%dd%u+%-| ]+$\") then bad(\"heal_source formula \" .. tostring(e.formula)) end\r\nif e.after ~= nil and e.after ~= \"heal_slot\" then bad(\"heal_source after heal_slot\") end\r\nif e.dice_at ~= nil and type(e.dice_at) ~= \"table\" then bad(\"heal_source dice_at is a list of levels\") end\r\nend\r\nif e.t == \"mode\" then\r\ne.use = e.use or name\r\n\r\nif (Feat.MODES and Feat.MODES[e.use]) or ({ [\"Wild Shape\"] = true, [\"Bardic Inspiration\"] = true, [\"Healer's Kit\"] = true })[e.use] then\r\nbad(\"mode \" .. e.use .. \" is the bot's own\")\r\nend\r\nfor _, k in ipairs({ \"hit\", \"dmg\", \"ac\" }) do if not num(e[k]) then bad(\"mode \" .. k .. \" \" .. tostring(e[k])) end end\r\n\r\nif e.scope ~= nil and not ({ weapon = true, melee = true, ranged = true, str = true, all = true })[e.scope] then bad(\"mode scope \" .. tostring(e.scope)) end\r\nif e.resist ~= nil and type(e.resist) ~= \"table\" then bad(\"mode resist is not a list\") end\r\nfor _, k in ipairs({ \"res\", \"on\" }) do if e[k] ~= nil and type(e[k]) ~= \"string\" then bad(\"mode \" .. k .. \" is not text\") end end\r\nif e.incap_ends ~= nil and type(e.incap_ends) ~= \"boolean\" then bad(\"mode incap_ends is true or false\") end\r\nelseif e.t == \"on_kill\" then\r\nif e.thp == nil or not num(e.thp) then bad(\"on_kill thp \" .. tostring(e.thp)) end\r\nelseif e.t == \"use_buff\" then\r\n\r\ne.use = e.use or name\r\nif type(e.pool) ~= \"string\" then bad(\"use_buff pool (the use it spends) is not text\") end\r\nif e.n ~= nil and not tonumber(e.n) then bad(\"use_buff n is not a number\") end\r\nif e.mins ~= nil and not tonumber(e.mins) then bad(\"use_buff mins is not a number\") end\r\nif e.note ~= nil and type(e.note) ~= \"string\" then bad(\"use_buff note is not text\") end\r\nelseif e.t == \"heal_bonus\" then\r\n\r\nif e.amount == nil or not (num(e.amount) or (type(e.amount) == \"string\" and e.amount:match(\"^[%u%d+*/ d]+$\"))) then bad(\"heal_bonus amount \" .. tostring(e.amount)) end\r\nif e.buff ~= nil and type(e.buff) ~= \"string\" then bad(\"heal_bonus buff is not text\") end\r\nelseif e.t == \"weapon_die\" and e.weapons ~= nil then\r\n\r\nif type(e.weapons) ~= \"table\" then bad(\"weapon_die weapons is not a list\") end\r\nfor _, w in ipairs(e.weapons) do if type(w) ~= \"string\" then bad(\"weapon_die weapons \" .. tostring(w)) end end\r\nelseif e.t == \"free_cast\" and (e.ability ~= nil or e.level ~= nil) then\r\n\r\nif e.ability ~= nil and not ({ STR = 1, DEX = 1, CON = 1, INT = 1, WIS = 1, CHA = 1 })[e.ability] then\r\nbad(\"free_cast ability \" .. tostring(e.ability) .. \" (STR ... CHA)\") end\r\nif not num(e.level) then bad(\"free_cast level \" .. tostring(e.level)) end\r\nelseif e.t == \"summon\" then\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\ne.name = e.name or name\r\nif type(e.name) ~= \"string\" then bad(\"summon name is text\") end\r\nif e.pool ~= nil and type(e.pool) ~= \"string\" then bad(\"summon pool is a use's name\") end\r\nif e.n ~= nil and not tonumber(e.n) then bad(\"summon n is a number\") end\r\nif e.ritual ~= nil and e.ritual ~= \"10m_rest\" then bad(\"summon ritual \" .. tostring(e.ritual) .. \" (10m_rest)\") end\r\nif e.pool == nil and e.ritual == nil and not e.free then bad(\"summon: pool (the use it spends), ritual or free\") end\r\nif e.row == nil and e.types == nil then bad(\"summon: types (what it may be) or row (its own stat block)\") end\r\nif e.row ~= nil and type(e.row) ~= \"string\" then bad(\"summon row is a monsters row's name\") end\r\nfor _, k in ipairs({ \"types\", \"size\", \"size_at\", \"max_at\", \"scale\" }) do if e[k] ~= nil and type(e[k]) ~= \"table\" then bad(\"summon \" .. k .. \" is a list or table\") end end\r\nif type(e.cr) == \"string\" then e.cr = e.cr:gsub(\"level\", \"LEVEL\") end\r\nif e.cr ~= nil and not (tonumber(e.cr) or e.cr == \"wildshape\" or tostring(e.cr):match(\"^%d+/%d+$\") or tostring(e.cr):match(\"^LEVEL/%d+$\")) then bad(\"summon cr \" .. tostring(e.cr)) end\r\nif e.max ~= nil and not num(e.max) then bad(\"summon max \" .. tostring(e.max)) end\r\nfor k, v in pairs(type(e.max_at) == \"table\" and e.max_at or {}) do if not tonumber(k) or not num(v) then bad(\"summon max_at \" .. tostring(k)) end end\r\nfor k, v in pairs(type(e.size_at) == \"table\" and e.size_at or {}) do if not tonumber(k) or not (v == \"any\" or type(v) == \"table\") then bad(\"summon size_at \" .. tostring(k)) end end\r\nif e.lasts ~= nil and not (e.lasts == \"0hp\" or e.lasts == \"hours:half_level\" or tostring(e.lasts):match(\"^hours:%d+$\") or tostring(e.lasts):match(\"^mins:%d+$\")) then bad(\"summon lasts \" .. tostring(e.lasts)) end\r\nif e.range ~= nil and not tonumber(e.range) then bad(\"summon range is feet\") end\r\nif e.obey ~= nil and e.obey ~= \"telepathic\" and e.obey ~= \"may_disobey\" then bad(\"summon obey \" .. tostring(e.obey) .. \" (telepathic or may_disobey)\") end\r\nif e.as_type ~= nil and type(e.as_type) ~= \"string\" then bad(\"summon as_type is a creature type\") end\r\n\r\nif e.mind ~= nil and e.mind ~= \"owner\" then bad(\"summon mind \" .. tostring(e.mind) .. \" (owner)\") end\r\n\r\nif e.group ~= nil and type(e.group) ~= \"string\" then bad(\"summon group is a name\") end\r\nfor k, v in pairs(type(e.scale) == \"table\" and e.scale or {}) do\r\n\r\nif not ({ ac = 1, hp = 1, hp_per = 1, atk = 1, dmg = 1, dc = 1 })[k] or not (tonumber(v) or (type(v) == \"string\" and v:match(\"^[%w_+%-*/() ]+$\"))) then bad(\"summon scale \" .. tostring(k)) end\r\nend\r\nelseif e.t == \"spell_stim\" then\r\n\r\n\r\nif not (type(e.list) == \"string\" or type(e.list) == \"table\") then bad(\"spell_stim list: a class's spell list or spell names\") end\r\nelseif e.t == \"init_bonus\" or e.t == \"check_bonus\" then\r\n\r\nif not num(e.add) then bad(e.t .. \" add \" .. tostring(e.add)) end\r\nif e.t == \"check_bonus\" and e.abilities == nil and e.skills == nil then bad(\"check_bonus: abilities or skills\") end\r\nelseif e.t == \"ward\" then\r\n\r\n\r\ne.use = e.use or name\r\nif not num(e.max) then bad(\"ward max \" .. tostring(e.max)) end\r\nif e.school ~= nil and type(e.school) ~= \"string\" then bad(\"ward school is a school's English name\") end\r\nelseif e.t == \"form_ac\" or e.t == \"form_thp\" then\r\n\r\n\r\nif e.t == \"form_ac\" and not num(e.ac) then bad(\"form_ac ac \" .. tostring(e.ac)) end\r\nif e.t == \"form_thp\" and not num(e.thp) then bad(\"form_thp thp \" .. tostring(e.thp)) end\r\nelseif e.t == \"form_save_add\" then\r\n\r\nfor k, v in pairs(e) do if k ~= \"t\" and not ({ Strength = 1, Dexterity = 1, Constitution = 1, Intelligence = 1, Wisdom = 1, Charisma = 1 })[k] then\r\nif not ({ from = 1, to = 1, [\"while\"] = 1, if_pick = 1 })[k] then bad(\"form_save_add \" .. tostring(k)) end\r\nelseif k ~= \"t\" and not num(v) then bad(\"form_save_add \" .. k .. \" \" .. tostring(v)) end end\r\nelseif e.t == \"use_mod\" then\r\n\r\n\r\ne.use = e.use or name\r\nif e.pool ~= nil and type(e.pool) ~= \"string\" then bad(\"use_mod pool is a use's name\") end\r\n\r\nfor _, k in ipairs({ \"attack_bonus\", \"ac_bonus\", \"ac_turn\" }) do\r\nif e[k] ~= nil and not (num(e[k]) or (type(e[k]) == \"string\" and e[k]:match(\"^[%w{}:_+| ]+$\"))) then bad(\"use_mod \" .. k .. \" \" .. tostring(e[k])) end\r\nend\r\nif e.max ~= nil and not num(e.max) then bad(\"use_mod max \" .. tostring(e.max)) end\r\nif e.dmg_mult ~= nil and not tonumber(e.dmg_mult) then bad(\"use_mod dmg_mult is a number\") end\r\nif e.dmg_reduce ~= nil and not (type(e.dmg_reduce) == \"string\" and e.dmg_reduce:match(\"^[%w{}:_+| ]+$\")) then bad(\"use_mod dmg_reduce \" .. tostring(e.dmg_reduce)) end\r\nif e.auto_miss ~= nil and type(e.auto_miss) ~= \"boolean\" then bad(\"use_mod auto_miss is true or false\") end\r\nelseif e.t == \"hp_bonus\" then\r\n\r\nif not num(e.per_level) or not num(e.amount) then bad(\"hp_bonus per_level/amount \" .. tostring(e.per_level or e.amount)) end\r\nelseif e.t == \"heat_cycle\" then\r\n\r\n\r\nfor _, k in ipairs({ \"every\", \"days\" }) do if e[k] ~= nil and not tonumber(e[k]) then bad(\"heat_cycle \" .. k .. \" is a number\") end end\r\nif type(e.cond) ~= \"string\" then bad(\"heat_cycle cond is a condition's name\") end\r\nif e.skip ~= nil and type(e.skip) ~= \"string\" then bad(\"heat_cycle skip is a condition's name\") end\r\nelseif e.t == \"womb\" then\r\n\r\nelseif e.t == \"brand_slots\" then\r\n\r\n\r\nif e.n ~= nil and not tonumber(e.n) then bad(\"brand_slots n is a number\") end\r\nif e.source ~= nil and type(e.source) ~= \"string\" then bad(\"brand_slots source is text\") end\r\nif e.kinds ~= nil and type(e.kinds) ~= \"table\" then bad(\"brand_slots kinds is a list\") end\r\nelseif e.t == \"dmg_to_stim\" then\r\n\r\n\r\nif e.part ~= nil and e.part ~= \"half\" and e.part ~= \"all\" then bad(\"dmg_to_stim part \" .. tostring(e.part) .. \" (half or all)\") end\r\nif e.res ~= nil and type(e.res) ~= \"string\" then bad(\"dmg_to_stim res is not a use's name\") end\r\nelseif e.t == \"skill_prof\" or e.t == \"unarmored_ac\" or e.t == \"advance_bonus\" or e.t == \"impl_step\" or e.t == \"stim_thp\" then\r\n\r\nif e.t == \"unarmored_ac\" and not ({ Strength = 1, Dexterity = 1, Constitution = 1, Intelligence = 1, Wisdom = 1, Charisma = 1 })[e.ability or \"\"] then bad(\"unarmored_ac ability \" .. tostring(e.ability)) end\r\nif e.t == \"advance_bonus\" and not num(e.add) then bad(\"advance_bonus add \" .. tostring(e.add)) end\r\nif e.t == \"skill_prof\" and type(e.skills) ~= \"table\" then bad(\"skill_prof skills is not a list\") end\r\nelseif e.t == \"form_cast\" then\r\n\r\nif type(e.spells) ~= \"table\" then bad(\"form_cast spells is not a list\") end\r\nelseif e.t == \"hd_heal\" then\r\n\r\nif not num(e.n) or not num(e.add) then bad(\"hd_heal n/add \" .. tostring(e.n or e.add)) end\r\nelseif e.t == \"advance_skill\" or e.t == \"death_adv\" or e.t == \"resist_natural\" then\r\n\r\nelseif e.t == \"inhib_src\" and ((e.max ~= nil and not num(e.max)) or (e.zero ~= nil and type(e.zero) ~= \"boolean\") or (e.rounds ~= nil and not tonumber(e.rounds))) then\r\nbad(\"inhib_src max (a term), zero (true), rounds (a number)\")\r\nelseif e.t == \"inhib_src\" then\r\n\r\nif not num(e.amount) then bad(\"inhib_src amount \" .. tostring(e.amount)) end\r\nelseif e.t == \"inhib\" then\r\n\r\nif not num(e.set) or not num(e.add) then bad(\"inhib set/add \" .. tostring(e.set or e.add)) end\r\nif e.mode ~= nil and type(e.mode) ~= \"string\" then bad(\"inhib mode is not a name\") end\r\nelseif e.t == \"inhib_ignore\" then\r\n\r\nelseif e.t == \"stim_resist\" or e.t == \"stim_vuln\" then\r\n\r\nif e.types ~= nil and type(e.types) ~= \"table\" then bad(e.t .. \" types is not a list\") end\r\nfor _, ty in ipairs(type(e.types) == \"table\" and e.types or {}) do if not K.DTYPES[tostring(ty):lower()] then bad(e.t .. \" type \" .. tostring(ty)) end end\r\nelseif e.t == \"on_climax\" then\r\n\r\n\r\n\r\nif e.when ~= nil and e.when ~= \"self\" and e.when ~= \"other\" and e.when ~= \"fail\" and e.when ~= \"other_fail\" then bad(\"on_climax when \" .. tostring(e.when) .. \" (self, other, fail or other_fail)\") end\r\nif e.thp ~= nil and not num(e.thp) then bad(\"on_climax thp \" .. tostring(e.thp)) end\r\nif e.heal ~= nil and e.heal ~= \"target\" and not num(e.heal) then bad(\"on_climax heal \" .. tostring(e.heal) .. \" (a term or \\\"target\\\")\") end\r\nif e.res ~= nil and type(e.res) ~= \"string\" then bad(\"on_climax res is not a use's name\") end\r\nif e.n ~= nil and not (num(e.n) or (type(e.n) == \"string\" and e.n:match(\"^%d*d%d+$\"))) then bad(\"on_climax n \" .. tostring(e.n)) end\r\nif e.note ~= nil and type(e.note) ~= \"string\" then bad(\"on_climax note is not text\") end\r\nif e.regain ~= nil and type(e.regain) ~= \"table\" then bad(\"on_climax regain is { slot = \\\"pact\\\" } or { res, n }\") end\r\nif e.use ~= nil and type(e.use) ~= \"string\" then bad(\"on_climax use is a use's name\") end\r\nelseif e.t == \"implement_prof\" then\r\n\r\nfor _, k in ipairs({ \"kinds\", \"names\" }) do if e[k] ~= nil and type(e[k]) ~= \"table\" then bad(\"implement_prof \" .. k .. \" is not a list\") end end\r\nif e.pick ~= nil and type(e.pick) ~= \"string\" then bad(\"implement_prof pick is a choice's key\") end\r\nelseif e.t == \"heal_echo\" then\r\n\r\nif e.of ~= nil and e.of ~= \"hd\" then bad(\"heal_echo of \" .. tostring(e.of)) end\r\nend\r\nend\r\nif rec.text == nil then rec.text = \"\" end\r\nfor _, k in ipairs({ \"tip\", \"text\", \"ko\", \"lite\" }) do\r\nif rec[k] ~= nil and type(rec[k]) ~= \"string\" then bad(k .. \" is not text\") end\r\nend\r\nif rec.can ~= nil then\r\nif type(rec.can) ~= \"table\" then bad(\"can is not a list\") end\r\nfor i, e in ipairs(rec.can) do\r\nif type(e) ~= \"table\" then bad(\"can \" .. i .. \" is not a table\") end\r\nif e.when ~= nil and not ({ act = true, bonus = true, react = true, hit = true, other = true })[e.when] then bad(\"can \" .. i .. \": when \" .. tostring(e.when)) end\r\nfor _, k in ipairs({ \"ko\", \"tip\", \"lite\", \"res\", \"unit\", \"cost\" }) do\r\nif e[k] ~= nil and type(e[k]) ~= \"string\" then bad(\"can \" .. i .. \": \" .. k .. \" is not text\") end\r\nend\r\nif e.pick ~= nil and (type(e.pick) ~= \"table\" or type(e.pick[1]) ~= \"string\" or e.pick[2] == nil) then bad(\"can \" .. i .. \": pick is not { key, value }\") end\r\n\r\nfor _, k in ipairs({ \"from\", \"n\" }) do\r\nif e[k] ~= nil and not tonumber(e[k]) then bad(\"can \" .. i .. \": \" .. k .. \" is not a number\") end\r\nif e[k] ~= nil then e[k] = tonumber(e[k]) end\r\nend\r\nend\r\nend\r\nend\r\n\r\n\r\n\r\nfunction K.subCheck(cl, n, rec, d)\r\nif type(n) ~= \"string\" or not n:match(\"^%a[%a ]*$\") then error(\"class \" .. cl .. \": subclass name \" .. tostring(n) .. \" (letters and spaces only)\") end\r\nif type(rec) ~= \"table\" or type(rec.levels) ~= \"table\" then error(\"class \" .. cl .. \": subclass \" .. n .. \" has no levels\") end\r\nfor _, part in ipairs({ \"levels\", \"always\", \"rows\" }) do\r\nif rec[part] ~= nil then\r\nif type(rec[part]) ~= \"table\" then error(\"class \" .. cl .. \": subclass \" .. n .. \": \" .. part .. \" is not a table\") end\r\nlocal t = {}\r\nfor lv, v in pairs(rec[part]) do\r\nif not tonumber(lv) or type(v) ~= \"table\" then error(\"class \" .. cl .. \": subclass \" .. n .. \": \" .. part .. \" \" .. tostring(lv)) end\r\nt[tostring(math.floor(tonumber(lv)))] = v\r\nend\r\nrec[part] = t\r\nend\r\nend\r\n\r\nfor lv, list in pairs(rec.levels) do\r\nfor _, f in ipairs(list) do if type(f) ~= \"string\" then error(\"class \" .. cl .. \": subclass \" .. n .. \": level \" .. lv .. \" feature \" .. tostring(f)) end end\r\nend\r\n\r\n\r\n\r\nfor _, list in pairs(rec.always or {}) do\r\nfor _, sp in ipairs(list) do\r\nlocal last = sp\r\nif type(sp) == \"table\" then\r\nfor _, x in ipairs(sp) do if type(x) ~= \"string\" then error(\"class \" .. cl .. \": subclass \" .. n .. \": spell \" .. tostring(x)) end end\r\nlast = sp[#sp]\r\nend\r\nif type(last) ~= \"string\" or (not SPELLS[last] and not (type(d.spells) == \"table\" and d.spells[last])) then error(\"class \" .. cl .. \": subclass \" .. n .. \": no spell \" .. tostring(last)) end\r\nend\r\nend\r\nfor _, k in ipairs({ \"ko\", \"tip\", \"request\" }) do\r\nif rec[k] ~= nil and type(rec[k]) ~= \"string\" then error(\"class \" .. cl .. \": subclass \" .. n .. \": \" .. k .. \" is not text\") end\r\nend\r\nK.d2check(\"class \" .. cl .. \": subclass \" .. n, rec)\r\nK.replCheck(\"class \" .. cl .. \": subclass \" .. n, rec)\r\n\r\nif rec.tools ~= nil then\r\nif type(rec.tools) ~= \"table\" then error(\"class \" .. cl .. \": subclass \" .. n .. \": tools is not a list\") end\r\nfor _, t in ipairs(rec.tools) do\r\nif type(t) ~= \"string\" or not (K.TOOLS and K.TOOLS[t]) then error(\"class \" .. cl .. \": subclass \" .. n .. \": no tool \" .. tostring(t)) end\r\nend\r\nend\r\nend\r\n\r\n\r\n\r\nfunction K.packLists(lists)\r\n\r\nlocal order, pending = {}, {}\r\nfor _, x in ipairs(lists) do\r\nif type(x[2]) == \"table\" then order[#order + 1] = x else pending[x[1]] = x end\r\nend\r\nfor _ = 1, #lists do\r\nlocal moved = false\r\nfor cl, x in pairs(pending) do\r\nif not pending[x[2]] then order[#order + 1] = x; pending[cl] = nil; moved = true end\r\nend\r\nif not moved then break end\r\nend\r\nfor cl, x in pairs(pending) do order[#order + 1] = x end\r\nfor _, x in ipairs(order) do\r\nlocal cl, sl, names = x[1], x[2], {}\r\nK.PACK.notes = x.notes\r\nif type(sl) == \"string\" then\r\nfor n, sp in pairs(SPELLS) do\r\nfor _, k in ipairs(sp.classes or {}) do if k == sl then names[#names + 1] = n; break end end\r\nend\r\nelseif type(sl) == \"table\" then\r\nfor _, n in ipairs(sl) do\r\nif SPELLS[n] then names[#names + 1] = n else K.packNote(\"class \" .. cl .. \": no spell \" .. tostring(n)) end\r\nend\r\nend\r\nfor _, n in ipairs(names) do\r\nlocal cls = {}\r\nfor _, k in ipairs(SPELLS[n].classes or {}) do cls[#cls + 1] = k end\r\ncls[#cls + 1] = cl\r\nK.packPut(SPELLS[n], \"classes\", cls)\r\nend\r\nK.PACK.notes = nil\r\nend\r\nend\r\n\r\n\r\nfunction K.osClock()\r\nlocal ok, t = pcall(function() return os.clock() end)\r\nreturn ok and type(t) == \"number\" and t or 0\r\nend\r\n\r\n\r\nfunction K.packFpSave(id)\r\nif not K.PACK.fp then return end\r\nlocal ok, was = pcall(getChatVar, id, \"dnd_pack_fp\")\r\nif ok and was ~= K.PACK.fp then pcall(setChatVar, id, \"dnd_pack_fp\", K.PACK.fp) end\r\nend\r\n\r\n\r\n\r\n\r\nK.MON_ALIAS = {}\r\nfunction K.aliasLoad(str)\r\nK.MON_ALIAS = {}\r\nfor a, b in tostring(str or \"\"):gmatch(\"([^=;]+)=([^;]+)\") do if MONSTERS[b] and not MONSTERS[a] then K.MON_ALIAS[a] = b end end\r\nend\r\nfunction K.aliasStr(t)\r\nlocal o = {}\r\nfor a, b in pairs(type(t) == \"table\" and t or {}) do o[#o + 1] = a .. \"=\" .. b end\r\ntable.sort(o)\r\nreturn table.concat(o, \";\")\r\nend\r\n\r\n\r\nK.MON_OLD = { Veteran = \"Warrior Veteran\", Thug = \"Tough\", [\"Cult Fanatic\"] = \"Cultist Fanatic\", Acolyte = \"Priest Acolyte\",\r\n[\"Tribal Warrior\"] = \"Warrior Infantry\", Goblin = \"Goblin Warrior\", Kobold = \"Kobold Warrior\", Hobgoblin = \"Hobgoblin Warrior\",\r\nBugbear = \"Bugbear Warrior\", Gnoll = \"Gnoll Warrior\", Sahuagin = \"Sahuagin Warrior\", Merfolk = \"Merfolk Skirmisher\",\r\nShrieker = \"Shrieker Fungus\", [\"Flying Sword\"] = \"Animated Flying Sword\", [\"Rug of Smothering\"] = \"Animated Rug of Smothering\",\r\n[\"Poisonous Snake\"] = \"Venomous Snake\", [\"Giant Poisonous Snake\"] = \"Giant Venomous Snake\", [\"Swarm of Poisonous Snakes\"] = \"Swarm of Venomous Snakes\" }\r\n\r\nfunction K.monKind(n)\r\nn = n or \"\"\r\nif MONSTERS[n] then return n end\r\nif K.MON_ALIAS[n] then return K.MON_ALIAS[n] end\r\nif K.MON_OLD[n] and MONSTERS[K.MON_OLD[n]] then return K.MON_OLD[n] end\r\nlocal base = n:match(\"^(.-) %d+$\")\r\nif base then return (MONSTERS[base] and base) or K.MON_ALIAS[base] or (K.MON_OLD[base] and MONSTERS[K.MON_OLD[base]] and K.MON_OLD[base]) or nil end\r\nreturn nil\r\nend\r\n\r\n\r\n\r\n\r\n\r\nK.PACK_CACHE_HEAD = \"DNDPACK1\\2\"\r\nfunction K.packCacheGet(id)\r\nlocal ok, v = pcall(getChatVar, id, \"dnd_pack_cache\")\r\nif not (ok and type(v) == \"string\" and v:sub(1, #K.PACK_CACHE_HEAD) == K.PACK_CACHE_HEAD) then return nil end\r\nlocal body, out, at = v:sub(#K.PACK_CACHE_HEAD + 1), {}, 1\r\nif body == \"\" then return out end\r\nwhile true do\r\nlocal i = body:find(\"\\1\", at, true)\r\nif not i then out[#out + 1] = body:sub(at); break end\r\nout[#out + 1] = body:sub(at, i - 1)\r\nat = i + 1\r\nend\r\nreturn out\r\nend\r\n\r\n\r\n\r\nK.PACK_FRESH_MAX = 50000\r\nfunction K.packFreshAtSend(id)\r\nlocal c = K.packCacheGet(id)\r\nif not c then return true end\r\nlocal n = 0\r\nfor _, t in ipairs(c) do n = n + #t end\r\nreturn n < K.PACK_FRESH_MAX\r\nend\r\nfunction K.packs(id, fresh)\r\nK.fxMemo = nil\r\nlocal oka, al = pcall(getChatVar, id, \"dnd_mon_alias\")\r\nif oka then K.aliasLoad(al) end\r\n\r\nlocal okm, mode = pcall(getChatVar, id, \"dnd_dlc_mode\")\r\nlocal okp, perm = pcall(getChatVar, id, \"dnd_dlc_perm\")\r\nlocal okf, furry = pcall(getChatVar, id, \"dnd_dlc_furry\")\r\nlocal okx, xeno = pcall(getChatVar, id, \"dnd_dlc_xeno\")\r\nlocal okl, lvd = pcall(getChatVar, id, \"dnd_dlc_lvdown\")\r\nlocal okad, adult = pcall(getChatVar, id, \"dnd_dlc_adult\")\r\nlocal okh, hit = pcall(getChatVar, id, \"dnd_dlc_hitomi\")\r\nlocal oko, omg = pcall(getChatVar, id, \"dnd_dlc_omega\")\r\nK.D2 = { mode = (okm and mode == \"hard\") and \"hard\" or \"mild\", perm = (okp and perm == \"on\") and \"on\" or \"off\", lvdown = (okl and lvd == \"on\") and \"on\" or \"off\",\r\nfurry = (okf and furry == \"on\") and \"on\" or \"off\", xeno = (okx and xeno == \"on\") and \"on\" or \"off\",\r\nadult = (okad and adult == \"off\") and \"off\" or \"on\", hitomi = (okh and hit == \"on\") and \"on\" or \"off\", omega = (oko and omg == \"on\") and \"on\" or \"off\" }\r\nlocal tRead = K.osClock()\r\nlocal texts = not fresh and K.packCacheGet(id) or nil\r\nK.PACK.fromCache = texts ~= nil\r\nif texts then\r\nK.PACK.texts = texts\r\nelse\r\nlocal ok, found = pcall(getLoreBooks, id, \"DND_PACK\")\r\n\r\n\r\nif not ok then\r\nif not K.PACK.texts then return K.PACK.list end\r\ntexts = K.PACK.texts\r\nelse\r\nif type(found) ~= \"table\" then found = {} end\r\ntexts = {}\r\nfor _, e in ipairs(found) do texts[#texts + 1] = type(e) == \"table\" and tostring(e.content or \"\") or \"\" end\r\nK.PACK.texts = texts\r\n\r\nlocal enc = K.PACK_CACHE_HEAD .. table.concat(texts, \"\\1\")\r\nlocal okc, was = pcall(getChatVar, id, \"dnd_pack_cache\")\r\nif not (okc and was == enc) then pcall(setChatVar, id, \"dnd_pack_cache\", enc) end\r\nend\r\nend\r\n\r\n\r\n\r\nlocal d2sig = K.D2.mode .. K.D2.perm .. K.D2.furry .. K.D2.xeno .. K.D2.adult\r\n\r\nlocal fp = { tostring(#texts) }\r\nfor _, t in ipairs(texts) do fp[#fp + 1] = tostring(#t) end\r\nK.PACK.fp = table.concat(fp, \",\")\r\nlocal prev = K.PACK.sig\r\nlocal same = type(prev) == \"table\" and prev.d2 == d2sig and #prev.texts == #texts\r\nif same then for i, t in ipairs(texts) do if prev.texts[i] ~= t then same = false; break end end end\r\nK.PACK.readMs = math.floor((K.osClock() - tRead) * 1000 + 0.5)\r\nif same then return K.PACK.list end\r\nlocal tMerge = K.osClock()\r\nK.packUndo(0)\r\nK.PACK.undo, K.PACK.list, K.PACK.sig = {}, {}, nil\r\nK.PACK.d2 = nil\r\nK.PACK.gen = (K.PACK.gen or 0) + 1\r\nK.gearList = nil\r\nlocal allLists = {}\r\nK.PACK.adultOff, K.PACK.adultOn = nil, nil\r\nfor _, t in ipairs(texts) do\r\n\r\n\r\n\r\nlocal adultPack = t:find('\"adult\"%s*:%s*true') ~= nil or t:find('\"arousal\"%s*:') ~= nil or t:find('\"d2\"%s*:') ~= nil\r\nlocal okj, data\r\nif not (adultPack and K.D2.adult == \"off\") then\r\nokj, data = pcall(function() return json.decode(t) end)\r\nend\r\nif adultPack and K.D2.adult == \"off\" then\r\nK.PACK.adultOff = true\r\nK.PACK.list[#K.PACK.list + 1] = { name = tostring(t:match('\"pack\"%s*:%s*\"([^\"]*)\"') or \"?\"), ok = true, notes = { \"off on the settings tab (adult module)\" } }\r\nelseif okj and type(data) == \"table\" then\r\nif adultPack then K.PACK.adultOn = true end\r\nlocal mark = #K.PACK.undo\r\nK.PACK.notes = {}\r\nK.PACK.curAdult = adultPack\r\nlocal okm, err = pcall(K.packMerge, data)\r\nK.PACK.curAdult = nil\r\n\r\nif not okm then K.packUndo(mark) end\r\n\r\nif okm and type(err) == \"table\" then\r\nfor _, x in ipairs(err) do x.notes = K.PACK.notes; allLists[#allLists + 1] = x end\r\nerr = nil\r\nend\r\nK.PACK.list[#K.PACK.list + 1] = { name = tostring(data.pack or \"?\"), ok = okm, err = not okm and tostring(err) or nil, notes = K.PACK.notes }\r\nK.PACK.notes = nil\r\nelse\r\nK.PACK.list[#K.PACK.list + 1] = { name = \"?\", ok = false, err = \"not JSON\" }\r\nend\r\nend\r\npcall(K.packLists, allLists)\r\nif K.MI then K.MI.k2e, K.MI.kc = nil, {} end\r\nif K.MI and K.MI.spAlts then pcall(K.MI.spAlts) end\r\nK.PACK.sig = { texts = texts, d2 = d2sig }\r\nK.PACK.mergeMs = math.floor((K.osClock() - tMerge) * 1000 + 0.5)\r\nreturn K.PACK.list\r\nend\r\n\r\n\r\n\r\n\r\n\r\n\r\nlocal ABILS = { \"Strength\", \"Dexterity\", \"Constitution\", \"Intelligence\", \"Wisdom\", \"Charisma\" }\r\nlocal ABBR = { STR = \"Strength\", DEX = \"Dexterity\", CON = \"Constitution\", INT = \"Intelligence\", WIS = \"Wisdom\", CHA = \"Charisma\" }\r\nlocal EXPERT = {}\r\nlocal SHEET\r\n\r\nlocal DEFAULT_SHEET = {\r\ndefault = true, species = \"Human\", class = \"Fighter\", background = \"Soldier\", level = 1,\r\nscores = { Strength = 17, Dexterity = 13, Constitution = 15, Intelligence = 8, Wisdom = 12, Charisma = 10 },\r\nskills = { \"Athletics\", \"Intimidation\", \"Perception\", \"Survival\" }, expertise = {}, gear = {},\r\npicks = { style = \"Great Weapon Fighting\", mastery = { \"Longsword\", \"Spear\", \"Shortbow\" }, feat = \"Alert\" },\r\n}\r\n\r\nlocal function abilityMod(score) return math.floor((score - 10) / 2) end\r\n\r\n\r\n\r\n\r\n\r\nfunction K.mcList(sh)\r\nreturn type(sh) == \"table\" and type(sh.mc) == \"table\" and sh.mc or {}\r\nend\r\nfunction K.charLevel(sh)\r\nif type(sh) == \"table\" and rawget(sh, \"charLv\") then return sh.charLv end\r\nlocal n = tonumber(type(sh) == \"table\" and sh.level) or 1\r\nfor _, m in ipairs(K.mcList(sh)) do n = n + (tonumber(m.level) or 0) end\r\nreturn n\r\nend\r\n\r\nfunction K.classes(sh)\r\nlocal out = { { name = sh.class, level = tonumber(sh.level) or 1 } }\r\nfor _, m in ipairs(K.mcList(sh)) do\r\nif CLASSES[m.class or \"\"] and (tonumber(m.level) or 0) > 0 and m.class ~= sh.class then out[#out + 1] = { name = m.class, level = tonumber(m.level) } end\r\nend\r\nfor _, c in ipairs(out) do c.row = K.rowAt(sh, c.name, c.level) end\r\nreturn out\r\nend\r\n\r\n\r\n\r\n\r\n\r\nK.SUBCAST, K.NIL = {}, {}\r\nfunction K.subCastApply(sh)\r\nfor cls, saved in pairs(K.SUBCAST) do\r\nlocal c = CLASSES[cls]\r\nif c then for k, v in pairs(saved) do if v == K.NIL then c[k] = nil else c[k] = v end end end\r\nend\r\nK.SUBCAST = {}\r\nif type(sh) ~= \"table\" or not K.subRec or not K.subOf or not CLASSES[sh.class or \"\"] then return end\r\nlocal list = { { name = sh.class, level = tonumber(sh.level) or 1 } }\r\nfor _, m in ipairs(K.mcList(sh)) do if CLASSES[m.class or \"\"] and (tonumber(m.level) or 0) > 0 then list[#list + 1] = { name = m.class, level = tonumber(m.level) } end end\r\nfor _, cc in ipairs(list) do\r\nlocal c = CLASSES[cc.name]\r\nlocal sub = c and not c.spell_ability and cc.level >= K.subLevel(cc.name) and K.subRec(cc.name, K.subOf(sh, cc.name))\r\nlocal sc = type(sub) == \"table\" and type(sub.spellcasting) == \"table\" and sub.spellcasting\r\nif sc and sc.ability then\r\nlocal saved = {}\r\nfor _, k in ipairs({ \"spell_ability\", \"caster\", \"swap\" }) do if c[k] == nil then saved[k] = K.NIL else saved[k] = c[k] end end\r\nK.SUBCAST[cc.name] = saved\r\nc.spell_ability, c.caster = sc.ability, sc.caster or \"third\"\r\nif sc.swap then c.swap = sc.swap end\r\nend\r\nend\r\nend\r\n\r\n\r\n\r\n\r\nK.SUBKEY = {}\r\nfunction K.subKey(cl)\r\nlocal k = K.SUBKEY[cl]\r\nif not k then k = \"sub\" .. (tostring(cl):gsub(\"%A\", \"\")); K.SUBKEY[cl] = k end\r\nreturn k\r\nend\r\n\r\nfunction K.subClassOf(key)\r\nif type(key) ~= \"string\" or not key:match(\"^sub%u\") then return nil end\r\nfor cl in pairs(CLASSES) do if K.subKey(cl) == key then return cl end end\r\nreturn nil\r\nend\r\n\r\nfunction K.subOnly(cl)\r\nif K.LITE then return false end\r\nreturn K.subOptions and #K.subOptions(cl) <= 1\r\nend\r\nfunction K.subOnlyTip(cl)\r\nreturn K.subOnly(cl) and \"\\n\\nSRD에는 이 클래스의 하위 클래스가 하나뿐이라 자동으로 정해집니다. 다른 하위 클래스는 데이터 팩(모듈)으로 더해집니다.\" or \"\"\r\nend\r\nfunction K.subDefault(cl)\r\nlocal c = CLASSES[cl or \"\"]\r\nreturn c and type(c.subclass) == \"table\" and c.subclass.name or nil\r\nend\r\nfunction K.subLevel(cl)\r\nlocal c = CLASSES[cl or \"\"]\r\nreturn c and type(c.subclass) == \"table\" and tonumber(c.subclass.level) or 99\r\nend\r\nfunction K.subRec(cl, name)\r\nlocal c = CLASSES[cl or \"\"]\r\nreturn c and name and type(c.subclasses) == \"table\" and c.subclasses[name] or nil\r\nend\r\n\r\nfunction K.subOptions(cl)\r\nlocal d, o, rest = K.subDefault(cl), {}, {}\r\nif d then o[1] = d end\r\nfor n, rec in pairs(type((CLASSES[cl or \"\"] or {}).subclasses) == \"table\" and CLASSES[cl].subclasses or {}) do\r\nif n ~= d and K.d2ok(rec) then rest[#rest + 1] = n end\r\nend\r\ntable.sort(rest)\r\nfor _, n in ipairs(rest) do o[#o + 1] = n end\r\nreturn o\r\nend\r\n\r\nfunction K.subOf(sh, cl)\r\nlocal p = type(sh) == \"table\" and type(sh.picks) == \"table\" and sh.picks or nil\r\nlocal v = p and p[K.subKey(cl)]\r\nif type(v) == \"string\" then return v end\r\nreturn K.subDefault(cl)\r\nend\r\n\r\n\r\n\r\n\r\nfunction K.rowAt(sh, name, lv)\r\nlocal row = (((CLASSES[name] or {}).levels or {})[lv]) or {}\r\nlocal sub = K.subOf(sh, name)\r\nif not sub or lv < K.subLevel(name) then return row end\r\nlocal def = K.subDefault(name)\r\nlocal rows = (K.subRec(name, sub) or {}).rows\r\nif sub == def and type(rows) ~= \"table\" then return row end\r\nlocal o = {}\r\nfor k, v in pairs(row) do o[k] = v end\r\nif sub ~= def then\r\nlocal drec = K.subRec(name, def) or {}\r\nfor _, k in ipairs(drec.row_keys or {}) do o[k] = nil end\r\nif type(drec.row_res) == \"table\" and type(o.res) == \"table\" then\r\nlocal r = {}\r\nfor n, x in pairs(o.res) do r[n] = x end\r\nfor _, n in ipairs(drec.row_res) do r[n] = nil end\r\no.res = r\r\nend\r\nend\r\nfor l = 1, lv do\r\nlocal add = type(rows) == \"table\" and rows[tostring(l)]\r\nfor k, v in pairs(type(add) == \"table\" and add or {}) do\r\nif k == \"res\" and type(v) == \"table\" then\r\nlocal r = {}\r\nfor n, x in pairs(o.res or {}) do r[n] = x end\r\nfor n, x in pairs(v) do r[n] = x end\r\no.res = r\r\nelse\r\no[k] = v\r\nend\r\nend\r\nend\r\nreturn o\r\nend\r\n\r\nfunction K.subHas(sh, name)\r\nif type(sh) ~= \"table\" or not sh.class then return false end\r\nfor _, c in ipairs(K.classes(sh)) do\r\nlocal rec = K.subRec(c.name, K.subOf(sh, c.name))\r\nif rec and c.level >= K.subLevel(c.name) then\r\nfor lv, list in pairs(type(rec.levels) == \"table\" and rec.levels or {}) do\r\nif (tonumber(lv) or 99) <= c.level then\r\nfor _, n in ipairs(list) do if n == name then return true end end\r\nend\r\nend\r\nend\r\nend\r\nreturn false\r\nend\r\n\r\nfunction K.cl(sh, name)\r\nif type(sh) ~= \"table\" then return 0 end\r\nif sh.class == name then return tonumber(sh.level) or 1 end\r\nfor _, m in ipairs(K.mcList(sh)) do if m.class == name then return tonumber(m.level) or 0 end end\r\nreturn 0\r\nend\r\nfunction K.rowOf(sh, name)\r\nlocal lv = K.cl(sh, name)\r\nreturn lv > 0 and K.rowAt(sh, name, lv) or {}\r\nend\r\n\r\nfunction K.castCl(sh)\r\nif type(sh) ~= \"table\" then return nil end\r\nif CLASSES[sh.class or \"\"] and CLASSES[sh.class].spell_ability then return sh.class end\r\nfor _, m in ipairs(K.mcList(sh)) do if CLASSES[m.class or \"\"] and CLASSES[m.class].spell_ability and (tonumber(m.level) or 0) > 0 then return m.class end end\r\nreturn nil\r\nend\r\n\r\n\r\n\r\nfunction K.view(sh, name, level)\r\nif name == sh.class and #K.mcList(sh) == 0 then return sh end\r\nreturn setmetatable({ class = name, level = level, mc = false, isView = true, charLv = K.charLevel(sh), base = sh.base or sh }, { __index = sh })\r\nend\r\n\r\nfunction K.udClass(sh)\r\nfor _, c in ipairs(K.classes(sh.base or sh)) do if (CLASSES[c.name] or {}).unarmored then return c.name end end\r\nreturn nil\r\nend\r\n\r\nfunction K.casters(sh)\r\nlocal o = {}\r\nfor _, c in ipairs(K.classes(sh)) do if (CLASSES[c.name] or {}).spell_ability then o[#o + 1] = c.name end end\r\nreturn o\r\nend\r\n\r\n\r\nfunction K.lists(sh, cls)\r\nlocal b = sh.base or sh\r\nif not cls or cls == K.castCl(b) then return b.cantrips or {}, b.spells or {} end\r\nlocal m = type(b.mcspells) == \"table\" and type(b.mcspells[cls]) == \"table\" and b.mcspells[cls] or {}\r\nreturn m.cantrips or {}, m.spells or {}\r\nend\r\nfunction K.setLists(sh, cls, cans, preps)\r\nlocal b = sh.base or sh\r\nif not cls or cls == K.castCl(b) then b.cantrips, b.spells = cans, preps; return end\r\nb.mcspells = type(b.mcspells) == \"table\" and b.mcspells or {}\r\nb.mcspells[cls] = { cantrips = cans, spells = preps }\r\nend\r\n\r\nfunction K.casterView(sh, cls)\r\ncls = cls or K.castCl(sh)\r\nif not cls or not (CLASSES[cls] or {}).spell_ability or K.cl(sh, cls) == 0 then return nil end\r\nlocal v = K.view(sh, cls, K.cl(sh, cls))\r\nif cls ~= K.castCl(sh.base or sh) then\r\nlocal cans, preps = K.lists(sh, cls)\r\nrawset(v, \"cantrips\", cans)\r\nrawset(v, \"spells\", preps)\r\nend\r\nreturn v\r\nend\r\nfunction K.casterViews(sh)\r\nlocal o = {}\r\nfor _, cls in ipairs(K.casters(sh)) do o[#o + 1] = K.casterView(sh, cls) end\r\nreturn o\r\nend\r\n\r\n\r\nfunction K.spellClassOf(sh, name)\r\n\r\nlocal cs = K.casters(sh)\r\nif #cs <= 1 then return cs[1] end\r\nlocal best, bm\r\nfor _, v in ipairs(K.casterViews(sh)) do\r\nlocal has = false\r\nfor _, l in ipairs({ v.cantrips or {}, v.spells or {}, Feat.always(v) }) do\r\nfor _, n in ipairs(l) do if n == name then has = true end end\r\nend\r\nif has then\r\nlocal m = abilityMod(tonumber((sh.scores or {})[CLASSES[v.class].spell_ability]) or 10)\r\nif not best or m > bm then best, bm = v.class, m end\r\nend\r\nend\r\nreturn best\r\nend\r\n\r\nfunction K.allLists(sh)\r\nlocal o = {}\r\nfor _, v in ipairs(K.casterViews(sh)) do\r\nfor _, l in ipairs({ v.cantrips or {}, v.spells or {} }) do for _, n in ipairs(l) do o[n] = true end end\r\nend\r\nfor _, n in ipairs(Feat.always(sh)) do o[n] = true end\r\nreturn o\r\nend\r\n\r\n\r\nK.MC_SLOTS = {\r\n{ 2 }, { 3 }, { 4, 2 }, { 4, 3 }, { 4, 3, 2 }, { 4, 3, 3 }, { 4, 3, 3, 1 }, { 4, 3, 3, 2 }, { 4, 3, 3, 3, 1 }, { 4, 3, 3, 3, 2 },\r\n{ 4, 3, 3, 3, 2, 1 }, { 4, 3, 3, 3, 2, 1 }, { 4, 3, 3, 3, 2, 1, 1 }, { 4, 3, 3, 3, 2, 1, 1 }, { 4, 3, 3, 3, 2, 1, 1, 1 },\r\n{ 4, 3, 3, 3, 2, 1, 1, 1 }, { 4, 3, 3, 3, 2, 1, 1, 1, 1 }, { 4, 3, 3, 3, 3, 1, 1, 1, 1 }, { 4, 3, 3, 3, 3, 2, 1, 1, 1 },\r\n{ 4, 3, 3, 3, 3, 2, 2, 1, 1 },\r\n}\r\n\r\nfunction K.casterLv(name, level)\r\nlocal k = (CLASSES[name or \"\"] or {}).caster\r\nif k == \"half\" then return math.ceil(level / 2) end\r\nif k == \"third\" then return math.floor(level / 3) end\r\nreturn level\r\nend\r\n\r\nfunction K.spellcasters(sh)\r\nlocal o = {}\r\nfor _, c in ipairs(K.classes(sh)) do\r\nlocal d = CLASSES[c.name] or {}\r\nif d.spell_ability and not d.pact then o[#o + 1] = c end\r\nend\r\nreturn o\r\nend\r\n\r\nfunction K.isBook(cl) return (CLASSES[cl or \"\"] or {}).spellbook == true end\r\nfunction K.bookClass(sh)\r\nfor _, c in ipairs(K.classes(sh)) do if K.isBook(c.name) then return c.name end end\r\nreturn nil\r\nend\r\n\r\nfunction K.classFeat(cl, level, name)\r\nlocal rows = (CLASSES[cl or \"\"] or {}).levels or {}\r\nfor i = 1, math.min(tonumber(level) or 0, #rows) do\r\nfor _, f in ipairs((rows[i] or {}).features or {}) do if f == name then return true end end\r\nend\r\nreturn false\r\nend\r\n\r\nfunction K.pactClass(sh)\r\nfor _, c in ipairs(K.classes(sh)) do if (CLASSES[c.name] or {}).pact then return c end end\r\nreturn nil\r\nend\r\n\r\nfunction K.pactApart(sh)\r\nreturn K.pactClass(sh) ~= nil and #K.spellcasters(sh) > 0\r\nend\r\n\r\nfunction K.pactSlotLevel()\r\nfor l = 9, 1, -1 do if PC.res[\"Pact Slot \" .. l] then return l end end\r\nreturn nil\r\nend\r\n\r\nfunction K.mcText(sh, ko)\r\nlocal o = {}\r\nfor _, c in ipairs(K.classes(sh)) do o[#o + 1] = (ko and ko(c.name) or c.name) .. \" \" .. c.level end\r\nreturn table.concat(o, \" / \")\r\nend\r\n\r\n\r\nfunction K.mcGains(name)\r\nreturn (CLASSES[name or \"\"] or {}).mc_gains or {}\r\nend\r\n\r\n\r\nfunction K.mcPrereq(sh, name)\r\nlocal need = {}\r\nlocal function check(cl)\r\nlocal c = CLASSES[cl or \"\"]\r\nif not c then return end\r\nlocal list = c.primary or {}\r\nlocal any = c.mc_need == \"any\"\r\nlocal ok = not any\r\nfor _, ab in ipairs(list) do\r\nlocal s = tonumber((sh.scores or {})[ab]) or 10\r\nif any then ok = ok or s >= 13 elseif s < 13 then ok = false end\r\nend\r\nif not ok then need[#need + 1] = { class = cl, abilities = list, either = any } end\r\nend\r\ncheck(name)\r\nfor _, c in ipairs(K.classes(sh)) do if c.name ~= name then check(c.name) end end\r\nreturn #need == 0, need\r\nend\r\n\r\n\r\n\r\nfunction K.mcCan(sh, name)\r\nlocal c = CLASSES[name or \"\"]\r\nif not c or name:sub(1, 1) == \"_\" then return false, \"no such class\" end\r\n\r\nif K.cl(sh, name) == 0 and K.d2need(c) then return false, K.D2_WHY[K.d2need(c)] end\r\nif K.charLevel(sh) >= #XP_LEVEL then return false, \"character level \" .. #XP_LEVEL end\r\nlocal lv = K.cl(sh, name)\r\nif lv > 0 then\r\nif lv >= K.maxLevel(name) then return false, \"max level \" .. K.maxLevel(name) end\r\nreturn true\r\nend\r\nif K.LITE then return false, \"one class in the light build\" end\r\n\r\nif c.pact and K.pactClass(sh) then return false, \"pact\" end\r\nif c.spellbook and K.bookClass(sh) then return false, \"book\" end\r\nlocal ok, need = K.mcPrereq(sh, name)\r\nif not ok then return false, \"prereq\", need end\r\nreturn true\r\nend\r\n\r\n\r\n\r\nfunction K.addLevel(sh, cls)\r\nlocal lv = K.cl(sh, cls) + 1\r\nif cls == sh.class then\r\nsh.level = lv\r\nelse\r\nsh.mc = type(sh.mc) == \"table\" and sh.mc or {}\r\nlocal m\r\nfor _, x in ipairs(sh.mc) do if x.class == cls then m = x end end\r\nif not m then m = { class = cls, level = 0 }; sh.mc[#sh.mc + 1] = m end\r\nm.level = lv\r\nend\r\nlocal total = K.charLevel(sh)\r\n\r\nif cls ~= sh.class or type(sh.lvcls) == \"table\" then\r\nlocal old, d = type(sh.lvcls) == \"table\" and sh.lvcls or {}, {}\r\nfor l = 1, total - 1 do d[l] = old[l] or old[tostring(l)] or sh.class end\r\nd[total] = cls\r\nsh.lvcls = d\r\nend\r\nreturn lv\r\nend\r\n\r\n\r\nfunction K.lvDie(sh, lv)\r\nlocal l = type(sh.lvcls) == \"table\" and sh.lvcls or {}\r\nreturn (CLASSES[l[lv] or l[tostring(lv)] or \"\"] or CLASSES[sh.class]).hit_die\r\nend\r\n\r\n\r\nfunction K.hdPool(sh)\r\nlocal o = {}\r\nfor lv = 1, K.charLevel(sh) do o[#o + 1] = K.lvDie(sh, lv) end\r\ntable.sort(o)\r\nreturn o\r\nend\r\n\r\nfunction K.hdNext(sh, hd)\r\nlocal p = K.hdPool(sh)\r\nreturn p[math.max(1, math.min(#p, tonumber(hd) or 1))] or CLASSES[sh.class].hit_die\r\nend\r\n\r\nfunction K.hdLeft(sh, hd)\r\nlocal p, n, o = K.hdPool(sh), {}, {}\r\nfor i = 1, math.min(tonumber(hd) or 0, #p) do n[p[i]] = (n[p[i]] or 0) + 1 end\r\nfor s, c in pairs(n) do o[#o + 1] = { s, c } end\r\ntable.sort(o, function(x, y) return x[1] > y[1] end)\r\nreturn o\r\nend\r\n\r\nfunction K.hdText(sh, hd)\r\nif #K.mcList(sh) == 0 then return \"d\" .. CLASSES[sh.class].hit_die end\r\nlocal o = {}\r\nfor _, x in ipairs(K.hdLeft(sh, hd)) do o[#o + 1] = x[2] .. \"d\" .. x[1] end\r\nreturn (#o > 0 and table.concat(o, \" + \") or \"none left\") .. \", the largest spent first\"\r\nend\r\n\r\n\r\nfunction K.score(sh, a)\r\nlocal r = K.swapAb and K.swapAb(sh, a) or a\r\nlocal s = (type(sh.mscores) == \"table\" and tonumber(sh.mscores[r])) or tonumber(sh.scores[r]) or 10\r\nreturn K.drained(sh, a, s)\r\nend\r\n\r\nfunction K.drainOf(r, a)\r\nlocal e = type(r) == \"table\" and type(r.sdrain) == \"table\" and r.sdrain[a]\r\nif type(e) ~= \"table\" then return nil end\r\nif tonumber(e.ends) and K.clockRef and tonumber(K.clockRef.min) and K.clockRef.min >= e.ends then r.sdrain[a] = nil; return nil end\r\nreturn e\r\nend\r\nfunction K.drained(sh, a, s)\r\n\r\nlocal pen = (a == \"Strength\" or a == \"Dexterity\") and type(sh) == \"table\" and tonumber(sh.pregPen) or nil\r\nif pen then s = math.max(1, (tonumber(s) or 10) - pen) end\r\nlocal e = K.drainOf(sh, a)\r\nif not e then return s end\r\nif tonumber(e.set) then return math.min(s, e.set) end\r\nreturn math.max(math.min(s, tonumber(e.min) or 1), s + (tonumber(e.n) or 0))\r\nend\r\n\r\nlocal function sheetMaxHp(sh)\r\nlocal cl = CLASSES[sh.class]\r\n\r\nlocal con = abilityMod(K.score(sh, \"Constitution\"))\r\nlocal extra = (SPECIES[sh.species] or {}).hp_per_level or 0\r\nif sh.species == \"Beastfolk\" and type(sh.picks) == \"table\" and sh.picks.beast == \"Bear\" then extra = extra + 1 end\r\nlocal hp = cl.hit_die + con + extra\r\n\r\n\r\nlocal rolls = sh.hp_rolls or {}\r\nlocal lvcls = type(sh.lvcls) == \"table\" and sh.lvcls or {}\r\nfor lv = 2, K.charLevel(sh) do\r\nlocal r = tonumber(rolls[lv]) or 0\r\nlocal die = (CLASSES[lvcls[lv] or lvcls[tostring(lv)] or \"\"] or cl).hit_die\r\nhp = hp + math.max(1, (r > 0 and r or math.floor(die / 2) + 1) + con + extra)\r\nend\r\n\r\nlocal bonus = 0\r\nfor _, c in ipairs(K.classes(sh)) do bonus = bonus + (c.row.hp_bonus or 0) end\r\n\r\nlocal lvAll = K.charLevel(sh)\r\nfor _, e in ipairs((Feat and Feat.fxOf) and Feat.fxOf(sh, \"hp_bonus\") or {}) do\r\nbonus = bonus + K.fxNum(e.amount or 0, sh, lvAll) + K.fxNum(e.per_level or 0, sh, lvAll) * lvAll\r\nend\r\nreturn hp + bonus + (tonumber(sh.mhp) or 0) * K.charLevel(sh)\r\nend\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\nK.MP = {\r\nSPELL = { 2, 3, 5, 6, 7, 9, 10, 11, 13 },\r\nCOST = { [\"Second Wind\"] = 2, [\"Action Surge\"] = 5, Rage = 3, [\"Focus Points\"] = 1, [\"Sorcery Points\"] = 1,\r\n[\"Channel Divinity\"] = 3, [\"Bardic Inspiration\"] = 2, [\"Wild Shape\"] = 3, Tireless = 2, [\"Nature's Veil\"] = 2,\r\n[\"Innate Sorcery\"] = 3 },\r\n\r\n\r\nGONE = { [\"Arcane Recovery\"] = true, [\"Magical Cunning\"] = true, [\"Sorcerous Restoration\"] = true, [\"Uncanny Metabolism\"] = true,\r\n[\"Hunter's Mark (free)\"] = true, [\"Divine Smite (free)\"] = true },\r\nNAME = { Barbarian = \"기력\", Fighter = \"기력\", Monk = \"기력\", Rogue = \"기력\", Ranger = \"기력\", Cleric = \"신성력\", Paladin = \"신성력\",\r\nBard = \"마나\", Druid = \"마나\", Sorcerer = \"마나\", Warlock = \"마나\", Wizard = \"마나\" },\r\n}\r\n\r\nfunction K.MP.cost(name)\r\nif not K.LITE or type(name) ~= \"string\" then return nil end\r\nlocal n = tonumber(name:match(\"^Spell Slot (%d)$\"))\r\nif n then return K.MP.SPELL[n] end\r\nif name == \"Lay On Hands\" then return 0.2 end\r\nreturn K.MP.COST[name]\r\nend\r\nfunction K.MP.name(sh)\r\nif K.EN then return \"MP\" end\r\nreturn K.MP.NAME[(sh or SHEET or {}).class or \"\"] or \"마나\"\r\nend\r\n\r\nfunction K.MP.wrap(rec)\r\nif not K.LITE or type(rec) ~= \"table\" or type(rec.res) ~= \"table\" or getmetatable(rec.res) then return rec end\r\nfor k in pairs(rec.res) do\r\nif K.MP.GONE[k] or K.MP.cost(k) then rec.res[k] = nil end\r\nend\r\nlocal function read(t, k)\r\nif K.MP.GONE[k] then return 0 end\r\nlocal c = K.MP.cost(k)\r\nif not c then return nil end\r\nlocal mp = tonumber(rawget(t, \"MP\")) or 0\r\nlocal lv = tonumber((tostring(k)):match(\"^Spell Slot (%d)$\"))\r\nif lv and lv >= 6 and type(rec.hi) == \"table\" and rec.hi[tostring(lv)] then return 0 end\r\nif k == \"Lay On Hands\" then return mp * 5 end\r\nreturn math.floor(mp / c)\r\nend\r\nsetmetatable(rec.res, {\r\n__index = read,\r\n__newindex = function(t, k, v)\r\nif K.MP.GONE[k] then return end\r\nlocal c = K.MP.cost(k)\r\nif not c then rawset(t, k, v); return end\r\nif not tonumber(v) then return end\r\nlocal d = tonumber(v) - (read(t, k) or 0)\r\nif d >= 0 then return end\r\nlocal mp = tonumber(rawget(t, \"MP\")) or 0\r\nlocal spend = k == \"Lay On Hands\" and math.ceil(-d / 5) or (-d * c)\r\nrawset(t, \"MP\", math.max(0, mp - spend))\r\nlocal lv = tonumber((tostring(k)):match(\"^Spell Slot (%d)$\"))\r\nif lv and lv >= 6 then\r\nrec.hi = type(rec.hi) == \"table\" and rec.hi or {}\r\nrec.hi[tostring(lv)] = true\r\nend\r\nend,\r\n})\r\nreturn rec\r\nend\r\n\r\nfunction K.MP.wrapAll(pc)\r\nif not K.LITE or type(pc) ~= \"table\" then return pc end\r\nK.MP.wrap(pc)\r\nfor _, l in ipairs({ pc.allies, pc.guests }) do\r\nfor _, a in ipairs(type(l) == \"table\" and l or {}) do K.MP.wrap(a) end\r\nend\r\nreturn pc\r\nend\r\n\r\nfunction K.MP.text(rec, sh)\r\nlocal cur = type(rec) == \"table\" and type(rec.res) == \"table\" and tonumber(rawget(rec.res, \"MP\")) or 0\r\nlocal max = PC.res.MP and PC.res.MP.max or 0\r\nreturn K.MP.name(sh) .. \" \" .. cur .. \"/\" .. max\r\nend\r\n\r\nK.MP.REQ = {\r\n{ \", or a spell slot to cast a spell\", \"\" },\r\n{ \"Lua spends the slot, so never write USE for a spell slot\", \"Lua takes the MP, so never write USE or MP for a spell\" },\r\n{ \"Slots are in the feature uses%.\", \"Spells cost MP by their level (the MP line in GAME STATE).\" },\r\n{ \"Spell slots are spent by CAST%.\", \"A spell's MP is spent by its CAST.\" },\r\n{ \"in a Short Rest Lua recovers slots by itself %b(); \", \"\" },\r\n{ \"when a fight starts Lua gives back all Rage uses %(once per Long Rest%); \", \"\" },\r\n{ \"when a fight starts with no Wild Shape uses left, Lua gives one back; once per Long Rest Wild Shape uses can become one spell slot, 2 levels each %b(); \", \"\" },\r\n{ \" %(Lua rolls; %d+ uses per Long Rest%)\", \" (Lua rolls)\" },\r\n{ \"when a fight starts, Lua brings Bardic Inspiration up to 2 if it is lower\", \"its share is in MP\" },\r\n{ \"when a fight starts, Lua brings Focus Points up to 4 if they are 3 or fewer\", \"its share is in MP\" },\r\n{ \"once per Short or Long Rest\", \"once per Long Rest\" },\r\n{ \"gain the benefits of a Short Rest and also regain\", \"regain\" },\r\n{ \"; a Short Rest also removes one Exhaustion level %(Lua%)\", \"\" },\r\n{ \"Hit Points, Hit Point Dice\", \"Hit Points\" }, { \"Hit Points; Hit Point Dice\", \"Hit Points\" }, { \"Hit Points, and Hit Point Dice\", \"Hit Points\" },\r\n\r\n{ \"Using a Higher%-Level Spell Slot\", \"Casting at a Higher Level\" },\r\n{ \"Use the spell slot's level for the spell's level\", \"Use the level it is cast at for the spell's level\" },\r\n{ \"spell slot level above\", \"level above\" },\r\n{ \"use a level (%d%+?) spell slot\", \"cast it at level %1\" },\r\n{ \"use a level (%d) or (%d) spell slot\", \"cast it at level %1 or %2\" },\r\n{ \"using a level (%d) spell slot\", \"at level %1\" },\r\n{ \"with a level (%d%+?) spell slot\", \"at level %1\" },\r\n{ \"with a spell slot of level (%d)\", \"at level %1\" },\r\n{ \"%(level (%d)%-(%d) slot%)\", \"(level %1-%2)\" },\r\n{ \"the level of the slot expended\", \"the level it was cast at\" },\r\n{ \"the level of the spell slot you use\", \"the level you cast it at\" },\r\n{ \"If that spell was cast with a spell slot, the slot isn't expended\", \"If that spell cost MP, the MP isn't spent\" },\r\n{ \"expending spell slots for both\", \"paying MP for both\" },\r\n{ \"expend a spell slot of the spell's level\", \"pay the MP of the spell's level\" },\r\n{ \"The level of the slot used to cast the spell\", \"The level the spell is cast at\" },\r\n{ \"%(a level (%d) slot restores it%)\", \"([USE|Spell Slot %1] restores it for that level's MP)\" },\r\n{ \"%(a Pact Magic slot restores it%)\", \"([USE|Spell Slot N] restores it for that level's MP)\" },\r\n{ \"a higher level spends a slot as usual\", \"a higher level costs MP as usual\" },\r\n{ \"casting with a level 1%-4 slot, roll 1d4; if it equals the slot level the slot is not spent %(narrate it; restore the slot with the user's OK%)\",\r\n\"casting a level 1-4 spell, roll 1d4; if it equals the spell level the spell's MP comes back: [MP|Player|+N|Boon of Spell Recall], N its cost (in a fight too)\" },\r\n{ \"of a level with slots\", \"of a level Player can cast\" },\r\n{ \"from a level 1%-5 slot\", \"of level 1-5\" },\r\n{ \"|slot level|\", \"|level|\" }, { \"|slot level]\", \"|level]\" }, { \"|slot]\", \"|level]\" },\r\n{ \"a higher slot\", \"a higher level\" },\r\n{ \"slot level\", \"spell level\" },\r\n{ \"uses no slot\", \"costs no MP\" },\r\n{ \"without a slot\", \"without MP\" },\r\n{ \"with a slot\", \"with MP\" },\r\n{ \"no spell slot left\", \"not enough MP\" },\r\n{ \"spell slots\", \"MP\" }, { \"spell slot\", \"MP\" },\r\n}\r\nfunction K.liteReq(s)\r\nif not K.LITE or type(s) ~= \"string\" then return s end\r\nfor _, r in ipairs(K.MP.REQ) do s = s:gsub(r[1], r[2]) end\r\nreturn s\r\nend\r\n\r\nK.MP.JOSA = { [\"마나\"] = { \"를\", \"로\", \"는\", \"와\" }, [\"기력\"] = { \"을\", \"으로\", \"은\", \"과\" }, [\"신성력\"] = { \"을\", \"으로\", \"은\", \"과\" } }\r\nfunction K.liteMP(s)\r\nif not K.LITE or type(s) ~= \"string\" or not (s:find(\"슬롯\", 1, true) or s:find(\"⟨MP\", 1, true) or s:find(\"짧은 휴식\", 1, true)) then return s end\r\nlocal w = (SHEET and not SHEET.default and PC.res.MP) and K.MP.name() or \"마나\"\r\nlocal j = K.MP.JOSA[w] or K.MP.JOSA[\"기력\"]\r\ns = s:gsub(\"⟨MP을⟩\", w .. j[1]):gsub(\"⟨MP으로⟩\", w .. j[2]):gsub(\"⟨MP은⟩\", w .. j[3]):gsub(\"⟨MP과⟩\", w .. j[4]):gsub(\"⟨MP⟩\", w)\r\ns = s:gsub(\"짧은 휴식이나 긴 휴식\", \"긴 휴식\"):gsub(\"짧은 휴식 효과를 받고 \", \"\"):gsub(\"짧은 휴식에 1회, 긴 휴식에 전부 다시 찹니다\", \"긴 휴식에 다시 찹니다\")\r\n:gsub(\"짧은 휴식에 1회, 긴 휴식에 전부\", \"긴 휴식에 다시 참\")\r\nif not s:find(\"슬롯\", 1, true) then return s end\r\nreturn (s:gsub(\"(%d)레벨 주문을 (%d)레벨 슬롯으로 쓰면\", \"%1레벨 주문을 %2레벨로 쓰면\")\r\n:gsub(\"(%d)레벨 슬롯으로\", \"%1레벨로\")\r\n:gsub(\"(%d)~(%d)레벨 슬롯\", \"%1~%2레벨\")\r\n:gsub(\"주문 슬롯이 있으면 슬롯으로도\", w .. j[2] .. \"도\")\r\n:gsub(\"가진 슬롯으로도\", w .. j[2] .. \"도\")\r\n:gsub(\"주문 슬롯을 써서\", w .. j[1] .. \" 써서\")\r\n:gsub(\"슬롯을 쓰지 않고\", w .. j[1] .. \" 쓰지 않고\")\r\n:gsub(\"슬롯을 쓰지 않습니다\", w .. j[1] .. \" 쓰지 않습니다\")\r\n:gsub(\"계약 슬롯 하나로\", \"레벨을 골라 그 비용의 \" .. w .. j[2])\r\n:gsub(\"계약 슬롯으로 다시\", w .. j[2] .. \" 다시\")\r\n:gsub(\"(%d)레벨 슬롯으로 다시\", \"%1레벨 비용으로 다시\")\r\n:gsub(\"슬롯을 쓴 주문\", w .. j[1] .. \" 쓴 주문\")\r\n:gsub(\"주문 슬롯 없이\", w .. \" 없이\")\r\n:gsub(\"슬롯과 재료 없이\", w .. j[4] .. \" 재료 없이\")\r\n:gsub(\"슬롯 없이\", w .. \" 없이\")\r\n:gsub(\"슬롯 대신\", w .. \" 대신\")\r\n:gsub(\"슬롯은 안 씁니다\", w .. j[3] .. \" 안 씁니다\")\r\n:gsub(\"높은 슬롯으로\", \"높은 레벨로\")\r\n:gsub(\"슬롯을 올리면\", \"레벨을 올리면\")\r\n:gsub(\"그 슬롯 레벨\", \"그 레벨\")\r\n:gsub(\"슬롯 레벨\", \"주문 레벨\")\r\n:gsub(\"소마법이나 슬롯이 있는 레벨\", \"소마법이나 쓸 수 있는 레벨\")\r\n:gsub(\"(%d)레벨 슬롯\", \"%1레벨 주문\"))\r\nend\r\n\r\nfunction K.MP.shown(name)\r\nlocal r = K.LITE and PC.res[name]\r\nreturn not (type(r) == \"table\" and r.virtual)\r\nend\r\n\r\nfunction K.MP.price(name, n)\r\nlocal r = K.LITE and PC.res[name]\r\nlocal c = type(r) == \"table\" and r.virtual and K.MP.cost(name)\r\nif not c then return nil end\r\nn = math.max(1, tonumber(n) or 1)\r\nreturn name == \"Lay On Hands\" and math.ceil(n / 5) or c * n\r\nend\r\n\r\n\r\nfunction K.MP.after(rec, name, n)\r\nlocal cost = K.MP.price(name, n)\r\nreturn cost and (\"-\" .. cost .. \", \" .. K.MP.text(rec)) or nil\r\nend\r\nfunction K.MP.short(rec, name, n, what)\r\nlocal cost = K.MP.price(name, n)\r\nif not cost then return nil end\r\nlocal lv = tonumber(name:match(\"^Spell Slot (%d)$\"))\r\nif lv and lv >= 6 and type(rec.hi) == \"table\" and rec.hi[tostring(lv)] then\r\nreturn \"a level \" .. lv .. \" spell was cast already since the last Long Rest (level 6 and up: once each)\"\r\nend\r\nreturn \"not enough \" .. K.MP.name() .. \": \" .. (what or name) .. \" costs \" .. cost .. \", \" .. K.MP.text(rec)\r\nend\r\n\r\nfunction K.MP.line(rec, who)\r\nif not (K.LITE and PC.res.MP) then return nil end\r\nlocal sp, top = {}, 0\r\nfor l = 1, 9 do if PC.res[\"Spell Slot \" .. l] then top = l end end\r\nfor l = 1, math.min(top, 5) do sp[#sp + 1] = tostring(K.MP.SPELL[l]) end\r\nlocal o = (who or \"Player\") .. \"'s \" .. K.MP.text(rec) .. \" (MP, one pool: a Long Rest fills it, a breather outside a fight gives some back).\"\r\nif top > 0 then\r\no = o .. \" A spell costs by its level: \" .. table.concat(sp, \"/\") .. \" for level 1-\" .. math.min(top, 5)\r\nif top >= 6 then\r\nlocal hi, used = {}, {}\r\nfor l = 6, top do\r\nhi[#hi + 1] = l .. \": \" .. K.MP.SPELL[l]\r\nif type(rec.hi) == \"table\" and rec.hi[tostring(l)] then used[#used + 1] = tostring(l) end\r\nend\r\no = o .. \"; \" .. table.concat(hi, \", \") .. \", each of these levels once per Long Rest\" .. (#used > 0 and (\" (cast already: \" .. table.concat(used, \", \") .. \")\") or \"\")\r\nend\r\no = o .. \".\"\r\nend\r\nlocal uses = {}\r\nfor name, r in pairs(PC.res) do\r\nif r.virtual and not name:match(\"^Spell Slot\") then\r\nuses[#uses + 1] = name == \"Lay On Hands\" and \"Lay On Hands 1 per 5 HP\" or (name .. \" \" .. K.MP.cost(name))\r\nend\r\nend\r\ntable.sort(uses)\r\nif #uses > 0 then o = o .. \" Uses: \" .. table.concat(uses, \", \") .. \".\" end\r\nreturn o .. \" Lua takes it with the CAST and USE tags; never write MP yourself.\"\r\nend\r\n\r\nlocal function classRes(sh)\r\nlocal cl, lv = sh.class, sh.level\r\nlocal row = CLASSES[cl].levels[lv] or {}\r\nlocal res = {}\r\n\r\n\r\nlocal gone = K.ownedGone(sh).res\r\nfor _, c in ipairs(K.classes(sh)) do\r\nfor name, v in pairs(c.row.res or {}) do if not gone[name] then\r\nlocal max = v[1]\r\nif max == \"CHA\" or max == \"WIS\" or max == \"INT\" then\r\nmax = math.max(1, abilityMod(K.score(sh, ABBR[max])))\r\nelseif max == \"L\" then\r\nmax = c.level\r\nelseif max == \"5L\" then\r\nmax = 5 * c.level\r\nelseif max == \"PB\" then\r\nmax = 2 + math.floor((K.charLevel(sh) - 1) / 4)\r\nend\r\nlocal short = v[2] == \"all\" and max or (tonumber(v[2]) or 0)\r\nif res[name] then res[name] = { max = res[name].max + max, short = res[name].short + short }\r\nelse res[name] = { max = max, short = short } end\r\nend end\r\nend\r\n\r\n\r\nlocal sc = K.spellcasters(sh)\r\nlocal slots\r\nif #sc == 1 then\r\nslots = sc[1].row.slots\r\nelseif #sc > 1 then\r\nlocal mlv = 0\r\nfor _, c in ipairs(sc) do mlv = mlv + K.casterLv(c.name, c.level) end\r\nslots = K.MC_SLOTS[math.min(#K.MC_SLOTS, mlv)]\r\nend\r\nfor i, n in ipairs(slots or {}) do\r\nif n > 0 then res[\"Spell Slot \" .. i] = { max = n, short = 0 } end\r\nend\r\nlocal pactC = K.pactClass(sh)\r\nif pactC then\r\nlocal nm = #sc > 0 and \"Pact Slot \" or \"Spell Slot \"\r\nfor i, n in ipairs(pactC.row.slots or {}) do\r\nif n > 0 then res[nm .. i] = { max = n, short = n } end\r\nend\r\nend\r\nif Feat.res then Feat.res(sh, res) end\r\n\r\nif K.LITE and K.MP_MAX then\r\nlocal mpmax = ((K.MP_MAX[cl] or {})[lv]) or 0\r\nfor name in pairs(res) do if K.MP.GONE[name] then res[name] = nil end end\r\nfor name, r in pairs(res) do\r\nlocal c = K.MP.cost(name)\r\nif c then res[name] = { max = name == \"Lay On Hands\" and mpmax * 5 or math.floor(mpmax / c), short = 0, virtual = true } end\r\nend\r\n\r\nlocal top = 0\r\nfor i, n in ipairs(row.slots or {}) do if n > 0 then top = i end end\r\nfor i = 1, top do res[\"Spell Slot \" .. i] = { max = math.floor(mpmax / K.MP.SPELL[i]), short = 0, virtual = true } end\r\nif mpmax > 0 then res.MP = { max = mpmax, short = 0 } end\r\nend\r\nreturn res\r\nend\r\n\r\n\r\nlocal function weaponProf(w)\r\nlocal rule = CLASSES[SHEET.class].weapons\r\nif rule == \"all\" or not w.martial then return true end\r\n\r\nfor _, e in ipairs(Feat.fxOf and Feat.fxOf(SHEET, \"weapon_prof\") or {}) do\r\nif e.martial then return true end\r\nfor _, n in ipairs(type(e.weapons) == \"table\" and e.weapons or {}) do if WEAPONS[n] == w then return true end end\r\nend\r\nif type(SHEET.picks) == \"table\" and (SHEET.picks.order == \"Protector\" or SHEET.picks.primal == \"Warden\") then return true end\r\nfor _, m in ipairs(K.mcList(SHEET)) do if K.mcGains(m.class).martial then return true end end\r\n\r\nfor _, n in ipairs(type(CLASSES[SHEET.class].weapons_also) == \"table\" and CLASSES[SHEET.class].weapons_also or {}) do if WEAPONS[n] == w then return true end end\r\nif rule == \"light\" then return w.light == true end\r\nreturn rule == \"finesse_light\" and (w.finesse or w.light) or false\r\nend\r\n\r\nlocal function armorProf(cat)\r\nif cat == \"heavy\" and type(SHEET.picks) == \"table\" and SHEET.picks.order == \"Protector\" then return true end\r\n\r\nfor _, e in ipairs(Feat.fxOf and Feat.fxOf(SHEET, \"armor_prof\") or {}) do\r\nfor _, c in ipairs(type(e.cats) == \"table\" and e.cats or {}) do if c == cat then return true end end\r\nend\r\nif cat == \"medium\" and type(SHEET.picks) == \"table\" and SHEET.picks.primal == \"Warden\" then return true end\r\nif CLASSES[SHEET.class].armor[cat] == true then return true end\r\nfor _, m in ipairs(K.mcList(SHEET)) do if K.mcGains(m.class)[cat] then return true end end\r\nreturn false\r\nend\r\n\r\n\r\n\r\n\r\nfunction K.d20Floor(sh, kind, ab)\r\nlocal best\r\nfor _, e in ipairs(Feat.fxOf and type(sh) == \"table\" and sh.class and Feat.fxOf(sh, \"d20_floor\") or {}) do\r\nlocal on = e.on\r\nlocal fits = on == \"all\" or (on == \"checks\" and kind == \"check\") or (on == \"saves\" and (kind == \"save\" or kind == \"conc\"))\r\nor (on == \"attacks\" and kind == \"attack\") or (on == \"conc\" and kind == \"conc\")\r\nif fits and type(e.abilities) == \"table\" then\r\nlocal okA = false\r\nfor _, x in ipairs(e.abilities) do if x == ab then okA = true end end\r\nfits = okA\r\nend\r\nlocal v = tonumber(e.value)\r\nif fits and v and (not best or v > best) then best = v end\r\nend\r\nreturn best\r\nend\r\n\r\nfunction K.dexCap(sh, cat)\r\nlocal cap = 2\r\nfor _, e in ipairs(Feat.fxOf and type(sh) == \"table\" and sh.class and Feat.fxOf(sh, \"armor_dex\") or {}) do\r\nif e.cat == cat and tonumber(e.max) and tonumber(e.max) > cap then cap = tonumber(e.max) end\r\nend\r\nreturn cap\r\nend\r\n\r\n\r\n\r\n\r\nfunction K.profSkills(sh)\r\nlocal out, seen = {}, {}\r\nlocal function add(s)\r\nif type(s) == \"string\" and not seen[s] then seen[s] = true; out[#out + 1] = s end\r\nend\r\nfor _, s in ipairs(sh.skills or {}) do add(s) end\r\nlocal pk = type(sh.picks) == \"table\" and sh.picks or {}\r\nadd(pk.keen)\r\nif sh.species == \"Human\" then add(pk.skillful) end\r\n\r\nif sh.species == \"Beastfolk\" then\r\nadd(\"Perception\")\r\nif pk.beast == \"Dog\" then add(\"Survival\") elseif pk.beast == \"Fox\" then add(\"Deception\") end\r\nend\r\nfor _, s in ipairs(type(pk.skilled) == \"table\" and pk.skilled or {}) do add(s) end\r\nlocal xs = false\r\nfor _, c in ipairs(K.classes(sh)) do if c.row.extra_skill then xs = true end end\r\nif xs then for _, s in ipairs(type(pk.xskill) == \"table\" and pk.xskill or {}) do add(s) end end\r\nfor _, s in ipairs(type(pk.mcskill) == \"table\" and pk.mcskill or {}) do add(s) end\r\n\r\nfor _, e in ipairs(Feat.fxOf and sh.class and Feat.fxOf(sh, \"skill_prof\") or {}) do for _, s in ipairs(e.skills or {}) do add(s) end end\r\nreturn out\r\nend\r\n\r\n\r\n\r\nfunction K.holdLevel(sh)\r\nlocal rows = CLASSES[sh.class].levels\r\nif sh.held and rows[sh.held] then sh.level, sh.held = sh.held, nil end\r\nif not rows[sh.level] then sh.held = sh.held or sh.level; sh.level = #rows end\r\nend\r\n\r\nlocal function applySheet(sh)\r\nK.holdLevel(sh)\r\nif K.subCastApply then K.subCastApply(sh) end\r\n\r\nif Feat.fxOf then\r\n\r\n\r\nlocal live = {}\r\nfor _, e in ipairs(Feat.fxOf(sh, \"score_up\")) do\r\nlive[e.src] = true\r\nsh.ups = type(sh.ups) == \"table\" and sh.ups or {}\r\nif not sh.ups[e.src] then\r\nlocal gave = {}\r\nfor _, a in ipairs(e.abilities or {}) do\r\nlocal s = sh.scores[a] or 10\r\nsh.scores[a] = math.max(s, math.min(e.max or 20, s + (e.amount or 0)))\r\ngave[a] = sh.scores[a] - s\r\nend\r\nsh.ups[e.src] = gave\r\nend\r\nend\r\nfor src, g in pairs(type(sh.ups) == \"table\" and sh.ups or {}) do\r\nif type(g) == \"table\" and not live[src] then\r\nfor a, d in pairs(g) do sh.scores[a] = (sh.scores[a] or 10) - (tonumber(d) or 0) end\r\nsh.ups[src] = nil\r\nend\r\nend\r\nend\r\nSHEET = sh\r\n\r\n\r\nlocal ms = type(sh.mscores) == \"table\" and sh.mscores or {}\r\nfor _, a in ipairs(ABILS) do\r\nlocal ra = K.swapAb and K.swapAb(sh, a) or a\r\nlocal s = K.drained(sh, a, tonumber(ms[ra]) or sh.scores[ra])\r\nSCORE[a] = s\r\nMOD[a] = abilityMod(s)\r\nend\r\nPROF = 2 + math.floor((K.charLevel(sh) - 1) / 4) + (tonumber(sh.mpb) or 0)\r\nfor k in pairs(SAVE_PROF) do SAVE_PROF[k] = nil end\r\nfor _, a in ipairs(CLASSES[sh.class].saves) do SAVE_PROF[a] = true end\r\n\r\nif Feat.fxOf then\r\nfor _, e in ipairs(Feat.fxOf(sh, \"save_prof\")) do for _, a in ipairs(e.abilities or {}) do SAVE_PROF[a] = true end end\r\nend\r\n\r\nfor _, g in ipairs(type(sh.gfeats) == \"table\" and sh.gfeats or {}) do\r\nif type(g) == \"table\" and g.ab and K.FX and (K.FX[g.name] or {}).asi_save then SAVE_PROF[g.ab] = true end\r\nend\r\nfor k in pairs(SKILL_PROF) do SKILL_PROF[k] = nil end\r\n\r\nfor _, s in ipairs(K.profSkills(sh)) do SKILL_PROF[s] = true end\r\nlocal pk = type(sh.picks) == \"table\" and sh.picks or {}\r\nfor k in pairs(EXPERT) do EXPERT[k] = nil end\r\nfor _, s in ipairs(sh.expertise or {}) do EXPERT[s] = true end\r\n\r\nif Feat.fxOf and sh.class then\r\nfor _, e in ipairs(Feat.fxOf(sh, \"skill_expert\")) do for _, x in ipairs(e.skills or {}) do if SKILL_PROF[x] then EXPERT[x] = true end end end\r\n\r\n\r\nfor _, e in ipairs(Feat.fxOf(sh, \"skill_fix\")) do\r\nlocal list = type(e.skills) == \"table\" and e.skills or {}\r\nif e.pick then local v = pk[e.pick]; list = type(v) == \"string\" and { v } or (type(v) == \"table\" and v or {}) end\r\nfor _, x in ipairs(list) do if SKILL[x] then if SKILL_PROF[x] then EXPERT[x] = true else SKILL_PROF[x] = true end end end\r\nend\r\nend\r\nPC.hp = sheetMaxHp(sh)\r\nPC.hit_die = CLASSES[sh.class].hit_die\r\nPC.class = sh.class\r\nPC.speed = (SPECIES[sh.species] or {}).speed or 30\r\nif sh.species == \"Elf\" and pk.lineage == \"Wood Elf\" then PC.speed = 35 end\r\n\r\nfor _, e in ipairs(Feat.fxOf and Feat.fxOf(sh, \"speed\") or {}) do\r\nif e.kind == \"walk\" and e.add ~= nil and K.charLevel(sh) >= (tonumber(e.from) or 0) then PC.speed = PC.speed + (K.fxNum(e.add, sh, e.srcLv) or 0) end\r\nend\r\nPC.res = classRes(sh)\r\nend\r\n\r\n\r\n\r\nlocal function stateOf(id, name)\r\nlocal sc = K.SC\r\nif not sc then return getState(id, name) end\r\nlocal v = sc[name]\r\nif v == nil then\r\nv = getState(id, name)\r\nsc[name] = (v == nil) and false or v\r\nend\r\nreturn v or nil\r\nend\r\n\r\nK.LOCK_KEYS = { dnd_sheet = true, dnd_pc = true, dnd_combat = true, dnd_clock = true, dnd_base = true, dnd_turn_delta = true }\r\nfunction K.lockedKey(k)\r\nreturn K.LOCKED and (K.LOCK_KEYS[k] or tostring(k):match(\"^dnd_seed_%d+$\")) and true or false\r\nend\r\nif setState and not K.rawSetState then\r\nK.rawSetState, K.rawSetStateChanged = setState, setStateChanged\r\nsetState = function(id, k, v) if K.lockedKey(k) then return nil end return K.rawSetState(id, k, v) end\r\nif K.rawSetStateChanged then\r\nsetStateChanged = function(id, k, v) if K.lockedKey(k) then return nil end return K.rawSetStateChanged(id, k, v) end\r\nend\r\nend\r\n\r\nlocal function loadSheet(id)\r\nif K.customBg then K.customBg(id) end\r\nlocal sh = stateOf(id, \"dnd_sheet\")\r\nif type(sh) ~= \"table\" or type(sh.scores) ~= \"table\" or not CLASSES[sh.class or \"\"] then\r\nsh = {}\r\nfor k, v in pairs(DEFAULT_SHEET) do\r\nif type(v) == \"table\" then\r\nlocal c = {}\r\nfor kk, vv in pairs(v) do\r\nif type(vv) == \"table\" then\r\nlocal cc = {}\r\nfor i, x in pairs(vv) do cc[i] = x end\r\nvv = cc\r\nend\r\nc[kk] = vv\r\nend\r\nv = c\r\nend\r\nsh[k] = v\r\nend\r\nend\r\nsh.skills = sh.skills or {}\r\nK.holdLevel(sh)\r\nreturn sh\r\nend\r\n\r\napplySheet(DEFAULT_SHEET)\r\n\r\n\r\n\r\nlocal function trim(s) return (s:gsub(\"^%s+\", \"\"):gsub(\"%s+$\", \"\")) end\r\n\r\nlocal function split(s)\r\nlocal out = {}\r\nfor part in (s .. \"|\"):gmatch(\"([^|]*)|\") do out[#out + 1] = trim(part) end\r\nreturn out\r\nend\r\n\r\n\r\nlocal function splitNames(s)\r\nlocal out = {}\r\nfor n in (s or \"\"):gmatch(\"[^,]+\") do\r\nn = trim(n)\r\nif n ~= \"\" and n ~= \"-\" then out[#out + 1] = n end\r\nend\r\nreturn out\r\nend\r\n\r\n\r\nlocal function clockNow()\r\nlocal ok, t = pcall(function() return os.clock() end)\r\nreturn ok and type(t) == \"number\" and t or 0\r\nend\r\n\r\n\r\nlocal function args(f)\r\nlocal out = {}\r\nfor _, v in ipairs(f) do\r\nif v == \"ok\" or v == \"auto\" or v:match(\"^bad:\") then break end\r\nout[#out + 1] = v\r\nend\r\nreturn out\r\nend\r\n\r\nlocal function verdictOf(bad) return (#bad == 0) and \"ok\" or (\"bad:\" .. table.concat(bad, \";\")) end\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\nK.TOOL_VAR = {}\r\nfor name, t in pairs(K.TOOLS or {}) do\r\nfor v in (((t.variants or \"\"):gsub(\"%b()\", \"\")) .. \",\"):gmatch(\"%s*([^,]-)%s*,\") do\r\nif v ~= \"\" then K.TOOL_VAR[v:lower()] = name end\r\nend\r\nNAMES_KO[name] = NAMES_KO[name] or t.ko\r\nend\r\nfunction K.toolProfs(sh)\r\nlocal out = {}\r\nif type(sh) ~= \"table\" then return out end\r\nlocal bg = BACKGROUNDS[sh.background or \"\"]\r\nif bg and bg.tool and K.TOOLS[bg.tool] then out[bg.tool] = true end\r\nif type(sh.bgTool) == \"string\" and K.TOOLS[sh.bgTool] then out[sh.bgTool] = true end\r\nfor _, c in ipairs(K.classes(sh)) do\r\nfor _, t in ipairs((CLASSES[c.name] or {}).tools or {}) do out[t] = true end\r\n\r\nlocal srec = c.level >= K.subLevel(c.name) and K.subRec(c.name, K.subOf(sh, c.name))\r\nfor _, t in ipairs(type(srec) == \"table\" and type(srec.tools) == \"table\" and srec.tools or {}) do\r\nif K.TOOLS[t] then out[t] = true end\r\nend\r\nend\r\nlocal pk = type(sh.picks) == \"table\" and sh.picks or {}\r\nif type(pk.monkTool) == \"string\" and K.TOOLS[pk.monkTool] then out[pk.monkTool] = true end\r\nreturn out\r\nend\r\n\r\n\r\nfunction K.formOf()\r\nlocal r = Cond and Cond.cur\r\nlocal m = type(r) == \"table\" and r.form and MONSTERS[r.form]\r\nreturn m and m.sc and m or nil\r\nend\r\nfunction K.abMod(ab)\r\nlocal m = K.formOf()\r\nif m and m.sc[ab] then return abilityMod(m.sc[ab]) end\r\nif m and K.polyNow() then return K.polyMod(m, ab) end\r\nreturn MOD[ab]\r\nend\r\n\r\n\r\nfunction K.polyNow()\r\nlocal r = Cond and Cond.cur\r\nreturn type(r) == \"table\" and type(r.formBy) == \"table\" and r.form ~= nil\r\nend\r\nfunction K.polyMod(m, ab)\r\nif type(m.sc) == \"table\" and m.sc[ab] then return abilityMod(m.sc[ab]) end\r\nreturn tonumber(type(m.saves) == \"table\" and m.saves[ab]) or 0\r\nend\r\nlocal function bonusFor(name)\r\nlocal fm = K.formOf()\r\nif SKILL[name] then\r\nlocal abN = SKILL[name]\r\n\r\nfor _, e in ipairs(SHEET and SHEET.class and Feat and Feat.fxOf and Feat.fxOf(SHEET, \"skill_ability\") or {}) do\r\nif e.skill == name and MOD[e.ability or \"\"] and K.abMod(e.ability) > K.abMod(abN) then abN = e.ability end\r\nend\r\nlocal b = K.abMod(abN) + (SKILL_PROF[name] and PROF or 0) * (EXPERT[name] and 2 or 1)\r\nlocal beastSk = fm and fm.sk and fm.sk[name]\r\nif fm and K.polyNow() then return (tonumber(beastSk) or K.polyMod(fm, abN)) + K.partySkill(name) end\r\n\r\nlocal pk = SHEET and type(SHEET.picks) == \"table\" and SHEET.picks or {}\r\nif (name == \"Arcana\" or name == \"Religion\") and pk.order == \"Thaumaturge\" then b = b + math.max(1, MOD.Wisdom) end\r\nif (name == \"Arcana\" or name == \"Nature\") and pk.primal == \"Magician\" then b = b + math.max(1, MOD.Wisdom) end\r\nif not SKILL_PROF[name] and not beastSk and SHEET and K.cl(SHEET, \"Bard\") >= 2 then b = b + math.floor(PROF / 2) end\r\nif beastSk and beastSk > b then b = beastSk end\r\nb = b + K.partySkill(name)\r\nb = b + K.checkBonus(name, SKILL[name])\r\nb = b + (K.lootCheck and K.lootCheck(Cond and Cond.cur) or 0)\r\nreturn b\r\nend\r\nif MOD[name] then return K.abMod(name) + (K.lootCheck and K.lootCheck(Cond and Cond.cur) or 0) + K.checkBonus(nil, name) end\r\n\r\nlocal tool = K.TOOLS and K.TOOLS[name]\r\nif tool and SHEET then\r\nlocal prof = K.toolProfs(SHEET)[name]\r\nreturn K.abMod(tool.ab) + (prof and PROF or (K.cl(SHEET, \"Bard\") >= 2 and math.floor(PROF / 2) or 0))\r\n+ (K.lootCheck and K.lootCheck(Cond and Cond.cur) or 0)\r\nend\r\nlocal ab = name:match(\"^(%a+) save$\")\r\n\r\n\r\nif ab and MOD[ab] and fm and K.polyNow() then\r\nreturn (tonumber(type(fm.saves) == \"table\" and fm.saves[ab]) or K.polyMod(fm, ab)) + (K.PARTY and K.PARTY.aura or 0) + (K.buffSum and K.buffSum(Cond and Cond.cur, \"save\") or 0)\r\nend\r\nif ab and MOD[ab] then\r\nlocal own = K.abMod(ab) + (SAVE_PROF[ab] and PROF or 0)\r\nif fm and fm.saves and tonumber(fm.saves[ab]) and fm.saves[ab] > own then own = fm.saves[ab] end\r\nif fm and SHEET and Feat and Feat.fxOf then\r\nfor _, e in ipairs(Feat.fxOf(SHEET, \"form_save_add\")) do if e[ab] then own = own + K.fxNum(e[ab], SHEET, e.srcLv) end end\r\nend\r\nreturn own + (K.PARTY and K.PARTY.aura or 0) + (K.lootSave and K.lootSave(Cond and Cond.cur) or 0) + (K.buffSum and K.buffSum(Cond and Cond.cur, \"save\") or 0)\r\n+ (K.recFx and K.recFx(Cond and Cond.cur).saves[ab] or 0)\r\nend\r\nreturn nil\r\nend\r\n\r\n\r\n\r\nfunction K.checkBonus(skill, ab)\r\nif not (SHEET and Feat and Feat.fxOf) then return 0 end\r\nlocal n = 0\r\nfor _, e in ipairs(Feat.fxOf(SHEET, \"check_bonus\")) do\r\nlocal hit = false\r\nfor _, x in ipairs(type(e.skills) == \"table\" and e.skills or {}) do if x == skill then hit = true end end\r\nfor _, x in ipairs(type(e.abilities) == \"table\" and e.abilities or {}) do if x == ab then hit = true end end\r\nif hit then n = n + math.max(tonumber(e.min) or -99, K.fxNum(e.add or 0, SHEET, e.srcLv)) end\r\nend\r\nreturn n\r\nend\r\n\r\n\r\n\r\nfunction K.otherSkills(sh)\r\nlocal prof, names, out = {}, {}, {}\r\nfor _, k in ipairs(K.profSkills(sh)) do prof[k] = true end\r\nfor k in pairs(SKILL) do names[#names + 1] = k end\r\ntable.sort(names)\r\nfor _, k in ipairs(names) do\r\nif not prof[k] and bonusFor(k) ~= MOD[SKILL[k]] then out[#out + 1] = string.format(\"%s %+d\", k, bonusFor(k)) end\r\nend\r\nreturn out\r\nend\r\n\r\n\r\nlocal function parseFormula(f)\r\nlocal dice, mod, neg = {}, 0, nil\r\nf = f:gsub(\"%s\", \"\")\r\nif f == \"\" then return nil end\r\nfor sign, term in f:gmatch(\"([+%-]?)([^+%-]+)\") do\r\nlocal n, s = term:match(\"^(%d*)d(%d+)$\")\r\nif n and sign == \"-\" then\r\n\r\n\r\nneg = neg or {}\r\nneg[#neg + 1] = { n = tonumber(n ~= \"\" and n or \"1\"), s = tonumber(s) }\r\nelseif n then\r\ndice[#dice + 1] = { n = tonumber(n ~= \"\" and n or \"1\"), s = tonumber(s) }\r\nelseif tonumber(term) then\r\nmod = mod + (sign == \"-\" and -1 or 1) * tonumber(term)\r\nelse\r\nreturn nil\r\nend\r\nend\r\nreturn { dice = dice, mod = mod, neg = neg }\r\nend\r\n\r\n\r\nlocal function canon(p, crit)\r\n\r\nlocal count, d = {}, {}\r\nfor _, x in ipairs(p.dice) do count[x.s] = (count[x.s] or 0) + x.n * (crit and 2 or 1) end\r\nfor sd, n in pairs(count) do d[#d + 1] = { n = n, s = sd } end\r\ntable.sort(d, function(a, b) return a.s > b.s end)\r\nlocal parts = {}\r\nfor _, x in ipairs(d) do parts[#parts + 1] = x.n .. \"d\" .. x.s end\r\nlocal s = table.concat(parts, \"+\")\r\n\r\nif type(p.neg) == \"table\" and #p.neg > 0 then\r\nlocal nc, nd = {}, {}\r\nfor _, x in ipairs(p.neg) do nc[x.s] = (nc[x.s] or 0) + x.n end\r\nfor sd, n in pairs(nc) do nd[#nd + 1] = { n = n, s = sd } end\r\ntable.sort(nd, function(a, b) return a.s > b.s end)\r\nfor _, x in ipairs(nd) do s = s .. \"-\" .. x.n .. \"d\" .. x.s end\r\nend\r\nif p.mod > 0 then s = s .. \"+\" .. p.mod elseif p.mod < 0 then s = s .. p.mod end\r\nreturn s\r\nend\r\n\r\nfunction K.diceSeq(p)\r\nlocal o = {}\r\nfor _, x in ipairs(type(p) == \"table\" and p.dice or {}) do o[#o + 1] = x end\r\nfor _, x in ipairs(type(p) == \"table\" and type(p.neg) == \"table\" and p.neg or {}) do o[#o + 1] = { n = x.n, s = x.s, neg = true } end\r\nreturn o\r\nend\r\n\r\nlocal function newPools(sizes)\r\nlocal p = {}\r\nfor k, n in pairs(sizes or POOL) do\r\nlocal sides = tonumber(k:sub(2))\r\np[k] = {}\r\nfor i = 1, n do p[k][i] = math.random(1, sides) end\r\nend\r\nreturn p\r\nend\r\n\r\n\r\n\r\nlocal function withMod(dmg, mod)\r\nif mod == 0 then return dmg end\r\nif tonumber(dmg) then return tostring(math.max(1, tonumber(dmg) + mod)) end\r\nlocal base, n = dmg:match(\"^(.-%d+d%d+)([+-]%d+)$\")\r\nif base then dmg, mod = base, mod + tonumber(n) end\r\nif mod > 0 then return dmg .. \"+\" .. mod elseif mod < 0 then return dmg .. mod end\r\nreturn dmg\r\nend\r\n\r\n\r\n\r\nlocal LOOT = {}\r\nLOOT.GRADE = { C = 0, B = 1, A = 2, S = 3 }\r\nLOOT.VALUE = { C = 10000, B = 40000, A = 400000, S = 4000000 }\r\n\r\nfunction LOOT.maxGrade(level) return level >= 11 and \"S\" or level >= 5 and \"A\" or \"B\" end\r\n\r\n\r\n\r\nfunction LOOT.tierText(level)\r\nlevel = tonumber(level) or 1\r\nlocal g, srd = \"C or B\", \"Common or Uncommon\"\r\nif level >= 17 then g, srd = \"A or S (S for a boss's or a legendary hoard)\", \"Very Rare or Legendary\"\r\nelseif level >= 11 then g, srd = \"A, or S for a boss's hoard\", \"Rare or Very Rare\"\r\nelseif level >= 5 then g, srd = \"B, or A for a strong foe's or a boss's hoard\", \"Uncommon or Rare\" end\r\nreturn string.format(\"Treasure at level %d, when a find is a magic item: a LOOT of grade %s, or an %s magic item that is %s.\", level, g, K.srdX(), srd)\r\nend\r\n\r\n\r\nlocal function gearOf(pc, name)\r\nif not name then return nil, nil, 0 end\r\nif WEAPONS[name] or ARMOR[name] then return WEAPONS[name], ARMOR[name], 0 end\r\nlocal l = type(pc) == \"table\" and type(pc.loot) == \"table\" and pc.loot[name]\r\n\r\n\r\nif type(l) == \"table\" and l.base then return WEAPONS[l.base], ARMOR[l.base], ((l.att and not l.attuned) or (K.MI and K.MI.off(l))) and 0 or (tonumber(l.plus) or 0) end\r\nreturn nil, nil, 0\r\nend\r\n\r\n\r\n\r\n\r\n\r\n\r\nLOOT.DIE = { B = \"1d4\", A = \"1d6\", S = \"1d8\" }\r\nLOOT.MAXPW = { C = 0, B = 1, A = 1, S = 2 }\r\n\r\n\r\n\r\nLOOT.SPELL_MAX = { B = 2, A = 3, S = 5 }\r\nLOOT.SPELL_USES = { B = 1, A = 2, S = 3 }\r\n\r\nfunction LOOT.spells(rec)\r\nlocal out = {}\r\nfor _, x in ipairs(LOOT.inUse(rec)) do\r\nfor _, w in ipairs(x[2].pw) do if w.k == \"spell\" and w.spell and not out[w.spell] then out[w.spell] = { x[1], x[2] } end end\r\nend\r\nif K.MI then K.MI.spells(rec, out) end\r\nreturn out\r\nend\r\n\r\nfunction LOOT.refill(rec)\r\nfor _, l in pairs(type(rec) == \"table\" and type(rec.loot) == \"table\" and rec.loot or {}) do\r\nif type(l) == \"table\" and type(l.pw) == \"table\" then\r\nfor _, w in ipairs(l.pw) do\r\nif w.k == \"spell\" and w.spell then\r\nl.left = type(l.left) == \"table\" and l.left or {}\r\nl.left[w.spell] = LOOT.SPELL_USES[l.grade] or 1\r\nend\r\nend\r\nend\r\n\r\nlocal m = type(l) == \"table\" and l.srd and K.MAGIC and K.MAGIC[l.srd]\r\nif m then\r\nif l.chmax and type(m.ch) == \"table\" and m.ch.regain and m.ch.regain ~= 0 and m.ch.regain_on == nil then\r\nl.ch = math.min(l.chmax, (tonumber(l.ch) or 0) + K.MI.roll(m.ch.regain))\r\nend\r\nl.left = type(l.left) == \"table\" and l.left or {}\r\nfor _, s in ipairs(m.sp or {}) do if s.day then l.left[s.s] = s.day end end\r\nif type(m.use) == \"table\" and m.use.day then l.left.use = m.use.day end\r\nend\r\nend\r\nend\r\n\r\nfunction LOOT.inUse(rec)\r\nlocal out = {}\r\nif type(rec) ~= \"table\" or type(rec.loot) ~= \"table\" then return out end\r\nlocal eq = type(rec.equip) == \"table\" and rec.equip or {}\r\nfor name, l in pairs(rec.loot) do\r\n\r\nlocal gone = K.MI.off(l)\r\nif type(l) == \"table\" and type(l.pw) == \"table\" and (tonumber((rec.items or {})[name]) or 0) > 0\r\nand not (l.att and not l.attuned) and not l.consumable and not gone and not (l.wornReq and not l.worn) then\r\nif not l.base or eq.main == name or eq.off == name or eq.armor == name then out[#out + 1] = { name, l } end\r\nend\r\nend\r\ntable.sort(out, function(x, y) return x[1] < y[1] end)\r\nreturn out\r\nend\r\nfunction LOOT.resists(rec)\r\nlocal out = {}\r\nfor _, x in ipairs(LOOT.inUse(rec)) do\r\nfor _, w in ipairs(x[2].pw) do if w.k == \"resist\" and w.type then out[#out + 1] = w.type end end\r\nend\r\nreturn out\r\nend\r\nfunction LOOT.saveBonus(rec)\r\nlocal n = 0\r\nfor _, x in ipairs(LOOT.inUse(rec)) do\r\nfor _, w in ipairs(x[2].pw) do if w.k == \"save\" then n = n + (tonumber(w.n) or 1) end end\r\nend\r\nreturn n\r\nend\r\nK.lootSave = LOOT.saveBonus\r\n\r\nfunction LOOT.attackFx(attacks, rec)\r\nif type(rec) ~= \"table\" then return end\r\n\r\n\r\nlocal bp = type(rec.buff) == \"table\" and rec.buff[\"Basic Poison\"]\r\nif type(bp) == \"table\" and bp.poison then\r\nfor _, a in ipairs(attacks) do\r\nif (a.item == bp.poison or (a.ammo and a.ammo == bp.poison)) and (a.type == \"Piercing\" or a.type == \"Slashing\") then\r\nif a.lootDmg then\r\na.extras = a.extras or {}\r\na.extras[#a.extras + 1] = { dice = \"1d4\", type = \"Poison\", src = \"Poison (Basic Poison)\" }\r\nelse\r\na.dmg = a.dmg .. \"+1d4\"\r\na.lootDmg, a.lootDie = \"Poison\", \"1d4\"\r\nend\r\na.poisoned = true\r\nend\r\nend\r\nend\r\nif type(rec.loot) ~= \"table\" then return end\r\nlocal inUse = {}\r\nfor _, x in ipairs(LOOT.inUse(rec)) do inUse[x[1]] = true end\r\nlocal added = {}\r\nfor _, a in ipairs(attacks) do\r\nlocal l = a.item and rec.loot[a.item]\r\n\r\nif type(l) == \"table\" and type(l.pw) == \"table\" and (not l.srd or inUse[a.item]) then\r\nfor _, w in ipairs(l.pw) do\r\nif w.k == \"dmg\" and w.dice then\r\nlocal ty = (w.type == \"weapon\" or not w.type) and a.type or w.type\r\nif w.vs or w.nat20 or w.may or w.thrown then\r\n\r\na.extras = a.extras or {}\r\na.extras[#a.extras + 1] = { dice = w.dice, nat20 = w.nat20 or nil, type = ty,\r\nsrc = ty .. \" (\" .. a.item .. (w.vs and (\", against a \" .. table.concat(w.vs, \" or \")) or \"\")\r\n.. (w.thrown and \", thrown\" or \"\") .. (w.nat20 and \", a d20 of 20 only\" or \"\")\r\n.. (w.may and not w.vs and \", while it is active\" or \"\") .. \")\" }\r\nelse\r\na.dmg = a.dmg .. \"+\" .. w.dice; a.lootDmg = ty; a.lootDie = w.dice\r\nend\r\nend\r\nif w.k == \"crit\" then a.critOn = math.min(a.critOn or 20, 19) end\r\nif w.k == \"dtype\" then a.type = w.type end\r\nif w.k == \"noammo\" then a.ammo = nil end\r\nif w.k == \"bonusattack\" and not added[a.item] and not a.name:find(\"Bonus Action\", 1, true) then\r\nadded[a.item] = true\r\nlocal b = {}\r\nfor k, v in pairs(a) do b[k] = v end\r\nb.name = a.item .. \" (Bonus Action)\"\r\nattacks[#attacks + 1] = b\r\nend\r\nend\r\nend\r\nend\r\n\r\nif K.MI then\r\nfor _, x in ipairs(K.MI.powers(rec, \"dmgbonus\")) do\r\nfor _, a in ipairs(attacks) do\r\nfor _, b in ipairs(x[1].bases or {}) do if a.base == b then a.dmg = withMod(a.dmg, tonumber(x[1].n) or 0) end end\r\nend\r\nend\r\nfor _, x in ipairs(K.MI.powers(rec, \"unarmed\")) do\r\nfor _, a in ipairs(attacks) do\r\nif a.name:match(\"^Unarmed Strike\") then\r\nlocal plus = tonumber(x[1].plus) or 0\r\na.dmg, a.hit, a.type = withMod(x[1].dice, (a.mod or 0) + plus), a.hit + plus, x[1].type\r\nend\r\nend\r\nend\r\nend\r\nend\r\n\r\nfunction LOOT.pwText(pw)\r\nlocal o = {}\r\nfor _, w in ipairs(type(pw) == \"table\" and pw or {}) do\r\nif w.k == \"dmg\" then o[#o + 1] = w.type .. \" +\" .. w.dice .. \" damage\"\r\nelseif w.k == \"crit\" then o[#o + 1] = \"Critical Hit on 19-20\"\r\nelseif w.k == \"resist\" then o[#o + 1] = \"Resistance to \" .. w.type\r\nelseif w.k == \"save\" then o[#o + 1] = \"+1 to every saving throw\"\r\nelseif w.k == \"spell\" then o[#o + 1] = w.spell .. \" \" .. (w.uses or 1) .. \"/Long Rest\" end\r\nend\r\nreturn table.concat(o, \", \")\r\nend\r\n\r\n\r\n\r\nfunction K.isShield(rec, name)\r\nif not name then return false end\r\nif name == \"Shield\" then return true end\r\nlocal _, a = gearOf(rec, name)\r\nreturn a ~= nil and a.cat == \"shield\"\r\nend\r\n\r\nlocal function pcStats(pc)\r\nlocal eq = pc.equip or {}\r\nlocal dex = MOD.Dexterity\r\nlocal wear = type(pc.wear) == \"table\" and pc.wear or {}\r\nlocal ac, speed, notes = 10 + dex, PC.speed, {}\r\n\r\nlocal form = pc.form and MONSTERS[pc.form]\r\nif form then\r\nlocal atk = {}\r\nfor _, x in ipairs(form.attacks or {}) do\r\natk[#atk + 1] = { name = x.name .. \" (\" .. pc.form .. \")\", hit = x.hit, dmg = x.dmg, type = x.type, beast = true, weapon = true }\r\nend\r\nFeat.fxDice(atk)\r\nlocal ba = K.buffSum(pc, \"atk\")\r\nif ba ~= 0 then for _, x in ipairs(atk) do x.hit = (tonumber(x.hit) or 0) + ba end end\r\nlocal wcap = Cond.fx(pc).speedCap\r\nlocal fac = tonumber(form.ac) or 10\r\nfor _, e in ipairs(pc.formBy and {} or Feat.fxOf(SHEET, \"form_ac\")) do fac = math.max(fac, K.fxNum(e.ac, SHEET, e.srcLv)) end\r\nlocal fsp = tonumber(form.speed) or 0\r\nfor bn, b in pairs(type(pc.buff) == \"table\" and pc.buff or {}) do\r\nif type(b) == \"table\" and (b.speedx or bn == \"Haste\") then fsp = fsp * 2; break end\r\nend\r\nreturn { ac = fac, speed = wcap and math.min(fsp, wcap) or fsp, attacks = atk, notes = { (type(pc.formBy) == \"table\" and pc.formBy.spell or \"Wild Shape\") .. \": \" .. pc.form } }\r\nend\r\nlocal _, a, aplus = gearOf(pc, eq.armor)\r\n\r\n\r\n\r\nlocal uaBest, monk, sneak = nil, nil, nil\r\nlocal udFrom = K.udClass(SHEET)\r\nfor _, c in ipairs(K.classes(SHEET)) do\r\nlocal cl, row = CLASSES[c.name], c.row\r\nlocal ua, noShield = row.unarmored, false\r\nif cl.unarmored and c.name == udFrom then ua, noShield = cl.unarmored, cl.unarmored_no_shield end\r\nif ua and not a and not (noShield and K.isShield(pc, eq.off)) then\r\nlocal v = 10 + dex + MOD[ua]\r\nif not uaBest or v > uaBest then uaBest = v end\r\nend\r\nif row.speed then\r\nif cl.unarmored_no_shield then\r\nif not a and not K.isShield(pc, eq.off) then speed = speed + row.speed end\r\nelseif not (a and a.cat == \"heavy\") then\r\nspeed = speed + row.speed\r\nend\r\nend\r\nif row.martial_arts and not a and not K.isShield(pc, eq.off) then monk = row.martial_arts end\r\nif row.sneak_attack then sneak = row.sneak_attack end\r\nend\r\n\r\nfor _, e in ipairs(Feat.fxOf(SHEET, \"unarmored_ac\")) do\r\nif not a and not (e.no_shield and K.isShield(pc, eq.off)) and MOD[e.ability or \"\"] then\r\nlocal v = 10 + (e.dex == false and 0 or dex) + MOD[e.ability] + (e.bonus and K.fxNum(e.bonus, SHEET, K.charLevel(SHEET)) or 0)\r\nif not uaBest or v > uaBest then uaBest = v end\r\nend\r\nend\r\nif uaBest then\r\nac = uaBest\r\nnotes[#notes + 1] = \"Unarmored Defense\"\r\nend\r\nif a then\r\nif a.dex == \"full\" then ac = a.base + dex\r\nelseif a.dex == \"max2\" then ac = a.base + math.min(dex, K.dexCap(SHEET, a.cat))\r\nelse ac = a.base end\r\nac = ac + aplus - (tonumber(wear[eq.armor]) or 0)\r\n\r\nlocal mith = K.MI and #K.MI.powers(pc, \"mithral\") > 0\r\nif a.str and SCORE.Strength < a.str and not mith then speed = speed - 10; notes[#notes + 1] = \"Speed -10 (armor too heavy)\" end\r\nif a.stealth and not mith then notes[#notes + 1] = \"Disadvantage on Stealth checks (armor)\" end\r\nif not armorProf(a.cat) and not (K.MI and #K.MI.powers(pc, \"prof\") > 0) then notes[#notes + 1] = \"not proficient with this armor: Disadvantage on Strength and Dexterity checks, saves and attack rolls, no spellcasting\" end\r\nend\r\n\r\n\r\nlocal buff = type(pc.buff) == \"table\" and pc.buff or {}\r\nlocal bnames = {}\r\nfor name, b in pairs(buff) do if type(b) == \"table\" then bnames[#bnames + 1] = name end end\r\ntable.sort(bnames, function(x, y)\r\nlocal bx, by = buff[x].base and 0 or 1, buff[y].base and 0 or 1\r\nif bx ~= by then return bx < by end\r\nreturn x < y\r\nend)\r\nlocal acFloor, floorBy\r\nfor _, name in ipairs(bnames) do\r\nlocal b = buff[name]\r\nif b.floor and b.floor > (acFloor or 0) then acFloor, floorBy = b.floor, name end\r\nif b.base and not a then\r\nac = math.max(ac, b.base + dex)\r\nnotes[#notes + 1] = name\r\nelseif b.bonus and (not b.conc or b.concBy or (type(pc.conc) == \"table\" and pc.conc.name == name)) then\r\nac = ac + b.bonus\r\nnotes[#notes + 1] = name .. \" +\" .. b.bonus .. \" AC\"\r\nend\r\nend\r\n\r\n\r\nlocal mac, mbase = 0, nil\r\nif K.MI then mac, mbase = K.MI.ac(pc, a, K.isShield(pc, eq.off)) end\r\nif mbase and not a and mbase + dex > ac then ac = mbase + dex; notes[#notes + 1] = \"magic item: AC \" .. mbase .. \" + Dexterity\" end\r\nif a and Feat.styled(SHEET, \"Defense\") then\r\nac = ac + 1\r\nnotes[#notes + 1] = \"Defense +1 AC\"\r\nend\r\nif K.isShield(pc, eq.off) then\r\nlocal _, _, splus = gearOf(pc, eq.off)\r\nac = ac + math.max(0, 2 + (splus or 0) - (tonumber(wear[eq.off]) or 0))\r\nif not armorProf(\"shield\") then notes[#notes + 1] = \"not proficient with the Shield\" end\r\nend\r\nif mac ~= 0 then ac = ac + mac; notes[#notes + 1] = \"magic items +\" .. mac .. \" AC\" end\r\n\r\nfor _, e in ipairs(Feat.fxOf(SHEET, \"ac_bonus\")) do\r\nlocal n = K.fxNum(e.n, SHEET, e.srcLv)\r\nif n ~= 0 then ac = ac + n; notes[#notes + 1] = tostring(e.src) .. string.format(\" %+d AC\", n) end\r\nend\r\n\r\nfor _, e in ipairs(K.modeFx(pc, SHEET)) do\r\nlocal n = e.ac and K.fxNum(e.ac, SHEET, e.srcLv) or 0\r\nif n ~= 0 then ac = ac + n; notes[#notes + 1] = pc.mode.name .. \" +\" .. n .. \" AC\" end\r\nend\r\nif acFloor and ac < acFloor then ac = acFloor; notes[#notes + 1] = floorBy .. \": AC \" .. acFloor end\r\n\r\nlocal attacks = {}\r\n\r\n\r\nlocal addOne, addThrown, addAll, addHeavy = 0, 0, 0, 0\r\nfor _, e in ipairs(Feat.fxOf(SHEET, \"dmg_add\")) do\r\nlocal n = K.fxNum(e.n, SHEET, e.srcLv)\r\n\r\nif e.heavy then addHeavy = addHeavy + n elseif e.one_hand then addOne = addOne + n elseif e.thrown then addThrown = addThrown + n else addAll = addAll + n end\r\nend\r\nlocal dualW = #Feat.fxOf(SHEET, \"dual_wield\") > 0\r\n\r\nlocal pactW = pc.pactW\r\nif pactW and not gearOf(pc, pactW) then pactW = nil end\r\nlocal function add(wname, hand)\r\nlocal w, _, plus = gearOf(pc, wname)\r\nif not w then return end\r\nlocal addAll = addAll + (w.heavy and addHeavy or 0)\r\n\r\nfor _, mw in pairs(type(pc.buff) == \"table\" and pc.buff or {}) do\r\nif type(mw) == \"table\" and mw.wplus and mw.choice == wname and plus == 0 then plus = tonumber(mw.wplus) or 0 end\r\nend\r\nlocal ab = w.ranged and \"Dexterity\" or \"Strength\"\r\nif w.finesse and MOD.Dexterity > MOD.Strength then ab = \"Dexterity\" end\r\n\r\nlocal blade = not w.ranged and Feat.invoked(SHEET, \"Pact of the Blade\") and ((pactW and wname == pactW) or (not pactW and hand == \"main\")) or false\r\nif blade and MOD.Charisma > MOD[ab] then ab = \"Charisma\" end\r\n\r\nfor _, e in ipairs(Feat.fxOf and Feat.fxOf(SHEET, \"weapon_ability\") or {}) do\r\nlocal hitW = false\r\nfor _, x in ipairs(e.weapons or {}) do if x == wname or (WEAPONS[wname] == nil and type(pc.loot) == \"table\" and type(pc.loot[wname]) == \"table\" and pc.loot[wname].base == x) then hitW = true end end\r\nif hitW and MOD[e.ability or \"\"] and MOD[e.ability] > MOD[ab] then ab = e.ability end\r\nend\r\nlocal monkW = monk and not w.ranged and (not w.martial or w.light)\r\nif monkW and MOD.Dexterity > MOD[ab] then ab = \"Dexterity\" end\r\nif monkW then\r\nlocal function size(d) local n, x = d:match(\"^(%d*)d(%d+)$\"); return (tonumber(n) or 1) * (tonumber(x) or 0) end\r\nif size(monk) > size(w.dmg) then w = setmetatable({ dmg = monk }, { __index = w }) end\r\nend\r\nlocal mod = MOD[ab]\r\nlocal hit = mod + ((weaponProf(w) or blade) and PROF or 0) + plus - (tonumber(wear[wname]) or 0)\r\nlocal fin = (w.finesse or w.ranged) and true or false\r\n\r\n\r\nlocal function entry(name, dmg, extra)\r\n\r\nlocal e = { name = name, hit = hit, dmg = dmg, ammo = w.ammo, fin = fin, type = w.type, mod = mod, weapon = true, str = ab == \"Strength\", melee = not w.ranged, pact = blade or nil,\r\nbase = (WEAPONS[wname] and wname) or (type(pc.loot) == \"table\" and type(pc.loot[wname]) == \"table\" and pc.loot[wname].base) or wname,\r\nitem = wname, magic = plus > 0 or nil, thrown = w.thrown or nil }\r\nfor k, v in pairs(extra or {}) do e[k] = v end\r\nattacks[#attacks + 1] = e\r\nreturn e\r\nend\r\n\r\nlocal function thrownToo()\r\nif w.thrown and addThrown ~= 0 then\r\nentry(wname .. \" (thrown)\", withMod(w.dmg, mod + plus + addThrown + addAll), { ranged = true, melee = false })\r\nend\r\nend\r\nif hand == \"off\" then\r\n\r\nlocal mainW = gearOf(pc, eq.main)\r\n\r\nif mainW and mainW.light and (w.light or (dualW and not w.ranged and not w.two)) then\r\n\r\nlocal twf = Feat.styled(SHEET, \"Two-Weapon Fighting\")\r\nentry(wname .. \" (off-hand, Bonus Action)\", withMod(w.dmg, (twf and mod or math.min(mod, 0)) + plus + addAll), { offhand = true })\r\nend\r\nentry(wname, withMod(w.dmg, mod + plus + addAll))\r\nthrownToo()\r\nreturn\r\nend\r\n\r\nlocal one = (not w.two and not w.ranged and (not eq.off or K.isShield(pc, eq.off))) and addOne or 0\r\nentry(wname, withMod(w.dmg, mod + plus + one + addAll), { twohand = w.two or nil, ranged = w.ranged or nil })\r\nif w.vers and not eq.off then\r\nentry(wname .. \" (two hands)\", withMod(w.vers, mod + plus + addAll), { twohand = true })\r\nend\r\nthrownToo()\r\nend\r\nif eq.main then add(eq.main, \"main\") end\r\nif eq.off and not K.isShield(pc, eq.off) then add(eq.off, \"off\") end\r\nif pactW and pactW ~= eq.main and pactW ~= eq.off and Feat.invoked(SHEET, \"Pact of the Blade\") then add(pactW, \"pact\") end\r\n\r\nif sneak then\r\nfor _, x in ipairs(attacks) do\r\nif x.fin then x.sneak = sneak end\r\nend\r\nend\r\n\r\nlocal fist = (Feat.fxOf(SHEET, \"unarmed_type\")[1] or {}).type or \"Bludgeoning\"\r\n\r\n\r\nlocal function dsize(d) local n, x = tostring(d or \"\"):match(\"^(%d*)d(%d+)\"); return (tonumber(n ~= \"\" and n or 1) or 1) * (tonumber(x) or 0) end\r\n\r\n\r\n\r\nlocal ud, udDice\r\nlocal holdsW = (eq.main and gearOf(pc, eq.main)) or (eq.off and not K.isShield(pc, eq.off) and gearOf(pc, eq.off))\r\nfor _, e in ipairs(Feat.fxOf(SHEET, \"unarmed_die\")) do\r\nlocal fits = not (e.no_armor and a) and not (e.no_shield and K.isShield(pc, eq.off)) and not (e.no_weapon and holdsW)\r\nlocal dt = fits and K.dieText(e, SHEET) or nil\r\nif dt and (not udDice or dsize(dt) > dsize(udDice)) then ud, udDice = e, dt end\r\nend\r\nif monk then\r\n\r\nlocal m = math.max(MOD.Strength, MOD.Dexterity)\r\nlocal md = (udDice and dsize(udDice) > dsize(monk)) and udDice or monk\r\nattacks[#attacks + 1] = { name = \"Unarmed Strike\", hit = m + PROF, dmg = withMod(md, m), type = fist, weapon = true, mod = m,\r\nstr = MOD.Strength >= MOD.Dexterity, melee = true }\r\nattacks[#attacks + 1] = { name = \"Unarmed Strike (Bonus Action)\", hit = m + PROF, dmg = withMod(md, m), type = fist, weapon = true, mod = m,\r\nstr = MOD.Strength >= MOD.Dexterity, melee = true }\r\nelseif udDice and not (SHEET.species == \"Beastfolk\" and dsize(udDice) <= 6) then\r\nlocal ab = ud.ability == \"DEX\" and \"Dexterity\" or (ud.ability == \"best\" and MOD.Dexterity > MOD.Strength) and \"Dexterity\" or \"Strength\"\r\nlocal m = MOD[ab]\r\nattacks[#attacks + 1] = { name = \"Unarmed Strike\", hit = m + PROF, dmg = withMod(udDice, m), type = fist, weapon = true, mod = m,\r\nstr = ab == \"Strength\", melee = true }\r\nelseif SHEET.species == \"Beastfolk\" then\r\n\r\nattacks[#attacks + 1] = { name = \"Unarmed Strike\", hit = MOD.Strength + PROF, dmg = withMod(\"1d6\", MOD.Strength), type = \"Slashing\",\r\nweapon = true, mod = MOD.Strength, str = true, melee = true }\r\nelse\r\nattacks[#attacks + 1] = { name = \"Unarmed Strike\", hit = MOD.Strength + PROF, dmg = tostring(math.max(1, 1 + MOD.Strength)), type = fist,\r\nweapon = true, mod = MOD.Strength, str = true, melee = true }\r\nend\r\n\r\n\r\nif K.AR and K.AR.on and K.AR.on() and type(K.PACK.impl) == \"table\" then\r\nfor n, impl in pairs(K.PACK.impl) do\r\n\r\nlocal ownT = impl.kind ~= \"tool\" or ((tonumber((pc.items or {})[impl.item or n]) or 0) > 0 or (tonumber((pc.items or {})[n]) or 0) > 0)\r\nlocal handT = impl.kind ~= \"tool\" or not ((eq.main and eq.off) or (eq.main and (gearOf(pc, eq.main) or {}).two))\r\nif impl.sturdy and not WEAPONS[n] and not K.d2need(impl) and K.AR.implHas(SHEET, impl, n) and ownT and handT then\r\nlocal fin = impl.ability == \"finesse\"\r\nlocal m = fin and math.max(MOD.Strength, MOD.Dexterity) or (MOD[impl.ability] or 0)\r\nattacks[#attacks + 1] = { name = n, hit = m + (K.AR.implProf(SHEET, impl, n) and PROF or 0), dmg = withMod(impl.sturdy, m), type = impl.type,\r\nweapon = true, mod = m, str = (fin and MOD.Strength >= MOD.Dexterity) or impl.ability == \"Strength\", melee = true,\r\nfin = fin or nil, twohand = impl.two_handed or nil, implement = true, sneak = (fin and sneak) or nil }\r\nend\r\nend\r\nend\r\n\r\n\r\nfor _, e in ipairs(Feat.fxOf(SHEET, \"feature_weapon\")) do\r\nlocal ab = e.finesse and (MOD.Dexterity > MOD.Strength and \"Dexterity\" or \"Strength\") or (e.ability == \"DEX\" and \"Dexterity\") or \"Strength\"\r\nlocal m = MOD[ab]\r\n\r\n\r\nlocal sst = e.ability == \"SPELL\" and Spell.stats(nil, e.srcClass) or nil\r\nlocal function put(nm, dice)\r\n\r\n\r\nif e.ability == \"SPELL\" and not sst then return end\r\nif sst then\r\nattacks[#attacks + 1] = { name = nm, hit = sst.atk, dmg = withMod(K.dieText({ dice = dice, srcClass = e.srcClass, srcLv = e.srcLv }, SHEET), sst.mod),\r\ntype = e.type, mod = sst.mod, featSpell = true, srange = e.ranged and \"ranged\" or \"melee\" }\r\nreturn\r\nend\r\nattacks[#attacks + 1] = { name = nm, hit = m + PROF, dmg = withMod(K.dieText({ dice = dice, srcClass = e.srcClass, srcLv = e.srcLv }, SHEET), m + addAll),\r\ntype = e.type, weapon = true, mod = m, str = ab == \"Strength\", melee = not e.ranged, fin = e.finesse and true or nil,\r\nthrown = e.thrown and true or nil, sneak = (e.finesse and sneak) or nil }\r\nend\r\nput(e.name, e.dice)\r\nif type(e.bonus) == \"table\" and type(e.bonus.dice) == \"string\" then put(e.name .. \" (Bonus Action)\", e.bonus.dice) end\r\nend\r\nFeat.weaponFx(attacks, pc)\r\nLOOT.attackFx(attacks, pc)\r\n\r\n\r\nlocal spAtk, spDmg = Spell.attacks(pc), {}\r\nfor _, x in ipairs(spAtk) do if not x.stim and not x.nodmg then spDmg[#spDmg + 1] = x end end\r\nFeat.fxDice(spDmg)\r\nfor _, x in ipairs(spAtk) do attacks[#attacks + 1] = x end\r\nFeat.riders(attacks, pc)\r\n\r\n\r\nfor bn, b in pairs(type(pc.buff) == \"table\" and pc.buff or {}) do\r\nlocal bm = type(b) == \"table\" and SPELLS[bn] and SPELLS[bn].m\r\nif bm and bm.size_dice and (b.choice == \"Enlarge\" or b.choice == \"Reduce\") then\r\nfor _, a in ipairs(attacks) do\r\nif a.weapon and not a.spell then\r\nif b.choice == \"Enlarge\" then\r\na.extras = a.extras or {}\r\na.extras[#a.extras + 1] = { dice = bm.size_dice, src = \"Enlarge\" }\r\nelse\r\na.dmg, a.min1 = a.dmg .. \"-\" .. bm.size_dice, true\r\nend\r\nend\r\nend\r\nend\r\nend\r\n\r\nlocal fx = Cond.fx(pc)\r\nfor _, x in ipairs(attacks) do x.hit = x.hit - fx.pen end\r\n\r\nif K.MI then for _, x in ipairs(K.MI.powers(pc, \"speedmin\")) do speed = math.max(speed, tonumber(x[1].n) or 0) end end\r\n\r\nlocal flyB\r\nfor _, b in pairs(type(pc.buff) == \"table\" and pc.buff or {}) do\r\nif type(b) == \"table\" and tonumber(b.speedAdd) then speed = speed + tonumber(b.speedAdd) end\r\nif type(b) == \"table\" and tonumber(b.fly) then flyB = math.max(flyB or 0, tonumber(b.fly)) end\r\nend\r\nfor bn, b in pairs(type(pc.buff) == \"table\" and pc.buff or {}) do\r\nif type(b) == \"table\" and (b.speedx or bn == \"Haste\") then speed = speed * 2; break end\r\nend\r\nspeed = fx.speed0 and 0 or math.max(0, speed - fx.slow)\r\nif flyB then flyB = fx.speed0 and 0 or math.max(0, flyB - fx.slow) end\r\nif fx.speedCap then speed = math.min(speed, fx.speedCap) end\r\n\r\nlocal ms = pc.mount and K.summonFind and K.summonFind(pc, pc.mount)\r\nif ms then\r\nlocal mst = ms.st or MONSTERS[ms.kind] or {}\r\nspeed = tonumber(ms.speed or mst.speed) or speed\r\nnotes[#notes + 1] = \"riding \" .. ms.name\r\nend\r\nlocal ba = K.buffSum(pc, \"atk\")\r\n\r\nlocal inStats = Cond.cur == pc\r\nif ba ~= 0 then for _, x in ipairs(attacks) do if not ((x.spell or x.featSpell) and inStats) then x.hit = (tonumber(x.hit) or 0) + ba end end end\r\n\r\nlocal rfx = K.recFx(pc)\r\nif #rfx.list > 0 then\r\nac = ac + rfx.ac\r\nfor _, x in ipairs(attacks) do\r\nfor _, d in ipairs(rfx.dmg) do x.dmg = x.dmg .. \"-\" .. d end\r\nif not x.spell then for _, d in ipairs(rfx.wdmg) do x.dmg, x.min1 = x.dmg .. \"-\" .. d, true end end\r\nend\r\nfor _, n in ipairs(rfx.list) do notes[#notes + 1] = n .. \" on it: \" .. K.foeFxText(K.foeFxOf(n)) .. \" (in these numbers)\" end\r\nend\r\nreturn { ac = ac, speed = speed, attacks = attacks, notes = notes, fly = flyB }\r\nend\r\n\r\nlocal function statsOf(unit, pc)\r\nif unit.side == \"pc\" then return pcStats(pc) end\r\nif unit.side == \"ally\" then\r\nlocal a = Ally.find(pc, unit.ally)\r\nif a then return Ally.with(a, pcStats, a) end\r\nreturn { ac = 10, speed = 30, attacks = {}, notes = {} }\r\nend\r\n\r\nlocal pk = unit.poly and K.polyLive(unit, pc)\r\nif pk then return MONSTERS[pk] end\r\nreturn unit.st or MONSTERS[unit.kind]\r\nend\r\n\r\nlocal function moneyText(cp)\r\nif cp == 0 then return \"0 gp\" end\r\nlocal parts = {}\r\nfor _, u in ipairs({ \"gp\", \"sp\", \"cp\" }) do\r\nlocal n = math.floor(cp / COIN[u])\r\ncp = cp - n * COIN[u]\r\nif n > 0 then parts[#parts + 1] = string.format(\"%d %s\", n, u) end\r\nend\r\nreturn table.concat(parts, \" \")\r\nend\r\n\r\n\r\n\r\nlocal function newPC()\r\nlocal res = {}\r\nfor name, r in pairs(PC.res) do res[name] = r.max end\r\nlocal items = {}\r\nfor k, v in pairs(PC.items) do items[k] = v end\r\nlocal equip = {}\r\nfor k, v in pairs(PC.equip) do equip[k] = v end\r\nreturn { hp = PC.hp, max = PC.hp, level = 1, xp = 0, hd = 1, cp = PC.cp, items = items, res = res,\r\nequip = equip, ds = { s = 0, f = 0 }, stable = false, dead = false }\r\nend\r\n\r\nlocal function loadPC(id)\r\nlocal pc = stateOf(id, \"dnd_pc\")\r\nif type(pc) ~= \"table\" then pc = {} end\r\nfor k, v in pairs(newPC()) do if pc[k] == nil then pc[k] = v end end\r\nif K.regSummons then K.regSummons(pc) end\r\nreturn K.MP.wrapAll(pc)\r\nend\r\n\r\nlocal function deepCopy(t)\r\nif type(t) ~= \"table\" then return t end\r\nlocal o = {}\r\nfor k, v in pairs(t) do o[k] = deepCopy(v) end\r\nreturn o\r\nend\r\n\r\nlocal function newCombat()\r\nreturn { active = false, order = {}, units = {}, last = \"\" }\r\nend\r\n\r\nlocal function loadCombat(id)\r\nlocal c = stateOf(id, \"dnd_combat\")\r\nif type(c) ~= \"table\" then c = newCombat() end\r\nc.order = c.order or {}\r\nc.units = c.units or {}\r\nif K.regSummons then K.regSummons(nil, c) end\r\nreturn c\r\nend\r\n\r\nlocal function loadClock(id)\r\nlocal t = stateOf(id, \"dnd_clock\")\r\nif type(t) ~= \"table\" or type(t.min) ~= \"number\" then t = { min = K.START_MIN } end\r\nreturn t\r\nend\r\n\r\n\r\nlocal function optOn(id, name)\r\nreturn getChatVar(id, name) ~= \"0\"\r\nend\r\n\r\n\r\nfunction K.suggestOn(id)\r\nreturn getChatVar(id, \"dnd_opt_suggest\") ~= \"0\"\r\nend\r\n\r\n\r\n\r\n\r\n\r\n\r\nlocal Seed = { SLOTS = 40 }\r\n\r\nfunction Seed.of(text)\r\nlocal slot, nonce = (text or \"\"):match(\"<!%-%-dseed:(%d+)x(%w+)%-%->\")\r\nreturn slot and (slot .. \"x\" .. nonce) or nil\r\nend\r\n\r\n\r\nfunction Seed.at(id, i)\r\nfor k = i, 0, -1 do\r\nlocal m = getChat(id, k)\r\nif m and m.role == \"char\" then return Seed.of(m.data), k end\r\nend\r\nreturn nil, nil\r\nend\r\n\r\nfunction Seed.ok(s)\r\nreturn type(s) == \"table\" and type(s.pc) == \"table\" and type(s.clock) == \"table\" and type(s.clock.min) == \"number\"\r\nand type(s.combat) == \"table\" and type(s.sheet) == \"table\" and type(s.sheet.scores) == \"table\"\r\nend\r\n\r\nfunction Seed.read(id, key)\r\nlocal slot, nonce = (key or \"\"):match(\"^(%d+)x(%w+)$\")\r\nif not slot then return nil end\r\nlocal s = getState(id, \"dnd_seed_\" .. slot)\r\nif Seed.ok(s) and s.nonce == nonce then return s end\r\nreturn nil\r\nend\r\n\r\nfunction Seed.write(id, key, s)\r\nlocal slot, nonce = key:match(\"^(%d+)x(%w+)$\")\r\ns.nonce = nonce\r\nsetState(id, \"dnd_seed_\" .. slot, s)\r\nend\r\n\r\n\r\n\r\n\r\n\r\n\r\nfunction K.missingIn(sh, pc)\r\nlocal function miss(x)\r\nif type(x) ~= \"table\" or type(x.scores) ~= \"table\" then return nil end\r\nif x.class and not CLASSES[x.class] then return x.class end\r\nif x.species and x.species ~= \"\" and not SPECIES[x.species] then return \"species:\" .. x.species end\r\nfor _, m in ipairs(K.mcList(x)) do\r\nif m.class and not CLASSES[m.class] then return m.class end\r\nend\r\n\r\nlocal p = type(x.picks) == \"table\" and x.picks or {}\r\nlocal cls = { x.class }\r\nfor _, m in ipairs(K.mcList(x)) do cls[#cls + 1] = m.class end\r\nfor _, cn in ipairs(cls) do\r\nlocal v = CLASSES[cn or \"\"] and p[K.subKey(cn)]\r\nif type(v) == \"string\" and not K.subRec(cn, v) then return cn .. \" (\" .. v .. \")\" end\r\nend\r\nend\r\nlocal r = miss(sh)\r\nif r then return r end\r\nif type(pc) ~= \"table\" then return nil end\r\nfor _, key in ipairs({ \"allies\", \"guests\" }) do\r\nfor _, a in ipairs(type(pc[key]) == \"table\" and pc[key] or {}) do\r\nr = type(a) == \"table\" and miss(a.sheet)\r\nif r then return r end\r\nend\r\nend\r\nreturn nil\r\nend\r\n\r\nfunction K.missKo(m)\r\nlocal sp = tostring(m or \"\"):match(\"^species:(.+)$\")\r\nreturn sp and (sp .. \" 종족\") or (tostring(m) .. \" 클래스\")\r\nend\r\nfunction K.missEn(m)\r\nlocal sp = tostring(m or \"\"):match(\"^species:(.+)$\")\r\nreturn sp and (\"the species \" .. sp) or (\"the class \" .. tostring(m))\r\nend\r\nfunction K.missingClass(id)\r\nlocal okS, sh = pcall(getState, id, \"dnd_sheet\")\r\nlocal okP, pc = pcall(getState, id, \"dnd_pc\")\r\nlocal r = K.missingIn(okS and sh or nil, okP and pc or nil)\r\nif r then return r end\r\nlocal okA, key, at = pcall(Seed.at, id, getChatLength(id) - 1)\r\nlocal snap = okA and key and Seed.read(id, key)\r\nif snap then return K.missingIn(snap.sheet, snap.pc) end\r\n\r\nif okA and not at then\r\nlocal okB, base = pcall(getState, id, \"dnd_base\")\r\nif okB and type(base) == \"table\" then return K.missingIn(base.sheet, base.pc) end\r\nend\r\nreturn nil\r\nend\r\n\r\n\r\n\r\n\r\nfunction K.missingFresh(id)\r\nlocal m = K.missingClass(id)\r\nif m and K.PACK.fromCache then\r\npcall(K.packs, id, true)\r\npcall(K.packFpSave, id)\r\nm = K.missingClass(id)\r\nend\r\nreturn m\r\nend\r\n\r\n\r\n\r\nfunction K.lockMsg(miss, tail)\r\nlocal names = {}\r\nfor _, x in ipairs(K.PACK.list or {}) do\r\nnames[#names + 1] = tostring(x.name) .. ((x.notes and x.notes[1] == \"off on the settings tab (adult module)\") and \"(꺼 둠)\" or (not x.ok and \"(읽기 실패)\" or \"\"))\r\nend\r\nlocal mk = K.missKo(miss)\r\nreturn \"모듈 없음: 이 캐릭터의 \" .. mk .. K.josa(mk, \"이\", \"가\") .. \" 들어 있는 모듈이 꺼져 있어 \" .. tail\r\n.. \" Lua가 읽은 모듈: \" .. (#names > 0 and table.concat(names, \", \") or \"없음\") .. \".\"\r\nend\r\n\r\nfunction Seed.newKey(id)\r\nlocal slot = (tonumber(getChatVar(id, \"dnd_seed_next\")) or 0) % Seed.SLOTS + 1\r\nsetChatVar(id, \"dnd_seed_next\", tostring(slot))\r\nreturn string.format(\"%dx%x\", slot, math.random(0, 0xfffffff))\r\nend\r\n\r\n\r\n\r\n\r\nlocal function familiarity(id)\r\nlocal v = getChatVar(id, \"dnd_opt_level\")\r\nif v == \"1\" or v == \"3\" then return v end\r\nreturn \"2\"\r\nend\r\n\r\n\r\n\r\nlocal TERMS_KO_LINE = \"Prose: pure story in Korean. Never mention skills, checks, DCs, dice or bonuses in the prose, and never put English\"\r\n.. \" in the prose, not even in parentheses; the tags and Lua's boxes show all of that. Keep the prose voice of the story so far\"\r\n\r\n.. \" (not the table talk at the start of the chat).\"\r\n.. \" Names in the prose come from the Korean names list (한글 용어 대조표).\"\r\n\r\n\r\n\r\nfunction K.bgGuide()\r\nlocal ab = { Strength = \"STR\", Dexterity = \"DEX\", Constitution = \"CON\", Intelligence = \"INT\", Wisdom = \"WIS\", Charisma = \"CHA\" }\r\nlocal names, out = {}, {}\r\nfor n, b in pairs(BACKGROUNDS) do if type(n) == \"string\" and type(b) == \"table\" and not b.custom and not K.d2need(b) then names[#names + 1] = n end end\r\ntable.sort(names)\r\nfor _, n in ipairs(names) do\r\nlocal b, a = BACKGROUNDS[n], {}\r\nfor _, x in ipairs(b.abilities or {}) do a[#a + 1] = ab[x] or x end\r\nout[#out + 1] = string.format(\"%s (%s; %s)\", n, table.concat(a, \", \"), table.concat(b.skills or {}, \", \"))\r\nend\r\nreturn table.concat(out, \", \")\r\nend\r\n\r\n\r\nfunction K.classNames()\r\nlocal base, more = {}, {}\r\nfor n in pairs(CLASSES) do\r\nif type(n) == \"string\" and n:sub(1, 1) ~= \"_\" and not K.d2need(CLASSES[n]) then\r\nlocal t = K.PACK.cls[n] and more or base\r\nt[#t + 1] = n\r\nend\r\nend\r\ntable.sort(base)\r\ntable.sort(more)\r\nfor _, n in ipairs(more) do base[#base + 1] = n end\r\nreturn base\r\nend\r\n\r\n\r\nfunction K.speciesGuide()\r\nlocal o = {}\r\nfor n, r in pairs(SPECIES) do if type(n) == \"string\" and not K.d2need(r) then o[#o + 1] = n end end\r\ntable.sort(o)\r\nreturn table.concat(o, \", \")\r\nend\r\n\r\n\r\n\r\nfunction K.noSpellsYet(sh, cls, lv)\r\nlocal row = K.rowAt(sh, cls, lv)\r\nreturn type(row) == \"table\" and (tonumber(row.cantrips) or 0) == 0 and (tonumber(row.prepared) or 0) == 0 and K.rowMaxLv(row) == 0\r\nend\r\n\r\n\r\nfunction K.spellsFrom(cl, after)\r\nlocal c = CLASSES[cl]\r\nif not (c and c.spell_ability) then return nil end\r\nfor lv = (after or 0) + 1, 20 do\r\nlocal row = type(c.levels) == \"table\" and c.levels[lv]\r\nif type(row) == \"table\" and ((tonumber(row.cantrips) or 0) > 0 or (tonumber(row.prepared) or 0) > 0) then return lv end\r\nend\r\nreturn nil\r\nend\r\nfunction K.packSkillGuide()\r\nlocal o, sp = {}, {}\r\nfor _, n in ipairs(K.classNames()) do\r\nlocal c = CLASSES[n]\r\nif K.PACK.cls[n] and type(c) == \"table\" and type(c.skills) == \"table\" and type(c.skills.from) == \"table\" then\r\no[#o + 1] = string.format(\"%s %d of %s\", n, tonumber(c.skills.choose) or 2, table.concat(c.skills.from, \", \"))\r\nend\r\nif K.PACK.cls[n] and type(c) == \"table\" and c.spell_ability then\r\nlocal from, r1 = K.spellsFrom(n, 0), type(c.levels) == \"table\" and c.levels[1] or {}\r\nsp[#sp + 1] = from == 1 and string.format(\"%s %d+%d\", n, tonumber(r1.cantrips) or 0, tonumber(r1.prepared) or 0)\r\nor from and string.format(\"%s none before level %d (no SPELLS tag below it)\", n, from) or nil\r\nend\r\nend\r\nreturn (#o > 0 and (\" A module's class takes its skills from its own list: \" .. table.concat(o, \"; \") .. \".\") or \"\")\r\n.. (#sp > 0 and (\" A module class's level-1 spells: \" .. table.concat(sp, \"; \") .. \".\") or \"\")\r\nend\r\n\r\nlocal CREATE_GUIDE = \" [PC|Species|Class|Background|method|STR,DEX,CON,INT,WIS,CHA|bonus|skills|equipment|level].\"\r\n.. \" Species: %%SPECIES%%. Classes: %%CLASSES%%. Backgrounds (bonus abilities; skills): %%BGS%%.\"\r\n\r\n.. \" Or a background the user makes up: first [BACKGROUND|Name|three abilities|two skills|Origin feat|tool] (feat: %%ORIGINS%%\"\r\n.. \"; tool: one SRD tool, may be left out; e.g. [BACKGROUND|등대지기|Constitution,Wisdom,Intelligence|Perception,Survival|Alert|Navigator's Tools]),\"\r\n.. \" then that name in the PC tag; its equipment is 50 GP (either option).\"\r\n.. \" method: standard (15,14,13,12,10,8 in any order), pointbuy (each 8-15, at most 27 points), or roll (first write [ROLL_STATS] alone; Lua rolls six scores; assign exactly those).\"\r\n.. \" scores are before the bonus. bonus: \\\"+2 STR +1 CON\\\" or \\\"+1 STR +1 DEX +1 CON\\\", only the background's three abilities.\"\r\n.. \" skills: the class's number from its list, none of the background's two; a Human adds one more of any skill.%%PACKSKILLS%% equipment: class option and background option, e.g. A,A; the Fighter's A is Chain Mail and a Greatsword (Strength), its B Studded Leather, a Scimitar, a Shortsword and a Longbow (Dexterity): pick the one that fits the scores (B = gold only for the other classes). level: 1-%%MAXLV%%.\"\r\n.. \" Lua checks every rule and builds the sheet.\"\r\n.. \" A spellcaster then also writes [SPELLS|cantrips|prepared spells] after the PC tag, from its class list. Level 1 counts (cantrips + level-1 spells):\"\r\n.. \" Cleric and Wizard 3+4, Bard and Druid 2+4, Sorcerer 4+2, Warlock 2+2, Paladin and Ranger 0+2 (leave the cantrip field empty: [SPELLS||Bless, Heroism]).\"\r\n\r\n.. \" Above level 1 the numbers are larger; write a few of each and Lua takes them, the rest stay open to pick later.\"\r\n\r\n.. \" A spell the class always has prepared (a Ranger's Hunter's Mark) comes by itself: do not count or name it.\"\r\n.. \" If the user leaves the choices to you, choose everything yourself and write the PC tag in this same reply: without a PC tag nothing is created.\"\r\n\r\n\r\n\r\n\r\nK.rs = 1\r\nfunction K.rseed(v) K.rs = (math.floor(tonumber(v) or 1) % 2147483647) + 1 end\r\n\r\n\r\nfunction K.seedNow(id, salt)\r\nif K.SEEDED then return end\r\nK.SEEDED = true\r\nlocal okt, sec = pcall(os.time)\r\nlocal h, s = 0, tostring(salt or \"\")\r\nfor i = 1, #s, 7 do h = (h * 31 + s:byte(i)) % 2147483647 end\r\nlocal okl, len = pcall(getChatLength, id)\r\nlocal v = ((okt and tonumber(sec)) or 0) * 31 + ((okl and tonumber(len)) or 0) * 7919 + h + math.floor(clockNow() * 1000003)\r\npcall(math.randomseed, v)\r\nK.rseed(v)\r\nend\r\nfunction K.d(n)\r\nK.rs = (1103515245 * K.rs + 12345) % 2147483648\r\nreturn (K.rs // 65536) % n + 1\r\nend\r\n\r\n\r\nfunction K.combatW(id)\r\nlocal v = getChatVar(id, \"dnd_combat_w\")\r\nif v == \"low\" or v == \"high\" then return v end\r\nreturn \"mid\"\r\nend\r\nK.COMBAT_W_TEXT = {\r\nlow = \"[FIGHTS: FEW] The user wants few fights. Meet a conflict first with talk, wit, stealth or a check; bring a fight only when the\"\r\n.. \" user seeks one or the story leaves no other way, and let a job's boss part end by talk, a trick or a deal as well as by a fight.\"\r\n.. \" A fight Player starts is a fight.\",\r\nhigh = \"[FIGHTS: MANY] The user enjoys fights. Let danger come often and do not shy away from a scene that turns into a fight\"\r\n.. \" (within the encounter budget in GAME STATE).\",\r\n}\r\n\r\n\r\n\r\n\r\n\r\nfunction K.checkD(id)\r\n\r\nlocal v = getChatVar(id, \"dnd_check_d\")\r\nif v == \"easy\" then return v end\r\nreturn \"mid\"\r\nend\r\nfunction K.fightD(id)\r\nlocal v = getChatVar(id, \"dnd_fight_d\")\r\nif v == \"easy\" or v == \"hard\" then return v end\r\nreturn \"mid\"\r\nend\r\n\r\nK.CHECK_FLOOR = {}\r\nK.BUDGET_KO = { Moderate = \"보통\", High = \"어려움\", Hard = \"어려움 1.5배\" }\r\nfunction K.dcFloor() return nil end\r\n\r\n\r\nK.DEATH_REAL = \" The user chose this rule: never soften a fight, an enemy's choices or a result to keep anyone alive.\"\r\nfunction K.checkGuide(d, deathRule)\r\nif d ~= \"mid\" then return nil end\r\n\r\nlocal fall = deathRule == \"gentle\" and \"Falling in a fight can come in a TRPG as a matter of course; do not bend the story to keep Player or a companion from it.\" or \"\"\r\n\r\n\r\nreturn \"Fair dice (the user's setting): decide what each creature does and each check's DC from the task alone, as if the numbers\"\r\n.. \" below were hidden; then take the next die in order and let the roll stand: a failure costs what it costs, a success gains what it gains.\"\r\n.. \" Never tilt a DC, a roll, an enemy's choices or an outcome to spare Player or to make success easy; that spoils the user's game.\"\r\n.. \" Never add a roll, a check or a move just to use up a die: a roll comes only when the fiction calls for one, and every creature acts\"\r\n.. \" as it really would (a ranged attacker keeps its distance and shoots rather than cross a hazard).\"\r\n.. \" Trouble comes only from the fiction (what the world and its people would really do), never made up to punish or to stretch a scene:\"\r\n.. \" a threat Player dealt with stays dealt with.\" .. (fall ~= \"\" and (\" \" .. fall) or \"\")\r\nend\r\nfunction K.capBudget(pc)\r\nlocal d = K.FIGHT_D or \"mid\"\r\nif d == \"easy\" then return Ally.budget(pc, 2), \"Moderate\" end\r\nif d == \"hard\" then return math.floor(Ally.budget(pc, 3) * 3 / 2), \"Hard\" end\r\nreturn Ally.budget(pc, 3), \"High\"\r\nend\r\n\r\n\r\nfunction K.checkW(id)\r\nlocal v = getChatVar(id, \"dnd_check_w\")\r\nif v == \"low\" or v == \"high\" then return v end\r\nreturn \"mid\"\r\nend\r\nK.CHECK_W_TEXT = {\r\nlow = \"[CHECKS: FEW] The user wants few checks. Roll only at real turning points: a danger, a hard obstacle or a contest whose\"\r\n.. \" failure would change the story. Everything else simply happens as Player does it.\",\r\nhigh = \"[CHECKS: MANY] The user enjoys checks, and this setting wins over \\\"When in doubt, do not roll\\\": call for one whenever an\"\r\n.. \" action's outcome is in some doubt (searching, climbing, sneaking, reading someone, a tricky talk, recalling lore), even when\"\r\n.. \" failure only costs time, detail or face. Still none for plain acts (walking, buying, asking someone who answers freely), and\"\r\n.. \" the essential clue is never behind a roll.\",\r\n}\r\n\r\n\r\n\r\nlocal function familiarityText(lv, suggest)\r\n\r\nlocal gmLine = \" A rule note for the user goes in one [GM|…] tag at the end of the reply, never in the prose and never as <gm>…</gm> or other made-up markup.\"\r\nlocal head\r\nif lv == \"3\" then\r\nhead = \"[PLAYER KNOWS THE RULES] \" .. TERMS_KO_LINE\r\nelseif lv == \"2\" then\r\nhead = \"[PLAYER KNOWS SOME OF THE RULES] \" .. TERMS_KO_LINE\r\nelse\r\nhead = \"[PLAYER IS NEW TO THE RULES] \" .. TERMS_KO_LINE .. \" Lua explains each check and attack on screen, so the prose never explains rules.\"\r\nend\r\nhead = head .. gmLine\r\nif not suggest then return head .. \" No suggested actions: write no OPT tag.\" end\r\nreturn head\r\n\r\n\r\n.. \"\\nOptions help a new player see what they could do; they are never a reason to add a problem. Take them from the situation as it\"\r\n.. \" stands; when nothing is at stake, options with - (no roll) are fine, and so is writing none.\"\r\n.. \" When you write them, end the reply with 2-4 things Player could try next, one per line. While a fight goes on, Lua adds Player's options\"\r\n.. \" itself: write none then. Write them yourself when there is no fight or the fight ended in this reply; none in a reply\"\r\n\r\n.. \" that starts a fight with COMBAT, or that ends with Player still Unconscious at 0 HP:\"\r\n.. \" [OPT|short Korean action|Skill, ability, \\\"Ability save\\\", Attack, or -|DC from the check table (5, 10, 15, 20, 25, 30) or an adventure module's own, a creature's passive score for Stealth, Sleight of Hand or Deception against it, or the target's AC for Attack].\"\r\n.. \" A shove or a thrown flask is not Player's check but the target's save: [OPT|short Korean action|Shove (or the flask)|the target's name], Lua works out the chance.\"\r\n\r\n.. ((K.AR and K.AR.on()) and \" An approach: [OPT|short Korean action|the implement as in Player's approaches|the partner's approach AC].\" or \"\")\r\n.. \" Skill and ability names in English as on the sheet. Give the check that action itself would need under the check rules above;\"\r\n.. \" walking somewhere, plain talk or a look around with nothing at stake is - (no roll); a spell is Attack for a spell attack, otherwise -. Lua shows the success chance.\"\r\n.. \" Suggestions only: never act for Player, and never Player's own action in this reply (an attack Player makes now is an ATTACK tag, not an OPT).\"\r\nend\r\n\r\n\r\nfunction K.gmFacts(pc, c)\r\nlocal o = {}\r\nlocal st = pcStats(pc)\r\nlocal atk = {}\r\nfor _, a in ipairs(st.attacks) do\r\natk[#atk + 1] = string.format(\"%s +%d %s%s%s\", a.name, a.hit, a.dmg, Feat.exText(a), Feat.masteryText(a))\r\nend\r\no[#o + 1] = \"Player's attacks: \" .. table.concat(atk, \"; \")\r\nlocal res = {}\r\nfor name, r in pairs(PC.res) do\r\nlocal n = pc.res[name] or 0\r\nif n > 0 and K.MP.shown(name) then res[#res + 1] = string.format(\"%s %d/%d\", name, n, r.max) end\r\nend\r\ntable.sort(res)\r\nlocal down = \"\"\r\nif pc.dead then down = \" Player is DEAD.\"\r\nelseif pc.hp <= 0 then\r\ndown = string.format(\" Player is DOWN at 0 HP (%s): no actions until healed or awake.\", pc.stable and \"stable\" or (\"dying, death saves \" .. (pc.ds and pc.ds.s or 0) .. \" successes / \" .. (pc.ds and pc.ds.f or 0) .. \" failures\"))\r\nend\r\no[#o + 1] = string.format(\"HP %d/%d.%s Uses left: %s\", pc.hp, pc.max, down, #res > 0 and table.concat(res, \", \") or \"none\")\r\nlocal flasks = {}\r\nfor k, h in pairs(K.HAZ) do if h.item and (pc.items[k] or 0) > 0 then flasks[#flasks + 1] = k .. \" x\" .. pc.items[k] end end\r\nif #flasks > 0 then o[#o + 1] = \"Flasks in the pack (thrown with HAZARD): \" .. table.concat(flasks, \", \") end\r\nlocal wt = K.wearText(pc)\r\nif wt then o[#o + 1] = \"Damaged gear: \" .. wt .. \" (a Mending spell or a smith repairs it)\" end\r\nif c and c.active then\r\nlocal en = {}\r\nfor _, name in ipairs(c.order or {}) do\r\nlocal u = c.units[name]\r\nif u and u.side == \"enemy\" and u.hp > 0 then\r\nlocal tags = {}\r\nfor _, x in ipairs(Cond.active(u)) do tags[#tags + 1] = x end\r\nif u.oiled then tags[#tags + 1] = \"covered in oil (+5 Fire from the next fire)\" end\r\nlocal m = MONSTERS[u.kind]\r\nlocal tr = {}\r\nfor _, t in ipairs(m.vul or {}) do tr[#tr + 1] = \"vulnerable to \" .. t end\r\nen[#en + 1] = string.format(\"%s HP %d/%d AC %d%s%s\", name, u.hp, u.max, m.ac, #tags > 0 and (\", \" .. table.concat(tags, \", \")) or \"\",\r\n#tr > 0 and (\", \" .. table.concat(tr, \", \")) or \"\")\r\nend\r\nend\r\nif #en > 0 then o[#o + 1] = \"Enemies: \" .. table.concat(en, \"; \") end\r\nend\r\nreturn \"[GM ADVICE] The user knows nothing about these rules. Be their friendly GM: end the reply with one GM tag holding the advice itself inside the brackets,\"\r\n.. \" e.g. [GM|숏소드는 맞히면 다음 공격이 쉬워집니다. 행동 연쇄도 아직 남아 있습니다.] (never [GM|advice] with the text outside it): 1-3 short sentences in very kind,\"\r\n.. \" plain Korean about what is worth knowing now (what a weapon or pick is good for, a use still left, a cost or risk, an enemy's weak spot),\"\r\n\r\n.. \" never a list of things to do next (that is the options' job, or the user's own),\"\r\n.. \" explaining any rule word in passing. Only when there is a rule worth explaining right now: right after the character is made (what its\"\r\n.. \" main features do), the first time a rule or a dice mechanic comes up in play (Advantage, a critical hit, a saving throw, a condition,\"\r\n.. \" a death saving throw, a feature with limited uses), a new choice or new gear, or real danger. Not every reply, never the same advice twice,\"\r\n.. \" and never in the reply that starts a fight with COMBAT. Use only these facts and the rules above;\"\r\n.. \" never invent numbers. No tags, | or brackets inside: say it in words (\" .. (K.LITE and \"긴 휴식\" or \"짧은 휴식\") .. \", not REST).\\n\"\r\n.. table.concat(o, \"\\n\")\r\nend\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\nK.TAG_NAMES = {}\r\nfor n in (\"ATTACK CHECK SAVE DAMAGE HEAL TRAP DEATH HAZARD TIME REST XP ITEM GOLD BUY SELL CAST PLACE ALLY COVER CONC COND PLAN\"\r\n.. \" QUEST STAGE WEAR USE LOOT SPELLS SPELLBOOK INITIATE PASSIVE GM OPT COMBAT COMBAT_END EQUIP UNEQUIP PC ROLL_STATS\"\r\n.. \" THREAD NPC SECRET BACKGROUND GIVE MP BUFF STIM SOOTHE NUMB CLIMAX ADVANCE INHIB SWAP REACT BOND HDHEAL OVERSTIM SCORE BADEND MAXDOWN KNOCKOUT IMPREG PREG BIND ESCAPE CURSE BRAND FETISH VICE SCENE STRIP\"):gmatch(\"%S+\") do K.TAG_NAMES[n] = true end\r\nK.FIELD_WORD = { [\"성공\"] = \"success\", [\"실패\"] = \"failure\", [\"명중\"] = \"hit\", [\"빗나감\"] = \"miss\", [\"빗나가다\"] = \"miss\",\r\n[\"치명타\"] = \"crit\", [\"치명\"] = \"crit\" }\r\n\r\nK.RESULT_LC = { hit = true, miss = true, crit = true, success = true, failure = true }\r\n\r\nK.D20_AT = { CHECK = 2, ATTACK = 3, SAVE = 3, HAZARD = 4 }\r\n\r\nK.COUNT_AT = { ITEM = 2, BUY = 2, SELL = 2, GIVE = 4 }\r\nK.TRIM_EMPTY = { ATTACK = true, SAVE = true, CHECK = true, HAZARD = true, CAST = true, HEAL = true }\r\nfunction K.looseTags(text)\r\ntext = text:gsub(\"［\", \"[\"):gsub(\"］\", \"]\")\r\n\r\ntext = text:gsub(\"(%[[ \\t]*([%a_]+)[ \\t]*|)([^\\n]*)\", function(open, nm, tail)\r\nif not K.TAG_NAMES[nm:upper()] then return nil end\r\nreturn open .. tail:gsub(\"|[ \\t]*%[([%d ,/]+)%][ \\t]*([|%]])\", \"|%1%2\")\r\nend)\r\n\r\nlocal lines = {}\r\nfor line in (text .. \"\\n\"):gmatch(\"([^\\n]*)\\n\") do\r\nlocal inner = line:match(\"^[ \\t]*[%*_`>]+[ \\t]*(%[[^\\n]*%])[ \\t]*[%*_`]*[ \\t]*$\")\r\nlocal nm = inner and inner:match(\"^%[[ \\t]*([%a_ %-]+)\")\r\nif nm and K.TAG_NAMES[(nm:gsub(\"^%s+\", \"\"):gsub(\"%s+$\", \"\"):gsub(\"[ %-]\", \"_\"):upper())] then line = inner end\r\n\r\nlocal open = not line:find(\"]\", 1, true) and line:match(\"^[ \\t]*%[[ \\t]*([%a][%a_ %-]-)[ \\t]*|\")\r\nif open and K.TAG_NAMES[(open:gsub(\"[ %-]\", \"_\"):upper())] then\r\nline = line:gsub(\"[ \\t|]+$\", \"\") .. \"]\"\r\nend\r\nlines[#lines + 1] = line\r\nend\r\ntext = table.concat(lines, \"\\n\")\r\n\r\n\r\ntext = text:gsub(\"%[([^%[%]\\n]*)%]\", function(b)\r\nif not (b:find(\"｜\", 1, true) or b:find(\"│\", 1, true)) then return nil end\r\nlocal b2 = b:gsub(\"｜\", \"|\"):gsub(\"│\", \"|\")\r\nlocal nm = b2:match(\"^[ \\t]*([%a][%a_ %-]-)[ \\t]*|\")\r\nif nm and K.TAG_NAMES[(nm:gsub(\"[ %-]\", \"_\"):upper())] then return \"[\" .. b2 .. \"]\" end\r\nreturn nil\r\nend)\r\n\r\n\r\n\r\n\r\n\r\n\r\ntext = text:gsub(\"%[[ \\t]*[Tt][Ii][Mm][Ee][ \\t|]*%][ \\t]*%+[ \\t]*(%d+[^%s%[%]|]*)|[^%]\\n]*%]\", \"[TIME|+%1]\")\r\ntext = text:gsub(\"%[[ \\t]*[Tt][Ii][Mm][Ee][ \\t|]*%][ \\t]*%+[ \\t]*(%d+[^%s%[%]|]*)%]?\", \"[TIME|+%1]\")\r\ntext = text:gsub(\"%[[ \\t]*[Tt][Ii][Mm][Ee][ \\t|]*%][ \\t]*(%d+[mhd])%f[%A]%]?\", \"[TIME|+%1]\")\r\ntext = text:gsub(\"%[[ \\t]*[Gg][Oo][Ll][Dd][ \\t|]*%][ \\t]*([%+%-][ \\t]*%d[%w ]-)[ \\t]*\\n\", \"[GOLD|%1]\\n\")\r\n\r\nreturn (text:gsub(\"%[([^%[%]\\n]+)%]\", function(body)\r\nlocal name, rest = body:match(\"^[ \\t]*([%a][%a_ %-]-)[ \\t]*|(.*)$\")\r\nif not name then name = body:match(\"^[ \\t]*([%a][%a_ %-]-)[ \\t]*$\") end\r\nif not name then return nil end\r\nlocal up = name:gsub(\"[ %-]\", \"_\"):upper()\r\nif not K.TAG_NAMES[up] then return nil end\r\nif not rest then return \"[\" .. up .. \"]\" end\r\nlocal f, judged, nModel = {}, false, 0\r\nfor part in (rest .. \"|\"):gmatch(\"([^|]*)|\") do\r\nlocal v = part:gsub(\"^%s+\", \"\"):gsub(\"%s+$\", \"\")\r\n\r\nif v == \"ok\" or v:sub(1, 4) == \"bad:\" then judged = true end\r\nif not judged then\r\nv = K.FIELD_WORD[v] or v\r\nif K.RESULT_LC[v:lower()] then v = v:lower() end\r\n\r\n\r\nlocal idx = nModel + 1\r\nv = v:gsub(\"(%d)D(%d)\", \"%1d%2\")\r\nif K.COUNT_AT[up] == idx then v = v:match(\"^[xX][ \\t]*(%d+)$\") or v:match(\"^×[ \\t]*(%d+)$\") or v:match(\"^(%d+)[ \\t]*개$\") or v end\r\nif up == \"CAST\" and idx == 2 then v = K.slotWord(v) end\r\nif (up == \"GOLD\" and idx == 1) or ((up == \"BUY\" or up == \"SELL\") and idx == 3) then v = K.coinKo(v) end\r\nv = v:gsub(\"^[Dd][Cc][ \\t]*(%d+)$\", \"%1\"):gsub(\"^[Aa][Cc][ \\t]*(%d+)$\", \"%1\"):gsub(\"^난이도[ \\t]*(%d+)$\", \"%1\"):gsub(\"^방어도[ \\t]*(%d+)$\", \"%1\")\r\nnModel = nModel + 1\r\nend\r\nf[#f + 1] = v\r\nend\r\n\r\n\r\nif not judged and K.TRIM_EMPTY[up] then\r\nwhile nModel > 1 and f[nModel] == \"\" do table.remove(f, nModel); nModel = nModel - 1 end\r\nend\r\nif not judged and up == \"ATTACK\" and nModel == 10 and (f[9] == \"-\" or f[9] == \"\") and (f[10] or \"\"):match(\"^%d+$\")\r\nand (f[7] or \"\"):find(\"%d[dD]%d\") and (f[8] or \"\"):find(\"%d\") then\r\ntable.remove(f, 9); nModel = nModel - 1\r\nend\r\n\r\n\r\n\r\n\r\nif up == \"ATTACK\" and nModel >= 8 then\r\nif not K.WEAPON_LC then\r\nK.WEAPON_LC = { [\"unarmed strike\"] = true }\r\nfor w in pairs(WEAPONS) do K.WEAPON_LC[w:lower()] = true end\r\nend\r\nfor i = 2, 3 do\r\nif K.WEAPON_LC[(f[i] or \"\"):lower()] then table.remove(f, i); nModel = nModel - 1; break end\r\nend\r\nend\r\n\r\n\r\nif up == \"DAMAGE\" or up == \"ATTACK\" or up == \"SAVE\" then\r\nfor i = nModel, 1, -1 do\r\nif K.DTYPES[(f[i] or \"\"):lower()] then table.remove(f, i); nModel = nModel - 1 end\r\nend\r\nend\r\n\r\n\r\nlocal resAt = ({ SAVE = 6, HAZARD = 7 })[up]\r\nif resAt and nModel == resAt + 2 and ({ success = true, failure = true })[f[resAt]] and f[resAt + 1] == \"-\" and (f[resAt + 2] or \"\"):match(\"^%d+$\") then\r\ntable.insert(f, resAt + 2, \"-\")\r\nnModel = nModel + 1\r\nend\r\n\r\nif (up == \"ATTACK\" or up == \"SAVE\" or up == \"HAZARD\") and nModel >= 8 and f[nModel] then\r\nlocal n = f[nModel]:match(\"^(%-?%d+)%s*%(.*%)$\")\r\nif n then f[nModel] = n end\r\nend\r\nlocal at = K.D20_AT[up]\r\nif at and at < nModel then\r\nlocal die, sign, n = f[at]:match(\"^(%d+)[ \\t]*([%+%-])[ \\t]*(%d+)$\")\r\nif not die then die, sign, n = f[at]:match(\"^(%a+ %d+,[ \\t]*%d+)[ \\t]*([%+%-])[ \\t]*(%d+)$\") end\r\nif die then\r\nf[at] = die\r\nif not (f[at + 1] or \"\"):match(\"^[%+%-]%s*%d+$\") then table.insert(f, at + 1, sign .. n) end\r\nend\r\nend\r\nreturn \"[\" .. up .. \"|\" .. table.concat(f, \"|\") .. \"]\"\r\nend))\r\nend\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\nK.LEAK_WORDS = { \"%f[%a]I%f[^%a]\", \"Let me\", \"Let's\", \"%f[%a]I'm\", \"%f[%a]I'll\", \"%f[%a]I've\", \"%f[%a]I'd\" }\r\n\r\n\r\n\r\n\r\nfunction K.cutDraft(text)\r\nlocal heads, p = {}, 1\r\nwhile true do\r\nlocal s, e = text:find(\"##[ \\t]*[Rr][Ee][Ss][Pp][Oo][Nn][Ss][Ee][ \\t]*\", p)\r\nif not s then break end\r\nlocal nx = text:sub(e + 1, e + 1)\r\nif (s == 1 or text:sub(s - 1, s - 1) == \"\\n\") and (nx == \"\\n\" or nx == \"\" or nx == \"\\r\") then heads[#heads + 1] = s end\r\np = e + 1\r\nend\r\nif #heads < 2 then return text end\r\nlocal last = heads[#heads]\r\nlocal pre, post = text:sub(1, last - 1), text:sub(last)\r\nlocal function body(s) return (s:gsub(\"\\2%d+\\2\", \"\"):gsub(\"#+[^\\n]*\", \"\"):gsub(\"%s\", \"\")) end\r\nif not (pre:find(\"%[[%u_]+|\") or #body(pre) > 300) then return text end\r\nif not (post:find(\"%[[%u_]+|\") or #body(post) > 300) then return text end\r\nlocal keep = {}\r\nfor h in pre:gmatch(\"\\2%d+\\2\") do keep[#keep + 1] = h end\r\nreturn (#keep > 0 and (table.concat(keep, \"\\n\") .. \"\\n\\n\") or \"\") .. post\r\nend\r\n\r\nfunction K.isMeta(s)\r\nfor _, w in ipairs(K.LEAK_WORDS) do if s:find(w) then return true end end\r\nreturn false\r\nend\r\n\r\n\r\n\r\n\r\nfunction K.cutTaken(text)\r\nif not text:find(\"%]%s*[^\\n]-%a\") then return text end\r\nlocal out, dropping = {}, false\r\nfor line in (text .. \"\\n\"):gmatch(\"([^\\n]*)\\n\") do\r\nlocal tail = line:match(\"^%s*%[[%u_]+|?[^%]\\n]*%](.*)$\")\r\nlocal korean = line:find(\"[\\234-\\237][\\128-\\191][\\128-\\191]\") ~= nil\r\nif tail and select(2, tail:gsub(\"%a\", \"\")) >= 20 and K.isMeta(tail) then\r\nline, dropping = nil, true\r\nelseif dropping and line:find(\"%a\") and not korean and not line:match(\"^%s*%[\") then\r\nline = nil\r\nelseif line:find(\"%S\") then\r\ndropping = false\r\nend\r\nif line then out[#out + 1] = line end\r\nend\r\nreturn table.concat(out, \"\\n\")\r\nend\r\n\r\nfunction K.cutLeak(text)\r\nif not text:find(\"[\\234-\\237][\\128-\\191][\\128-\\191]\") then return text end\r\nlocal out = {}\r\nfor line in (text .. \"\\n\"):gmatch(\"([^\\n]*)\\n\") do\r\nif line and not line:match(\"^%s*%[\") and not line:match(\"^%s*[%*%-]\") and not line:find(\"<\", 1, true) and not line:find(\"│\", 1, true) then\r\nfor s, run in line:gmatch(\"()([\\32-\\126]+)\") do\r\nlocal _, sp = run:gsub(\" \", \"\")\r\nlocal _, al = run:gsub(\"%a\", \"\")\r\nif #run >= 100 and sp >= 12 and al >= 60 and K.isMeta(run) then\r\nlocal pre = line:sub(1, s - 1)\r\nlocal last\r\nfor e in pre:gmatch(\"[\\234-\\237][\\128-\\191][\\128-\\191]()\") do last = e end\r\nif last then\r\nlocal p = pre:sub(last, last)\r\nline = pre:sub(1, last - 1) .. (p:match(\"[%.%?!\\\"']\") and p or \"\")\r\nelse\r\nline = \"\"\r\nend\r\nbreak\r\nend\r\nend\r\nend\r\nif line then out[#out + 1] = line end\r\nend\r\nreturn table.concat(out, \"\\n\")\r\nend\r\n\r\nfunction K.holdQuoted(text, held)\r\nlocal function hold(s) held[#held + 1] = s; return \"\\2\" .. #held .. \"\\2\" end\r\n\r\ntext = K.looseTags(text)\r\ntext = text:gsub(\"```.-```\", hold):gsub(\"`[^`\\n]+`\", hold)\r\nlocal out, pos = {}, 1\r\nwhile true do\r\nlocal s, e = text:find(\"%[[%u_]+|?[^%]\\n]*%]\", pos)\r\nif not s then break end\r\n\r\nlocal ls = s\r\nwhile ls > 1 and text:sub(ls - 1, ls - 1) ~= \"\\n\" and text:sub(ls - 2, ls - 1) ~= \"\\\\n\" do ls = ls - 1 end\r\nlocal pre = text:sub(ls, s - 1)\r\nlocal ok = pre:match(\"^%s*[%-%*•]?%s*$\") or pre:match(\"^%s*[%-%*•]?%s*%[[%u_]+|?[^\\n]*%]%s*$\")\r\nout[#out + 1] = text:sub(pos, s - 1)\r\nout[#out + 1] = ok and text:sub(s, e) or hold(text:sub(s, e))\r\npos = e + 1\r\nend\r\nout[#out + 1] = text:sub(pos)\r\nreturn table.concat(out)\r\nend\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\nfunction K.spellNames(text)\r\nif type(text) ~= \"string\" or not text:find(\"(\", 1, true) then return text end\r\nreturn (text:gsub(\"()(%s?)%(([^%(%)\\n|%[%]]*)%)\", function(pos, sp, inner)\r\n\r\nlocal before = text:sub(math.max(1, pos - 60), pos - 1)\r\nlocal words = {}\r\nfor w in before:gmatch(\"[^%s`%*_]+\") do words[#words + 1] = w end\r\nif not before:match(\"[%a']$\") then return nil end\r\nlocal en\r\nfor k = math.min(5, #words), 1, -1 do\r\nlocal cand = table.concat(words, \" \", #words - k + 1, #words)\r\n\r\nif SPELLS[cand] or (NAMES_KO[cand] and cand:match(\"^%u\")) then en = cand; break end\r\nend\r\nif not en then return nil end\r\nlocal ko = NAMES_KO[en]\r\nif not ko or not inner:find(\"[\\128-\\255]\") then return nil end\r\nlocal cut = #inner + 1\r\nfor _, d in ipairs({ \" - \", \" — \", \", \", \": \", \"; \", \" · \", \" (\" }) do\r\nlocal i = inner:find(d, 1, true)\r\nif i and i < cut then cut = i end\r\nend\r\nlocal name, rest = inner:sub(1, cut - 1), inner:sub(cut)\r\nif name == ko or not name:find(\"[\\128-\\255]\") then return nil end\r\nreturn sp .. \"(\" .. ko .. rest .. \")\"\r\nend))\r\nend\r\n\r\nfunction K.gmFix(t)\r\nif not t:find(\"[GM\", 1, true) then return t end\r\n\r\n\r\nlocal out, i = {}, 1\r\nwhile true do\r\nlocal s = t:find(\"[GM|\", i, true)\r\nif not s then out[#out + 1] = t:sub(i); break end\r\nlocal depth, j, close = 1, s + 4, nil\r\nwhile j <= #t do\r\nlocal ch = t:sub(j, j)\r\nif ch == \"[\" then\r\ndepth = depth + 1\r\nelseif ch == \"]\" then\r\ndepth = depth - 1\r\nif depth == 0 then close = j; break end\r\nelseif ch == \"\\n\" then\r\nbreak\r\nend\r\nj = j + 1\r\nend\r\nif close then\r\nlocal inner = t:sub(s + 4, close - 1):gsub(\"%[([^%[%]]*)%]\", function(x) return (x:gsub(\"|\", \" \")) end)\r\nout[#out + 1] = t:sub(i, s + 3) .. inner .. \"]\"\r\ni = close + 1\r\nelse\r\nout[#out + 1] = t:sub(i, s + 3)\r\ni = s + 4\r\nend\r\nend\r\nt = table.concat(out)\r\nlocal function placeholder(x)\r\nx = trim(x or \"\"):lower()\r\nreturn x == \"\" or x == \"advice\" or x == \"조언\" or x == \"...\" or x == \"…\"\r\nend\r\nlocal function pack(inner, body, tail)\r\nif not placeholder(inner) or trim(body) == \"\" then return nil end\r\nlocal b = trim(body):gsub(\"[|%]]\", \"/\"):gsub(\"%s*\\n%s*\", \" \")\r\nreturn \"[GM|\" .. b .. \"]\" .. (tail or \"\")\r\nend\r\nt = t:gsub(\"%[GM|?([^%]]*)%]%s*\\n(.-)(\\n%s*%[)\", pack)\r\nt = t:gsub(\"%[GM|?([^%]]*)%]%s*\\n(.-)$\", function(inner, body) return pack(inner, body, \"\") end)\r\nreturn t\r\nend\r\n\r\n\r\nlocal function liveSnap(id, sheet)\r\nreturn { sheet = sheet, pc = loadPC(id), combat = loadCombat(id), clock = loadClock(id) }\r\nend\r\n\r\n\r\n\r\n\r\nlocal function syncBases(id, fn0)\r\n\r\nlocal function fn(s)\r\nif type(s) == \"table\" then K.MP.wrapAll(s.pc) end\r\nreturn fn0(s)\r\nend\r\nlocal len = getChatLength(id)\r\nlocal base = getState(id, \"dnd_base\")\r\nif Seed.ok(base) and base.len == len and fn(base) ~= false then setState(id, \"dnd_base\", base) end\r\nlocal key, at = Seed.at(id, len - 1)\r\nif not at then return end\r\nlocal pkey = Seed.at(id, at - 1)\r\nlocal prev = pkey and Seed.read(id, pkey)\r\nif prev then\r\n\r\nlocal clean = prev.clean\r\nif not clean then clean = deepCopy(prev); clean.nonce = nil end\r\nif fn(prev) ~= false then prev.clean = clean; Seed.write(id, pkey, prev) end\r\nend\r\nlocal cur = key and Seed.read(id, key)\r\nif cur then\r\nlocal snap = liveSnap(id, loadSheet(id))\r\nsnap.prev = cur.prev\r\nSeed.write(id, key, snap)\r\nsetChatVar(id, \"dnd_seed_live\", key)\r\nend\r\nend\r\n\r\n\r\n\r\n\r\nfunction Seed.restore(id)\r\nif K.LOCKED then return end\r\nlocal key, at = Seed.at(id, getChatLength(id) - 1)\r\nlocal live = getChatVar(id, \"dnd_seed_live\")\r\nlocal s\r\nif key and key ~= live then\r\ns = Seed.read(id, key)\r\nif s and s.clean then\r\n\r\n\r\nlocal gone = Seed.read(id, live)\r\nif not (gone and gone.prev == key) and Seed.ok(s.clean) then s = s.clean end\r\ns.clean = nil\r\nSeed.write(id, key, s)\r\nend\r\nelseif not at and live ~= \"\" and live ~= \"null\" then\r\n\r\n\r\ns = getState(id, \"dnd_base\")\r\nif not Seed.ok(s) then s = nil end\r\nkey = \"\"\r\nend\r\nif s then\r\nsetState(id, \"dnd_sheet\", s.sheet)\r\nsetState(id, \"dnd_pc\", s.pc)\r\nsetState(id, \"dnd_combat\", s.combat)\r\nsetState(id, \"dnd_clock\", s.clock)\r\nsetState(id, \"dnd_turn_delta\", {})\r\nsetChatVar(id, \"dnd_seed_live\", key)\r\nend\r\nend\r\n\r\n\r\n\r\n\r\n\r\nfunction onStart(id) end\r\n\r\n\r\n\r\n\r\nK.POOL_AT = { { 17, { d20 = 32, d4 = 24, d6 = 90, d8 = 36, d10 = 24, d12 = 18 } },\r\n{ 11, { d20 = 24, d4 = 16, d6 = 40, d8 = 24, d10 = 16, d12 = 12 } } }\r\nfunction K.poolSizes(id)\r\nlocal pc = loadPC(id)\r\nlocal lv = tonumber(type(pc) == \"table\" and pc.level) or 1\r\nfor _, a in ipairs(Ally.list(pc)) do lv = math.max(lv, tonumber(a.level) or 0) end\r\nlocal base = POOL\r\nfor _, row in ipairs(K.POOL_AT) do if lv >= row[1] then base = row[2]; break end end\r\n\r\n\r\nlocal c = loadCombat(id)\r\nlocal n = 0\r\nif type(c) == \"table\" and c.active and type(c.units) == \"table\" then\r\nfor name, u in pairs(c.units) do\r\n\r\nlocal r = u.side ~= \"enemy\" and Ally.rec(pc, name, u)\r\nif r then\r\nif not r.dead and (tonumber(r.hp) or 0) > 0 then n = n + 1 end\r\nelseif (tonumber(u.hp) or 0) > 0 then\r\nn = n + 1\r\nend\r\nend\r\nend\r\nif n <= 5 then return base end\r\nlocal out = {}\r\nfor k, v in pairs(base) do out[k] = math.min(v * 3, math.ceil(v * n / 5)) end\r\nreturn out\r\nend\r\n\r\n\r\n\r\n\r\nfunction K.sendPools(id)\r\nlocal okt, now = pcall(function() return os.time() end)\r\nlocal len = getChatLength(id)\r\nif okt and now then\r\nlocal meta, pools = getState(id, \"dnd_pool_meta\"), getState(id, \"dnd_pool\")\r\nif type(meta) == \"table\" and meta.len == len and math.abs(now - (tonumber(meta.at) or 0)) <= 1\r\nand type(pools) == \"table\" and type(pools.d20) == \"table\" then\r\nreturn pools\r\nend\r\nend\r\nlocal pools = newPools(K.poolSizes(id))\r\n\r\nlocal force = tonumber(getChatVar(id, \"dnd_dbg_d20\"))\r\nif force then\r\npools.d20[1] = force\r\nsetChatVar(id, \"dnd_dbg_d20\", \"\")\r\nend\r\nsetState(id, \"dnd_pool\", pools)\r\nsetState(id, \"dnd_pool_meta\", { len = len, at = okt and now or 0 })\r\nreturn pools\r\nend\r\n\r\nfunction K.atSend(id)\r\nSeed.restore(id)\r\n\r\nlocal okf, errf = pcall(K.Form.atSend, id)\r\nif not okf then setChatVar(id, \"dnd_lua_error\", \"form: \" .. tostring(errf)) end\r\nlocal okc, errc = pcall(K.CharCode.atSend, id)\r\nif not okc then setChatVar(id, \"dnd_lua_error\", \"character code: \" .. tostring(errc)) end\r\nK.sendPools(id)\r\n\r\nsetChatVarChanged(id, \"dnd_drawer_open\", \"0\")\r\nsetChatVarChanged(id, \"dnd_drawer_tab\", \"1\")\r\nend\r\n\r\n\r\n\r\nlocal SLOTS = { { 4, \"밤\", \"night\" }, { 6, \"새벽\", \"dawn\" }, { 11, \"아침\", \"morning\" },\r\n{ 17, \"낮\", \"afternoon\" }, { 21, \"저녁\", \"evening\" }, { 24, \"밤\", \"night\" } }\r\n\r\nlocal function clockParts(min)\r\nlocal day = math.floor(min / 1440)\r\nlocal h, m = math.floor((min % 1440) / 60), min % 60\r\nlocal slotKo, slotEn\r\nfor _, s in ipairs(SLOTS) do\r\nif h < s[1] then slotKo, slotEn = s[2], s[3]; break end\r\nend\r\nlocal doy = 9 * 30 + day\r\nreturn { day = day + 1, h = h, m = m, month = math.floor(doy / 30) % 12 + 1, date = doy % 30 + 1, ko = slotKo, en = slotEn }\r\nend\r\n\r\nlocal function clockKo(min)\r\nlocal p = clockParts(min)\r\nreturn string.format(\"모험 %d일째 · %s · %d월 %d일\", p.day, p.ko, p.month, p.date)\r\nend\r\n\r\nlocal function clockEn(min)\r\nlocal p = clockParts(min)\r\nreturn string.format(\"day %d of the adventure, %02d:%02d (%s), calendar %d/%d\", p.day, p.h, p.m, p.en, p.month, p.date)\r\nend\r\n\r\n\r\n\r\n\r\nfunction K.maxLevel(cl)\r\nlocal c = CLASSES[cl or \"\"]\r\nreturn c and #c.levels or 1\r\nend\r\nfunction K.maxLevelAll()\r\nlocal m = 1\r\nfor _, c in pairs(CLASSES) do m = math.max(m, #c.levels) end\r\nreturn m\r\nend\r\n\r\nfunction K.asiLevel(cl, lv)\r\nfor _, f in ipairs((((CLASSES[cl or \"\"] or {}).levels or {})[lv] or {}).features or {}) do\r\nif f == \"Ability Score Improvement\" then return true end\r\nend\r\nreturn false\r\nend\r\n\r\nfunction K.xpNext(pc, cl)\r\ncl = cl or (SHEET and SHEET.class)\r\nif pc.level >= K.maxLevel(cl) then return nil end\r\nreturn XP_LEVEL[pc.level + 1]\r\nend\r\nlocal function xpNext(pc) return K.xpNext(pc) end\r\n\r\n\r\nfunction K.lvHistText(pc)\r\nif not (K.AR and K.AR.on() and type(SHEET) == \"table\" and xpNext(pc) and (tonumber(pc.xp) or 0) >= xpNext(pc)) then return \"\" end\r\nlocal cur = type(SHEET.picks) == \"table\" and SHEET.picks.sexhist\r\nif type(cur) ~= \"string\" then return \"\" end\r\nfor _, n in ipairs(K.AR.names()) do\r\nif n ~= cur and K.AR.histOpen(n, pc) then return \"; at that level-up (the character tab) the sexual history may change to one the XP has opened\" end\r\nend\r\nreturn \"\"\r\nend\r\n\r\n\r\nK.CREATE_WORDS = { \"OOC\", \"GM\", \"캐릭터\", \"시트\", \"종족\", \"클래스\", \"직업\", \"능력치\", \"[PC\" }\r\nfunction K.creationTalk(t)\r\nif type(t) ~= \"string\" or t == \"\" then return false end\r\nlocal up = t:upper()\r\nfor _, w in ipairs(K.CREATE_WORDS) do if up:find(w, 1, true) then return true end end\r\nfor en in pairs(CLASSES) do\r\nif en:sub(1, 1) ~= \"_\" and (t:find(en, 1, true) or (NAMES_KO[en] and t:find(NAMES_KO[en], 1, true))) then return true end\r\nend\r\nreturn false\r\nend\r\n\r\n\r\n\r\n\r\n\r\nfunction K.modKo()\r\nif K.modKoGen ~= K.PACK.gen or not K.modKoSet then\r\nlocal set = {}\r\nfor _, u in ipairs(K.PACK.undo or {}) do\r\nif u[1] == NAMES_KO and type(u[2]) == \"string\" and u[3] == nil then set[u[2]] = true end\r\nend\r\nK.modKoSet, K.modKoGen = set, K.PACK.gen\r\nend\r\nreturn K.modKoSet\r\nend\r\nfunction K.modNamesLine(pc, c)\r\nlocal set = K.modKo()\r\nif next(set) == nil then return nil end\r\nlocal seen, o = {}, {}\r\nlocal function add(n)\r\nif type(n) == \"string\" and set[n] and not seen[n] and NAMES_KO[n] then seen[n] = true; o[#o + 1] = n .. \" \" .. NAMES_KO[n] end\r\nend\r\nlocal function conds(r)\r\nfor n in pairs(type(r) == \"table\" and type(r.cond) == \"table\" and r.cond or {}) do add(n) end\r\n\r\nif type(r) == \"table\" and K.AR and K.AR.on() then for n in pairs(K.AR.condsOf(r)) do add(n) end end\r\nend\r\nlocal function sheet(sh)\r\nif type(sh) ~= \"table\" then return end\r\nadd(sh.species); add(sh.class); add(sh.background)\r\nlocal bg = BACKGROUNDS[sh.background or \"\"]\r\nif type(bg) == \"table\" then\r\nadd(bg.feat)\r\nfor _, x in ipairs(type(bg.fx) == \"table\" and bg.fx or {}) do add(type(x) == \"table\" and x.name or x) end\r\nend\r\nfor _, cl in ipairs(K.classes(sh)) do add(cl.name); add(K.subOf(sh, cl.name)) end\r\nfor _, x in ipairs(Feat.fxList(sh)) do add(x.name) end\r\nfor _, x in ipairs(K.afflictOn(sh)) do add(x.e and x.e.name) end\r\nend\r\nsheet(SHEET)\r\nfor _, n in ipairs(Cond.active(pc)) do add(n) end\r\nif K.AR and K.AR.on() then for n in pairs(K.AR.condsOf(pc)) do add(n) end end\r\nfor _, r in ipairs(Ally.list(pc)) do sheet(r.sheet); conds(r) end\r\nif type(c) == \"table\" and c.active then for _, u in pairs(c.units or {}) do conds(u) end end\r\nif type(pc.scene) == \"table\" and type(pc.scene.units) == \"table\" then for _, u in pairs(pc.scene.units) do conds(u) end end\r\nfor n in pairs(type(pc.items) == \"table\" and pc.items or {}) do add(n) end\r\nif #o == 0 then return nil end\r\ntable.sort(o)\r\nwhile #o > 40 do table.remove(o) end\r\nreturn \"Module names in Korean (in the prose use these, never a translation of your own): \" .. table.concat(o, \", \") .. \".\"\r\nend\r\n\r\nlocal function stateText(pc, clock, fight, c)\r\nlocal items = {}\r\nfor name, n in pairs(pc.items) do\r\n\r\nitems[#items + 1] = ((n > 1) and (name .. \" x\" .. n) or name) .. (name == K.KIT and (\" (\" .. K.kitLeft(pc) .. \" uses; [ITEM|-Healer's Kit|1] spends one use)\") or \"\")\r\nend\r\ntable.sort(items)\r\nlocal res = {}\r\nfor name, r in pairs(PC.res) do\r\nif K.MP.shown(name) and name ~= \"MP\" then res[#res + 1] = string.format(\"%s %d/%d\", name, pc.res[name] or 0, r.max) end\r\nend\r\ntable.sort(res)\r\nlocal lines = {\r\n\"[GAME STATE] Kept by Lua. Trust these numbers over anything earlier in the chat.\",\r\n\r\n\r\n\r\n\r\n\"Now: \" .. clockEn(clock.min) .. \": the time for a status line too, whatever earlier replies wrote. Report time that passes\"\r\n.. \" with [TIME|+Nm/+Nh/+Nd] (a long skip: +Nw, +Nmo, +Ny).\",\r\nstring.format(\"Player: HP %d/%d%s, level %d, XP %d%s, %s%s.\",\r\npc.hp, pc.max, K.maxBonusText(pc) .. ((tonumber(pc.thp) or 0) > 0 and (\", \" .. pc.thp .. \" temporary HP\") or \"\"), pc.level, pc.xp,\r\n\r\nxpNext(pc) and (\" (level \" .. (pc.level + 1) .. \" at \" .. xpNext(pc) .. K.lvHistText(pc) .. \")\") or \" (the highest level: no more XP, so write no XP tag)\",\r\nK.LITE and \"\" or string.format(\"Hit Point Dice %d/%d (%s), \", pc.hd, pc.level, K.hdText(SHEET, pc.hd)), table.concat(res, \", \")),\r\n\"Money: \" .. moneyText(pc.cp) .. \". Counted items: \" .. (#items > 0 and table.concat(items, \", \") or \"none\") .. \".\",\r\n}\r\nlines[#lines + 1] = K.MP.line(pc)\r\nlines[#lines + 1] = K.buffText(pc, \"Player\")\r\nlines[#lines + 1] = K.summonText(pc)\r\nlines[#lines + 1] = K.implantText(pc, c)\r\nlines[#lines + 1] = K.wardText(pc)\r\nlines[#lines + 1] = K.AR.sizesText(pc, c)\r\nlines[#lines + 1] = K.omegaText(pc, clock)\r\nlines[#lines + 1] = K.echoText(pc, clock, c)\r\ndo\r\nlocal hs = {}\r\nfor _, r in ipairs({ pc, table.unpack(Ally.list(pc)) }) do\r\nfor n, h in pairs(type(r.heals) == \"table\" and r.heals or {}) do\r\nif type(h) == \"table\" and (tonumber(h.ends) or 0) > clock.min then\r\nlocal q = clockParts(h.ends)\r\nhs[#hs + 1] = string.format(\"%s ([HEAL|Target|%s|%s|dice|amount], until %02d:%02d on day %d)\", n, n, h.formula, q.h, q.m, q.day)\r\nend\r\nend\r\nend\r\ntable.sort(hs)\r\nif #hs > 0 then lines[#lines + 1] = \"Healing that lasts: \" .. table.concat(hs, \"; \") .. \".\" end\r\nend\r\ndo\r\nlocal ms = {}\r\nfor _, r in ipairs({ pc, table.unpack(Ally.list(pc)) }) do\r\nlocal n = K.mirrorLeft(r)\r\nif n > 0 then ms[#ms + 1] = string.format(\"%s %d\", r == pc and \"Player\" or (r.name or \"?\"), n) end\r\nend\r\nif #ms > 0 then lines[#lines + 1] = \"Mirror Image duplicates left: \" .. table.concat(ms, \", \") .. \". Write a hit on them as usual: Lua rolls a d6 for\"\r\n.. \" each duplicate, and on any 3+ a duplicate is hit instead (no damage, one fewer); the ATTACK's verdict says which.\" end\r\nend\r\nif K.AR.on() then\r\nlines[#lines + 1] = \"Player's \" .. K.AR.text(pc, pc, c) .. \", \" .. K.AR.apAC(pcStats(pc).ac, K.AR.inhib(pc, pc)) .. \".\"\r\nlines[#lines + 1] = K.AR.implText(pc)\r\nlines[#lines + 1] = K.AR.rules(pc, c)\r\nlines[#lines + 1] = K.sceneText(pc, c)\r\nlines[#lines + 1] = K.PG.rules(pc, c)\r\nend\r\nlocal now = Feat.now(pc)\r\nif now then lines[#lines + 1] = \"Player \" .. now:gsub(\"^A\", \"a\") .. \".\" end\r\nlocal wait = Feat.waiting(SHEET, pc)\r\nif wait then lines[#lines + 1] = wait\r\nelseif K.undoText(pc) ~= \"\" then lines[#lines + 1] = (K.undoText(pc):gsub(\"^ \", \"\")) end\r\nlocal found, magic = {}, {}\r\nfor name, l in pairs(type(pc.loot) == \"table\" and pc.loot or {}) do\r\nif type(l) == \"table\" and l.srd then\r\nmagic[#magic + 1] = K.MI.text(name, l, pc.items[name])\r\nif l.att then magic.att = true end\r\nelseif type(l) == \"table\" then\r\nlocal pwt = LOOT.pwText(l.pw)\r\nfound[#found + 1] = string.format(\"%s (grade %s, %s%s%s)\", name, l.grade or \"C\",\r\nl.base and (l.base .. \" +\" .. (l.plus or 0)) or \"no bonus\", pwt ~= \"\" and (\", \" .. pwt) or \"\", (l.fx or \"\") ~= \"\" and (\"; \" .. l.fx) or \"\")\r\n\r\nif type(l.pwFix) == \"table\" then\r\nfound[#found] = found[#found] .. string.format(\"; its spell power (%s) was above grade %s: pick an %s spell of level %d or lower close to it and write\"\r\n.. \" [LOOT|%s|%s|-|-|spell Name] in your next reply (sets the power, not a new copy)\", tostring(l.pwFix.want), l.grade or \"?\", K.srdX(), tonumber(l.pwFix.max) or 0, name, l.grade or \"?\")\r\nend\r\nend\r\nend\r\nif #found > 0 then\r\ntable.sort(found)\r\nlines[#lines + 1] = \"Found items (Lua counts only the listed bonus and powers while it is equipped, a trinket's while carried; any other effect is narrated): \"\r\n.. table.concat(found, \", \") .. \".\"\r\nend\r\nlines[#lines + 1] = LOOT.tierText(pc.level)\r\nif #magic > 0 then\r\ntable.sort(magic)\r\nlines[#lines + 1] = K.srdX() .. \" magic items (Lua counts the powers listed while the item is worn or held, once attuned when it needs it; the rest of\"\r\n.. \" its rules text is narrated): \" .. table.concat(magic, \"; \") .. \".\"\r\nif magic.att then lines[#lines + 1] = \"Attuning takes a Short Rest focused on the item, out of a fight, 3 items at most: [ATTUNE|Item] (Lua counts the hour\"\r\n.. \" unless a [REST|short] in the same reply was it); [ATTUNE|-Item] ends it. A companion's: [ATTUNE|Name/Item].\" end\r\nend\r\nlocal st = pcStats(pc)\r\nlocal atk = {}\r\nfor _, a in ipairs(st.attacks) do atk[#atk + 1] = string.format(\"%s +%d %s\", a.name, a.hit, a.dmg) end\r\nlocal eq = pc.equip or {}\r\nlocal wt539 = not pc.form and K.walkTied(SHEET, st.speed) or {}\r\nif st.fly then wt539[#wt539 + 1] = string.format(\"fly %d ft, hover\", st.fly) end\r\nlines[#lines + 1] = string.format(\"Equipped: armor %s, main hand %s, off hand %s%s. AC %d, Speed %d ft%s. Attacks: %s.%s\",\r\neq.armor or \"none\", eq.main or \"empty\", eq.off or \"empty\", (pc.pactW and Feat.invoked(SHEET, \"Pact of the Blade\")) and (\", pact weapon \" .. pc.pactW) or \"\", st.ac, st.speed, #wt539 > 0 and (\" (\" .. table.concat(wt539, \", \") .. \")\") or \"\", table.concat(atk, \"; \"),\r\n#st.notes > 0 and (\" \" .. table.concat(st.notes, \"; \") .. \".\") or \"\")\r\nlocal wt = K.wearText(pc)\r\nif wt then\r\nlines[#lines + 1] = \"Damaged gear (kept by Lua, already in the numbers above): \" .. wt\r\n.. \". A Mending spell or a smith in a town repairs it: [WEAR|Item|repair].\"\r\nend\r\nlocal n = Ally.size(pc)\r\nlines[#lines + 1] = string.format(\"Encounter XP budget (sum of the monsters' XP, %s): Low %d, Moderate %d, High %d.\",\r\nn > 1 and (\"party of \" .. n) or \"Player alone\", Ally.budget(pc, 1), Ally.budget(pc, 2), Ally.budget(pc, 3))\r\n\r\n.. (function() local cb, cl = K.capBudget(pc); return cl == \"High\" and \"\" or string.format(\" The user's fight difficulty caps a fight at %s (%d XP).\", cl == \"Hard\" and \"1.5 x High\" or cl, cb) end)()\r\n\r\n.. \" Above the cap, Lua leaves out the last enemies named in the COMBAT tag until it fits. Only a fight the story has already\"\r\n.. \" shown to be hopeless may go above it, marked [COMBAT|Monster|...|deadly]; it then stands as written, and Player keeps a way out\"\r\n.. \" (fleeing, surrender or talking stay possible).\"\r\nlocal tn, td = TRAP.row(\"nuisance\", pc.level), TRAP.row(\"deadly\", pc.level)\r\nlines[#lines + 1] = string.format(\"Traps at Player's level: nuisance save DC %d, damage %s; deadly save DC %d, damage %s.\", tn[1], tn[2], td[1], td[2])\r\n.. \" A fall of Player or a companion (no save): [TRAP|Fall N|-|-|-|-|-|Nd6|dice|damage], 1d6 per 10 feet, 20d6 at most, Prone after (a companion: Name/- in the second field).\"\r\n\r\n.. \" Finding one (Perception, or Investigation for a hidden lid): DC 11 for a trip wire or a net, 15 for a hidden pit, needle or darts;\"\r\n.. \" disarming: a DC 15 Dexterity check (Thieves' Tools, or Sleight of Hand), none once a trip wire is found (cut or stepped over).\"\r\n\r\n\r\nlocal pn = (pc.placeName or \"\") ~= \"\" and (\", now at \" .. pc.placeName) or \", its name not written yet\"\r\nlines[#lines + 1] = (pc.place == \"wild\" and (\"Place: away from any settlement (no merchant)\" .. pn .. \".\") or (\"Place: in a town or village (merchants nearby)\" .. pn .. \".\"))\r\n.. \" Whenever Player moves to another place (another area, building or notable spot; not within the same room), write\"\r\n.. \" [PLACE|town or wild|short Korean name: area · spot (예: 은빛 항구 · 금잔 여관)]: town in a town or village, wild in the wilds, ruins or a dungeon.\"\r\n.. \" The status panel shows that name; a status line the preset asks for uses it too.\"\r\nlocal conds = Cond.text(pc, clock)\r\nif conds then lines[#lines + 1] = conds end\r\n\r\nlines[#lines + 1] = (K.LITE and (\"One [REST|long] rests Player and the companions together (8 hours; Lua moves the clock: write no TIME\"\r\n.. \" for it). There is no Short Rest in this game: outside a fight a breather, a meal or a healer's care gives back some HP and MP as the\"\r\n.. \" story fits, [HEAL|Target|Rest|N|-|N] and [MP|Target|+N] (Lua keeps the maximum; in a fight only potions, spells and features heal).\"\r\n.. \" If Player sleeps on until morning, add the extra hours with TIME (e.g. [TIME|+4h]).\")\r\nor (\"One REST tag rests Player and the companions together. Lua rolls the Hit Point Dice (not from the pools) and moves the clock\"\r\n.. \" itself, 1 hour for a Short Rest and exactly 8 for a Long Rest: write no TIME for it. If Player sleeps on until morning, add\"\r\n.. \" the extra hours with TIME (e.g. [TIME|+4h]).\")) .. K.npcHealText(pc)\r\n\r\n.. \" Standing watch is part of a Long Rest's 8 hours, and the one on watch notices with passive scores (PASSIVE).\"\r\n\r\n.. \" A rest is interrupted by rolling Initiative, by damage or by casting a spell (a cantrip does not); a Long Rest needs 6 hours of sleep:\"\r\n.. \" write the REST only for one that was finished (an interrupted Long Rest takes 1 hour more for each interruption).\"\r\nif pc.long_end then\r\nlocal wait = K.LONG_WAIT - (clock.min - pc.long_end)\r\n\r\nlines[#lines + 1] = wait > 0 and string.format(\"A Long Rest is possible again in %d hours (a limit only: never hurry the story to reach it).\", math.ceil(wait / 60))\r\nor \"A Long Rest is possible.\"\r\nend\r\nif K.DEATH == \"gentle\" then\r\n\r\nlines[#lines + 1] = \"Death rule (the user's choice): gentle. At 0 HP Player and the companions fall Unconscious and Stable; nobody dies,\"\r\n\r\n\r\n\r\n.. \" not even by massive damage; there are no death saving throws, and while the fight goes on enemies stop attacking a fallen one. When a fight ends with someone in the party still\"\r\n.. \" standing, the fallen come to with 1 HP in the next reply (Lua sets it). If the whole party falls, the fight is lost, not the lives\"\r\n.. \" (what the enemies do then, leave, rob or take captive, is in COMBAT STATUS):\"\r\n\r\n.. \" the fallen come to with 1 HP an hour after the fight, at the TIME tag that reaches that hour (write the time that passes,\"\r\n.. \" e.g. [TIME|+1h], before they speak or act).\"\r\nelseif K.DEATH == \"harsh\" then\r\nlines[#lines + 1] = \"Death rule (the user's choice): harsh. At 0 HP Player or a companion dies at once; no death saving throws.\"\r\n.. K.DEATH_REAL\r\nelse\r\n\r\nlines[#lines + 1] = \"Death rule (the user's choice): SRD. Death is real here: at 0 HP Player and the companions make death saving throws\"\r\n.. \" (three failures: dead), a blow whose damage past 0 HP is the HP maximum or more kills outright, and enemies may keep attacking\"\r\n.. \" one who is down (each hit a failed death save, a Critical Hit two).\" .. K.DEATH_REAL\r\nend\r\nif pc.dead then\r\nlines[#lines + 1] = \"Player is DEAD.\" .. ((type(SHEET) == \"table\" and not SHEET.default)\r\nand \" To play on with a new character the user clears the sheet with 시트 초기화 on the character tab, then makes one.\" or \"\")\r\nelseif pc.hp <= 0 and pc.stable then\r\n\r\n\r\nlocal wake\r\nif fight then\r\nwake = \"no actions or speech until healed.\"\r\n\r\n.. (K.DEATH == \"srd\" and (\" If the fight ends in this reply, Player stays down 1-4 hours (Lua sets the hour; the next\"\r\n.. \" request gives it): no waking in this reply.\") or \"\")\r\nelseif K.DEATH == \"gentle\" and K.partyStands(pc) then\r\nwake = \"the fight is over and someone in the party stands, so in this reply Player comes to with 1 HP (gentle rule; Lua sets it), groggy but able to talk and move.\"\r\nelseif pc.wake then\r\n\r\nlocal hrs = math.max(1, math.floor((math.max(0, pc.wake - clock.min) + 59) / 60))\r\n\r\nwake = string.format(\"Player stays Unconscious until %s (about %s of story time from now). Until then no speech or action from\"\r\n.. \" Player; a HEAL tag (a potion, a spell) wakes Player at once. To move on, write the time that passes with TIME first: Lua\"\r\n.. \" wakes Player with 1 HP at the TIME tag that reaches that hour, and the tags after it see Player up.\",\r\nclockEn(pc.wake), hrs == 1 and \"an hour\" or (hrs .. \" hours\"))\r\nelse\r\nwake = \"Player stays Unconscious for \" .. (K.DEATH == \"gentle\" and \"an hour\" or \"1-4 hours\") .. \" of story time (Lua sets the hour\"\r\n.. \" when this reply ends): no speech or action from Player in this reply; a HEAL tag (a potion, a spell) wakes Player at once.\"\r\nend\r\nlines[#lines + 1] = \"Player is at 0 HP, Unconscious and Stable (no death saving throws): \" .. wake\r\nelseif pc.hp <= 0 then\r\n\r\n\r\n\r\nlocal s = string.format(\"Player is at 0 HP and Unconscious, dying. Death saving throws so far: %d successes, %d failures;\"\r\n.. \" a hit of %d or more now kills Player outright (massive damage).\", pc.ds.s, pc.ds.f, pc.max)\r\n\r\n.. (((type(pc.res) == \"table\" and tonumber(pc.res[\"Heroic Inspiration\"]) or 0) > 0)\r\nand \" A save that would be the third failure takes Player's Heroic Inspiration by itself (Lua rerolls it and says the result): write the save as rolled, and never offer that reroll in the story.\" or \"\")\r\n\r\n\r\n\r\nlocal after = \" Player comes to in this reply only by a 20 or a HEAL tag; once Stable, Player wakes 1-4 hours later, at an hour\"\r\n.. \" Lua sets (the next request gives it). The companions' waking after a fight is theirs, not Player's: a dying Player rolls on.\"\r\n\r\nlocal dmod = -(tonumber(Cond.fx(pc).pen) or 0) + (K.PARTY and tonumber(K.PARTY.aura) or 0)\r\n+ (K.lootSave and tonumber(K.lootSave(pc)) or 0) + (K.buffSum and tonumber(K.buffSum(pc, \"save\")) or 0)\r\nlocal need = dmod == 0 and \"10 or higher succeeds\" or string.format(\"a total of 10 or higher succeeds: %+d to the d20, so %d or more on the die; a 1 is two failures, a 20 HP 1\", dmod, 10 - dmod)\r\nif fight then\r\ns = s .. \" At the start of each of Player's turns write [DEATH|d20|success/failure] with the next d20 (\" .. need .. \").\"\r\n.. \" That save is Player's whole turn. If the fight ends in this reply, the saves go on one after another (no turns then)\"\r\n.. \" until Player is Stable, up or dead.\" .. after\r\nelse\r\n\r\ns = s .. \" No fight is on, so the saves come about 6 seconds apart: in this reply write [DEATH|d20|success/failure] (the\"\r\n.. \" next d20s, \" .. need .. \") one after another until Player is Stable, up or dead, unless someone helps first.\"\r\n.. after\r\nend\r\nif K.partyStands(pc) then\r\n\r\n\r\nlocal spare = K.spareBy(pc)\r\ns = s .. \" A companion who stands can make Player Stable with its action: a Wisdom (Medicine) check DC 10,\"\r\n.. \" [CHECK|Name/Medicine|d20|+bonus|10|success/failure]\"\r\n.. (spare and (\", or \" .. spare .. \"'s Spare the Dying, [CAST|Spare the Dying|0|\" .. spare .. \"]\") or \"\")\r\n\r\n.. (K.kitLeft(pc) > 0 and (\", or one use of the Healer's Kit with no check, [USE|Name/Healer's Kit|Player] (\" .. K.kitLeft(pc) .. \" uses left)\") or \"\")\r\n.. \"; Lua sets Stable on a success. A HEAL tag (a potion, a spell) brings Player up at once.\"\r\nend\r\nlines[#lines + 1] = s\r\nend\r\nlocal rn = K.raiseNote(pc, clock, c)\r\nif rn then lines[#lines + 1] = rn end\r\nreturn table.concat(lines, \"\\n\")\r\nend\r\n\r\n\r\nlocal function sheetText(sh, guide)\r\nlocal ab = {}\r\n\r\nlocal fm = K.formOf()\r\nfor _, a in ipairs(ABILS) do\r\nlocal sc = fm and fm.sc and fm.sc[a]\r\nab[#ab + 1] = sc and string.format(\"%s %d (%+d, the form's)\", a:sub(1, 3):upper(), sc, abilityMod(sc))\r\nor string.format(\"%s %d (%+d)\", a:sub(1, 3):upper(), SCORE[a], MOD[a])\r\nend\r\nlocal sk = {}\r\nfor _, k in ipairs(K.profSkills(sh)) do sk[#sk + 1] = string.format(\"%s %+d%s\", k, bonusFor(k), EXPERT[k] and \" (Expertise)\" or \"\") end\r\nlocal ot = K.otherSkills(sh)\r\nif #ot > 0 then\r\nif #sk == 0 then sk[1] = \"none\" end\r\nsk[#sk] = sk[#sk] .. \"; without proficiency but with a bonus: \" .. table.concat(ot, \", \")\r\nend\r\nlocal cl = CLASSES[sh.class]\r\nlocal feats = Feat.levelFeatures(sh)\r\nfor _, c in ipairs(K.classes(sh)) do\r\nlocal scl = CLASSES[c.name].subclass\r\nif scl and c.level >= scl.level then\r\n\r\n\r\nlocal sub = K.subOf(sh, c.name) or scl.name\r\nlocal first = sub ~= scl.name and ((K.subRec(c.name, sub) or {}).levels or {})[tostring(scl.level)]\r\nfeats[#feats + 1] = \"Subclass \" .. sub .. (sub ~= scl.name and (\" (\" .. (type(first) == \"table\" and #first > 0 and (table.concat(first, \", \") .. \"; \") or \"\")\r\n.. \"this one, not the \" .. scl.name .. \" the class entry names)\") or \"\")\r\nend\r\nend\r\n\r\n\r\nlocal sv, svp = {}, {}\r\nfor _, a in ipairs(ABILS) do\r\nsv[#sv + 1] = string.format(\"%s %+d\", a:sub(1, 3):upper(), bonusFor(a .. \" save\"))\r\nif SAVE_PROF[a] then svp[#svp + 1] = a end\r\nend\r\n\r\nlocal seenF, featsU = {}, {}\r\nfor _, x in ipairs(feats) do\r\n\r\nif not seenF[x] and not (K.LITE and K.MP.GONE[x]) then seenF[x] = true; featsU[#featsU + 1] = x end\r\nend\r\nfeats = featsU\r\nlocal lines = {\r\nstring.format(\"Character: %s %s, %s background. %s. Proficiency Bonus +%d. Saving throws: %s (proficient: %s).\"\r\n.. \" Skill proficiencies: %s; every other skill uses its ability modifier. Base Speed %s (the current one is on the Equipped line). Class features: %s.\",\r\nsh.species, #K.mcList(sh) > 0 and (K.mcText(sh) .. \" (multiclass, character level \" .. K.charLevel(sh) .. \")\") or (sh.class .. \" level \" .. sh.level),\r\nsh.background, table.concat(ab, \", \"), PROF, table.concat(sv, \", \"), table.concat(svp, \", \"),\r\ntable.concat(sk, \", \"), K.speedText and K.speedText(sh) or (PC.speed .. \" ft\"), table.concat(feats, \", \")),\r\n}\r\nlines[#lines + 1] = K.toolText(sh)\r\n\r\nfor _, e in ipairs(Feat.fxOf(sh, \"count_as\")) do\r\nif type(e.types) == \"table\" and #e.types > 0 then\r\nlines[#lines + 1] = string.format(\"Player counts as %s for effects that pick creatures by type (Turn Undead, a ward against that type)%s.\",\r\ntable.concat(e.types, \" and \"), e.optional and \", when it chooses to\" or \"\")\r\nend\r\nend\r\n\r\nfor _, cx in ipairs(K.classes(sh)) do\r\nlocal d = K.subDefault(cx.name)\r\nif d and cx.level >= K.subLevel(cx.name) and K.subOnly(cx.name) then\r\nlines[#lines + 1] = string.format(\"%s subclass: %s, the only one the SRD has for it; never offer another (more come only with a data pack).\", cx.name, d)\r\nend\r\nend\r\n\r\nif #K.mcList(sh) > 0 then\r\nlines[#lines + 1] = \"Multiclass (SRD): each class's features at that class's own level; the saving throws are the first class's (\"\r\n.. sh.class .. \"); the Proficiency Bonus and cantrips go by the character level; one Extra Attack at most (it does not stack)\"\r\n.. (#K.casters(sh) > 1 and (\"; each prepared spell is one casting class's and uses that class's ability, each class prepares spells only up to\"\r\n.. \" the level its own levels allow, and the spell slots are shared (the SRD Multiclass Spellcaster table): any of them casts any of the spells\")\r\nor K.castCl(sh) and (\"; spells from the \" .. K.castCl(sh) .. \" levels\") or \"\") .. \".\"\r\nend\r\nif sh.held then\r\nlines[#lines + 1] = string.format(\"Level %d came from a data pack (a module) that is off now: until it is on again Player has level %d's class features.\",\r\nsh.held, sh.level)\r\nend\r\nif K.cl(sh, \"Rogue\") > 0 then\r\nlines[#lines + 1] = \"Sneak Attack \" .. K.rowOf(sh, \"Rogue\").sneak_attack .. \" once per turn (Advantage, or an ally within 5 ft of the target that is not Incapacitated, and no Disadvantage; Finesse or ranged weapon): add it to the formula.\"\r\nend\r\nlocal ft = Feat.text(sh, {})\r\nif ft then lines[#lines + 1] = ft end\r\nlines[#lines + 1] = K.replacedText(sh)\r\nlines[#lines + 1] = \"When Player spends a limited use (a class feature with uses, or a spell slot to cast a spell), write [USE|name]\"\r\n.. \" with the exact name from the uses in GAME STATE, e.g. [USE|Action Surge]. Spell slots are spent by CAST. Second Wind is spent by its HEAL tag alone: no USE for it.\"\r\n.. (K.cl(sh, \"Fighter\") >= 2 and \" Action Surge: one more action this turn, never the Magic action (no spell with it), once a turn.\" or \"\")\r\n\r\nlocal cviews = K.casterViews(sh)\r\nlocal multiCast = #cviews > 1\r\nfor _, csh in ipairs(cviews) do\r\nlocal cl, sh0, sh = CLASSES[csh.class], sh, csh\r\nlocal m = MOD[cl.spell_ability]\r\nlocal dr = K.drainOf(sh0, cl.spell_ability)\r\nif dr and dr.keepSpell then m = abilityMod(tonumber((type(sh0.mscores) == \"table\" and sh0.mscores[cl.spell_ability]) or sh0.scores[cl.spell_ability]) or 10) end\r\nlocal row = K.rowAt(sh, sh.class, sh.level)\r\nlocal maxLv = K.rowMaxLv(row)\r\nlocal who = multiCast and (sh.class .. \" \") or \"\"\r\nlines[#lines + 1] = string.format(\"Spellcasting (%s%s): spell save DC %d%s, spell attack %+d. Slots are in the feature uses.\",\r\nmultiCast and (sh.class .. \", \") or \"\", cl.spell_ability, 8 + PROF + m, sh.class == \"Sorcerer\" and \" (+1 during Innate Sorcery)\" or \"\", PROF + m)\r\nif ((sh.cantrips and #sh.cantrips > 0) or (sh.spells and #sh.spells > 0)) then\r\n\r\n\r\n\r\nlocal alw = Feat.always(sh)\r\nlines[#lines + 1] = (multiCast and (sh.class .. \" cantrips: \") or \"Cantrips: \") .. (#(sh.cantrips or {}) > 0 and table.concat(sh.cantrips, \", \") or \"none\")\r\n.. \". Prepared spells: \" .. table.concat(sh.spells or {}, \", \")\r\n.. (#alw > 0 and (\"; always prepared too (not counted): \" .. table.concat(alw, \", \")) or \"\")\r\n.. \". Player casts no spell outside the list \\\"Spells Player can cast\\\".\"\r\n\r\nlocal oc = Spell.cantripsOpen(sh, row)\r\nlocal op = math.max(0, row.prepared - #(sh.spells or {}))\r\nif oc + op > 0 then\r\nlines[#lines] = lines[#lines] .. string.format(\" Still open: %d cantrips, %d prepared spells; the screen tells the user, so pick them\"\r\n.. \" with the user only when asked (a SPELLS tag with the whole list).\", oc, op)\r\n\r\n.. (oc > 0 and (\" The cantrips it can still take: \" .. table.concat(Spell.cantripsLeft(sh), \", \") .. \".\") or \"\")\r\nend\r\nelseif K.noSpellsYet(sh, sh.class, sh.level) then\r\nlocal from = K.spellsFrom(sh.class, sh.level)\r\nlines[#lines + 1] = string.format(\"%s %d has no spells to pick yet%s: write no SPELLS tag.\", sh.class, sh.level,\r\nfrom and (\" (they start at level \" .. from .. \")\") or \"\")\r\nelse\r\nlines[#lines + 1] = \"No \" .. who .. \"spells chosen yet: before Player casts \" .. (multiCast and (\"as a \" .. sh.class) or \"anything\")\r\n.. \", help the user (OOC) pick them and write the SPELLS tag.\"\r\nend\r\nif not K.noSpellsYet(sh, sh.class, sh.level) then\r\nlines[#lines + 1] = string.format(\"Spell list tag: [SPELLS|%s%d cantrips, comma-separated|1-%d prepared spells of level 1-%d, comma-separated],\"\r\n.. \" English names from the %s list (the SRD's and a module's); %s.\", multiCast and (sh.class .. \"|\") or \"\", Spell.cantripsWant(sh, row), row.prepared, maxLv, sh.class, Spell.changeRule(sh))\r\nend\r\nif K.isBook(sh.class) then\r\nlocal book = type(sh.book) == \"table\" and sh.book or {}\r\nlocal room, roomAny = Spell.bookRoom(sh)\r\n\r\n\r\nlocal rit = {}\r\nfor _, n in ipairs(book) do if SPELLS[n] and SPELLS[n].ritual then rit[#rit + 1] = n end end\r\nlines[#lines + 1] = (#book > 0 and (\"Spellbook: \" .. table.concat(book, \", \") .. \". Prepared spells come only from it. \"\r\n.. (#rit > 0 and (\"Rituals in it: \" .. table.concat(rit, \", \") .. \".\") or \"No ritual in it.\"))\r\nor \"No spellbook yet: the first SPELLS tag starts it with the prepared spells.\")\r\n\r\n\r\n.. (room > 0 and string.format(\" Room for %d more spells (level 1-%d, Wizard list\" .. (roomAny < room and string.format(\"; %d of them Evocation spells only, Evocation Savant\", room - roomAny) or \"\")\r\n.. \"), not chosen yet: no other spell is in the book until\"\r\n.. \" [SPELLBOOK|Spell, Spell] writes it, when the user asks (ritual spells such as Detect Magic suit an empty place). The screen\"\r\n.. \" already shows the user the empty places: never mention them in the story.\", room, maxLv)\r\nor \" The book is full for this level: a spell found on a scroll or in another book is copied with [SPELLBOOK|Spell] for 50 gp and 2 hours per spell level (Lua takes both).\")\r\n.. (#rit > 0 and \" A ritual spell in the book is cast as a Ritual even when not prepared, never in a fight: [CAST|Spell|ritual].\" or \"\")\r\nend\r\nend\r\nlines[#lines + 1] = string.format(\"Passive scores (noticing without trying): Perception %d, Insight %d, Investigation %d.\",\r\n10 + bonusFor(\"Perception\"), 10 + bonusFor(\"Insight\"), 10 + bonusFor(\"Investigation\"))\r\nif sh.default and guide then\r\nlines[#lines + 1] = \"No character has been created yet; Player is the default test character above. If the user asks (OOC) to make one, help them choose, then write one tag:\"\r\n.. (CREATE_GUIDE:gsub(\"%%%%MAXLV%%%%\", tostring(K.maxLevelAll())):gsub(\"%%%%BGS%%%%\", function() return K.bgGuide() end)\r\n:gsub(\"%%%%SPECIES%%%%\", function() return K.speciesGuide() end):gsub(\"%%%%ORIGINS%%%%\", function() return K.originNames() end)\r\n:gsub(\"%%%%CLASSES%%%%\", function() return table.concat(K.classNames(), \", \") end)\r\n:gsub(\"%%%%PACKSKILLS%%%%\", function() return K.packSkillGuide() end))\r\nelseif sh.default then\r\nlines[#lines + 1] = \"Player is the default test character above; the user can ask (OOC) to make a new one.\"\r\nend\r\n\r\nif sh.default and sh.reset == \"dead\" then\r\nlines[#lines + 1] = \"The user cleared the sheet after Player's death to make a new character: the one who died stays dead in the story, and the new one enters it once made.\"\r\nelseif sh.default and sh.reset then\r\nlines[#lines + 1] = \"The user cleared the sheet to make the character again from the start: the new one takes its place in the story once made.\"\r\nend\r\nreturn table.concat(lines, \"\\n\")\r\nend\r\n\r\n\r\n\r\nlocal function turnList(c, pc)\r\nlocal n, start = #c.order, 1\r\nfor i, name in ipairs(c.order) do if name == c.last then start = i % n + 1 end end\r\nlocal out, i, mine = {}, start, false\r\nfor _ = 1, 2 * n do\r\nlocal name = c.order[i]\r\nlocal u = c.units[name]\r\nif u and u.side == \"pc\" then\r\nif mine then break end\r\nmine = true\r\nif pc.dead then break end\r\nout[#out + 1] = K.upNow(pc) and \"Player (what the user's message says)\"\r\nor (pc.stable and \"Player (down and Stable: no roll)\"\r\n\r\nor \"Player (down: only the death saving throw, none if made Stable before this turn)\")\r\nelseif u and u.side == \"ally\" then\r\nlocal a = Ally.find(pc, u.ally)\r\nif a and K.upNow(a) then out[#out + 1] = name .. (u.guest and \" (helper: you play them)\" or \" (companion: you play them)\")\r\n\r\n\r\nelseif a and not a.dead then out[#out + 1] = name .. \" (down: skip it, unless healed before this turn: then it stands and acts)\" end\r\nelseif u and u.side == \"friend\" then\r\n\r\nlocal lim = u.noatk and \" (familiar: you play it; no attacks)\" or (pc.mount == name and \" (Player rides it: Dash, Disengage or Dodge only)\")\r\nor (u.summon and \" (summoned: you play it)\") or \" (helper: you play them)\"\r\nif u.hp > 0 then out[#out + 1] = name .. lim end\r\nelseif u and u.hp > 0 then\r\n\r\n\r\nlocal note = \"\"\r\nlocal fi = u.side == \"enemy\" and K.foeCondFx(u, pc).incap\r\nif fi then\r\nnote = \" (\" .. fi .. \": no action, only the save its spell allows at the end of its turn)\"\r\nelseif u.side == \"enemy\" and u.tgt then\r\n\r\nnote = \" (attacks \" .. u.tgt .. ((u.tgt == \"Player\" and (pc.hp or 0) <= 0) and \", down, or the enemies stop: below\" or \"\") .. \")\"\r\nend\r\nout[#out + 1] = name .. note\r\nelseif u and K.foeUp(u) then\r\n\r\nout[#out + 1] = name .. \" (at 0 HP: its turn starts with Regeneration, the HEAL tag)\"\r\nend\r\ni = i % n + 1\r\nend\r\nreturn out\r\nend\r\n\r\nlocal function combatText(c, pc, hazards, userText)\r\nK.roundNow, K.fightNow, K.curC = tonumber(c.round) or 1, c.active, c\r\nK.curPc = pc or K.curPc\r\nlocal order, stats, seen = {}, {}, {}\r\nlocal lrNames = {}\r\nlocal selfActing = false\r\nfor _, name in ipairs(c.order) do\r\nlocal u = c.units[name]\r\nlocal r = Ally.rec(pc, name, u)\r\nlocal hp = r and r.hp or u.hp\r\nlocal max = r and r.max or u.max\r\nlocal st = statsOf(u, pc)\r\nlocal atk = {}\r\nfor _, a in ipairs(st.attacks) do\r\natk[#atk + 1] = string.format(\"%s +%d %s%s%s%s\", a.name, a.hit, a.dmg, (a.adv and (\" (with Advantage \" .. a.adv .. \")\") or \"\")\r\n\r\n.. (a.bloodied and (\" (\" .. a.bloodied .. \" while it is Bloodied)\") or \"\") .. (a.vsb and (\" (\" .. a.vsb .. \" against a Bloodied target)\") or \"\")\r\n.. (a.alt and (\" (\" .. a.alt .. \" \" .. (a.altwhy or \"\") .. \")\") or \"\"), Feat.exText(a), Feat.masteryText(a))\r\nend\r\n\r\nlocal down = \"\"\r\nif u.side == \"ally\" and r and r.dead then\r\ndown = \" (DEAD: no turn, no rolls)\"\r\nelseif hp <= 0 and u.side == \"enemy\" and K.foeUp(u) then\r\ndown = \" (DOWN, not dead: Regeneration at the start of its turn brings it back unless Acid or Fire damage comes first)\"\r\nelseif hp <= 0 then\r\n\r\ndown = u.side == \"pc\" and (pc.dead and \" (DEAD: no turn, no rolls)\" or pc.zeroAct and \" (0 HP, still acting: it falls when it climaxes or dies; damage is death save failures)\"\r\nor \" (DOWN: no turn; only death saving throws)\")\r\nor u.side == \"ally\" and (r and r.zeroAct and \" (0 HP, still acting: it falls when it climaxes or dies)\" or \" (DOWN: no rolls)\") or (u.climaxOut and \" (OUT: a climax with no recovery dice, as one defeated; no turn, no rolls)\")\r\n\r\nor \" (DEAD: no turn, no rolls)\"\r\nend\r\nif u.ko and hp > 0 then down = \" (KNOCKED OUT: alive, a captive once the fight ends; no turn, no rolls)\" end\r\n\r\nlocal lrLeft = (u.side == \"enemy\" and u.lr) and string.format(\", Legendary Resistance %d left\", u.lr) or \"\"\r\nif u.side == \"enemy\" and (tonumber(u.lr) or 0) > 0 and (hp > 0 or K.foeUp(u)) then lrNames[#lrNames + 1] = name end\r\n\r\nlocal cov = K.coverOf(u)\r\nif cov > 0 and hp > 0 then\r\nlocal dex\r\nif u.side == \"enemy\" then\r\ndex = type(st.saves) == \"table\" and st.saves.Dexterity or 0\r\nelse\r\ndex = Ally.run(pc, r, function() return bonusFor(\"Dexterity save\") - Cond.fx(r or pc).pen end)\r\nend\r\nlrLeft = lrLeft .. string.format(\", behind %s: AC %d against ranged attacks, Dexterity save %+d\", K.COVER_EN[cov], st.ac + cov, dex + cov)\r\nend\r\n\r\nif u.side == \"enemy\" then\r\nlocal mm = MONSTERS[u.kind or \"\"] or {}\r\nif (tonumber(u.thp) or 0) > 0 then lrLeft = lrLeft .. string.format(\", Temporary HP %d\", u.thp) end\r\nif (tonumber(u.exh) or 0) > 0 then lrLeft = lrLeft .. string.format(\", Exhaustion %d (-%d to its d20 tests)\", u.exh, 2 * u.exh) end\r\nif tonumber(u.acUp) then lrLeft = lrLeft .. string.format(\", AC +%d (%s)\", u.acUp, u.acUpWhy or \"until its turn\") end\r\nif (mm.react or mm.shield or mm.split) and not mm.reactive and u.reactRound == (c.round or 1) then lrLeft = lrLeft .. \", its reaction used this round\" end\r\nif mm.shield and mm.shield.uses then lrLeft = lrLeft .. string.format(\", Protective Magic %d left\", tonumber(u.shieldLeft) or mm.shield.uses) end\r\n\r\nlocal cfx = K.foeCondFx(u, pc)\r\nif #cfx.list > 0 then\r\nlocal cs = {}\r\nfor _, cn in ipairs(cfx.list) do\r\nlocal x = u.cond[cn]\r\nlocal who = type(x) == \"table\" and (x.by or x.src or (type(x.conc) == \"table\" and x.conc.spell)) or nil\r\ncs[#cs + 1] = cn .. (who and (\" (\" .. tostring(who) .. K.prismHint(u, cn, x) .. \")\") or \"\")\r\nend\r\nlrLeft = lrLeft .. \", \" .. table.concat(cs, \", \") .. (cfx.incap and \"; it takes no action\" or \"\")\r\n.. (next(cfx.autofail) and \"; it fails Strength and Dexterity saves\" or \"\")\r\n.. (cfx.crit and \"; a hit from within 5 ft is a Critical Hit\" or \"\")\r\nend\r\nlrLeft = lrLeft .. K.foeFxLine(u, pc, st)\r\nif (tonumber(u.strip) or 0) > 0 then lrLeft = lrLeft .. string.format(\", AC %d now (Clasp Master: %d piece%s off)\", K.foeAC(u, pc, st), u.strip, u.strip > 1 and \"s\" or \"\") end\r\nlocal pk = K.polyLive(u, pc)\r\nif pk then lrLeft = lrLeft .. string.format(\", a %s by %s (%s's): the numbers of its own line below; the spell ends when its Temporary HP are gone\", pk, u.poly.by, tostring(u.poly.caster or \"Player\")) end\r\nend\r\n\r\nlocal sw = u.side ~= \"enemy\" and K.swallowed(c, u.side == \"pc\" and \"Player\" or name)\r\nif sw then lrLeft = lrLeft .. \", SWALLOWED by \" .. sw .. \" (Blinded and Restrained, Total Cover from everything outside it; its acid at the start of its turns)\" end\r\n\r\nlocal arr = r or u\r\nif K.AR.on() and ((type(arr.ar) == \"table\" and ((tonumber(arr.ar.cur) or 0) > 0 or (tonumber(arr.ar.numb) or 0) > 0 or arr.ar.incapTo)) or next(K.AR.condsOf(arr)) ~= nil) then\r\nlrLeft = lrLeft .. \", \" .. K.AR.text(arr, pc, c)\r\nend\r\n\r\nif K.AR.on() and u.side == \"enemy\" then\r\nlocal best = 0\r\nfor _, x in ipairs(st.attacks or {}) do if (tonumber(x.hit) or 0) > best then best = tonumber(x.hit) end end\r\nlrLeft = lrLeft .. string.format(\", its approaches %+d with an implement's own dice and no modifier, \", best) .. K.AR.apAC(st.ac, K.AR.inhib(u, pc))\r\nend\r\norder[#order + 1] = string.format(\"- %s: initiative %d, HP %d/%d%s%s\", name, u.init, hp, max, down, lrLeft)\r\n\r\nlocal kind = u.side == \"pc\" and \"Player\" or u.side == \"ally\" and name or u.kind\r\n\r\nlocal shownAs = (u.side == \"enemy\" or u.side == \"friend\") and name:match(\"^(.-) %d+$\")\r\nlocal label = (shownAs and shownAs ~= u.kind and K.MON_ALIAS[shownAs] == u.kind) and (shownAs .. \" (\" .. tostring(u.kind) .. \"'s stat block)\") or kind\r\nlocal polyK = u.side == \"enemy\" and K.polyLive(u, pc)\r\nif polyK then label = name .. \" as a \" .. polyK .. \" (Polymorph)\" end\r\nlocal beast = u.side == \"enemy\" or u.side == \"friend\"\r\nlocal seenKey = (u.side == \"friend\" and \"+\" or \"\") .. label\r\nif not seen[seenKey] then\r\nseen[seenKey] = true\r\n\r\n\r\n\r\nlocal saves = \"\"\r\nif beast and type(st.saves) == \"table\" then\r\nlocal sv = {}\r\nfor _, ab in ipairs(ABILS) do sv[#sv + 1] = string.format(\"%s %+d\", ab:sub(1, 3):upper(), st.saves[ab] or 0) end\r\nsaves = \". Saves: \" .. table.concat(sv, \", \")\r\nend\r\nlocal traits = beast and Feat.traitText(st) or \"\"\r\nif r then\r\nlocal res = Feat.resists(r)\r\nif #res > 0 then traits = \". Resists \" .. table.concat(res, \", \") end\r\nend\r\nlocal acts = \"\"\r\nlocal m = beast and MONSTERS[polyK or u.kind]\r\n\r\nif m and (m.multi or m.acts) then\r\nacts = (m.multi and (\". Multiattack: \" .. m.multi) or \"\")\r\nif m.acts then acts = acts:gsub(\"%.$\", \"\") .. \". Other actions: \" .. m.acts end\r\nend\r\n\r\nif m and m.auto and #m.auto > 0 then\r\nacts = acts:gsub(\"%.$\", \"\") .. \". On its own: \" .. table.concat(m.auto, \" \")\r\nselfActing = true\r\nend\r\n\r\n\r\nif m and m.sfx then\r\nlocal fx = {}\r\nfor _, e in ipairs(m.sfx) do fx[#fx + 1] = K.sfxText(e) end\r\nacts = acts:gsub(\"%.$\", \"\") .. \". Save effects: \" .. table.concat(fx, \"; \")\r\nend\r\nif m and m.la then\r\nacts = acts:gsub(\"%.$\", \"\") .. string.format(\". Legendary actions (%d a round, each right after another creature's turn, with the usual tags): %s\",\r\nm.la, table.concat(m.lacts or {}, \", \"))\r\nend\r\n\r\n\r\nif m then acts = acts:gsub(\"%.$\", \"\") .. K.selfText(m, u.kind) end\r\n\r\n\r\nfor _, e in ipairs((m and u.side == \"enemy\") and m.sfx or {}) do\r\nif e.n == \"Swallow\" and e.s then\r\nacts = acts:gsub(\"%.$\", \"\") .. string.format(\". Its own save to keep what it swallowed (the DC its stat block gives) is a HAZARD on it:\"\r\n.. \" [HAZARD|Name|Swallow|Constitution|d20|%+d|DC|success/failure|-|-|0]\", (type(st.saves) == \"table\" and st.saves.Constitution) or 0)\r\nbreak\r\nend\r\nend\r\nstats[#stats + 1] = string.format(\"- %s%s: AC %d, Speed %d ft. Attacks: %s%s%s%s\", label,\r\nu.side == \"enemy\" and \" (every one)\" or u.side == \"friend\" and \" (helper on Player's side, every one; Lua keeps its numbers as they are: a spell or feature on it is narrated only)\"\r\nor (u.side == \"ally\" and u.guest) and \" (helper on Player's side)\" or u.side == \"ally\" and \" (companion)\" or \"\",\r\nst.ac, st.speed, table.concat(atk, \"; \"), saves, traits, acts)\r\nend\r\nend\r\n\r\n\r\nlocal said = (c.showOpening and tostring(c.opening or \"\") or \"\") .. \"\\n\" .. tostring(userText or \"\")\r\nlocal okPlan, plan = pcall(Ally.plan, pc, c, said)\r\nif not okPlan then plan = nil end\r\n\r\nreturn \"[COMBAT STATUS] A fight is on.\" .. (c.underwater and (\" It is underwater (SRD): a melee weapon attack has Disadvantage unless\"\r\n\r\n.. \" it deals Piercing damage or the attacker has a Swim Speed; a ranged weapon attack misses beyond its normal range and has\"\r\n.. \" Disadvantage within it; everything has Resistance to Fire damage (Lua halves it).\") or \"\")\r\n.. (c.deadly and (\" It is a deadly fight (marked, above the High budget):\"\r\n\r\n.. \" Player's way out stays open; an enemy lets a Player who flees, surrenders or talks have a real chance, and the story shows that chance.\") or \"\")\r\n.. \" Initiative order, highest first:\\n\" .. table.concat(order, \"\\n\")\r\n\r\n\r\n\r\n.. (#lrNames > 0 and (\"\\nLegendary Resistance (\" .. table.concat(lrNames, \", \") .. \"): while it has a use left, a failed save becomes\"\r\n.. \" a success in two cases only. One: the spell or feature does more than damage (it has no damage, or its failure would also\"\r\n.. \" make it Blinded, Charmed, Deafened, Frightened, Grappled, Incapacitated, Paralyzed, Petrified, Poisoned, Prone, Restrained,\"\r\n.. \" Stunned or Unconscious, banish it or take its spells); a condition it is immune to does not count. Two: the failure's damage\"\r\n.. \" would drop it to 0 HP and a success's would not. Against damage alone the d20 stands. Write a turned save as a success\"\r\n.. \" with a success's damage (half, or none, as the effect says) and tell it so in the story; Lua spends the use.\") or \"\")\r\n.. \"\\nStats:\\n\" .. table.concat(stats, \"\\n\")\r\n.. K.meleeNote(c)\r\n.. \"\\nThis reply's turns, in this order: \" .. table.concat(turnList(c, pc), \", \")\r\n.. \". Then stop: Player's next turn is the user's. Skip anyone who drops to 0 HP on the way.\"\r\n\r\n.. (not K.upNow(pc) and \" Player cannot act now (down): play every turn in the list, whatever the user's message says.\"\r\nor c.showOpening and (\" When the fight broke out the user had said: \\\"\" .. c.opening .. \"\\\". If that was an action against the enemies\"\r\n.. \" (an attack, a spell, a breath, a shove), play it on Player's turn in this reply as declared, unless the user's message now asks\"\r\n\r\n.. \" for something else; a message that is not an action (\\\"go on\\\", \\\"계속\\\", \\\"제 차례까지 묘사\\\", a sigh) means go ahead with it.\"\r\n\r\n\r\n.. \" An enemy that comes before Player in this list noticed late but was quicker: tell it that way, and the declared action lands\"\r\n\r\n.. \" on Player's turn; if Player falls before that turn, the turn is skipped and the action is lost.\")\r\n\r\n\r\n\r\nor (\" If the user's message leaves Player's turn to you (empty or silent, \\\"*says nothing*\\\", \\\"...\\\", \\\"go on\\\", \\\"계속\\\", a sigh,\"\r\n.. \" an emote), play Player's turn as Player would act, in character, and go on with the list. A question or OOC talk alone\"\r\n.. \" gets its answer and no turns: Player's turn waits for the user's action.\"))\r\n\r\n\r\n.. \" Use these exact names, HP and AC (the AC as listed, which already counts the spells Lua tracks; cover only as the order list shows it).\"\r\n.. \" Lua applies the damage.\"\r\n.. (plan and (\"\\n\" .. plan) or \"\")\r\n\r\n.. \"\\nWhen the user's words, these facts and Lua's plans disagree: the facts (HP, what is in effect, uses left) are true;\"\r\n.. \" what Player and the companions try is the user's to say; Lua's plans fill in what nobody said. Asked for the impossible,\"\r\n.. \" keep the facts and do the nearest possible thing. Decide each turn once and do not revisit it.\"\r\n\r\n\r\n.. \" An enemy attacks the one named after it in the turn list (Lua's pick); if that one falls before the enemy's turn, it attacks\"\r\n\r\n.. \" another one standing, with the rest of a Multiattack too.\"\r\n\r\n\r\n\r\n\r\n.. (K.DEATH == \"srd\" and K.wipeText(c, pc) or \"\")\r\n\r\n.. \"\\nCover (there is no map): none unless a COVER tag set it; the order list then gives the numbers to write. When someone ducks\"\r\n.. \" behind something solid (a rock, a wall, a cart) or the scene puts them there, write [COVER|Name|half] (+2), or\"\r\n.. \" [COVER|Name|three-quarters] (+5) when only a narrow gap shows; [COVER|Name|-] when they leave it. It counts against ranged\"\r\n.. \" attacks and Dexterity saves only: a melee attacker has come round it.\"\r\n.. \" Total Cover (fully behind a wall): it cannot be targeted, and an area whose point of origin has no clear line to it misses it (no tag).\"\r\n.. \"\\nEvery attack is a tag on its own line: [ATTACK|Attacker|Target|d20|+hit|AC|hit|formula|dice|damage]\"\r\n\r\n.. \"\\n- AC: the target's Armor Class as listed above, never the roll's total.\"\r\n.. \"\\n- d20: the next d20 from the pool. With Advantage write \\\"adv A,B\\\", with Disadvantage \\\"dis A,B\\\" (two d20 from the pool; use the higher / lower).\"\r\n\r\n.. \" On its turn a creature has one action and at most one Bonus Action; one reaction a round (back at the start of its turn).\"\r\n.. \" Advantage and Disadvantage on the same roll cancel out, however many of each: one d20.\"\r\n.. \" Disadvantage: a ranged attack beyond its normal range (none beyond the long range), a ranged attack (spells too) with an enemy within 5 ft\"\r\n.. \" that sees the attacker and is not Incapacitated, an attack at a target the attacker cannot see. Advantage: an attack by one the target cannot see\"\r\n.. \" (hidden, Invisible, in darkness it has no Darkvision for). A Heavily Obscured place (darkness, thick fog) blinds sight into it.\"\r\n.. \" Dodge: until its next turn attacks at it by an attacker it can see have Disadvantage, and its Dexterity saves Advantage (gone if Incapacitated or at Speed 0).\"\r\n.. \" Hide (DC 15 Stealth, out of every enemy's sight, Heavily Obscured or behind Three-Quarters or Total Cover): hidden until it attacks, makes noise, casts a spell with a Verbal component or is found.\"\r\n.. \" Grappled: an action and an Athletics or Acrobatics check against the escape DC frees it; it ends by itself when the grappler is Incapacitated or they are pulled apart.\"\r\n.. \" A flyer knocked Prone, Incapacitated or at Speed 0 falls (not one that hovers): a HAZARD Fall N.\"\r\n.. \" Ready: its action names a trigger and what it does, used as its reaction before its next turn; a readied spell is cast at once (the CAST and slot then) and held with Concentration.\"\r\n.. \" A melee hit that drops a creature to 0 HP may knock it out instead (to take it alive): [KNOCKOUT|Name] right after that ATTACK.\"\r\n\r\n.. \"\\n- A natural 20 is \\\"crit\\\": double every die in the formula, added dice too (1d8+3 becomes 2d8+3, 1d6+2+1d4 becomes 2d6+2+2d4).\"\r\n.. \" A natural 1 is \\\"miss\\\". Otherwise hit if d20 + hit >= AC.\"\r\n.. \"\\n- formula: the attack's damage formula above. dice: the damage dice taken from the pools in order, comma-separated. damage: what lands:\"\r\n.. \" the dice plus the modifier, halved (round down) against a resistance, doubled against a vulnerability, 0 against an immunity,\"\r\n.. \" with any effect written next to the attack (Great Weapon Fighting, Uncanny Dodge). Keep track of HP with that number.\"\r\n.. \"\\n- On a miss: [ATTACK|Attacker|Target|d20|+hit|AC|miss|-|-|0]\"\r\n.. \"\\n- Examples: [ATTACK|Player|Goblin Warrior 1|14|+5|15|hit|1d8+3|6|9]  [ATTACK|Goblin Warrior 2|Player|adv 7,16|+4|16|hit|1d6+1d4+2|3,2|7]\"\r\n.. \"\\nWrite each attack tag once, at the moment it happens in the prose; never list a round's tags first and repeat them later.\"\r\n\r\n\r\n.. \" An attack roll whose total equals the target's AC hits (it needs to meet the AC, not beat it).\"\r\n.. \" Write every tag whole, then tell what its dice say: a hit is a hit even when it drops Player. Never leave a tag unfinished\"\r\n.. \" or turn its result into another to spare Player; Lua finishes an unfinished one by the dice anyway.\"\r\n.. \" Player falls only at 0 HP: subtract the damage from the HP above; while HP is above 0, Player is hurt but still fighting.\"\r\n\r\n\r\n.. ((K.DEATH == \"srd\" and not pc.dead and (pc.hp or 0) > 0)\r\n\r\n\r\nand string.format(\" Massive damage: a blow whose damage beyond Player's remaining HP is %d (Player's HP maximum) or more kills Player outright;\"\r\n.. \" now that is a blow of %d or more, and after each hit on Player in this reply it is that many fewer (at 1 HP: %d). Tell such a blow as Player's death.\",\r\npc.max, pc.hp + pc.max, 1 + pc.max) or \"\")\r\n.. \"\\nSpecial abilities not covered by the tags (Nimble Escape, Pack Tactics, knocking Prone) come from the monster's stat block in the lorebook\"\r\n.. \" and give Advantage only where it says so. Never invent an ability the stat block does not have, even if the monster's name suggests one.\"\r\n\r\n.. \" A Recharge X-Y action can be used, then again only after a d6 at the start of the monster's turn shows X-Y, or after a rest.\"\r\n\r\n\r\n.. \" A monster's Multiattack and other actions are listed above. A save Player or a companion makes against a creature's action or\"\r\n.. \" trait, and damage one deals with no attack roll, is [SAVE|Player or the companion's name|Ability|d20|+its save bonus|DC|success/failure|formula|dice|damage]\"\r\n.. \" with the numbers of \\\"Save effects\\\" above (no damage: - - 0; damage with no save, an aura or a burning body: - in the five save fields,\"\r\n.. \" e.g. [SAVE|Player|-|-|-|-|-|1d10|6|6]). For an area, roll the damage once and write the same dice for each one it catches;\"\r\n.. \" another creature's use of it rolls its own. Lua applies it.\"\r\n\r\n.. \" A condition a feature or one of Player's side puts on a creature without a HAZARD of its own: [COND|Target|+Condition|duration|the feature or who]\"\r\n.. \" (duration Nr rounds, +1m, turn = until the start of its user's next turn, dmg = damage ends it, - until [COND|Target|-Condition]); Lua keeps it, and refuses what one that\"\r\n.. \" cannot act does (a Charmed one's attack on its charmer too).\"\r\n.. \" An enemy's spell that changes the numbers of Player's side (Slow, Bane, Ray of Enfeeblement, Reduce): after the failed save [COND|Name|+Spell|duration|its caster] (Lua counts it).\"\r\n.. (selfActing and (\" \\\"On its own\\\" traits need no action: Lua does not play them, so play each one when it says (a creature starting its\"\r\n.. \" turn in the area, the monster's death): a SAVE as above for Player's side, [COND|+Condition|duration] for a condition, and for\"\r\n.. \" a creature's own Hit Points the tag its line names. Whether a creature stands or dies follows Lua's Hit Points alone.\") or \"\")\r\n.. (K.wearFight(c) and (\" Gear damage: when a creature's effect damages a nonmagical weapon or armor (a Rust Monster's Antennae after a\"\r\n.. \" failed Dexterity save, a weapon hitting an ooze, an ooze's Pseudopod hitting armor), write [WEAR|Item|-1] once per point\"\r\n.. \" (Name/Item for a companion's gear); Lua lowers its attack or AC and breaks it at the limit.\") or \"\")\r\n\r\n.. (hazards and (\"\\nImprovised effects (not a spell, not an attack): a thrown flask, burning oil, or the scene itself hurting enemies\"\r\n.. \" (a falling chandelier, a collapsing shelf, spreading flames): one [HAZARD|Target|what|Ability|d20|+save bonus|DC|success/failure|formula|dice|damage]\"\r\n.. \" per creature. what = Alchemist's Fire / Acid / Holy Water / Oil (Lua takes the flask from the pack, so no ITEM tag for it; Dexterity save DC \"\r\n.. (8 + MOD.Dexterity + PROF) .. \"; Oil does no damage but leaves the target covered in oil: write - - 0), Burning Oil (5 Fire, no save:\"\r\n.. \" write - in the five save fields, e.g. [HAZARD|Goblin Warrior 1|Burning Oil|-|-|-|-|-|5|-|5]), Burning (1d4 Fire at the start of its turn, no save),\"\r\n.. \" or minor/major + a damage type for the scene, e.g. major Bludgeoning (Lua sets it: minor DC \" .. TRAP.row(\"nuisance\", pc.level or 1)[1] .. \" \"\r\n.. TRAP.row(\"nuisance\", pc.level or 1)[2] .. \", major DC \" .. TRAP.row(\"deadly\", pc.level or 1)[1] .. \" \" .. TRAP.row(\"deadly\", pc.level or 1)[2]\r\n.. \", half on a success; you pick the save that fits). Shove (instead of one attack, a target no more than one size larger; the target saves with its better of Strength\"\r\n.. \" and Dexterity, DC \" .. K.shoveDC() .. \", no damage: on a failure pushed 5 feet or knocked Prone, then [COND|Target|+Prone|-|Shove]), Grapple (the same, a failure: Grappled,\"\r\n.. \" Lua keeps it; [COND|Target|-Grappled] when it escapes or is let go) and Fall N for a fall of N feet\"\r\n.. \" (1d6 Bludgeoning per 10 feet, up to 20d6, no save), so a shove off a ledge is Shove, then Fall 30.\"\r\n.. \" One damage roll per what per reply; which creatures are in the area is yours to narrate.\"\r\n.. \" Grease is nonflammable: it never burns.\")\r\nor (\"\\nImprovised effects (a thrown flask, a shove of a target no more than one size larger, a fall, the scene hurting enemies) are one\"\r\n.. \" [HAZARD|Target|what|Ability|d20|+save bonus|DC|success/failure|formula|dice|damage] per creature; Lua checks them.\"))\r\n\r\n\r\n.. \"\\nMoving and fleeing: the distance is the story's, but on its turn a creature moves at most its Speed (Dash doubles it and takes its action).\"\r\n.. \" A creature closes the gap only if it is faster, Dashes instead of attacking, or Player moved less: backing away at full Speed from an\"\r\n.. \" enemy just as fast that also attacks (a bow shot, say) keeps the distance. Leaving an enemy's reach without Disengage provokes its\"\r\n.. \" Opportunity Attack (an ATTACK tag right before leaving). A flight ends the fight only after breaking line of sight and a\"\r\n.. \" successful Hide (DC 15 Stealth), or when no enemy can or will follow for a reason the story set up before the flight;\"\r\n.. \" until then an enemy as fast or faster that pursues stays in the fight.\"\r\n\r\n\r\n.. \"\\nAn enemy drops only when the tags bring its HP to 0: as you write, take this reply's damage on it from its HP above;\"\r\n.. \" above 0 it is still fighting, however hurt. It leaves the fight alive only by surrender,\"\r\n.. \" escape or truce, and then write [COMBAT_END|reason], e.g. [COMBAT_END|hid], [COMBAT_END|enemies fled], [COMBAT_END|surrender].\"\r\n.. \" Without one of these, every enemy above is still fighting. Lua ends the fight when every enemy is at 0 HP.\"\r\n\r\n\r\n.. \"\\nTelling the fight: each blow is its own moment, as its tag came out. A hit lands as hard as its damage is against the target's\"\r\n.. \" HP (a nick, a deep cut, a blow that staggers); a miss is a parry, a dodge or armor turning it, a near thing when the roll came\"\r\n.. \" close; a crit is the clean, decisive strike; a Graze, the edge that still bites. Weapons with technical precision and tactile\"\r\n.. \" weight, not vague slashes: the guard or stance, footwork and distance\" .. (K.EN and \"\" or \" (간합)\") .. \", the edge's alignment and the exact path of each cut,\"\r\n.. \" thrust, bind and deflection; and the body behind it: weight carried up from the ground, the coiled tension in muscles and joints,\"\r\n.. \" the shock of impact running through the hilt into the palms, wrists and bones.\"\r\n\r\n.. \" Spells with the same precision and weight: how the caster shapes them (the gesture, the words, the focus, the strain of\"\r\n.. \" holding it), what they are made of (fire's heat and roar, cold that bites and stiffens, lightning's crack and the smell of ozone,\"\r\n.. \" a necrotic withering, radiant light that sears, force striking unseen, thunder's blow to the chest, psychic pressure behind the\"\r\n.. \" eyes) and what they do to each body they catch: a save made is a dive aside or a body braced through it, a failed one takes all\"\r\n.. \" of it; a healing spell, what knits shut and how it feels. Taking a hit, from inside the body that takes it: where it lands and\"\r\n.. \" how (a blunt blow's deep jolt, an edge's cold line and then the heat, a point's punch), the breath knocked out, the footing lost,\"\r\n.. \" armor or a shield taking part of it and the arm behind it going numb; a monster's blow carries its whole body (claws, jaws, bulk,\"\r\n.. \" reach, its stat block).\"\r\n\r\n.. \" Blood where a body has it: a cut wells and runs, a puncture seeps dark, a heavy blow brings it to the mouth, it slicks a grip\"\r\n.. \" and spatters the ground, more of it as the HP falls; a body without it shows the damage its own way (bone chipping, ichor,\"\r\n.. \" stone cracking, a form coming apart). Each companion fights in their own way (weapon, note). Wounds follow the HP: at half or less a body moves\"\r\n.. \" hurt, with a few left it reels, Player and the companions too while they fight on. Concrete detail over adjectives; vary the\"\r\n.. \" rhythm, no phrase twice in a reply, and the numbers stay in the tags.\"\r\n\r\n\r\n.. (K.DEATH == \"gentle\" and (\"\\nIf the last one standing on Player's side falls, the fight is lost and stops there: no more turns.\"\r\n\r\n.. \" Right after that tag write [COMBAT_END|party defeated]; then \" .. K.wipeGo(c, pc) .. \", then [TIME|+1h],\"\r\n.. \" after which Player and the companions come to with 1 HP (Lua sets it).\")\r\nor \"\")\r\n\r\n.. \"\\nNever play Player's turn after the list ends: that one is the user's.\"\r\nend\r\n\r\n\r\n\r\nlocal COMBAT_BEATS = {\r\n\"the enemy shows a habit or a technique of its own: let its move tell what kind of foe it is\",\r\n\"the ground or something nearby joins the fight\",\r\n\"one sense takes over the moment: a sound, a smell, the light or pain\",\r\n\"a brief stillness first, both sides measuring each other, then the move\",\r\n\"Player's body shows in the move: breath, legs, grip, as tired as Player is\",\r\n\"someone's footing or position changes what the next blow can do\",\r\n}\r\nK.SHORT_INPUT = 15\r\n\r\n\r\n\r\nlocal Pace = {}\r\nPace.STEPS = { { 8, 70 }, { 5, 45 }, { 3, 25 } }\r\nPace.CUE = {\r\nthreat = \"let a threat surface: a hostile sign, pressure from the surroundings, someone or something moving against Player\",\r\ngimmick = \"let a challenge surface: an obstacle, a hazard, a trap or a puzzle that asks Player to act (a trap goes off only through the TRAP tag)\",\r\nreward = \"let Player come across something worth having: coin, useful gear, information or someone's goodwill\",\r\n}\r\n\r\n\r\n\r\n\r\nPace.REST_WORDS = { \"쉬자\", \"쉬죠\", \"쉬어\", \"쉬고\", \"쉬며\", \"쉰다\", \"휴식\", \"잠을\", \"잠들\", \"잠자\", \"자자\", \"밤을 보내\", \"밤을 새\", \"야영\", \"눈을 붙\" }\r\nfunction Pace.restTalk(t)\r\nif type(t) ~= \"string\" then return false end\r\nlocal low = t:lower()\r\nfor _, w in ipairs(Pace.REST_WORDS) do if low:find(w, 1, true) then return true end end\r\nfor _, w in ipairs({ \"rest\", \"camp\", \"sleep\" }) do if low:find(\"%f[%a]\" .. w .. \"%f[%A]\") then return true end end\r\nreturn false\r\nend\r\n\r\nfunction Pace.cue(pc, nowTurn, cw)\r\nlocal pace = type(pc.pace) == \"table\" and pc.pace or {}\r\nlocal best, bestP\r\nfor _, k in ipairs({ \"threat\", \"gimmick\", \"reward\" }) do\r\nlocal since = nowTurn - (tonumber(pace[k]) or 0)\r\nlocal p = 0\r\nfor _, st in ipairs(Pace.STEPS) do\r\nif since >= st[1] then p = st[2]; break end\r\nend\r\nif k == \"reward\" and since < 6 then p = 0 end\r\n\r\nif k == \"threat\" and cw == \"low\" then p = 0 end\r\nif k == \"threat\" and cw == \"high\" then p = (since >= 2) and math.min(95, math.max(p, 25) * 2) or 0 end\r\nif p > 0 and (not bestP or p > bestP) then best, bestP = k, p end\r\nend\r\nif best and math.random(1, 100) <= bestP then\r\nreturn \"[PACING CUE] If the scene supports it, \" .. Pace.CUE[best]\r\n.. \". Only a nudge: skip it when it would feel forced, and never let it override what the user just did.\"\r\nend\r\nreturn nil\r\nend\r\n\r\nlocal function combatBeat()\r\n\r\nreturn \"[COMBAT BEAT] The user's message is short. Make this round vivid with one beat: \"\r\n.. COMBAT_BEATS[math.random(1, #COMBAT_BEATS)] .. \". The dice and tags stay exactly as they are.\"\r\nend\r\n\r\n\r\n\r\n\r\nK.En = {}\r\nfunction K.En.on(id) return getChatVar(id, \"dnd_lang\") == \"en\" end\r\nK.En.GREET = {\r\n{ \"변경 마을 '애시턴'의 선술집\", [[The tavern in Ashton, a village on the frontier, gets loud well before sundown. Its walls were built from stones pried out of the old kingdom's fallen ramparts, and half of someone's crest is still carved into them. Beside the door, a notice board bristles with job postings pinned one over another.\r\n\r\n\"Strange noises under the well. Need someone to look into it. 10 gold.\"\r\n\"Three sheep missing near the tower north of the ruins. Someone saw wolf tracks. Reward if found.\"\r\n\"Guide wanted. To the old royal road, three days out.\"\r\n\r\nIn a corner, a traveling peddler has spread out his bundle: two red potions, a vial of holy water, a bundle of arrows, a healer's kit with bandages and herbs. Next to the potions, a crooked hand has written \"50 gold a bottle.\"\r\n\r\nThe barkeep, wiping a mug, glances at your chain mail and the longsword at your hip. \"Army, were you? Folk like you are the most use around here. Drink first, or work first? Rooms are upstairs. Five silver a night.\"]] },\r\n{ \"해가 기울 무렵, 옛 왕국의 가도\", [[As the sun sinks, the old kingdom's highway runs on over the hill, missing a stone here and there. A broken milestone lies half sunk in the dirt by the roadside, the name of the royal city carved on it lost under moss.\r\n\r\nOver the hill, a valley opens below. A fresh palisade has been driven into one side of a crumbled wall, and a few lines of supper smoke rise from inside it. This is Ashton, a settlement on the frontier. On the ridge north of the wall, a lone tower juts up like a broken tooth.\r\n\r\nAn old porter resting on a stump beside the milestone shifts the pack on his back and looks up. The backs of his hands are cracked and there is dust in the lines around his eyes.\r\n\r\n\"If you're bound for Ashton, walk with me. This road's not so safe once the sun's down.\" He points his staff toward the village. \"They say there's more work there than hands lately. Noises under the well, sheep gone missing near the tower. Sword or book, they'll take anyone, by the sound of it.\"\r\n\r\nHalfway into his first step, the porter stops and looks you up and down.\r\n\r\n\"So, what do you do for a living?\"]] },\r\n{ \"모험을 시작하기 전에, 잠깐 테이블에\", [[Before the adventure begins, take a seat at the table for a moment.\r\n\r\nThis game runs on the fifth-edition rules, 2024 revision. Lua counts the dice and the numbers; I will tell you about the world, the people in it, and what your choices bring about.\r\n\r\nFirst we settle on your character. Pick a species, class and background under character creation below, or just tell me about the character you would like to play. One line is enough, like \"an elf wizard who works with fire.\"\r\n\r\nThen we settle on the first scene.\r\n- Tell me in one line where you would like to begin. The back alleys of a port city, a lodge in a snowstorm, the gate of a fallen fortress, anywhere at all.\r\n- If you added an adventure module, just say \"start with the module\" and we will begin at its first scene.\r\n- If you leave it open, I will open the story somewhere that suits your character.\r\n\r\nSo, who are you?]] },\r\n}\r\n\r\nfunction K.En.greeting(text)\r\nfor _, g in ipairs(K.En.GREET) do\r\nif (text or \"\"):find(g[1], 1, true) then\r\nlocal mark = text:match(\"^%s*(※※C?\\n?)\") or \"\"\r\nif K.LITE then\r\nreturn mark .. (g[2]:gsub(\"This game runs on the fifth%-edition rules, 2024 revision%.\", \"This is a fantasy tabletop RPG run on dice and ability scores.\")\r\n:gsub(\"an elf wizard\", \"an elf mage\"))\r\nend\r\nreturn mark .. g[2]\r\nend\r\nend\r\nreturn nil\r\nend\r\nfunction K.En.hangul(s) return (s or \"\"):find(\"[\\234-\\237][\\128-\\191][\\128-\\191]\") ~= nil end\r\n\r\nK.En.SWAP = {\r\n\r\n{ \"던전 앤 다이스\", \"Dungeon and Dice\" }, { \" 성인 DLC\", \" adult DLC\" }, { \" (개인용)\", \" (private)\" },\r\n\r\n{ \"You are the Game Master of 다이스 앤 소드,\", \"You are the Game Master of Dice and Sword,\" },\r\n{ \" In the prose, classes, species and features go by the Korean names of the term list (전사, 마법사, 마족, 수인), never the usual D&D ones (파이터, 위저드, 티플링).\",\r\n\" In the prose keep to plain fantasy words: no D&D names of places, planes or gods.\" },\r\n{ \"Write the narration in Korean prose with plain endings (~했다, ~이다); NPCs speak however suits them. The formal ~습니다/~십시오 endings belong\",\r\n\"Write the narration in English prose; NPCs speak however suits them. A polite, formal GM voice belongs\" },\r\n{ \"do not carry them into the narration\", \"do not carry it into the narration\" },\r\n{ \" in the formal ~습니다 endings\", \" in a polite, formal voice\" },\r\n{ \"(formal ~습니다)\", \"(polite, formal)\" },\r\n{ \"OOC, (OOC) or 사담, or\", \"OOC or (OOC), or\" },\r\n{ \"(spells, a feat, gear), \\\"~정하자\\\".\", \"(spells, a feat, gear).\" },\r\n{ \"[QUEST|+끊긴 짐마차 찾기|상인 조합장|가도에서 소식이 끊긴 짐마차의 행방을 찾는다|city|Grassland]\",\r\n\"[QUEST|+The Missing Wagon|Merchant guildmaster|Find out what became of a wagon lost on the highway|city|Grassland]\" },\r\n{ \"[LOOT|서리 맺힌 롱소드|B|Longsword|칼날에 늘 서리가 낀다]\", \"[LOOT|Frost-Rimed Longsword|B|Longsword|Frost always clings to the blade]\" },\r\n{ \"[LOOT|뱀 문양 청동 열쇠|C|-|시체 품에서 나온 정교한 열쇠]\", \"[LOOT|Bronze Serpent Key|C|-|A finely made key found on the body]\" },\r\n\r\n{ \"[BACKGROUND|등대지기|\", \"[BACKGROUND|Lighthouse Keeper|\" },\r\n{ \"[GM|숏소드는 맞히면 다음 공격이 쉬워집니다. 행동 연쇄도 아직 남아 있습니다.]\",\r\n\"[GM|A Shortsword hit makes your next attack easier. You still have Action Surge left.]\" },\r\n{ \"Party setting: 혼자 (no companions).\", \"Party setting: alone (no companions).\" },\r\n{ \"\\\"지금은 동료 없이 하는 설정입니다. 동료를 들이려면 동료 탭에서 파티 최대 인원을 올려 주십시오.\\\"\",\r\n\"\\\"This game is set to play without companions. To take one on, raise the party size on the companions tab.\\\"\" },\r\n}\r\n\r\nK.En.PSWAP = {\r\n{ \"\\\"파티가 가득 찼습니다%(동료 (%d+)명%)%.[^\\\"]*\\\"\",\r\n\"\\\"The party is full (%1 companions). To take on someone new, send one away on the companions tab or raise the party size.\\\"\" },\r\n}\r\nfunction K.En.replace(s, from, to)\r\nlocal out, i = {}, 1\r\nwhile true do\r\nlocal a, b = s:find(from, i, true)\r\nif not a then break end\r\nout[#out + 1] = s:sub(i, a - 1) .. to\r\ni = b + 1\r\nend\r\nout[#out + 1] = s:sub(i)\r\nreturn table.concat(out)\r\nend\r\nfunction K.En.strip(s)\r\nif type(s) ~= \"string\" or not K.En.hangul(s) and not s:find(\"Korean\", 1, true) then return s end\r\n\r\nif K.AR and K.AR.WORDS then s = K.En.replace(K.En.replace(s, K.AR.WORDS .. \" \", \"\"), K.AR.WORDS, \"\") end\r\nfor _, p in ipairs(K.En.SWAP) do s = K.En.replace(s, p[1], p[2]) end\r\nfor _, p in ipairs(K.En.PSWAP) do s = s:gsub(p[1], p[2]) end\r\n\r\ns = s:gsub(\"## Korean names %(한글 용어 대조표%).-\\n%- Feats:[^\\n]*\", \"\")\r\n\r\ns = s:gsub(\"%s?%(([^()\\n]*)%)\", function(inner) if K.En.hangul(inner) then return \"\" end end)\r\n\r\ns = s:gsub(\" = [^\\n]- in prose\", function(m) if K.En.hangul(m) then return \"\" end end)\r\n\r\n\r\ns = s:gsub(\"([%a%)'])( [\\234-\\237][^;|,%.:%)\\n%[%]]*)\", function(pre, ko)\r\nif ko:find(\"%a\") then return nil end\r\nreturn pre\r\nend)\r\ns = s:gsub(\"Korean\", \"English\")\r\nreturn s\r\nend\r\n\r\n\r\n\r\n\r\n\r\nK.REF_MAX = { mon = 5, spell = 5, item = 3 }\r\nK.REF_CAP = 12000\r\nfunction K.loreBody(id, comment)\r\nlocal ok, found = pcall(getLoreBooks, id, comment)\r\nif not ok or type(found) ~= \"table\" then return nil end\r\nfor _, e in ipairs(found) do\r\nlocal s = type(e) == \"table\" and tostring(e.content or \"\") or \"\"\r\nif s ~= \"\" then return s end\r\nend\r\nreturn nil\r\nend\r\nfunction K.refNames(c, userText, lastReply, planned)\r\nlocal mons, mSeen, spells, sSeen = {}, {}, {}, {}\r\nlocal function addM(n)\r\nn = trim((n or \"\"):gsub(\"%s*%b()\", \"\"):gsub(\"%s+%d+%s*$\", \"\"))\r\nif MONSTERS[n] and not mSeen[n] and #mons < K.REF_MAX.mon then mSeen[n] = true; mons[#mons + 1] = n end\r\nend\r\nlocal function addS(n)\r\nn = trim(n or \"\")\r\nif SPELLS[n] and not sSeen[n] and #spells < K.REF_MAX.spell then sSeen[n] = true; spells[#spells + 1] = n end\r\nend\r\nif c.active then\r\nlocal kinds = {}\r\nfor _, u in pairs(type(c.units) == \"table\" and c.units or {}) do\r\nif type(u) == \"table\" and u.kind and (tonumber(u.hp) or 1) > 0 then kinds[#kinds + 1] = u.kind end\r\nend\r\ntable.sort(kinds)\r\nfor _, k in ipairs(kinds) do addM(k) end\r\nend\r\n\r\n\r\nif not c.active then\r\nfor _, n in ipairs(type(planned) == \"table\" and planned or {}) do addM(n) end\r\nend\r\nlocal texts = { userText or \"\", lastReply or \"\" }\r\nfor _, s in ipairs(texts) do\r\nfor n in s:gmatch(\"%[CAST|([^|%]]+)\") do addS(n) end\r\nfor f in s:gmatch(\"|([^|%]%[\\n]+)\") do addM(f) end\r\nfor f in s:gmatch(\"\\226\\150\\182%s*([^|%]%[\\n(]+)\") do addM(f) end\r\nend\r\n\r\nlocal names = {}\r\nfor n in pairs(SPELLS) do if NAMES_KO[n] then names[#names + 1] = n end end\r\ntable.sort(names)\r\nfor _, n in ipairs(names) do\r\nif #spells >= K.REF_MAX.spell then break end\r\nlocal ko = NAMES_KO[n]\r\nlocal syl = select(2, ko:gsub(\"[\\234-\\237][\\128-\\191][\\128-\\191]\", \"\"))\r\nfor _, s in ipairs(texts) do\r\nif not sSeen[n] and ((syl > 2 and ko ~= \"거미줄\" and s:find(ko, 1, true))\r\nor s:find(ko .. \" 주문\", 1, true) or s:find(ko .. \"을 시전\", 1, true) or s:find(ko .. \"를 시전\", 1, true)\r\nor s:find(ko .. \" 시전\", 1, true)) then\r\naddS(n)\r\nend\r\nend\r\nend\r\n\r\nlocal items, iSeen = {}, {}\r\nlocal low = (userText or \"\"):lower() .. \"\\n\" .. (lastReply or \"\"):lower()\r\nfor _, kv in ipairs(K.MAGIC_KEYS or {}) do\r\nif #items >= K.REF_MAX.item then break end\r\nif not iSeen[kv[2]] and low:find(kv[1]:lower(), 1, true) then iSeen[kv[2]] = true; items[#items + 1] = kv[2] end\r\nend\r\nreturn mons, spells, items\r\nend\r\n\r\n\r\nK.LORE_MAX, K.LORE_CAP = 8, 9000\r\nfunction K.loreNames(userText, lastReply)\r\nlocal hay = (((userText or \"\") .. \"\\n\" .. (lastReply or \"\")):lower():gsub(\"%s\", \"\"))\r\nlocal out = {}\r\nfor _, e in ipairs(K.LORE_KEYS or {}) do\r\nif #out >= K.LORE_MAX then break end\r\nfor _, k in ipairs(e[2] or {}) do\r\nlocal kk = (k:lower():gsub(\"%s\", \"\"))\r\nif kk ~= \"\" and hay:find(kk, 1, true) then out[#out + 1] = e[1]; break end\r\nend\r\nend\r\nreturn out\r\nend\r\n\r\nfunction K.refText(id, c, userText, lastReply, planned)\r\nlocal mons, spells, items = K.refNames(c, userText, lastReply, planned)\r\nlocal parts = {}\r\nfor _, n in ipairs(mons) do\r\nlocal b = K.loreBody(id, \"몬스터: \" .. n)\r\nif b then parts[#parts + 1] = b end\r\nend\r\nfor _, n in ipairs(spells) do\r\nlocal b = K.loreBody(id, \"주문: \" .. n)\r\nif b then parts[#parts + 1] = b end\r\nend\r\nfor _, n in ipairs(items) do\r\nlocal b = K.loreBody(id, \"마법 물건: \" .. n)\r\nif b then parts[#parts + 1] = b end\r\nend\r\n\r\nlocal kept, size = {}, 0\r\nfor i, s in ipairs(parts) do\r\nif i > 1 and size + #s > K.REF_CAP then break end\r\nkept[#kept + 1] = s\r\nsize = size + #s\r\nend\r\nparts = kept\r\n\r\nlocal lsize = 0\r\nfor _, cm in ipairs(K.loreNames(userText, lastReply)) do\r\nlocal b = K.loreBody(id, cm)\r\nif b and lsize + #b <= K.LORE_CAP then parts[#parts + 1] = b; lsize = lsize + #b end\r\nend\r\nif #parts == 0 then return nil end\r\nreturn \"[REFERENCE] Rules text of what is in play (stat blocks, spells, magic items, and the species, classes, backgrounds and\"\r\n.. \" places the last messages name); where a number differs from Lua's above, Lua's wins.\\n\\n\" .. table.concat(parts, \"\\n\\n\")\r\nend\r\n\r\n\r\nfunction K.En.request(messages, text)\r\nfor _, m in ipairs(messages) do\r\nfor _, field in ipairs({ \"content\", \"data\" }) do\r\nlocal v = m[field]\r\nif type(v) == \"string\" then\r\nif m.role == \"system\" then\r\nm[field] = K.En.strip(v)\r\nelseif (m.role == \"assistant\" or m.role == \"char\") and K.En.hangul(v) then\r\nm[field] = K.En.greeting(v) or v\r\nend\r\nend\r\nend\r\nend\r\nreturn K.En.strip(text)\r\nend\r\n\r\n\r\n\r\n\r\nfunction K.chatAsHist(v)\r\nv = tostring(v or \"\")\r\nif v:find(\"|ok|\", 1, true) or v:find(\"|bad:\", 1, true) or v:find(\"|auto|\", 1, true) then v = K.histTags(v) end\r\nreturn (v:gsub(\"※※C?\\n?\", \"\"):gsub(\"\\n?%[OPT|[^%]]*%]\", \"\"):gsub(\"\\n?%[GM|[^%]]*%]\", \"\"):gsub(\"\\n?%[STATUS|[^%]]*%]\", \"\")\r\n:gsub(\"\\n?%[HP|[^%]]*%]\", \"\"):gsub(\"\\n?%[XP|[^%]|]*|[^%]|]*|auto|[^%]]*%]\", \"\"):gsub(\"\\n?<!%-%-dseed:%w+%-%->\", \"\")\r\n:gsub(\"\\n?%[ROUND|[^%]]*%]\", \"\"))\r\nend\r\nlistenEdit(\"editRequest\", function(id, messages, meta)\r\nlocal t0 = clockNow()\r\nK.seedNow(id, \"request\")\r\nK.CHK_D, K.FIGHT_D = K.checkD(id), K.fightD(id)\r\n\r\n\r\nsetChatVar(id, \"dnd_lua_error\", \"\")\r\nK.EN = K.LITE and K.En.on(id) or nil\r\npcall(K.packs, id, K.packFreshAtSend(id))\r\npcall(K.packFpSave, id)\r\nlocal packBad = {}\r\nfor _, x in ipairs(K.PACK.list or {}) do if not x.ok then packBad[#packBad + 1] = tostring(x.name) .. \": \" .. tostring(x.err or \"?\") end end\r\nif #packBad > 0 then setChatVar(id, \"dnd_lua_error\", \"모듈 팩을 읽지 못함: \" .. table.concat(packBad, \" / \")) end\r\nlocal missCl = K.missingFresh(id)\r\nK.LOCKED = missCl and true or nil\r\nlocal oka, erra = pcall(K.atSend, id)\r\nif not oka then setChatVar(id, \"dnd_lua_error\", \"send: \" .. tostring(erra)) end\r\n\r\n\r\nif missCl then\r\ntable.insert(messages, #messages, { role = \"user\", content = \"Lua cannot load \" .. K.missEn(missCl) .. \" (its module is not loaded),\"\r\n.. \" so Lua is not tracking the character until the module is back. Tell the story only, with no tags.\" })\r\nK.CharCode.strip(messages)\r\nreturn messages\r\nend\r\nlocal pools = getState(id, \"dnd_pool\")\r\nif type(pools) ~= \"table\" or type(pools.d20) ~= \"table\" then return messages end\r\n\r\n\r\nlocal lines = { \"[DICE POOL for this reply] Pre-rolled results. Spend each kind strictly in order, starting from the first. Never skip, reuse or invent a number.\"\r\n.. \" A formula with two kinds takes each kind from its own line: 1d8+4+2d6 is the next d8 from the d8 line, then the next two from the d6 line.\"\r\n\r\n\r\n.. \" A check, attack or save succeeds or fails by its die against the DC: take the die before planning or noting how it turns out;\"\r\n.. \" where other instructions say the world's conditions decide results, these dice are part of those conditions.\" }\r\nfor _, k in ipairs(K.POOL_ORDER) do\r\nlines[#lines + 1] = k .. \": \" .. table.concat(pools[k], \", \")\r\nend\r\nlines[#lines + 1] = \"If a kind runs out, end the reply before using it again.\"\r\nlocal userText, prevText = \"\", \"\"\r\n\r\n\r\n\r\n\r\nlocal uAt\r\nlocal nC = getChatLength(id) - 1\r\nlocal mU = getChat(id, nC)\r\nif mU and mU.role == \"user\" then userText, uAt = tostring(mU.data or \"\"), nC end\r\nif uAt then\r\nfor k = uAt - 1, math.max(0, uAt - 4), -1 do\r\nlocal m = getChat(id, k)\r\nif m and m.role == \"char\" and not Shop.isLine(m) then prevText = K.chatAsHist(m.data); break end\r\nend\r\nend\r\nfor i = #messages, 1, -1 do\r\nif uAt then break end\r\nif messages[i].role == \"user\" then\r\nuserText = tostring(messages[i].content or messages[i].data or \"\")\r\n\r\nfor j = i - 1, 1, -1 do\r\nif messages[j].role == \"assistant\" or messages[j].role == \"char\" then\r\nprevText = tostring(messages[j].content or messages[j].data or \"\")\r\nbreak\r\nend\r\nend\r\nbreak\r\nend\r\nend\r\nif prevText == \"\" then\r\n\r\nlocal n = getChatLength(id) - 1\r\nfor k = n, math.max(0, n - 3), -1 do\r\nlocal m = getChat(id, k)\r\nif m and m.role == \"char\" then prevText = tostring(m.data or \"\"); break end\r\nend\r\nend\r\nlocal sh = loadSheet(id)\r\napplySheet(sh)\r\nlocal pc = loadPC(id)\r\nCond.cur = pc\r\nK.DEATH = Feat.deathRule(id)\r\nFeat.gentleFix(pc)\r\nFeat.downFix(pc)\r\nK.partyFx(pc, sh)\r\nK.REPLY = getChatLength(id)\r\n\r\n\r\n\r\n\r\nlocal lastReply = uAt and prevText or \"\"\r\nfor i = #messages, 1, -1 do\r\nif uAt then break end\r\nif messages[i].role == \"assistant\" or messages[i].role == \"char\" then\r\nlastReply = tostring(messages[i].content or messages[i].data or \"\")\r\nbreak\r\nend\r\nend\r\nlocal guide = getChatLength(id) <= 2 or K.creationTalk(userText)\r\nor (sh.default and (getChatLength(id) <= 20 or K.creationTalk(lastReply)))\r\nlocal formSt, formNote\r\nif K.Form.fields(userText) then formSt, formNote = tostring(getChatVar(id, \"dnd_form\") or \"\"):match(\"^(%a*)|(.*)$\") end\r\nif formSt == \"ok\" then guide = false end\r\nlocal codeSt, codeNote\r\nif K.CharCode.find(userText) then codeSt, codeNote = tostring(getChatVar(id, \"dnd_charcode\") or \"\"):match(\"^(%a*)|(.*)$\") end\r\nif codeSt == \"ok\" then guide = false end\r\n\r\nlocal cgLine\r\nif sh.default and K.Cg then\r\nlocal cg = K.Cg.load(id)\r\nif cg.bgx and not cg.done then\r\nguide = true\r\nlocal rolled = getState(id, \"dnd_rolled\")\r\ncgLine = \"[CHARACTER BUILDER] The user picked on the greeting's buttons: species \" .. (cg.sp or \"(not picked: ask)\") .. \", class \" .. (cg.cl or \"(not picked: ask)\")\r\n.. \", scores \" .. ((cg.ab == \"roll\" and type(rolled) == \"table\") and (\"roll, already rolled \" .. table.concat(rolled, \",\") .. \" (no ROLL_STATS; place them for the class)\")\r\nor \"standard (placed for the class)\")\r\n.. \", skills \" .. (#cg.sk > 0 and table.concat(cg.sk, \", \") or \"(not picked: choose for the class)\")\r\n.. \", equipment \" .. (cg.eq or \"the one that fits\") .. \", level \" .. tostring(cg.lv or 1)\r\n.. \". The background is the one this message describes: make it ([BACKGROUND|…], its two skills not among the picked ones; what the user did not say, choose to fit),\"\r\n.. \" then write the PC tag with the picks in this same reply.\"\r\nend\r\nend\r\nlocal c, clock = loadCombat(id), loadClock(id)\r\nK.roundNow, K.fightNow, K.curC = tonumber(c.round) or 1, c.active, c\r\nK.curPc = pc or K.curPc\r\nK.wakeCap(pc, c, clock.min)\r\n\r\n\r\nlocal cg = not pc.dead and K.checkGuide(K.checkD(id), Feat.deathRule(id)) or nil\r\nif cg then table.insert(lines, 2, cg) end\r\nlocal text = table.concat(lines, \"\\n\") .. \"\\n\\n\" .. sheetText(sh, guide) .. \"\\n\" .. stateText(pc, clock, c.active, c)\r\nlocal modNames = not K.En.on(id) and K.modNamesLine(pc, c) or nil\r\nif modNames then text = text .. \"\\n\" .. modNames end\r\nif cgLine then text = text .. \"\\n\\n\" .. cgLine end\r\nif formSt == \"ok\" then\r\ntext = text .. \"\\n\\n[SHEET FORM] The user filled in the character sheet form and Lua created the character (\" .. formNote\r\n.. \", the sheet above). Do not write a PC tag. Confirm it in one or two Korean OOC sentences, mention picks left on the\"\r\n.. \" character tab if the GAME STATE lists any, then start or continue the scene.\"\r\nelseif formSt == \"bad\" then\r\ntext = text .. \"\\n\\n[SHEET FORM] The user's character sheet form could not be used: \" .. formNote\r\n.. \". Reply only out of character, in Korean: say briefly what to fix in the form and offer help. No story this turn, no PC tag.\"\r\nend\r\nif codeSt == \"ok\" then\r\ntext = text .. \"\\n\\n[CHARACTER CODE] The user brought their character from another adventure and Lua loaded it (\" .. codeNote\r\n.. \", the sheet above: its items, money, XP and companions, rested). Do not write a PC tag or any tag that gives items, money or XP for it.\"\r\n.. \" Welcome the returning character in one or two Korean OOC sentences, then begin the new adventure's opening scene.\"\r\nelseif codeSt == \"bad\" then\r\ntext = text .. \"\\n\\n[CHARACTER CODE] The user's character code could not be loaded: \" .. codeNote\r\n.. \". Reply only out of character, in Korean: say that in one or two sentences. No story this turn, no tags.\"\r\nend\r\nlocal spells = Spell.text(pc, c.active)\r\nif spells then text = text .. \"\\n\" .. spells end\r\n\r\n\r\nif not sh.default and not c.active then\r\nlocal talk = K.spellTalk(userText) or K.spellTalk(lastReply) or K.pickTalk(userText)\r\nfor _, v in ipairs(K.casterViews(sh)) do\r\nlocal vr = K.rowOf(sh, v.class)\r\nlocal none = #(v.spells or {}) == 0 and #(v.cantrips or {}) == 0\r\nlocal open = #(v.spells or {}) < (vr.prepared or 0) or Spell.cantripsOpen(v, vr) > 0\r\nif none or (talk and (Spell.win(pc, sh, v.class) or open)) then text = text .. \"\\n\" .. Spell.prepText(v) end\r\nend\r\nend\r\nif K.subTalk(userText) or K.subTalk(lastReply) then\r\nlocal sl = K.subListText(sh, userText)\r\nif sl then text = text .. \"\\n\" .. sl end\r\nend\r\n\r\n\r\n\r\nif Feat.miOpen(sh) and (K.miTalk(userText) or K.miTalk(lastReply) or K.pickTalk(userText) or K.spellTalk(userText)) then\r\ntext = text .. \"\\n[Magic Initiate] Still open: its two cantrips and one level 1 spell, apart from the class's own spells:\"\r\n.. \" [INITIATE|cantrip, cantrip|level 1 spell], not a SPELLS tag (the status card's taps do not choose them either). \"\r\n.. Spell.choiceText(Feat.miList(sh), sh)\r\nend\r\nif not c.active and K.pickTalk(userText) then\r\nlocal adv = K.pickAdvice(sh, pc)\r\nif adv then text = text .. \"\\n\" .. adv end\r\nend\r\nlocal shop = Shop.text(pc)\r\nif shop then\r\n\r\nlocal said = Shop.isLine(getChat(id, -1)) or Shop.isLine(getChat(id, -2))\r\ntext = text .. \"\\n\\n\" .. shop .. (said and \" The user's message \\\"(\" .. (K.En.on(id) and \"To the merchant: …\" or \"상인에게 …\") .. \")\\\" states these trades as Player's action in the story; it is not out-of-character talk.\" or \"\")\r\nend\r\n\r\nlocal partyCue = math.floor((getChatLength(id) + 1) / 2) % 4 == 0\r\nlocal party = Ally.text(pc, c.active, tonumber(getChatVar(id, \"dnd_party_want\")) or Ally.MAX, userText, partyCue, prevText)\r\nif party then text = text .. \"\\n\\n\" .. party end\r\n\r\nlocal goingAll, going, tags = Ally.leaving(id), {}, {}\r\nfor _, nm in ipairs(goingAll) do\r\nif Ally.find(pc, nm) and not Ally.isGuest(pc, nm) then going[#going + 1] = nm; tags[#tags + 1] = \"[ALLY|-\" .. nm .. \"|short Korean reason]\" end\r\nend\r\nif #going ~= #goingAll then setChatVar(id, \"dnd_party_leave\", table.concat(going, \"|\")) end\r\nif #going > 0 and not c.active then\r\ntext = text .. \"\\n[PARTY LEAVE] The user has decided to part ways with \" .. table.concat(going, \" and \") .. \". In this reply write a natural farewell that fits the story\"\r\n.. \" and \" .. table.concat(tags, \" \") .. \".\"\r\nend\r\nif c.active then\r\n\r\n\r\n\r\nif K.foeTargets(c, pc) then setState(id, \"dnd_combat\", c) end\r\nc.showOpening = c.opening ~= nil and c.openingAt == getChatLength(id) - 2\r\nK.ALLY_STYLE = getChatVar(id, \"dnd_ally_style\")\r\ntext = text .. \"\\n\\n\" .. combatText(c, pc, K.hazardWanted(pc, userText, lastReply), userText)\r\nelse\r\nlocal ct = K.craftText(pc, userText)\r\nif ct then text = text .. \"\\n\\n\" .. ct end\r\nend\r\nlocal et = K.envText(userText)\r\nif et then text = text .. \"\\n\\n\" .. et end\r\n\r\nlocal fix = K.Fix.request(lastReply)\r\nif fix then text = text .. \"\\n\\n\" .. fix end\r\nlocal pcBad = sh.default and K.pcRefused(lastReply)\r\nif pcBad then text = text .. \"\\n\\n\" .. pcBad end\r\n\r\nlocal um0, prev0 = getChat(id, -1), getChat(id, -2)\r\nif Shop.isLine(prev0) then prev0 = getChat(id, -3) end\r\nlocal pick = um0 and um0.role == \"user\" and prev0 and prev0.role ~= \"user\" and K.optPick(um0.data, prev0.data)\r\nif pick and K.optLocks(pick) then\r\ntext = text .. \"\\n\\n[OPTION PICKED] The user chose \\\"\" .. pick.label .. \"\\\" from the last reply's options: its check is \"\r\n.. pick.kind .. \" against DC \" .. pick.dc .. \", as offered. The dice in the pool do not change that DC (Lua holds it).\"\r\nelseif not pick and um0 and um0.role == \"user\" and prev0 and prev0.role ~= \"user\" then\r\n\r\n\r\nlocal offered = {}\r\nfor _, o in ipairs(K.optList(prev0.data)) do\r\nif K.optLocks(o) then offered[#offered + 1] = string.format(\"\\\"%s\\\" %s DC %d\", o.label, o.kind, o.dc) end\r\nend\r\nif #offered > 0 then\r\ntext = text .. \"\\n\\n[LAST OPTIONS] The last reply offered these checks: \" .. table.concat(offered, \"; \")\r\n.. \". If the user's message does one of them in other words, that check and DC hold.\"\r\nend\r\nend\r\nlocal lk = K.luckText(pc)\r\nif lk then text = text .. \"\\n\" .. lk end\r\n\r\nfor _, key in ipairs({ \"bless\", \"guidance\" }) do\r\nlocal b = K.D4_BUFF[key]\r\nlocal by, potion = K.buffBy(b.spell, pc)\r\n\r\nif not by and key == \"guidance\" and K.partyKnows and K.partyKnows(pc, \"Guidance\") then\r\ntext = text .. \"\\nGuidance cast in this reply before a check: write that check's d20 field as \\\"14 guidance 3\\\" (3 the next d4); Lua adds Lua's own d4 when it is left out.\"\r\nend\r\nif by then\r\ntext = text .. \"\\n\" .. string.format(\"%s is on (%s): %s add%s 1d4 to %s. Write the d20 field with\"\r\n.. \" \\\"%s N\\\" after it, N the next d4 from the pool, e.g. \\\"14 %s 3\\\" or \\\"adv 14,6 %s 3\\\"; the total adds N, the d20 alone\"\r\n.. \" decides a natural 20 or 1.\", b.spell, potion and (potion .. \", no Concentration\") or (by .. \" concentrates\"),\r\npotion and by or \"the creatures it was cast on\", potion and \"s\" or \"\", b.what, key, key, key)\r\nend\r\nend\r\n\r\n\r\nlocal jobs = Quest.text(pc, not c.active and prev0 ~= nil and prev0.role ~= \"user\"\r\nand tostring(prev0.data or \"\"):find(\"· 전투 종료\", 1, true) ~= nil)\r\nif jobs then text = text .. \"\\n\\n\" .. jobs end\r\n\r\nif not c.active and not (jobs and jobs:find(\"for example\", 1, true)) and K.combatW(id) ~= \"low\" then\r\nlocal rf = K.readyFoes(pc, loadClock(id), tonumber(getChatVar(id, \"dnd_shop_salt\")))\r\nif rf then text = text .. \"\\n\" .. rf end\r\nend\r\nlocal okr, ref = pcall(K.refText, id, c, userText, lastReply ~= \"\" and lastReply or prevText, K.planLive(pc, clock))\r\nif okr and ref then text = text .. \"\\n\\n\" .. ref elseif not okr then setChatVar(id, \"dnd_lua_error\", \"ref: \" .. tostring(ref)) end\r\ntext = text .. \"\\n\\n\" .. familiarityText(familiarity(id), K.suggestOn(id))\r\nif familiarity(id) == \"1\" then\r\nlocal okg, g = pcall(K.gmFacts, pc, c)\r\nif okg and g then text = text .. \"\\n\" .. g elseif not okg then setChatVar(id, \"dnd_lua_error\", \"gm: \" .. tostring(g)) end\r\nend\r\n\r\n\r\nlocal ooc = \"0\"\r\nsetChatVarChanged(id, \"dnd_ooc\", ooc)\r\nlocal trimmed = userText:gsub(\"^%s+\", \"\"):gsub(\"%s+$\", \"\")\r\nif c.active and ooc == \"0\" and trimmed ~= \"\" and trimmed:sub(1, 1) ~= \"/\" and (utf8.len(trimmed) or #trimmed) <= K.SHORT_INPUT then\r\ntext = text .. \"\\n\\n\" .. combatBeat()\r\nend\r\n\r\nlocal cw = K.combatW(id)\r\nif cw ~= \"mid\" and not c.active and not pc.dead then text = text .. \"\\n\\n\" .. K.COMBAT_W_TEXT[cw] end\r\nlocal exl = K.expansionLine()\r\nif exl then text = text .. \"\\n\\n\" .. exl end\r\nlocal pln = not pc.dead and K.planText(pc, clock, c.active) or nil\r\nif pln then text = text .. \"\\n\\n\" .. pln end\r\nlocal chw = K.checkW(id)\r\nif chw ~= \"mid\" and not c.active and not pc.dead then text = text .. \"\\n\\n\" .. K.CHECK_W_TEXT[chw] end\r\nif not c.active and ooc == \"0\" and not pc.dead then\r\nlocal cue = optOn(id, \"dnd_opt_pace\") and not Pace.restTalk(userText) and Pace.cue(pc, math.floor((getChatLength(id) + 1) / 2), cw) or nil\r\nif cue then text = text .. \"\\n\\n\" .. cue end\r\nend\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\nlocal MARKS = { \"※※\", \"[OPT|\", \"[GM|\", \"[STATUS|\", \"[HP|\", \"[FIX|\", \"[CONCSAVE|\", \"[XP|\", \"<!--dseed:\", \"[ROUND|\" }\r\nlocal function marked(v)\r\nfor _, k in ipairs(MARKS) do if v:find(k, 1, true) then return true end end\r\nreturn false\r\nend\r\nfor _, m in ipairs(messages) do\r\nfor _, field in ipairs({ \"content\", \"data\" }) do\r\nlocal v = m[field]\r\nif type(v) == \"string\" and (v:find(\"|ok|\", 1, true) or v:find(\"|bad:\", 1, true) or v:find(\"|auto|\", 1, true)) then\r\nm[field] = K.histTags(v)\r\nv = m[field]\r\nend\r\nif type(v) == \"string\" and marked(v) then\r\nm[field] = (v:gsub(\"※※C?\\n?\", \"\"):gsub(\"\\n?%[OPT|[^%]]*%]\", \"\"):gsub(\"\\n?%[GM|[^%]]*%]\", \"\")\r\n:gsub(\"\\n?%[STATUS|[^%]]*%]\", \"\"):gsub(\"\\n?%[HP|[^%]]*%]\", \"\"):gsub(\"\\n?%[FIX|[^%]]*%]\", \"\")\r\n:gsub(\"\\n?%[CONCSAVE|[^%]]*%]\", \"\")\r\n:gsub(\"\\n?%[XP|[^%]|]*|[^%]|]*|auto|[^%]]*%]\", \"\")\r\n:gsub(\"\\n?<!%-%-dseed:%w+%-%->\", \"\")\r\n:gsub(\"\\n?%[ROUND|[^%]]*%]\", \"\")\r\n\r\n:gsub(\"%[TIME|([^%]|]*)|ok|[^%]]*%]\", \"[TIME|%1]\"))\r\nend\r\nend\r\nend\r\ntext = K.liteReq(text)\r\nif K.En.on(id) then text = K.En.request(messages, text) end\r\n\r\n\r\nif getChatVar(id, \"dnd_opt_debug\") == \"1\" then\r\nsetState(id, \"dnd_last_req\", text)\r\nsetChatVar(id, \"dnd_perf_req\", string.format(\"%.0f\", (clockNow() - t0) * 1000))\r\n\r\n\r\n\r\nlocal okj, ms, kb = pcall(function()\r\nlocal c0 = clockNow()\r\nlocal s = json.encode(messages)\r\njson.decode(s)\r\nreturn (clockNow() - c0) * 1000, #s / 1024\r\nend)\r\nif okj then setChatVar(id, \"dnd_perf_json\", string.format(\"%.0f|%.0f|%d\", ms, kb, #messages)) end\r\nend\r\n\r\n\r\n\r\ntable.insert(messages, #messages, { role = \"user\", content = text })\r\nK.CharCode.strip(messages)\r\nreturn messages\r\nend)\r\n\r\n\r\n\r\n\r\n\r\nlocal Canon = { ALIAS = { player = true, [\"당신\"] = true, [\"플레이어\"] = true, you = true, pc = true } }\r\n\r\nK.KO_ALIAS = { [\"지각\"] = \"Perception\", [\"마법 갑옷\"] = \"Mage Armor\" }\r\n\r\nfunction Canon.name(v)\r\nv = trim(v or \"\")\r\nif v == \"\" then return v end\r\nif not Canon.en or Canon.gen ~= K.PACK.gen then\r\nCanon.en, Canon.gen = {}, K.PACK.gen\r\nfor en, ko in pairs(NAMES_KO) do\r\nCanon.en[en:lower()] = en\r\nif Canon.en[ko] == nil then Canon.en[ko] = en elseif Canon.en[ko] ~= en then Canon.en[ko] = false end\r\nend\r\nfor _, t in ipairs({ ITEMS, SPELLS, SKILL, MOD, WEAPONS, ARMOR, HEAL_SRC, CLASSES }) do\r\nfor en in pairs(t) do if type(en) == \"string\" then Canon.en[en:lower()] = en end end\r\nend\r\nend\r\nlocal slot = v:match(\"^(%d)%s*레벨 슬롯$\") or v:match(\"^[Ss]pell [Ss]lot (%d)$\")\r\nif slot then return \"Spell Slot \" .. slot end\r\nlocal ps = v:match(\"^계약 (%d)%s*레벨 슬롯$\") or v:match(\"^[Pp]act [Ss]lot (%d)$\")\r\nif ps then return \"Pact Slot \" .. ps end\r\nlocal ab = v:match(\"^(.-)%s*내성$\") or v:match(\"^(.-)%s+[Ss]ave$\") or v:match(\"^(.-)%s+[Ss]aving [Tt]hrow$\")\r\nif ab then\r\nlocal a = Canon.en[ab] or Canon.en[ab:lower()]\r\nif a and MOD[a] then return a .. \" save\" end\r\nend\r\nreturn Canon.en[v] or Canon.en[v:lower()] or K.KO_ALIAS[v] or v\r\nend\r\n\r\n\r\nK.AMMO = { Arrows = true, Bolts = true, [\"Firearm Bullets\"] = true, [\"Sling Bullets\"] = true, Needles = true }\r\nK.AMMO_OF = { crossbow = true, blowgun = true, sling = true, bow = true, longbow = true, shortbow = true }\r\nK.GUN_WORD = { pistol = true, musket = true, firearm = true, gun = true }\r\n\r\n\r\n\r\nfunction K.itemName(name, rec)\r\nlocal n = trim(name or \"\")\r\nif n == \"\" or ITEMS[n] then return n end\r\nif rec and type(rec.loot) == \"table\" and type(rec.loot[n]) == \"table\" then return n end\r\nlocal bare, each = n:match(\"^(.-)%s*%((%d+)%)$\")\r\nif bare then\r\nlocal b = K.itemName(bare, rec)\r\nif ITEMS[b] or K.MI.parse(b) then return b, tonumber(each) end\r\nend\r\nlocal function known(x)\r\nx = Canon.name(x)\r\nreturn ITEMS[x] and x or nil\r\nend\r\n\r\nlocal one = known((n:gsub(\"^[Pp]otions of \", \"Potion of \")))\r\nif one then return one end\r\nlocal p, why = K.MI.parse(n)\r\nif p or why then return n end\r\nlocal function formOf(x)\r\nreturn known(x) or known((x:gsub(\"s$\", \"\"))) or known(x .. \"s\")\r\nend\r\nlocal function bullets(x)\r\nlocal low = x:lower()\r\nreturn low == \"bullet\" or low == \"bullets\" or x == \"탄환\"\r\nend\r\nif n == \"총알\" then return \"Firearm Bullets\" end\r\nif bullets(n) then\r\n\r\nlocal it = rec and type(rec.items) == \"table\" and rec.items or {}\r\nlocal gun = (tonumber(it.Pistol) or 0) > 0 or (tonumber(it.Musket) or 0) > 0\r\nreturn ((tonumber(it.Sling) or 0) > 0 and not gun) and \"Sling Bullets\" or \"Firearm Bullets\"\r\nend\r\nlocal a, b = n:match(\"^(.-),%s*(.+)$\")\r\nif a and formOf(b .. \" \" .. a) then return formOf(b .. \" \" .. a) end\r\nlocal word, rest = n:match(\"^(%a+)%s+(.+)$\")\r\nif word then\r\nlocal w = word:lower()\r\nif K.GUN_WORD[w] and (bullets(rest) or rest:lower():match(\"^balls?$\")) then return \"Firearm Bullets\" end\r\nlocal am = K.AMMO_OF[w] and formOf(rest)\r\nif am and K.AMMO[am] then return am end\r\nend\r\nlocal held = n:match(\"^[Vv]ials? of (.+)$\") or n:match(\"^[Ff]lasks? of (.+)$\") or n:match(\"^[Bb]ottles? of (.+)$\")\r\nreturn formOf(held or n) or n\r\nend\r\n\r\n\r\n\r\nfunction K.monCanon(v)\r\nlocal k = Canon.name(v)\r\nif MONSTERS[k] then return k end\r\nlocal o = K.MON_OLD[k] or K.MON_OLD[trim(v or \"\")]\r\nif o and MONSTERS[o] then return o end\r\nreturn k\r\nend\r\nfunction Canon.actor(v, persona)\r\nlocal t = trim(v or \"\")\r\nif Canon.ALIAS[t:lower()] or (persona and persona ~= \"\" and t == persona) then return \"Player\" end\r\nreturn t\r\nend\r\n\r\n\r\n\r\nfunction K.unitFix(c, pc, v)\r\nlocal t = trim(v or \"\")\r\nif t == \"\" or t == \"Player\" or type(c) ~= \"table\" or not c.active or type(c.units) ~= \"table\" or c.units[t] then return v end\r\nif Ally.find(pc, t) then return v end\r\nif not K.MON_EN then\r\nK.MON_EN = {}\r\nfor en, m in pairs(MONSTERS) do if type(m) == \"table\" and type(m.ko) == \"string\" then K.MON_EN[m.ko] = en end end\r\nend\r\nlocal function kindOf(w)\r\nw = trim(w or \"\")\r\nreturn K.MON_EN[w] or Canon.name(w)\r\nend\r\nlocal base, n = t:match(\"^(.-)%s*(%d+)$\")\r\nlocal cands = {}\r\nfor name, u in pairs(c.units) do\r\nif u.side == \"enemy\" then\r\nlocal nk, nn = name:match(\"^(.-) (%d+)$\")\r\nif base and base ~= \"\" then\r\nif nn == n and nk and (nk:lower() == base:lower() or nk == kindOf(base)) then cands[#cands + 1] = name end\r\nelseif nk and (nk:lower() == t:lower() or nk == kindOf(t)) then\r\ncands[#cands + 1] = name\r\nend\r\nend\r\nend\r\nreturn #cands == 1 and cands[1] or v\r\nend\r\n\r\n\r\nfunction K.slotWord(v)\r\nlocal t = trim(v or \"\"):lower()\r\nlocal n = t:match(\"^(%d)%s*[snrt][tdh]$\") or t:match(\"^(%d)%s*레벨\") or t:match(\"^(%d)%s*%-?%s*level$\") or t:match(\"^level%s*(%d)$\")\r\nor t:match(\"^slot%s*(%d)$\") or t:match(\"^(%d)%s*slot$\") or t:match(\"^spell slot%s*(%d)$\")\r\nif n then return n end\r\nif t == \"cantrip\" or t == \"소마법\" then return \"0\" end\r\nreturn v\r\nend\r\n\r\nfunction K.coinKo(v)\r\nlocal s0 = tostring(v or \"\")\r\nif not s0:find(\"[\\128-\\255]\") then return v end\r\nlocal s1 = s0\r\nfor _ = 1, 3 do s1 = s1:gsub(\"(%d),(%d%d%d)\", \"%1%2\") end\r\n\r\ns1 = s1:gsub(\"(%d+)[ \\t]*백금화\", \" %1 pp \"):gsub(\"(%d+)[ \\t]*골드\", \" %1 gp \"):gsub(\"(%d+)[ \\t]*금화\", \" %1 gp \")\r\n:gsub(\"(%d+)[ \\t]*은화\", \" %1 sp \"):gsub(\"(%d+)[ \\t]*동화\", \" %1 cp \"):gsub(\"(%d+)[ \\t]*실버\", \" %1 sp \")\r\ns1 = s1:gsub(\"백금화[ \\t]*(%d+)\", \" %1 pp \"):gsub(\"금화[ \\t]*(%d+)\", \" %1 gp \"):gsub(\"은화[ \\t]*(%d+)\", \" %1 sp \"):gsub(\"동화[ \\t]*(%d+)\", \" %1 cp \")\r\ns1 = s1:gsub(\"%s+\", \" \"):gsub(\"^%s+\", \"\"):gsub(\"%s+$\", \"\"):gsub(\"^([%+%-]) \", \"%1\")\r\nif s1:find(\"[\\128-\\255]\") or s1:sub(2):find(\"[%+%-]\") then return v end\r\nreturn s1\r\nend\r\n\r\nfunction K.durNorm(part)\r\nlocal p = tostring(part or \"\"):gsub(\"%s\", \"\"):lower()\r\nif p == \"\" or p == \"-\" or p == \"dmg\" or p == \"conc\" then return part end\r\np = p:gsub(\"라운드\", \"r\"):gsub(\"rounds?\", \"r\")\r\nif p:match(\"^%+?%d+r$\") then return p end\r\nlocal body = p:gsub(\"days?\", \"d\"):gsub(\"hours?\", \"h\"):gsub(\"minutes?\", \"m\"):gsub(\"mins?\", \"m\")\r\n:gsub(\"시간\", \"h\"):gsub(\"분\", \"m\"):gsub(\"일\", \"d\"):match(\"^%+?(.*)$\") or \"\"\r\nlocal add = 0\r\nfor n, u in body:gmatch(\"(%d+)([mhd])\") do add = add + tonumber(n) * K.TIME_UNIT[u] end\r\nif add > 0 and body:gsub(\"%d+[mhd]\", \"\") == \"\" then return \"+\" .. add .. \"m\" end\r\nreturn part\r\nend\r\n\r\n\r\nfunction Canon.signed(v)\r\nlocal sign, name = (v or \"\"):match(\"^%s*([+-])%s*(.-)%s*$\")\r\nif not sign then return v end\r\nreturn sign .. Canon.name(name)\r\nend\r\n\r\nfunction Canon.list(v)\r\nlocal out = {}\r\nfor _, n in ipairs(splitNames(v)) do out[#out + 1] = Canon.name(n) end\r\nreturn table.concat(out, \", \")\r\nend\r\n\r\n\r\n\r\n\r\nfunction K.toolOf(v)\r\nv = trim(v or \"\")\r\nlocal base, sk = v:match(\"^(.-)%s*%((.-)%)$\")\r\nif not (base and K.TOOLS[Canon.name(base)] or (base and K.TOOL_VAR[base:lower()])) then base, sk = v, nil end\r\nlocal n = Canon.name(base)\r\nif K.TOOLS[n] then return n, sk and Canon.name(sk) end\r\nlocal low = base:lower():gsub(\"'\", \"\")\r\nfor k in pairs(K.TOOLS) do if k:lower():gsub(\"'\", \"\") == low then return k, sk and Canon.name(sk) end end\r\nif K.TOOL_VAR[base:lower()] then return K.TOOL_VAR[base:lower()], sk and Canon.name(sk) end\r\nreturn nil\r\nend\r\n\r\nfunction K.toolText(sh, who, short)\r\nlocal o = {}\r\nfor n in pairs(K.toolProfs(sh)) do\r\nlocal t = K.TOOLS[n]\r\no[#o + 1] = string.format(\"%s = %s in prose %+d (%s%s)\", n, t.ko, bonusFor(n), t.ab, t.util ~= \"\" and (\"; \" .. t.util) or \"\")\r\nend\r\ntable.sort(o)\r\nlocal monk = K.cl(sh, \"Monk\") > 0 and not (type(sh.picks) == \"table\" and sh.picks.monkTool)\r\nif #o == 0 and not monk then return nil end\r\nif short then return \"Tools: \" .. (#o > 0 and table.concat(o, \"; \") or \"one Artisan's tool or instrument, not named yet\") end\r\nreturn (who or \"Player\") .. \"'s tool proficiencies: \" .. (#o > 0 and table.concat(o, \"; \") or \"none yet\")\r\n.. (monk and \"; a Monk's one Artisan's tool or Musical Instrument, not named yet (the first check with one names it)\" or \"\")\r\n.. \". \" .. K.TOOL_RULE .. \".\"\r\nend\r\n\r\nK.TOOL_RULE = \"A check with a tool: [CHECK|Tool|d20|+bonus|DC|success/failure], the tool's ability (+ the Proficiency Bonus when proficient);\"\r\n.. \" with a skill the GM uses with it, [CHECK|Tool (Skill)|...] still takes the tool's bonus, never the skill's, and proficient in both: Advantage (adv A,B).\"\r\n.. \" Utilize DCs are in the tool's line\"\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\nK.MI = { kc = {} }\r\nfunction K.MI.has(rec, name) return type(rec) == \"table\" and type(rec.loot) == \"table\" and type(rec.loot[name]) == \"table\" end\r\n\r\nfunction K.MI.byKo(s)\r\nif not K.MI.k2e then\r\nK.MI.k2e = {}\r\nlocal used = {}\r\nfor e2, ko in pairs(NAMES_KO) do if not K.MAGIC[e2] then used[ko] = true end end\r\nfor en, m in pairs(K.MAGIC or {}) do\r\nK.MI.k2e[en:lower()] = en\r\nif type(m.ko) == \"string\" and (NAMES_KO[en] == m.ko or not used[m.ko]) then K.MI.k2e[m.ko] = en end\r\nend\r\nend\r\nreturn K.MI.k2e[s] or K.MI.k2e[(s or \"\"):lower()]\r\nend\r\nK.MI.VALUE = { C = 10000, B = 40000, A = 400000, S = 4000000, L = 20000000 }\r\nK.MI.RANK = { C = 0, B = 1, A = 2, S = 3, L = 4, X = 5 }\r\n\r\nK.MI.SCROLL = { [0] = { \"C\", 13, 5 }, { \"C\", 13, 5 }, { \"B\", 13, 5 }, { \"B\", 15, 7 }, { \"A\", 15, 7 }, { \"A\", 17, 9 }, { \"S\", 17, 9 },\r\n{ \"S\", 18, 10 }, { \"S\", 18, 10 }, { \"L\", 19, 11 } }\r\nK.MI.DMG_KO = { Acid = \"산성\", Bludgeoning = \"타격\", Cold = \"냉기\", Fire = \"화염\", Force = \"역장\", Lightning = \"번개\", Necrotic = \"사령\",\r\nPiercing = \"관통\", Poison = \"독성\", Psychic = \"정신\", Radiant = \"광휘\", Slashing = \"참격\", Thunder = \"천둥\" }\r\nK.MI.VAR_KO = { Hill = \"언덕\", Frost = \"서리\", Stone = \"바위\", Cloud = \"구름\", Storm = \"폭풍\", Absorption = \"흡수\", Agility = \"민첩\",\r\nAwareness = \"경계\", Fortitude = \"강인함\", [\"Greater Absorption\"] = \"상급 흡수\", Insight = \"통찰\", Intellect = \"지성\",\r\nLeadership = \"지도력\", Mastery = \"숙달\", Protection = \"보호\", Regeneration = \"재생\", Reserve = \"비축\", Strength = \"힘\",\r\nSustenance = \"지속\", Aberration = \"기괴체\", Beast = \"야수\", Celestial = \"천상체\", Construct = \"구조체\", Dragon = \"용\",\r\nElemental = \"원소\", Humanoid = \"인간형\", Fey = \"요정\", Fiend = \"악마\", Giant = \"거인\", Monstrosity = \"괴물\",\r\nOoze = \"점액\", Plant = \"식물\", Undead = \"언데드\" }\r\n\r\nfunction K.MI.roll(f)\r\nif tonumber(f) then return tonumber(f) end\r\nlocal p = parseFormula(tostring(f or \"0\"))\r\nif not p then return 0 end\r\nlocal s = p.mod\r\nfor _, d in ipairs(p.dice) do for _ = 1, d.n do s = s + K.d(d.s) end end\r\nreturn s\r\nend\r\n\r\nfunction K.MI.fits(spec, g)\r\nif type(spec) == \"table\" then\r\nfor _, x in ipairs(spec) do if x == g then return true end end\r\nreturn false\r\nend\r\nif spec == \"any_weapon\" then return WEAPONS[g] ~= nil end\r\nif spec == \"any_melee\" then return WEAPONS[g] ~= nil and not WEAPONS[g].ranged end\r\nif spec == \"any_armor\" then return ARMOR[g] ~= nil and ARMOR[g].cat ~= \"shield\" end\r\nif spec == \"medium_heavy_nohide\" then return ARMOR[g] ~= nil and (ARMOR[g].cat == \"medium\" or ARMOR[g].cat == \"heavy\") and g ~= \"Hide Armor\" end\r\nreturn spec == g\r\nend\r\n\r\nfunction K.MI.parse(name)\r\nname = trim(name or \"\")\r\nif name == \"\" or type(K.MAGIC) ~= \"table\" then return nil end\r\nlocal function upd(key, r, g, n) return { key = key, m = K.MAGIC[key], base = g, plus = n, r = r } end\r\n\r\nlocal n, g = name:match(\"^%+(%d)%s+(.+)$\")\r\nif not n then g, n = name:match(\"^(.-),?%s+%+(%d)$\") end\r\nif n and tonumber(n) >= 1 and tonumber(n) <= 3 then\r\nn = tonumber(n)\r\ng = K.itemName(Canon.name(trim(g)))\r\nif g == \"Wand of the War Mage\" then\r\nreturn { key = \"Wand of the War Mage, +1, +2, or +3\", m = K.MAGIC[\"Wand of the War Mage, +1, +2, or +3\"], var = \"+\" .. n, r = ({ \"B\", \"A\", \"S\" })[n] }\r\nend\r\nif g == \"Shield\" then return upd(\"Shield, +1, +2, or +3\", ({ \"B\", \"A\", \"S\" })[n], g, n) end\r\nif ARMOR[g] then return upd(\"Armor, +1, +2, or +3\", ({ \"A\", \"S\", \"L\" })[n], g, n) end\r\nif WEAPONS[g] then return upd(\"Weapon, +1, +2, or +3\", ({ \"B\", \"A\", \"S\" })[n], g, n) end\r\n\r\nlocal vk = g .. \" +1, +2, or +3\"\r\nif K.MAGIC[vk] and type(K.MAGIC[vk].var) == \"table\" and K.MAGIC[vk].var[\"+\" .. n] then return K.MI.parse(vk .. \" (+\" .. n .. \")\") end\r\nif K.AMMO[g] then\r\nlocal p = upd(\"Ammunition, +1, +2, or +3\", ({ \"B\", \"A\", \"S\" })[n], nil, 0)\r\np.ammo = g\r\nreturn p\r\nend\r\nreturn nil\r\nend\r\nlocal wm = name:match(\"^Wand of the War Mage%s*%(%+(%d)%)$\")\r\nif wm then return K.MI.parse(\"+\" .. wm .. \" Wand of the War Mage\") end\r\nlocal key, inner = name:match(\"^(.-)%s*%((.-)%)%s*$\")\r\nkey = key or name\r\nlocal m = K.MAGIC[key]\r\nif not m and K.MAGIC[name] then key, m, inner = name, K.MAGIC[name], nil end\r\n\r\nif not m and K.MI.byKo(name) then key, inner = K.MI.byKo(name), nil; m = K.MAGIC[key] end\r\nif not m and K.MI.byKo(key) then key = K.MI.byKo(key); m = K.MAGIC[key] end\r\nif not m then\r\nlocal metal, g2 = key:match(\"^(Mithral) (.+)$\")\r\nif not metal then metal, g2 = key:match(\"^(Adamantine) (.+)$\") end\r\nif metal and (ARMOR[Canon.name(g2)] or g2 == \"Armor\") then\r\nreturn K.MI.parse(metal .. \" Armor\" .. (g2 ~= \"Armor\" and (\" (\" .. g2 .. \")\") or (inner and (\" (\" .. inner .. \")\") or \"\")))\r\nend\r\nlocal sp = key:match(\"^Spell Scroll of (.+)$\") or key:match(\"^Scroll of (.+)$\")\r\nif sp then return K.MI.parse(\"Spell Scroll (\" .. sp .. \")\") end\r\nif key == \"Stone of Good Luck\" or key == \"Luckstone\" then return K.MI.parse(\"Stone of Good Luck (Luckstone)\") end\r\nreturn nil\r\nend\r\nlocal out = { key = key, m = m, r = type(m.r) == \"string\" and m.r or nil }\r\nfor part in ((inner or \"\") .. \",\"):gmatch(\"%s*([^,]-)%s*,\") do\r\nif part ~= \"\" then\r\nlocal cp = Canon.name(part)\r\nif key == \"Spell Scroll\" and SPELLS[cp] then\r\nout.var = cp\r\nelseif type(m.var) == \"table\" and (m.var[part] or m.var[cp]) then\r\nout.var = m.var[part] and part or cp\r\nelse\r\nlocal hit\r\nfor v in pairs(type(m.var) == \"table\" and m.var or {}) do if v:lower() == part:lower() then hit = v end end\r\nif hit then out.var = hit\r\nelseif WEAPONS[cp] or ARMOR[cp] then out.base = cp end\r\nend\r\nend\r\nend\r\nif key == \"Spell Scroll\" then\r\nif not out.var then return nil, \"name the spell: Spell Scroll (Fireball)\" end\r\nout.r = K.MI.SCROLL[SPELLS[out.var].level or 0][1]\r\nelseif type(m.var) == \"table\" then\r\nif not out.var then\r\nlocal o = {}\r\nfor v in pairs(m.var) do o[#o + 1] = v end\r\ntable.sort(o)\r\nreturn nil, key .. \" comes in kinds: name one, \" .. key .. \" (\" .. table.concat(o, \"/\") .. \")\"\r\nend\r\nlocal v = m.var[out.var]\r\nout.r = type(v) == \"string\" and v or (type(v) == \"table\" and v.r) or out.r\r\nend\r\nif m.base then\r\nif out.base and not K.MI.fits(m.base, out.base) then return nil, out.base .. \" cannot be \" .. key end\r\nif not out.base then\r\nif type(m.base) == \"string\" and (WEAPONS[m.base] or ARMOR[m.base]) then out.base = m.base\r\nelseif type(m.base) == \"table\" and #m.base <= 2 and ARMOR[m.base[1]] then out.base = m.base[1]\r\nelse return nil, \"name its base: \" .. key .. \" (Longsword)\" end\r\nend\r\nend\r\nout.plus = m.plus or 0\r\nout.r = out.r or (type(m.r) == \"table\" and m.r[1]) or \"B\"\r\nreturn out\r\nend\r\n\r\nfunction K.MI.canon(p)\r\nif p.key:match(\"^Weapon, \") or p.key:match(\"^Armor, \") or p.key:match(\"^Shield, \") then return \"+\" .. p.plus .. \" \" .. p.base end\r\nif p.key:match(\"^Ammunition, \") then return \"+\" .. ({ B = 1, A = 2, S = 3 })[p.r] .. \" \" .. p.ammo end\r\nif p.key:match(\"^Wand of the War Mage\") then return \"Wand of the War Mage (\" .. p.var .. \")\" end\r\nlocal inner = {}\r\nif p.var then inner[#inner + 1] = p.var end\r\nlocal m = p.m\r\nif p.base and not (type(m.base) == \"string\" and m.base == p.base) then inner[#inner + 1] = p.base end\r\nreturn #inner > 0 and (p.key .. \" (\" .. table.concat(inner, \", \") .. \")\") or p.key\r\nend\r\n\r\nfunction K.MI.maybe(v)\r\nif type(v) ~= \"string\" or #v > 80 then return false end\r\nif K.MI.byKo(v) or v:match(\"^%+%d \") or v:match(\"%+%d$\") then return true end\r\nlocal key = v:match(\"^(.-)%s*%(.-%)%s*$\")\r\nif key and (K.MAGIC[key] or K.MI.byKo(key)) then return true end\r\nreturn (v:match(\"^Mithral \") or v:match(\"^Adamantine \") or v:match(\"Scroll\") or v:match(\"Luckstone\") or v:match(\"^Wand of the War Mage\")) ~= nil\r\nend\r\n\r\nfunction K.MI.ko(name)\r\nlocal hit = K.MI.kc[name]\r\nif hit ~= nil then return hit or nil end\r\nlocal p = K.MI.parse(name)\r\nlocal out = false\r\nif p then\r\nlocal base = p.base and (NAMES_KO[p.base] or p.base)\r\nif p.key:match(\"^Weapon, \") or p.key:match(\"^Armor, \") or p.key:match(\"^Shield, \") then out = \"+\" .. p.plus .. \" \" .. base\r\nelseif p.key:match(\"^Ammunition, \") then out = \"+\" .. ({ B = 1, A = 2, S = 3 })[p.r] .. \" \" .. (NAMES_KO[p.ammo] or p.ammo)\r\nelse\r\nlocal inner = {}\r\nif p.var then\r\ninner[#inner + 1] = (p.key == \"Spell Scroll\" and (NAMES_KO[p.var] or p.var)) or K.MI.DMG_KO[p.var] or K.MI.VAR_KO[p.var] or p.var\r\nend\r\nif p.base and not (type(p.m.base) == \"string\" and p.m.base == p.base) then inner[#inner + 1] = base end\r\nout = (p.m.ko or p.key) .. (#inner > 0 and (\" (\" .. table.concat(inner, \", \") .. \")\") or \"\")\r\nend\r\nend\r\nK.MI.kc[name] = out\r\nreturn out or nil\r\nend\r\nfunction K.MI.keeps(m) return type(m) == \"table\" and (m.cursed or m.att or (type(m.wear) == \"table\" and #m.wear > 0)) and true or false end\r\n\r\nfunction K.MI.record(p)\r\nlocal m = p.m\r\nlocal l = { srd = p.key, var = p.var, grade = p.r or \"C\", base = p.base, plus = p.plus or 0, pw = {}, att = m.att or nil,\r\nby = m.by, cat = m.cat, left = {} }\r\nlocal pws = m.pw or {}\r\nif type(m.var) == \"table\" and type(m.var[p.var or \"\"]) == \"table\" and m.var[p.var].pw then pws = m.var[p.var].pw end\r\nlocal vn = type(m.var) == \"table\" and type(m.var[p.var or \"\"]) == \"table\" and m.var[p.var].n or nil\r\nfor _, w in ipairs(pws) do\r\nif w.k == \"vuln\" and w.type == \"others\" then\r\nfor _, t in ipairs({ \"Bludgeoning\", \"Piercing\", \"Slashing\" }) do if t ~= p.var then l.pw[#l.pw + 1] = { k = \"vuln\", type = t } end end\r\nelse\r\nlocal x = {}\r\nfor k, v in pairs(w) do x[k] = v end\r\nif x.type == \"var\" then x.type = p.var end\r\nif x.n == \"var\" then x.n = vn end\r\nl.pw[#l.pw + 1] = x\r\nend\r\nend\r\nif type(m.ch) == \"table\" then l.chmax = K.MI.roll(m.ch.max); l.ch = l.chmax end\r\nfor _, s in ipairs(m.sp or {}) do if s.day then l.left[s.s] = s.day end end\r\nif type(m.use) == \"table\" and m.use.day then l.left.use = m.use.day end\r\n\r\nif p.key == \"Spell Scroll\" or m.cat == \"Potion\" or (type(m.use) == \"table\" and not m.use.day and not K.MI.keeps(m)) then l.consumable = true end\r\nif m.worn then l.wornReq = true end\r\nif m.pack then l.pack = true end\r\nif m.mundane then l.cost = m.cost end\r\nif m.cursed then l.cursed = true end\r\nreturn l\r\nend\r\n\r\nfunction K.MI.allowed(p, rec)\r\n\r\nlocal off = type(p.m) == \"table\" and p.m.pack and K.d2need(p.m)\r\nif off then return false, p.key .. \" is \" .. tostring(K.D2_WHY[off] or off) end\r\nlocal lv = tonumber(rec and rec.level) or 1\r\nif (p.r == \"L\" or p.r == \"X\") and lv < 11 then\r\nreturn false, (p.r == \"L\" and \"a Legendary\" or \"an Artifact\") .. \" item at level \" .. lv .. \" (only from level 11)\"\r\nend\r\nreturn true\r\nend\r\n\r\nfunction K.MI.ensure(rec, name)\r\nif K.MI.has(rec, name) then return name, rec.loot[name] end\r\nlocal p, why = K.MI.parse(name)\r\nif not p then return nil, why end\r\nlocal cn = K.MI.canon(p)\r\nif K.MI.has(rec, cn) then return cn, rec.loot[cn] end\r\nif p.key == \"Spell Scroll\" and p.var and K.spellOff(p.var) then return nil, K.spellOff(p.var) end\r\nlocal okm, whyc = K.MI.allowed(p, rec)\r\nif not okm then return nil, whyc end\r\nrec.loot = type(rec.loot) == \"table\" and rec.loot or {}\r\nrec.loot[cn] = K.MI.record(p)\r\nreturn cn, rec.loot[cn]\r\nend\r\n\r\nfunction K.MI.powers(rec, kind)\r\nlocal out = {}\r\nfor _, x in ipairs(LOOT.inUse(rec)) do\r\nfor _, w in ipairs(x[2].pw or {}) do if w.k == kind then out[#out + 1] = { w, x[2], x[1] } end end\r\nend\r\nreturn out\r\nend\r\nfunction K.MI.sum(rec, kind)\r\nlocal n = 0\r\nfor _, x in ipairs(K.MI.powers(rec, kind)) do n = n + (tonumber(x[1].n) or 0) end\r\nreturn n\r\nend\r\n\r\nfunction K.MI.ac(rec, armor, shield)\r\nlocal add, base = 0, nil\r\nfor _, x in ipairs(K.MI.powers(rec, \"ac\")) do\r\nif x[1][\"if\"] ~= \"noarmor_noshield\" or (not armor and not shield) then add = add + (tonumber(x[1].n) or 0) end\r\nend\r\nfor _, x in ipairs(K.MI.powers(rec, \"acbase\")) do if not armor then base = math.max(base or 0, tonumber(x[1].n) or 0) end end\r\nreturn add, base\r\nend\r\nK.lootCheck = function(rec) return K.MI.sum(rec, \"check\") end\r\n\r\n\r\nfunction K.MI.sync(rec, sh)\r\nif type(rec) ~= \"table\" or type(sh) ~= \"table\" or type(sh.scores) ~= \"table\" then return false end\r\nlocal set, add = {}, {}\r\nfor _, x in ipairs(K.MI.powers(rec, \"set\")) do\r\nlocal w = x[1]\r\nif tonumber(w.n) then set[w.ab] = math.max(set[w.ab] or 0, tonumber(w.n)) end\r\nend\r\nfor _, b in pairs(type(rec.buff) == \"table\" and rec.buff or {}) do\r\nfor ab, v in pairs(type(b) == \"table\" and type(b.sets) == \"table\" and b.sets or {}) do set[ab] = math.max(set[ab] or 0, tonumber(v) or 0) end\r\nend\r\nfor _, x in ipairs(K.MI.powers(rec, \"add\")) do\r\nlocal w = x[1]\r\nadd[w.ab] = add[w.ab] or {}\r\nadd[w.ab][#add[w.ab] + 1] = w\r\nend\r\nlocal ms\r\nfor _, a in ipairs(ABILS) do\r\nlocal base = tonumber(sh.scores[a]) or 10\r\nlocal v = base\r\nfor _, w in ipairs(add[a] or {}) do\r\nlocal n = tonumber(w.n) or 0\r\n\r\nif n < 0 then if v > (tonumber(w.min) or 1) then v = math.max(tonumber(w.min) or 1, v + n) end\r\nelseif v < (tonumber(w.max) or 20) then v = math.min(tonumber(w.max) or 20, v + n) end\r\nend\r\nif set[a] and set[a] > v then v = set[a] end\r\nif v ~= base then ms = ms or {}; ms[a] = v end\r\nend\r\nlocal pb = K.MI.sum(rec, \"pb\")\r\nlocal mhp = K.MI.sum(rec, \"maxhp\")\r\nlocal function same(x, y)\r\nif type(x) ~= \"table\" or type(y) ~= \"table\" then return x == y end\r\nfor k, v in pairs(x) do if y[k] ~= v then return false end end\r\nfor k, v in pairs(y) do if x[k] ~= v then return false end end\r\nreturn true\r\nend\r\n\r\n\r\nlocal fxk, conds = {}, {}\r\nfor _, x in ipairs(LOOT.inUse(rec)) do\r\nlocal m = x[2].srd and K.MAGIC and K.MAGIC[x[2].srd]\r\nif m and m.pack then\r\nif type(m.fx) == \"table\" and #m.fx > 0 then fxk[#fxk + 1] = x[2].srd end\r\nfor _, w in ipairs(m.wear or {}) do conds[w] = x[1] end\r\nlocal af = m.afflict\r\nif type(af) == \"table\" and not x[2].afflicted and (af.when == \"equip\" or (af.when == \"attune\" and x[2].attuned)) then\r\nx[2].afflicted = true\r\nK.MI.afflictNow(rec, x[1], af)\r\nend\r\nend\r\nend\r\ntable.sort(fxk)\r\nlocal fxs, cs = #fxk > 0 and fxk or nil, next(conds) and conds or nil\r\nlocal itemChanged = not same(sh.itemFx, fxs) or not same(rec.itemCond, cs)\r\nsh.itemFx, rec.itemCond = fxs, cs\r\nlocal changed = itemChanged or not same(sh.mscores, ms) or (sh.mpb or 0) ~= pb or (sh.mhp or 0) ~= mhp\r\nsh.mscores, sh.mpb, sh.mhp = ms, pb > 0 and pb or nil, mhp > 0 and mhp or nil\r\nreturn changed\r\nend\r\n\r\n\r\nfunction K.MI.afflictNow(rec, itemName, af)\r\nlocal r = K.PACK.afflict and K.PACK.afflict[af.name]\r\nlocal tag = r and ({ curse = \"CURSE\", brand = \"BRAND\", fetish = \"FETISH\" })[r.kind]\r\nif not tag then return end\r\nlocal pc = K.curPc or K.partyPc\r\nlocal who = (rec == pc and \"Player\") or rec.name or \"Player\"\r\nlocal f = tag == \"CURSE\" and { who, \"+\" .. af.name, itemName, tostring(r.level or 3) }\r\nor tag == \"BRAND\" and { who, \"+\" .. af.name, \"1\", itemName } or { who, \"+\" .. af.name, \"-\", itemName }\r\npcall(K.afflictTag, tag, f, K.curC or { units = {} }, pc, K.clockRef)\r\nend\r\n\r\n\r\nfunction K.MI.off(l)\r\nif not (type(l) == \"table\" and l.pack) then return nil end\r\nlocal m = K.MAGIC and K.MAGIC[l.srd or \"\"]\r\nif not (type(m) == \"table\" and m.pack) then return \"gone\" end\r\nreturn K.d2need(m)\r\nend\r\nfunction K.MI.offWhy(name, off)\r\nreturn name .. (off == \"gone\" and \" belongs to a module that is not loaded\" or (\" is \" .. tostring(K.D2_WHY[off] or off)))\r\nend\r\n\r\n\r\nfunction K.MI.cursedHold(rec, name)\r\nlocal l = type(rec) == \"table\" and type(rec.loot) == \"table\" and rec.loot[name]\r\nif not (type(l) == \"table\" and l.cursed) or K.MI.off(l) then return nil end\r\nif K.castNow(\"Remove Curse\") or K.castNow(\"Wish\") then l.cursed = nil; return nil end\r\nreturn name .. \" is cursed: its user won't part with it (Remove Curse cast in this reply ends that)\"\r\nend\r\n\r\nfunction K.MI.climaxCharge(rec)\r\nlocal o = {}\r\nfor _, x in ipairs(LOOT.inUse(rec)) do\r\nlocal l, m = x[2], x[2].srd and K.MAGIC and K.MAGIC[x[2].srd]\r\nif m and type(m.ch) == \"table\" and m.ch.regain_on == \"climax\" and l.chmax and (tonumber(l.ch) or 0) < l.chmax then\r\nlocal add = m.ch.regain and m.ch.regain ~= 0 and K.MI.roll(m.ch.regain) or 1\r\nl.ch = math.min(l.chmax, (tonumber(l.ch) or 0) + math.max(1, add))\r\no[#o + 1] = string.format(\"%s %d/%d charges\", x[1], l.ch, l.chmax)\r\nend\r\nend\r\nreturn #o > 0 and (\" (\" .. table.concat(o, \"; \") .. \")\") or \"\"\r\nend\r\n\r\nfunction K.MI.shortRefill(rec)\r\nfor _, l in pairs(type(rec) == \"table\" and type(rec.loot) == \"table\" and rec.loot or {}) do\r\nlocal m = type(l) == \"table\" and l.srd and K.MAGIC and K.MAGIC[l.srd]\r\nfor _, sp in ipairs(m and m.sp or {}) do\r\nif sp.day and sp.rest == \"short\" then l.left = type(l.left) == \"table\" and l.left or {}; l.left[sp.s] = sp.day end\r\nend\r\nend\r\nend\r\n\r\nfunction K.MI.spAlts()\r\nfor _, m in pairs(K.MAGIC or {}) do\r\nfor _, s in ipairs(type(m) == \"table\" and type(m.sp) == \"table\" and m.sp or {}) do\r\nif type(s) == \"table\" and type(s.alts) == \"table\" then\r\ns.s = s.alts[1]\r\nfor _, x in ipairs(s.alts) do if SPELLS[x] then s.s = x; break end end\r\nend\r\nend\r\nend\r\nend\r\n\r\nfunction K.MI.spells(rec, out)\r\nfor _, x in ipairs(LOOT.inUse(rec)) do\r\nlocal l = x[2]\r\nlocal m = l.srd and K.MAGIC[l.srd]\r\nfor _, s in ipairs(m and m.sp or {}) do\r\nif not out[s.s] and SPELLS[s.s] then out[s.s] = { x[1], l, s } end\r\nend\r\nend\r\nreturn out\r\nend\r\n\r\n\r\n\r\n\r\nK.MI.LAST = {\r\n[\"Staff of Power\"] = { one = \"+2 Quarterstaff\", twenty = \"1d8+2\" },\r\n[\"Staff of the Magi\"] = { one = false, twenty = \"1d12+1\" },\r\n[\"Staff of the Woodlands\"] = { one = \"Quarterstaff\" },\r\n}\r\nfunction K.MI.lastCharge(rec, itemName, l, m)\r\nif not (tonumber(l.ch) == 0 and type(m) == \"table\" and type(m.ch) == \"table\" and m.ch.last) then return \"\" end\r\nlocal spec = K.MI.LAST[l.srd or \"\"] or K.MI.LAST[itemName] or {}\r\nlocal d = K.d(20)\r\nif d == 20 and spec.twenty then\r\nlocal p = parseFormula(spec.twenty)\r\nlocal n = p and p.mod or 0\r\nfor _, dd in ipairs(p and p.dice or {}) do for _ = 1, dd.n do n = n + K.d(dd.s) end end\r\nl.ch = math.min(tonumber(l.chmax) or n, n)\r\nreturn string.format(\", the last charge: d20 20, %d charges back\", l.ch)\r\nend\r\nif d ~= 1 or spec.one == false then return \", the last charge: d20 \" .. d .. \", it holds\" end\r\nlocal items = type(rec.items) == \"table\" and rec.items or {}\r\nitems[itemName] = (tonumber(items[itemName]) or 1) - 1\r\nif items[itemName] <= 0 then\r\nitems[itemName] = nil\r\nif type(rec.loot) == \"table\" then rec.loot[itemName] = nil end\r\nend\r\nlocal eq = type(rec.equip) == \"table\" and rec.equip or nil\r\nif type(spec.one) == \"string\" then\r\n\r\nlocal left = spec.one\r\nif not ITEMS[left] then left = K.MI.ensure(rec, left) or left end\r\nitems[left] = (tonumber(items[left]) or 0) + 1\r\nif eq and eq.main == itemName then eq.main = left end\r\nreturn \", the last charge: d20 1, it is left a \" .. left\r\nend\r\nif eq and eq.main == itemName and not items[itemName] then eq.main = nil end\r\nreturn \", the last charge: d20 1, the item is destroyed\"\r\nend\r\nfunction K.MI.itemCast(pc, name, sp, xi, l, f2, raw)\r\nlocal row = xi.row or {}\r\nlocal base = row.lvl or sp.level\r\nlocal want = tonumber(raw) or tonumber(f2:match(\"(%d+)%s*$\")) or base\r\nlocal level, cost = base, row.c or 0\r\nif row.lvl then\r\nlevel = row.lvl\r\nelseif want > base then\r\nif not row.up then return nil, xi.item .. \" casts \" .. name .. \" at level \" .. base .. \" only\" end\r\ncost = (row.c or 1) + (want - base)\r\nif cost > row.up then return nil, xi.item .. \" spends at most \" .. row.up .. \" charges on \" .. name end\r\nlevel = want\r\nend\r\nlocal out = { level = level, dc = row.dc, atk = row.atk }\r\nif row.ab then\r\nlocal am = abilityMod(K.score(SHEET, ABBR[row.ab] or row.ab))\r\nout.dc, out.atk = 8 + PROF + am, PROF + am\r\nend\r\nif row.day then\r\nl.left = type(l.left) == \"table\" and l.left or {}\r\nif l.left[name] == nil then l.left[name] = row.day end\r\nif (l.left[name] or 0) < 1 then return nil, xi.item .. \": \" .. name .. \" again only after \" .. (row.rest == \"short\" and \"a Short Rest\" or \"the next dawn (a Long Rest)\") end\r\nout.commit = function()\r\nl.left[name] = l.left[name] - 1\r\nreturn string.format(\"%s %d/%d per %s\", xi.item, l.left[name], row.day, row.rest == \"short\" and \"Short Rest\" or \"dawn\")\r\nend\r\nelseif cost > 0 then\r\nif (tonumber(l.ch) or 0) < cost then\r\nreturn nil, string.format(\"%s has %d charges; %s at level %d takes %d\", xi.item, tonumber(l.ch) or 0, name, level, cost)\r\nend\r\nout.commit = function()\r\nl.ch = l.ch - cost\r\nlocal note = K.MI.lastCharge(pc, xi.item, l, K.MAGIC[l.srd] or {})\r\nreturn string.format(\"%s %d/%d charges%s\", xi.item, l.ch, l.chmax or l.ch, note)\r\nend\r\nelse\r\nout.commit = function() return xi.item .. \", at will\" end\r\nend\r\nreturn out\r\nend\r\n\r\n\r\n\r\nfunction K.MI.scrollCast(pc, name, sp, who)\r\nlocal sname = \"Spell Scroll (\" .. name .. \")\"\r\nlocal holder\r\nfor _, r in ipairs({ pc, K.partyPc }) do\r\nif not holder and type(r) == \"table\" and (tonumber((r.items or {})[sname]) or 0) > 0 then holder = r end\r\nend\r\nif not holder then return nil, \"no \" .. sname .. \" in the pack\" end\r\nlocal onList = false\r\nfor _, c in ipairs(K.classes(SHEET)) do for _, cl in ipairs(sp.classes or {}) do if cl == c.name then onList = true end end end\r\nif not onList then return nil, name .. \" is not on \" .. who .. \"'s spell list: the scroll cannot be read\" end\r\nlocal row = K.MI.SCROLL[sp.level or 0]\r\nlocal hl = type(holder.loot) == \"table\" and holder.loot[sname]\r\nlocal out = { level = sp.level, dc = (hl and hl.dc) or row[2], atk = (hl and hl.atk) or row[3] }\r\nlocal top = 0\r\nfor k in pairs(PC.res or {}) do\r\nlocal n = tonumber(k:match(\"^Spell Slot (%d)$\") or k:match(\"^Pact Slot (%d)$\"))\r\nif n and n > top then top = n end\r\nend\r\nlocal check\r\nif (sp.level or 0) > top then\r\nlocal st = Spell.stats(nil)\r\nlocal mod = st and st.mod or 0\r\nlocal d = K.d(20)\r\ncheck = { d = d, mod = mod, dc = 10 + sp.level }\r\nout.fizzle = d + mod < check.dc\r\nend\r\nout.commit = function()\r\nholder.items[sname] = holder.items[sname] - 1\r\nif holder.items[sname] <= 0 then\r\nholder.items[sname] = nil\r\nif type(holder.loot) == \"table\" then holder.loot[sname] = nil end\r\nend\r\nreturn sname .. (check and string.format(\" (check d20 %d%+d vs DC %d)\", check.d, check.mod, check.dc) or \"\")\r\nend\r\nreturn out\r\nend\r\n\r\n\r\n\r\nfunction K.poisonUse(f, rec, c, clock)\r\nlocal head = \"[USE|Basic Poison\" .. ((f[2] or \"\") ~= \"\" and (\"|\" .. f[2]) or \"\")\r\nlocal function fail(why) return head .. \"|bad:\" .. why .. \"|-]\", false end\r\nif (tonumber((rec.items or {})[\"Basic Poison\"]) or 0) < 1 then return fail(\"no Basic Poison in the pack\") end\r\nlocal eq = type(rec.equip) == \"table\" and rec.equip or {}\r\nlocal w = trim(f[2] or \"\") ~= \"\" and K.itemName(Canon.name(trim(f[2])), rec) or eq.main\r\nlocal wd = w and gearOf(rec, w)\r\nlocal ammo = w and K.MI.AMMO[w]\r\nif not (wd or ammo) then return fail(\"name the weapon or the ammunition: [USE|Basic Poison|Dagger]\") end\r\nif (tonumber((rec.items or {})[w]) or 0) < 1 then return fail(\"no \" .. w .. \" in the pack\") end\r\nif wd and not (wd.type == \"Piercing\" or wd.type == \"Slashing\") then return fail(w .. \" deals \" .. tostring(wd.type) .. \": the poison needs Piercing or Slashing\") end\r\nrec.items[\"Basic Poison\"] = rec.items[\"Basic Poison\"] - 1\r\nif rec.items[\"Basic Poison\"] <= 0 then rec.items[\"Basic Poison\"] = nil end\r\nrec.buff = type(rec.buff) == \"table\" and rec.buff or {}\r\nlocal now = (type(clock) == \"table\" and tonumber(clock.min)) or tonumber(K.replyClock) or 0\r\nlocal n = ammo and math.min(3, tonumber(rec.items[w]) or 0) or 1\r\nrec.buff[\"Basic Poison\"] = { poison = w, n = n, by = \"Basic Poison\", fight = true, ends = now + 1,\r\ntell = string.format(\"%s coated: +1d4 Poison on %s hit with Piercing or Slashing damage (Lua counts it in the attack)\", w, ammo and (\"each of the next \" .. n) or \"the next\") }\r\nreturn head .. \"|ok|\" .. w .. \" coated\" .. (ammo and (\" (\" .. n .. \")\") or \"\") .. \", 1 minute; \" .. (rec.items[\"Basic Poison\"] or 0) .. \" left]\", true\r\nend\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\nK.CRAFT_EXTRA = { Shield = { \"Smith's Tools\", \"Woodcarver's Tools\" } }\r\nK.SCRIBE = { [0] = { 1, 1500 }, { 1, 2500 }, { 3, 10000 }, { 5, 15000 }, { 10, 100000 }, { 25, 150000 }, { 40, 1000000 }, { 50, 1250000 },\r\n{ 60, 1500000 }, { 120, 5000000 } }\r\nfunction K.craftTools(name)\r\nlocal out = {}\r\nfor t, row in pairs(K.TOOLS or {}) do\r\nfor _, m in ipairs(row.makes or {}) do if m == name then out[#out + 1] = t end end\r\nend\r\nfor _, t in ipairs(K.CRAFT_EXTRA[name] or {}) do out[#out + 1] = t end\r\ntable.sort(out)\r\nreturn out\r\nend\r\nfunction K.craft(f, pc, c, clock, persona)\r\nlocal raw = trim(f[1] or \"\")\r\nlocal n = tonumber(trim(f[2] or \"1\")) or 0\r\nlocal head = \"[CRAFT|\" .. table.concat(f, \"|\")\r\nlocal function fail(why) return head .. \"|bad:\" .. why .. \"|\" .. moneyText(pc.cp) .. \"]\", false end\r\nif c.active then return fail(\"not during a fight\") end\r\nif n < 1 or n ~= math.floor(n) or n > 100 then return fail(\"count 1-100\") end\r\nlocal hname = trim(f[3] or \"\")\r\nlocal helper = hname ~= \"\" and Ally.find(pc, Canon.actor(hname, persona)) or nil\r\nif hname ~= \"\" and not (helper and not helper.dead) then return fail(\"the helper is a companion's name\") end\r\nlocal days, cost, made, note = 0, 0, nil, \"\"\r\nlocal sp = raw:match(\"^Spell Scroll%s*%((.-)%)$\") or raw:match(\"^Scroll of (.+)$\") or raw:match(\"^주문 두루마리%s*%((.-)%)$\")\r\nif sp then\r\nlocal spell = Canon.name(trim(sp))\r\nlocal s = SPELLS[spell]\r\nif not s then return fail(K.spellOff(spell) or (\"unknown spell \" .. sp)) end\r\nif not Spell.known(spell) or not Spell.stats(spell) then return fail(spell .. \" is not among Player's prepared spells\") end\r\nif not (SKILL_PROF.Arcana or K.toolProfs(SHEET)[\"Calligrapher's Supplies\"]) then\r\nreturn fail(\"scribing needs proficiency in Arcana or with Calligrapher's Supplies\")\r\nend\r\nlocal row = K.SCRIBE[s.level or 0]\r\ndays, cost = row[1] * n, row[2] * n\r\nmade = \"Spell Scroll (\" .. spell .. \")\"\r\nif s.cost then note = \" (its material at hand: \" .. s.cost .. \")\" end\r\nhelper = nil\r\nelse\r\nlocal name, each = K.itemName(Canon.name(raw), pc)\r\nif each then n = n * each end\r\nif name == \"Potion of Healing\" then\r\nif not K.toolProfs(SHEET)[\"Herbalism Kit\"] then return fail(\"a Potion of Healing needs proficiency with the Herbalism Kit\") end\r\ndays, cost = n, 2500 * n\r\nelse\r\nif not ITEMS[name] then\r\nif K.storyGear(name) or K.STORY_GEAR[name] then return fail(\"story gear: Lua does not count it, narrate the work (no tag)\") end\r\nreturn fail(\"an SRD item a tool makes\")\r\nend\r\nlocal tools = K.craftTools(name)\r\nif #tools == 0 then return fail(\"no tool makes \" .. name .. \" (the SRD's Craft lists)\") end\r\nlocal tool\r\nfor _, t in ipairs(tools) do if K.toolProfs(SHEET)[t] and not tool then tool = t end end\r\nif not tool then return fail(name .. \" needs proficiency with \" .. table.concat(tools, \" or \")) end\r\nif helper and not Ally.with(helper, function() return K.toolProfs(SHEET)[tool] end) then\r\nreturn fail((helper.name or \"the helper\") .. \" is not proficient with \" .. tool)\r\nend\r\nlocal price = (tonumber(PRICE[name]) or 0) * n\r\nif price <= 0 then return fail(\"no price for \" .. name) end\r\ncost = math.floor(price / 2)\r\ndays = math.max(1, math.ceil(price / 1000))\r\nnote = \" (\" .. tool .. \")\"\r\nend\r\nmade = name\r\nend\r\nif helper then days = math.ceil(days / 2); note = note .. \" with \" .. helper.name end\r\nif pc.cp < cost then return fail(string.format(\"the materials cost %s, the party has %s\", moneyText(cost), moneyText(pc.cp))) end\r\npc.cp = pc.cp - cost\r\nif clock then clock.min = clock.min + (days - 1) * 1440 + 480 end\r\npc.items[made] = (pc.items[made] or 0) + n\r\nif sp then\r\nlocal cn, l = K.MI.ensure(pc, made)\r\nif cn and l then\r\nlocal st = Spell.stats(made:match(\"%((.-)%)$\"))\r\nl.dc, l.atk = st and st.dc or nil, st and st.atk or nil\r\nend\r\nend\r\nreturn string.format(\"%s|ok|%d %s made, %d day%s of work%s, materials %s, %s left]\", head, n, made, days, days > 1 and \"s\" or \"\", note,\r\nmoneyText(cost), moneyText(pc.cp)), true\r\nend\r\n\r\nK.CRAFT_WORDS = { \"만들\", \"제작\", \"제조\", \"빚\", \"조합\", \"양조\", \"물약을 만\", \"두루마리\", \"베껴\", \"craft\", \"brew\", \"scribe\", \"forge\", \"make\" }\r\nfunction K.craftText(pc, userText)\r\nlocal t = tostring(userText or \"\"):lower()\r\nlocal hit = false\r\nfor _, w in ipairs(K.CRAFT_WORDS) do if t:find(w, 1, true) then hit = true end end\r\nif not hit or t:find(\"캐릭터\", 1, true) or t:find(\"character\", 1, true) then return nil end\r\nlocal can = {}\r\nlocal profs = K.toolProfs(SHEET)\r\nlocal names = {}\r\nfor tl in pairs(profs) do names[#names + 1] = tl end\r\ntable.sort(names)\r\nfor _, tl in ipairs(names) do\r\nlocal items = {}\r\nfor _, m in ipairs(K.TOOLS[tl].makes or {}) do if ITEMS[m] and m ~= \"Potion of Healing\" then items[#items + 1] = m end end\r\nfor _, m in ipairs(K.CRAFT_EXTRA.Shield) do if m == tl then items[#items + 1] = \"Shield\" end end\r\nif #items > 0 then can[#can + 1] = tl .. \": \" .. table.concat(items, \", \") end\r\nend\r\nif profs[\"Herbalism Kit\"] then can[#can + 1] = \"Potion of Healing (25 GP and 1 day each)\" end\r\nif Spell.any() and (SKILL_PROF.Arcana or profs[\"Calligrapher's Supplies\"]) then\r\ncan[#can + 1] = \"Spell Scroll (a prepared spell): cantrip 1 day 15 GP, level 1 1 day 25 GP, 2: 3 days 100 GP, 3: 5 days 150 GP, 4: 10 days 1,000 GP,\"\r\n.. \" 5: 25 days 1,500 GP, 6: 40 days 10,000 GP, 7: 50 days 12,500 GP, 8: 60 days 15,000 GP, 9: 120 days 50,000 GP\"\r\nend\r\nreturn \"Crafting (SRD, out of a fight): [CRAFT|Item|count] or [CRAFT|Item|count|Companion] (one helper proficient with the same tool\"\r\n.. \" halves the days). Lua takes the materials (half the price) from the purse and the days of 8 hours' work (the price in GP / 10,\"\r\n.. \" at least 1) from the clock: write no TIME for them. What Player can make: \" .. (#can > 0 and table.concat(can, \"; \") or \"nothing that Lua counts (no tool proficiency that crafts)\") .. \".\"\r\nend\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\nK.FAMILIARS = { \"Bat\", \"Cat\", \"Frog\", \"Hawk\", \"Lizard\", \"Octopus\", \"Owl\", \"Rat\", \"Raven\", \"Spider\", \"Weasel\" }\r\nK.SUMMON = {\r\n[\"Find Familiar\"] = { familiar = true },\r\n[\"Find Steed\"] = { steed = true, one = true },\r\n[\"Phantom Steed\"] = { kind = \"Riding Horse\", mins = 60, phantom = true, one = true },\r\n[\"Animate Dead\"] = { kinds = { \"Skeleton\", \"Zombie\" }, mins = 1440 },\r\n[\"Create Undead\"] = { mins = 1440 },\r\n[\"Summon Dragon\"] = { dragon = true, conc = true, one = true },\r\n\r\n[\"Animate Objects\"] = { objects = true, conc = true, mins = 1, short = true },\r\n[\"Planar Ally\"] = { planar = true },\r\n}\r\nK.OBJ_SIZE = { Tiny = \"Medium\", Small = \"Medium\", Medium = \"Medium\", Large = \"Large\", Huge = \"Huge\" }\r\nK.OBJ_COUNT = { Medium = 1, Large = 2, Huge = 3 }\r\n\r\nK.UNDEAD = { [6] = { Ghoul = 3 }, [7] = { Ghoul = 4 }, [8] = { Ghoul = 5, Ghast = 2, Wight = 2 }, [9] = { Ghoul = 6, Ghast = 3, Wight = 3, Mummy = 2 } }\r\nK.STEED_DMG = { Celestial = \"Radiant\", Fey = \"Psychic\", Fiend = \"Necrotic\" }\r\nK.DRAGON_DMG = { Acid = true, Cold = true, Fire = true, Lightning = true, Poison = true }\r\n\r\nfunction K.summonRow(kind, lvl, st, choice)\r\nif kind == \"Otherworldly Steed\" then\r\nlocal ty = K.STEED_DMG[choice or \"\"] and choice or \"Celestial\"\r\nreturn { ac = 10 + lvl, hp = 5 + 10 * lvl, init = 1, speed = 60, cr = \"0\", xp = 0, fly = lvl >= 4 or nil,\r\nsaves = { Strength = 4, Dexterity = 1, Constitution = 2, Intelligence = -2, Wisdom = 1, Charisma = -1 },\r\nattacks = { { name = \"Otherworldly Slam\", hit = st.atk, dmg = \"1d8+\" .. lvl, type = K.STEED_DMG[ty] } },\r\nacts = (ty == \"Fiend\" and (\"Fell Glare (Bonus Action, once per Long Rest): one creature within 60 ft, Wisdom save DC \" .. st.dc .. \" or Frightened until the end of its caster's next turn\"))\r\nor (ty == \"Fey\" and \"Fey Step (Bonus Action, once per Long Rest): teleports with its rider up to 60 ft\")\r\nor (\"Healing Touch (Bonus Action, once per Long Rest): one creature within 5 ft regains 2d8+\" .. lvl .. \" HP\"),\r\nko = \"이계의 군마\", what = \"Large \" .. ty, steed = true }\r\nend\r\nif kind == \"Animated Object\" then\r\nlocal up = math.max(0, lvl - 5)\r\nlocal size = K.OBJ_SIZE[choice or \"\"] or \"Medium\"\r\nlocal dmg = size == \"Huge\" and ((2 + up) .. \"d12+\" .. (3 + st.mod)) or size == \"Large\" and ((2 + up) .. \"d6+\" .. (3 + st.mod))\r\nor ((1 + up) .. \"d4+3\")\r\nreturn { ac = 15, hp = size == \"Huge\" and 40 or size == \"Large\" and 20 or 10, init = 0, speed = 30, cr = \"0\", xp = 0,\r\nsaves = { Strength = 3, Dexterity = 0, Constitution = 0, Intelligence = -4, Wisdom = -4, Charisma = -5 },\r\nimm = { \"Poison\", \"Psychic\" }, cimm = { \"Charmed\", \"Exhaustion\", \"Frightened\", \"Paralyzed\", \"Poisoned\" },\r\nattacks = { { name = \"Slam\", hit = st.atk, dmg = dmg, type = \"Force\" } }, ko = \"움직이는 물체\", what = size .. \" Construct\" }\r\nend\r\nif kind == \"Draconic Spirit\" then\r\nlocal t = K.DRAGON_DMG[choice or \"\"] and choice or \"Fire\"\r\nreturn { ac = 14 + lvl, hp = 50 + 10 * math.max(0, lvl - 5), init = 2, speed = 30, cr = \"0\", xp = 0, fly = true,\r\nsaves = { Strength = 4, Dexterity = 2, Constitution = 3, Intelligence = 0, Wisdom = 2, Charisma = 2 },\r\nres = { \"Acid\", \"Cold\", \"Fire\", \"Lightning\", \"Poison\" }, cimm = { \"Charmed\", \"Frightened\", \"Poisoned\" },\r\nattacks = { { name = \"Rend\", hit = st.atk, dmg = \"1d6+\" .. (4 + lvl), type = \"Piercing\" } },\r\nmulti = math.floor(lvl / 2) .. \" Rend attacks and its Breath Weapon\",\r\nacts = string.format(\"Breath Weapon: each creature in a 30-ft Cone, [HAZARD|Target|Draconic Breath|Dexterity|d20|+bonus|%d|success/failure|2d6|dice|damage], %s, half on a success\",\r\nst.dc, t),\r\nbreath = { dc = st.dc, type = t }, ko = \"용의 영혼\", what = \"Large Dragon\" }\r\nend\r\nend\r\n\r\nfunction K.regSummons(pc, c)\r\nfor _, s in ipairs(type(pc) == \"table\" and type(pc.summons) == \"table\" and pc.summons or {}) do\r\n\r\n\r\nif type(s) == \"table\" and s.rowOf and type(MONSTERS[s.rowOf]) == \"table\" and K.summonScale then\r\nlocal owner = s.by == \"Player\" and pc or Ally.find(pc, s.by or \"\")\r\nlocal sh = owner and ((owner == pc and SHEET) or owner.sheet)\r\nif type(sh) == \"table\" then\r\nlocal ok, row = pcall(K.summonScale, MONSTERS[s.rowOf], s.scale, sh, (s.cls and K.cl(sh, s.cls) > 0) and K.cl(sh, s.cls) or K.charLevel(sh), s.cls)\r\nif ok and type(row) == \"table\" then\r\nlocal grow = (tonumber(row.hp) or 0) - (tonumber(s.max) or 0)\r\nif grow ~= 0 then s.max = row.hp; s.hp = math.max(0, math.min(s.max, (tonumber(s.hp) or 0) + math.max(0, grow))) end\r\nrow.ko, row.summonRow = row.ko or (s.st and s.st.ko), true\r\ns.st = row\r\nend\r\nend\r\nend\r\nif type(s) == \"table\" and type(s.st) == \"table\" and s.kind then MONSTERS[s.kind] = s.st end\r\nend\r\nfor _, u in pairs(type(c) == \"table\" and type(c.units) == \"table\" and c.units or {}) do\r\nif type(u) == \"table\" and type(u.st) == \"table\" and u.kind then MONSTERS[u.kind] = u.st end\r\nend\r\nend\r\nfunction K.summonFind(pc, name)\r\nfor i, s in ipairs(type(pc.summons) == \"table\" and pc.summons or {}) do if s.name == name then return s, i end end\r\nreturn nil\r\nend\r\n\r\nfunction K.summonName(pc, c, kind)\r\nlocal base = \"Summoned \" .. (kind:gsub(\"%s*%b()$\", \"\"))\r\nfor n = 1, 99 do\r\nlocal nm = base .. \" \" .. n\r\nif not K.summonFind(pc, nm) and not (c.units or {})[nm] then return nm end\r\nend\r\nreturn base .. \" 99\"\r\nend\r\n\r\nfunction K.summonJoin(c, s)\r\nlocal init = 0\r\nlocal caster = s.by == \"Player\" and \"Player\" or s.by\r\nif c.units[caster] then init = c.units[caster].init or 0 end\r\nc.units[s.name] = { side = \"friend\", kind = s.kind, hp = s.hp, max = s.max, init = init, summon = true, st = s.st,\r\nnoatk = s.noatk, by = s.by, ar = s.ar }\r\nlocal at = #c.order + 1\r\nfor i, nm in ipairs(c.order) do if nm == caster then at = i + 1 end end\r\n\r\nwhile c.order[at] and c.units[c.order[at]] and c.units[c.order[at]].summon and c.units[c.order[at]].by == s.by do at = at + 1 end\r\ntable.insert(c.order, at, s.name)\r\nend\r\n\r\nfunction K.summonTag(f, c, pc, clock, persona)\r\nlocal name = Canon.name(trim(f[1] or \"\"))\r\nlocal head = \"[SUMMON|\" .. table.concat(f, \"|\")\r\nlocal function fail(why) return head .. \"|bad:\" .. why .. \"|-]\", false end\r\nlocal sm = K.SUMMON[name]\r\nif not sm then\r\n\r\nlocal fe, fby = K.summonFeatFind(trim(f[1] or \"\"), pc)\r\nif fe then return K.summonFeatTag(f, c, pc, clock, fe, fby) end\r\nlocal fn = {}\r\nfor _, x in ipairs(K.summonFeatAll(pc)) do fn[#fn + 1] = x end\r\nreturn fail(\"a spell that makes a creature: Find Familiar, Find Steed, Phantom Steed, Animate Dead, Create Undead, Summon Dragon\"\r\n.. (#fn > 0 and (\", or a feature: \" .. table.concat(fn, \", \")) or \"\"))\r\nend\r\n\r\nFeat.cur.summoned = Feat.cur.summoned or {}\r\nlocal casting, anyCast\r\nfor _, x in ipairs(Feat.cur.casts or {}) do\r\nif x.name == name then\r\nanyCast = true\r\nif not casting and not Feat.cur.summoned[x] then casting = x end\r\nend\r\nend\r\nif not anyCast then return fail(\"cast \" .. name .. \" with CAST first\") end\r\nif not casting then return fail(name .. \" made its creatures already in this casting\") end\r\nlocal owner = casting.by or \"Player\"\r\nlocal by = owner ~= \"Player\" and Ally.find(pc, owner) or nil\r\nlocal lvl = tonumber(casting.level) or SPELLS[name].level\r\nlocal choice = Canon.name(trim(f[2] or \"\"))\r\nlocal want = tonumber(trim(f[3] or \"\"))\r\nlocal st = Ally.run(pc, by, function() return Spell.stats(name) end) or { atk = 5, dc = 13 }\r\nlocal kind, count, row\r\nif sm.familiar then\r\nlocal ok = false\r\nfor _, k in ipairs(K.FAMILIARS) do if k == choice then ok = true end end\r\nif not ok and MONSTERS[choice] and MONSTERS[choice].beast and MONSTERS[choice].cr == \"0\" then ok = true end\r\nif not ok then return fail(\"a familiar's form: \" .. table.concat(K.FAMILIARS, \", \") .. \", or another Beast of CR 0\") end\r\nkind, count = choice, 1\r\nelseif sm.steed then\r\nkind, count = \"Otherworldly Steed\" .. (owner ~= \"Player\" and (\" (\" .. owner .. \")\") or \"\"), 1\r\nif choice ~= \"\" and not K.STEED_DMG[choice] then return fail(\"the steed's type: Celestial, Fey or Fiend\") end\r\nrow = K.summonRow(\"Otherworldly Steed\", lvl, st, choice)\r\nelseif sm.phantom then\r\nkind, count = sm.kind, 1\r\nelseif name == \"Animate Dead\" then\r\nif choice ~= \"Skeleton\" and choice ~= \"Zombie\" then return fail(\"Skeleton (bones) or Zombie (a corpse)\") end\r\nlocal most = 1 + 2 * math.max(0, lvl - 3)\r\ncount = want or most\r\nif count < 1 or count > most then return fail(string.format(\"a level %d casting animates %d at most\", lvl, most)) end\r\nkind = choice\r\nelseif name == \"Create Undead\" then\r\nlocal tbl = K.UNDEAD[math.min(9, lvl)] or K.UNDEAD[6]\r\nif not tbl[choice] then\r\nlocal o = {}\r\nfor k, v in pairs(tbl) do o[#o + 1] = k .. \" \" .. v end\r\ntable.sort(o)\r\nreturn fail(\"a level \" .. lvl .. \" casting makes \" .. table.concat(o, \" or \"))\r\nend\r\ncount = want or tbl[choice]\r\nif count < 1 or count > tbl[choice] then return fail(string.format(\"%d %s at most\", tbl[choice], choice)) end\r\nkind = choice\r\nelseif sm.objects then\r\nlocal size = K.OBJ_SIZE[choice]\r\nif not size then return fail(\"the objects' size: Medium (or smaller), Large or Huge\") end\r\nlocal room = math.max(1, st.mod or 1)\r\nlocal most = math.floor(room / K.OBJ_COUNT[size])\r\ncount = want or most\r\nif count < 1 or count * K.OBJ_COUNT[size] > room then\r\nreturn fail(string.format(\"objects up to the spellcasting modifier (%d): %d %s at most\", room, most, size))\r\nend\r\nkind = \"Animated Object (\" .. size .. \")\" .. (owner ~= \"Player\" and (\" (\" .. owner .. \")\") or \"\")\r\nrow = K.summonRow(\"Animated Object\", lvl, st, size)\r\nelseif sm.planar then\r\n\r\n\r\nlocal m = MONSTERS[choice]\r\nlocal what = m and m.what or \"\"\r\nif not (what:find(\"Celestial\") or what:find(\"Elemental\") or what:find(\"Fiend\")) then return fail(\"the GM's creature: an \" .. K.srdX() .. \" Celestial, Elemental or Fiend\") end\r\nlocal n, u = trim(f[3] or \"\"):match(\"^(%d+)%s*([mhd])$\")\r\nn = tonumber(n)\r\nif not n or (u == \"d\" and n > 10) then return fail(\"the service's time: 10m, 2h or 3d (10 days at most)\") end\r\nlocal mins = n * (u == \"m\" and 1 or u == \"h\" and 60 or 1440)\r\nlocal price = n * (u == \"m\" and 10000 or u == \"h\" and 100000 or 1000000)\r\nlocal adj = trim(f[4] or \"\"):lower()\r\nif adj == \"half\" then price = math.floor(price / 2) elseif adj == \"free\" then price = 0 end\r\nif pc.cp < price then return fail(string.format(\"the service costs %s, the party has %s\", moneyText(price), moneyText(pc.cp))) end\r\npc.cp = pc.cp - price\r\nkind, count = choice, 1\r\nsm = { mins = mins, paid = price }\r\nelseif sm.packSummon then\r\n\r\nlocal ps = sm.packSummon\r\nif type(ps.choices) == \"table\" and #ps.choices > 0 then\r\nlocal ok = false\r\nfor _, x in ipairs(ps.choices) do if x == choice or (NAMES_KO[x] and NAMES_KO[x] == trim(f[2] or \"\")) then ok, choice = true, x end end\r\nif not ok then return fail(\"its kind: \" .. table.concat(ps.choices, \", \")) end\r\nend\r\nkind, count = ps.kind .. (owner ~= \"Player\" and (\" (\" .. owner .. \")\") or \"\"), 1\r\nrow = K.packSummonRow(ps, lvl, st, choice)\r\nelseif sm.dragon then\r\nif choice ~= \"\" and not K.DRAGON_DMG[choice] then return fail(\"the breath's damage type: Acid, Cold, Fire, Lightning or Poison\") end\r\nkind, count = \"Draconic Spirit\" .. (owner ~= \"Player\" and (\" (\" .. owner .. \")\") or \"\"), 1\r\nrow = K.summonRow(\"Draconic Spirit\", lvl, st, choice)\r\nend\r\nif not row and not MONSTERS[kind] then return fail(\"no stat block for \" .. kind) end\r\npc.summons = type(pc.summons) == \"table\" and pc.summons or {}\r\n\r\nif sm.familiar or sm.one then\r\nfor i = #pc.summons, 1, -1 do\r\nlocal s = pc.summons[i]\r\nif s.spell == name and s.by == owner then\r\ntable.remove(pc.summons, i)\r\nif c.units[s.name] then c.units[s.name] = nil end\r\nfor j = #(c.order or {}), 1, -1 do if c.order[j] == s.name then table.remove(c.order, j) end end\r\nif pc.mount == s.name then pc.mount = nil end\r\nend\r\nend\r\nend\r\nif row then MONSTERS[kind] = row end\r\nlocal now = (type(clock) == \"table\" and tonumber(clock.min)) or 0\r\nlocal made = {}\r\nlocal stb = row or MONSTERS[kind]\r\nfor _ = 1, count do\r\nlocal s = { name = K.summonName(pc, c, kind), kind = kind, st = row, hp = stb.hp, max = stb.hp, spell = name, by = owner,\r\nends = sm.mins and (now + sm.mins) or nil, noatk = sm.familiar or nil, conc = sm.conc or nil,\r\nspeed = sm.phantom and 100 or nil, phantom = sm.phantom or nil, short = sm.short or nil }\r\npc.summons[#pc.summons + 1] = s\r\nmade[#made + 1] = s.name\r\nif c.active then K.summonJoin(c, s) end\r\nend\r\n\r\nif sm.dragon then\r\nlocal r = by or pc\r\nr.buff = type(r.buff) == \"table\" and r.buff or {}\r\nr.buff[\"Summon Dragon\"] = { res = { row.breath.type }, conc = true, concBy = owner, by = owner }\r\nend\r\nFeat.cur.summoned[casting] = true\r\nreturn head .. \"|ok|\" .. table.concat(made, \", \") .. \" (HP \" .. stb.hp .. (sm.mins and (\", \" .. K.spanText(sm.mins)) or \"\") .. \")\"\r\n.. (sm.paid and (\" paid \" .. moneyText(sm.paid) .. \", \" .. moneyText(pc.cp) .. \" left\") or \"\") .. \"]\", true\r\nend\r\n\r\nfunction K.mountTag(f, c, pc)\r\nlocal raw = trim(f[1] or \"\")\r\nlocal head = \"[MOUNT|\" .. raw\r\nlocal function fail(why) return head .. \"|bad:\" .. why .. \"|-]\", false end\r\nif raw == \"-\" or raw == \"\" then\r\nif not pc.mount then return fail(\"not riding\") end\r\npc.mount = nil\r\nreturn head .. \"|ok|on foot]\", true\r\nend\r\nlocal s = K.summonFind(pc, raw)\r\nif not s then\r\nfor _, x in ipairs(type(pc.summons) == \"table\" and pc.summons or {}) do\r\nlocal st = x.st or MONSTERS[x.kind] or {}\r\nif not s and (st.steed or x.phantom or (st.what or \"\"):find(\"^Large\")) and (raw:lower() == \"steed\" or raw == x.kind or raw:find(\"탈것\", 1, true) or raw:find(\"군마\", 1, true)) then s = x end\r\nend\r\nend\r\nif not s then return fail(\"a summoned creature to ride (its name)\") end\r\nlocal st = s.st or MONSTERS[s.kind] or {}\r\nif not (st.what or \"\"):find(\"^Large\") and not (st.what or \"\"):find(\"^Huge\") then return fail(s.name .. \" is too small to ride\") end\r\npc.mount = s.name\r\nreturn head .. \"|ok|riding \" .. s.name .. \", Speed \" .. (s.speed or st.speed or 30) .. \" ft]\", true\r\nend\r\n\r\n\r\nfunction K.summonsTick(pc, c, clock)\r\nif type(pc.summons) ~= \"table\" then return end\r\nlocal now = type(clock) == \"table\" and tonumber(clock.min) or nil\r\nfor i = #pc.summons, 1, -1 do\r\nlocal s = pc.summons[i]\r\nlocal u = type(c) == \"table\" and c.units and c.units[s.name]\r\nif u and u.summon then s.hp, s.ar = u.hp, u.ar end\r\nlocal caster = s.by == \"Player\" and pc or Ally.find(pc, s.by)\r\nlocal gone = (tonumber(s.hp) or 0) <= 0 or (s.ends and now and s.ends <= now)\r\nor (s.conc and not (caster and type(caster.conc) == \"table\" and caster.conc.name == s.spell))\r\nor (s.phantom and (tonumber(s.hp) or 0) < (tonumber(s.max) or 0))\r\nor ((s.spell == \"Find Steed\") and (not caster or caster.dead))\r\nif gone then\r\ntable.remove(pc.summons, i)\r\nif pc.mount == s.name then pc.mount = nil end\r\n\r\nif u and (not c.active or (tonumber(s.hp) or 0) > 0) then\r\nc.units[s.name] = nil\r\nfor j = #(c.order or {}), 1, -1 do if c.order[j] == s.name then table.remove(c.order, j) end end\r\nend\r\nend\r\nend\r\nif #pc.summons == 0 then pc.summons = nil end\r\nend\r\n\r\nfunction K.summonText(pc)\r\nif type(pc.summons) ~= \"table\" or #pc.summons == 0 then return nil end\r\nlocal o = {}\r\nfor _, s in ipairs(pc.summons) do\r\nlocal st = s.st or MONSTERS[s.kind] or {}\r\nlocal p = s.ends and clockParts(s.ends)\r\n\r\nlocal fx = (s.as and (\", counts as a \" .. s.as) or \"\") .. (s.obey == \"telepathic\" and (\", obeys \" .. s.by .. \"'s telepathic commands\") or \"\")\r\n.. (s.obey == \"may_disobey\" and \", may ignore an order (its own will, the story's)\" or \"\")\r\n.. (s.range and (\", gone if more than \" .. s.range .. \" ft from \" .. s.by .. \" (the story's)\") or \"\")\r\no[#o + 1] = string.format(\"%s = %s in prose (%s's %s, HP %d/%d%s%s%s%s)\", s.name, st.ko or s.kind, s.by, s.spell, s.hp, s.max,\r\np and string.format(\", %s until %02d:%02d on day %d\", s.feat and \"lasts\" or \"obeys\", p.h, p.m, p.day) or \"\", s.noatk and \", cannot attack\" or \"\",\r\nfx, pc.mount == s.name and \", Player rides it: a controlled mount, Dash, Disengage or Dodge only\" or \"\")\r\nend\r\nreturn \"Summoned creatures (Lua keeps their HP; each joins a fight on Player's side right after its caster, played with its stat\"\r\n.. \" block's tags): \" .. table.concat(o, \"; \") .. \". Riding one: [MOUNT|name] (it must be Large), getting off: [MOUNT|-]; either costs half\"\r\n.. \" Player's Speed of movement. Knocked Prone while riding: [COND|+Prone], Lua rolls the DC 10 Dexterity save (off the mount on a failure).\"\r\nend\r\n\r\nfunction K.summonWhat(name)\r\nlocal sm = K.SUMMON[name]\r\nif not sm then return nil end\r\nlocal ex = sm.familiar and \"[SUMMON|Find Familiar|Owl]\" or sm.steed and \"[SUMMON|Find Steed|Celestial] (Celestial, Fey or Fiend)\"\r\nor sm.phantom and \"[SUMMON|Phantom Steed]\" or name == \"Animate Dead\" and \"[SUMMON|Animate Dead|Skeleton|1] (Skeleton or Zombie, two more per slot level above 3)\"\r\nor name == \"Create Undead\" and \"[SUMMON|Create Undead|Ghoul|3]\" or name == \"Animate Objects\" and \"[SUMMON|Animate Objects|Medium|3] (Medium, Large or Huge; as many as the spellcasting modifier allows, Large counts 2, Huge 3)\"\r\nor name == \"Planar Ally\" and \"[SUMMON|Planar Ally|Creature|1h] (the GM's Celestial, Elemental or Fiend; 10m / 1h / 1d up to 10 days, 100 / 1,000 / 10,000 GP each, half or free as a fourth field)\"\r\nor (sm.packSummon and (\"[SUMMON|\" .. name .. (type(sm.packSummon.choices) == \"table\" and #sm.packSummon.choices > 0\r\nand (\"|\" .. sm.packSummon.choices[1] .. \"] (\" .. table.concat(sm.packSummon.choices, \", \") .. \")\") or \"]\")))\r\n\r\nor (\"[SUMMON|Summon Dragon|Fire] (the breath's type; the Draconic Spirit at slot level L: AC 14+L, HP 50 + 10 per level above 5,\"\r\n.. \" floor(L/2) Rend attacks at the caster's spell attack bonus, 1d6+4+L Piercing each, Breath Weapon 2d6 of that type in a\"\r\n.. \" 30-ft Cone, Dexterity save at the spell DC, half on a success)\")\r\nreturn \"right after the CAST, \" .. ex .. \": Lua keeps the creature\"\r\nend\r\n\r\n\r\nfunction K.calc(expr, vars)\r\nif type(expr) == \"number\" then return expr end\r\nlocal s0 = tostring(expr or \"\"):gsub(\"%s\", \"\")\r\nlocal pos = 1\r\nlocal sum, prod, atom\r\nfunction atom()\r\nlocal ch = s0:sub(pos, pos)\r\nif ch == \"(\" then\r\npos = pos + 1\r\nlocal v = sum()\r\nif s0:sub(pos, pos) == \")\" then pos = pos + 1 end\r\nreturn v\r\nend\r\nif ch == \"-\" then pos = pos + 1; return -atom() end\r\nlocal num = s0:match(\"^%d+\", pos)\r\nif num then pos = pos + #num; return tonumber(num) end\r\nlocal id = s0:match(\"^[%a_][%w_]*\", pos)\r\nif id then pos = pos + #id; return tonumber((vars or {})[id]) or 0 end\r\npos = pos + 1\r\nreturn 0\r\nend\r\nfunction prod()\r\nlocal v = atom()\r\nwhile true do\r\nlocal ch = s0:sub(pos, pos)\r\nif ch == \"*\" then pos = pos + 1; v = v * atom()\r\nelseif ch == \"/\" then pos = pos + 1; local d = atom(); v = d ~= 0 and math.floor(v / d) or 0\r\nelse return v end\r\nend\r\nend\r\nfunction sum()\r\nlocal v = prod()\r\nwhile true do\r\nlocal ch = s0:sub(pos, pos)\r\nif ch == \"+\" then pos = pos + 1; v = v + prod()\r\nelseif ch == \"-\" then pos = pos + 1; v = v - prod()\r\nelse return v end\r\nend\r\nend\r\nlocal r = sum()\r\n\r\nif r ~= r or r == math.huge or r == -math.huge then return 0 end\r\nreturn math.max(-1000000, math.min(1000000, math.floor(r)))\r\nend\r\n\r\nfunction K.calcDice(expr, vars)\r\nlocal dice = {}\r\nlocal rest = tostring(expr or \"\"):gsub(\"%s\", \"\"):gsub(\"(%d*)d(%d+)\", function(n, sd) dice[#dice + 1] = (n ~= \"\" and n or \"1\") .. \"d\" .. sd; return \"0\" end)\r\nlocal n = K.calc(rest ~= \"\" and rest or \"0\", vars)\r\nlocal out = table.concat(dice, \"+\")\r\nif n ~= 0 or out == \"\" then out = out .. (out ~= \"\" and string.format(\"%+d\", n) or tostring(n)) end\r\nreturn out\r\nend\r\nfunction K.packSummonRow(ps, lvl, st, choice)\r\nlocal v = { LVL = lvl, SPELL_ATK = st.atk or 0, SPELL_DC = st.dc or 10, MOD = st.mod or 0, PB = PROF or 2 }\r\nlocal s1 = ps.st\r\n\r\n\r\nlocal bc = choice and type(ps.by_choice) == \"table\" and ps.by_choice[choice]\r\nif type(bc) == \"table\" then\r\nlocal m = {}\r\nfor k, x in pairs(s1) do m[k] = x end\r\nfor k, x in pairs(bc) do m[k] = x end\r\ns1 = m\r\nend\r\nlocal row = { ac = K.calc(s1.ac or 10, v), hp = math.max(1, K.calc(s1.hp or 10, v)), init = tonumber(s1.init) or 0, speed = tonumber(s1.speed) or 30,\r\ncr = \"0\", xp = 0, saves = type(s1.saves) == \"table\" and s1.saves or {}, res = s1.res, imm = s1.imm, cimm = s1.cimm,\r\nfly = s1.fly and true or nil, swim = s1.swim and true or nil, ko = ps.ko, what = s1.what or ps.what or \"Medium Spirit\",\r\nctypes = (type(s1.ctypes) == \"table\" and s1.ctypes) or (type(ps.ctypes) == \"table\" and ps.ctypes) or nil, acts = s1.acts, attacks = {} }\r\nfor _, a in ipairs(type(s1.attacks) == \"table\" and s1.attacks or {}) do\r\nrow.attacks[#row.attacks + 1] = { name = a.name, hit = a.hit and K.calc(a.hit, v) or (st.atk or 0), dmg = K.calcDice(a.dmg or \"1d6\", v), type = a.type }\r\nend\r\nif s1.multi == \"half\" then row.multi = math.max(1, math.floor(lvl / 2)) .. \" attacks (half the spell's level)\"\r\nelseif s1.multi then row.multi = tostring(s1.multi) end\r\nif choice and choice ~= \"\" then row.acts = (row.acts and (row.acts .. \"; \") or \"\") .. \"kind: \" .. choice end\r\nreturn row\r\nend\r\n\r\nfunction K.crNum(v) local a, b = tostring(v or \"\"):match(\"^(%d+)/(%d+)$\"); return a and tonumber(a) / tonumber(b) or tonumber(v) or 99 end\r\n\r\nfunction K.summonFeatAll(pc)\r\nlocal o = {}\r\nfor _, e in ipairs(Feat.fxOf(SHEET, \"summon\")) do o[#o + 1] = e.name end\r\nfor _, a in ipairs(Ally.list(pc)) do\r\nif not a.dead and type(a.sheet) == \"table\" then\r\nfor _, e in ipairs(Feat.fxOf(a.sheet, \"summon\")) do o[#o + 1] = a.name .. \"/\" .. e.name end\r\nend\r\nend\r\nreturn o\r\nend\r\nfunction K.summonFeatFind(raw, pc)\r\nlocal who, fname = raw:match(\"^(.-)%s*/%s*(.+)$\")\r\nfname = fname or raw\r\nif not who or who == \"Player\" or who == pc.name then\r\nfor _, e in ipairs(Feat.fxOf(SHEET, \"summon\")) do if e.name == fname then return e, nil end end\r\nend\r\nfor _, a in ipairs(Ally.list(pc)) do\r\nif (not who or a.name == who) and type(a.sheet) == \"table\" then\r\nfor _, e in ipairs(Feat.fxOf(a.sheet, \"summon\")) do if e.name == fname then return e, a end end\r\nend\r\nend\r\nreturn nil\r\nend\r\n\r\nfunction K.summonLimits(e, sh)\r\nlocal lv = tonumber(e.srcLv) or (e.srcClass and K.cl(sh, e.srcClass)) or tonumber(sh.level) or 1\r\nlocal o = { lv = lv, fly = true }\r\nif e.cr == \"wildshape\" then\r\nlocal row = K.rowOf(sh, \"Druid\")\r\no.cr, o.fly = K.crNum(row.forms or \"0\"), row.fly and true or false\r\no.crText = tostring(row.forms or \"0\")\r\nelseif type(e.cr) == \"string\" and e.cr:match(\"^LEVEL/%d+$\") then\r\no.cr = lv / tonumber(e.cr:match(\"(%d+)$\"))\r\nelseif e.cr ~= nil then\r\no.cr = K.crNum(e.cr)\r\nend\r\nif o.cr and not o.crText then\r\nlocal best = \"0\"\r\nfor _, x in ipairs({ \"1/8\", \"1/4\", \"1/2\", \"1\", \"2\", \"3\", \"4\", \"5\", \"6\", \"7\", \"8\", \"9\", \"10\", \"11\", \"12\", \"13\", \"14\", \"15\", \"16\", \"17\", \"18\", \"19\", \"20\" }) do\r\nif K.crNum(x) <= o.cr then best = x end\r\nend\r\no.crText = best\r\nend\r\no.sizes = type(e.size) == \"table\" and e.size or nil\r\nlocal at = -1\r\nfor k, v in pairs(type(e.size_at) == \"table\" and e.size_at or {}) do\r\nif tonumber(k) and tonumber(k) <= lv and tonumber(k) > at then at = tonumber(k); o.sizes = v ~= \"any\" and v or nil end\r\nend\r\nlocal mx = e.max or 1\r\nat = -1\r\nfor k, v in pairs(type(e.max_at) == \"table\" and e.max_at or {}) do\r\nif tonumber(k) and tonumber(k) <= lv and tonumber(k) > at then at = tonumber(k); mx = v end\r\nend\r\nif type(mx) == \"string\" and mx:match(\"^%u%u%u$\") then mx = mx .. \"1\" end\r\no.most = math.max(1, K.fxNum(mx, sh, lv))\r\nif e.lasts == \"hours:half_level\" then o.mins = math.max(1, math.floor(lv / 2)) * 60\r\nelseif type(e.lasts) == \"string\" and e.lasts:match(\"^hours:%d+$\") then o.mins = tonumber(e.lasts:match(\"(%d+)$\")) * 60\r\nelseif type(e.lasts) == \"string\" and e.lasts:match(\"^mins:%d+$\") then o.mins = tonumber(e.lasts:match(\"(%d+)$\")) end\r\nreturn o\r\nend\r\n\r\nfunction K.summonFits(m, e, lim)\r\nif type(m) ~= \"table\" then return false, \"not a stat block Lua has\" end\r\nlocal size = tostring(m.what or \"\"):match(\"^(%a+)\") or \"\"\r\nif type(e.types) == \"table\" then\r\nlocal ok = false\r\nfor _, ty in ipairs(e.types) do\r\nfor _, ct in ipairs(m.ctypes or {}) do if ct == ty or ct == \"Pure \" .. ty then ok = true end end\r\nif ty == \"Beast\" and m.beast then ok = true end\r\nend\r\nif not ok then return false, \"not a \" .. table.concat(e.types, \" or \") end\r\nend\r\nif lim.cr and K.crNum(m.cr) > lim.cr then return false, \"CR \" .. lim.crText .. \" at most\" end\r\nif m.fly and not lim.fly then return false, \"no Fly Speed yet (its Wild Shape's)\" end\r\nif lim.sizes then\r\nlocal ok = false\r\nfor _, z in ipairs(lim.sizes) do if z == size then ok = true end end\r\nif not ok then return false, table.concat(lim.sizes, \" or \") .. \" only\" end\r\nend\r\nreturn true\r\nend\r\n\r\nfunction K.summonPicks(e, lim, n)\r\nlocal o = {}\r\nfor k, m in pairs(MONSTERS) do if type(m) == \"table\" and not m.summonRow and K.summonFits(m, e, lim) then o[#o + 1] = k end end\r\ntable.sort(o)\r\nlocal more = #o > n\r\nwhile #o > n do table.remove(o) end\r\nreturn o, more\r\nend\r\n\r\nfunction K.summonScale(base, sc, sh, lv, cls)\r\nlocal row = deepCopy(base)\r\nsc = type(sc) == \"table\" and sc or {}\r\n\r\n\r\nlocal vars = { LEVEL = lv, PB = 2 + math.floor((K.charLevel(sh) - 1) / 4) }\r\nfor ab, k in pairs({ Strength = \"STR\", Dexterity = \"DEX\", Constitution = \"CON\", Intelligence = \"INT\", Wisdom = \"WIS\", Charisma = \"CHA\" }) do\r\nvars[k] = abilityMod(K.score(sh, ab))\r\nend\r\nlocal sa = (CLASSES[cls or \"\"] or {}).spell_ability\r\nlocal sm = sa and abilityMod(K.score(sh, sa)) or math.max(vars.INT, vars.WIS, vars.CHA)\r\nvars.SPELL_ATK, vars.SPELL_DC = vars.PB + sm, 8 + vars.PB + sm\r\nlocal function v(t) return tonumber(t) or K.calc(t, vars) end\r\nif sc.ac then row.ac = v(sc.ac) end\r\nif sc.hp then row.hp = math.max(1, v(sc.hp) * (sc.hp_per and v(sc.hp_per) or 1)) end\r\nfor _, a in ipairs(type(row.attacks) == \"table\" and row.attacks or {}) do\r\nif sc.atk then a.hit = v(sc.atk) end\r\nlocal d = tostring(a.dmg or \"\"):match(\"^(%d*d%d+)\")\r\nif sc.dmg and d then local m = v(sc.dmg); a.dmg = d .. (m ~= 0 and string.format(\"%+d\", m) or \"\") end\r\nend\r\nfor _, x in ipairs(type(row.sfx) == \"table\" and row.sfx or {}) do if sc.dc then x.dc = v(sc.dc) end end\r\nrow.cr, row.xp = \"0\", 0\r\nreturn row\r\nend\r\n\r\nfunction K.summonFeatTag(f, c, pc, clock, e, by)\r\nlocal head = \"[SUMMON|\" .. table.concat(f, \"|\")\r\nlocal function fail(why) return head .. \"|bad:\" .. why .. \"|-]\", false end\r\nlocal owner = by and by.name or \"Player\"\r\nlocal rec = by or pc\r\nif rec.dead then return fail(owner .. \" is dead\") end\r\nlocal sh = by and by.sheet or SHEET\r\nlocal lim = K.summonLimits(e, sh)\r\nlocal count = tonumber(trim(f[3] or \"\")) or 1\r\nif count < 1 or count ~= math.floor(count) then return fail(\"count: a whole number\") end\r\nif count > lim.most then return fail(lim.most .. \" at a time at most\") end\r\nlocal kind, row\r\nif e.row then\r\nlocal base = MONSTERS[e.row]\r\nif type(base) ~= \"table\" then return fail(\"no stat block \" .. e.row .. \" (its module's monsters)\") end\r\nrow = K.summonScale(base, e.scale, sh, lim.lv, e.srcClass)\r\nkind = e.row .. \" (\" .. owner .. \")\"\r\nelse\r\nlocal choice = Canon.name(trim(f[2] or \"\"))\r\nlocal m = MONSTERS[choice]\r\nif not m then\r\nfor en, r in pairs(MONSTERS) do if type(r) == \"table\" and r.ko == trim(f[2] or \"\") then choice, m = en, r end end\r\nend\r\nlocal ok, why = K.summonFits(m, e, lim)\r\nif not ok then\r\nlocal picks, more = K.summonPicks(e, lim, 12)\r\nreturn fail((m and (choice .. \": \" .. why) or (\"write the creature: \" .. why)) .. (#picks > 0 and (\"; it may be \" .. table.concat(picks, \", \") .. (more and \", …\" or \"\")) or \"\"))\r\nend\r\nkind = choice\r\nif e.as_type then\r\n\r\nrow = deepCopy(m)\r\nrow.ctypes, row.beast = { e.as_type }, nil\r\nrow.what = ((m.what or \"\"):match(\"^(%a+)\") or \"Medium\") .. \" \" .. e.as_type\r\nrow.cr, row.xp = \"0\", 0\r\nkind = choice .. \" (\" .. e.name .. (owner ~= \"Player\" and (\", \" .. owner) or \"\") .. \")\"\r\nend\r\nend\r\n\r\n\r\nif e.mind == \"owner\" and type(sh) == \"table\" then\r\nif not row then\r\nrow = deepCopy(MONSTERS[kind])\r\nrow.cr, row.xp = \"0\", 0\r\nkind = kind .. \" (\" .. e.name .. (owner ~= \"Player\" and (\", \" .. owner) or \"\") .. \")\"\r\nend\r\nrow.saves = type(row.saves) == \"table\" and row.saves or {}\r\nrow.sc = type(row.sc) == \"table\" and row.sc or {}\r\nfor _, ab in ipairs({ \"Intelligence\", \"Wisdom\", \"Charisma\" }) do\r\nlocal sc = K.score(sh, ab)\r\nif tonumber(sc) then row.sc[ab], row.saves[ab] = sc, abilityMod(sc) end\r\nend\r\nend\r\n\r\nlocal spend\r\nif e.ritual then\r\nif c.active then return fail(\"a 10-minute ritual: not in a fight\") end\r\nelseif e.free then\r\n\r\nelse\r\nlocal k, n = e.pool, (tonumber(e.n) or 1) * count\r\nrec.res = type(rec.res) == \"table\" and rec.res or {}\r\nif (tonumber(rec.res[k]) or 0) < n then return fail(K.MP.short(rec, k, n) or (\"no \" .. k .. \" left (\" .. n .. \" needed)\")) end\r\nrec.res[k] = rec.res[k] - n\r\nspend = k .. \" \" .. rec.res[k] .. \" left\"\r\nend\r\nif row then row.summonRow = true; MONSTERS[kind] = row end\r\npc.summons = type(pc.summons) == \"table\" and pc.summons or {}\r\n\r\nlocal mine = {}\r\nfor i, s in ipairs(pc.summons) do\r\nif (s.spell == e.name or (e.group and s.group == e.group)) and s.by == owner then mine[#mine + 1] = i end\r\nend\r\nlocal gone = {}\r\nfor j = #mine + count - lim.most, 1, -1 do\r\nlocal i = mine[j]\r\nif i then\r\nlocal s = table.remove(pc.summons, i)\r\ngone[#gone + 1] = s.name\r\nif c.units and c.units[s.name] then c.units[s.name] = nil end\r\nfor q = #(c.order or {}), 1, -1 do if c.order[q] == s.name then table.remove(c.order, q) end end\r\nif pc.mount == s.name then pc.mount = nil end\r\nend\r\nend\r\nlocal now = (type(clock) == \"table\" and tonumber(clock.min)) or 0\r\nif e.ritual and type(clock) == \"table\" then clock.min = (tonumber(clock.min) or 0) + 10; now = clock.min end\r\nlocal stb = row or MONSTERS[kind]\r\nlocal made = {}\r\nfor _ = 1, count do\r\nlocal s = { name = K.summonName(pc, c, kind), kind = kind, st = row, hp = stb.hp, max = stb.hp, spell = e.name, by = owner, feat = true,\r\nends = lim.mins and (now + lim.mins) or nil, as = e.as_type, obey = e.obey, range = tonumber(e.range),\r\nrowOf = e.row, scale = e.row and e.scale or nil, cls = e.srcClass, group = e.group }\r\npc.summons[#pc.summons + 1] = s\r\nmade[#made + 1] = s.name\r\nif c.active then K.summonJoin(c, s) end\r\nend\r\nreturn head .. \"|ok|\" .. table.concat(made, \", \") .. \" (HP \" .. stb.hp .. (lim.mins and (\", \" .. K.spanText(lim.mins)) or \"\")\r\n.. (spend and (\", \" .. spend) or \"\") .. (e.ritual and \", 10 minutes\" or \"\") .. (#gone > 0 and (\"; gone: \" .. table.concat(gone, \", \")) or \"\") .. \")]\", true\r\nend\r\n\r\nfunction K.summonFeatLine(e, sh, rec)\r\nlocal lim = K.summonLimits(e, sh)\r\nlocal who = rec.name\r\nlocal tag = \"[SUMMON|\" .. (who and (who .. \"/\") or \"\") .. e.name .. \"|\" .. (e.row and \"-\" or \"creature\") .. \"|count]\"\r\nlocal cost = e.ritual and \"a 10-minute ritual out of a fight (Lua adds the time), no use\"\r\nor string.format(\"%d %s use each\", tonumber(e.n) or 1, e.pool)\r\nlocal what\r\nif e.row then\r\nlocal m = MONSTERS[e.row]\r\nwhat = (m and m.ko or e.row) .. \" (its stat block with \" .. (who or \"Player\") .. \"'s numbers)\"\r\nelse\r\nlocal picks, more = K.summonPicks(e, lim, 10)\r\nlocal parts = {}\r\nif type(e.types) == \"table\" then parts[#parts + 1] = table.concat(e.types, \" or \") end\r\nif lim.cr then parts[#parts + 1] = \"of CR \" .. lim.crText .. \" or lower\" end\r\nif lim.sizes then parts[#parts + 1] = table.concat(lim.sizes, \" or \") end\r\nlocal w = table.concat(parts, \" \")\r\nwhat = (w:match(\"^[AEIOU]\") and \"an \" or \"a \") .. w .. (e.as_type and (\" (it counts as a \" .. e.as_type .. \")\") or \"\")\r\n.. (#picks > 0 and (\": \" .. table.concat(picks, \", \") .. (more and \", …\" or \"\")) or \": none Lua has yet\")\r\nend\r\nreturn string.format(\"%s: %s spends %s and makes %s; up to %d at a time%s (one more sends the oldest away)%s; Lua keeps its HP like a spell's summon\",\r\ne.name, tag, cost, what, lim.most, e.group and (\", counted with the rest of \" .. e.group) or \"\", lim.mins and (\", each lasts \" .. K.spanText(lim.mins)) or \", each lasts until it drops to 0 HP\")\r\nend\r\n\r\n\r\n\r\nfunction K.swapType(by, pc, what, dtype, traits, dmg)\r\nlocal sh = K.ownSheet(by or pc, pc)\r\nif not (sh and dtype and (tonumber(dmg) or 0) > 0) then return dtype, \"\" end\r\nlocal best, bestN\r\nfor _, e in ipairs(Feat.fxOf(sh, \"dtype_swap\")) do\r\nlocal fits = (what.form and e.form) or (what.unarmed and e.unarmed) or false\r\nif not fits and what.spell and e.spells then\r\nlocal sp = SPELLS[what.spell]\r\nif type(e.spells) == \"string\" then\r\nfor _, cl in ipairs(sp and sp.classes or {}) do if cl == e.spells then fits = true end end\r\nelse\r\nfor _, n in ipairs(e.spells) do if n == what.spell then fits = true end end\r\nend\r\nend\r\nif fits then\r\nif not best then best, bestN = dtype, (Feat.adjust(traits, dmg, dtype)) end\r\nfor _, ty in ipairs(type(e.into) == \"table\" and e.into or { e.into }) do\r\nlocal n = Feat.adjust(traits, dmg, ty)\r\nif n > bestN then best, bestN = ty, n end\r\nend\r\nend\r\nend\r\n\r\nif what.pact then\r\nif not best then best, bestN = dtype, (Feat.adjust(traits, dmg, dtype)) end\r\nfor _, ty in ipairs({ \"Necrotic\", \"Psychic\", \"Radiant\" }) do\r\nlocal n = Feat.adjust(traits, dmg, ty)\r\nif n > bestN then best, bestN = ty, n end\r\nend\r\nend\r\nif best and best ~= dtype then return best, \" (as \" .. best .. \")\" end\r\nreturn dtype, \"\"\r\nend\r\n\r\n\r\n\r\n\r\n\r\nfunction K.spellDtype(dtype, traits, dmg)\r\nif type(dtype) ~= \"string\" then return dtype, \"\" end\r\nlocal list = dtype:match(\"^choice %(([^)]*)%)\") or (dtype:find(\" or \", 1, true) and dtype)\r\nif list then\r\nlocal best, bestN\r\nfor ty in list:gmatch(\"%a+\") do\r\nif K.DMG_KO and K.DMG_KO[ty] then\r\nlocal n = Feat.adjust0(traits, 100, ty)\r\nif not best or n > bestN then best, bestN = ty, n end\r\nend\r\nend\r\nreturn best, best and (\" (as \" .. best .. \")\") or \"\"\r\nend\r\nlocal one = dtype:match(\"^(%a+) %(\")\r\nif one then return one, \"\" end\r\nreturn dtype, \"\"\r\nend\r\n\r\n\r\nfunction K.typedAdjust(traits, dmg, dtype, m)\r\nlocal a, b = tostring(dtype or \"\"):match(\"^(%a+) and (%a+)$\")\r\nif not (a and (tonumber(dmg) or 0) > 0) then\r\nlocal n, note = Feat.adjust(traits, dmg, a or dtype)\r\nreturn n, note, a or dtype\r\nend\r\n\r\nlocal w = {}\r\nfor term in tostring(type(m) == \"table\" and m.damage or \"\"):gsub(\"%s\", \"\"):gmatch(\"[^+]+\") do\r\nlocal n, sz = term:match(\"^(%d+)d(%d+)$\")\r\nw[#w + 1] = n and { tonumber(n) * (tonumber(sz) + 1) / 2, true } or { tonumber(term) or 0, false }\r\nend\r\nlocal wa, wb, lastD = 0, 0, nil\r\nfor i, x in ipairs(w) do if x[2] then lastD = i end end\r\nfor i, x in ipairs(w) do if i == lastD then wb = x[1] else wa = wa + x[1] end end\r\nif wa <= 0 or wb <= 0 then wa, wb = 1, 1 end\r\nlocal pa = math.floor(dmg * wa / (wa + wb) + 0.5)\r\nlocal na = Feat.adjust(traits, pa, a)\r\nlocal nb = Feat.adjust(traits, dmg - pa, b)\r\nlocal note = (na ~= pa or nb ~= dmg - pa) and string.format(\" (%s %d, %s %d)\", a, na, b, nb) or \"\"\r\nreturn na + nb, note, dtype\r\nend\r\n\r\nfunction K.isType(dtype, t)\r\nif dtype == t then return true end\r\nreturn type(dtype) == \"string\" and type(t) == \"string\" and (\" and \" .. dtype .. \" and \"):find(\" and \" .. t .. \" and \", 1, true) ~= nil\r\nend\r\n\r\nfunction K.spellStimOf(by, spell, pc)\r\nif not K.AR.on() then return nil end\r\nlocal sp = SPELLS[spell or \"\"]\r\nlocal sh = sp and K.AR.sheetOf(by, pc)\r\nif not sh then return nil end\r\nfor _, e in ipairs(Feat.fxOf(sh, \"spell_stim\")) do\r\nlocal on, own = false, false\r\nif type(e.list) == \"table\" then\r\nfor _, x in ipairs(e.list) do if x == spell then on = true end end\r\nelse\r\nfor _, k in ipairs(sp.classes or {}) do\r\nif k == e.list then on = true end\r\nif k == (e.srcClass or sh.class) then own = true end\r\nend\r\nend\r\nif on and not own then return e end\r\nend\r\nreturn nil\r\nend\r\n\r\nfunction K.spellStimGive(tname, u, amt, dtype, by, pc, c, crit)\r\nlocal t = u\r\nif u.loose then t = K.AR.target(tname, c, pc) end\r\nif not t then return string.format(\" (as %d %s stimulation: no scene creature to keep it, the story's)\", amt, dtype), \"\" end\r\nlocal text, extra = K.AR.give(t, amt, pc, c, crit, tname, nil, { type = dtype, magical = true, by = (by == pc or not by) and \"Player\" or by.name })\r\nreturn \" (as \" .. dtype .. \" stimulation, no damage: \" .. text .. \")\", extra or \"\"\r\nend\r\n\r\n\r\n\r\n\r\nfunction K.heatTick(rec, sh, clock)\r\nif type(rec) ~= \"table\" or type(sh) ~= \"table\" or type(clock) ~= \"table\" then return end\r\nlocal e = Feat.fxOf(sh, \"heat_cycle\")[1]\r\nif not e then rec.heat = nil; return end\r\nlocal now = tonumber(clock.min) or 0\r\nrec.heat = type(rec.heat) == \"table\" and rec.heat or {}\r\nlocal h = rec.heat\r\nlocal p = type(sh.picks) == \"table\" and sh.picks or {}\r\nlocal pd = tonumber(p.heatday)\r\nif pd and h.picked ~= pd then h.next, h.picked = now + pd * 1440, pd end\r\nif not tonumber(h.next) then h.next = now + K.d(30) * 1440 end\r\nlocal every, days = (tonumber(e.every) or 30) * 1440, (tonumber(e.days) or 3) * 1440\r\nrec.cond = type(rec.cond) == \"table\" and rec.cond or {}\r\n\r\nlocal hEnd = tonumber(rec.cond[e.cond])\r\nif e.skip and rec.cond[e.skip] and hEnd and hEnd > now then rec.cond[e.cond], rec.cond[e.skip], h.on = nil, nil, nil end\r\n\r\n\r\nif h.next + every < now then\r\nif e.skip and rec.cond[e.skip] then rec.cond[e.skip] = nil end\r\nh.next = h.next + math.floor((now - h.next) / every) * every\r\nend\r\nfor _ = 1, 400 do\r\nif h.next > now then break end\r\nif e.skip and rec.cond[e.skip] then\r\nrec.cond[e.skip] = nil\r\nelseif h.next + days > now and CONDS[e.cond] then\r\nrec.cond[e.cond] = h.next + days\r\nh.on = h.next\r\nrec.condSrc = type(rec.condSrc) == \"table\" and rec.condSrc or {}\r\nrec.condSrc[e.cond] = e.src\r\nend\r\nh.next = h.next + every\r\nend\r\nend\r\n\r\nfunction K.omegaText(pc, clock)\r\nif K.D2.omega ~= \"on\" or not K.AR.on() then return nil end\r\nlocal o = {}\r\nlocal now = type(clock) == \"table\" and tonumber(clock.min) or 0\r\nfor _, r in ipairs({ pc, table.unpack(Ally.list(pc)) }) do\r\nlocal h = type(r.heat) == \"table\" and r.heat\r\nlocal e = h and Feat.fxOf((r == pc and SHEET) or r.sheet, \"heat_cycle\")[1]\r\nif e then\r\nlocal nm = r == pc and \"Player\" or r.name\r\nlocal endAt = type(r.cond) == \"table\" and tonumber(r.cond[e.cond])\r\nif endAt and endAt > now then\r\nlocal days = tonumber(e.days) or 3\r\no[#o + 1] = string.format(\"%s is in heat (day %d of %d)\", nm, math.min(days, math.floor((now - (tonumber(h.on) or now)) / 1440) + 1), days)\r\nelseif tonumber(h.next) then\r\no[#o + 1] = string.format(\"%s in %d days\", nm, math.max(0, math.ceil((h.next - now) / 1440)))\r\nend\r\nend\r\nend\r\nreturn \"Omegaverse world: every humanoid has a second gender (alpha, beta, omega); NPCs' are the story's.\"\r\n.. (#o > 0 and (\" Heat: \" .. table.concat(o, \"; \") .. \".\") or \"\")\r\nend\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\nK.IMPLANT_MINS = { [0] = 0, 1, 2, 5, 10, 30, 60, 120, 240, 480 }\r\nfunction K.rowMaxLv(row)\r\nif type(row) ~= \"table\" then return 0 end\r\nif tonumber(row.max_spell) then return tonumber(row.max_spell) end\r\nlocal m = 0\r\nfor i, n in ipairs(row.slots or {}) do if n > 0 then m = i end end\r\nreturn m\r\nend\r\n\r\nfunction K.implantClass(sh)\r\nif type(sh) ~= \"table\" then return nil end\r\nfor _, c in ipairs(K.classes(sh)) do\r\nlocal cl = CLASSES[c.name]\r\nif cl and type(cl.implant) == \"table\" then return c.name, cl.implant, c.level end\r\nend\r\nreturn nil\r\nend\r\nfunction K.implantNum(v, at, sh, lv)\r\nlocal best, bl = v, -1\r\nfor k, x in pairs(type(at) == \"table\" and at or {}) do\r\nif tonumber(k) and tonumber(k) <= lv and tonumber(k) > bl then best, bl = x, tonumber(k) end\r\nend\r\nreturn math.max(1, K.fxNum(best, sh, lv))\r\nend\r\nfunction K.implantTag(f, c, pc, clock, persona)\r\nlocal head = \"[IMPLANT|\" .. table.concat(f, \"|\")\r\nlocal function fail(why) return head .. \"|bad:\" .. why .. \"|-]\", false end\r\nlocal tname = trim(f[1] or \"\")\r\nlocal name = Canon.name(trim(f[2] or \"\"))\r\nlocal trig = trim(f[4] or \"\")\r\nlocal who = trim(f[5] or \"\") ~= \"\" and Canon.actor(trim(f[5]), persona) or \"Player\"\r\nlocal by = who ~= \"Player\" and Ally.find(pc, who) or nil\r\nif who ~= \"Player\" and not by then return fail(\"unknown companion \" .. who) end\r\nlocal rec = by or pc\r\nif rec.dead then return fail(who .. \" is dead\") end\r\nlocal sh = by and by.sheet or SHEET\r\nlocal cls, def, clv = K.implantClass(sh)\r\nif not cls then return fail(who .. \" has no class that implants spells\") end\r\nlocal sp = SPELLS[name]\r\nif not sp then return fail(K.spellOff(name) or \"unknown spell\") end\r\nif trig == \"\" or trig == \"-\" then return fail(\"write its trigger: [IMPLANT|Target|Spell|level|a word or a gesture]\") end\r\nif not Ally.run(pc, by, function() return Spell.known(name) end) then return fail(name .. \" is not among \" .. who .. \"'s prepared spells\") end\r\nlocal maxLv = K.rowMaxLv(K.rowAt(sh, cls, clv))\r\nlocal level = tonumber(trim(f[3] or \"\")) or sp.level\r\nif level ~= math.floor(level) or level < 0 then return fail(\"level: a whole number (0 for a cantrip)\") end\r\nif level < sp.level then level = sp.level end\r\nif level > maxLv then return fail(string.format(\"level %d at most (%s %d)\", maxLv, cls, clv)) end\r\nif Ally.rec(pc, tname) then return fail(\"an implant goes into a creature of the fight or the scene\") end\r\nlocal u = K.AR.target(tname, c, pc)\r\nif not u then return fail(\"target must be a creature in the fight or in the scene\") end\r\n\r\nlocal cns = type(def.cond) == \"table\" and def.cond or { def.cond or \"Mesmerized\" }\r\nlocal on = false\r\nfor _, n in ipairs(K.foeCondFx(u, pc).list) do for _, cn in ipairs(cns) do if n == cn then on = true end end end\r\nif not on then return fail(tname .. \" is not \" .. table.concat(cns, \" or \")) end\r\nlocal mins = K.IMPLANT_MINS[math.min(9, level)] or 0\r\nlocal mul = 1\r\nfor _, e in ipairs(Feat.fxOf(sh, \"implant_time\")) do mul = mul * (tonumber(e.mul) or 1) end\r\n\r\nlocal exact = mins * mul\r\nmins = exact >= 1 and math.ceil(exact) or exact\r\nlocal span = (mins > 0 and mins < 1) and (math.floor(mins * 60 + 0.5) .. \" seconds\") or K.spanText(mins)\r\n\r\nif type(Feat.cur.implantNow) == \"table\" and Feat.cur.implantNow[tname] then mins, span = 0, \"no time\"; Feat.cur.implantNow[tname] = nil end\r\nif mins > 0 and c.active then return fail(string.format(\"a level %d implant takes %s: not in a fight\", level, span)) end\r\n\r\nlocal perDay = math.huge\r\nlocal pdv = def.per_day or \"PB\"\r\nfor k, x in pairs(type(def.per_day_at) == \"table\" and def.per_day_at or {}) do if tonumber(k) and tonumber(k) <= clv then pdv = x end end\r\nif not (pdv == 0 or pdv == \"0\" or pdv == \"none\") then perDay = K.implantNum(pdv, def.per_day_at, sh, clv) end\r\n\r\nlocal tInt = tonumber(((MONSTERS[u.kind or \"\"] or {}).saves or {}).Intelligence) or 0\r\nlocal hv = def.hold or \"INT+PB\"\r\nfor k, x in pairs(type(def.hold_at) == \"table\" and def.hold_at or {}) do if tonumber(k) and tonumber(k) <= clv then hv = x end end\r\nlocal hold = math.max(1, K.fxNum((tostring(hv):gsub(\"%f[%a]INT%f[%A]\", \"0\")), sh, clv) + (tostring(hv):find(\"%f[%a]INT%f[%A]\") and tInt or 0))\r\nlocal now = tonumber(type(clock) == \"table\" and clock.min) or 0\r\nlocal day = math.floor(now / 1440)\r\npc.implants = type(pc.implants) == \"table\" and pc.implants or {}\r\npc.implDay = type(pc.implDay) == \"table\" and pc.implDay or {}\r\nlocal d0 = pc.implDay[tname]\r\nlocal made = (type(d0) == \"table\" and d0.day == day) and (tonumber(d0.n) or 0) or 0\r\nif made >= perDay then return fail(string.format(\"%d implants a day in one creature (%s: %d today)\", perDay, tname, made)) end\r\nif type(clock) == \"table\" and mins >= 1 then clock.min = now + mins end\r\nlocal list = pc.implants[tname] or {}\r\nlist[#list + 1] = { spell = name, level = level, trigger = trig, by = who }\r\nlocal lost = {}\r\nwhile #list > hold do lost[#lost + 1] = table.remove(list, 1).spell end\r\npc.implants[tname] = list\r\npc.implDay[tname] = { day = day, n = made + 1 }\r\nif c.active then c.last = who end\r\nreturn head .. \"|ok|\" .. name .. \" level \" .. level .. \" on \\\"\" .. trig .. \"\\\", \" .. (mins > 0 and span or \"an action\")\r\n.. string.format(\", %d/%d held\", #list, hold) .. (#lost > 0 and (\"; lost: \" .. table.concat(lost, \", \")) or \"\") .. \"]\", true\r\nend\r\nfunction K.triggerTag(f, c, pc, ctx, persona)\r\nlocal head = \"[TRIGGER|\" .. table.concat(f, \"|\")\r\nlocal function fail(why) return head .. \"|bad:\" .. why .. \"|-]\", false end\r\nlocal tname = trim(f[1] or \"\")\r\nlocal name = Canon.name(trim(f[2] or \"\"))\r\nlocal list = type(pc.implants) == \"table\" and pc.implants[tname] or nil\r\nlocal at\r\nfor i, x in ipairs(list or {}) do if x.spell == name and not at then at = i end end\r\nif not at then\r\nlocal o = {}\r\nfor _, x in ipairs(list or {}) do o[#o + 1] = x.spell end\r\nreturn fail(tname .. \" holds no implanted \" .. name .. (#o > 0 and (\" (it holds \" .. table.concat(o, \", \") .. \")\") or \"\"))\r\nend\r\nlocal x = list[at]\r\nlocal by = x.by ~= \"Player\" and Ally.find(pc, x.by) or nil\r\nif x.by ~= \"Player\" and not by then return fail(x.by .. \" is not in the party\") end\r\nif (by or pc).dead then return fail(x.by .. \" is dead\") end\r\nif ctx.rolls then ctx.rolls[name] = nil end\r\nctx.implantCast, ctx.implantLevel, ctx.implantOn = name, x.level, tname\r\nlocal ok, line, good = pcall(function()\r\nif by then return Ally.with(by, Spell.cast, { name, tostring(x.level), by.name }, by, c, ctx) end\r\nreturn Spell.cast({ name, tostring(x.level) }, pc, c, ctx)\r\nend)\r\nctx.implantCast, ctx.implantLevel, ctx.implantOn = nil, nil, nil\r\nif not ok then error(line, 0) end\r\nif not good then return fail((line:match(\"|bad:([^|%]]*)\") or \"not cast\")) end\r\ntable.remove(list, at)\r\nif #list == 0 then pc.implants[tname] = nil end\r\nFeat.cur.implantFail = Feat.cur.implantFail or {}\r\nFeat.cur.implantFail[name .. \"|\" .. tname] = true\r\nreturn head .. \"|ok|\" .. name .. \" level \" .. x.level .. \" cast on \" .. tname .. \" by \" .. x.by .. \", no slot: its first save fails]\", true\r\nend\r\n\r\nfunction K.implantText(pc, c)\r\nlocal casters, cn = {}, nil\r\nlocal n0, d0 = K.implantClass(SHEET)\r\nif n0 then casters[#casters + 1] = \"Player\"; cn = d0.cond end\r\nfor _, a in ipairs(Ally.list(pc)) do\r\nlocal n1, d1 = K.implantClass(type(a.sheet) == \"table\" and a.sheet or nil)\r\nif n1 and not a.dead then casters[#casters + 1] = a.name; cn = cn or d1.cond end\r\nend\r\ncn = cn or \"Mesmerized\"\r\nlocal cnl = type(cn) == \"table\" and cn or { cn }\r\ncn = table.concat(cnl, \" or \")\r\nlocal held = {}\r\nfor t, list in pairs(type(pc.implants) == \"table\" and pc.implants or {}) do\r\nlocal o = {}\r\nfor _, x in ipairs(list) do o[#o + 1] = string.format(\"%s level %d (%s's) on \\\"%s\\\"\", x.spell, x.level, x.by, x.trigger) end\r\nif #o > 0 then held[#held + 1] = t .. \": \" .. table.concat(o, \"; \") end\r\nend\r\ntable.sort(held)\r\nif #casters == 0 and #held == 0 then return nil end\r\nlocal mz = {}\r\nlocal function scan(units)\r\nfor nm, u in pairs(type(units) == \"table\" and units or {}) do\r\nif type(u) == \"table\" and (tonumber(u.hp) or 1) > 0 then\r\nlocal hit = false\r\nfor _, x in ipairs(K.foeCondFx(u, pc).list) do for _, y in ipairs(cnl) do if x == y then hit = true end end end\r\nif hit then mz[#mz + 1] = nm end\r\nend\r\nend\r\nend\r\nif type(c) == \"table\" and c.active then scan(c.units) end\r\nif type(pc.scene) == \"table\" then scan(pc.scene.units) end\r\ntable.sort(mz)\r\nreturn \"Implanted spells: \" .. (#casters > 0 and (table.concat(casters, \", \") .. \" cast with no slots: [IMPLANT|Target|Spell|level|trigger] (a companion's name as a fifth field) puts a prepared spell\"\r\n.. \" into a \" .. cn .. \" creature; Lua moves the clock by its time (a cantrip: an action; level 1: 1 minute, 2: 2, 3: 5, 4: 10, 5: 30, 6: 1 hour, 7: 2,\"\r\n.. \" 8: 4, 9: 8; not in a fight unless a cantrip). [TRIGGER|Target|Spell] when its trigger comes casts it on that creature with no slot, its first\"\r\n.. \" save failing; then write the spell's SAVE or other tags as after a CAST. \") or \"\")\r\n.. cn .. \" now: \" .. (#mz > 0 and table.concat(mz, \", \") or \"nobody\") .. \". Held: \" .. (#held > 0 and table.concat(held, \" | \") or \"none\") .. \".\"\r\nend\r\n\r\n\r\n\r\n\r\n\r\nK.ENV = {\r\n{ w = { \"추위\", \"추운\", \"한파\", \"혹한\", \"눈보라\", \"설원\", \"설산\", \"빙하\", \"얼어붙\", \"영하\", \"cold\", \"freez\", \"blizzard\", \"arctic\" },\r\nt = \"Extreme Cold (0 °F or lower): at the end of each hour exposed, a DC 10 Constitution save, [CHECK|Constitution save|d20|+bonus|10|success/failure] (a companion's: Name/Constitution save), and on a failure [COND|+Exhaustion]; Resistance or Immunity to Cold passes it.\" },\r\n{ w = { \"얼음물\", \"차가운 물\", \"얼음 호수\", \"빙판 아래\", \"frigid\", \"icy water\" },\r\nt = \"Frigid Water: a creature lasts as many minutes as its Constitution score, then each minute a DC 10 Constitution save ([CHECK|Constitution save|...]) or [COND|+Exhaustion]; Cold Resistance passes it.\" },\r\n{ w = { \"더위\", \"폭염\", \"사막\", \"열사\", \"작열\", \"찜통\", \"heat\", \"desert\", \"scorching\" },\r\nt = \"Extreme Heat (100 °F or higher) without drinkable water: at the end of each hour a Constitution save, DC 5 the first hour and 1 more each hour after, or [COND|+Exhaustion]; Medium or Heavy armor gives Disadvantage on it; Fire Resistance passes it.\" },\r\n{ w = { \"고산\", \"산꼭대기\", \"높은 산\", \"고지대\", \"altitude\", \"summit\" },\r\nt = \"High Altitude (10,000 ft or more): each hour of travel counts as two for how long one can travel; 30 days there acclimate (not above 20,000 ft).\" },\r\n{ w = { \"숨을 참\", \"숨 참\", \"질식\", \"익사\", \"잠수\", \"물에 빠\", \"물속\", \"수중\", \"가라앉\", \"drown\", \"suffocat\", \"hold its breath\", \"hold my breath\", \"underwater\" },\r\nt = \"Suffocation: one holds the breath for 1 + Constitution modifier minutes (at least 30 seconds); then each turn's end brings [COND|+Exhaustion], all of it gone once breathing again. A fight underwater: add underwater to the COMBAT tag, e.g. [COMBAT|Merrow|underwater].\" },\r\n{ w = { \"심해\", \"깊은 물\", \"깊은 바다\", \"deep water\" },\r\nt = \"Deep Water (more than 100 ft deep): after each hour of swimming, without a Swim Speed, a DC 10 Constitution save or [COND|+Exhaustion].\" },\r\n{ w = { \"빙판\", \"얼음 위\", \"미끄러운 얼음\", \"slippery ice\", \"ice floor\" },\r\nt = \"Slippery Ice: Difficult Terrain; moving onto it the first time in a turn or starting a turn there, a DC 10 Dexterity save or [COND|+Prone].\" },\r\n{ w = { \"얇은 얼음\", \"얼음이 깨\", \"thin ice\" },\r\nt = \"Thin Ice: holds 3d10 x 10 lb on each 10-ft square; more breaks it and those on it fall into frigid water.\" },\r\n{ w = { \"강풍\", \"돌풍\", \"폭풍우\", \"모래폭풍\", \"strong wind\", \"gale\", \"sandstorm\" },\r\nt = \"Strong Wind: Disadvantage on ranged weapon attack rolls (write dis A,B), open flames go out, fog disperses, a flyer must land at the end of its turn or fall; a sandstorm gives Disadvantage on Wisdom (Perception) checks.\" },\r\n{ w = { \"폭우\", \"폭설\", \"장대비\", \"heavy rain\", \"heavy snow\", \"downpour\" },\r\nt = \"Heavy Precipitation: everything there is Lightly Obscured, Disadvantage on Wisdom (Perception) checks; heavy rain puts out open flames.\" },\r\n}\r\nfunction K.envText(userText)\r\nlocal s = tostring(userText or \"\"):lower()\r\nif s == \"\" then return nil end\r\nlocal o = {}\r\nfor _, e in ipairs(K.ENV) do\r\nfor _, w in ipairs(e.w) do\r\nif s:find(w, 1, true) then o[#o + 1] = e.t; break end\r\nend\r\nend\r\nif #o == 0 then return nil end\r\nreturn \"[ENVIRONMENT] SRD rules for where the words go (Lua counts the tags): \" .. table.concat(o, \" \")\r\nend\r\n\r\n\r\nfunction K.MI.text(name, l, n)\r\nlocal m = K.MAGIC[l.srd] or {}\r\nlocal o = {}\r\nif m.pack and type(m.text) == \"string\" and m.text ~= \"\" then o[#o + 1] = m.text end\r\nif l.cursed then o[#o + 1] = \"cursed: it won't be taken off or parted with until Remove Curse\" end\r\nif l.att then o[#o + 1] = l.attuned and \"attuned\" or (\"needs attunement: [ATTUNE|\" .. name .. \"]\") end\r\nif l.wornReq then o[#o + 1] = l.worn and \"worn ([UNEQUIP|\" .. name .. \"] takes it off)\" or (\"not worn: works once worn, [EQUIP|\" .. name .. \"]\") end\r\nlocal plus = tonumber(l.plus) or 0\r\nif l.base and plus > 0 then\r\no[#o + 1] = WEAPONS[l.base] and (\"+\" .. plus .. \" to attack and damage rolls (in the attack list when held)\")\r\nor (\"+\" .. plus .. \" AC (in the AC when worn)\")\r\nend\r\nfor _, w in ipairs(l.pw or {}) do\r\nlocal k = w.k\r\nif k == \"ac\" then o[#o + 1] = \"+\" .. w.n .. \" AC\" .. (w[\"if\"] and \" with no armor and no Shield\" or \"\")\r\nelseif k == \"acbase\" then o[#o + 1] = \"AC \" .. w.n .. \" + Dexterity with no armor\"\r\nelseif k == \"save\" then o[#o + 1] = \"+\" .. (w.n or 1) .. \" to saving throws\"\r\nelseif k == \"check\" then o[#o + 1] = \"+\" .. w.n .. \" to ability checks\"\r\nelseif k == \"set\" then o[#o + 1] = w.ab .. \" \" .. tostring(w.n)\r\nelseif k == \"add\" and (tonumber(w.n) or 0) < 0 then o[#o + 1] = w.ab .. \" \" .. w.n .. \" (min \" .. (w.min or 1) .. \")\"\r\nelseif k == \"add\" then o[#o + 1] = w.ab .. \" +\" .. w.n .. \" (max \" .. (w.max or 20) .. \")\"\r\nelseif k == \"pb\" then o[#o + 1] = \"+\" .. w.n .. \" Proficiency Bonus\"\r\nelseif k == \"spellatk\" then o[#o + 1] = \"+\" .. tostring(w.n) .. \" spell attack\"\r\nelseif k == \"spelldc\" then o[#o + 1] = \"+\" .. tostring(w.n) .. \" spell save DC\"\r\nelseif k == \"resist\" then o[#o + 1] = \"Resistance to \" .. tostring(w.type)\r\nelseif k == \"imm\" then o[#o + 1] = \"immune to \" .. w.type .. \" damage\"\r\nelseif k == \"vuln\" then o[#o + 1] = \"Vulnerability to \" .. w.type\r\nelseif k == \"cimm\" then o[#o + 1] = \"cannot be \" .. w.cond\r\nelseif k == \"dmg\" then\r\no[#o + 1] = \"+\" .. w.dice .. \" \" .. (w.type == \"weapon\" and \"of the weapon's type\" or w.type) .. (w.vs and (\" against a \" .. table.concat(w.vs, \" or \")) or \"\")\r\n.. (w.nat20 and \" on a d20 of 20\" or \"\") .. (w.thrown and \" when thrown\" or \"\") .. (w.may and \" (may add)\" or \"\")\r\nelseif k == \"dtype\" then o[#o + 1] = \"deals \" .. w.type .. \" damage\"\r\nelseif k == \"nocrit\" then o[#o + 1] = \"a Critical Hit on the wearer is a normal hit (Lua applies it)\"\r\nelseif k == \"mithral\" then o[#o + 1] = \"no Strength need, no Stealth Disadvantage\"\r\nelseif k == \"maxhp\" then o[#o + 1] = \"+1 HP per level\"\r\nelseif k == \"speedmin\" then o[#o + 1] = \"Speed at least \" .. w.n\r\nelseif k == \"dmgbonus\" then o[#o + 1] = \"+\" .. w.n .. \" damage with \" .. table.concat(w.bases, \" or \")\r\nelseif k == \"bonusattack\" then o[#o + 1] = \"one attack with it as a Bonus Action\"\r\nelseif k == \"unarmed\" then o[#o + 1] = \"Unarmed Strikes \" .. w.dice .. \" \" .. w.type .. \", +\" .. w.plus .. \" to hit and damage\"\r\nelseif k == \"deathsave\" then o[#o + 1] = \"a Death Saving Throw of 9 or lower counts as 10 (Lua applies it)\"\r\nelseif k == \"tell\" then o[#o + 1] = w.t end\r\nend\r\nif l.chmax then o[#o + 1] = string.format(\"%d/%d charges\", l.ch or 0, l.chmax) end\r\nlocal sps = {}\r\nfor _, s in ipairs(m.sp or {}) do\r\nlocal sp = SPELLS[s.s]\r\n\r\nif sp then sps[#sps + 1] = s.s .. \" \" .. (s.day and (s.day .. \"/dawn\") or ((s.c or 0) == 0 and \"at will\" or (s.c .. \" charge\" .. (s.c > 1 and \"s\" or \"\"))))\r\n.. (s.up and (\", +1 charge per level above \" .. sp.level .. \" (up to \" .. s.up .. \")\") or \"\") .. (s.lvl and (\", at level \" .. s.lvl) or \"\")\r\n.. (s.dc and (\", DC \" .. s.dc) or \"\") .. (s.atk and (\", +\" .. s.atk .. \" to hit\") or \"\") end\r\nend\r\nif #sps > 0 then o[#o + 1] = \"casts [CAST|Spell|item] (level N: [CAST|Spell|item N]): \" .. table.concat(sps, \"; \") end\r\nif l.srd == \"Spell Scroll\" then\r\nlocal row = K.MI.SCROLL[(SPELLS[l.var] or {}).level or 0]\r\no[#o + 1] = string.format(\"read it to cast %s, if it is on the reader's spell list: [CAST|%s|scroll], DC %d, +%d to hit\", l.var, l.var, row[2], row[3])\r\nlocal wiz, bc = false, SHEET and K.bookClass(SHEET)\r\nfor _, k in ipairs((SPELLS[l.var] or {}).classes or {}) do if k == bc then wiz = true end end\r\nif wiz and (SPELLS[l.var].level or 0) >= 1 then\r\no[#o + 1] = \"a \" .. bc .. \" may copy it into the spellbook instead: [SPELLBOOK|\" .. l.var .. \"] (50 gp and 2 hours per level, Lua's Arcana check DC \"\r\n.. (10 + SPELLS[l.var].level) .. \", the scroll used either way)\"\r\nend\r\nend\r\nif type(m.use) == \"table\" then\r\nlocal u = m.use\r\nlocal what = u.heal and (\"[HEAL|Name|\" .. name .. \"|\" .. u.heal .. \"|dice|amount], \" .. (u.day and (u.day .. \"/dawn\") or \"a charge each\"))\r\nor (\"[USE|\" .. name .. (u.sharp and \"|Weapon\" or \"\") .. \"]\" .. (u.day and (\" \" .. u.day .. \"/dawn\") or \"\"))\r\no[#o + 1] = \"use: \" .. what .. (u.narr and (\" (\" .. u.narr .. \")\") or \"\")\r\nend\r\n\r\nreturn string.format(\"%s = %s in prose%s%s\", name, K.MI.ko(name) or name, (n or 1) > 1 and (\" x\" .. n) or \"\", #o > 0 and (\" (\" .. table.concat(o, \"; \") .. \")\") or \"\")\r\nend\r\n\r\n\r\n\r\n\r\n\r\nK.LINEAGE = {\r\nElf = { \"lineage\", { drow = \"Drow\", dark = \"Drow\", [\"드로우\"] = \"Drow\", [\"다크\"] = \"Drow\", high = \"High Elf\", [\"하이\"] = \"High Elf\",\r\nwood = \"Wood Elf\", [\"우드\"] = \"Wood Elf\", [\"숲\"] = \"Wood Elf\" } },\r\nGnome = { \"gnome\", { forest = \"Forest\", [\"숲\"] = \"Forest\", rock = \"Rock\", [\"바위\"] = \"Rock\" } },\r\nGoliath = { \"giant\", { cloud = \"Cloud\", [\"구름\"] = \"Cloud\", fire = \"Fire\", [\"화염\"] = \"Fire\", frost = \"Frost\", [\"서리\"] = \"Frost\",\r\nhill = \"Hill\", [\"언덕\"] = \"Hill\", stone = \"Stone\", [\"바위\"] = \"Stone\", storm = \"Storm\", [\"폭풍\"] = \"Storm\",\r\n[\"바람\"] = \"Cloud\", [\"불꽃\"] = \"Fire\", [\"대지\"] = \"Hill\" } },\r\nTiefling = { \"legacy\", { abyssal = \"Abyssal\", [\"심연\"] = \"Abyssal\", chthonic = \"Chthonic\", [\"저승\"] = \"Chthonic\",\r\ninfernal = \"Infernal\", [\"지옥\"] = \"Infernal\", [\"독\"] = \"Abyssal\", [\"죽음\"] = \"Chthonic\", [\"불꽃\"] = \"Infernal\" } },\r\n\r\nBeastfolk = { \"beast\", { dog = \"Dog\", [\"개\"] = \"Dog\", cat = \"Cat\", [\"고양이\"] = \"Cat\", fox = \"Fox\", [\"여우\"] = \"Fox\",\r\nbear = \"Bear\", [\"곰\"] = \"Bear\" } },\r\n\r\nDragonborn = { \"dragon\", { acid = \"Acid\", black = \"Acid\", copper = \"Acid\", [\"산성\"] = \"Acid\", [\"블랙\"] = \"Acid\", [\"검은\"] = \"Acid\",\r\n[\"카퍼\"] = \"Acid\", [\"구리\"] = \"Acid\",\r\ncold = \"Cold\", silver = \"Cold\", white = \"Cold\", [\"냉기\"] = \"Cold\", [\"실버\"] = \"Cold\", [\"은\"] = \"Cold\",\r\n[\"화이트\"] = \"Cold\", [\"흰\"] = \"Cold\",\r\nfire = \"Fire\", brass = \"Fire\", gold = \"Fire\", red = \"Fire\", [\"화염\"] = \"Fire\", [\"브라스\"] = \"Fire\",\r\n[\"놋쇠\"] = \"Fire\", [\"골드\"] = \"Fire\", [\"금\"] = \"Fire\", [\"황금\"] = \"Fire\", [\"레드\"] = \"Fire\", [\"붉은\"] = \"Fire\",\r\nlightning = \"Lightning\", blue = \"Lightning\", bronze = \"Lightning\", [\"번개\"] = \"Lightning\",\r\n[\"블루\"] = \"Lightning\", [\"푸른\"] = \"Lightning\", [\"브론즈\"] = \"Lightning\", [\"청동\"] = \"Lightning\",\r\npoison = \"Poison\", green = \"Poison\", [\"독\"] = \"Poison\", [\"그린\"] = \"Poison\", [\"녹색\"] = \"Poison\",\r\n[\"초록\"] = \"Poison\" } },\r\n}\r\n\r\nK.SPECIES_ALIAS = { drow = { \"Elf\", \"Drow\" }, [\"드로우\"] = { \"Elf\", \"Drow\" }, eladrin = { \"Elf\" }, [\"엘라드린\"] = { \"Elf\" },\r\nduergar = { \"Dwarf\" }, [\"두에르가\"] = { \"Dwarf\" }, svirfneblin = { \"Gnome\" }, [\"스비프네블린\"] = { \"Gnome\" } }\r\n\r\n\r\nfunction K.species(v)\r\nv = trim(v or \"\")\r\nlocal sp = Canon.name(v)\r\nif SPECIES[sp] then return sp end\r\nlocal low, at = v:lower(), 0\r\n\r\nlocal function lit(x) return (x:gsub(\"[%-%.%+%*%?%[%]%(%)%^%$%%]\", \"%%%0\")) end\r\nfor en in pairs(SPECIES) do\r\nlocal ko = NAMES_KO[en]\r\nfor e in low:gmatch(\"%f[%a]\" .. lit(en:lower()) .. \"%f[%A]()\") do if e > at then at, sp = e, en end end\r\nif ko then for e in low:gmatch(lit(ko) .. \"()\") do if e > at then at, sp = e, en end end end\r\nend\r\nlocal words = {}\r\nlocal rest = low:gsub(\"·\", \" \")\r\nif at > 0 then\r\nrest = rest:gsub(\"%f[%a]\" .. lit(sp:lower()) .. \"%f[%A]\", \" \")\r\nif NAMES_KO[sp] then rest = rest:gsub(lit(NAMES_KO[sp]), \" \") end\r\nend\r\nfor w in rest:gmatch(\"[^%s%-%(%)%[%],/:;]+\") do words[#words + 1] = w end\r\nif at == 0 then\r\nfor _, w in ipairs(words) do\r\nlocal al = K.SPECIES_ALIAS[w]\r\nif al then return al[1], al[2] and { [K.LINEAGE[al[1]][1]] = al[2] } or nil end\r\nend\r\nreturn nil\r\nend\r\nlocal row = K.LINEAGE[sp]\r\nif not row then return sp end\r\nfor _, w in ipairs(words) do\r\nlocal opt = row[2][w] or row[2][(w:gsub(\"의$\", \"\"))]\r\nif opt then return sp, { [row[1]] = opt } end\r\nend\r\nreturn sp\r\nend\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\nfunction K.afflictOn(sh)\r\nlocal out = {}\r\nlocal base = type(sh) == \"table\" and (sh.base or sh) or nil\r\nlocal now = K.clockRef and tonumber(K.clockRef.min)\r\nlocal list = {}\r\nfor _, e in ipairs(base and type(base.afflict) == \"table\" and base.afflict or {}) do list[#list + 1] = e end\r\n\r\nlocal p = base and type(base.picks) == \"table\" and base.picks or {}\r\nif type(p.fetish) == \"table\" then\r\nlocal hist = K.PACK.ar and K.PACK.ar.hist[p.sexhist or \"\"]\r\nlocal limit = tonumber(hist and type(hist.fetish) == \"table\" and hist.fetish.on) or 3\r\nfor _, n in ipairs(p.fetish) do\r\nlocal on = #p.fetish <= limit and type(p.fetishon) ~= \"table\"\r\nfor _, x in ipairs(type(p.fetishon) == \"table\" and p.fetishon or {}) do if x == n then on = true end end\r\nlist[#list + 1] = { name = n, kind = \"fetish\", src = \"history\", on = on }\r\nend\r\nend\r\nfor _, e in ipairs(list) do\r\nlocal rec = type(e) == \"table\" and K.PACK.afflict and K.PACK.afflict[e.name or \"\"]\r\n\r\nif type(e) == \"table\" and type(e.conc) == \"table\" and K.AR and K.AR.concOver(e.conc, K.curPc) then e.over, e.conc = true, nil end\r\nif rec and not (type(e) == \"table\" and e.over) and not (tonumber(e.ends) and now and now >= e.ends) then\r\nlocal fx = {}\r\nif e.on ~= false then for _, x in ipairs(rec.fx or {}) do fx[#fx + 1] = x end end\r\nfor _, x in ipairs(type(rec.neg) == \"table\" and rec.neg or {}) do fx[#fx + 1] = x end\r\nout[#out + 1] = { e = e, rec = rec, fx = fx }\r\nend\r\nend\r\nreturn out\r\nend\r\n\r\nfunction K.fetishSlots(sh)\r\nlocal p = type(sh) == \"table\" and type(sh.picks) == \"table\" and sh.picks or {}\r\nlocal hist = K.AR and K.AR.on() and K.PACK.ar and K.PACK.ar.hist[p.sexhist or \"\"]\r\nlocal fe = hist and type(hist.fetish) == \"table\" and hist.fetish or {}\r\nlocal histN = tonumber(fe.n) or 0\r\nlocal n, on = histN, tonumber(fe.on)\r\nfor _, e in ipairs(Feat.fxOf(sh, \"fetish_slots\")) do n = n + (tonumber(e.n) or 2) end\r\nif not on and n > 3 then on = 3 end\r\nlocal all = {}\r\nfor x, r in pairs(K.PACK.afflict or {}) do if r.kind == \"fetish\" and K.d2ok(r) then all[#all + 1] = x end end\r\ntable.sort(all)\r\nlocal opts = all\r\n\r\nif type(fe.one_of) == \"table\" then\r\nlocal oneOf, inOne = {}, {}\r\nfor _, x in ipairs(fe.one_of) do if K.PACK.afflict and K.PACK.afflict[x] and K.d2ok(K.PACK.afflict[x]) then oneOf[#oneOf + 1] = x; inOne[x] = true end end\r\nlocal k = 0\r\nfor _, x in ipairs(type(p.fetish) == \"table\" and p.fetish or {}) do if inOne[x] then k = k + 1 end end\r\nif k < histN then opts = oneOf end\r\nend\r\nreturn n, on, opts\r\nend\r\n\r\n\r\n\r\nfunction K.histOver(sh)\r\nlocal out = {}\r\nif not (K.AR and K.AR.on()) then return out end\r\nlocal p = type(sh) == \"table\" and type(sh.picks) == \"table\" and sh.picks or {}\r\nlocal hist = K.PACK.ar.hist[p.sexhist or \"\"]\r\nif not hist then return out end\r\nlocal tools = type(p.imptools) == \"table\" and p.imptools or {}\r\nlocal tn = tonumber(hist.tools) or 0\r\nif #tools > tn then out[#out + 1] = { key = \"imptools\", need = #tools - tn, opts = { table.unpack(tools) } } end\r\nlocal fe = type(p.fetish) == \"table\" and p.fetish or {}\r\nif K.PACK.afflict and #fe > 0 then\r\nlocal n = K.fetishSlots(sh)\r\nlocal hf = type(hist.fetish) == \"table\" and hist.fetish or {}\r\nlocal outside = {}\r\nif type(hf.one_of) == \"table\" then\r\nlocal inOne = {}\r\nfor _, x in ipairs(hf.one_of) do inOne[x] = true end\r\nfor _, x in ipairs(fe) do if not inOne[x] then outside[#outside + 1] = x end end\r\nend\r\nlocal free = n - (tonumber(hf.n) or 0)\r\nlocal need = math.max(#fe - n, #outside - free)\r\nif need > 0 then out[#out + 1] = { key = \"fetish\", need = need, opts = #outside > free and outside or { table.unpack(fe) } } end\r\nend\r\nreturn out\r\nend\r\n\r\nfunction K.swapAb(sh, a)\r\nfor _, x in ipairs(K.afflictOn(sh)) do\r\nfor _, e in ipairs(x.fx) do\r\nif e.t == \"swap_scores\" then\r\nif e.a == a then return e.b end\r\nif e.b == a then return e.a end\r\nend\r\nend\r\nend\r\nreturn a\r\nend\r\n\r\nfunction K.afflictConds(t, pc)\r\nlocal out = {}\r\nfor n in pairs(type(t) == \"table\" and type(t.itemCond) == \"table\" and t.itemCond or {}) do out[#out + 1] = n end\r\nlocal sh = type(t) == \"table\" and ((t.sheet) or (t == (pc or K.curPc) and SHEET)) or nil\r\nif not sh then return out end\r\nfor _, x in ipairs(K.afflictOn(sh)) do\r\nif not (x.rec.kind == \"fetish\" and x.e.on == false) then\r\nfor _, n in ipairs(type(x.rec.conds) == \"table\" and x.rec.conds or {}) do out[#out + 1] = n end\r\nend\r\nend\r\nlocal function bound(r) for n in pairs(type(r) == \"table\" and type(r.cond) == \"table\" and r.cond or {}) do if K.bindOf and K.bindOf(r, n) then return true end end return false end\r\nfor _, e in ipairs(Feat.fxOf and Feat.fxOf(sh, \"cond_when\") or {}) do\r\nlocal w, on = e.when, false\r\nif w == \"bound\" then on = bound(t)\r\nelseif w == \"half_hp\" then on = (tonumber(t.max) or 0) > 0 and (tonumber(t.hp) or 0) <= (tonumber(t.max) or 0) / 2\r\nelseif w == \"intoxicated\" then on = (type(t.ar) == \"table\" and K.AR and K.AR.overHard(t.ar, t) >= 1) or (type(t.cond) == \"table\" and t.cond.Intoxicated ~= nil)\r\nelseif w == \"pregnant\" then on = type(t.preg) == \"table\"\r\nelseif w == \"in_sight_of_bound\" then\r\nlocal cc = K.curC\r\nfor _, u in pairs(type(cc) == \"table\" and cc.active and type(cc.units) == \"table\" and cc.units or {}) do if u ~= t and bound(u) then on = true end end\r\nlocal p0 = pc or K.curPc\r\nfor _, r in ipairs(type(p0) == \"table\" and { p0, table.unpack(Ally.list(p0)) } or {}) do if r ~= t and bound(r) then on = true end end\r\nend\r\nif on and type(e.cond) == \"string\" then out[#out + 1] = e.cond end\r\nend\r\nreturn out\r\nend\r\n\r\nfunction K.condEff(name, out, depth)\r\nout, depth = out or {}, depth or 0\r\nlocal m = CONDS[name]\r\nif not m or out[name] or depth > 3 then return out end\r\nout[name] = m\r\nfor _, x in ipairs(m.pack and type(m.pack.has) == \"table\" and m.pack.has or {}) do K.condEff(x, out, depth + 1) end\r\nreturn out\r\nend\r\n\r\nfunction K.condDesc(row)\r\nlocal o = {}\r\nif type(row.text) == \"string\" and row.text ~= \"\" then o[#o + 1] = row.text end\r\nif type(row.auto_fail) == \"table\" and #row.auto_fail > 0 then o[#o + 1] = \"fails \" .. table.concat(row.auto_fail, \" and \") .. \" saves\" end\r\nif type(row.dis_checks) == \"table\" and #row.dis_checks > 0 then o[#o + 1] = \"Disadvantage on \" .. table.concat(row.dis_checks, \" and \") .. \" checks\" end\r\nif row.adv_vs then o[#o + 1] = \"attacks and approaches against it have Advantage\" end\r\nif row.own_dis then o[#o + 1] = \"Disadvantage on its attacks and approaches with the bound limbs\" end\r\nif tonumber(row.speed) then o[#o + 1] = \"Speed \" .. row.speed .. \" ft at most\" end\r\nif row.no_fly then o[#o + 1] = \"can't fly\" end\r\nif row.no_verbal then o[#o + 1] = \"can't speak (no Verbal components)\" end\r\nif row.no_somatic then o[#o + 1] = \"no Somatic components\" end\r\nif row.no_breathe then o[#o + 1] = \"can't breathe: holds its breath 1 + Constitution modifier minutes (at least 30 seconds), then suffocates\" end\r\nlocal srd = {}\r\nfor _, x in ipairs(type(row.has) == \"table\" and row.has or {}) do if CONDS[x] and not CONDS[x].pack then srd[#srd + 1] = x end end\r\nif #srd > 0 then o[#o + 1] = \"also \" .. table.concat(srd, \", \") end\r\nreturn table.concat(o, \"; \")\r\nend\r\nfunction Cond.load(pc)\r\npc.cond = type(pc.cond) == \"table\" and pc.cond or {}\r\npc.exh = tonumber(pc.exh) or 0\r\nreturn pc.cond\r\nend\r\n\r\nfunction Cond.active(pc)\r\nlocal out = {}\r\n\r\nlocal cc = K.curC\r\nfor name, r in pairs(type(pc.condR) == \"table\" and pc.condR or {}) do\r\nif type(r) == \"table\" and cc and not (cc.active and cc.fid == r.fid and (tonumber(cc.round) or 1) < (tonumber(r.to) or 0)) then\r\npc.cond[name], pc.condR[name] = nil, nil\r\nend\r\nend\r\nfor name, cs in pairs(type(pc.condSpell) == \"table\" and pc.condSpell or {}) do\r\nif K.AR and K.AR.concOver(cs, K.curPc) then pc.cond[name], pc.condSpell[name] = nil, nil end\r\nend\r\nfor name in pairs(Cond.load(pc)) do if CONDS[name] then out[#out + 1] = name end end\r\ntable.sort(out)\r\nreturn out\r\nend\r\n\r\n\r\nfunction Cond.fx(pc)\r\nlocal fx = { pen = 0, autofail = {} }\r\nif not pc then return fx end\r\nif K.AR and K.AR.incapNow(pc) then fx.incap = \"Incapacitated (a climax)\" end\r\nCond.load(pc)\r\nfx.pen = 2 * pc.exh + math.max(0, tonumber(pc.ordeal) or 0)\r\nfx.slow = 5 * pc.exh\r\nlocal names = Cond.active(pc)\r\nfor _, n in ipairs(K.afflictConds and K.afflictConds(pc, K.curPc) or {}) do names[#names + 1] = n end\r\nfor _, name in ipairs(names) do\r\nfor _, m in pairs(K.condEff(name)) do\r\nif m.speed == 0 then fx.speed0 = true end\r\nif tonumber(m.speedCap) then fx.speedCap = math.min(fx.speedCap or m.speedCap, m.speedCap) end\r\nif m.incapacitated or m.no_actions then fx.incap = name end\r\nif m.no_hostile then fx.nohostile = name end\r\nfor _, a in ipairs(m.auto_fail_saves or {}) do fx.autofail[a] = name end\r\nif m.auto_crit_within_5ft then fx.crit = true end\r\nend\r\nend\r\nreturn fx\r\nend\r\n\r\nfunction Cond.expire(pc, clock)\r\nfor name, t in pairs(Cond.load(pc)) do\r\nif type(t) ~= \"number\" or (t >= 0 and t <= clock.min) then pc.cond[name] = nil end\r\nend\r\nend\r\n\r\n\r\nfunction Cond.verify(f, pc, clock)\r\nlocal sign, raw = (f[1] or \"\"):match(\"^%s*([+-])%s*(.-)%s*$\")\r\nlocal head = \"[COND|\" .. table.concat(f, \"|\")\r\nlocal function fail(why) return head .. \"|bad:\" .. why .. \"|-]\", false end\r\nif not sign then return fail(\"write +Condition or -Condition\") end\r\nlocal name = Canon.name(raw)\r\nif not CONDS[name] then for n in pairs(CONDS) do if NAMES_KO[n] == raw then name = n end end end\r\nif not CONDS[name] then return fail(\"not a condition of this game\") end\r\nlocal packRow = CONDS[name].pack\r\nif packRow and sign == \"+\" and not (K.AR and K.AR.on()) then return fail(name .. \": no module brings it in this game\") end\r\nif packRow and sign == \"+\" then\r\nlocal off = K.d2need(packRow)\r\nif off then return fail(name .. \" is \" .. K.D2_WHY[off]) end\r\nend\r\nCond.load(pc)\r\nif name == \"Exhaustion\" then\r\nlocal why = sign == \"+\" and Feat.immune(pc, pc.sheet or SHEET, name)\r\nif why then return head .. \"|ok|immune (\" .. why .. \")]\", true end\r\n\r\nif sign == \"+\" and Feat.fxOf then\r\nlocal mo = type(pc.mode) == \"table\" and pc.mode.name\r\nfor _, e in ipairs(Feat.fxOf(pc.sheet or SHEET, \"overstim_lower\")) do\r\nif e.exh and (not e.mode or e.mode == mo) then return head .. \"|ok|none (\" .. (e.src or \"overstim_lower\") .. \")]\", true end\r\nend\r\nend\r\nif sign == \"+\" then\r\npc.exh = math.min(6, pc.exh + 1)\r\nif pc.exh >= 6 then pc.dead = true end\r\nelseif pc.exh > 0 then\r\npc.exh = pc.exh - 1\r\nif type(pc.ar) == \"table\" and (tonumber(pc.ar.overstim) or 0) > 0 then pc.ar.overstim = pc.ar.overstim - 1 end\r\nelse\r\nreturn fail(\"no Exhaustion\")\r\nend\r\nelseif sign == \"-\" then\r\nif not pc.cond[name] then return fail(\"not \" .. name) end\r\npc.cond[name] = nil\r\nif type(pc.condBind) == \"table\" then pc.condBind[name] = nil end\r\nelse\r\n\r\n\r\nlocal why = Feat.immune(pc, pc.sheet or SHEET, name)\r\nif why then return head .. \"|ok|immune (\" .. why .. \")]\", true end\r\n\r\nif name == \"Prone\" and pc.mount then\r\nlocal d = K.d(20)\r\nlocal b = bonusFor(\"Dexterity save\") - Cond.fx(pc).pen\r\nif d + b >= 10 then\r\nreturn head .. \"|ok|\" .. string.format(\"stays on %s (Dexterity save d20 %d%+d vs DC 10)\", pc.mount, d, b) .. \"]\", true\r\nend\r\nK.fellFrom = pc.mount\r\npc.mount = nil\r\nend\r\nlocal d = (f[2] or \"-\"):gsub(\"%s\", \"\")\r\n\r\nlocal set, dmgEnd, rounds, concOn\r\nfor part in (d .. \",\"):gmatch(\"([^,]*),\") do\r\npart = K.durNorm(part)\r\nlocal n, u = part:match(\"^%+?(%d+)([mhd])$\")\r\nlocal rn = part:match(\"^%+?(%d+)r$\")\r\nif n then set = clock.min + math.min(365 * 1440, tonumber(n) * K.TIME_UNIT[u])\r\nelseif part == \"-\" or part == \"\" then set = set or -1\r\nelseif part == \"dmg\" then dmgEnd = true; set = set or -2\r\nelseif part == \"conc\" then concOn = true; set = set or -1\r\nelseif rn then rounds = tonumber(rn)\r\nelse\r\nreturn fail(\"duration +10m, +1h, +1d, Nr (rounds), dmg (until damaged), parts with commas (1h,dmg), or -\")\r\nend\r\nend\r\npc.condDmg = type(pc.condDmg) == \"table\" and pc.condDmg or {}\r\npc.condR = type(pc.condR) == \"table\" and pc.condR or {}\r\npc.condDmg[name], pc.condR[name] = dmgEnd or nil, nil\r\nif rounds then\r\nlocal cc = K.curC\r\nif cc and cc.active then\r\npc.condR[name] = { to = (tonumber(cc.round) or 1) + rounds, fid = cc.fid }\r\nset = set or -3\r\nelse\r\nset = set or -1\r\nend\r\nend\r\npc.cond[name] = set or -1\r\npc.condSpell = type(pc.condSpell) == \"table\" and pc.condSpell or {}\r\npc.condSpell[name] = concOn and K.AR and K.AR.concOf(f[3], K.curPc or pc) or nil\r\npc.condSrc = type(pc.condSrc) == \"table\" and pc.condSrc or {}\r\npc.condSrc[name] = (f[3] and trim(f[3]) ~= \"\") and trim(f[3]) or nil\r\nif type(pc.condBind) == \"table\" then pc.condBind[name] = nil end\r\nend\r\nlocal now = Cond.active(pc)\r\nif pc.exh > 0 then now[#now + 1] = \"Exhaustion \" .. pc.exh end\r\nlocal fell = K.fellFrom\r\nK.fellFrom = nil\r\nreturn head .. \"|ok|\" .. (#now > 0 and table.concat(now, \", \") or \"none\") .. (fell and (\" (fell off \" .. fell .. \")\") or \"\") .. \"]\", true\r\nend\r\n\r\nfunction Cond.text(pc, clock)\r\nlocal parts = {}\r\nfor _, name in ipairs(Cond.active(pc)) do\r\nlocal t = pc.cond[name]\r\nif not CONDS[name].pack then\r\nparts[#parts + 1] = string.format(\"%s (%s): %s\", name, t >= 0 and (\"ends \" .. clockEn(t)) or \"until removed\", CONDS[name].en)\r\nelseif t >= 0 then\r\nparts[#parts + 1] = string.format(\"%s (ends %s)\", name, clockEn(t))\r\nend\r\nend\r\nif pc.exh > 0 then\r\n\r\n\r\nparts[#parts + 1] = string.format(\"Exhaustion %d: every d20 test takes -%d and Speed -%d ft. The attack bonuses Lua lists already include it;\"\r\n.. \" take it off ability checks and saving throws yourself (write their bonus with it included). A Long Rest removes one level; level 6 is death\",\r\npc.exh, 2 * pc.exh, 5 * pc.exh)\r\nend\r\nif (tonumber(pc.ordeal) or 0) > 0 then\r\n\r\nparts[#parts + 1] = string.format(\"Back from the dead: every d20 test takes -%d (one less per Long Rest). The attack bonuses Lua lists\"\r\n.. \" already include it; take it off ability checks and saving throws yourself\", pc.ordeal)\r\nend\r\nif pc.taxed then parts[#parts + 1] = \"Taxed by Resurrection: no spells and Disadvantage on D20 Tests until a Long Rest\" end\r\nlocal dt = K.drainText and SHEET and K.drainText(pc, pc) or \"\"\r\nif dt ~= \"\" then parts[#parts + 1] = dt:gsub(\"^, l\", \"L\") .. \" (Lua's numbers already have them)\" end\r\nif #parts == 0 then return nil end\r\nreturn \"Player's conditions (kept by Lua): \" .. table.concat(parts, \". \") .. \".\"\r\nend\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\nfunction K.d20Part(cur, pools, field, bad, rec, kind)\r\nfield = field:gsub(\"^%s*[CcNn][a-z]*%s*(%d+)%s*$\", function(n)\r\nreturn n\r\nend)\r\nlocal mode, a, b = field:match(\"^(%a+)%s+(%d+)%s*,%s*(%d+)$\")\r\nlocal wanted, count\r\nlocal fm = mode and K.FX_MODE[mode]\r\nif fm then\r\nlocal sh = rec and (rec.sheet or SHEET)\r\nlocal has, lvOf = false, nil\r\nlocal dieS = fm.die\r\nfor _, e in ipairs(sh and Feat.fxOf(sh, fm.t) or {}) do\r\nif e.mode == mode then\r\nhas, lvOf = true, e.srcLv\r\n\r\nif type(e.die) == \"string\" and e.die:find(\"{\", 1, true) then\r\ndieS = tostring(K.dieText({ dice = e.die, srcClass = e.srcClass, srcLv = e.srcLv }, sh)):match(\"d(%d+)\") or dieS\r\nend\r\nend\r\nend\r\nlocal res = rec and type(rec.res) == \"table\" and rec.res\r\nlocal function take(k, want)\r\ncur[k] = (cur[k] or 0) + 1\r\nlocal v = pools[k] and pools[k][cur[k]]\r\nif v == nil then K.poolEmpty(bad, k); v = K.pastDie(pools, k, cur[k]) end\r\nif tonumber(want) ~= v then bad[#bad + 1] = k .. \" \" .. tostring(want) .. \"->\" .. v end\r\nreturn v\r\nend\r\nlocal v = take(\"d20\", a)\r\n\r\n\r\nlocal dsz = tostring(dieS):match(\"^%d+$\") or tostring(dieS):match(\"^%d*d(%d+)$\") or \"8\"\r\nlocal w = fm.fixed or take(fm.t == \"die_bonus\" and (\"d\" .. dsz) or \"d20\", b)\r\nK.d20Got = { v, w }\r\nlocal why\r\nlocal okKind = false\r\nfor _, x in ipairs(fm.on or { \"save\" }) do if x == kind then okKind = true end end\r\nif not has then why = \"no \" .. fm.src\r\nelseif not okKind then why = fm.src .. \": \" .. table.concat(fm.on or { \"save\" }, \" or \") .. \" only\"\r\nelseif fm.use and (not res or (res[fm.use] or 0) < 1) then why = \"no \" .. fm.use .. \" left\" end\r\nif why then bad[#bad + 1] = why; return v, mode, v end\r\nif fm.use then res[fm.use] = res[fm.use] - 1 end\r\nif fm.t == \"die_bonus\" then return v + w, mode, v end\r\n\r\nlocal bn = fm.bonus == \"LEVEL\" and (tonumber(lvOf or sh.level) or 0) or (fm.bonus ~= nil and (tonumber(K.fxNum(fm.bonus, sh, lvOf)) or 0)) or 0\r\nreturn w + bn, mode, w\r\nend\r\nif mode == \"bi\" then\r\n\r\ncur.d20 = cur.d20 + 1\r\nlocal v = pools.d20[cur.d20]\r\nif v == nil then K.poolEmpty(bad, \"d20\"); v = K.pastDie(pools, \"d20\", cur.d20) end\r\nif tonumber(a) ~= v then bad[#bad + 1] = \"d20 \" .. tostring(a) .. \"->\" .. v end\r\nK.d20Got = { v, tonumber(b) }\r\nlocal die = rec and rec.bi\r\nif not die then bad[#bad + 1] = \"no Bardic Inspiration die\"; return v, mode end\r\nlocal k = \"d\" .. die:match(\"d(%d+)$\")\r\ncur[k] = (cur[k] or 0) + 1\r\nlocal w = pools[k] and pools[k][cur[k]]\r\nif w == nil then K.poolEmpty(bad, k); w = K.pastDie(pools, k, cur[k]) end\r\nif tonumber(b) ~= w then bad[#bad + 1] = k .. \" \" .. tostring(b) .. \"->\" .. w end\r\nK.d20Got[2] = w\r\nrec.bi = nil\r\nreturn v + w, mode, v\r\nend\r\nif mode == \"adv\" or mode == \"dis\" or mode == \"luck\" or mode == \"insp\" then\r\nwanted, count = { tonumber(a), tonumber(b) }, 2\r\n\r\nlocal p1, p2 = pools.d20[cur.d20 + 1], pools.d20[cur.d20 + 2]\r\nif (mode == \"adv\" or mode == \"dis\") and wanted[1] == p2 and wanted[2] == p1 then wanted = { p1, p2 } end\r\nelse\r\nmode, count = \"normal\", 1\r\nwanted = { tonumber(field) }\r\nend\r\nlocal got = {}\r\nfor i = 1, count do\r\ncur.d20 = cur.d20 + 1\r\nlocal v = pools.d20[cur.d20]\r\n\r\n\r\nif v == nil then K.poolEmpty(bad, \"d20\"); v = K.pastDie(pools, \"d20\", cur.d20) end\r\nif wanted[i] ~= v then bad[#bad + 1] = \"d20 \" .. tostring(wanted[i]) .. \"->\" .. v end\r\ngot[i] = v\r\nend\r\nK.d20Got = got\r\nif mode == \"adv\" then return math.max(got[1], got[2]), mode end\r\nif mode == \"dis\" then return math.min(got[1], got[2]), mode end\r\nif mode == \"luck\" then\r\nlocal sh = rec and (rec.sheet or SHEET)\r\nif not (sh and sh.species == \"Halfling\") then bad[#bad + 1] = \"Luck is a Halfling trait\"; return got[1], mode end\r\nif got[1] ~= 1 then bad[#bad + 1] = \"Luck rerolls only a 1\"; return got[1], mode end\r\nreturn got[2], mode\r\nend\r\nif mode == \"insp\" then\r\nlocal res = rec and type(rec.res) == \"table\" and rec.res\r\nif not res or (res[\"Heroic Inspiration\"] or 0) < 1 then bad[#bad + 1] = \"no Heroic Inspiration\"; return got[1], mode end\r\nres[\"Heroic Inspiration\"] = res[\"Heroic Inspiration\"] - 1\r\nreturn got[2], mode\r\nend\r\nreturn got[1], mode\r\nend\r\n\r\n\r\n\r\n\r\n\r\nK.D4_BUFF = {\r\nbless = { spell = \"Bless\", on = { attack = true, save = true }, what = \"attack rolls and saving throws\" },\r\nguidance = { spell = \"Guidance\", on = { check = true }, what = \"ability checks\" },\r\n\r\n\r\n\r\nbane = { spell = \"Bane\", on = { attack = true, save = true }, what = \"attack rolls and saving throws\", minus = \"roller\" },\r\nward = { spell = \"Blade Ward\", on = { attack = true }, what = \"attack rolls against its target\", minus = \"target\" },\r\n\r\ncut = { spell = \"Cutting Words\", on = { attack = true }, what = \"a creature's attack rolls\", minus = \"cut\" },\r\n}\r\nK.D4_BUFF[\"축복\"], K.D4_BUFF[\"안내\"] = K.D4_BUFF.bless, K.D4_BUFF.guidance\r\nK.D4_BUFF[\"억압\"] = K.D4_BUFF.bane\r\n\r\n\r\nfunction K.d4MinusWhy(buff, rec, kind)\r\nif kind and not buff.on[kind] then return buff.spell .. \" takes off from \" .. buff.what .. \" only\" end\r\nlocal pc = K.partyPc\r\nif buff.minus == \"cut\" then\r\nif kind ~= \"attack\" or type(K.d20Foe) ~= \"table\" then return \"Cutting Words takes off from a creature's attack roll only\" end\r\nif not K.cutter(pc) then return \"no Cutting Words (a Lore Bard with a Bardic Inspiration left)\" end\r\nK.cutSpend(pc)\r\nreturn nil\r\nend\r\nif buff.minus == \"roller\" then\r\nlocal u = K.d20Foe\r\nif type(u) == \"table\" and not (K.foeFx(u, pc).bane) then return \"no \" .. buff.spell .. \" on \" .. tostring(K.d20FoeName or \"it\") end\r\nreturn nil\r\nend\r\nlocal t = K.d20Tgt\r\nif type(t) ~= \"table\" then return buff.spell .. \" takes off from \" .. buff.what .. \" only\" end\r\nif t.side then return nil end\r\nfor bn, b in pairs(type(t.buff) == \"table\" and t.buff or {}) do\r\nif type(b) == \"table\" and b.d4minus and (not pc or K.buffLive(pc, bn, b)) then return nil end\r\nend\r\nreturn \"no ward that takes 1d4 off on \" .. tostring(t.name or \"Player\")\r\nend\r\n\r\n\r\n\r\nfunction K.concOn(pc, who, spell)\r\npc = pc or K.partyPc\r\nif type(pc) ~= \"table\" then return false end\r\nlocal r = (who == \"Player\" or who == nil) and pc or Ally.find(pc, who)\r\nif not r then return K.buffBy(spell, pc) == who end\r\nreturn type(r.conc) == \"table\" and r.conc.name == spell and not r.conc.lost and not r.dead and true or false\r\nend\r\n\r\nfunction K.partyKnows(pc, name)\r\nlocal function has(sh)\r\nif type(sh) ~= \"table\" then return false end\r\nfor _, k in ipairs({ \"cantrips\", \"spells\" }) do for _, n in ipairs(type(sh[k]) == \"table\" and sh[k] or {}) do if n == name then return true end end end\r\nreturn Feat.extras and Feat.extras(sh)[name] ~= nil or false\r\nend\r\nif has(SHEET) then return true end\r\nfor _, a in ipairs(Ally.list(pc)) do if not a.dead and has(a.sheet) then return true end end\r\nreturn false\r\nend\r\n\r\nfunction K.buffBy(spell, pc, rec)\r\npc = pc or K.partyPc\r\nif type(pc) ~= \"table\" then return nil end\r\nif type(pc.conc) == \"table\" and pc.conc.name == spell then return \"Player\" end\r\nfor _, a in ipairs(Ally.list(pc)) do\r\nif type(a.conc) == \"table\" and a.conc.name == spell and not a.dead then return a.name end\r\nend\r\n\r\nif spell == \"Bless\" then\r\nfor _, r in ipairs({ pc, table.unpack(Ally.list(pc)) }) do\r\nfor n, b in pairs(type(r.buff) == \"table\" and r.buff or {}) do\r\nif type(b) == \"table\" and b.bless and (not rec or (rec.name or \"Player\") == (r.name or \"Player\")) then return r.name or \"Player\", n end\r\nend\r\nend\r\nend\r\nreturn nil\r\nend\r\n\r\n\r\n\r\nfunction K.partySkill(skill)\r\nlocal pc = K.partyPc\r\nif type(pc) ~= \"table\" then return 0 end\r\nlocal best = 0\r\nfor _, r in ipairs({ pc, table.unpack(Ally.list(pc)) }) do\r\nlocal n = type(r.conc) == \"table\" and r.conc.name\r\nlocal ps = n and SPELLS[n] and SPELLS[n].m and SPELLS[n].m.party_skill\r\nlocal v = type(ps) == \"table\" and tonumber(ps[skill]) or 0\r\nif v > best and not r.dead and (tonumber(r.hp) or 0) > 0 then best = v end\r\nend\r\nreturn best\r\nend\r\n\r\n\r\nlocal function takeD20(cur, pools, field, bad, rec, kind)\r\nlocal raw, n0 = field or \"\", #bad\r\nlocal refused = n0 > 0\r\n\r\nlocal pn = (field or \"\"):match(\"^%s*portent%s*(%d+)%s*$\") or (field or \"\"):match(\"^%s*예지%s*(%d+)%s*$\")\r\nif pn then\r\nlocal v = tonumber(pn)\r\nlocal why = K.portentUse(v, refused)\r\nif why then bad[#bad + 1] = why end\r\nK.d20Got = nil\r\nreturn v, nil, v\r\nend\r\n\r\nlocal lpre, lword, lsign, ldie = (field or \"\"):match(\"^(.-%d)%s+(%a+)%s*([%+%-]?)%s*(%d+)%s*$\")\r\nlocal luckE, luckR\r\nif lword then luckE, luckR = K.luckFind(lword:lower()) end\r\nif luckE then field = lpre end\r\nlocal pre, word, die = (field or \"\"):match(\"^(.-%d)%s*%+?%s*([^%d%s,%+]+)%s*(%d+)%s*$\")\r\nlocal buff = word and K.D4_BUFF[word:lower()]\r\nif buff then field = pre end\r\nK.d20Got = nil\r\nlocal roll, mode, nat = K.d20Part(cur, pools, field, bad, rec, kind)\r\nnat = nat or roll\r\n\r\nlocal function note(w)\r\nlocal got = K.d20Got or {}\r\nif w then got[#got + 1] = w end\r\nlocal fixed = false\r\nfor i = n0 + 1, #bad do if bad[i]:match(\"^d%d+ %S*%->\") then fixed = true end end\r\nif not fixed or K.diceQuiet then return end\r\nlocal i = 0\r\nK.d20Log = raw:find(\"%d\") and (raw:gsub(\"%d+\", function(d) i = i + 1; return got[i] and tostring(got[i]) or d end)) or tostring(got[1] or \"\")\r\nend\r\nif not buff then note() end\r\nif buff then\r\nlocal dk = \"d4\"\r\nif buff.minus == \"cut\" then local _, cd = K.cutter(K.partyPc); dk = cd or \"d6\" end\r\ncur[dk] = (cur[dk] or 0) + 1\r\nlocal w = pools[dk] and pools[dk][cur[dk]]\r\nif w == nil then K.poolEmpty(bad, dk); w = K.pastDie(pools, dk, cur[dk]) end\r\nif tonumber(die) ~= w then bad[#bad + 1] = dk .. \" \" .. tostring(die) .. \"->\" .. w end\r\nnote(w)\r\nlocal why = buff.minus and K.d4MinusWhy(buff, rec, kind)\r\nif buff.minus then\r\nif why then bad[#bad + 1] = why else roll = roll - w end\r\nelseif not rec then\r\nbad[#bad + 1] = buff.spell .. \" is on Player's side only\"\r\nelseif not K.buffBy(buff.spell, nil, rec) then\r\nbad[#bad + 1] = \"no \" .. buff.spell .. \" in effect (nobody concentrates on it)\"\r\nelseif kind and not buff.on[kind] then\r\nbad[#bad + 1] = buff.spell .. \" adds to \" .. buff.what .. \" only\"\r\nelse\r\nroll = roll + w\r\nend\r\nend\r\nif luckE then\r\nlocal sz = tonumber((luckE.dice or \"1d4\"):match(\"d(%d+)\")) or 4\r\nlocal k = \"d\" .. sz\r\ncur[k] = (cur[k] or 0) + 1\r\nlocal w = pools[k] and pools[k][cur[k]]\r\nif w == nil then K.poolEmpty(bad, k); w = K.pastDie(pools, k, cur[k]) end\r\nif tonumber(ldie) ~= w then bad[#bad + 1] = k .. \" \" .. tostring(ldie) .. \"->\" .. w end\r\nlocal key, cost = luckE.pool or luckE.use or luckE.src, tonumber(luckE.n) or 1\r\nluckR.res = type(luckR.res) == \"table\" and luckR.res or {}\r\nif (tonumber(luckR.res[key]) or 0) < cost then\r\nbad[#bad + 1] = \"no \" .. key .. \" left for \" .. tostring(luckE.src)\r\nelse\r\nif not refused then luckR.res[key] = luckR.res[key] - cost end\r\nroll = roll + (lsign == \"-\" and -w or w)\r\nend\r\nend\r\nreturn roll, mode, nat\r\nend\r\n\r\nfunction K.ownSheet(r, pc)\r\nif type(r) ~= \"table\" then return nil end\r\nif r.sheet then return r.sheet end\r\nif r == pc then return K.outerSheet or SHEET end\r\nreturn nil\r\nend\r\n\r\nfunction K.partyRecs()\r\nlocal pc = K.curPc or K.partyPc\r\nif type(pc) ~= \"table\" then return {}, nil end\r\nlocal o = { pc }\r\nfor _, a in ipairs(Ally.list(pc)) do if not a.dead then o[#o + 1] = a end end\r\nreturn o, pc\r\nend\r\n\r\nfunction K.luckFind(word)\r\nlocal recs, pc = K.partyRecs()\r\nfor _, r in ipairs(recs) do\r\nlocal sh = K.ownSheet(r, pc)\r\nfor _, e in ipairs(sh and Feat.fxOf(sh, \"d20_luck\") or {}) do\r\nif tostring(e.word or \"luck\"):lower() == word then return e, r end\r\nend\r\nend\r\nreturn nil\r\nend\r\n\r\nfunction K.portentUse(v, dry)\r\nlocal recs = K.partyRecs()\r\nlocal kept = {}\r\nfor _, r in ipairs(recs) do\r\nfor i, x in ipairs(type(r.portent) == \"table\" and r.portent or {}) do\r\nif x == v then\r\nif not dry then table.remove(r.portent, i) end\r\nreturn nil\r\nend\r\nkept[#kept + 1] = tostring(x)\r\nend\r\nend\r\nreturn \"no Portent roll of \" .. tostring(v) .. \" kept\" .. (#kept > 0 and (\" (kept: \" .. table.concat(kept, \", \") .. \")\") or \"\")\r\nend\r\nfunction K.portentRoll(rec, sh)\r\nlocal e = type(sh) == \"table\" and sh.class and Feat.fxOf(sh, \"portent\")[1]\r\nif not e then rec.portent = nil; return \"\" end\r\nlocal lv, n, at = tonumber(e.srcLv) or tonumber(sh.level) or 1, tonumber(e.n) or 2, -1\r\nfor k, v in pairs(type(e.n_at) == \"table\" and e.n_at or {}) do\r\nif tonumber(k) and tonumber(k) <= lv and tonumber(k) > at then at, n = tonumber(k), tonumber(v) or n end\r\nend\r\nrec.portent = {}\r\nfor _ = 1, n do rec.portent[#rec.portent + 1] = K.d(20) end\r\nlocal v = {}\r\nfor _, x in ipairs(rec.portent) do v[#v + 1] = tostring(x) end\r\nreturn \", \" .. (e.src or \"Portent\") .. \" \" .. table.concat(v, \", \")\r\nend\r\n\r\nfunction K.luckText(pc)\r\nlocal o = {}\r\nfor _, r in ipairs({ pc, table.unpack(Ally.list(pc)) }) do\r\nif not r.dead then\r\nlocal sh = K.ownSheet(r, pc)\r\nlocal nm = r == pc and \"Player\" or r.name\r\nfor _, e in ipairs(sh and Feat.fxOf(sh, \"d20_luck\") or {}) do\r\nlocal key, cost = e.pool or e.use or e.src, tonumber(e.n) or 1\r\nlocal left = type(r.res) == \"table\" and tonumber(r.res[key]) or 0\r\nif left >= cost then\r\nlocal w, die = tostring(e.word or \"luck\"), (e.dice or \"1d4\"):match(\"d%d+\") or \"d4\"\r\no[#o + 1] = string.format(\"%s (%s, %s, %d %s each, %d left): once any creature's d20 test is rolled, write that tag's d20 field\"\r\n.. \" as \\\"14 %s 3\\\" to add it or \\\"14 %s -3\\\" to take it off (3 the next %s of the pool); Lua spends it\", tostring(e.src), nm,\r\ne.dice or \"1d4\", cost, key, left, w, w, die)\r\nend\r\nend\r\nif type(r.portent) == \"table\" and #r.portent > 0 then\r\nlocal v = {}\r\nfor _, x in ipairs(r.portent) do v[#v + 1] = tostring(x) end\r\no[#o + 1] = string.format(\"Portent (%s): %s kept; write any creature's d20 field as \\\"portent %s\\\" to use one in its place\"\r\n.. \" (no pool die); the rest go at the next Long Rest\", nm, table.concat(v, \", \"), v[1])\r\nend\r\nend\r\nend\r\nreturn #o > 0 and table.concat(o, \"\\n\") or nil\r\nend\r\n\r\n\r\n\r\nfunction K.poolMiss(q, given, pools, cur)\r\nlocal c, n, miss, lastK = {}, 0, 0, nil\r\nfor _, x in ipairs(K.diceSeq(q)) do\r\nlocal k = \"d\" .. x.s\r\nlastK = k\r\nfor _ = 1, x.n do\r\nc[k] = (c[k] or cur[k] or 0) + 1\r\nn = n + 1\r\nif given[n] ~= (pools[k] and pools[k][c[k]]) then miss = miss + 1 end\r\nend\r\nend\r\n\r\nfor i = n + 1, #given do\r\nif lastK then c[lastK] = (c[lastK] or cur[lastK] or 0) + 1 end\r\nif not lastK or given[i] ~= (pools[lastK] and pools[lastK][c[lastK]]) then miss = miss + 1 end\r\nend\r\nreturn miss\r\nend\r\n\r\n\r\n\r\n\r\nfunction K.poolEmpty(bad, k)\r\nlocal w = k .. \" pool empty\"\r\nfor _, x in ipairs(bad) do if x == w then return end end\r\nbad[#bad + 1] = w\r\nend\r\nfunction K.pastDie(pools, k, i)\r\nlocal h = 2166136261\r\nfor _, kk in ipairs(K.POOL_ORDER) do\r\nfor _, v in ipairs(type(pools[kk]) == \"table\" and pools[kk] or {}) do h = ((h ~ (tonumber(v) or 0)) * 16777619) & 0xffffffff end\r\nend\r\nh = ((h ~ ((tonumber(i) or 0) * 2654435761 + #k)) * 16777619) & 0xffffffff\r\nh = ((h ~ (h >> 15)) * 2246822519) & 0xffffffff\r\nreturn (h ~ (h >> 13)) % tonumber(k:sub(2)) + 1\r\nend\r\n\r\n\r\n\r\n\r\nfunction K.logDice(vals)\r\nif K.diceLog and vals and not K.diceQuiet then K.diceLog[#K.diceLog + 1] = vals end\r\nend\r\n\r\n\r\nfunction K.diceText(vals, q)\r\nlocal by, took, o = {}, {}, {}\r\nfor _, x in ipairs(vals) do\r\nby[x.s] = by[x.s] or {}\r\ntable.insert(by[x.s], x.v)\r\nend\r\nfor _, d in ipairs(q and q.dice or {}) do\r\nfor _ = 1, d.n do\r\nlocal w = by[d.s]\r\nif w and (took[d.s] or 0) < #w then\r\ntook[d.s] = (took[d.s] or 0) + 1\r\no[#o + 1] = tostring(w[took[d.s]])\r\nend\r\nend\r\nend\r\nlocal seen = {}\r\nfor _, x in ipairs(vals) do\r\nseen[x.s] = (seen[x.s] or 0) + 1\r\nif seen[x.s] > (took[x.s] or 0) then o[#o + 1] = tostring(x.v) end\r\nend\r\nreturn table.concat(o, \",\")\r\nend\r\n\r\nfunction K.diceSets(s)\r\nlocal o = {}\r\nfor set in (tostring(s or \"\") .. \"/\"):gmatch(\"([^/]*)/\") do\r\nlocal l = K.diceList(set)\r\nif l ~= \"\" then o[#o + 1] = l end\r\nend\r\nreturn table.concat(o, \" / \")\r\nend\r\n\r\n\r\n\r\n\r\nK.GOES_OFF = { [\"Delayed Blast Fireball\"] = true }\r\nfunction K.goneOff(out, pc)\r\nfor who, r in pairs(Feat.cur.boom or {}) do\r\nlocal mark = \"\\3\" .. who .. \"\\3\"\r\nlocal n, k = 0, 0\r\nlocal at = 1\r\nwhile true do\r\nlocal i = out:find(mark, at, true)\r\nif not i then break end\r\nn, at = n + 1, i + #mark\r\nend\r\nlocal sp = type(r) == \"table\" and type(r.conc) == \"table\" and r.conc.boomed and r.conc.name\r\nlocal line = \"\"\r\nif sp and K.GOES_OFF[sp] then\r\nr.conc = nil\r\n\r\n\r\nline = \"\\n[CONC|end\" .. (who == \"Player\" and \"\" or (\"|\" .. who)) .. \"|auto|\" .. sp .. \"]\"\r\nend\r\nout = out:gsub(mark:gsub(\"%p\", \"%%%0\"), function() k = k + 1; return k == n and line or \"\" end)\r\nend\r\nFeat.cur.boom = nil\r\nreturn (out:gsub(\"\\3[^\\3]*\\3\", \"\"))\r\nend\r\n\r\n\r\n\r\n\r\nfunction K.diceNote(line)\r\nif type(line) ~= \"string\" then return line end\r\nlocal s, e, tag\r\nfor a, t, b in line:gmatch(\"()%[(%u+)|[^%]]*()%]\") do\r\nif K.FIX_AT[t] then s, tag, e = a, t, b end\r\nend\r\nif not s then return line end\r\nlocal at = K.FIX_AT[tag]\r\nlocal rest = line:sub(s + #tag + 2, e - 1)\r\nif not K.isFixed(tag, rest) then return line end\r\nlocal f = split(rest)\r\nlocal vi\r\nfor i, v in ipairs(f) do if v:sub(1, 4) == \"bad:\" then vi = i break end end\r\nlocal vb = rest:find(\"|bad:\", 1, true)\r\nif not (vi and vb) then return line end\r\nlocal add = {}\r\nif K.d20Log and at.d20 and at.d20 < vi and trim(K.d20Log) ~= f[at.d20] then add[#add + 1] = \"Lua d20 \" .. trim(K.d20Log) end\r\nif at.dice and at.dice < vi then\r\nlocal wrote = K.diceSets(f[at.dice])\r\nlocal shown = f[at.formula]\r\nfor part in (f[vi]:sub(5) .. \";\"):gmatch(\"([^;]*);\") do shown = trim(part):match(\"^formula .-%->(.+)$\") or shown end\r\nlocal q = parseFormula(shown or \"\")\r\nlocal sets = {}\r\nfor _, vals in ipairs(K.diceLog or {}) do\r\nlocal t = K.diceText(vals, q)\r\nif t ~= \"\" then sets[#sets + 1] = t end\r\nend\r\nlocal lua = table.concat(sets, \" / \")\r\nif #(K.diceLog or {}) == 0 and wrote ~= \"\" then lua = \"-\" end\r\nif lua ~= \"\" and lua ~= wrote then add[#add + 1] = \"Lua dice \" .. lua end\r\nend\r\nif #add == 0 then return line end\r\nlocal ve = rest:find(\"|\", vb + 1, true) or (#rest + 1)\r\nrest = rest:sub(1, ve - 1) .. \";\" .. table.concat(add, \";\") .. rest:sub(ve)\r\nreturn line:sub(1, s - 1) .. \"[\" .. tag .. \"|\" .. rest .. line:sub(e)\r\nend\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\nlocal function spendDice(p, givenText, pools, cur, bad, pModel)\r\nlocal fill = givenText == \"?\"\r\nlocal given = {}\r\nfor v in (givenText or \"\"):gmatch(\"%-?%d+\") do given[#given + 1] = tonumber(v) end\r\nlocal byS\r\nif type(pModel) == \"table\" and not fill and not K.MAXDICE\r\nand K.poolMiss(pModel, given, pools, cur) <= K.poolMiss(p, given, pools, cur) then\r\nbyS = {}\r\nlocal gi, lastS = 0, nil\r\nfor _, x in ipairs(K.diceSeq(pModel)) do\r\nbyS[x.s] = byS[x.s] or {}\r\nlastS = x.s\r\nfor _ = 1, x.n do\r\ngi = gi + 1\r\ntable.insert(byS[x.s], given[gi] or false)\r\nend\r\nend\r\n\r\n\r\nif lastS then for i = gi + 1, #given do table.insert(byS[lastS], given[i]) end end\r\nend\r\nlocal sum, gi, vals, took = 0, 0, {}, {}\r\n\r\n\r\nlocal mm, wr, gt = {}, {}, {}\r\nlocal function check(k, g, v)\r\nwr[k] = wr[k] or {}; gt[k] = gt[k] or {}\r\nwr[k][#wr[k] + 1] = tonumber(g) or -999\r\ngt[k][#gt[k] + 1] = v\r\nif g ~= v then mm[#mm + 1] = { k = k, g = g, v = v } end\r\nend\r\nfor _, x in ipairs(K.diceSeq(p)) do\r\nlocal k = \"d\" .. x.s\r\nfor _ = 1, x.n do\r\ngi = gi + 1\r\nlocal v\r\nif K.MAXDICE then\r\nv = x.s\r\nif given[gi] ~= v and not fill then bad[#bad + 1] = k .. \" \" .. tostring(given[gi]) .. \"->\" .. v end\r\nelseif byS then\r\nlocal w = byS[x.s]\r\ntook[x.s] = (took[x.s] or 0) + 1\r\nif w and took[x.s] <= #w then\r\nlocal g = w[took[x.s]] or nil\r\ncur[k] = (cur[k] or 0) + 1\r\nv = pools[k] and pools[k][cur[k]]\r\nif v == nil then K.poolEmpty(bad, k); v = K.pastDie(pools, k, cur[k]) end\r\ncheck(k, g, v)\r\nelse\r\nv = K.d(x.s)\r\nend\r\nelse\r\ncur[k] = (cur[k] or 0) + 1\r\nv = pools[k] and pools[k][cur[k]]\r\nif v == nil then K.poolEmpty(bad, k); v = K.pastDie(pools, k, cur[k]) end\r\nif not fill then check(k, given[gi], v) end\r\nend\r\nsum = sum + (x.neg and -v or v)\r\nvals[#vals + 1] = { s = x.s, v = v, neg = x.neg }\r\nend\r\nend\r\nfor _, x in ipairs(mm) do\r\nlocal a, b = wr[x.k], gt[x.k]\r\nlocal sa, sb = {}, {}\r\nfor i, y in ipairs(a) do sa[i] = y end\r\nfor i, y in ipairs(b) do sb[i] = y end\r\ntable.sort(sa); table.sort(sb)\r\nlocal same = #sa == #sb\r\nfor i = 1, #sa do if sa[i] ~= sb[i] then same = false end end\r\nif not same then bad[#bad + 1] = x.k .. \" \" .. tostring(x.g) .. \"->\" .. x.v end\r\nend\r\n\r\nfor s, w in pairs(byS or {}) do\r\nlocal extra = #w - (took[s] or 0)\r\nif extra > 0 then cur[\"d\" .. s] = (cur[\"d\" .. s] or 0) + extra end\r\nend\r\nK.logDice(vals)\r\nreturn math.max(0, sum + p.mod), vals, sum + p.mod\r\nend\r\n\r\n\r\n\r\nfunction K.spendRefused(pools, cur, d20, formula, dice)\r\nlocal quiet = K.diceQuiet\r\nK.diceQuiet = true\r\nif d20 and tostring(d20):find(\"%d\") then takeD20(cur, pools, tostring(d20), {}) end\r\nlocal q = parseFormula(formula or \"\")\r\nif q and #K.diceSeq(q) > 0 then\r\nfor set in (tostring(dice or \"\") .. \"/\"):gmatch(\"([^/]*)/\") do\r\nif set:find(\"%d\") then spendDice(q, set, pools, cur, {}, q) end\r\nend\r\nend\r\nK.diceQuiet = quiet\r\nend\r\n\r\nfunction K.spendWritten(f, pools, cur)\r\nK.spendRefused(pools, cur, nil, f[7], f[8])\r\nend\r\n\r\nfunction K.diceList(s)\r\nlocal o = {}\r\nfor v in tostring(s or \"\"):gmatch(\"%-?%d+\") do o[#o + 1] = v end\r\nreturn table.concat(o, \",\")\r\nend\r\n\r\n\r\nfunction K.oneRoll(sum, before, cur, pools, q, p, wroteText)\r\nlocal used, seen = {}, {}\r\nfor _, f in ipairs({ q, p }) do\r\nfor _, d in ipairs(f.dice) do\r\nlocal k = \"d\" .. d.s\r\nif not seen[k] then\r\nseen[k] = true\r\nfor i = (before[k] or 0) + 1, cur[k] or 0 do used[#used + 1] = pools[k] and pools[k][i] end\r\nend\r\nend\r\nend\r\nreturn { sum = sum, dice = table.concat(used, \",\"), wrote = K.diceList(wroteText) }\r\nend\r\nfunction K.sameRoll(full, text)\r\nlocal w = K.diceList(text)\r\nreturn w == full.dice or (w ~= \"\" and w == full.wrote)\r\nend\r\n\r\n\r\n\r\nfunction K.ownRoll(r)\r\nreturn r.dice == \"\" and r.wrote == \"\"\r\nend\r\n\r\nfunction K.wroteF(formula, dice)\r\nlocal q = parseFormula(formula or \"\")\r\nif q then return q end\r\nif trim(dice or \"-\") == \"-\" or trim(dice or \"\") == \"\" then return { dice = {}, mod = 0 } end\r\nreturn nil\r\nend\r\n\r\n\r\n\r\n\r\n\r\nK.D20_FIELD = { ATTACK = 3, CHECK = 2, SAVE = 3, DEATH = 1, TRAP = 3, HAZARD = 4, CLIMAX = 2, ADVANCE = 5, STRIP = 2 }\r\nfunction K.nextRoll(tag, rest, pools, cur)\r\nlocal i = K.D20_FIELD[tag]\r\nif not i then return false end\r\nlocal field = split(rest)[i] or \"\"\r\n\r\nlocal pre, word = field:match(\"^(.-%d)%s*%+?%s*([^%d%s,%+]+)%s*%d+%s*$\")\r\nif word and K.D4_BUFF[word:lower()] then field = pre end\r\nlocal nums = {}\r\nfor v in field:gmatch(\"%d+\") do nums[#nums + 1] = tonumber(v) end\r\n\r\nlocal md = field:match(\"^%s*(%a+)%s\")\r\nif md == \"bi\" or (md and K.FX_MODE[md] and K.FX_MODE[md].t == \"die_bonus\") then nums = { nums[1] } end\r\nif #nums == 0 then return false end\r\nlocal d = type(pools) == \"table\" and type(pools.d20) == \"table\" and pools.d20 or {}\r\nlocal p1, p2 = d[(cur.d20 or 0) + 1], d[(cur.d20 or 0) + 2]\r\nif #nums == 1 then return p1 == nums[1] end\r\nreturn (p1 == nums[1] and p2 == nums[2]) or (p1 == nums[2] and p2 == nums[1])\r\nend\r\n\r\n\r\nfunction Feat.gentleFix(r)\r\nif K.DEATH == \"gentle\" and type(r) == \"table\" and (tonumber(r.hp) or 0) <= 0 and not r.dead then\r\nr.stable = true\r\nr.ds = { s = 0, f = 0 }\r\nend\r\nend\r\n\r\n\r\nfunction Feat.downFix(r)\r\nif not (type(r) == \"table\" and type(r.mode) == \"table\" and ((tonumber(r.hp) or 0) <= 0 or Cond.fx(r).incap)) then return end\r\nif r.mode.name == \"Rage\" then r.mode = nil; return end\r\n\r\n\r\nfor _, e in ipairs(K.modeFx(r, r.sheet or SHEET)) do\r\nif e.incap_ends then r.mode = nil; return end\r\nend\r\nend\r\n\r\n\r\n\r\n\r\nlocal function hurtPC(pc, dmg, crit)\r\nlocal adj = K.lastAdj\r\nK.lastAdj = nil\r\n\r\nlocal root = K.curPc or K.partyPc\r\nlocal real = root ~= nil and (pc == root or (function()\r\nfor _, a in ipairs(Ally.list(root)) do if a == pc then return true end end\r\nreturn false\r\nend)())\r\nif Feat.cur and type(Feat.cur.hpLost) == \"table\" and real then Feat.cur.hpLost[K.byKey(pc)] = nil end\r\nif dmg <= 0 or pc.dead then return \"\" end\r\n\r\nK.shieldTook = nil\r\nlocal shK = K.byKey(pc)\r\nlocal shield = Feat.cur and type(Feat.cur.dmgShield) == \"table\" and Feat.cur.dmgShield[shK]\r\nif shield then\r\nFeat.cur.dmgShield[shK] = nil\r\nK.shieldTook = true\r\nreturn \" (\" .. shield .. \": teleported out of the way, no damage)\"\r\nend\r\n\r\nlocal addNote = \"\"\r\nif adj and adj.rec == pc and type(adj.parts) == \"table\" and K.AR and K.AR.on() then\r\nlocal sh = pc.sheet or SHEET\r\nfor _, e in ipairs(sh and Feat.fxOf(sh, \"dmg_add_stim\") or {}) do\r\nfor _, ty in ipairs(e.types or {}) do\r\nlocal part = math.min(dmg, tonumber(adj.parts[ty]) or 0)\r\nif part > 0 then\r\nlocal txt, extra = K.AR.give(pc, part, K.curPc or pc, K.curC, false, pc.name or \"Player\", nil, { type = ty, raw = true })\r\naddNote = addNote .. string.format(\" (%s: %d %s stimulation, %s)\", e.src or \"dmg_add_stim\", part, ty, tostring(txt))\r\nif extra and extra ~= \"\" then Feat.cur.dtsLines = (Feat.cur.dtsLines or \"\") .. extra end\r\nadj.parts[ty] = nil\r\nend\r\nend\r\nend\r\nend\r\n\r\nlocal hp0 = math.max(0, tonumber(pc.hp) or 0)\r\nlocal out = K.hurtPC1(pc, dmg, crit)\r\nlocal lost = hp0 - math.max(0, tonumber(pc.hp) or 0)\r\nif Feat.cur and real then\r\nFeat.cur.hpLost = type(Feat.cur.hpLost) == \"table\" and Feat.cur.hpLost or {}\r\nFeat.cur.hpLost[K.byKey(pc)] = lost > 0 and lost or nil\r\nend\r\nreturn addNote .. out\r\nend\r\nfunction K.hurtPC1(pc, dmg, crit)\r\n\r\nlocal stimNote = \"\"\r\nif K.AR and K.AR.dmgToStim then\r\ndmg, stimNote = K.AR.dmgToStim(pc, dmg)\r\nif dmg <= 0 then return stimNote end\r\nend\r\nif K.AR and K.AR.stimHealEnds then stimNote = stimNote .. K.AR.stimHealEnds(pc) end\r\nif K.AR and K.AR.condDamaged then stimNote = stimNote .. K.AR.condDamaged(pc) end\r\nif stimNote ~= \"\" then return stimNote .. K.hurtPC0(pc, dmg, crit) .. K.polyGone(pc) end\r\nreturn K.hurtPC0(pc, dmg, crit) .. K.polyGone(pc)\r\nend\r\n\r\nfunction K.polyGone(r)\r\nif not (type(r) == \"table\" and r.form and type(r.formBy) == \"table\" and (tonumber(r.thp) or 0) <= 0) then return \"\" end\r\nlocal sp = r.formBy.spell\r\nr.form, r.formBy, r.formEnds, r.thp = nil, nil, nil, nil\r\nreturn \" (\" .. tostring(sp) .. \" ends: its Temporary HP are gone)\"\r\nend\r\n\r\nfunction K.hurtPC0(pc, dmg, crit)\r\n\r\nlocal wsh = pc.sheet or (pc == K.curPc and SHEET) or nil\r\nif (tonumber(pc.ward) or 0) > 0 and type(wsh) == \"table\" and not K.wardOf(wsh) then pc.ward = nil end\r\nlocal wd = tonumber(pc.ward) or 0\r\nif wd > 0 and dmg > 0 then\r\nlocal soak = math.min(wd, dmg)\r\npc.ward = wd - soak\r\nlocal wn = string.format(\" (Arcane Ward took %d, %d left)\", soak, pc.ward)\r\nif dmg - soak <= 0 then return wn end\r\nreturn wn .. K.hurtPC00(pc, dmg - soak, crit)\r\nend\r\nreturn K.hurtPC00(pc, dmg, crit)\r\nend\r\nfunction K.hurtPC00(pc, dmg, crit)\r\nlocal thp = tonumber(pc.thp) or 0\r\nif thp > 0 then\r\nlocal soak = math.min(thp, dmg)\r\npc.thp = thp - soak\r\ndmg = dmg - soak\r\nif dmg <= 0 then\r\n\r\n\r\nif (tonumber(pc.hp) or 0) <= 0 and not pc.dead and K.DEATH ~= \"gentle\" then\r\npc.stable = false\r\npc.ds = type(pc.ds) == \"table\" and pc.ds or { s = 0, f = 0 }\r\npc.ds.f = (tonumber(pc.ds.f) or 0) + (crit and 2 or 1)\r\nif pc.ds.f >= 3 then pc.dead = true end\r\nend\r\nreturn \" (temporary HP)\"\r\nend\r\nend\r\n\r\nlocal rule = K.DEATH\r\nif pc.hp > 0 then\r\nlocal rest = dmg - pc.hp\r\npc.hp = math.max(0, pc.hp - dmg)\r\n\r\nif pc.hp == 0 and type(pc.buff) == \"table\" and type(pc.buff[\"Death Ward\"]) == \"table\" then\r\npc.buff[\"Death Ward\"] = nil\r\npc.hp = 1\r\nreturn \" (Death Ward: 1 HP)\"\r\nend\r\nif pc.hp == 0 and type(pc.res) == \"table\" and (pc.res[\"Relentless Endurance\"] or 0) > 0 and (rule == \"gentle\" or rest < pc.max) then\r\npc.res[\"Relentless Endurance\"] = pc.res[\"Relentless Endurance\"] - 1\r\npc.hp = 1\r\nreturn \" (Relentless Endurance)\"\r\nelseif pc.hp == 0 and rest < pc.max and type(pc.mode) == \"table\" and pc.mode.name == \"Rage\"\r\nand #Feat.fxOf(pc.sheet or SHEET, \"relentless_rage\") > 0 then\r\n\r\nlocal sh = pc.sheet or SHEET\r\nlocal dc = 10 + 5 * (tonumber(pc.rr) or 0)\r\nlocal bonus = abilityMod(K.score(sh, \"Constitution\")) + 2 + math.floor((K.charLevel(sh) - 1) / 4) + (tonumber(sh.mpb) or 0)\r\nlocal d = K.d(20)\r\npc.rr = (tonumber(pc.rr) or 0) + 1\r\nif d + bonus >= dc then\r\npc.hp = 2 * K.cl(sh, \"Barbarian\")\r\nreturn string.format(\" (Relentless Rage: d20 %d%+d vs DC %d, %d HP)\", d, bonus, dc, pc.hp)\r\nend\r\nif rule == \"gentle\" then pc.stable = true end\r\nreturn string.format(\" (Relentless Rage failed: d20 %d%+d vs DC %d)\", d, bonus, dc)\r\nelseif pc.hp == 0 and rule ~= \"harsh\" and rest < pc.max and K.zeroAct(pc) then\r\n\r\npc.zeroAct = true\r\nreturn \" (\" .. K.zeroAct(pc) .. \": still acting at 0 HP)\"\r\nelseif pc.hp == 0 and rule == \"gentle\" then\r\npc.stable = true\r\nelseif pc.hp == 0 and (rule == \"harsh\" or rest >= pc.max) then\r\npc.dead = true\r\n\r\nif Feat.cur then Feat.cur.killed = true end\r\n\r\nif rule ~= \"harsh\" then return \" (massive damage)\" end\r\nend\r\nelseif rule == \"gentle\" then\r\nreturn \"\"\r\nelseif dmg >= pc.max then\r\npc.dead = true\r\nreturn \" (massive damage)\"\r\nelse\r\npc.stable = false\r\npc.ds.f = pc.ds.f + (crit and 2 or 1)\r\nif pc.ds.f >= 3 then pc.dead = true end\r\nend\r\nreturn \"\"\r\nend\r\n\r\n\r\n\r\nfunction K.maxBonusText(r)\r\nlocal o = {}\r\nfor name, b in pairs(type(r) == \"table\" and type(r.buff) == \"table\" and r.buff or {}) do\r\nif type(b) == \"table\" and tonumber(b.maxhp) then o[#o + 1] = name .. \" +\" .. b.maxhp end\r\nend\r\ntable.sort(o)\r\nreturn #o > 0 and (\" (\" .. table.concat(o, \", \") .. \" in the maximum; Lua takes it off when it ends)\") or \"\"\r\nend\r\nfunction K.maxBonus(r)\r\nlocal n = -(K.maxDownOf and K.maxDownOf(r, \"hp\") or 0)\r\nfor _, b in pairs(type(r) == \"table\" and type(r.buff) == \"table\" and r.buff or {}) do\r\nif type(b) == \"table\" then n = n + (tonumber(b.maxhp) or 0) end\r\nend\r\nreturn n\r\nend\r\n\r\n\r\n\r\nfunction K.healRecv(t, take)\r\nif not (Feat.cur and type(t) == \"table\") then return 0, \"\" end\r\nif (tonumber(t.hp) or 0) >= (tonumber(t.max) or 0) then return 0, \"\" end\r\nlocal p = K.partyPc or K.curPc\r\nlocal sh = t.sheet or (t == p and SHEET) or nil\r\nlocal add, note = 0, \"\"\r\nfor _, e in ipairs(type(sh) == \"table\" and Feat.fxOf(sh, \"heal_received\") or {}) do\r\nlocal key = tostring(K.byKey(t)) .. \"|\" .. tostring(e.src)\r\nFeat.cur.healRecv = Feat.cur.healRecv or {}\r\nif not Feat.cur.healRecv[key] then\r\nlocal n = Ally.run(p or t, (p and t ~= p) and t or nil, function() return K.fxNum(e.amount or \"CON\", sh, e.srcLv) end)\r\nn = math.max(0, tonumber(n) or 0)\r\nif take then Feat.cur.healRecv[key] = true end\r\nadd = add + n\r\nnote = note .. string.format(\" (%s +%d)\", e.src, n)\r\nend\r\nend\r\nreturn add, note\r\nend\r\n\r\n\r\nK.AB_I = { Strength = 1, Dexterity = 2, Constitution = 3, Intelligence = 4, Wisdom = 5, Charisma = 6 }\r\nfunction K.abModOf(u, ab, pc)\r\nif type(u) ~= \"table\" then return 0 end\r\nlocal sh = K.ownSheet(u, pc or K.partyPc)\r\nif type(sh) == \"table\" and type(sh.scores) == \"table\" then return abilityMod(K.score(sh, ab)) end\r\nlocal m = MONSTERS[(K.kindOf and K.kindOf(u, pc)) or u.kind or \"\"] or {}\r\nlocal sc = type(m.ab) == \"table\" and tonumber(m.ab[K.AB_I[ab] or 0])\r\nif sc then return abilityMod(sc) end\r\nif ab == \"Constitution\" and tonumber(m.conm) then return tonumber(m.conm) end\r\nreturn tonumber((m.saves or {})[ab]) or 0\r\nend\r\n\r\nfunction K.gainExtra(sh, k)\r\nlocal b = type(sh) == \"table\" and (sh.base or sh) or nil\r\nfor key, v in pairs(b and type(b.pickLR) == \"table\" and b.pickLR or {}) do\r\nif tostring(key):find(\"^gain:\") and v == k then return 1 end\r\nend\r\nreturn 0\r\nend\r\n\r\n\r\nfunction K.restNoHp(sh, kind)\r\nfor _, e in ipairs(type(sh) == \"table\" and Feat.fxOf(sh, \"rest_no_hp\") or {}) do\r\nlocal fits = type(e.rests) ~= \"table\"\r\nfor _, r in ipairs(type(e.rests) == \"table\" and e.rests or {}) do if r == kind then fits = true end end\r\nif fits then return e.src or \"rest_no_hp\" end\r\nend\r\nreturn nil\r\nend\r\n\r\n\r\nfunction K.healHalf(rec, pc)\r\nlocal p = pc or K.partyPc or K.curPc\r\nlocal sh = type(rec) == \"table\" and (rec.sheet or (rec == p and SHEET)) or nil\r\nlocal e = type(sh) == \"table\" and Feat.fxOf(sh, \"heal_half\")[1]\r\nreturn e and (e.src or \"heal_half\") or nil\r\nend\r\n\r\nfunction K.healWrote(f5, base, t)\r\nlocal add = base > 0 and K.healRecv(t, false) or 0\r\nlocal w = tonumber(f5)\r\nreturn w == base or w == base + add, base + add\r\nend\r\nlocal function healPC(pc, n, noRecv)\r\nK.healRecvLast = \"\"\r\nif n > 0 and not noRecv then\r\nlocal add, note = K.healRecv(pc, true)\r\nif add > 0 then n = n + add; K.healRecvLast = note end\r\nend\r\nif n > 0 then pc.zeroAct = nil end\r\nif pc.hp <= 0 and n > 0 then pc.ds = { s = 0, f = 0 }; pc.stable = false end\r\npc.hp = math.min(pc.max, pc.hp + n)\r\nend\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\nfunction Spell.stats(name, cls)\r\n\r\n\r\ncls = cls or (SHEET and ((name and K.spellClassOf(SHEET, name)) or K.castCl(SHEET)))\r\nlocal cl = CLASSES[cls or \"\"]\r\nlocal ab = cl and cl.spell_ability\r\nif name and SHEET then\r\nlocal x = Feat.extras(SHEET)[name]\r\nif x and (x.only or not (ab and Spell.classKnown(name))) then ab = x.ab end\r\nend\r\nif not ab then return nil end\r\nlocal m = MOD[ab]\r\n\r\nlocal dr = SHEET and K.drainOf(SHEET, ab)\r\nif dr and dr.keepSpell then m = abilityMod(tonumber((type(SHEET.mscores) == \"table\" and SHEET.mscores[ab]) or SHEET.scores[ab]) or 10) end\r\nlocal innate = Cond.cur and type(Cond.cur.mode) == \"table\" and Cond.cur.mode.name == \"Innate Sorcery\" and cls == \"Sorcerer\" and 1 or 0\r\n\r\n\r\nlocal cur = Spell.cur\r\nif not (type(cur) == \"table\" and cur.name == name) then cur = Cond.cur and Cond.cur.conc end\r\nif name and type(cur) == \"table\" and cur.name == name and (cur.dc or cur.atk) then\r\nreturn { ab = ab, mod = m, dc = cur.dc or (8 + PROF + m), atk = cur.atk or (PROF + m), item = true }\r\nend\r\nlocal bdc, batk = 0, 0\r\nif K.MI and Cond.cur then bdc, batk = K.MI.sum(Cond.cur, \"spelldc\"), K.MI.sum(Cond.cur, \"spellatk\") end\r\nreturn { ab = ab, mod = m, dc = 8 + PROF + m + innate + bdc, atk = PROF + m + batk + (K.buffSum and K.buffSum(Cond.cur, \"atk\") or 0) }\r\nend\r\n\r\n\r\n\r\nfunction K.castMinutes(sp)\r\nlocal t = tostring(sp and sp.time or \"\")\r\nlocal m = tonumber(t:match(\"(%d+)분\"))\r\nif m then return m end\r\nlocal h = tonumber(t:match(\"(%d+)시간\"))\r\nreturn h and h * 60 or 0\r\nend\r\n\r\nfunction Spell.classKnown(name)\r\nreturn SHEET ~= nil and K.allLists(SHEET)[name] == true\r\nend\r\n\r\n\r\nfunction Spell.any()\r\nreturn SHEET ~= nil and #Spell.names() > 0\r\nend\r\n\r\nfunction Spell.known(name)\r\nreturn Spell.classKnown(name) or (SHEET and Feat.extras(SHEET)[name] ~= nil) or false\r\nend\r\n\r\n\r\nfunction Spell.names()\r\nlocal out, seen = {}, {}\r\nlocal function add(n) if not seen[n] and SPELLS[n] then seen[n] = true; out[#out + 1] = n end end\r\nfor _, v in ipairs(K.casterViews(SHEET)) do\r\nfor _, n in ipairs(v.cantrips or {}) do add(n) end\r\nfor _, n in ipairs(v.spells or {}) do add(n) end\r\nend\r\nfor _, n in ipairs(Feat.always(SHEET)) do add(n) end\r\nlocal ex = {}\r\nfor n in pairs(Feat.extras(SHEET)) do ex[#ex + 1] = n end\r\ntable.sort(ex)\r\nfor _, n in ipairs(ex) do add(n) end\r\nreturn out\r\nend\r\n\r\n\r\nfunction K.cantripTier(level)\r\nlevel = level or 1\r\nreturn 1 + (level >= 5 and 1 or 0) + (level >= 11 and 1 or 0) + (level >= 17 and 1 or 0)\r\nend\r\n\r\n\r\n\r\n\r\nfunction Spell.formula(name, base, level, part)\r\nlocal sp = SPELLS[name]\r\nlocal m = sp and sp.m or {}\r\nlocal st = Spell.stats(name)\r\nlocal lvl = tostring(math.max(level or 0, sp and sp.level or 0))\r\nlocal text = base:gsub(\"MOD\", tostring(st and st.mod or 0)):gsub(\"LVL\", lvl)\r\nlocal p = parseFormula(text)\r\nif not p then return nil end\r\n\r\nif name == \"Eldritch Blast\" and SHEET and Feat.invoked(SHEET, \"Agonizing Blast\") then p.mod = p.mod + MOD.Charisma end\r\n\r\nif m.cantrip and not m.beams and SHEET then\r\nlocal x = K.cantripTier(K.charLevel(SHEET))\r\nfor _, d in ipairs(p.dice) do d.n = d.n * x end\r\nend\r\n\r\nif m.grow and SHEET then\r\nfor _, at in ipairs(m.grow.at) do\r\nif K.cl(SHEET, m.grow.cls or SHEET.class) >= at then\r\nfor _, d in ipairs(parseFormula(m.grow.dice).dice) do p.dice[#p.dice + 1] = { n = d.n, s = d.s } end\r\nend\r\nend\r\nend\r\nlocal up = m.upcast\r\nlocal extra = (level or 0) - (sp and sp.level or 0)\r\nif up and up.dice and extra > 0 and (not up.applies_to or up.applies_to == part) then\r\nlocal u = parseFormula(up.dice)\r\nfor _, d in ipairs(u.dice) do p.dice[#p.dice + 1] = { n = d.n * extra, s = d.s } end\r\nend\r\n\r\nif SHEET and sp and (base == m.damage or (m.extra_save and base == m.extra_save.damage)) then\r\np.mod = p.mod + Feat.spellMod(name, sp, m, base)\r\nend\r\nreturn canon(p, false)\r\nend\r\n\r\n\r\n\r\nfunction K.extraDice(want, m, wrote)\r\nlocal ed = type(m) == \"table\" and type(m.extra_dice) == \"table\" and parseFormula(m.extra_dice.die or \"\")\r\nlocal w, p = want and parseFormula(want), parseFormula(wrote or \"\")\r\nif not (ed and #ed.dice == 1 and w and p) or p.mod ~= w.mod then return want end\r\nlocal s = ed.dice[1].s\r\nlocal function count(f)\r\nlocal o = {}\r\nfor _, d in ipairs(f.dice) do o[d.s] = (o[d.s] or 0) + d.n end\r\nreturn o\r\nend\r\nlocal a, b = count(w), count(p)\r\nfor k, n in pairs(a) do if k ~= s and b[k] ~= n then return want end end\r\nfor k, n in pairs(b) do if k ~= s and a[k] ~= n then return want end end\r\nif (b[s] or 0) < (a[s] or 0) then return want end\r\nreturn canon(p, false)\r\nend\r\n\r\n\r\n\r\n\r\nfunction K.formCast(sh, name)\r\nlocal sp = SPELLS[name]\r\nif type(sh) ~= \"table\" or not sp then return false end\r\nif K.cl(sh, \"Druid\") >= 18 and not sp.cost and not sp.mcons then return true end\r\nfor _, e in ipairs(Feat.fxOf(sh, \"form_cast\")) do\r\nfor _, n in ipairs(type(e.spells) == \"table\" and e.spells or {}) do if n == name then return true end end\r\nend\r\nreturn false\r\nend\r\n\r\n\r\n\r\n\r\nfunction Spell.active(pc)\r\nlocal out = {}\r\nlocal mine = Spell.cur and (Spell.cur.by or \"Player\") == (pc.name or \"Player\")\r\nif mine then out[#out + 1] = Spell.cur end\r\nif type(pc.conc) == \"table\" and pc.conc.name and not (mine and Spell.cur.name == pc.conc.name) then out[#out + 1] = pc.conc end\r\n\r\nfor name, l in pairs(type(pc.lasting) == \"table\" and pc.lasting or {}) do\r\nif not (mine and Spell.cur.name == name) then out[#out + 1] = { name = name, level = l } end\r\nend\r\nreturn out\r\nend\r\n\r\n\r\nfunction K.stimWhyKo(w)\r\nif w == \"Incapacitated by a climax\" then return \"절정으로 행동불능\" end\r\nif w == \"numbness\" then return \"둔감\" end\r\nreturn K.toKo and K.toKo(w) or w\r\nend\r\n\r\n\r\nK.STIM_KO = { Bludgeoning = \"문지름\", Piercing = \"파고듦\", Slashing = \"할퀴기\", Thunder = \"떨림\", Force = \"마력\", Necrotic = \"오싹함\" }\r\nfunction K.stimKo(ty)\r\nreturn K.STIM_KO[ty or \"\"] or (K.DMG_KO and K.DMG_KO[ty or \"\"]) or ty\r\nend\r\n\r\n\r\n\r\nfunction K.arResultKo(who, note, ty, amt)\r\nnote = tostring(note or \"\"):gsub(\"→\", \"->\"):gsub(\"%-&gt;\", \"->\")\r\nlocal nty = note:match(\"^(%u%l+) %d\") or note:match(\"^(%u%l+) %-\")\r\nlocal body = nty and note:sub(#nty + 2) or note\r\nty = nty or ty\r\nlocal a1, a2 = body:match(\", CLIMAX: arousal (%d+)%->(%d+)\")\r\nlocal cur, mx = body:match(\"^(%d+)/(%d+)\")\r\nif not (a1 or cur) then return K.arNoteKo(note) end\r\nlocal fails = tonumber(body:match(\", Edging: %d+ successes, (%d+) failures\") or \"\")\r\nlocal tail = {}\r\nif ty and tonumber(amt) then tail[#tail + 1] = K.stimKo(ty) .. \" +\" .. amt end\r\nif fails and fails > 0 then tail[#tail + 1] = \"임계 실패 \" .. fails end\r\nlocal numb = body:match(\"%(numbness %-?(%d+)%)\")\r\nif numb then tail[#tail + 1] = \"둔감 -\" .. numb end\r\nlocal rw = body:match(\"%(resisted: ([^)]*)%)\")\r\nif rw then tail[#tail + 1] = \"저항: \" .. K.stimWhyKo(rw) end\r\nlocal vw = body:match(\"%(vulnerable: ([^)]*)%)\")\r\nif vw then tail[#tail + 1] = \"취약: \" .. K.stimWhyKo(vw) end\r\n\r\nlocal wd = body:match(\"%(willing: Advantage, Lua.s second d20 (%d+)%)\")\r\nif wd then tail[#tail + 1] = \"동의: 이점, Lua의 두 번째 d20 \" .. wd\r\nelseif body:find(\"(willing: Advantage, cancelled by Disadvantage)\", 1, true) then tail[#tail + 1] = \"동의: 이점, 불리와 상쇄\" end\r\nlocal out\r\nif a1 then out = who .. \" 절정: 흥분도 \" .. a1 .. \"→\" .. a2\r\nelse out = who .. \" 흥분도 \" .. cur .. \"/\" .. mx .. (body:find(\", Edging\", 1, true) and \", 임계\" or \"\") end\r\nlocal inc = body:match(\"Incapacitated for (%d+) rounds?\")\r\nlocal incTo = body:match(\"Incapacitated until round (%d+)\")\r\nif inc then out = out .. \", \" .. inc .. \"라운드 행동불능\"\r\nelseif incTo then out = out .. \", \" .. incTo .. \"라운드까지 행동불능\"\r\nelseif body:find(\"Incapacitated for a while\", 1, true) then out = out .. \", 잠시 행동불능\"\r\nelseif body:find(\"Incapacitated for a moment\", 1, true) then out = out .. \", 잠시 숨을 고름\" end\r\nif body:find(\"at its maximum (out of a fight\", 1, true) then out = out .. \", 최대\" end\r\nif body:find(\"out of the fight, as one defeated\", 1, true) then out = out .. \", 싸움에서 빠짐\" end\r\nif #tail > 0 then out = out .. \" (\" .. table.concat(tail, \", \") .. \")\" end\r\nreturn out\r\nend\r\n\r\nfunction K.arNoteKo(note)\r\n\r\nnote = tostring(note or \"\"):gsub(\"→\", \"->\"):gsub(\"%-&gt;\", \"->\")\r\nnote = note:gsub(\"^swapped to ([^:]+): \", function(w) return (K.toKo and K.toKo(w) or w) .. \"에게 넘어감: \" end)\r\nnote = note:gsub(\" %(resisted: ([^)]*)%)\", function(w) return \" (저항: \" .. K.stimWhyKo(w) .. \")\" end)\r\n:gsub(\" %(vulnerable: ([^)]*)%)\", function(w) return \" (취약: \" .. K.stimWhyKo(w) .. \")\" end)\r\nnote = K.climaxKo(note)\r\nreturn (note:gsub(\"^(%a+) \", function(ty) return K.stimKo(ty) .. \" \" end):gsub(\"numbness %-?\", \"둔감 -\")\r\n:gsub(\", Edging: (%d+) successes, (%d+) failures\", \", 임계: 성공 %1 · 실패 %2\"):gsub(\", Edging\", \", 임계\")\r\n:gsub(\", CLIMAX: arousal (%d+)%->(%d+) %(recovery dice (%d+)%)\", \", 절정: %1→%2 (회복 주사위 %3)\")\r\n:gsub(\"Incapacitated until round (%d+) %b()\", \"%1라운드까지 행동불능\"):gsub(\"Incapacitated until round (%d+)\", \"%1라운드까지 행동불능\")\r\n:gsub(\"Incapacitated for (%d+) rounds?\", \"%1라운드 행동불능\")\r\n:gsub(\", CLIMAX with no recovery dice left: out of the fight, as one defeated\", \", 회복 주사위 없이 절정: 싸움에서 빠짐\"))\r\nend\r\n\r\nfunction K.climaxKo(s)\r\nreturn (tostring(s or \"\"):gsub(\"Incapacitated for a while %((%d+) rounds?%)\", \"잠시 행동불능(%1라운드)\")\r\n:gsub(\"a second climax in a row: Stunned while it lasts\", \"두 번 연속 절정: 그동안 충격\"):gsub(\"a third in a row: Paralyzed while it lasts\", \"세 번 연속: 그동안 마비\")\r\n:gsub(\"climax (%d+) in a row\", \"%1번 연속 절정\"):gsub(\"not Incapacitated %(halved%)\", \"행동불능 없음(절반)\")\r\n:gsub(\"still Edging %(overstimulation 5%)\", \"아직 임계(과자극 5)\")\r\n:gsub(\"%(willing: Advantage, Lua.s second d20 (%d+)%)\", \"(동의: 이점, Lua의 두 번째 d20 %1)\")\r\n:gsub(\"Incapacitated for a moment %(the story's%)\", \"잠시 숨을 고름\"):gsub(\"at its maximum %(out of a fight: no Edging%)\", \"최대 (전투 밖: 임계 없음)\")\r\n:gsub(\"%(willing: Advantage, cancelled by Disadvantage%)\", \"(동의: 이점, 불리와 상쇄)\"))\r\nend\r\n\r\nfunction K.dropWill(tag, rest)\r\nlocal at = tag == \"CHECK\" and 6 or 10\r\nlocal parts = {}\r\nfor p in (rest .. \"|\"):gmatch(\"([^|]*)|\") do parts[#parts + 1] = p end\r\nlocal w = trim(parts[at] or \"\"):lower()\r\nif (w == \"willing\" or w == \"unwilling\") and #parts > at then\r\ntable.remove(parts, at)\r\nreturn table.concat(parts, \"|\")\r\nend\r\nreturn rest\r\nend\r\n\r\nfunction K.concRecs(pc)\r\nlocal o = { pc }\r\nfor _, r in ipairs(Ally.list(pc)) do o[#o + 1] = r end\r\nfor _, r in ipairs(Ally.guests and Ally.guests(pc) or {}) do o[#o + 1] = r end\r\nreturn o\r\nend\r\nfunction K.concEndClear(pc)\r\nfor _, r in ipairs(K.concRecs(pc)) do r.concEnd = nil end\r\nend\r\n\r\nfunction K.concGone(pc, fits)\r\nfor _, r in ipairs(K.concRecs(pc)) do\r\nlocal e = type(r.concEnd) == \"table\" and r.concEnd\r\nlocal sp = e and SPELLS[e.name or \"\"]\r\nif sp and fits(sp.m or {}) then\r\nreturn string.format(\"%s has ended (%s's Concentration %s): cast it again (a new CAST and slot) to use it\", e.name, r == pc and \"Player\" or (r.name or \"?\"), e.why or \"ended\")\r\nend\r\nend\r\nreturn nil\r\nend\r\n\r\nfunction K.concGoneText(r, who)\r\nlocal e = type(r) == \"table\" and type(r.concEnd) == \"table\" and r.concEnd\r\nif not (e and e.name) then return \"\" end\r\nif type(r.conc) == \"table\" and r.conc.name == e.name then return \"\" end\r\nreturn string.format(\" %s's %s has ended (its Concentration %s): it does nothing more unless cast again.\", who, e.name, e.why or \"ended\")\r\nend\r\n\r\nfunction Spell.all(pc)\r\nlocal out, rest = {}, {}\r\nfor _, r in ipairs({ pc, table.unpack(Ally.list(pc)) }) do\r\nfor _, a in ipairs(Spell.active(r)) do\r\nlocal t = (a == Spell.cur) and out or rest\r\nt[#t + 1] = { a, r }\r\nend\r\nend\r\nfor _, x in ipairs(rest) do out[#out + 1] = x end\r\nreturn out\r\nend\r\n\r\n\r\nfunction Spell.attacks(pc)\r\nif not SHEET then return {} end\r\nlocal out = {}\r\nlocal function add(name, level)\r\nlocal sp = SPELLS[name]\r\nlocal m = sp and sp.m\r\nlocal st = Spell.stats(name)\r\nif st and m and m.kind == \"attack\" and m.damage and m.attack ~= \"weapon\" then\r\n\r\nout[#out + 1] = { name = name .. \" (spell)\", hit = st.atk, dmg = Spell.formula(name, m.damage, level, m.type), spell = name, type = m.type,\r\nsrange = m.attack }\r\nelseif st and m and m.kind == \"attack\" and not m.damage and m.foe_cond and m.attack ~= \"weapon\" then\r\n\r\n\r\nout[#out + 1] = { name = name .. \" (spell; no damage, on a hit its condition)\", hit = st.atk, dmg = \"0\", spell = name, type = m.type,\r\nsrange = m.attack, nodmg = true }\r\nelseif st and m and m.kind == \"attack\" and type(m.stim) == \"table\" and m.attack ~= \"weapon\" then\r\n\r\nlocal ty = m.stim.type or \"Force\"\r\nout[#out + 1] = { name = name .. \" (spell; \" .. ty .. \" stimulation, to arousal, not HP)\", hit = st.atk,\r\ndmg = Spell.formula(name, K.spellTerms(m.stim.dice or \"1d6\", name), level, \"stim\"), spell = name, type = ty,\r\nsrange = m.attack, stim = true, level = level }\r\nend\r\nend\r\nfor _, n in ipairs(Spell.names()) do\r\nif SPELLS[n].level == 0 then add(n, 0) end\r\nend\r\nfor _, a in ipairs(Spell.active(pc)) do\r\nif SPELLS[a.name] and SPELLS[a.name].level > 0 and not K.SUMMON[a.name] then add(a.name, a.level) end\r\nend\r\nreturn out\r\nend\r\n\r\nfunction Spell.cast(f, pc, c, ctx)\r\nK.castSlot = false\r\nlocal name = Canon.name(f[1] or \"\")\r\nlocal head = \"[CAST|\" .. name .. \"|\" .. (f[2] or \"\")\r\nlocal function fail(why) return head .. \"|bad:\" .. why .. \"|-]\", false end\r\nlocal who = pc.name or \"Player\"\r\nif pc.name then head = head .. \"|\" .. who end\r\nlocal sp = SPELLS[name]\r\nif not sp then return fail(K.spellOff(name) or \"unknown spell\") end\r\nlocal gag = K.bindCastBlock(pc, sp)\r\nif gag then return fail(gag) end\r\n\r\n\r\n\r\nif (f[2] or \"\"):lower() == \"ritual\" then\r\n\r\nlocal anyR = false\r\nfor _, e in ipairs(SHEET and Feat.fxOf(SHEET, \"ritual_any\") or {}) do if sp.level >= 1 and sp.level <= (tonumber(e.max_level) or 0) then anyR = e.src or true end end\r\nif not (sp and (sp.ritual or anyR)) then return fail(\"not a ritual\") end\r\n\r\nif pc.form and (pc.formBy or not K.formCast(SHEET, name)) then return fail(who .. (pc.formBy and \" is a Beast (Polymorph): no spells\" or \" is in Wild Shape: no spells\")) end\r\nif type(pc.mode) == \"table\" and pc.mode.name == \"Rage\" then return fail(who .. \" is raging: no spells\") end\r\nfor _, e in ipairs(K.modeFx(pc, SHEET)) do\r\nif e.no_spells then return fail(who .. \" is in \" .. pc.mode.name .. \": no spells\") end\r\nend\r\n\r\nlocal rfx = Cond.fx(pc)\r\nif rfx.incap then return fail(who .. \" is \" .. rfx.incap) end\r\nif not K.upNow(pc) then return fail(who .. \" is down\") end\r\nlocal inBook = false\r\nlocal wiz = K.bookClass(SHEET) ~= nil\r\nif wiz then\r\nfor _, b in ipairs(type(SHEET.book) == \"table\" and SHEET.book or {}) do if b == name then inBook = true end end\r\nend\r\nif not (inBook or Spell.known(name)) then\r\nreturn fail(wiz and \"not prepared and not in the spellbook\" or \"not prepared\")\r\nend\r\nif c.active then return fail(\"a ritual takes 10 minutes more: not in a fight\") end\r\nif ctx.clock then ctx.clock.min = ctx.clock.min + 10 + K.castMinutes(sp) end\r\nSpell.cur = { name = name, level = sp.level, by = pc.name }\r\n\r\nFeat.cur.casts = Feat.cur.casts or {}\r\nFeat.cur.casts[#Feat.cur.casts + 1] = Spell.cur\r\n\r\n\r\nlocal rl = \"\"\r\nif type(pc.conc) == \"table\" and pc.conc.name and pc.conc.name ~= name then\r\nrl = \", ends \" .. pc.conc.name\r\npc.concEnd = { name = pc.conc.name, why = \"the ritual took the Concentration\" }\r\npc.conc = nil\r\nend\r\nif type(sp.m) == \"table\" and sp.m.concentration then\r\nlocal now = type(ctx.clock) == \"table\" and tonumber(ctx.clock.min) or nil\r\npc.conc = { name = name, level = sp.level, ends = now and (now + (sp.mins or 1)) or nil }\r\nif type(pc.concEnd) == \"table\" and pc.concEnd.name == name then pc.concEnd = nil end\r\nend\r\nreturn head .. \"|ok|ritual\" .. rl .. \"]\", true\r\nend\r\n\r\n\r\nlocal freeUse, atWill, freeFx\r\n\r\nlocal xi = Feat.extras(SHEET)[name]\r\nlocal itemL = xi and xi.item and type(pc.loot) == \"table\" and pc.loot[xi.item]\r\nlocal f2 = (f[2] or \"\"):lower()\r\n\r\nif itemL and not (f2 == \"free\" or f2:match(\"^item\") or not Spell.classKnown(name)) then itemL = nil end\r\nlocal srdCast\r\nif f2 == \"scroll\" then\r\nlocal why\r\nsrdCast, why = K.MI.scrollCast(pc, name, sp, who)\r\nif not srdCast then return fail(why) end\r\nitemL = nil\r\nelseif itemL and itemL.srd then\r\nlocal why\r\nsrdCast, why = K.MI.itemCast(pc, name, sp, xi, itemL, f2, f[2])\r\nif not srdCast then return fail(why) end\r\nitemL = nil\r\nelseif f2:match(\"^item\") then\r\nreturn fail(\"no magic item in use casts \" .. name .. (xi and xi.item and (\" (\" .. xi.item .. \" needs attunement or is not held)\") or \"\"))\r\nend\r\nif srdCast then\r\n\r\nelseif itemL then\r\nitemL.left = type(itemL.left) == \"table\" and itemL.left or {}\r\nif (itemL.left[name] or 0) < 1 then return fail(\"no uses of \" .. xi.item .. \" left (a Long Rest refills them)\") end\r\nelseif (f[2] or \"\"):lower() == \"free\" then\r\nlocal why\r\nfreeUse, why, atWill, freeFx = Feat.freeCast(SHEET, pc, name, sp)\r\nif not freeUse then return fail(why) end\r\nend\r\nlocal implanted = type(ctx) == \"table\" and ctx.implantCast == name\r\nif not freeUse and not srdCast and not implanted and not Spell.known(name) then return fail(\"not among \" .. who .. \"'s cantrips or prepared spells\") end\r\nif not Spell.stats(name) then return fail(\"not a spellcaster\") end\r\nif pc.form and (pc.formBy or not K.formCast(SHEET, name)) then return fail(who .. (pc.formBy and \" is a Beast (Polymorph): no spells\" or \" is in Wild Shape: no spells\")) end\r\nif type(pc.mode) == \"table\" and pc.mode.name == \"Rage\" and not (freeFx and freeFx.rage_ok) then return fail(who .. \" is raging: no spells\") end\r\nfor _, e in ipairs(K.modeFx(pc, SHEET)) do\r\nif e.no_spells then return fail(who .. \" is in \" .. pc.mode.name .. \": no spells\") end\r\nend\r\nif pc.taxed then return fail(who .. \" is taxed by Resurrection: no spells until a Long Rest\") end\r\nlocal fx = Cond.fx(pc)\r\n\r\nlocal upCast = type(Feat.cur.climaxCast) == \"table\" and Feat.cur.climaxCast[pc]\r\nif upCast and (upCast.used or (fx.incap and fx.incap ~= \"Incapacitated (a climax)\")) then upCast = nil end\r\nif fx.incap and not upCast then return fail(who .. \" is \" .. fx.incap) end\r\nif upCast then upCast.used = true end\r\nif not K.upNow(pc) then return fail(who .. \" is down\") end\r\nlocal bad, level, left = {}, 0, \"cantrip\"\r\n\r\nlocal x = Feat.extras(SHEET)[name]\r\nlocal want = tonumber(f[2]) or sp.level\r\nif srdCast then\r\nlevel = srdCast.level\r\nleft = srdCast.commit()\r\n\r\nif srdCast.fizzle then\r\nreturn head .. \"|bad:the scroll's check failed, the spell fades with no effect|\" .. left .. \"]\", false\r\nend\r\nelseif itemL then\r\nlevel = sp.level\r\nitemL.left[name] = itemL.left[name] - 1\r\nleft = string.format(\"%s %d/%d\", xi.item, itemL.left[name], LOOT.SPELL_USES[itemL.grade] or 1)\r\nelseif implanted then\r\nlevel, left = tonumber(ctx.implantLevel) or sp.level, \"implanted in \" .. tostring(ctx.implantOn) .. \", no slot\"\r\nelseif freeUse and atWill then\r\nlevel, left = K.freeLevel(freeFx, sp), freeUse .. \", at will\"\r\nelseif freeUse then\r\nlevel = K.freeLevel(freeFx, sp)\r\nlocal cost = tonumber(type(freeFx) == \"table\" and freeFx.n) or 1\r\nif (pc.res[freeUse] or 0) < cost then return fail(\"no \" .. cost .. \" \" .. freeUse .. \" left\") end\r\n\r\n\r\nif freeUse == \"Signature Spells\" then\r\nlocal mx = PC.res[freeUse] and PC.res[freeUse].max or 2\r\nif (pc.res[freeUse] or 0) >= mx then pc.sigUsed = nil end\r\nif type(pc.sigUsed) == \"table\" and pc.sigUsed[name] then return fail(name .. \"'s free casting is used (each Signature Spell once, back on a Short or Long Rest)\") end\r\npc.sigUsed = type(pc.sigUsed) == \"table\" and pc.sigUsed or {}\r\npc.sigUsed[name] = true\r\nend\r\npc.res[freeUse] = pc.res[freeUse] - cost\r\nleft = string.format(\"%s %d/%d\", freeUse, pc.res[freeUse], PC.res[freeUse] and PC.res[freeUse].max or 1)\r\nelseif x and x.only then\r\nif (pc.res[x.free] or 0) < 1 then return fail(\"no \" .. x.free .. \" uses left\") end\r\npc.res[x.free] = pc.res[x.free] - 1\r\nleft = string.format(\"%s %d/%d\", x.free, pc.res[x.free], PC.res[x.free].max)\r\nelseif sp.level > 0 and x and x.atwill and want <= sp.level then\r\nlevel, left = x.fx and K.freeLevel(x.fx, sp) or sp.level, \"at will\"\r\nelseif sp.level > 0 and x and x.free and want <= sp.level and (pc.res[x.free] or 0) >= (tonumber(x.fx and x.fx.n) or 1) then\r\nlevel = x.fx and K.freeLevel(x.fx, sp) or sp.level\r\npc.res[x.free] = pc.res[x.free] - (tonumber(x.fx and x.fx.n) or 1)\r\nleft = string.format(\"%s %d/%d\", x.free, pc.res[x.free], PC.res[x.free].max)\r\nelseif sp.level > 0 and PC.res[name .. \" (free)\"] and want <= sp.level and (pc.res[name .. \" (free)\"] or 0) > 0 then\r\n\r\nlocal key = name .. \" (free)\"\r\nlevel = sp.level\r\npc.res[key] = pc.res[key] - 1\r\nleft = K.MP.after(pc, key) or string.format(\"%s %d/%d\", key, pc.res[key], PC.res[key].max)\r\nelseif sp.level > 0 and want <= sp.level and select(3, Feat.freeCast(SHEET, pc, name, sp)) then\r\n\r\nlocal fu, _, _, fe = Feat.freeCast(SHEET, pc, name, sp)\r\nlevel, left = K.freeLevel(fe, sp), fu .. \", at will\"\r\nelseif sp.level > 0 then\r\nlevel = tonumber(f[2]) or sp.level\r\nif level < sp.level then bad[#bad + 1] = \"slot \" .. level .. \"->\" .. sp.level; level = sp.level end\r\nlocal key = \"Spell Slot \" .. level\r\n\r\nlocal pact = K.pactLevel()\r\nif pact and level < pact and not PC.res[key] then level, key = pact, \"Spell Slot \" .. pact end\r\n\r\n\r\n\r\n\r\n\r\n\r\nlocal upFrom\r\nlocal function between(lo, hi)\r\nfor l = lo, hi do if PC.res[\"Spell Slot \" .. l] and (pc.res[\"Spell Slot \" .. l] or 0) > 0 then return true end end\r\nreturn false\r\nend\r\nlocal pl = K.pactSlotLevel()\r\nif pl and (pc.res[\"Pact Slot \" .. pl] or 0) > 0 and (level == pl or (level < pl and (pc.res[key] or 0) < 1 and not between(level + 1, pl - 1))) then\r\nif level < pl and PC.res[key] then upFrom = level end\r\nlevel, key = pl, \"Pact Slot \" .. pl\r\nend\r\nlocal icl = not PC.res[key] and K.implantClass(SHEET)\r\nif icl then return fail(\"a \" .. icl .. \" has no spell slots: its spells go in with [IMPLANT|Target|Spell|level|trigger] and go off with [TRIGGER|Target|Spell]\") end\r\nif not PC.res[key] then return fail(K.LITE and (\"no level \" .. level .. \" spells yet\") or (\"no level \" .. level .. \" slots\")) end\r\nif (pc.res[key] or 0) < 1 and not K.LITE then\r\nfor l = level + 1, 9 do\r\nlocal k2 = \"Spell Slot \" .. l\r\nif PC.res[k2] and (pc.res[k2] or 0) > 0 then upFrom, level, key = level, l, k2; break end\r\nend\r\nend\r\nif (pc.res[key] or 0) < 1 then return fail(K.MP.short(pc, key, 1, \"level \" .. level) or (\"no level \" .. level .. \" slots left, none higher either\")) end\r\npc.res[key] = pc.res[key] - 1\r\nK.castSlot = true\r\nleft = K.MP.after(pc, key) or string.format(\"%s %d: %d/%d\", key:match(\"^Pact\") and \"pact slot\" or \"slot\", level, pc.res[key], PC.res[key].max)\r\nif upFrom then left = left .. string.format(\" (no level %d slot left: cast at level %d)\", upFrom, level) end\r\nend\r\nif K.castSlot then left = left .. K.wardCast(pc, SHEET, name, level) end\r\n\r\n\r\nlocal ownFx = (freeFx and freeFx.ability and freeFx) or (x and x.fx and not K.castSlot and x.fx) or nil\r\nlocal ownDc, ownAtk\r\nif ownFx and ABBR[ownFx.ability] then\r\nlocal om = MOD[ABBR[ownFx.ability]] or 0\r\nownDc, ownAtk = 8 + PROF + om, PROF + om\r\nend\r\nlocal m = sp.m or {}\r\n\r\nlocal durMins, isConc = sp.mins, m.concentration\r\nfor _, d in ipairs(type(m.dur_at) == \"table\" and m.dur_at or {}) do\r\nif type(d) == \"table\" and level >= (tonumber(d.level) or 99) then\r\ndurMins = tonumber(d.mins) or durMins\r\nif d.conc ~= nil then isConc = d.conc and true or nil end\r\nend\r\nend\r\nif isConc then\r\nif type(pc.conc) == \"table\" and pc.conc.name then left = left .. \", ends \" .. pc.conc.name end\r\n\r\nlocal now = type(ctx) == \"table\" and type(ctx.clock) == \"table\" and tonumber(ctx.clock.min) or nil\r\n\r\nif type(pc.conc) == \"table\" and pc.conc.name and pc.conc.name ~= name then pc.concEnd = { name = pc.conc.name, why = \"moved to another spell\" }\r\nelseif type(pc.concEnd) == \"table\" and pc.concEnd.name == name then pc.concEnd = nil end\r\npc.conc = { name = name, level = level, ends = now and (now + (durMins or 1)) or nil,\r\ndc = (srdCast and srdCast.dc) or ownDc, atk = (srdCast and srdCast.atk) or ownAtk }\r\nend\r\n\r\n\r\nif m.ac_base or m.ac_bonus then\r\npc.buff = type(pc.buff) == \"table\" and pc.buff or {}\r\nlocal now = ctx.clock and ctx.clock.min or 0\r\npc.buff[name] = { base = m.ac_base, bonus = m.ac_bonus, conc = m.concentration or nil,\r\nends = m.ac_base and (now + 480) or (m.cast == \"reaction\" and -2 or -1) }\r\nend\r\nctx.rolls = ctx.rolls or {}\r\nSpell.cur = { name = name, level = level, by = pc.name, dc = srdCast and srdCast.dc or nil, atk = srdCast and srdCast.atk or nil, slot = K.castSlot }\r\nif upCast and sp.level > 0 then\r\nSpell.cur.level = math.min(9, level + 1)\r\nleft = left .. \" (\" .. upCast.src .. \": as level \" .. Spell.cur.level .. \")\"\r\nend\r\n\r\nif type(m.dur_at) == \"table\" then Spell.cur.durMins, Spell.cur.conc = durMins, isConc and true or false end\r\nif ownDc then Spell.cur.dc, Spell.cur.atk = ownDc, ownAtk end\r\n\r\n\r\nif type(m.heal_src) == \"string\" then\r\nlocal now = type(ctx) == \"table\" and type(ctx.clock) == \"table\" and tonumber(ctx.clock.min) or (K.clockRef and tonumber(K.clockRef.min)) or 0\r\npc.heals = type(pc.heals) == \"table\" and pc.heals or {}\r\npc.heals[name] = { ends = now + (tonumber(m.heal_mins) or tonumber(sp.mins) or 60), formula = m.heal_src, conc = isConc and true or nil }\r\nend\r\nFeat.cur.casts = Feat.cur.casts or {}\r\nFeat.cur.casts[#Feat.cur.casts + 1] = Spell.cur\r\nif m.lasting then\r\npc.lasting = type(pc.lasting) == \"table\" and pc.lasting or {}\r\npc.lasting[name] = level\r\n\r\nlocal lm = tonumber(m.lasting_mins) or (m.lasting ~= true and tonumber(m.lasting)) or ((sp.mins or 0) > 0 and sp.mins) or nil\r\npc.lastingEnds = type(pc.lastingEnds) == \"table\" and pc.lastingEnds or {}\r\nlocal now = type(ctx) == \"table\" and type(ctx.clock) == \"table\" and tonumber(ctx.clock.min) or (K.clockRef and tonumber(K.clockRef.min)) or 0\r\npc.lastingEnds[name] = lm and (now + lm) or nil\r\nend\r\nif tonumber(m.decoys) then pc.mirror = { n = tonumber(m.decoys), spell = name } end\r\n\r\nif type(m.impl_buff) == \"table\" and m.impl_buff.one and type(pc.implBind) == \"table\" then pc.implBind[name] = nil end\r\nif c.active then c.last = who end\r\nreturn head .. \"|\" .. verdictOf(bad) .. \"|\" .. left .. \"]\", #bad == 0\r\nend\r\n\r\n\r\n\r\n\r\nfunction K.fxDC(e)\r\n\r\nlocal sab = type(e.dc) == \"string\" and e.dc:match(\"^SCORE:(%u%u%u)$\")\r\nif sab then\r\nlocal full = { STR = \"Strength\", DEX = \"Dexterity\", CON = \"Constitution\", INT = \"Intelligence\", WIS = \"Wisdom\", CHA = \"Charisma\" }\r\nreturn tonumber(SCORE and SCORE[full[sab] or \"\"]) or 10\r\nend\r\nif e.dc == \"SPELL\" then\r\n\r\nlocal cls = (e.srcClass and (CLASSES[e.srcClass] or {}).spell_ability and e.srcClass) or e.cls or K.castCl(SHEET)\r\nlocal ab = (CLASSES[cls or \"\"] or {}).spell_ability\r\nreturn 8 + PROF + (ab and MOD[ab] or 0)\r\nend\r\n\r\nlocal full = { STR = \"Strength\", DEX = \"Dexterity\", CON = \"Constitution\", INT = \"Intelligence\", WIS = \"Wisdom\", CHA = \"Charisma\" }\r\nlocal mid, best = (e.dc or \"\"):match(\"^8%+(.-)%+PB$\") or \"\", nil\r\nfor t in (mid .. \"|\"):gmatch(\"(%u%u%u)|\") do\r\nlocal m = full[t] and MOD[full[t]]\r\nif m and (not best or m > best) then best = m end\r\nend\r\nreturn 8 + PROF + (best or MOD.Strength)\r\nend\r\n\r\n\r\n\r\n\r\n\r\n\r\nfunction K.sparkDice(level)\r\nlevel = tonumber(level) or 1\r\nreturn 1 + (level >= 7 and 1 or 0) + (level >= 13 and 1 or 0) + (level >= 18 and 1 or 0)\r\nend\r\n\r\nfunction K.featHaz(n)\r\nif not K.FEAT_HAZ then\r\nK.FEAT_HAZ = {}\r\nfor _, rec in pairs(K.FX or {}) do\r\nfor _, e in ipairs(rec.fx or {}) do if e.t == \"foe_save\" and e.name then K.FEAT_HAZ[e.name:lower()] = true end end\r\nend\r\nend\r\nreturn K.FEAT_HAZ[(n or \"\"):lower()] == true\r\nend\r\nfunction K.cdFoeSaves(sh)\r\nif K.cl(sh, \"Cleric\") < 2 then return {} end\r\nlocal list = K.cdFoeSaves0(sh)\r\nif not K.replaced(sh, \"Turn Undead\") then return list end\r\nlocal o = {}\r\nfor _, e in ipairs(list) do if e.name ~= \"Turn Undead\" then o[#o + 1] = e end end\r\nreturn o\r\nend\r\nfunction K.cdFoeSaves0(sh)\r\nlocal lv = K.cl(sh, \"Cleric\")\r\nlocal spark = K.sparkDice(lv) .. \"d8+WIS\"\r\nlocal turned = \"turned: it flees\"\r\nreturn {\r\n\r\n{ name = \"Turn Undead\", save = \"Wisdom\", dc = \"SPELL\", cls = \"Cleric\", use = \"Channel Divinity\", undead = true, dmg = lv >= 5 and \"WIS1d8\" or nil,\r\ntype = \"Radiant\", fail = turned, lrfx = { \"Frightened\", \"Incapacitated\" }, magic = true, cond = { \"Frightened\", \"Incapacitated\" }, mins = 1, wake = true },\r\n{ name = \"Divine Spark\", key = \"Divine Spark\", save = \"Constitution\", dc = \"SPELL\", cls = \"Cleric\", use = \"Channel Divinity\", dmg = spark, type = \"Radiant\", half = true, magic = true },\r\n{ name = \"Divine Spark (Radiant)\", key = \"Divine Spark\", save = \"Constitution\", dc = \"SPELL\", cls = \"Cleric\", use = \"Channel Divinity\", dmg = spark, type = \"Radiant\", half = true, magic = true },\r\n{ name = \"Divine Spark (Necrotic)\", key = \"Divine Spark\", save = \"Constitution\", dc = \"SPELL\", cls = \"Cleric\", use = \"Channel Divinity\", dmg = spark, type = \"Necrotic\", half = true, magic = true },\r\n}\r\nend\r\n\r\n\r\n\r\n\r\nK.HAZ = {\r\n[\"Alchemist's Fire\"] = { save = \"Dexterity\", dmg = \"1d4\", type = \"Fire\", item = true, burn = true },\r\nAcid = { save = \"Dexterity\", dmg = \"2d6\", type = \"Acid\", item = true },\r\n[\"Holy Water\"] = { save = \"Dexterity\", dmg = \"2d8\", type = \"Radiant\", item = true, unholy = true },\r\nOil = { save = \"Dexterity\", item = true, oil = true },\r\n[\"Burning Oil\"] = { flat = 5, type = \"Fire\", nosave = true },\r\nBurning = { dmg = \"1d4\", type = \"Fire\", nosave = true },\r\n\r\nShove = { either = { \"Strength\", \"Dexterity\" }, shove = true },\r\n\r\nGrapple = { either = { \"Strength\", \"Dexterity\" }, shove = true, grapple = true },\r\n}\r\n\r\n\r\nK.SIZE_RANK = { Tiny = 1, Small = 2, Medium = 3, Large = 4, Huge = 5, Gargantuan = 6 }\r\nK.SIZE_KO = { Tiny = \"초소형\", Small = \"소형\", Medium = \"중형\", Large = \"대형\", Huge = \"거대형\", Gargantuan = \"초대형\" }\r\nfunction K.unitSize(u)\r\nlocal pk = type(u) == \"table\" and u.poly and K.polyLive and K.polyLive(u, K.partyPc)\r\nif pk then return ((MONSTERS[pk] or {}).what or \"\"):match(\"^(%a+)\") or \"Medium\" end\r\nlocal m = type(u) == \"table\" and MONSTERS[u.kind or \"\"] or {}\r\nreturn (type(u) == \"table\" and u.size) or (m.what or \"\"):match(\"^(%a+)\") or \"Medium\"\r\nend\r\n\r\nfunction K.speedText(sh)\r\nlocal o = { tostring(PC.speed) .. \" ft\" }\r\nlocal lv = K.charLevel(sh)\r\nfor _, e in ipairs(Feat.fxOf and Feat.fxOf(sh, \"speed\") or {}) do\r\nif lv >= (tonumber(e.from) or 0) and e.kind and e.kind ~= \"walk\" then\r\nlocal dbl = e.double_at and lv >= (tonumber(e.double_at) or 99)\r\nif e.speed == \"walk\" or not tonumber(e.speed) then\r\n\r\n\r\no[#o + 1] = string.format(\"%s = %swalking Speed%s\", e.kind, dbl and \"twice the \" or \"\", e.hover and \" (hover)\" or \"\")\r\nelse\r\no[#o + 1] = string.format(\"%s %d ft%s\", e.kind, tonumber(e.speed) * (dbl and 2 or 1), e.hover and \" (hover)\" or \"\")\r\nend\r\nend\r\nend\r\nreturn table.concat(o, \", \")\r\nend\r\n\r\n\r\nfunction K.walkTied(sh, cur)\r\nlocal o = {}\r\nlocal lv = K.charLevel(sh)\r\nfor _, e in ipairs(Feat.fxOf and Feat.fxOf(sh, \"speed\") or {}) do\r\nif lv >= (tonumber(e.from) or 0) and e.kind and e.kind ~= \"walk\" and (e.speed == \"walk\" or not tonumber(e.speed)) then\r\nlocal dbl = e.double_at and lv >= (tonumber(e.double_at) or 99)\r\no[#o + 1] = string.format(\"%s %d ft%s\", e.kind, cur * (dbl and 2 or 1), e.hover and \" (hover)\" or \"\")\r\nend\r\nend\r\nreturn o\r\nend\r\nfunction K.recSize(r)\r\nif type(r) ~= \"table\" then return \"Medium\" end\r\nif r.form and MONSTERS[r.form] then return (MONSTERS[r.form].what or \"\"):match(\"^(%a+)\") or \"Medium\" end\r\nlocal sh = r.sheet or SHEET\r\nfor _, e in ipairs(type(sh) == \"table\" and Feat.fxOf and Feat.fxOf(sh, \"size\") or {}) do\r\nif K.SIZE_RANK[e.size or \"\"] then return e.size end\r\nend\r\nlocal sp = SPECIES[(type(sh) == \"table\" and sh.species) or \"\"] or {}\r\nlocal a, b = tostring(sp.size or \"Medium\"):match(\"^(%a+) or (%a+)$\")\r\nlocal pk = type(sh) == \"table\" and type(sh.picks) == \"table\" and sh.picks.size\r\nif a and (pk == a or pk == b) then return pk end\r\nif a and K.SIZE_RANK[a] and K.SIZE_RANK[b] then return K.SIZE_RANK[a] >= K.SIZE_RANK[b] and a or b end\r\nreturn (tostring(sp.size or \"Medium\")):match(\"^(%a+)\") or \"Medium\"\r\nend\r\nfunction K.canShove(r, u)\r\nlocal a, b = K.SIZE_RANK[K.recSize(r)] or 3, K.SIZE_RANK[K.unitSize(u)] or 3\r\nreturn b <= a + 1\r\nend\r\nK.HAZ_SEV = { minor = \"nuisance\", [\"가벼움\"] = \"nuisance\", major = \"deadly\", [\"위험함\"] = \"deadly\" }\r\n\r\n\r\n\r\n\r\n\r\nfunction K.roundMark(c, tag, f, wasActive, line, last0)\r\nif not c.active then return line end\r\nif K.inReact and wasActive then return line end\r\nif not wasActive then\r\nc.round, c.rt, c.acted = 1, nil, {}\r\nreturn line .. \"\\n[ROUND|1]\"\r\nend\r\nlocal actor = c.last\r\nif not actor or actor == \"\" then return line end\r\nif actor == c.rt then\r\nif K.ROUND_TAGS[tag] then K.roundHere(actor) end\r\nreturn line\r\nend\r\nif tag == \"CAST\" then\r\nlocal sp = SPELLS[Canon.name(f[1] or \"\")]\r\nif sp and sp.m and sp.m.cast == \"reaction\" then return line end\r\nend\r\n\r\nlocal cs = Spell.cur\r\nlocal csm = type(cs) == \"table\" and SPELLS[cs.name or \"\"] and SPELLS[cs.name].m\r\nif type(csm) == \"table\" and csm.cast == \"reaction\" and csm.damage and K.byKey(cs.by) == actor\r\nand ((csm.kind == \"save\" and tag == \"SAVE\") or (csm.kind == \"auto\" and tag == \"DAMAGE\") or (csm.kind == \"attack\" and tag == \"ATTACK\")) then\r\nc.last = last0\r\nreturn line\r\nend\r\nlocal step = K.roundStep(c, actor, c.rt or last0)\r\nif step == \"out\" then\r\nc.last = last0\r\nreturn line\r\nend\r\nc.rt = actor\r\nFeat.cur.roundSeen = true\r\nK.roundHere(actor)\r\nif step == \"wrap\" then\r\nc.round = (tonumber(c.round) or 1) + 1\r\nc.acted = { [actor] = true }\r\nreturn \"[ROUND|\" .. c.round .. \"]\\n\" .. line\r\nend\r\nif type(c.acted) == \"table\" then c.acted[actor] = true end\r\nreturn line\r\nend\r\n\r\n\r\n\r\n\r\n\r\nK.ROUND_TAGS = { ATTACK = true, ADVANCE = true, CAST = true, USE = true, SAVE = true, DAMAGE = true, HEAL = true, HAZARD = true }\r\nfunction K.roundHere(actor)\r\nFeat.cur.roundHereAt = type(Feat.cur.roundHereAt) == \"table\" and Feat.cur.roundHereAt or {}\r\nFeat.cur.roundN = (tonumber(Feat.cur.roundN) or 0) + 1\r\nFeat.cur.roundHereAt[actor] = Feat.cur.roundN\r\nend\r\nfunction K.roundStep(c, actor, prev)\r\nlocal a, b\r\nfor i, name in ipairs(c.order or {}) do\r\nif name == prev then a = i end\r\nif name == actor then b = i end\r\nend\r\nif not (a and b and b < a) then return \"on\" end\r\nif type(c.acted) ~= \"table\" or not Feat.cur.roundSeen then return \"wrap\" end\r\nif not c.acted[actor] then return \"turn\" end\r\n\r\n\r\nlocal here = type(Feat.cur.roundHereAt) == \"table\" and Feat.cur.roundHereAt or {}\r\nlocal mine = tonumber(here[actor])\r\nif mine and (actor == \"Player\" or not (tonumber(here.Player) and here.Player > mine)) then return \"out\" end\r\nlocal pc = K.curPc\r\nfor _, name in ipairs(c.order or {}) do\r\nlocal u = type(c.units) == \"table\" and c.units[name]\r\nif u and not c.acted[name] then\r\nlocal r = (u.side == \"pc\" or u.side == \"ally\") and type(pc) == \"table\" and Ally.rec(pc, name) or nil\r\nlocal can\r\nif r then can = K.upNow(r) and not r.dead\r\nelseif u.side == \"pc\" or u.side == \"ally\" then can = false\r\nelse can = (tonumber(u.hp) or 0) > 0 and not (type(pc) == \"table\" and K.foeCondFx(u, pc).incap) end\r\nif can then return \"out\" end\r\nend\r\nend\r\nreturn \"wrap\"\r\nend\r\n\r\n\r\nfunction K.roundAfter(c, tag, rest, persona)\r\nlocal rd = tonumber(c.round) or 1\r\nif not (tag == \"ATTACK\" or tag == \"ADVANCE\") or not c.active then return rd end\r\nlocal actor = Canon.actor(K.tagFields(rest)[1] or \"\", persona)\r\nif actor == \"\" or actor == c.rt then return rd end\r\nreturn K.roundStep(c, actor, c.rt or c.last) == \"wrap\" and rd + 1 or rd\r\nend\r\n\r\nfunction K.roundHtml(n)\r\nlocal rule = 'flex:1;height:1px;background:linear-gradient(90deg,%s)'\r\nreturn '<div style=\"display:flex;align-items:center;gap:12px;margin:14px 0 16px;color:#d4af5a;font-family:\\'Nanum Myeongjo\\',\\'Noto Serif KR\\',\\'Batang\\',serif;'\r\n.. 'font-size:13px;font-weight:700;letter-spacing:.12em\"><span style=\"' .. string.format(rule, \"rgba(212,175,90,0),rgba(212,175,90,.65)\") .. '\"></span>'\r\n.. n .. '라운드<span style=\"' .. string.format(rule, \"rgba(212,175,90,.65),rgba(212,175,90,0)\") .. '\"></span></div>'\r\nend\r\n\r\n\r\n\r\nfunction K.hazSpell(what)\r\nlocal n = Canon.name(trim(((what or \"\"):gsub(\"%s*%b()%s*$\", \"\"))))\r\nif K.HAZ[n] or not SPELLS[n] then return nil end\r\nreturn n\r\nend\r\n\r\n\r\n\r\nK.HAZ_WORDS = { \"던지\", \"던져\", \"던진\", \"밀치\", \"밀쳐\", \"밀어\", \"떠밀\", \"떨어뜨\", \"떨어트\", \"추락\", \"낙하\", \"기름\", \"불을 붙\", \"불붙\",\r\n\"불 붙\", \"불태\", \"태워\", \"폭발\", \"무너뜨\", \"무너트\", \"절벽\", \"낭떠러지\", \"벼랑\", \"넘어뜨\", \"넘어트\", \"샹들리에\",\r\n\"throw\", \"shove\", \"push\", \"oil\", \"ignite\", \"fall\" }\r\nfunction K.hazardWanted(pc, userText, lastReply)\r\nfor k, h in pairs(K.HAZ) do\r\nif h.item and type(pc.items) == \"table\" and (pc.items[k] or 0) > 0 then return true end\r\nend\r\nif tostring(lastReply or \"\"):find(\"[HAZARD|\", 1, true) then return true end\r\nlocal t = tostring(userText or \"\"):lower()\r\nfor _, w in ipairs(K.HAZ_WORDS) do\r\nif t:find(w, 1, true) then return true end\r\nend\r\nreturn false\r\nend\r\n\r\n\r\nfunction K.shoveDC()\r\nlocal ab = K.abMod(\"Strength\")\r\nlocal r = (Cond and Cond.cur) or K.curPc\r\nif SHEET and K.cl(SHEET, \"Monk\") >= 1 and type(r) == \"table\" then\r\nlocal eq = r.equip or {}\r\nlocal _, worn = gearOf(r, eq.armor)\r\nif not worn and not K.isShield(r, eq.off) then ab = math.max(ab, K.abMod(\"Dexterity\")) end\r\nend\r\nreturn 8 + ab + PROF\r\nend\r\nfunction K.hazard(f, pools, cur, c, pc, ctx)\r\nlocal bad = {}\r\nlocal head = \"[HAZARD|\" .. table.concat(f, \"|\", 1, 10)\r\n\r\nlocal function refuse(why)\r\nK.spendRefused(pools, cur, f[4], f[8], f[9])\r\nreturn head .. \"|bad:\" .. why .. \"|-]\", false\r\nend\r\nlocal u = c.units[f[1] or \"\"]\r\nif not (c.active and u and u.side == \"enemy\") then\r\n\r\n\r\nu = K.looseTarget(c, f[1])\r\nif not u then return refuse(\"not an enemy in this fight\") end\r\nend\r\n\r\nif not u.loose and (tonumber(u.hp) or 0) <= 0 and not K.foeUp(u) then return refuse((f[1] or \"\") .. \" is down at 0 HP: no save, nothing more\") end\r\nlocal what = trim(f[2] or \"\")\r\nlocal h = K.HAZ[Canon.name(what)] or K.HAZ[what]\r\nif h and h.shove and not K.canShove(pc, u) then\r\nreturn refuse(\"too big to shove: \" .. K.unitSize(u) .. \" (one size larger than \" .. K.recSize(pc) .. \" at most)\")\r\nend\r\nlocal key = h and (K.HAZ[Canon.name(what)] and Canon.name(what) or what)\r\nlocal sev, dtype = what:match(\"^(%S+)%s+(.+)$\")\r\nlocal ft = tonumber(what:match(\"^[Ff]all%s*(%d+)\") or what:match(\"^낙하%s*(%d+)\") or \"\")\r\nif not h and ft then\r\nlocal n = math.min(20, math.floor(ft / 10))\r\nif n < 1 then return refuse(\"a fall under 10 feet does no damage\") end\r\nh = { dmg = n .. \"d6\", type = \"Bludgeoning\", nosave = true, fall = true }\r\nkey = \"Fall \" .. ft\r\nelseif not h and sev and K.HAZ_SEV[sev:lower()] then\r\n\r\nlocal row = TRAP.row(K.HAZ_SEV[sev:lower()], pc.level or 1)\r\nlocal t = Canon.name(dtype)\r\n\r\nfor en, ko in pairs(K.DMG_KO) do if dtype == ko or dtype:lower() == en:lower() then t = en end end\r\nif not K.DMG_KO[t] then return refuse(\"damage type \" .. dtype .. \"\") end\r\nh = { dc = row[1], dmg = row[2], type = t, half = true, scene = true }\r\nkey = sev:lower() .. \" \" .. t\r\nend\r\n\r\nif not h then\r\nfor _, x in ipairs((MONSTERS[u.kind or \"\"] or {}).hurts or {}) do\r\nif x.n:lower() == what:lower() then\r\nh = tonumber(x.d) and { flat = tonumber(x.d), type = x.t, nosave = true, self = true } or { dmg = x.d, type = x.t, nosave = true, self = true }\r\nkey = u.kind .. \"|\" .. x.n\r\nend\r\nend\r\nend\r\n\r\n\r\nif not h and what:lower() == \"swallow\" then\r\nfor _, x in ipairs((MONSTERS[u.kind or \"\"] or {}).sfx or {}) do\r\nif x.n == \"Swallow\" and x.s then\r\nif not tonumber(f[6]) then return refuse(\"write the DC its stat block gives for keeping what it swallowed\") end\r\nh = { save = \"Constitution\", dc = tonumber(f[6]), nodmg = true, ownSwallow = true, feat = { name = \"Swallow\", fail = \"it regurgitates what it swallowed\" } }\r\nkey = u.kind .. \"|own Swallow\"\r\nend\r\nend\r\nend\r\n\r\n\r\nif not h then\r\nlocal list = Feat.fxOf(SHEET, \"foe_save\")\r\nfor _, e in ipairs(K.cdFoeSaves(SHEET)) do list[#list + 1] = e end\r\nif K.cl(SHEET, \"Monk\") >= 3 then\r\nlocal ma = tostring(K.rowOf(SHEET, \"Monk\").martial_arts or \"1d6\"):match(\"(d%d+)\") or \"d6\"\r\nfor _, ty in ipairs({ \"Bludgeoning\", \"Piercing\", \"Slashing\" }) do\r\nlist[#list + 1] = { name = \"Deflect Attacks (\" .. ty .. \")\", key = \"Deflect Attacks\", save = \"Dexterity\", dcN = 8 + MOD.Wisdom + PROF, dmg = \"2\" .. ma .. \"+DEX\", type = ty, use = \"Focus Points\", each = true }\r\nend\r\nend\r\n\r\n\r\n\r\nlocal monkDC, rogueDC = 8 + MOD.Wisdom + PROF, 8 + MOD.Dexterity + PROF\r\nif K.cl(SHEET, \"Monk\") >= 5 then\r\nlist[#list + 1] = { name = \"Stunning Strike\", save = \"Constitution\", dcN = monkDC, cond = { \"Stunned\" }, turn = true }\r\nend\r\nif K.subHas(SHEET, \"Open Hand Technique\") then\r\nlist[#list + 1] = { name = \"Open Hand Technique (Push)\", alias = \"Push\", save = \"Strength\", dcN = monkDC, fail = \"pushed up to 15 ft away\" }\r\nlist[#list + 1] = { name = \"Open Hand Technique (Topple)\", save = \"Dexterity\", dcN = monkDC, cond = { \"Prone\" } }\r\nend\r\nif K.cl(SHEET, \"Rogue\") >= 5 then\r\nlist[#list + 1] = { name = \"Cunning Strike (Poison)\", alias = \"Poison\", save = \"Constitution\", dcN = rogueDC, cond = { \"Poisoned\" }, mins = 1, end_save = true }\r\nlist[#list + 1] = { name = \"Cunning Strike (Trip)\", alias = \"Trip\", save = \"Dexterity\", dcN = rogueDC, cond = { \"Prone\" } }\r\nend\r\nif K.cl(SHEET, \"Rogue\") >= 14 then\r\nlist[#list + 1] = { name = \"Devious Strikes (Daze)\", alias = \"Daze\", save = \"Constitution\", dcN = rogueDC, fail = \"Dazed: on its next turn only one of move, action or Bonus Action\" }\r\nlist[#list + 1] = { name = \"Devious Strikes (Knock Out)\", alias = \"Knock Out\", save = \"Constitution\", dcN = rogueDC, cond = { \"Unconscious\" }, mins = 1, wake = true, end_save = true }\r\nlist[#list + 1] = { name = \"Devious Strikes (Obscure)\", alias = \"Obscure\", save = \"Dexterity\", dcN = rogueDC, cond = { \"Blinded\" }, rounds = 2 }\r\nend\r\nfor _, a in ipairs(pcStats(pc).attacks or {}) do\r\nif a.mastery == \"Topple\" then\r\nlist[#list + 1] = { name = \"Topple\", save = \"Constitution\", dcN = 8 + (tonumber(a.mod) or 0) + PROF, cond = { \"Prone\" } }\r\nbreak\r\nend\r\nend\r\n\r\nfor _, s in ipairs(type(pc.summons) == \"table\" and pc.summons or {}) do\r\nlocal b = type(s.st) == \"table\" and s.st.breath\r\nif b then list[#list + 1] = { name = \"Draconic Breath\", save = \"Dexterity\", dcN = b.dc, dmg = \"2d6\", type = b.type, half = true, magic = true } end\r\nend\r\nfor _, e in ipairs(list) do\r\nif e.name:lower() == what:lower() or (type(e.alias) == \"string\" and e.alias:lower() == what:lower()) then\r\nlocal dc = e.dcN or (e.dc and K.fxDC(e))\r\n\r\n\r\nlocal base = (e.dmg20 and K.cl(SHEET, \"Ranger\") >= 20) and e.dmg20 or e.dmg\r\n\r\nlocal dmg = base and canon(parseFormula((base:gsub(\"WIS1\", tostring(math.max(1, MOD.Wisdom))):gsub(\"WIS\", tostring(MOD.Wisdom)):gsub(\"DEX\", tostring(MOD.Dexterity))\r\n:gsub(\"CHA\", tostring(MOD.Charisma)):gsub(\"STR\", tostring(MOD.Strength)):gsub(\"CON\", tostring(MOD.Constitution)):gsub(\"INT\", tostring(MOD.Intelligence))\r\n:gsub(\"LEVEL\", tostring(tonumber(e.srcLv) or K.charLevel(SHEET))):gsub(\"PB\", tostring(PROF)))), false)\r\n\r\nif dmg and type(e.grow) == \"table\" and e.grow.dice then\r\nlocal p, g = parseFormula(dmg), parseFormula(e.grow.dice)\r\nfor _, at in ipairs(e.grow.at or {}) do\r\nif K.charLevel(SHEET) >= (tonumber(at) or 99) then for _, d in ipairs(g.dice) do p.dice[#p.dice + 1] = { n = d.n, s = d.s } end end\r\nend\r\ndmg = canon(p, false)\r\nend\r\nh = { save = e.save, dc = dc, dmg = dmg, type = e.type, nosave = not e.save, nodmg = not e.dmg, half = e.half, feat = e }\r\nkey = \"feat|\" .. (e.key or e.name)\r\nend\r\nend\r\n\r\nif h and h.feat.undead and not (MONSTERS[K.kindOf(u, pc) or u.kind or \"\"] or {}).undead then return refuse(\"\" .. h.feat.name .. \" reaches Undead only\") end\r\nif h and h.feat.use then\r\n\r\n\r\nctx.featUsed = ctx.featUsed or {}\r\nlocal k = h.feat.use .. \"|\" .. (h.feat.key or h.feat.name)\r\nif h.feat.each then ctx.featUsed[k] = nil end\r\n\r\n\r\nif not ctx.featUsed[k] and not K.featCondOn(u, h.feat.name) then\r\nif (type(pc.res) == \"table\" and pc.res[h.feat.use] or 0) < 1 then return refuse(\"no \" .. h.feat.use .. \" left\") end\r\npc.res[h.feat.use] = pc.res[h.feat.use] - 1\r\nctx.featUsed[k] = true\r\nif h.feat.name == \"Turn Undead\" then c.turned = true end\r\nend\r\nend\r\nend\r\nif not h then\r\nlocal why = K.foeSaveWhy(SHEET, what)\r\nif why then return refuse(why) end\r\nreturn refuse(\"what: an SRD flask (Alchemist's Fire, Acid, Holy Water, Oil), Burning Oil, Burning, or minor/major + damage type\")\r\nend\r\nif u.loose and not h.feat then return refuse(\"not an enemy in this fight\") end\r\nctx.haz = ctx.haz or {}\r\n\r\nif h.item then\r\nlocal n = pc.items and pc.items[key] or 0\r\nif n < 1 then return refuse(\"no \" .. key .. \" in the pack\") end\r\nctx.hazTook = ctx.hazTook or {}\r\nctx.hazTook[key] = true\r\npc.items[key] = n - 1\r\nif pc.items[key] == 0 then pc.items[key] = nil end\r\nend\r\nlocal saved, roll, lrNote = false, nil, nil\r\nlocal ab\r\nlocal covNote, mrNote = \"\", \"\"\r\nlocal fx, worth, resAt = nil, false, nil\r\nif h.nosave then\r\nif trim(f[3] or \"-\") ~= \"-\" then bad[#bad + 1] = \"no save: write - in the save fields\" end\r\nelse\r\nab = Canon.name((f[3] or \"\"):gsub(\"%s+[Ss]ave$\", \"\"):gsub(\"%s*내성$\", \"\"))\r\nif h.save and ab ~= h.save then bad[#bad + 1] = \"save \" .. tostring(f[3]) .. \"->\" .. h.save; ab = h.save end\r\nif h.either then\r\n\r\nlocal sv = (MONSTERS[K.kindOf(u, pc) or u.kind or \"\"] or {}).saves or {}\r\nlocal best = ((sv[h.either[1]] or 0) >= (sv[h.either[2]] or 0)) and h.either[1] or h.either[2]\r\nif ab ~= best then bad[#bad + 1] = \"save \" .. tostring(f[3]) .. \"->\" .. best .. \" (the target's better)\"; ab = best end\r\nend\r\nif not ((MONSTERS[K.kindOf(u, pc) or u.kind or \"\"] or {}).saves or {})[ab] and not K.Form.ABSET[ab] then return refuse(\"ability \" .. tostring(f[3]) .. \"\") end\r\nlocal rmode\r\nK.d20Foe, K.d20FoeName = (not u.loose) and u or nil, f[1]\r\nroll, rmode = takeD20(cur, pools, f[4] or \"\", bad)\r\nK.d20Foe, K.d20FoeName = nil, nil\r\nlocal bonus = K.foeDrain(u, ab, (((MONSTERS[K.kindOf(u, pc) or u.kind or \"\"] or {}).saves or {})[ab] or 0) - K.foeExh(u))\r\n\r\nlocal cov = (h.item and ab == \"Dexterity\") and K.coverOf(u) or 0\r\nif cov > 0 and tonumber(f[5]) == bonus + cov then bonus, covNote = bonus + cov, K.coverNote(cov) end\r\nif K.fxOldBonus(u, ab, f[5], bonus) then f[5] = string.format(\"%+d\", bonus) end\r\nif tonumber(f[5]) ~= bonus then bad[#bad + 1] = string.format(\"bonus %s->%+d\", f[5] or \"\", bonus) end\r\nlocal dc = h.dc or (8 + K.abMod(h.shove and \"Strength\" or \"Dexterity\") + PROF)\r\nif h.shove and not h.dc then\r\nlocal dS = K.shoveDC()\r\nif tonumber(f[6]) == dS or (tonumber(f[6]) ~= dc and dS > dc) then dc = dS end\r\nend\r\nif tonumber(f[6]) ~= dc then bad[#bad + 1] = \"DC \" .. (f[6] or \"\") .. \"->\" .. dc end\r\n\r\nlocal sure = false\r\nroll, sure, mrNote = K.saveMods(u, roll, rmode, h.feat and h.feat.magic)\r\nlocal autofail = (not u.loose) and K.foeCondFx(u, pc).autofail[ab]\r\nif autofail then mrNote = mrNote .. \" (\" .. autofail .. \": fails Strength and Dexterity saves)\" end\r\nsaved = (sure or roll + bonus >= dc) and not autofail\r\n\r\n\r\nfx = h.shove and \"pick\" or h.feat and (h.feat.lrfx or (h.nodmg and {} or nil)) or nil\r\nworth = K.lrWorth(u, fx, f[7])\r\nsaved, lrNote = K.legendary(u, saved, worth)\r\nresAt = #bad + 1\r\nend\r\nlocal dmg, note = 0, covNote .. mrNote .. (lrNote or \"\")\r\nif h.oil or h.shove or h.nodmg then\r\nif not saved then note = h.oil and \" (covered in oil)\" or h.grapple and \"\" or h.shove and \" (pushed 5 ft or Prone)\" or (h.feat.fail and (\" (\" .. h.feat.fail .. \")\"))\r\nor (h.feat.cond and \"\") or (\" (\" .. h.feat.name .. \": failed)\") end\r\nif h.oil and not saved then u.oiled = true end\r\nif h.ownSwallow and not saved then K.unswallow(c, f[1]) end\r\nif (f[8] or \"-\") ~= \"-\" then bad[#bad + 1] = \"no damage: write - - 0\" end\r\nelseif h.feat and saved and not h.half and trim(f[8] or \"-\") == \"-\" then\r\n\r\n\r\nif trim(f[10] or \"0\") ~= \"0\" and trim(f[10] or \"\") ~= \"-\" then bad[#bad + 1] = \"damage \" .. tostring(f[10]) .. \"->0\" end\r\nf[10] = \"0\"\r\nelseif h.flat then\r\ndmg = h.flat\r\nif trim(f[8] or \"\") ~= tostring(h.flat) then bad[#bad + 1] = \"formula \" .. tostring(f[8]) .. \"->\" .. h.flat end\r\nelse\r\nlocal fAt = #bad\r\nlocal want = canon(parseFormula(h.dmg), false)\r\nlocal given = parseFormula(f[8] or \"\")\r\nif not given or canon(given, false) ~= want then bad[#bad + 1] = \"formula \" .. (f[8] or \"\") .. \"->\" .. want end\r\n\r\nlocal full = ctx.haz[key]\r\nif full then\r\nif not K.sameRoll(full, f[9]) then bad[#bad + 1] = \"same roll for every target: \" .. full.dice end\r\nK.logDice(full.vals)\r\nfull = full.sum\r\nelse\r\nlocal p = parseFormula(want)\r\nlocal before = {}\r\nfor k, v in pairs(cur) do before[k] = v end\r\nlocal q = K.wroteF(f[8], f[9])\r\nlocal sum, vals = spendDice(p, f[9], pools, cur, bad, q)\r\nctx.haz[key] = K.oneRoll(sum, before, cur, pools, q or p, p, f[9])\r\nctx.haz[key].vals = vals\r\nif K.ownRoll(ctx.haz[key]) then ctx.haz[key] = nil end\r\nfull = sum\r\nend\r\nif h.unholy and not (MONSTERS[K.kindOf(u, pc) or u.kind or \"\"] or {}).unholy then\r\nfull, note = 0, \" (not a Fiend or Undead)\"\r\nend\r\n\r\n\r\nif not h.nosave and not saved and not worth and (tonumber(u.lr) or 0) > 0 then\r\nlocal mk, lr2 = MONSTERS[u.kind], \"\"\r\nsaved, lr2 = K.legendary(u, saved, false, (Feat.adjust(mk, full, h.type)), (Feat.adjust(mk, h.half and math.floor(full / 2) or 0, h.type)))\r\nnote = note .. lr2\r\n\r\n\r\nif saved and h.feat and not h.half and trim(f[8] or \"-\") == \"-\" then\r\nfor i = #bad, fAt + 1, -1 do table.remove(bad, i) end\r\nif trim(f[10] or \"\") == \"-\" then f[10] = \"0\" end\r\nend\r\n\r\nif not saved and fx == nil and f[7] == \"success\" then note = note .. K.NO_LR end\r\nend\r\n\r\nif h.half and ab == \"Dexterity\" and ((MONSTERS[K.kindOf(u, pc) or u.kind or \"\"] or {}) or {}).evasion then\r\ndmg = saved and 0 or math.floor(full / 2)\r\nnote = note .. \" (Evasion)\"\r\nelse\r\ndmg = saved and (h.half and math.floor(full / 2) or 0) or full\r\nend\r\nif h.burn and not saved then note = note .. \" (burning: 1d4 Fire at the start of its turns, a HAZARD Burning)\" end\r\nif h.fall and dmg > 0 then note = note .. \" (lands Prone)\" end\r\nif h.feat and h.feat.fail and not saved then note = note .. \" (\" .. h.feat.fail .. \")\" end\r\nend\r\nif resAt and f[7] ~= (saved and \"success\" or \"failure\") then table.insert(bad, resAt, \"result->\" .. (saved and \"success\" or \"failure\")) end\r\nif h.feat and type(h.feat.regain) == \"table\" and not saved and h.save then note = note .. K.regain(pc, pc, h.feat.regain, h.feat.name) end\r\nlocal n2\r\nlocal raw = dmg\r\nK.ignoreRes = (h.feat and h.feat.ignore_res) and h.type or nil\r\ndmg, n2 = Feat.adjust((MONSTERS[K.kindOf(u, pc) or u.kind or \"\"] or {}), dmg, h.type)\r\nK.ignoreRes = nil\r\nnote = note .. n2\r\nif tonumber(f[10]) ~= dmg then bad[#bad + 1] = \"damage \" .. tostring(f[10]) .. \"->\" .. dmg end\r\nlocal was = u.hp\r\nif not u.loose then\r\nnote = note .. K.hurtFoe(u, raw, dmg, h.type, false)\r\nnote = note .. K.afterHit(c, f[1], u, dmg, raw, h.type, \"Player\", was, pc)\r\nif was > 0 and u.hp == 0 then note = note .. Feat.blessing(pc) end\r\nend\r\n\r\n\r\nlocal fsrc = (h.feat and h.feat.name) or (h.grapple and \"Grapple\") or nil\r\n\r\nlocal cu = (not u.loose and u) or K.sceneUnit(pc, f[1])\r\nif fsrc and cu then\r\nif saved then\r\nlocal e0 = K.featCondOn(cu, fsrc)\r\nif e0 and ((h.feat and h.feat.end_save) or e0.tag) then\r\nlocal gone = K.featCondOff(cu, fsrc)\r\nif #gone > 0 then note = note .. \" (no longer \" .. table.concat(gone, \", \") .. \")\" end\r\nend\r\nelse\r\nif h.feat and h.feat.implant_now then Feat.cur.implantNow = Feat.cur.implantNow or {}; Feat.cur.implantNow[f[1]] = true end\r\nlocal fc = (h.feat and h.feat.cond) or (h.grapple and { \"Grappled\" }) or nil\r\nif fc and (u.loose or (tonumber(u.hp) or 0) > 0) and not K.featCondOn(cu, fsrc) then\r\nlocal now = K.featCondPut(cu, type(fc) == \"table\" and fc or { fc }, fsrc, \"Player\", nil, c, type(ctx) == \"table\" and ctx.clock or nil, h.feat or {})\r\nif #now > 0 then note = note .. \" (now \" .. table.concat(now, \", \") .. \")\" end\r\nend\r\nend\r\nelseif fsrc and u.loose and not saved and h.feat and h.feat.cond then\r\nnote = note .. \" (\" .. table.concat(type(h.feat.cond) == \"table\" and h.feat.cond or { h.feat.cond }, \", \") .. \")\"\r\nend\r\nif not h.self and not u.loose then c.last = \"Player\" end\r\nlocal hpOut = u.loose and (dmg > 0 and (dmg .. \" damage\") or \"-\") or (u.hp .. \"/\" .. u.max)\r\nreturn head .. \"|\" .. verdictOf(bad) .. \"|\" .. hpOut .. note .. \"]\", #bad == 0\r\nend\r\n\r\n\r\n\r\n\r\n\r\n\r\nfunction K.looseTarget(c, name)\r\nif c.active then return nil end\r\nlocal kind = K.monCanon(trim((name or \"\"):gsub(\"%s+%d+$\", \"\")))\r\nlocal m = MONSTERS[kind]\r\nif m then return { side = \"enemy\", kind = kind, hp = m.hp, max = m.hp, loose = true } end\r\nif trim(name or \"\") ~= \"\" and trim(name or \"\") ~= \"Player\" then return { side = \"enemy\", hp = 0, max = 0, loose = true, npc = true } end\r\nreturn nil\r\nend\r\n\r\n\r\nfunction K.saveNoDmg(pc, ab)\r\nfor _, x in ipairs(Spell.all(pc)) do\r\nlocal a = x[1]\r\nlocal m = SPELLS[a.name] and SPELLS[a.name].m or {}\r\nlocal sv = m.save and m or m.extra_save\r\nif type(m.save2) == \"table\" and m.save2.save == ab and not (sv and sv.save == ab) then sv = m.save2 end\r\nif sv and sv.save == ab then return sv.damage == nil end\r\nend\r\nreturn true\r\nend\r\nfunction Spell.save(f, pools, cur, c, pc, ctx)\r\nK.MAXDICE = Feat.cur.overchannel or nil\r\nlocal bad = {}\r\nlocal head = \"[SAVE|\" .. table.concat(f, \"|\", 1, 9)\r\nlocal ab = Canon.name((f[2] or \"\"):gsub(\"%s+[Ss]ave$\", \"\"):gsub(\"%s*내성$\", \"\"))\r\nK.d20Foe, K.d20FoeName = c.active and c.units[f[1] or \"\"] or nil, f[1]\r\nlocal roll, rmode = takeD20(cur, pools, f[3] or \"\", bad)\r\nK.d20Foe, K.d20FoeName = nil, nil\r\n\r\nlocal function refuse(why)\r\nK.spendRefused(pools, cur, nil, f[7], f[8])\r\nreturn head .. \"|bad:\" .. why .. \"|-]\", false\r\nend\r\nctx.rolls = ctx.rolls or {}\r\nlocal u = c.units[f[1] or \"\"]\r\nif not (c.active and u and u.side == \"enemy\") then u = K.looseTarget(c, f[1]) end\r\nif not u then return refuse(\"not an enemy in this fight\") end\r\nlocal sp, name, level, by\r\nfor _, x in ipairs(Spell.all(pc)) do\r\nlocal a = x[1]\r\nlocal m = SPELLS[a.name] and SPELLS[a.name].m or {}\r\nlocal sv = m.save and m or m.extra_save\r\nif type(m.save2) == \"table\" and m.save2.save == ab and not (sv and sv.save == ab) then sv = m.save2 end\r\nif sv and sv.save == ab and not name then sp, name, level, by = sv, a.name, a.level, x[2] end\r\nend\r\n\r\n\r\nlocal cu0 = (u.loose and K.sceneUnit(pc, f[1])) or u\r\nif not name and type(cu0.cond) == \"table\" then\r\n\r\nfor pass = 1, 2 do\r\nfor cn, e in pairs(cu0.cond) do\r\nlocal m2 = type(e) == \"table\" and SPELLS[e.by or \"\"] and SPELLS[e.by].m\r\nlocal es = m2 and (pass == 1 and m2.end_save or (pass == 2 and not e.untilR and type(m2.end_save) ~= \"table\" and m2.save))\r\nif type(es) == \"table\" then es = es[cn] end\r\nif es == ab and not name then\r\nsp, name, level, by = { save = ab, on_save = \"none\" }, e.by, SPELLS[e.by].level, Ally.rec(pc, e.caster or \"Player\")\r\nend\r\nend\r\nend\r\nend\r\n\r\n\r\nlocal sanct\r\nif not name then\r\nfor _, r in ipairs({ pc, table.unpack(Ally.list(pc)) }) do\r\nfor bn, b in pairs(type(r.buff) == \"table\" and r.buff or {}) do\r\nif type(b) == \"table\" and b.asave == ab then\r\nif not name then sp, name, level, by = { save = ab, on_save = \"none\" }, bn, SPELLS[bn] and SPELLS[bn].level or 1, Ally.rec(pc, b.by or \"Player\") or pc end\r\nif name == bn then sanct = sanct or {}; sanct[r.name or \"Player\"] = true end\r\nend\r\nend\r\nend\r\nend\r\nif not name then\r\nlocal gone = K.concGone(pc, function(m) local sv = m.save and m or m.extra_save; return (sv and sv.save == ab) or (type(m.save2) == \"table\" and m.save2.save == ab) end)\r\nif gone then return refuse(gone) end\r\nreturn refuse(\"no spell in effect with a \" .. ab .. \" save (write CAST first; a creature's save against its own trait is a HAZARD on it)\")\r\nend\r\nif K.GOES_OFF[name] then\r\nlocal who, r = (by and by.name) or \"Player\", by or pc\r\nFeat.cur.boom = Feat.cur.boom or {}\r\nFeat.cur.boom[who] = r\r\n\r\nif type(r.conc) == \"table\" and r.conc.name == name then r.conc.boomed = true end\r\nK.boomNow = who\r\nend\r\n\r\n\r\nlocal dmgText = sp.damage\r\nlocal arPart = 0\r\nif type(dmgText) == \"string\" and dmgText:find(\"AROUSAL\", 1, true) then\r\n\r\nif u.loose then\r\nK.spendRefused(pools, cur, nil, f[7], f[8])\r\nreturn head .. \"|ok|its arousal is Lua's only in a fight: the damage is the story's]\", true\r\nend\r\nlocal cur0 = (K.AR.on() and type(u.ar) == \"table\" and tonumber(u.ar.cur)) or 0\r\narPart = dmgText:find(\"AROUSAL/2\", 1, true) and math.floor(cur0 / 2) or cur0\r\ndmgText = dmgText:gsub(\"AROUSAL/2\", tostring(math.floor(cur0 / 2))):gsub(\"AROUSAL\", tostring(cur0))\r\nend\r\nlocal st, want = Ally.run(pc, by, function()\r\nreturn Spell.stats(name), dmgText and Spell.formula(name, dmgText, level, sp.type)\r\nend)\r\nwant = K.extraDice(want, sp, f[7])\r\n\r\nlocal bonus = u.npc and (tonumber(f[4]) or 0) or K.foeDrain(u, ab, ((MONSTERS[K.kindOf(u, pc)].saves or {})[ab] or 0) - K.foeExh(u))\r\n\r\n\r\nlocal cov = (ab == \"Dexterity\" and not (SPELLS[name].m or {}).nocover) and K.coverOf(u) or 0\r\n\r\n\r\nlocal wc = (SPELLS[name].m or {}).approach and K.AR.willingFor(u, (by and by ~= pc and by.name) or \"Player\")\r\nlocal apAdd = (SPELLS[name].m or {}).approach and K.AR.saveAdd(u, pc, wc and \"willing\" or K.apWill, by or pc) or 0\r\nlocal covered = cov > 0 and (tonumber(f[4]) == bonus + cov or (apAdd ~= 0 and tonumber(f[4]) == bonus + cov + apAdd))\r\nif covered then bonus = bonus + cov end\r\n\r\nlocal inh0 = Feat.cur.inhib0 and Feat.cur.inhib0[u]\r\nlocal apOld = ((SPELLS[name].m or {}).approach and inh0 ~= nil) and (K.D2.mode == \"hard\" and K.apWill ~= \"willing\" and inh0 or math.min(0, inh0)) or nil\r\nif apAdd ~= 0 or (apOld and apOld ~= 0) then\r\nbonus = bonus + apAdd\r\nlocal w = tonumber(f[4])\r\nif w == bonus - apAdd or (apOld and w == bonus - apAdd + apOld) then f[4] = string.format(\"%+d\", bonus); head = \"[SAVE|\" .. table.concat(f, \"|\", 1, 9) end\r\nend\r\nif K.fxOldBonus(u, ab, f[4], bonus) then f[4] = string.format(\"%+d\", bonus); head = \"[SAVE|\" .. table.concat(f, \"|\", 1, 9) end\r\nif tonumber(f[4]) ~= bonus then bad[#bad + 1] = string.format(\"bonus %s->%+d\", f[4] or \"\", bonus) end\r\nif tonumber(f[5]) ~= st.dc then\r\n\r\n\r\nlocal old = by and K.withOld(by, function() return Ally.run(pc, by, function() return Spell.stats(name) end) end)\r\nif old and tonumber(f[5]) == old.dc then\r\nf[5] = tostring(st.dc)\r\nhead = \"[SAVE|\" .. table.concat(f, \"|\", 1, 9)\r\nelse\r\nbad[#bad + 1] = \"DC \" .. (f[5] or \"\") .. \"->\" .. st.dc\r\nend\r\nend\r\nlocal sure, mrNote\r\nroll, sure, mrNote = K.saveMods(u, roll, rmode, true)\r\n\r\nlocal autofail = not u.loose and K.foeCondFx(u, pc).autofail[ab]\r\nif autofail then mrNote = mrNote .. \" (\" .. autofail .. \": fails Strength and Dexterity saves)\" end\r\nif apAdd ~= 0 then mrNote = mrNote .. string.format(\" (inhibition %+d)\", apAdd) end\r\nlocal ok = (sure or roll + bonus >= st.dc) and not autofail\r\n\r\nlocal impK = name .. \"|\" .. tostring(f[1] or \"\")\r\nif Feat.cur.implantFail and Feat.cur.implantFail[impK] then\r\nFeat.cur.trigSpell = name\r\nFeat.cur.implantFail[impK] = nil\r\nok = false\r\nmrNote = mrNote .. \" (implanted: its first save fails)\"\r\nend\r\n\r\n\r\nlocal worth = K.lrWorth(u, sp.lrfx, f[6])\r\n\r\n\r\nlocal prism = sp.prism and K.prismRays(ctx, f[1], tostring(f[3]) .. \"|\" .. tostring(f[8])) or nil\r\nlocal prismM = SPELLS[name or \"\"] and SPELLS[name].m\r\nif prism then worth = K.prismWorth(u, prism)\r\nelseif type(prismM) == \"table\" and prismM.prism then worth = true end\r\nlocal lrNote\r\nok, lrNote = K.legendary(u, ok, worth)\r\nlocal resAt = #bad + 1\r\nlocal dmg = 0\r\nlocal potent0 = Ally.run(pc, by, function()\r\nreturn K.subHas(SHEET, \"Potent Cantrip\") and SPELLS[name].level == 0 and Spell.classKnown(name)\r\nend)\r\nlocal rApplied, rKeyOut\r\nlocal noneOnSave = sp.damage and ok and sp.on_save ~= \"half\" and not potent0\r\nif noneOnSave and trim(f[7] or \"-\") == \"-\" then\r\n\r\nif trim(f[9] or \"0\") ~= \"0\" and trim(f[9] or \"\") ~= \"-\" then bad[#bad + 1] = \"damage \" .. tostring(f[9]) .. \"->0\" end\r\nelseif sp.damage then\r\nlocal fAt = #bad\r\nlocal given = parseFormula(f[7] or \"\")\r\n\r\nlocal rN, rSrc, rKey = K.spellRiderFor(by or pc, name, sp.type or Feat.spellType(name, by))\r\nlocal riderHere = rN and given and parseFormula(want .. \"+\" .. rN) and canon(given, false) == canon(parseFormula(want .. \"+\" .. rN), false)\r\nif not given or (canon(given, false) ~= want and not riderHere) then bad[#bad + 1] = \"formula \" .. (f[7] or \"\") .. \"->\" .. want end\r\n\r\nlocal full = ctx.rolls[name]\r\nif full then\r\nif not K.sameRoll(full, f[8]) then bad[#bad + 1] = \"same roll for every target: \" .. full.dice end\r\nK.logDice(full.vals)\r\nfull = full.sum + arPart\r\nelse\r\nlocal p = parseFormula(want)\r\nlocal before = {}\r\nfor k, v in pairs(cur) do before[k] = v end\r\nlocal q = K.wroteF(f[7], f[8])\r\nlocal sum, vals = spendDice(p, f[8], pools, cur, bad, q)\r\nsum = sum + K.adeptOnes(by or pc, sp.type or Feat.spellType(name, by), vals)\r\nctx.rolls[name] = K.oneRoll(sum, before, cur, pools, q or p, p, f[8])\r\nctx.rolls[name].vals = vals\r\nctx.rolls[name].sum = (tonumber(ctx.rolls[name].sum) or sum) - arPart\r\nif K.ownRoll(ctx.rolls[name]) then ctx.rolls[name] = nil end\r\nfull = sum\r\nend\r\nlocal potent = Ally.run(pc, by, function()\r\nreturn K.subHas(SHEET, \"Potent Cantrip\") and SPELLS[name].level == 0 and Spell.classKnown(name)\r\nend)\r\nlocal onSave = (sp.on_save == \"half\" or potent) and math.floor(full / 2) or 0\r\n\r\n\r\nif not ok and not worth and (tonumber(u.lr) or 0) > 0 then\r\nlocal mk, dt = u.kind and MONSTERS[u.kind], sp.type or Feat.spellType(name, by)\r\ndt = K.spellDtype(dt, mk, full)\r\ndt = K.swapType(by or pc, pc, { spell = name }, dt, mk, full)\r\nK.ignoreRes = K.adeptTypes((by and by.sheet) or SHEET)[dt or \"\"] and dt or nil\r\nif prism then\r\nlocal adSh = (by and by.sheet) or SHEET\r\nok, lrNote = K.legendary(u, ok, false, (K.prismDmg(mk, full, prism, adSh)), (K.prismDmg(mk, onSave, prism, adSh)))\r\nelse\r\nok, lrNote = K.legendary(u, ok, false, (K.typedAdjust(mk, full, dt, sp)), (K.typedAdjust(mk, onSave, dt, sp)))\r\nend\r\nK.ignoreRes = nil\r\n\r\n\r\nif ok and onSave == 0 and trim(f[7] or \"-\") == \"-\" then\r\nfor i = #bad, fAt + 1, -1 do table.remove(bad, i) end\r\nnoneOnSave = true\r\nend\r\n\r\nif not ok and sp.lrfx == nil and f[6] == \"success\" then lrNote = K.NO_LR end\r\nend\r\n\r\nif onSave > 0 and ab == \"Dexterity\" and u.kind and (MONSTERS[K.kindOf(u, pc) or u.kind] or {}).evasion then\r\ndmg = ok and 0 or math.floor(full / 2)\r\nlrNote = (lrNote or \"\") .. \" (Evasion)\"\r\nelse\r\ndmg = ok and onSave or full\r\nend\r\nif riderHere and dmg > 0 then\r\ndmg = dmg + rN\r\nrApplied, rKeyOut = true, rKey\r\nlrNote = (lrNote or \"\") .. string.format(\" (%s +%d)\", rSrc, rN)\r\nend\r\nelseif (f[7] or \"-\") ~= \"-\" then\r\nbad[#bad + 1] = \"no damage: write - - 0\"\r\nend\r\nif f[6] ~= (ok and \"success\" or \"failure\") then table.insert(bad, resAt, \"result->\" .. (ok and \"success\" or \"failure\")) end\r\n\r\nlocal cu = (not u.loose and u) or K.sceneUnit(pc, f[1])\r\nlocal condNote, prismCond = \"\", nil\r\nif prism then\r\nprismCond = cu and K.prismCond(cu, prism, ok, by and by.name or \"Player\") or {}\r\nelseif type(prismM) == \"table\" and prismM.prism then\r\ncondNote = cu and K.prismLater(cu, ab, ok) or \"\"\r\nelse\r\ncondNote = cu and K.foeCondApply(cu, name, ok, by and by.name or \"Player\") or \"\"\r\nend\r\nif cu then condNote = condNote .. K.foeFxApply(cu, name, ok, by and by.name or \"Player\") end\r\nif not ok and not u.loose and (SPELLS[name].m or {}).form_beast then\r\nFeat.cur.polyFail = Feat.cur.polyFail or {}\r\nFeat.cur.polyFail[f[1]] = name\r\ncondNote = condNote .. \" (its form next: a BUFF with the Beast)\"\r\nend\r\n\r\nif sanct and not ok then\r\nFeat.cur.sanct = Feat.cur.sanct or {}\r\nFeat.cur.sanct[f[1]] = sanct\r\ncondNote = condNote .. \" (\" .. name .. \": it picks another target or loses the attack)\"\r\nend\r\nlocal note\r\nlocal raw, dtype = dmg, sp.type or Feat.spellType(name, by)\r\nlocal swN, spN\r\ndtype, spN = K.spellDtype(dtype, u.kind and MONSTERS[K.kindOf(u, pc)], dmg)\r\ndtype, swN = K.swapType(by or pc, pc, { spell = name }, dtype, u.kind and MONSTERS[u.kind], dmg)\r\nswN = spN .. swN\r\nlocal ss = K.spellStimOf(by, name, pc)\r\nK.ignoreRes = K.adeptTypes((by and by.sheet) or SHEET)[dtype or \"\"] and dtype or nil\r\nif ss then note = \"\" else dmg, note, dtype = K.typedAdjust(u.kind and MONSTERS[K.kindOf(u, pc)], dmg, dtype, sp); note = swN .. note end\r\nK.ignoreRes = nil\r\n\r\nlocal prismBase\r\nif prism then\r\nlocal parts, first = {}, nil\r\nif ss then\r\n\r\nlocal per = dmg\r\ndmg = 0\r\nfor _, r in ipairs(prism) do\r\nparts[#parts + 1] = { r = r, ty = K.PRISM[r][2], n = K.PRISM[r][2] and per or nil }\r\nif K.PRISM[r][2] then dmg = dmg + per end\r\nend\r\nelse\r\nprismBase = raw\r\ndmg, parts, first = K.prismDmg(u.kind and MONSTERS[K.kindOf(u, pc)], raw, prism, (by and by.sheet) or SHEET)\r\nlocal tys = {}\r\nfor _, x in ipairs(K.prismTyped(parts)) do if not K.isType(table.concat(tys, \" and \"), x.ty) then tys[#tys + 1] = x.ty end end\r\ndtype, note = (#tys > 0 and table.concat(tys, \" and \")) or first, swN\r\nraw = raw * #K.prismTyped(parts)\r\nend\r\ncondNote = condNote .. K.prismNote(prism, parts, ok, prismCond, cu ~= nil)\r\nend\r\nif rApplied and dmg > 0 then Feat.cur.riderUsed = Feat.cur.riderUsed or {}; Feat.cur.riderUsed[rKeyOut] = true end\r\nnote = mrNote .. (lrNote or \"\") .. note .. (covered and K.coverNote(cov) or \"\") .. condNote\r\n\r\n\r\nif prismBase and (tonumber(f[9]) == prismBase or tonumber(f[9]) == dmg) then f[9] = tostring(dmg); head = \"[SAVE|\" .. table.concat(f, \"|\", 1, 9) end\r\nif tonumber(f[9]) ~= dmg and not (noneOnSave and dmg == 0) and not (not sp.damage and dmg == 0 and trim(f[9] or \"\") == \"-\") then\r\nbad[#bad + 1] = \"damage \" .. tostring(f[9]) .. \"->\" .. dmg\r\nend\r\n\r\nif dmg > 0 and not ss and (SPELLS[name].level or 0) == 0 then\r\nFeat.cur.cantripHit = Feat.cur.cantripHit or {}\r\nFeat.cur.cantripHit[by and by.name or \"Player\"] = name\r\nend\r\nlocal was = u.hp\r\nlocal ssx = \"\"\r\nif ss then\r\nlocal st\r\nst, ssx = K.spellStimGive(f[1], u, dmg, dtype, by, pc, c, false)\r\nnote = note .. st\r\nelse\r\nnote = note .. K.hurtFoe(u, raw, dmg, dtype, false)\r\nnote = note .. K.afterHit(c, f[1], u, dmg, raw, dtype, by.name or \"Player\", was, pc)\r\nend\r\nif was > 0 and u.hp == 0 and not u.loose then note = note .. Feat.blessing(by) end\r\nif not u.loose then c.last = by.name or \"Player\" end\r\n\r\nlocal hpOut = u.loose and ((dmg > 0 and not ss) and (dmg .. \" damage\") or \"-\") or (u.hp .. \"/\" .. u.max)\r\nreturn head .. \"|\" .. verdictOf(bad) .. \"|\" .. hpOut .. note .. \"]\" .. ssx, #bad == 0\r\nend\r\n\r\n\r\n\r\nfunction K.selfDamage(f, pools, cur, c, pc)\r\nlocal head = \"[DAMAGE|\" .. table.concat(f, \"|\", 1, 5)\r\nlocal function no(why) K.spendRefused(pools, cur, nil, f[2], f[3]); return head .. \"|bad:\" .. why .. \"|-]\", false end\r\nlocal rec = Ally.rec(pc, f[1] or \"\")\r\nif not rec then return no(\"a feature's damage to its own owner: Player or a companion\") end\r\nlocal sh = K.ownSheet(rec, pc)\r\nlocal want, fx = trim(f[5] or \"\"), nil\r\nfor _, e in ipairs(sh and Feat.fxOf(sh, \"self_damage\") or {}) do\r\nif e.src == want or e.src == Canon.name(want) or e.name == want or NAMES_KO[e.src or \"\"] == want then fx = e end\r\nend\r\nif not fx then return no((f[1] or \"\") .. \" has no feature \" .. want .. \" that hurts its owner\") end\r\nlocal form = parseFormula(f[2] or \"\")\r\nif not form then return no(\"formula: a number, or dice like 1d6+2\") end\r\nlocal bad = {}\r\nlocal d0 = spendDice(form, f[3], pools, cur, bad, K.wroteF(f[2], f[3]))\r\nlocal dmg = math.max(0, tonumber(d0) or 0)\r\nif tonumber(f[4]) ~= dmg then bad[#bad + 1] = \"damage \" .. tostring(f[4]) .. \"->\" .. dmg end\r\n\r\nlocal note = dmg > 0 and not rec.dead and (K.hurtPC00(rec, dmg, false) .. K.polyGone(rec)) or \"\"\r\nreturn head .. \"|\" .. verdictOf(bad) .. \"|\" .. (rec.dead and \"dead\" or (rec.hp .. \"/\" .. rec.max)) .. \" (\" .. tostring(fx.src) .. \": \"\r\n.. (fx.type and (fx.type .. \" \") or \"\") .. \"damage nothing lessens)\" .. note .. \"]\", #bad == 0\r\nend\r\n\r\n\r\n\r\nfunction K.dartMod(ctx, name, by, pc, key)\r\nctx.dartMod = ctx.dartMod or {}\r\nif ctx.dartMod[key or name] then return 0 end\r\nlocal sp = SPELLS[name]\r\nlocal r = Ally.run(pc, by, function() return { Feat.spellMod(name, sp, sp.m, sp.m.damage, true) } end)\r\nreturn tonumber(r[1]) or 0, r[2]\r\nend\r\n\r\nfunction Spell.damage(f, pools, cur, c, pc, ctx)\r\nK.MAXDICE = Feat.cur.overchannel or nil\r\nlocal head = \"[DAMAGE|\" .. table.concat(f, \"|\", 1, 4)\r\nlocal function refuse(why)\r\nK.spendRefused(pools, cur, nil, f[2], f[3])\r\nreturn head .. \"|bad:\" .. why .. \"|-]\", false\r\nend\r\nlocal u = c.units[f[1] or \"\"]\r\nlocal rec = Ally.rec(pc, f[1] or \"\")\r\nif not (c.active and u and u.side == \"enemy\") and not rec then u = K.looseTarget(c, f[1]) end\r\nif not u and not rec then return refuse(\"not an enemy in this fight\") end\r\nlocal name, level, by, casting\r\nfor _, x in ipairs(Spell.all(pc)) do\r\nlocal m = SPELLS[x[1].name] and SPELLS[x[1].name].m or {}\r\nif m.kind == \"auto\" and not name then name, level, by, casting = x[1].name, x[1].level, x[2], x[1] end\r\nend\r\nif rec and name and not (u and u.side == \"enemy\") then\r\n\r\nlocal m0 = SPELLS[name].m\r\nlocal one0 = parseFormula(K.spellTerms(m0.damage, name, by, pc))\r\nif not one0 then return refuse(name .. \": its damage is no formula\") end\r\nctx.darts = ctx.darts or {}\r\nif ctx.darts[casting or name] == nil then ctx.darts[casting or name] = (m0.darts or 1) + ((m0.upcast or {}).darts or 0) * ((level or SPELLS[name].level) - SPELLS[name].level) end\r\nif ctx.darts[casting or name] <= 0 then return refuse(\"no darts of \" .. name .. \" left\") end\r\nctx.darts[casting or name] = ctx.darts[casting or name] - 1\r\nlocal bad0 = {}\r\nlocal given0 = parseFormula(f[2] or \"\")\r\nif not given0 or canon(given0, false) ~= canon(one0, false) then bad0[#bad0 + 1] = \"formula \" .. tostring(f[2]) .. \"->\" .. canon(one0, false) end\r\nlocal dmg0 = spendDice(one0, f[3], pools, cur, bad0, K.wroteF(f[2], f[3]))\r\ndmg0 = math.max(0, tonumber(dmg0) or 0)\r\nlocal ss0 = K.spellStimOf(by, name, pc)\r\nlocal landed, note0\r\nif ss0 then landed, note0 = dmg0, \"\" else landed, note0 = Feat.adjust(Feat.traits(rec), dmg0, m0.type) end\r\nif tonumber(f[4]) ~= landed then bad0[#bad0 + 1] = \"damage \" .. tostring(f[4]) .. \"->\" .. landed end\r\nlocal ssx0 = \"\"\r\nif ss0 then\r\nlocal st0\r\nst0, ssx0 = K.spellStimGive(f[1], rec, landed, m0.type, by, pc, c, false)\r\nnote0 = note0 .. st0\r\nlanded = 0\r\nelse\r\nnote0 = note0 .. hurtPC(rec, landed, false)\r\nif K.shieldTook then landed = 0 end\r\nend\r\nif m0.soothe_same and K.AR.on() and landed > 0 then\r\nlocal a, mx = K.AR.st(rec), K.AR.max(rec, pc)\r\nlocal b4 = tonumber(a.cur) or 0\r\na.cur = math.max(0, b4 - landed)\r\nif a.cur < mx then a.edge = nil end\r\nnote0 = note0 .. string.format(\" (arousal %d->%d)\", b4, a.cur)\r\nend\r\nif c.active then c.last = (by and by.name) or \"Player\" end\r\nreturn head .. \"|\" .. verdictOf(bad0) .. \"|\" .. (rec.dead and \"dead\" or (rec.hp .. \"/\" .. rec.max)) .. note0 .. \"]\" .. ssx0, #bad0 == 0\r\nend\r\nif not name then\r\nlocal gone = K.concGone(pc, function(m) return m.kind == \"auto\" end)\r\nif gone then return refuse(gone) end\r\nreturn refuse(\"no spell in effect that hits without a roll (write CAST first)\")\r\nend\r\nlocal sp = SPELLS[name]\r\nlocal m = sp.m\r\n\r\nif m.slay and u.hp > 0 and u.hp <= m.slay then\r\nlocal was = u.hp\r\nu.hp = 0\r\nif not u.loose then c.last = by.name or \"Player\" end\r\nlocal note = string.format(\" (%s: %d HP or fewer, dies)\", name, m.slay) .. (u.loose and \"\" or Feat.blessing(by))\r\nreturn head .. \"|ok|\" .. (u.loose and (was .. \" damage\") or (\"0/\" .. u.max)) .. note .. \"]\", true\r\nend\r\nctx.darts = ctx.darts or {}\r\nif ctx.darts[casting or name] == nil then ctx.darts[casting or name] = (m.darts or 1) + ((m.upcast or {}).darts or 0) * (level - sp.level) end\r\nlocal one = parseFormula(K.spellTerms(m.damage, name, by, pc))\r\nif not one or #one.dice ~= 1 then return refuse(name .. \": its damage is not one kind of die (N darts of 1dX+N)\") end\r\nlocal given = parseFormula(f[2] or \"\")\r\nlocal bad = {}\r\nlocal n = 0\r\nlocal add, addSrc = K.dartMod(ctx, name, by, pc, casting)\r\nif given and #given.dice == 1 and given.dice[1].s == one.dice[1].s then n = given.dice[1].n end\r\nif n < 1 or (given.mod ~= n * one.mod and given.mod ~= n * one.mod + add) then\r\nbad[#bad + 1] = \"formula: N darts = Nd\" .. one.dice[1].s .. \"+N\" .. (add > 0 and (\"+\" .. add .. \" on the first\") or \"\")\r\nn = math.max(1, math.min(ctx.darts[casting or name], n))\r\nelseif add > 0 and given.mod ~= n * one.mod + add then\r\nbad[#bad + 1] = string.format(\"formula %s->%dd%d+%d (%s +%d on one damage roll)\", f[2], n, one.dice[1].s, n * one.mod + add, addSrc or \"bonus\", add)\r\nend\r\nif n > ctx.darts[casting or name] then bad[#bad + 1] = \"only \" .. ctx.darts[casting or name] .. \" darts left\"; n = ctx.darts[casting or name] end\r\nctx.darts[casting or name] = ctx.darts[casting or name] - n\r\nif add > 0 then ctx.dartMod[casting or name] = true end\r\nlocal p = { dice = { { n = n, s = one.dice[1].s } }, mod = n * one.mod + add }\r\nlocal dmg = n > 0 and spendDice(p, f[3], pools, cur, bad, K.wroteF(f[2], f[3])) or 0\r\nlocal note\r\n\r\nlocal refl = name == \"Magic Missile\" and u.kind and (MONSTERS[u.kind] or {}).reflect\r\nif refl then dmg = 0 end\r\nlocal raw = dmg\r\nlocal ss = K.spellStimOf(by, name, pc)\r\nif ss then note = \"\" else\r\nlocal mt0, spN = K.spellDtype(m.type, u.kind and MONSTERS[u.kind], dmg)\r\nlocal mt, swN = K.swapType(by or pc, pc, { spell = name }, mt0, u.kind and MONSTERS[u.kind], dmg)\r\nswN = spN .. swN\r\ndmg, note = Feat.adjust(u.kind and MONSTERS[u.kind], dmg, mt)\r\nnote = swN .. note\r\nend\r\nif refl then note = note .. \" (Reflective Carapace)\" end\r\nif add > 0 then note = note .. string.format(\" (%s: +%d)\", addSrc or \"bonus\", add) end\r\nif tonumber(f[4]) ~= dmg then bad[#bad + 1] = \"damage \" .. tostring(f[4]) .. \"->\" .. dmg end\r\nlocal was = u.hp\r\nlocal ssx = \"\"\r\nif ss then\r\nlocal st\r\nst, ssx = K.spellStimGive(f[1], u, dmg, m.type, by, pc, c, false)\r\nnote = note .. st\r\ndmg = 0\r\nelse\r\nnote = note .. K.hurtFoe(u, raw, dmg, m.type, false)\r\nnote = note .. K.afterHit(c, f[1], u, dmg, raw, m.type, by.name or \"Player\", was, pc)\r\nend\r\nif was > 0 and u.hp == 0 and not u.loose then note = note .. Feat.blessing(by) end\r\nif not u.loose then c.last = by.name or \"Player\" end\r\n\r\nif m.soothe_same and K.AR.on() and dmg > 0 and not u.loose then\r\nlocal a, mx = K.AR.st(u), K.AR.max(u, pc)\r\nlocal b4 = tonumber(a.cur) or 0\r\na.cur = math.max(0, b4 - dmg)\r\nif a.cur < mx then a.edge = nil end\r\nnote = note .. string.format(\" (arousal %d->%d)\", b4, a.cur)\r\nend\r\n\r\nlocal hpOut = u.loose and (dmg > 0 and (dmg .. \" damage\") or \"-\") or (u.hp .. \"/\" .. u.max)\r\nreturn head .. \"|\" .. verdictOf(bad) .. \"|\" .. hpOut .. note .. \"]\" .. ssx, #bad == 0\r\nend\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\nfunction K.legendary(u, ok, worth, failDmg, saveDmg)\r\nif ok or type(u) ~= \"table\" or (tonumber(u.lr) or 0) < 1 then return ok, \"\" end\r\nlocal hp = tonumber(u.hp) or 0\r\nif not worth and not (failDmg and hp > 0 and failDmg >= hp and (saveDmg or 0) < hp) then return ok, \"\" end\r\nu.lr = u.lr - 1\r\nreturn true, \" (Legendary Resistance, \" .. u.lr .. \" left)\"\r\nend\r\n\r\n\r\n\r\n\r\nfunction K.lrWorth(u, fx, written)\r\nlocal wrote = trim(written or \"\"):lower() == \"success\"\r\nif fx == \"pick\" then return wrote end\r\nif type(fx) ~= \"table\" then return false end\r\nif #fx == 0 then return true end\r\nlocal imm = {}\r\nfor _, x in ipairs((MONSTERS[u.kind or \"\"] or {}).cimm or {}) do imm[x] = true end\r\nfor _, cn in ipairs(fx) do if not imm[cn] then return true end end\r\nreturn wrote\r\nend\r\n\r\nK.NO_LR = \" (no Legendary Resistance against damage alone)\"\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\nfunction K.saveMods(u, roll, mode, magical)\r\nlocal m = type(u) == \"table\" and u.kind and MONSTERS[u.kind] or {}\r\nif magical and m.mres == 2 then return roll, true, \" (Greater Magic Resistance)\" end\r\nlocal why = (magical and m.mres == 1 and \"Magic Resistance\")\r\nor (m.bfrenzy and (tonumber(u.hp) or 0) * 2 <= (tonumber(u.max) or 0) and \"Bloodied Frenzy\") or nil\r\nif why and mode == \"normal\" then\r\nlocal second = K.d(20)\r\nreturn math.max(roll, second), false, string.format(\" (%s: Advantage, Lua's second d20 %d)\", why, second)\r\nend\r\nreturn roll, false, \"\"\r\nend\r\n\r\n\r\n\r\n\r\n\r\n\r\nK.PRISM = { { \"Red\", \"Fire\" }, { \"Orange\", \"Acid\" }, { \"Yellow\", \"Lightning\" }, { \"Green\", \"Poison\" }, { \"Blue\", \"Cold\" },\r\n{ \"Indigo\", cond = \"Restrained\" }, { \"Violet\", cond = \"Blinded\" } }\r\nK.PRISM_KO = { Red = \"빨강\", Orange = \"주황\", Yellow = \"노랑\", Green = \"초록\", Blue = \"파랑\", Indigo = \"남색\", Violet = \"보라\" }\r\nfunction K.prismRays(ctx, who, salt)\r\nctx.prism = ctx.prism or {}\r\nif not ctx.prism[who] then\r\n\r\n\r\nlocal h = ((tonumber(K.REPLY) or 0) * 7919) % 2147483647\r\nlocal s0 = tostring(who) .. \"|\" .. tostring(salt or \"\")\r\nfor i = 1, #s0 do h = (h * 31 + s0:byte(i)) % 2147483647 end\r\nlocal function d8() h = (1103515245 * h + 12345) % 2147483648; return (h // 65536) % 8 + 1 end\r\nlocal function one() local r = d8(); while r == 8 do r = d8() end; return r end\r\nlocal r = d8()\r\nctx.prism[who] = r == 8 and { one(), one(), eight = true } or { r }\r\nend\r\nreturn ctx.prism[who]\r\nend\r\nfunction K.prismImm(u)\r\nlocal imm = {}\r\nfor _, x in ipairs((MONSTERS[type(u) == \"table\" and u.kind or \"\"] or {}).cimm or {}) do imm[x] = true end\r\nreturn imm\r\nend\r\nfunction K.prismWorth(u, rays)\r\nlocal imm = K.prismImm(u)\r\nfor _, r in ipairs(rays) do local cn = K.PRISM[r].cond; if cn and not imm[cn] then return true end end\r\nreturn false\r\nend\r\n\r\nfunction K.prismDmg(mk, amount, rays, sh)\r\nlocal total, parts, first = 0, {}, nil\r\nlocal adept = K.adeptTypes(sh)\r\nfor _, r in ipairs(rays) do\r\nlocal ty = K.PRISM[r][2]\r\nif ty then\r\nK.ignoreRes = adept[ty] and ty or nil\r\nlocal n, note = Feat.adjust(mk, amount, ty)\r\nK.ignoreRes = nil\r\ntotal, first = total + n, first or ty\r\nparts[#parts + 1] = { r = r, ty = ty, n = n, note = note }\r\nelse\r\nparts[#parts + 1] = { r = r }\r\nend\r\nend\r\nreturn total, parts, first\r\nend\r\nfunction K.prismTyped(parts)\r\nlocal o = {}\r\nfor _, x in ipairs(parts) do if x.ty then o[#o + 1] = x end end\r\nreturn o\r\nend\r\n\r\nfunction K.prismCond(u, rays, ok, caster)\r\nlocal out = {}\r\nif ok or type(u) ~= \"table\" or u.loose then return out end\r\nu.cond = type(u.cond) == \"table\" and u.cond or {}\r\nlocal imm = K.prismImm(u)\r\nfor _, r in ipairs(rays) do\r\nlocal cn = K.PRISM[r].cond\r\nif cn and imm[cn] then out[r] = \"immune\"\r\nelseif cn then\r\nu.cond[cn] = { by = \"Prismatic Spray\", caster = caster }\r\nif cn == \"Restrained\" then u.prism = { s = 0, f = 0 } end\r\nout[r] = cn\r\nend\r\nend\r\nreturn out\r\nend\r\nfunction K.prismNote(rays, parts, ok, conds, kept)\r\nlocal o = {}\r\nfor _, x in ipairs(parts) do\r\nlocal p = K.PRISM[x.r]\r\nlocal t = x.r .. \" \" .. p[1]\r\nif x.ty then\r\nlocal adj = trim((tostring(x.note or \"\"):gsub(\"[()]\", \"\")))\r\nt = t .. \", \" .. x.ty .. \" \" .. tostring(x.n) .. (adj ~= \"\" and (\" \" .. adj) or \"\")\r\nelseif ok then t = t .. \", no effect\"\r\nelseif conds and conds[x.r] then t = t .. \", \" .. conds[x.r]\r\nelse t = t .. \", \" .. p.cond .. \" by the story\" end\r\no[#o + 1] = t\r\nend\r\nreturn \" (Prismatic Spray \" .. (rays.eight and \"8, two rays: \" or \"ray \") .. table.concat(o, \"; \") .. \")\"\r\nend\r\n\r\nfunction K.prismLater(u, ab, ok)\r\nif type(u) ~= \"table\" or type(u.cond) ~= \"table\" then return \"\" end\r\nlocal function mine(n) return type(u.cond[n]) == \"table\" and u.cond[n].by == \"Prismatic Spray\" end\r\nif ab == \"Constitution\" and mine(\"Restrained\") then\r\nu.prism = type(u.prism) == \"table\" and u.prism or { s = 0, f = 0 }\r\nif ok then u.prism.s = u.prism.s + 1 else u.prism.f = u.prism.f + 1 end\r\nif u.prism.s >= 3 then u.cond.Restrained, u.prism = nil, nil; return \" (no longer Restrained)\" end\r\nif u.prism.f >= 3 then\r\nlocal caster = u.cond.Restrained.caster\r\nu.cond.Restrained, u.prism = nil, nil\r\nif K.prismImm(u).Petrified then return \" (no longer Restrained; immune: Petrified)\" end\r\nu.cond.Petrified = { by = \"Prismatic Spray\", caster = caster, stone = true }\r\nreturn \" (now Petrified)\"\r\nend\r\nreturn string.format(\" (Indigo: %d successes, %d failures)\", u.prism.s, u.prism.f)\r\nelseif ab == \"Wisdom\" and mine(\"Blinded\") then\r\nlocal caster = u.cond.Blinded.caster\r\nu.cond.Blinded = nil\r\nif ok then return \" (no longer Blinded)\" end\r\nu.cond.Incapacitated = { by = \"Prismatic Spray\", caster = caster, stone = true, plane = true }\r\nreturn \" (sent to another plane: out of this fight)\"\r\nend\r\nreturn \"\"\r\nend\r\n\r\nfunction K.prismHint(u, cn, x)\r\nif type(x) ~= \"table\" or x.by ~= \"Prismatic Spray\" then return \"\" end\r\nif cn == \"Restrained\" then\r\nlocal p = type(u.prism) == \"table\" and u.prism or { s = 0, f = 0 }\r\nreturn string.format(\": a Constitution SAVE at the end of each of its turns, no damage; three successes end it, three failures Petrify it (%d successes, %d failures so far)\", p.s, p.f)\r\nelseif cn == \"Blinded\" then\r\nreturn \": a Wisdom SAVE at the start of its caster's next turn, no damage; a success ends it, a failure sends it to another plane\"\r\nelseif x.plane then\r\nreturn \": sent to another plane, out of this fight\"\r\nelseif cn == \"Petrified\" then\r\nreturn \": until Greater Restoration or the like\"\r\nend\r\nreturn \"\"\r\nend\r\n\r\nfunction K.prismKo(body)\r\nlocal out = body:gsub(\"^8, two rays: \", \"8, 광선 둘: \"):gsub(\"^ray \", \"광선 \")\r\nout = out:gsub(\"(%d) (%a+)\", function(n, c) return n .. \" \" .. (K.PRISM_KO[c] or c) end)\r\n:gsub(\", (%a+) (%d+)\", function(t, n) local k = K.DMG_KO and K.DMG_KO[t]; if k then return \", \" .. k .. \" \" .. n end end)\r\n:gsub(\" resisted\", \" 저항\"):gsub(\" immune\", \" 면역\"):gsub(\" vulnerable\", \" 취약\"):gsub(\"no effect\", \"효과 없음\")\r\n:gsub(\", (%a+) by the story\", function(cn) return \", \" .. (NAMES_KO[cn] or cn) .. \"(이야기)\" end)\r\n:gsub(\", (%a+)$\", function(cn) return \", \" .. (NAMES_KO[cn] or (cn == \"immune\" and \"면역\") or cn) end)\r\n:gsub(\", (%a+);\", function(cn) return \", \" .. (NAMES_KO[cn] or (cn == \"immune\" and \"면역\") or cn) .. \";\" end)\r\nreturn out\r\nend\r\n\r\n\r\n\r\n\r\n\r\n\r\nK.FOE_COND = {\r\n[\"Hold Person\"] = { \"Paralyzed\" }, [\"Hold Monster\"] = { \"Paralyzed\" },\r\nSleep = { \"Incapacitated\", second = \"Unconscious\", wake = true },\r\n\r\n\r\n[\"Flesh to Stone\"] = { \"Restrained\", third = \"Petrified\", keep = true },\r\n\r\n\r\n\r\n[\"Hideous Laughter\"] = { \"Incapacitated\", also = { \"Prone\" } },\r\n[\"Hypnotic Pattern\"] = { \"Incapacitated\", also = { \"Charmed\" }, wake = true },\r\nBanishment = { \"Incapacitated\" },\r\nEntangle = { \"Restrained\" }, Web = { \"Restrained\" }, [\"Black Tentacles\"] = { \"Restrained\" }, [\"Ensnaring Strike\"] = { \"Restrained\" },\r\nFear = { \"Frightened\" }, Weird = { \"Frightened\" },\r\nSuggestion = { \"Charmed\" }, Compulsion = { \"Charmed\" }, [\"Dominate Beast\"] = { \"Charmed\" }, [\"Dominate Person\"] = { \"Charmed\" },\r\n[\"Dominate Monster\"] = { \"Charmed\" }, [\"Irresistible Dance\"] = { \"Charmed\" },\r\n\r\n\r\n[\"Stinking Cloud\"] = { \"Incapacitated\", also = { \"Poisoned\" }, rounds = 1 },\r\n[\"Color Spray\"] = { \"Blinded\", rounds = 2 },\r\n}\r\n\r\nfunction K.lessForms(formula, dice)\r\nlocal n, sz = tostring(dice or \"\"):match(\"^(%d+)d(%d+)$\")\r\nlocal o = {}\r\nlocal i, j = tostring(formula):find(\"+\" .. tostring(dice), 1, true)\r\nif not (n and i) then return o end\r\nfor cnt = tonumber(n) - 1, 1, -1 do o[#o + 1] = formula:sub(1, i - 1) .. \"+\" .. cnt .. \"d\" .. sz .. formula:sub(j + 1) end\r\nreturn o\r\nend\r\n\r\n\r\nfunction K.cutter(pc)\r\nif type(pc) ~= \"table\" then return nil end\r\nfor _, r in ipairs({ pc, table.unpack(Ally.list(pc)) }) do\r\nlocal sh = K.ownSheet(r, pc)\r\nif sh and not r.dead and K.subHas(sh, \"Cutting Words\") and (tonumber(type(r.res) == \"table\" and r.res[\"Bardic Inspiration\"]) or 0) > 0 then\r\nlocal sz = tostring((K.rowOf(sh, \"Bard\") or {}).bi or \"\"):match(\"d(%d+)\")\r\nif sz then return r, \"d\" .. sz end\r\nend\r\nend\r\nreturn nil\r\nend\r\nfunction K.cutSpend(pc)\r\nlocal r = K.cutter(pc)\r\nif r and not K.diceQuiet then r.res[\"Bardic Inspiration\"] = r.res[\"Bardic Inspiration\"] - 1 end\r\nreturn r\r\nend\r\n\r\n\r\nfunction K.recFx(r)\r\nlocal o = { ac = 0, saves = {}, dmg = {}, wdmg = {}, list = {} }\r\nif type(r) ~= \"table\" or type(r.sfx) ~= \"table\" then return o end\r\nlocal cc = K.curC\r\nlocal names = {}\r\nfor n in pairs(r.sfx) do names[#names + 1] = n end\r\ntable.sort(names)\r\nfor _, n in ipairs(names) do\r\nlocal e, d = r.sfx[n], K.foeFxOf(n)\r\nlocal over = type(e) ~= \"table\" or not d or (e.untilR and not (cc and cc.active and cc.fid == e.fid and (tonumber(cc.round) or 1) < e.untilR))\r\nor (tonumber(e.ends) and K.clockRef and tonumber(K.clockRef.min) and K.clockRef.min >= e.ends)\r\nif over then r.sfx[n] = nil\r\nelse\r\no.list[#o.list + 1] = n\r\no.ac = o.ac + (tonumber(d.ac) or 0)\r\nfor ab, v in pairs(type(d.saves) == \"table\" and d.saves or {}) do o.saves[ab] = (o.saves[ab] or 0) + (tonumber(v) or 0) end\r\nif d.dmg then o.dmg[#o.dmg + 1] = d.dmg end\r\nif d.wdmg then o.wdmg[#o.wdmg + 1] = d.wdmg end\r\nend\r\nend\r\nif next(r.sfx) == nil then r.sfx = nil end\r\nreturn o\r\nend\r\nfunction K.recFxTag(f, r, spell, sign, c, clock)\r\nlocal head = \"[COND|\" .. table.concat(f, \"|\")\r\nif sign == \"-\" then\r\nif not (type(r.sfx) == \"table\" and r.sfx[spell]) then return head .. \"|bad:\" .. (r.name or \"Player\") .. \" has no \" .. spell .. \" on it|-]\", false end\r\nr.sfx[spell] = nil\r\nreturn head .. \"|ok|(no longer under \" .. spell .. \")]\", true\r\nend\r\nlocal e = { src = trim(f[4] or \"\") }\r\nlocal active = type(c) == \"table\" and c.active\r\nfor part in (trim(f[3] or \"\"):gsub(\"%s\", \"\") .. \",\"):gmatch(\"([^,]*),\") do\r\nlocal dn, du = part:match(\"^%+?(%d+)([mhd])$\")\r\nlocal rn = part:match(\"^%+?(%d+)r$\")\r\nif dn and du == \"m\" and active then e.untilR, e.fid = (tonumber(c.round) or 1) + 10 * tonumber(dn), c.fid\r\nelseif dn then e.ends = (tonumber(type(clock) == \"table\" and clock.min) or tonumber(K.clockRef and K.clockRef.min) or 0) + tonumber(dn) * K.TIME_UNIT[du]\r\nelseif rn and active then e.untilR, e.fid = (tonumber(c.round) or 1) + tonumber(rn), c.fid end\r\nend\r\nr.sfx = type(r.sfx) == \"table\" and r.sfx or {}\r\nr.sfx[spell] = e\r\nreturn head .. \"|ok|(under \" .. spell .. \": \" .. K.foeFxText(K.foeFxOf(spell)) .. \")]\", true\r\nend\r\n\r\n\r\nfunction K.cmdDie(pc, who)\r\nif type(Feat.cur.used) ~= \"table\" then return nil end\r\nfor r, used in pairs(Feat.cur.used) do\r\nif type(used) == \"table\" and used[\"Superiority Dice\"] and K.byKey((r == pc and \"Player\") or r.name or \"?\") ~= K.byKey(who)\r\nand not (type(Feat.cur.cmdUsed) == \"table\" and Feat.cur.cmdUsed[r]) then\r\nlocal sh = K.ownSheet(r, pc)\r\nfor _, e in ipairs(sh and Feat.fxOf(sh, \"weapon_die\") or {}) do\r\nif e.res == \"Superiority Dice\" and type(e.dice) == \"string\" then return { dice = e.dice, by = r } end\r\nend\r\nend\r\nend\r\nreturn nil\r\nend\r\n\r\nfunction K.wakeFoe(u)\r\nif type(u) ~= \"table\" or type(u.cond) ~= \"table\" then return \"\" end\r\nlocal gone, slept = {}, false\r\nfor name, x in pairs(u.cond) do\r\nif type(x) == \"table\" and x.wake then\r\ngone[#gone + 1] = name\r\nif x.by == \"Sleep\" or name == \"Unconscious\" then slept = true end\r\nend\r\nend\r\nfor _, name in ipairs(gone) do u.cond[name] = nil end\r\nif #gone == 0 then return \"\" end\r\ntable.sort(gone)\r\nreturn slept and \" (wakes up)\" or (\" (no longer \" .. table.concat(gone, \", \") .. \")\")\r\nend\r\n\r\n\r\nfunction K.cimmIgnore(caster, spell, cond)\r\nlocal pc = K.curPc or K.partyPc\r\nlocal r = type(pc) == \"table\" and Ally.rec(pc, caster or \"Player\")\r\nlocal sh = r and K.AR.sheetOf(r, pc)\r\nfor _, e in ipairs(sh and Feat.fxOf(sh, \"cimm_ignore\") or {}) do\r\nlocal okC = false\r\nfor _, x in ipairs(type(e.conds) == \"table\" and e.conds or { \"Charmed\" }) do if x == cond then okC = true end end\r\nif okC then\r\nfor _, n in ipairs(type(e.spells) == \"table\" and e.spells or {}) do if n == spell then return true end end\r\nif e.implant and Feat.cur.trigSpell == spell then return true end\r\nend\r\nend\r\nreturn false\r\nend\r\n\r\n\r\nfunction K.featActor(pc, c, src)\r\nsrc = trim(src or \"\")\r\nif src == \"\" or src == \"-\" or SPELLS[Canon.name(src)] then return nil end\r\nlocal r = Ally.rec(pc, src)\r\nif r then return (r == pc and \"Player\") or r.name end\r\nlocal units = type(c) == \"table\" and type(c.units) == \"table\" and c.units or {}\r\nlocal su = units[src]\r\nif su then return su.side ~= \"enemy\" and src or nil end\r\nif not K.knownName(src) then return nil end\r\nlocal last = type(c) == \"table\" and c.last\r\nif last and units[last] and units[last].side ~= \"enemy\" then return last end\r\nreturn \"Player\"\r\nend\r\n\r\nK.FEAT_TERMS = { Grapple = true, Shove = true, Topple = true, Trip = true, Poison = true, Daze = true, [\"Knock Out\"] = true, Obscure = true }\r\nfunction K.knownName(src)\r\nlocal n = Canon.name(trim(src or \"\"))\r\nif K.FEAT_TERMS[n] or NAMES_KO[n] or K.FX[n] or (K.PACK.feat and K.PACK.feat[n]) then return true end\r\nif n:match(\"%(.-%)$\") and K.knownName((n:gsub(\"%s*%(.-%)$\", \"\"))) then return true end\r\nfor _, ko in pairs(NAMES_KO) do if ko == src then return true end end\r\nreturn false\r\nend\r\n\r\n\r\nfunction K.featCondPut(u, conds, src, who, dur, c, clock, spec)\r\nu.cond = type(u.cond) == \"table\" and u.cond or {}\r\nlocal e0 = { src = src, caster = who, feat = true }\r\nlocal active = type(c) == \"table\" and c.active\r\nlocal rnd = active and (tonumber(c.round) or 1) or 0\r\nlocal function parse(part)\r\nlocal dn, du = part:match(\"^%+?(%d+)([mhd])$\")\r\nlocal rn = part:match(\"^%+?(%d+)r$\")\r\nif part == \"dmg\" then e0.wake = true\r\nelseif part == \"turn\" and not active then\r\ne0.ends = (tonumber(type(clock) == \"table\" and clock.min) or tonumber(K.clockRef and K.clockRef.min) or 0) + 1\r\nelseif part == \"turn\" then e0.turnOf, e0.r0t, e0.fid = who, rnd, c.fid\r\nelseif dn and du == \"m\" and active then e0.untilR, e0.fid = rnd + 10 * tonumber(dn), c.fid\r\nelseif dn then e0.ends = (tonumber(type(clock) == \"table\" and clock.min) or tonumber(K.clockRef and K.clockRef.min) or 0) + tonumber(dn) * K.TIME_UNIT[du]\r\nelseif rn and active then e0.untilR, e0.fid = rnd + tonumber(rn), c.fid\r\nelseif rn then e0.ends = (tonumber(type(clock) == \"table\" and clock.min) or tonumber(K.clockRef and K.clockRef.min) or 0) + math.max(1, math.ceil(tonumber(rn) / 10)) end\r\nend\r\nif type(spec) == \"table\" then\r\n\r\nlocal function n(v) return tonumber(v) or ((type(v) == \"string\" and SHEET) and math.max(1, K.fxNum(v, SHEET, K.charLevel(SHEET))) or nil) end\r\nif spec.turn then parse(\"turn\") end\r\nif n(spec.rounds) then parse(n(spec.rounds) .. \"r\") end\r\nif n(spec.mins) then parse(n(spec.mins) .. \"m\") end\r\nif spec.wake then e0.wake = true end\r\nelse\r\nfor part in (trim(dur or \"\"):gsub(\"%s\", \"\") .. \",\"):gmatch(\"([^,]*),\") do parse(part) end\r\nend\r\nlocal now = {}\r\nlocal mk = MONSTERS[(K.kindOf and K.kindOf(u, K.partyPc)) or u.kind or \"\"] or {}\r\nfor _, x in ipairs(conds) do\r\nlocal imm = false\r\nfor _, y in ipairs(mk.cimm or {}) do if y == x then imm = true end end\r\nif not imm then\r\nlocal e = {}\r\nfor k, v in pairs(e0) do e[k] = v end\r\nu.cond[x] = e\r\nnow[#now + 1] = x\r\nend\r\nend\r\nreturn now\r\nend\r\n\r\nfunction K.turnOver(u, e)\r\nlocal cc = K.curC\r\nif not (type(cc) == \"table\" and cc.active and cc.fid == e.fid) then return true end\r\nlocal r = tonumber(cc.round) or 1\r\nif r <= (tonumber(e.r0t) or 0) then return false end\r\nif r > (tonumber(e.r0t) or 0) + 1 then return true end\r\nlocal me, giver\r\nfor i, nm in ipairs(cc.order or {}) do\r\nif cc.units[nm] == u then me = i end\r\nif K.byKey(nm) == K.byKey(e.turnOf) then giver = i end\r\nend\r\nreturn not (me and giver and me < giver)\r\nend\r\n\r\nfunction K.featCondOn(u, src)\r\nfor _, e in pairs(type(u) == \"table\" and type(u.cond) == \"table\" and u.cond or {}) do\r\nif type(e) == \"table\" and e.feat and e.src == src then return e end\r\nend\r\nreturn nil\r\nend\r\nfunction K.featCondOff(u, src)\r\nlocal gone = {}\r\nfor name, e in pairs(type(u) == \"table\" and type(u.cond) == \"table\" and u.cond or {}) do\r\nif type(e) == \"table\" and e.feat and e.src == src then gone[#gone + 1] = name end\r\nend\r\nfor _, name in ipairs(gone) do u.cond[name] = nil end\r\ntable.sort(gone)\r\nreturn gone\r\nend\r\n\r\n\r\nfunction K.charmedBy(u, pc, tgt)\r\nfor _, name in ipairs(K.foeCondFx(u, pc).list) do\r\nlocal e = u.cond[name]\r\nlocal charm = name == \"Charmed\"\r\nif not charm then for x in pairs(K.condEff(name)) do if x == \"Charmed\" then charm = true end end end\r\nlocal who = type(e) == \"table\" and (e.caster or e.src)\r\nif charm and who and K.byKey(who) == K.byKey(tgt) then return name end\r\nend\r\nreturn nil\r\nend\r\n\r\n\r\nfunction K.heldFull(e)\r\nif e.ranOut then return true end\r\nlocal cc = K.curC\r\nlocal mins = tonumber(SPELLS[e.by or \"\"] and SPELLS[e.by].mins) or 1\r\nreturn (type(cc) == \"table\" and cc.active and cc.fid == e.r0f and tonumber(e.r0) and (tonumber(cc.round) or 1) >= e.r0 + 10 * mins) and true or false\r\nend\r\nfunction K.stoneRanOut(who, spell)\r\nlocal cc = K.curC\r\nfor _, u in pairs(type(cc) == \"table\" and type(cc.units) == \"table\" and cc.units or {}) do\r\nfor _, e in pairs(type(u) == \"table\" and type(u.cond) == \"table\" and u.cond or {}) do\r\nif type(e) == \"table\" and e.keep and e.by == spell and (e.caster or \"Player\") == who then e.ranOut = true end\r\nend\r\nend\r\nend\r\n\r\nfunction K.foeCondFx(u, pc)\r\nlocal fx = { autofail = {}, list = {} }\r\nif type(u) == \"table\" and type(u.cond) ~= \"table\" and K.AR and K.AR.incapNow(u) then fx.incap = \"Incapacitated (a climax)\"; return fx end\r\nif type(u) ~= \"table\" or type(u.cond) ~= \"table\" then return fx end\r\nlocal names = {}\r\nfor name, e in pairs(u.cond) do\r\nlocal sp = type(e) == \"table\" and SPELLS[e.by or \"\"]\r\nif type(e) == \"table\" and e.ko then\r\nnames[#names + 1] = name\r\nelseif type(e) == \"table\" and e.pack and CONDS[name] then\r\nlocal cc = K.curC\r\nlocal roundsOver = e.untilR and not (cc and cc.active and cc.fid == e.fid and (tonumber(cc.round) or 1) < e.untilR)\r\nif (tonumber(e.ends) and K.clockRef and tonumber(K.clockRef.min) and K.clockRef.min >= e.ends) or roundsOver or K.AR.concOver(e.conc, pc) then u.cond[name] = nil\r\nelse names[#names + 1] = name end\r\nelseif type(e) == \"table\" and e.feat then\r\nlocal cc = K.curC\r\nlocal over = (e.untilR and not (cc and cc.active and cc.fid == e.fid and (tonumber(cc.round) or 1) < e.untilR))\r\nor (tonumber(e.ends) and K.clockRef and tonumber(K.clockRef.min) and K.clockRef.min >= e.ends)\r\nor (e.turnOf and K.turnOver(u, e))\r\nif over then u.cond[name] = nil else names[#names + 1] = name end\r\nelseif type(e) == \"table\" and e.stone then\r\nnames[#names + 1] = name\r\nelseif type(e) == \"table\" and e.keep and sp and sp.m and sp.m.concentration and not K.concOn(pc, e.caster or \"Player\", e.by) and K.heldFull(e) then\r\ne.stone = true\r\nnames[#names + 1] = name\r\nelseif not sp or (sp.m and sp.m.concentration and not K.concOn(pc, e.caster or \"Player\", e.by))\r\nor (e.untilR and not (K.curC and K.curC.active and K.curC.fid == e.fid and (tonumber(K.curC.round) or 1) < e.untilR)) then\r\nu.cond[name] = nil\r\nelse\r\nnames[#names + 1] = name\r\nend\r\nend\r\ntable.sort(names)\r\nfor _, name in ipairs(names) do\r\nfx.list[#fx.list + 1] = name\r\nfor _, m in pairs(K.condEff(name)) do\r\nfor _, a in ipairs(m.auto_fail_saves or {}) do fx.autofail[a] = name end\r\nif m.auto_crit_within_5ft then fx.crit = name end\r\nif m.incapacitated or m.no_actions then fx.incap = name end\r\nif m.no_hostile then fx.nohostile = name end\r\nend\r\nend\r\nif K.AR and K.AR.incapNow(u) then fx.incap = fx.incap or \"Incapacitated (a climax)\" end\r\nreturn fx\r\nend\r\n\r\nfunction K.foeCondApply(u, spell, ok, caster)\r\nlocal e = K.FOE_COND[spell]\r\n\r\nif not e then\r\nlocal fc = SPELLS[spell] and SPELLS[spell].m and SPELLS[spell].m.foe_cond\r\nif type(fc) == \"string\" then e = { fc } elseif type(fc) == \"table\" and type(fc[1]) == \"string\" then e = fc\r\nelseif type(fc) == \"table\" and type(fc.name) == \"string\" then\r\ne = { fc.name, also = fc.also, rounds = fc.rounds, wake = fc.wake, second = fc.second, third = fc.third, keep = fc.keep }\r\nend\r\nend\r\n\r\nif not e and ok and type(u) == \"table\" and type(u.cond) == \"table\" then\r\nlocal had = {}\r\nfor name, x in pairs(u.cond) do if type(x) == \"table\" and x.by == spell then had[#had + 1] = name end end\r\nfor _, name in ipairs(had) do u.cond[name] = nil end\r\ntable.sort(had)\r\nreturn #had > 0 and (\" (no longer \" .. table.concat(had, \", \") .. \")\") or \"\"\r\nend\r\nif not e or type(u) ~= \"table\" or u.loose then return \"\" end\r\nu.cond = type(u.cond) == \"table\" and u.cond or {}\r\nif ok then\r\nlocal had = {}\r\nfor name, x in pairs(u.cond) do if type(x) == \"table\" and x.by == spell then had[#had + 1] = name end end\r\nif #had == 0 then return \"\" end\r\nif e.third then\r\nu.fts = type(u.fts) == \"table\" and u.fts or { f = 0, s = 0 }\r\nu.fts.s = u.fts.s + 1\r\nif u.fts.s < 3 then return \"\" end\r\nu.fts = nil\r\nend\r\nfor _, name in ipairs(had) do u.cond[name] = nil end\r\ntable.sort(had)\r\nreturn \" (no longer \" .. table.concat(had, \", \") .. \")\"\r\nend\r\nlocal put\r\nlocal r0prev = type(u.cond[e[1]]) == \"table\" and u.cond[e[1]].by == spell and u.cond[e[1]].r0 or nil\r\nif e.second and type(u.cond[e[1]]) == \"table\" and u.cond[e[1]].by == spell then\r\nput = e.second\r\nelseif e.third then\r\n\r\n\r\n\r\nlocal function mine(n) return type(u.cond[n]) == \"table\" and u.cond[n].by == spell end\r\nif mine(e.third) then return \"\" end\r\nif not mine(e[1]) then\r\nu.fts = { f = 0, s = 0 }\r\nput = e[1]\r\nelse\r\nu.fts = type(u.fts) == \"table\" and u.fts or { f = 0, s = 0 }\r\nu.fts.f = u.fts.f + 1\r\nput = u.fts.f >= 3 and e.third or e[1]\r\nif put == e.third then u.cond[e[1]] = nil end\r\nend\r\nelse\r\nput = e[1]\r\nend\r\nfor _, x in ipairs((MONSTERS[u.kind or \"\"] or {}).cimm or {}) do\r\nif not K.cimmIgnore(caster, spell, x) then\r\nif x == put then return \"\" end\r\n\r\nfor _, h in ipairs(CONDS[put] and CONDS[put].pack and CONDS[put].pack.has or {}) do if h == x then return \" (immune: \" .. x .. \")\" end end\r\nend\r\nend\r\n\r\nlocal now = {}\r\nfor _, x in ipairs({ put, table.unpack(type(e.also) == \"table\" and e.also or {}) }) do\r\nlocal imm = false\r\nfor _, y in ipairs((MONSTERS[u.kind or \"\"] or {}).cimm or {}) do if y == x and not K.cimmIgnore(caster, spell, y) then imm = true end end\r\nif not imm and not (type(u.cond[x]) == \"table\" and u.cond[x].by == spell) then\r\nu.cond[x] = { by = spell, caster = caster, wake = e.wake }\r\nlocal cc = K.curC\r\nif tonumber(e.rounds) and type(cc) == \"table\" and cc.active then u.cond[x].untilR, u.cond[x].fid = (tonumber(cc.round) or 1) + tonumber(e.rounds), cc.fid end\r\n\r\nif type(cc) == \"table\" and cc.active then u.cond[x].r0, u.cond[x].r0f = r0prev or (tonumber(cc.round) or 1), cc.fid end\r\nif e.keep and x == e.third then u.cond[x].keep = true end\r\nnow[#now + 1] = x\r\nend\r\nend\r\nreturn #now > 0 and (\" (now \" .. table.concat(now, \", \") .. \")\") or \"\"\r\nend\r\n\r\n\r\n\r\n\r\n\r\nfunction K.foeFxOf(spell)\r\nlocal m = SPELLS[spell or \"\"] and SPELLS[spell].m\r\nif type(m) ~= \"table\" then return nil end\r\nif type(m.foe_fx) == \"table\" then return m.foe_fx end\r\nif type(m.extra_save) == \"table\" and type(m.extra_save.foe_fx) == \"table\" then return m.extra_save.foe_fx end\r\nreturn nil\r\nend\r\nfunction K.foeFx(u, pc)\r\nlocal o = { ac = 0, saves = {}, dmg = {}, wdmg = {}, list = {} }\r\nif type(u) ~= \"table\" or type(u.sfx) ~= \"table\" then return o end\r\nlocal names = {}\r\nfor n in pairs(u.sfx) do names[#names + 1] = n end\r\ntable.sort(names)\r\nfor _, n in ipairs(names) do\r\nlocal e, d = u.sfx[n], K.foeFxOf(n)\r\nlocal m = SPELLS[n] and SPELLS[n].m or {}\r\nif type(e) ~= \"table\" or not d or (m.concentration and not K.concOn(pc, e.caster or \"Player\", n)) then\r\nu.sfx[n] = nil\r\nelse\r\no.list[#o.list + 1] = n\r\no.ac = o.ac + (tonumber(d.ac) or 0)\r\nfor ab, v in pairs(type(d.saves) == \"table\" and d.saves or {}) do o.saves[ab] = (o.saves[ab] or 0) + (tonumber(v) or 0) end\r\nif d.bane then o.bane = n end\r\nif d.dmg then o.dmg[#o.dmg + 1] = d.dmg end\r\nif d.wdmg then o.wdmg[#o.wdmg + 1] = d.wdmg end\r\nend\r\nend\r\nif next(u.sfx) == nil then u.sfx = nil end\r\nreturn o\r\nend\r\nK.AB6 = { \"Strength\", \"Dexterity\", \"Constitution\", \"Intelligence\", \"Wisdom\", \"Charisma\" }\r\nfunction K.foeFxText(d)\r\nlocal o = {}\r\nif tonumber(d.ac) then o[#o + 1] = string.format(\"AC %+d\", d.ac) end\r\nfor _, ab in ipairs(K.AB6) do\r\nlocal v = type(d.saves) == \"table\" and tonumber(d.saves[ab])\r\nif v then o[#o + 1] = string.format(\"%s saves %+d\", ab, v) end\r\nend\r\nif d.bane then o[#o + 1] = \"attack rolls and saves -1d4\" end\r\nif d.dmg then o[#o + 1] = \"damage rolls -\" .. d.dmg end\r\nif d.wdmg then o[#o + 1] = \"weapon damage -\" .. d.wdmg end\r\nreturn table.concat(o, \", \")\r\nend\r\n\r\nfunction K.foeFxKo(list)\r\nlocal AB = { Strength = \"근력\", Dexterity = \"민첩\", Constitution = \"건강\", Intelligence = \"지능\", Wisdom = \"지혜\", Charisma = \"매력\" }\r\nreturn (list:gsub(\"AC ([%+%-]%d+)\", \"방어도 %1\"):gsub(\"(%a+) saves ([%+%-]%d+)\", function(a, v) return (AB[a] or a) .. \" 내성 \" .. v end)\r\n:gsub(\"attack rolls and saves %-\", \"명중·내성 -\"):gsub(\"weapon damage %-\", \"무기 피해 -\"):gsub(\"damage rolls %-\", \"피해 굴림 -\"):gsub(\", \", \"·\"))\r\nend\r\nfunction K.foeFxApply(u, spell, ok, caster)\r\nlocal d = K.foeFxOf(spell)\r\nif not d or type(u) ~= \"table\" or u.loose then return \"\" end\r\nif ok then\r\nif type(u.sfx) == \"table\" and u.sfx[spell] then\r\nu.sfx[spell] = nil\r\nreturn \" (no longer under \" .. spell .. \")\"\r\nend\r\nreturn \"\"\r\nend\r\nu.sfx = type(u.sfx) == \"table\" and u.sfx or {}\r\nif not u.sfx[spell] then\r\nFeat.cur.sfxNew = Feat.cur.sfxNew or {}\r\nFeat.cur.sfxNew[u] = true\r\nend\r\nu.sfx[spell] = { caster = caster }\r\nreturn \" (under \" .. spell .. \": \" .. K.foeFxText(d) .. \")\"\r\nend\r\n\r\nfunction K.foeFxLine(u, pc, st)\r\nlocal fx = K.foeFx(u, pc)\r\nif #fx.list == 0 then return \"\" end\r\nlocal o = {}\r\nlocal a1 = type(st) == \"table\" and type(st.attacks) == \"table\" and st.attacks[1]\r\nfor _, n in ipairs(fx.list) do\r\nlocal d, e = K.foeFxOf(n), u.sfx[n]\r\nlocal p = {}\r\nif tonumber(d.ac) then p[#p + 1] = string.format(\"AC %+d (AC %d now)\", d.ac, (tonumber(st and st.ac) or 10) + fx.ac - (tonumber(u.strip) or 0)) end\r\nfor _, ab in ipairs(K.AB6) do\r\nlocal v = type(d.saves) == \"table\" and tonumber(d.saves[ab])\r\nlocal now = v and K.foeDrain(u, ab, ((type(st) == \"table\" and type(st.saves) == \"table\" and st.saves[ab]) or 0) - K.foeExh(u))\r\nif v then p[#p + 1] = string.format(\"%s saves %+d (%s save %+d now)\", ab, v, ab, now) end\r\nend\r\nif d.bane then p[#p + 1] = \"its attack rolls and saves take the next d4 off: write the d20 field \\\"14 bane 3\\\"\" end\r\nif d.dmg then p[#p + 1] = \"each damage formula of its attacks ends with -\" .. d.dmg .. \", that die written last\" .. (a1 and (\" (\" .. a1.name .. \": \" .. a1.dmg .. \"-\" .. d.dmg .. \")\") or \"\") end\r\nif d.wdmg then p[#p + 1] = \"its weapon attacks' damage formulas end with -\" .. d.wdmg .. \", that die written last (at least 1 lands)\" end\r\no[#o + 1] = n .. \" (\" .. tostring(type(e) == \"table\" and e.caster or \"Player\") .. \"'s): \" .. table.concat(p, \", \")\r\nend\r\nreturn \", \" .. table.concat(o, \"; \")\r\nend\r\n\r\n\r\nfunction K.resD4Take(r, dtype, by, pools, cur, bad, pc)\r\nfor bn, b in pairs(type(r) == \"table\" and type(r.buff) == \"table\" and r.buff or {}) do\r\nif type(b) == \"table\" and b.resd4 and b.choice == dtype and K.buffLive(pc, bn, b) then\r\nlocal key = tostring(r.name or \"Player\") .. \"|\" .. tostring(by or \"?\")\r\nFeat.cur.resD4 = Feat.cur.resD4 or {}\r\nif Feat.cur.resD4[key] then return nil end\r\nFeat.cur.resD4[key] = true\r\ncur.d4 = (cur.d4 or 0) + 1\r\nlocal w = pools.d4 and pools.d4[cur.d4]\r\nif w == nil then K.poolEmpty(bad, \"d4\"); w = K.pastDie(pools, \"d4\", cur.d4) end\r\nreturn { n = w, src = bn }\r\nend\r\nend\r\nreturn nil\r\nend\r\n\r\n\r\nfunction K.polyLive(u, pc)\r\nlocal p = type(u) == \"table\" and type(u.poly) == \"table\" and u.poly\r\nif not p then return nil end\r\nif not MONSTERS[p.kind or \"\"] or not K.concOn(pc or K.partyPc, p.caster or \"Player\", p.by) or (tonumber(u.thp) or 0) <= 0 then\r\nu.poly, u.thp = nil, nil\r\nreturn nil\r\nend\r\nreturn p.kind\r\nend\r\nfunction K.kindOf(u, pc) return K.polyLive(u, pc) or (type(u) == \"table\" and u.kind) or nil end\r\n\r\nfunction K.polyTag(f, c, pc, name, m)\r\nlocal head = \"[BUFF|\" .. table.concat(f, \"|\")\r\nlocal function fail(why) return head .. \"|bad:\" .. why .. \"|-]\", false end\r\nlocal beast = Canon.name(trim(f[3] or \"\"))\r\nlocal mon = MONSTERS[beast]\r\nif not (mon and mon.beast) then return fail(\"name the Beast it becomes, one with a stat block: [BUFF|Target|\" .. name .. \"|Beast]\") end\r\nlocal casting\r\nfor _, x in ipairs(Feat.cur.casts or {}) do if x.name == name then casting = x end end\r\nif not casting then return fail(\"cast \" .. name .. \" with CAST first\") end\r\nlocal who = casting.by or \"Player\"\r\nlocal cr = K.crNum\r\nlocal t = Ally.rec(pc, f[1] or \"\")\r\nif t then\r\nif t.dead or (tonumber(t.hp) or 0) <= 0 then return fail((t.name or \"Player\") .. \" is down\") end\r\nlocal lim = K.charLevel((t ~= pc and t.sheet) or K.outerSheet or SHEET)\r\nif cr(mon.cr) > lim then return fail(beast .. \" is CR \" .. tostring(mon.cr) .. \": CR \" .. lim .. \" at most (the level)\") end\r\nt.form, t.formEnds, t.formBy = beast, nil, { spell = name, by = who }\r\nt.thp = math.max(tonumber(t.thp) or 0, tonumber(mon.hp) or 1)\r\nreturn head .. \"|ok|\" .. (t.name or \"Player\") .. \" is a \" .. beast .. \" (AC \" .. tostring(mon.ac) .. \", \" .. t.thp .. \" temporary HP)]\", true\r\nend\r\nlocal u = c.active and c.units[f[1] or \"\"]\r\nif not (u and u.side == \"enemy\") then return fail(\"target must be Player, a companion or a creature in the fight\") end\r\nif not (type(Feat.cur.polyFail) == \"table\" and Feat.cur.polyFail[f[1]] == name) then\r\nreturn fail(f[1] .. \" made no failed save against \" .. name .. \" in this reply (its SAVE first)\")\r\nend\r\nlocal own = MONSTERS[u.kind or \"\"] or {}\r\nif cr(mon.cr) > cr(own.cr or \"0\") then return fail(beast .. \" is CR \" .. tostring(mon.cr) .. \": CR \" .. tostring(own.cr) .. \" at most (its own)\") end\r\nu.poly = { kind = beast, by = name, caster = who }\r\nu.thp = tonumber(mon.hp) or 1\r\nreturn head .. \"|ok|\" .. f[1] .. \" is a \" .. beast .. \" (AC \" .. tostring(mon.ac) .. \", \" .. u.thp .. \" temporary HP)]\", true\r\nend\r\n\r\nfunction K.mirrorLeft(r)\r\nlocal mi = type(r) == \"table\" and type(r.mirror) == \"table\" and r.mirror\r\nif not mi then return 0 end\r\nif not (type(r.lasting) == \"table\" and r.lasting[mi.spell or \"Mirror Image\"]) then r.mirror = nil; return 0 end\r\nreturn tonumber(mi.n) or 0\r\nend\r\n\r\n\r\nfunction K.buffHas(r, key)\r\nfor _, b in pairs(type(r) == \"table\" and type(r.buff) == \"table\" and r.buff or {}) do\r\nif type(b) == \"table\" and b[key] and not (tonumber(b.ends) and K.clockRef and tonumber(K.clockRef.min) and K.clockRef.min >= b.ends) then return true end\r\nend\r\nreturn false\r\nend\r\nfunction K.dieFor(r, die)\r\nif K.buffHas(r, \"maxdice\") then return die end\r\n\r\nlocal pc = K.curPc\r\nif type(pc) == \"table\" and Ally and Ally.list then\r\nfor _, x in ipairs({ pc, table.unpack(Ally.list(pc)) }) do\r\nlocal sh = x ~= r and ((x == pc and (K.outerSheet or SHEET)) or x.sheet)\r\nif sh and Feat.fxOf and #Feat.fxOf(sh, \"ally_reroll_hd\") > 0 then return math.max(K.d(die), K.d(die)) end\r\nend\r\nend\r\nreturn K.d(die)\r\nend\r\nfunction K.recoverBonus(r, pc)\r\nlocal sh = type(r) == \"table\" and (r.sheet or (r == pc and (K.outerSheet or SHEET))) or nil\r\nlocal n = 0\r\nfor _, e in ipairs(sh and Feat.fxOf and Feat.fxOf(sh, \"recover_bonus\") or {}) do n = n + K.fxNum(e.add or 0, sh, K.charLevel(sh)) end\r\nreturn n\r\nend\r\n\r\nfunction K.pactKeys(r, pc)\r\nreturn Ally.run(pc, r ~= pc and r or nil, function()\r\nlocal o, any = {}, false\r\nfor k in pairs(PC.res) do if k:match(\"^Pact Slot\") then o[#o + 1] = k; any = true end end\r\nif not any and SHEET and K.cl(SHEET, \"Warlock\") > 0 and #K.mcList(SHEET) == 0 then\r\nfor k in pairs(PC.res) do if k:match(\"^Spell Slot\") then o[#o + 1] = k end end\r\nend\r\ntable.sort(o)\r\nreturn o\r\nend) or {}\r\nend\r\nfunction K.pactSpend(r, pc)\r\nfor _, k in ipairs(K.pactKeys(r, pc)) do\r\nif (tonumber(type(r.res) == \"table\" and r.res[k]) or 0) > 0 then r.res[k] = r.res[k] - 1; return k end\r\nend\r\nreturn nil\r\nend\r\n\r\nfunction K.regain(r, pc, rg, src)\r\nif type(rg) ~= \"table\" or type(r) ~= \"table\" then return \"\" end\r\nr.res = type(r.res) == \"table\" and r.res or {}\r\nlocal n = tonumber(rg.n)\r\nif not n then\r\nlocal p = parseFormula and parseFormula(tostring(rg.n or \"1\"))\r\nn = 0\r\nfor _, d in ipairs(p and p.dice or {}) do for _ = 1, d.n do n = n + K.d(d.s) end end\r\nn = n + (p and p.mod or 0)\r\nend\r\nlocal maxOf = function(k) return Ally.run(pc, r ~= pc and r or nil, function() return PC.res[k] and PC.res[k].max end) end\r\nif rg.res then\r\nlocal mx = maxOf(rg.res)\r\nif not mx then return \"\" end\r\nlocal was = tonumber(r.res[rg.res]) or 0\r\nr.res[rg.res] = math.min(mx, was + n)\r\nreturn string.format(\" (%s: %s +%d, %d/%d)\", src or \"regain\", rg.res, r.res[rg.res] - was, r.res[rg.res], mx)\r\nelseif rg.slot == \"pact\" then\r\nlocal keys = K.pactKeys(r, pc)\r\nfor i = #keys, 1, -1 do\r\nlocal k = keys[i]\r\nlocal mx = maxOf(k)\r\nif mx and (tonumber(r.res[k]) or 0) < mx then\r\nr.res[k] = math.min(mx, (tonumber(r.res[k]) or 0) + n)\r\nreturn string.format(\" (%s: %s back, %d/%d)\", src or \"regain\", k, r.res[k], mx)\r\nend\r\nend\r\nreturn string.format(\" (%s: no spent Warlock slot)\", src or \"regain\")\r\nend\r\nreturn \"\"\r\nend\r\nfunction K.buffSum(r, key)\r\nlocal n = 0\r\nfor _, b in pairs(type(r) == \"table\" and type(r.buff) == \"table\" and r.buff or {}) do\r\nif type(b) == \"table\" and tonumber(b[key]) then n = n + b[key] end\r\nend\r\nreturn n\r\nend\r\nfunction K.zeroAct(r)\r\nlocal sh = type(r) == \"table\" and (r.sheet or (r.name == nil and SHEET)) or nil\r\nif not (sh and Feat.fxOf and K.AR and K.AR.on()) then return nil end\r\nfor _, e in ipairs(Feat.fxOf(sh, \"zero_hp_act\")) do\r\nlocal a = type(r.ar) == \"table\" and r.ar or {}\r\nif e[\"if\"] ~= \"arousal_over_half\" or (tonumber(a.cur) or 0) * 2 > K.AR.max(r, r.name == nil and r or nil) then return e.src or \"zero_hp_act\" end\r\nend\r\nreturn nil\r\nend\r\nfunction K.upNow(r) return type(r) == \"table\" and not r.dead and ((tonumber(r.hp) or 0) > 0 or r.zeroAct) end\r\n\r\n\r\nfunction K.pickHas(v, name)\r\nif v == name then return true end\r\nfor _, x in ipairs(type(v) == \"table\" and v or {}) do if x == name then return true end end\r\nreturn false\r\nend\r\nfunction K.fxImpl(sh, e, impl, name)\r\nlocal p = type(sh) == \"table\" and type(sh.picks) == \"table\" and sh.picks or {}\r\nif e.pick and K.pickHas(p[e.pick], name) then return true end\r\nfor _, x in ipairs(e.names or {}) do if x == name then return true end end\r\nfor _, x in ipairs(e.kinds or {}) do if impl and x == impl.kind then return true end end\r\nfor _, x in ipairs(e.types or {}) do if impl and x == impl.type then return true end end\r\nreturn not (e.pick or e.names or e.kinds or e.types)\r\nend\r\nfunction K.joinNote(a, b) return (a ~= \"\" and b ~= \"\") and (a .. \", \" .. b) or (a .. b) end\r\nfunction K.foeExh(u) return 2 * (tonumber(type(u) == \"table\" and u.exh) or 0) end\r\n\r\nfunction K.fxOldBonus(u, ab, written, bonus)\r\nif not (type(Feat.cur.sfxNew) == \"table\" and Feat.cur.sfxNew[u]) then return false end\r\nlocal d = K.foeFx(u, K.partyPc).saves[ab] or 0\r\nreturn d ~= 0 and tonumber(written) == bonus - d\r\nend\r\n\r\nfunction K.foeDrain(u, ab, bonus)\r\nbonus = bonus + (K.foeFx(u, K.partyPc).saves[ab] or 0)\r\nlocal e = K.drainOf(u, ab)\r\nif not e then return bonus end\r\nif tonumber(e.set) then return math.min(bonus, abilityMod(e.set)) end\r\nreturn bonus + math.floor((tonumber(e.n) or 0) / 2)\r\nend\r\n\r\n\r\nfunction K.situational(st, u, tgt)\r\nlocal exh = K.foeExh(u)\r\nlocal need = exh > 0\r\nfor _, a in ipairs(st.attacks or {}) do if a.bloodied or a.vsb or a.alt then need = true end end\r\n\r\nlocal sfx = K.foeFx(u, K.partyPc)\r\nlocal off = \"\"\r\nfor _, x in ipairs(sfx.dmg) do off = off .. \"-\" .. x end\r\nlocal woff = \"\"\r\nfor _, x in ipairs(sfx.wdmg) do woff = woff .. \"-\" .. x end\r\nif off ~= \"\" or woff ~= \"\" then need = true end\r\n\r\n\r\nlocal _, cutD = K.cutter(K.partyPc)\r\nlocal mk = MONSTERS[(K.kindOf(u, K.partyPc)) or u.kind or \"\"] or {}\r\nlocal strM = (type(mk.sc) == \"table\" and tonumber(mk.sc.Strength) and abilityMod(mk.sc.Strength))\r\nor (type(mk.saves) == \"table\" and tonumber(mk.saves.Strength))\r\nif cutD or (strM and u.side == \"enemy\") then need = true end\r\nif not need then return st end\r\nlocal s2 = {}\r\nfor k, v in pairs(st) do s2[k] = v end\r\ns2.attacks = {}\r\nlocal selfB = (tonumber(u.hp) or 0) * 2 <= (tonumber(u.max) or 0)\r\nlocal tB = type(tgt) == \"table\" and (tonumber(tgt.hp) or 0) * 2 <= (tonumber(tgt.max) or 0)\r\nfor _, a in ipairs(st.attacks) do\r\nlocal b = {}\r\nfor k, v in pairs(a) do b[k] = v end\r\nb.hit = a.hit - exh\r\nif a.bloodied and selfB then b.dmg = a.bloodied end\r\nif a.vsb and tB then b.dmg = a.vsb end\r\nlocal wo = (not a.spell) and woff or \"\"\r\nb.dmg = b.dmg .. off .. wo\r\nif wo ~= \"\" then b.min1 = true end\r\ns2.attacks[#s2.attacks + 1] = b\r\nif a.alt then\r\nlocal c2 = {}\r\nfor k, v in pairs(b) do c2[k] = v end\r\nc2.dmg = a.alt .. off .. wo\r\ns2.attacks[#s2.attacks + 1] = c2\r\nend\r\nend\r\nif strM and u.side == \"enemy\" then\r\nlocal hasU = false\r\nfor _, a in ipairs(s2.attacks) do if (a.name or \"\"):match(\"^Unarmed Strike\") then hasU = true end end\r\nif not hasU then\r\ns2.attacks[#s2.attacks + 1] = { name = \"Unarmed Strike\", hit = strM + (tonumber(mk.pb) or 2) - exh, dmg = tostring(math.max(1, 1 + strM)) .. off,\r\ntype = \"Bludgeoning\", melee = true, unarmedM = true }\r\nend\r\nend\r\nif cutD then\r\nlocal n0 = #s2.attacks\r\nfor i = 1, n0 do\r\nlocal a = s2.attacks[i]\r\nif not a.nodmg then\r\nlocal c3 = {}\r\nfor k, v in pairs(a) do c3[k] = v end\r\nc3.dmg, c3.cutw = a.dmg .. \"-1\" .. cutD, true\r\ns2.attacks[#s2.attacks + 1] = c3\r\nend\r\nend\r\nend\r\nreturn s2\r\nend\r\n\r\nfunction K.newFoe(c, after, kind, hp, size)\r\nlocal n = 0\r\nfor nm in pairs(c.units) do\r\nlocal k, i = nm:match(\"^(.-) (%d+)$\")\r\nif k == kind and tonumber(i) > n then n = tonumber(i) end\r\nend\r\nlocal name = kind .. \" \" .. (n + 1)\r\nlocal base = c.units[after]\r\nc.units[name] = { side = \"enemy\", kind = kind, hp = hp, max = hp, init = base and base.init or 0, xp = 0, size = size }\r\nlocal at = #c.order + 1\r\nfor i, x in ipairs(c.order) do if x == after then at = i + 1 end end\r\ntable.insert(c.order, at, name)\r\nreturn name\r\nend\r\n\r\n\r\n\r\n\r\n\r\nfunction K.afterHit(c, name, u, dmg, raw, dtype, by, was, pc)\r\nif not (type(c) == \"table\" and c.active and type(u) == \"table\" and u.side == \"enemy\" and not u.loose and c.units[name] == u) then return \"\" end\r\nlocal m = MONSTERS[u.kind or \"\"] or {}\r\nlocal note = \"\"\r\nif m.split and (raw or 0) > 0 and u.hp >= 10 then\r\nlocal size = u.size or (m.what or \"\"):match(\"^(%a+)\") or \"Large\"\r\nlocal typed = false\r\nfor _, ty in ipairs(m.split) do if K.isType(dtype, ty) then typed = true end end\r\nlocal nowB = (was or 0) * 2 > u.max and u.hp * 2 <= u.max\r\nif (size == \"Large\" or size == \"Medium\") and (typed or nowB) and u.reactRound ~= (c.round or 1) and not K.foeCondFx(u, pc).incap then\r\nlocal h = math.floor(u.hp / 2)\r\nlocal smaller = size == \"Large\" and \"Medium\" or \"Small\"\r\nu.hp, u.max, u.size, u.reactRound = h, h, smaller, c.round or 1\r\nnote = string.format(\" (Split: %s appears; each has %d HP)\", K.newFoe(c, name, u.kind, h, smaller), h)\r\nend\r\nend\r\nif m.limbs and K.isType(dtype, \"Slashing\") and (dmg or 0) > 0 then\r\nlocal s = type(u.slash) == \"table\" and u.slash.by == by and u.slash.round == (c.round or 1) and u.slash or { by = by, round = c.round or 1, n = 0 }\r\ns.n = s.n + dmg\r\nu.slash = s\r\nif s.n >= 15 and not s.cut and u.hp * 2 <= u.max and (tonumber(u.limbsCut) or 0) < m.limbs then\r\ns.cut = true\r\nu.limbsCut = (tonumber(u.limbsCut) or 0) + 1\r\nu.exh = (tonumber(u.exh) or 0) + 1\r\nlocal lm = MONSTERS[\"Troll Limb\"]\r\nnote = note .. string.format(\" (Loathsome Limbs: %s falls off and fights on; the troll has Exhaustion %d)\",\r\nK.newFoe(c, name, \"Troll Limb\", lm and lm.hp or 14, \"Small\"), u.exh)\r\nend\r\nend\r\nreturn note\r\nend\r\n\r\n\r\n\r\n\r\n\r\n\r\nfunction K.hurtFoe(u, raw, dmg, dtype, crit)\r\nlocal m = MONSTERS[u.kind] or {}\r\n\r\nif (dmg or 0) > 0 and K.AR and K.AR.guardOf and K.AR.guardOf(u, K.curPc) then\r\nlocal d0, gn = K.AR.dmgToStim(u, dmg)\r\nif d0 <= 0 then return gn end\r\ndmg = d0\r\nend\r\nlocal cdNote = (dmg or 0) > 0 and K.AR and K.AR.condDamaged and K.AR.condDamaged(u) or \"\"\r\nif cdNote ~= \"\" then return cdNote .. K.hurtFoe(u, raw, dmg, dtype, crit) end\r\nif m.absorb and dtype == m.absorb.t and (raw or 0) > 0 then\r\nlocal was = u.hp\r\nu.hp = math.min(u.max, u.hp + raw)\r\nreturn string.format(\" (%s: +%d HP)\", m.absorb.n, u.hp - was)\r\nend\r\nif (dmg or 0) <= 0 then return \"\" end\r\nfor _, t in ipairs(m.regen and m.regen.stop or {}) do if K.isType(dtype, t) then u.burned = true end end\r\nlocal fullDmg = dmg\r\n\r\nlocal thpNote = \"\"\r\nif (tonumber(u.thp) or 0) > 0 then\r\nlocal a = math.min(u.thp, dmg)\r\nu.thp = u.thp - a\r\nif u.thp <= 0 then u.thp = nil end\r\ndmg = dmg - a\r\nthpNote = string.format(\" (temporary HP -%d)\", a)\r\n\r\nif not u.thp and type(u.poly) == \"table\" then thpNote = thpNote .. \" (\" .. tostring(u.poly.by) .. \" ends: back to \" .. tostring(u.kind) .. \")\"; u.poly = nil end\r\nif dmg <= 0 then return thpNote .. K.wakeFoe(u) end\r\nend\r\nlocal was, note = u.hp, thpNote\r\nu.hp = math.max(0, u.hp - dmg)\r\nif was > 0 and u.hp == 0 and m.fortitude and not K.isType(dtype, \"Radiant\") and not crit then\r\nlocal r, b = K.d(20), (m.saves or {}).Constitution or 0\r\nif r + b >= 5 + fullDmg then\r\nu.hp = 1\r\nnote = string.format(\" (Undead Fortitude: d20 %d%+d vs DC %d, 1 HP)\", r, b, 5 + fullDmg)\r\nend\r\nend\r\nif was > 0 and u.hp == 0 and m.regen and m.regen.zero then u.zeroAt = K.REPLY end\r\nif was > 0 and u.hp == 0 and Feat.cur and K.koMelee then Feat.cur.dropped = Feat.cur.dropped or {}; Feat.cur.dropped[u] = true end\r\n\r\nnote = note .. K.wakeFoe(u)\r\nreturn note\r\nend\r\n\r\n\r\n\r\nfunction K.foeUp(u)\r\nif type(u) ~= \"table\" then return false end\r\nif (tonumber(u.hp) or 0) > 0 then return true end\r\nlocal m = u.side == \"enemy\" and MONSTERS[u.kind or \"\"]\r\nreturn m and m.regen and m.regen.zero and not u.burned and u.zeroAt ~= nil and (K.REPLY or 0) - u.zeroAt <= 2 or false\r\nend\r\n\r\n\r\n\r\nfunction K.foeHeal(f, pools, cur, c, u)\r\nlocal head = \"[HEAL|\" .. table.concat(f, \"|\", 1, 5)\r\nlocal function refuse(why)\r\nK.spendRefused(pools, cur, nil, f[3], f[4])\r\nreturn head .. \"|bad:\" .. why .. \"|-]\", false\r\nend\r\nlocal m = MONSTERS[u.kind] or {}\r\nlocal src = Canon.name(f[2] or \"\")\r\nlocal e, regen = nil, false\r\nif m.regen and m.regen.n == src then e, regen = m.regen, true end\r\nfor _, h in ipairs(m.heals or {}) do if h.n == src then e = h end end\r\n\r\nlocal thpE\r\nif not e then\r\nfor _, x in pairs(c.units or {}) do\r\nlocal mx = x.side == \"enemy\" and MONSTERS[x.kind or \"\"]\r\nfor _, h in ipairs(mx and mx.thps or {}) do if h.n == src then thpE = h end end\r\nend\r\nend\r\nif thpE and u.hp > 0 and tostring(u.kind or \"\"):match(\"^Swarm of\") then\r\nreturn refuse(u.kind .. \" is a Swarm: it can't gain Temporary HP\")\r\nend\r\nif thpE and u.hp > 0 then\r\nlocal bad = {}\r\nlocal p = parseFormula(thpE.d)\r\nlocal given = parseFormula(f[3] or \"\")\r\nif not given or canon(given, false) ~= canon(p, false) then bad[#bad + 1] = \"formula \" .. (f[3] or \"\") .. \"->\" .. canon(p, false) end\r\nlocal amount = spendDice(p, f[4], pools, cur, bad, K.wroteF(f[3], f[4]))\r\nif tonumber(f[5]) ~= amount then bad[#bad + 1] = \"amount \" .. tostring(f[5]) .. \"->\" .. amount end\r\nu.thp = math.max(tonumber(u.thp) or 0, amount)\r\nlocal acNote = \"\"\r\nif thpE.ac then\r\nu.acUp, u.acUpRound, u.acUpKeep, u.acUpWhy = thpE.ac, c.round or 1, true, src .. \", until the end of its giver's next turn\"\r\nacNote = string.format(\" (AC +%d until the end of its giver's next turn)\", thpE.ac)\r\nend\r\nreturn head .. \"|\" .. verdictOf(bad) .. \"|\" .. u.hp .. \"/\" .. u.max .. \" (temporary HP \" .. u.thp .. \")\" .. acNote .. \"]\", #bad == 0\r\nend\r\nif not e then return refuse(\"\" .. u.kind .. \" has no \" .. src .. \" that heals it\") end\r\nlocal bad = {}\r\nif regen then\r\nif u.regenAt == K.REPLY then return refuse(\"once at the start of each of its turns\") end\r\nu.regenAt = K.REPLY\r\nif u.burned then\r\nu.burned = nil\r\nK.spendRefused(pools, cur, nil, f[3], f[4])\r\nreturn head .. \"|bad:no Regeneration on the turn after Acid or Fire damage|\" .. u.hp .. \"/\" .. u.max .. \"]\", false\r\nend\r\nif u.hp <= 0 and (e.one or not K.foeUp(u)) then return refuse(\"\" .. u.kind .. \" is down: no Regeneration\") end\r\nelseif u.hp <= 0 then\r\nreturn refuse(\"\" .. u.kind .. \" is down\")\r\nend\r\nlocal p = parseFormula(e.d)\r\nlocal given = parseFormula(f[3] or \"\")\r\nif not given or canon(given, false) ~= canon(p, false) then bad[#bad + 1] = \"formula \" .. (f[3] or \"\") .. \"->\" .. canon(p, false) end\r\nlocal amount = #p.dice > 0 and spendDice(p, f[4], pools, cur, bad, K.wroteF(f[3], f[4])) or p.mod\r\nif tonumber(f[5]) ~= amount then bad[#bad + 1] = \"amount \" .. tostring(f[5]) .. \"->\" .. amount end\r\nlocal was0 = u.hp\r\nu.hp = math.min(u.max, u.hp + amount)\r\nif u.hp > 0 then u.zeroAt = nil end\r\n\r\nlocal grow = \"\"\r\nif u.hp > was0 and (tonumber(u.exh) or 0) > 0 then u.exh, grow = nil, \" (its limbs grow back)\" end\r\nreturn head .. \"|\" .. verdictOf(bad) .. \"|\" .. u.hp .. \"/\" .. u.max .. grow .. \"]\", #bad == 0\r\nend\r\n\r\n\r\nfunction K.selfText(m, kind)\r\nlocal o = {}\r\nlocal r = m.regen\r\nif r then\r\no[#o + 1] = string.format(\"%s %s at the start of each of its turns%s: [HEAL|%s N|%s|%s|-|%s]%s%s\", r.n, r.d, r.one and \" while it has 1 HP or more\" or \"\",\r\nkind, r.n, r.d, r.d, r.stop and (\", none on the turn after it took \" .. table.concat(r.stop, \" or \") .. \" damage\") or \"\",\r\nr.zero and \"; at 0 HP it is down, not dead, until a turn starts without Regeneration\" or \"\")\r\nend\r\nfor _, h in ipairs(m.heals or {}) do o[#o + 1] = string.format(\"%s regains %s: [HEAL|%s N|%s|%s|dice|amount]\", h.n, h.d, kind, h.n, h.d) end\r\n\r\nfor _, h in ipairs(m.thps or {}) do\r\no[#o + 1] = string.format(\"%s gives it or another one %s Temporary HP%s: [HEAL|target|%s|%s|dice|amount]\", h.n, h.d,\r\nh.ac and string.format(\" and AC +%d until the end of its next turn\", h.ac) or \"\", h.n, h.d)\r\nend\r\nfor _, h in ipairs(m.hurts or {}) do\r\no[#o + 1] = string.format(\"%s: %s %s to itself, [HAZARD|%s N|%s|-|-|-|-|-|%s|%s|%s]\", h.n, h.d, h.t, kind, h.n, h.d,\r\ntonumber(h.d) and \"-\" or \"dice\", tonumber(h.d) and h.d or \"damage\")\r\nend\r\nif m.absorb then o[#o + 1] = m.absorb.n .. \" (\" .. m.absorb.t .. \" heals it; Lua applies it)\" end\r\nif m.fortitude then o[#o + 1] = \"Undead Fortitude (Lua rolls it when damage drops it to 0)\" end\r\nif #o == 0 then return \"\" end\r\nreturn \". Its own Hit Points: \" .. table.concat(o, \"; \")\r\nend\r\n\r\n\r\nfunction K.sfxText(e)\r\nlocal head = e.n .. (e.o and (\" (\" .. e.o .. \")\") or \"\") .. (e.lg and \" (legendary action)\" or \"\")\r\nif not e.s then return string.format(\"%s: no save, %s %s\", head, e.d or \"-\", e.t or \"\") end\r\nreturn string.format(\"%s: %s save DC %d%s%s\", head, e.s:sub(1, 3):upper(), e.dc or 0,\r\ne.d and string.format(\", %s %s, %s on a success\", e.d, e.t or \"\", e.h and \"half\" or \"none\") or \", no damage\",\r\ne.sl and string.format(\"; on a failure a target with %d HP or fewer dies (Lua applies it)\", e.sl) or \"\")\r\nend\r\n\r\n\r\n\r\n\r\nfunction K.swallowed(c, who)\r\nlocal by = type(c) == \"table\" and type(c.swallow) == \"table\" and c.swallow[who]\r\nif not by then return nil end\r\nlocal u = c.units and c.units[by]\r\nif not u or (tonumber(u.hp) or 0) <= 0 then c.swallow[who] = nil; return nil end\r\nreturn by\r\nend\r\nfunction K.unswallow(c, by)\r\nfor who, x in pairs(type(c.swallow) == \"table\" and c.swallow or {}) do if x == by then c.swallow[who] = nil end end\r\nend\r\n\r\n\r\n\r\n\r\n\r\n\r\nfunction K.foeSave(f, pools, cur, c, pc, ctx, r)\r\nlocal bad = {}\r\nlocal head = \"[SAVE|\" .. table.concat(f, \"|\", 1, 9)\r\nlocal function refuse(why)\r\nK.spendRefused(pools, cur, f[3], f[7], f[8])\r\nreturn head .. \"|bad:\" .. why .. \"|-]\", false\r\nend\r\nif r.dead then return refuse(\"\" .. (r.name or \"Player\") .. \" is dead\") end\r\nlocal nosave = trim(f[2] or \"-\") == \"-\"\r\nlocal ab = Canon.name((f[2] or \"\"):gsub(\"%s+[Ss]ave$\", \"\"):gsub(\"%s*내성$\", \"\"))\r\nif not nosave and not MOD[ab] then return refuse(\"an ability, or - for no save\") end\r\nlocal given = (f[7] or \"-\") ~= \"-\" and parseFormula(f[7]) or nil\r\nlocal function same(a, b) return a and b and canon(parseFormula(a), false) == canon(b, false) end\r\n\r\nlocal cands, seen = {}, {}\r\nfor _, name in ipairs(c.order or {}) do\r\nlocal u = c.units[name]\r\nlocal m = u and u.side == \"enemy\" and MONSTERS[u.kind]\r\nif m and m.sfx and not seen[u.kind] then\r\nseen[u.kind] = true\r\nfor _, e in ipairs(m.sfx) do\r\nif (nosave and not e.s) or (not nosave and e.s == ab) then cands[#cands + 1] = { e = e, kind = u.kind } end\r\nend\r\nend\r\nend\r\nlocal dcW = tonumber(f[5])\r\n\r\nlocal who = r.name or \"Player\"\r\nlocal by = K.swallowed(c, who)\r\nlocal byKind = by and c.units[by] and c.units[by].kind\r\nlocal acidHit, kept = false, {}\r\nfor _, x in ipairs(cands) do\r\nif x.e.n == \"Swallow (each turn)\" and x.kind ~= byKind then\r\nif same(x.e.d, given) then acidHit = true end\r\nelse\r\nkept[#kept + 1] = x\r\nend\r\nend\r\ncands = kept\r\nlocal pick\r\nfor _, x in ipairs(cands) do if not pick and (nosave or x.e.dc == dcW) and same(x.e.d, given) then pick = x end end\r\nfor _, x in ipairs(cands) do if not pick and not nosave and x.e.dc == dcW and (x.e.d ~= nil) == (given ~= nil) then pick = x end end\r\nfor _, x in ipairs(cands) do if not pick and not nosave and x.e.dc == dcW then pick = x end end\r\n\r\nif acidHit and not pick then return refuse(who .. \" is not swallowed (regurgitated, or never swallowed): no acid\") end\r\npick = pick or cands[1]\r\nlocal e = pick and pick.e\r\n\r\nlocal ok = false\r\nlocal fx = Cond.fx(r)\r\nlocal covNote = \"\"\r\nif nosave then\r\nfor i = 3, 6 do if trim(f[i] or \"-\") ~= \"-\" then bad[#bad + 1] = \"no save: write - in the save fields\"; break end end\r\nelse\r\nlocal roll, _, natS = takeD20(cur, pools, f[3] or \"\", bad, r, \"save\")\r\nlocal flS = K.d20Floor(r.sheet or SHEET, \"save\", ab)\r\nif flS and natS and natS < flS then roll = roll + flS - natS end\r\nlocal real = bonusFor(ab .. \" save\") - fx.pen\r\n\r\nlocal cov = ab == \"Dexterity\" and K.coverOf(c.units[f[1] or \"\"]) or 0\r\n\r\nlocal apAdd = ((e and e.approach) or K.apWill) and K.AR.saveAdd(r, r, K.apWill) or 0\r\nif cov > 0 and (tonumber(f[4]) == real + cov or (apAdd ~= 0 and tonumber(f[4]) == real + cov + apAdd)) then real, covNote = real + cov, K.coverNote(cov) end\r\nif apAdd ~= 0 then\r\nreal = real + apAdd\r\nif tonumber(f[4]) == real - apAdd then f[4] = string.format(\"%+d\", real); head = \"[SAVE|\" .. table.concat(f, \"|\", 1, 9) end\r\ncovNote = covNote .. string.format(\" (inhibition %+d)\", apAdd)\r\nend\r\n\r\nif tonumber(f[4]) ~= real and tonumber(f[4]) and tonumber(f[4]) == K.oldBonus(r, ab .. \" save\") then\r\nf[4] = string.format(\"%+d\", real)\r\nhead = \"[SAVE|\" .. table.concat(f, \"|\", 1, 9)\r\nend\r\nif tonumber(f[4]) ~= real then bad[#bad + 1] = string.format(\"bonus %s->%+d\", f[4] or \"\", real) end\r\nlocal dc = e and e.dc or dcW\r\nif e and dcW ~= e.dc then bad[#bad + 1] = \"DC \" .. (f[5] or \"\") .. \"->\" .. e.dc end\r\nif not dc or dc < 1 or dc > 30 then bad[#bad + 1] = \"DC 1-30\"; dc = 99 end\r\nok = roll + real >= dc and not fx.autofail[ab]\r\nif f[6] ~= (ok and \"success\" or \"failure\") then bad[#bad + 1] = \"result->\" .. (ok and \"success\" or \"failure\") end\r\nend\r\n\r\nlocal formula\r\nif e then formula = e.d else formula = given and canon(given, false) end\r\nlocal dtype = e and e.t\r\nlocal half = e and e.h\r\nlocal dmg, note = 0, \"\"\r\nlocal preAdj, rxPre\r\nif not formula then\r\nif given then bad[#bad + 1] = \"no damage: write - - 0\"\r\nelseif trim(f[9] or \"0\") ~= \"0\" and trim(f[9] or \"\") ~= \"-\" then bad[#bad + 1] = \"damage \" .. tostring(f[9]) .. \"->0\" end\r\nelseif e and ok and not half and not given then\r\n\r\nif trim(f[9] or \"0\") ~= \"0\" and trim(f[9] or \"\") ~= \"-\" then bad[#bad + 1] = \"damage \" .. tostring(f[9]) .. \"->0\" end\r\nelse\r\nif not same(formula, given) then bad[#bad + 1] = \"formula \" .. (f[7] or \"\") .. \"->\" .. canon(parseFormula(formula), false) end\r\nctx.foeRolls = ctx.foeRolls or {}\r\nlocal key = (pick and pick.kind or \"?\") .. \"|\" .. (e and e.n or formula)\r\nlocal full = ctx.foeRolls[key]\r\n\r\n\r\nlocal q = K.wroteF(f[7], f[8])\r\nif full and not K.sameRoll(full, f[8]) then\r\nlocal trial, tbad = {}, {}\r\nfor k, v in pairs(cur) do trial[k] = v end\r\nK.diceQuiet = true\r\nspendDice(parseFormula(formula), f[8], pools, trial, tbad, q)\r\nK.diceQuiet = nil\r\nif #tbad == 0 then full = nil end\r\nend\r\nif full then\r\nif not K.sameRoll(full, f[8]) then bad[#bad + 1] = \"same roll for each one it catches: \" .. full.dice end\r\nK.logDice(full.vals)\r\nfull = full.sum\r\nelse\r\nlocal p = parseFormula(formula)\r\nlocal before = {}\r\nfor k, v in pairs(cur) do before[k] = v end\r\nlocal sum, vals = spendDice(p, f[8], pools, cur, bad, q)\r\nctx.foeRolls[key] = K.oneRoll(sum, before, cur, pools, q or p, p, f[8])\r\nctx.foeRolls[key].vals = vals\r\nfull = sum\r\nend\r\n\r\nlocal evade = ab == \"Dexterity\" and half and not fx.incap and #Feat.fxOf(r.sheet or SHEET, \"evasion\") > 0\r\nif evade then dmg, note = ok and 0 or math.floor(full / 2), \" (Evasion)\"\r\nelseif not e then\r\n\r\ndmg = ok and ((tonumber(f[9]) == math.floor(full / 2)) and math.floor(full / 2) or 0) or full\r\nelse dmg = ok and (half and math.floor(full / 2) or 0) or full end\r\n\r\n\r\nif ok and dmg > 0 and tonumber(f[9]) == 0 then\r\nfor bn, b in pairs(type(r.buff) == \"table\" and r.buff or {}) do\r\nif type(b) == \"table\" and b.snone and K.buffLive(pc, bn, b) then dmg, note = 0, note .. \" (\" .. bn .. \": none on a success)\"; break end\r\nend\r\nend\r\nlocal n2\r\npreAdj = dmg\r\ndmg, n2 = Feat.adjust(Feat.traits(r), dmg, dtype)\r\nnote = note .. n2\r\n\r\nlocal srcU = \"?\"\r\nif pick then\r\nif c.last and c.units[c.last] and c.units[c.last].kind == pick.kind then srcU = c.last\r\nelse\r\nfor _, nm in ipairs(c.order or {}) do\r\nlocal x = c.units[nm]\r\nif srcU == \"?\" and x and x.side == \"enemy\" and x.kind == pick.kind then srcU = nm end\r\nend\r\nend\r\nend\r\nlocal rx = dmg > 0 and K.resD4Take(r, dtype, srcU, pools, cur, bad, pc)\r\nif rx then\r\nrxPre = dmg\r\ndmg = math.max(0, dmg - rx.n)\r\nnote = note .. string.format(\" (%s: -%d)\", rx.src, rx.n)\r\nend\r\nend\r\n\r\nif not e and formula then\r\nnote = note .. ((nosave and type(r.cond) == \"table\" and r.cond.Poisoned ~= nil) and \" (Poisoned: taken as written)\" or \" (not in COMBAT STATUS: taken as written)\")\r\nend\r\n\r\nif preAdj and tonumber(f[9]) ~= dmg and tonumber(f[9]) and tonumber(f[9]) == K.oldLanded(r, preAdj, dtype) then\r\nf[9] = tostring(dmg)\r\nhead = \"[SAVE|\" .. table.concat(f, \"|\", 1, 9)\r\nend\r\nif rxPre and tonumber(f[9]) == rxPre then f[9] = tostring(dmg); head = \"[SAVE|\" .. table.concat(f, \"|\", 1, 9) end\r\nif tonumber(f[9]) ~= dmg and not (dmg == 0 and trim(f[9] or \"\") == \"-\") then bad[#bad + 1] = \"damage \" .. tostring(f[9]) .. \"->\" .. dmg end\r\n\r\nif e and e.sl and not ok and (tonumber(r.hp) or 0) > 0 and r.hp <= e.sl then\r\nr.hp, r.dead = 0, true\r\nnote = covNote .. note .. string.format(\" (%s: %d HP or fewer, dies)\", e.n, e.sl)\r\nelse\r\nnote = covNote .. note .. hurtPC(r, dmg, false)\r\nend\r\n\r\n\r\nif e and e.n == \"Swallow\" and not nosave and not ok and not r.dead then\r\nlocal by = type(c.hitBy) == \"table\" and c.hitBy[who] or c.last\r\nlocal bu = by and c.units[by]\r\nif not (bu and bu.side == \"enemy\" and bu.kind == pick.kind and (tonumber(bu.hp) or 0) > 0) then\r\nby = nil\r\nfor _, nm in ipairs(c.order or {}) do\r\nlocal x = c.units[nm]\r\nif not by and x and x.side == \"enemy\" and x.kind == pick.kind and (tonumber(x.hp) or 0) > 0 then by = nm end\r\nend\r\nend\r\nif by then\r\nc.swallow = type(c.swallow) == \"table\" and c.swallow or {}\r\nc.swallow[who] = by\r\nnote = note .. \" (swallowed by \" .. by .. \")\"\r\nend\r\nend\r\nreturn head .. \"|\" .. verdictOf(bad) .. \"|\" .. (r.dead and \"dead\" or (r.hp .. \"/\" .. r.max)) .. note .. \"]\", #bad == 0\r\nend\r\n\r\n\r\n\r\n\r\n\r\nfunction K.isEvo(n)\r\nlocal sp = SPELLS[n or \"\"]\r\nreturn sp ~= nil and ((K.SCHOOL_EN and K.SCHOOL_EN[sp.school or \"\"]) or sp.school) == \"Evocation\"\r\nend\r\nfunction Spell.bookCounts(sh)\r\n\r\nlocal bc = K.bookClass(sh)\r\nif not bc then return 0, 0, 0, 0 end\r\nlocal b = CLASSES[bc].book or { start = 6, per_level = 2 }\r\nlocal lv = K.cl(sh, bc)\r\nlocal base = (tonumber(b.start) or 6) + (tonumber(b.per_level) or 2) * (lv - 1)\r\nlocal sav = 0\r\nif K.subHas(sh, \"Evocation Savant\") then\r\nsav = 2\r\nfor _, at in ipairs({ 5, 7, 9, 11, 13, 15, 17 }) do if lv >= at then sav = sav + 1 end end\r\nend\r\nlocal paid = type(sh.bookPaid) == \"table\" and sh.bookPaid or {}\r\nlocal evo, other = 0, 0\r\nfor _, n in ipairs(type(sh.book) == \"table\" and sh.book or {}) do\r\nif not paid[n] then\r\nif sav > 0 and K.isEvo(n) then evo = evo + 1 else other = other + 1 end\r\nend\r\nend\r\nreturn base, sav, evo, other\r\nend\r\n\r\nfunction Spell.bookRoom(sh)\r\nlocal base, sav, evo, other = Spell.bookCounts(sh)\r\nlocal all = math.max(0, base + sav - other - evo)\r\nreturn all, math.max(0, math.min(base - other, all))\r\nend\r\n\r\n\r\nfunction Spell.bookAdd(f, c, sh, pc, clock)\r\nlocal head = \"[SPELLBOOK|\" .. (f[1] or \"\")\r\nlocal bc = K.bookClass(sh)\r\nif not bc then return head .. \"|bad:only a Wizard keeps a spellbook|-]\", false end\r\nif c.active then return head .. \"|bad:not during a fight|-]\", false end\r\nlocal row = K.rowOf(sh, bc)\r\nlocal maxLv = K.rowMaxLv(row)\r\nsh.book = type(sh.book) == \"table\" and sh.book or {}\r\nlocal bad, added, paid = {}, {}, 0\r\nfor _, raw in ipairs(splitNames(f[1])) do\r\nlocal n = Canon.name((raw:gsub(\"^%+%s*\", \"\")))\r\nlocal sp = SPELLS[n]\r\nlocal have = false\r\nfor _, b in ipairs(sh.book) do if b == n then have = true end end\r\nlocal mine = false\r\nfor _, k in ipairs(sp and sp.classes or {}) do if k == bc then mine = true end end\r\nif not sp then bad[#bad + 1] = \"unknown \" .. n\r\nelseif not have and K.spellOff(n) then bad[#bad + 1] = K.spellOff(n)\r\nelseif not mine then bad[#bad + 1] = n .. \" not a \" .. bc .. \" spell\"\r\nelseif sp.level < 1 or sp.level > maxLv then bad[#bad + 1] = n .. \" level \" .. sp.level .. \" (1-\" .. maxLv .. \")\"\r\nelseif have then bad[#bad + 1] = n .. \" already in the book\"\r\nelseif select(K.isEvo(n) and 1 or 2, Spell.bookRoom(sh)) > 0 then\r\nsh.book[#sh.book + 1] = n\r\nadded[#added + 1] = n\r\nelse\r\nlocal cost = 5000 * sp.level\r\n\r\n\r\nlocal sname = \"Spell Scroll (\" .. n .. \")\"\r\nlocal scroll = (tonumber((pc.items or {})[sname]) or 0) > 0\r\nif pc.cp < cost then\r\nbad[#bad + 1] = \"copying \" .. n .. \" costs \" .. moneyText(cost)\r\nelse\r\npc.cp = pc.cp - cost\r\nclock.min = clock.min + 120 * sp.level\r\npaid = paid + cost\r\nlocal copied = true\r\nif scroll then\r\npc.items[sname] = pc.items[sname] - 1\r\nif pc.items[sname] <= 0 then\r\npc.items[sname] = nil\r\nif type(pc.loot) == \"table\" then pc.loot[sname] = nil end\r\nend\r\nlocal d, b = K.d(20), bonusFor(\"Arcana\")\r\nif d + b < 10 + sp.level then\r\ncopied = false\r\nbad[#bad + 1] = string.format(\"copying %s from its scroll: Arcana d20 %d%+d vs DC %d failed, the scroll is gone\", n, d, b, 10 + sp.level)\r\nend\r\nend\r\nif copied then\r\nsh.book[#sh.book + 1] = n\r\nadded[#added + 1] = n\r\nsh.bookPaid = type(sh.bookPaid) == \"table\" and sh.bookPaid or {}\r\nsh.bookPaid[n] = true\r\nend\r\nend\r\nend\r\nend\r\nlocal note = string.format(\"book %d%s\", #sh.book, paid > 0 and (\", copied for \" .. moneyText(paid)) or \"\")\r\nreturn head .. \"|\" .. verdictOf(bad) .. \"|\" .. note .. \"]\", #bad == 0\r\nend\r\n\r\n\r\n\r\nfunction K.pactLevel()\r\nif K.LITE or not (SHEET and (CLASSES[K.castCl(SHEET) or \"\"] or {}).pact) or K.pactApart(SHEET) then return nil end\r\nfor l = 9, 1, -1 do if PC.res[\"Spell Slot \" .. l] then return l end end\r\nreturn nil\r\nend\r\n\r\n\r\nfunction Spell.text(pc, fight)\r\nlocal names = Spell.names()\r\nif #names == 0 then return nil end\r\nlocal lines = {}\r\nlocal extras = Feat.extras(SHEET)\r\nlocal multiCast = #K.casters(SHEET) > 1\r\nlocal life = K.subHas(SHEET, \"Disciple of Life\")\r\n\r\nlocal anyRitual = false\r\nlocal function ritualNote(name)\r\nlocal sp = SPELLS[name]\r\nif fight or not (sp and sp.ritual and sp.level > 0) then return \"\" end\r\nanyRitual = true\r\nreturn \"; also as a Ritual: [CAST|\" .. name .. \"|ritual]\"\r\nend\r\nlocal anyCost = false\r\nlocal function costNote(name)\r\nlocal c = SPELLS[name] and SPELLS[name].cost\r\nif not c then return \"\" end\r\nanyCost = true\r\nreturn \"; needs \" .. c\r\nend\r\nlocal function line(name)\r\nlocal sp = SPELLS[name]\r\nlocal m = sp and sp.m\r\nlocal st = Spell.stats(name)\r\nif not st then return end\r\nif not m then\r\n\r\nlocal x = extras[name]\r\nif x then lines[#lines + 1] = string.format(\"- %s%s (level %d): effect narrated%s%s%s\", name, NAMES_KO[name] and (\" = \" .. NAMES_KO[name] .. \" in prose\") or \"\",\r\nsp.level, x.free and \", once per Long Rest without a slot (its CAST spends that first, never a USE tag)\" or \"\", ritualNote(name), costNote(name)) end\r\nreturn\r\nend\r\nlocal x = extras[name]\r\nlocal lv = (x and x.only) and (\"species ability, uses: \" .. x.free) or sp.level == 0 and \"cantrip\" or (\"level \" .. sp.level)\r\nlocal scls = multiCast and K.spellClassOf(SHEET, name)\r\nif scls then lv = lv .. \", \" .. scls end\r\n\r\nlocal pact = K.pactLevel()\r\nlocal at = (pact and not x and sp.level >= 1 and sp.level < pact) and pact or sp.level\r\nif at ~= sp.level then lv = lv .. \", cast at level \" .. at .. \" with Pact Magic: [CAST|\" .. name .. \"|\" .. at .. \"]\" end\r\nif x and x.item then\r\nlocal l = type(Cond.cur) == \"table\" and type(Cond.cur.loot) == \"table\" and Cond.cur.loot[x.item]\r\nlocal leftN = l and type(l.left) == \"table\" and l.left[name] or 0\r\nlv = lv .. string.format(\", from %s: %d/%d per Long Rest, [CAST|%s|free]\", x.item, leftN, l and LOOT.SPELL_USES[l.grade] or 1, name)\r\nend\r\nlocal up = \"\"\r\nif at == sp.level then\r\nif m.upcast and m.upcast.dice then up = \", +\" .. m.upcast.dice .. \" per slot level above \" .. sp.level end\r\nif m.upcast and m.upcast.darts then up = \", +\" .. m.upcast.darts .. \" dart per slot level above \" .. sp.level end\r\nif m.upcast and m.upcast.rays then up = \", +\" .. m.upcast.rays .. \" ray per slot level above \" .. sp.level end\r\nend\r\nlocal more = at - sp.level\r\nlocal what\r\nif K.SUMMON[name] then\r\nwhat = K.summonWhat(name)\r\nelseif m.kind == \"attack\" and m.damage and m.attack ~= \"weapon\" then\r\nlocal rays = m.rays and (m.rays + ((m.upcast or {}).rays or 0) * more)\r\nlocal rm, rsrc = 0, nil\r\nif m.rays or m.beams then rm, rsrc = Feat.spellMod(name, sp, m, m.damage, true) end\r\nwhat = string.format(\"spell attack %+d, %s %s%s%s\", st.atk, Spell.formula(name, m.damage, at, m.type), m.type or \"\",\r\n(rays and (\", \" .. rays .. \" rays, one attack each\") or \"\")\r\n.. ((tonumber(rm) or 0) > 0 and string.format(\"; %s +%d on one %s's damage, once a casting (Lua lists it as may add)\", rsrc or \"bonus\", rm, m.beams and \"beam\" or \"ray\") or \"\"),\r\nm.extra_save and (string.format(\"; then %s save, %s %s\", m.extra_save.save, Spell.formula(name, m.extra_save.damage, at, m.extra_save.type), m.extra_save.type)) or \"\")\r\nelseif m.kind == \"attack\" and type(m.stim) == \"table\" and m.attack ~= \"weapon\" then\r\n\r\nwhat = string.format(\"spell attack %+d, %s %s stimulation (arousal, not HP: an ATTACK tag with the amount in its damage field)\", st.atk,\r\nSpell.formula(name, K.spellTerms(m.stim.dice or \"1d6\", name), at, \"stim\") or \"?\", m.stim.type or \"Force\")\r\nelseif m.kind == \"save\" then\r\nwhat = string.format(\"%s save DC %d%s\", m.save, st.dc, m.damage and string.format(\", %s %s, %s on a success\", Spell.formula(name, m.damage, at, m.type),\r\n(m.prism and \"of its ray's type\") or m.type or Feat.spellType(name) or \"\", m.on_save == \"half\" and \"half\" or \"none\")\r\nor (\", no damage\" .. (type(m.fail) == \"string\" and (\"; effect: \" .. K.spellTerms(K.failText(m), name)) or \"\")))\r\nelseif m.kind == \"auto\" and m.say then\r\nwhat = K.spellTerms(m.say, name)\r\nelseif m.kind == \"auto\" then\r\n\r\nlocal nd = (m.darts or 1) + ((m.upcast or {}).darts or 0) * more\r\nlocal dm, dsrc = Feat.spellMod(name, sp, m, m.damage, true)\r\nwhat = string.format(\"%s of %s %s, no roll: DAMAGE\", nd == 1 and \"1 hit\" or (nd .. \" darts\"), K.spellTerms(m.damage, name), m.type or \"\")\r\n.. ((tonumber(dm) or 0) > 0 and string.format(\"; %s +%d on one damage roll: the casting's first DAMAGE on a foe adds it to its formula (3 darts: 3d4+3+%d)\", dsrc or \"bonus\", dm, dm) or \"\")\r\n.. (m.slay and string.format(\"; a target with %d HP or fewer dies (Lua applies it)\", m.slay) or \"\")\r\nelseif m.kind == \"heal\" and (m.heal_all or m.heal_share) then\r\nwhat = m.heal_all and \"heals all the HP the target is missing: [HEAL|Target|\" .. name .. \"|N|-|N] with N = that\"\r\nor string.format(\"heals %d HP in all, divided: one [HEAL|Target|%s|N|-|N] each with its share\", m.heal_share, name)\r\nelseif m.hp_bonus or m.temp_hp or m.temp_share then\r\nwhat = K.hpBuffWhat(name, m, sp.level, \"Player\")\r\nelseif m.rider then\r\n\r\n\r\n\r\nwhat = (m.effect or (\"+\" .. m.rider .. \" \" .. (m.rider_type or \"\")))\r\n.. (m.rider_each and \"; add its dice to each such attack's formula\" or \"; add its dice to that hit's formula\")\r\n.. \" (once cast, Lua lists it with the attacks as \\\"may add\\\"); no BUFF tag\"\r\nelseif m.kind == \"buff\" and m.cast ~= \"reaction\" then\r\nwhat = K.buffWhat(name, m, sp.level)\r\nelseif m.kind == \"buff\" and m.ac_bonus then\r\n\r\nwhat = \"a Reaction when hit: +\" .. m.ac_bonus .. \" AC until the start of the caster's next turn, against that attack too;\"\r\n.. \" write its CAST before that ATTACK (Lua counts the AC)\"\r\nelseif m.kind == \"heal\" then\r\nlocal hf = Spell.formula(name, m.heal, at)\r\nif life and sp.level >= 1 then\r\nhf = canon(parseFormula(hf .. \"+\" .. (2 + sp.level)), false) .. \" with Disciple of Life (a higher slot: its dice and 1 more per level)\"\r\nend\r\nwhat = \"heals \" .. hf\r\nelseif m.raise then\r\nwhat = K.raiseWhat(name, m.raise)\r\nelseif name == \"Gentle Repose\" then\r\nwhat = \"on a body: right after the CAST [BUFF|Name|Gentle Repose]; its 10 days do not count toward a spell that raises the dead (Lua keeps it)\"\r\nelseif type(m.say) == \"string\" and m.say ~= \"\" then\r\n\r\n\r\nwhat = K.spellTerms(m.say, name) .. \" (narrated)\"\r\nelse\r\nwhat = \"effect narrated\"\r\nend\r\nif type(m.type) == \"string\" and m.type:find(\"^choice\") then\r\nwhat = what .. \"; its type: Lua takes the listed one each target fares worst against and names it in the box; the story uses that one\"\r\nend\r\nif m.prism then\r\nwhat = what .. \"; each creature's SAVE as for one ray (the damage rolled once for all): Lua rolls each one's ray with its own d8\"\r\n.. \" (1-5 a damage type, 6 Indigo Restrained, 7 Violet Blinded, 8 two rays) and sets the damage and the condition\"\r\nend\r\n\r\nlocal ffx = K.foeFxOf(name)\r\nif ffx then\r\nwhat = what .. \"; \" .. (m.kind ~= \"save\" and type(m.extra_save) == \"table\" and (m.extra_save.save .. \" SAVE for an unwilling creature (no BUFF on it); \") or \"\")\r\n.. \"a creature that fails: Lua keeps \" .. K.foeFxText(ffx) .. \" on it while the Concentration lasts (COMBAT STATUS says how to write it)\"\r\nend\r\n\r\nlocal fcK = K.FOE_COND[name] or (type(m.foe_cond) == \"table\" and m.foe_cond.name and m.foe_cond)\r\nif type(fcK) == \"table\" and fcK.keep and fcK.third then\r\nwhat = what .. \"; held its full duration (\" .. (sp.mins or 1) * 10 .. \" rounds, or its time on the clock), \" .. fcK.third .. \" stays for good (Lua keeps it until a COND takes it off)\"\r\nend\r\nif m.form_beast then\r\nwhat = what .. \"; a creature that fails, or a willing one of Player's side: right after it [BUFF|Target|\" .. name .. \"|Beast] (a Beast with a stat block,\"\r\n.. \" CR up to the target's CR or level): Lua swaps its stat block and gives Temporary HP equal to the Beast's HP; it ends with the Concentration or when they are gone\"\r\nend\r\nif m.rider and m.kind == \"save\" then\r\nwhat = what .. string.format(\"; its +%s %s on the caster's hits: Lua lists it with the caster's attacks as \\\"may add\\\"\", m.rider, m.rider_type or \"\")\r\nend\r\n\r\nif type(m.puts) == \"table\" and not m.concentration and not K.FOE_COND[name] and not tostring(m.say or \"\"):find(\"[COND|\", 1, true) then\r\nwhat = what .. \"; on a creature's failure [COND|Target|+\" .. table.concat(m.puts, \"/\") .. \"|-|\" .. name .. \"] right after (Lua keeps it until [COND|Target|-Name])\"\r\nend\r\n\r\nif type(m.save2) == \"table\" and m.save2.save then\r\nwhat = what .. string.format(\"; later a %s save (a SAVE with that ability)%s\", tostring(m.save2.save),\r\nm.save2.damage and string.format(\", %s %s\", Spell.formula(name, m.save2.damage, sp.level, m.save2.type) or m.save2.damage, m.save2.type or \"\") or \"\")\r\nend\r\n\r\nif x and x.src == \"feature\" then\r\nwhat = what .. string.format(\"; %s, no slot: [CAST|%s|free] spends %s (cast at level %d)\", x.atwill and \"at will\" or \"a feature's casting\", name, x.free or \"-\",\r\nK.freeLevel(x.fx, sp))\r\nelseif x and x.free and not x.only then what = what .. \"; once per Long Rest without a slot: its CAST spends that first, never a USE tag\" end\r\n\r\nlines[#lines + 1] = string.format(\"- %s%s (%s): %s%s%s%s%s%s\", name, NAMES_KO[name] and (\" = \" .. NAMES_KO[name] .. \" in prose\") or \"\",\r\nlv, what, up, (m.concentration and \", Concentration\" or \"\") .. K.AR.apNote(m), m.warn and (\"; \" .. K.spellTerms(m.warn, name)) or \"\", ritualNote(name), costNote(name))\r\nend\r\nfor _, n in ipairs(names) do line(n) end\r\n\r\nif K.bookClass(SHEET) and not fight then\r\nlocal have = {}\r\nfor _, n in ipairs(names) do have[n] = true end\r\nfor _, n in ipairs(type(SHEET.book) == \"table\" and SHEET.book or {}) do\r\nlocal sp = SPELLS[n]\r\nif sp and sp.ritual and not have[n] then\r\nanyRitual = true\r\nlines[#lines + 1] = string.format(\"- %s%s (level %d, ritual only: [CAST|%s|ritual]): effect narrated\", n,\r\nNAMES_KO[n] and (\" = \" .. NAMES_KO[n] .. \" in prose\") or \"\", sp.level, n)\r\nend\r\nend\r\nend\r\nif #lines == 0 then return nil end\r\ntable.insert(lines, 1, \"Spells Player can cast (numbers by Lua):\")\r\nlocal conc = type(pc.conc) == \"table\" and pc.conc.name\r\nlines[#lines + 1] = \"To cast, write [CAST|Spell|slot level] first ([CAST|Fire Bolt|0] for a cantrip); Lua spends the slot, so never write USE for a spell slot.\"\r\n.. K.slotsRule(pc)\r\n\r\nlocal pl = K.pactSlotLevel()\r\nif pl then\r\nlines[#lines] = lines[#lines] .. string.format(\" Pact Magic slots (level %d, back on a Short Rest) and the other slots both cast any of these spells:\"\r\n.. \" a spell cast at level %d takes a Pact Magic slot first, and a lower level with no slot of its own left takes one too (at level %d).\", pl, pl, pl)\r\nend\r\nif anyCost then lines[#lines + 1] = K.COST_RULE end\r\nif not fight then\r\n\r\nlines[#lines] = lines[#lines] .. \" A healing spell is then HEAL with the spell's name. Lua ends Concentration that damage breaks;\"\r\n.. \" write [CONC|end] only when Player drops it on purpose, [CONC|end|Name] when a companion does.\"\r\n.. (conc and (\" Player is concentrating on \" .. conc .. \".\") or \"\")\r\n.. (anyRitual and (\" A Ritual uses no slot and takes 10 minutes longer than its casting time (Lua moves the clock: no TIME for it);\"\r\n.. \" never in a fight, never at a higher level.\") or \"\")\r\n\r\n\r\nlocal cviews = K.casterViews(SHEET)\r\nif #cviews > 1 then\r\n\r\nlocal o = {}\r\nfor _, v in ipairs(cviews) do\r\nif not K.noSpellsYet(v, v.class, v.level) then\r\no[#o + 1] = v.class .. \" \" .. (Spell.win(pc, SHEET, v.class) and \"open now, until a fight starts\" or (\"closed, opens again \" .. Spell.opensAgain(v)))\r\nend\r\nend\r\nif #o > 0 then\r\nlines[#lines + 1] = \"Swapping prepared spells (a SPELLS tag naming the class, or the taps in the status card's spell block; Lua refuses one that takes a spell out\"\r\n.. \" while closed, and if the user asks, tell them when it opens): \" .. table.concat(o, \"; \") .. \". Adding one up to the number is open.\"\r\nend\r\nelseif cviews[1] and K.noSpellsYet(cviews[1], cviews[1].class, cviews[1].level) then\r\n\r\nelse\r\nlines[#lines + 1] = pc.prep and \"Swapping prepared spells is open now, until a fight starts: a SPELLS tag, or the taps in the status card's spell block.\"\r\nor (\"Swapping prepared spells is closed now: Lua refuses a SPELLS tag that takes one out. It opens again \" .. Spell.opensAgain(SHEET)\r\n.. \"; if the user asks, tell them that. Adding one up to the number is open.\")\r\nend\r\nreturn table.concat(lines, \"\\n\")\r\nend\r\nlines[#lines] = lines[#lines]\r\n.. \" Then its effect: a spell attack is an ATTACK tag with the formula above (a higher slot adds its dice);\"\r\n.. \" a creature's save is [SAVE|Target|Ability|d20|+its save bonus|DC|success/failure|formula|dice|damage] (save bonuses in COMBAT STATUS; for an area,\"\r\n.. \" roll the damage once and write the same dice for every target; a target that takes none, as on a success where it says none: - - 0, no dice taken);\"\r\n.. \" Magic Missile is [DAMAGE|Target|NdX+N|dice|damage] for N darts; a healing spell is HEAL with the spell's name.\"\r\n.. \" A Concentration spell ends the one before. When a concentrating caster takes damage, Lua rolls the Constitution save itself and\"\r\n.. \" on a failure ends the spell once this reply is over (a CONCSAVE line it adds); write [CONC|end] only when Player drops it on purpose,\"\r\n.. \" [CONC|end|Name] when a companion does.\"\r\n.. (conc and (\" Player is concentrating on \" .. conc .. \".\") or \"\")\r\n.. K.concGoneText(pc, \"Player\")\r\nreturn table.concat(lines, \"\\n\")\r\nend\r\n\r\nlocal function verifyCheck(f, pools, cur, lock)\r\n\r\nlocal bad = {}\r\n\r\nlocal tool, toolSk\r\nif not (SKILL[f[1] or \"\"] or MOD[f[1] or \"\"] or (f[1] or \"\"):match(\" save$\")) then tool, toolSk = K.toolOf(f[1]) end\r\nif tool then\r\nf[1] = tool .. (toolSk and (\" (\" .. toolSk .. \")\") or \"\")\r\n\r\nlocal pk = SHEET and (type(SHEET.picks) == \"table\" and SHEET.picks or nil)\r\nif SHEET and K.cl(SHEET, \"Monk\") > 0 and not (pk and pk.monkTool) and (K.TOOLS[tool].artisan or tool == \"Musical Instrument\") then\r\nSHEET.picks = pk or {}\r\nSHEET.picks.monkTool = tool\r\nend\r\nend\r\nlocal kind = tool or f[1]\r\nlocal roll, _, nat = takeD20(cur, pools, f[2], bad, Cond.cur, (f[1] or \"\"):match(\" save$\") and \"save\" or \"check\")\r\n\r\n\r\nif (SKILL[f[1] or \"\"] and SKILL_PROF[f[1]]) or (tool and K.toolProfs(SHEET)[tool]) then\r\nfor _, e in ipairs(Feat.fxOf(SHEET, \"d20_floor\")) do\r\nif (e.on == nil or e.on == \"proficient_check\") and nat < e.value then roll, nat = roll + e.value - nat, e.value end\r\nend\r\nend\r\ndo\r\nlocal f1 = f[1] or \"\"\r\nlocal isSave = f1:match(\" save$\") ~= nil\r\nlocal ab = isSave and f1:gsub(\" save$\", \"\") or (SKILL[f1] and type(SKILL[f1]) == \"string\" and SKILL[f1]) or (MOD[f1] and f1) or nil\r\nlocal fl = K.d20Floor(SHEET, isSave and \"save\" or \"check\", ab)\r\nif fl and nat < fl then roll, nat = roll + fl - nat, fl end\r\nend\r\nlocal bonus, dc = tonumber(f[3]), tonumber(f[4])\r\nlocal fx = Cond.fx(Cond.cur)\r\nlocal real = bonusFor(kind)\r\nif real then real = real - fx.pen end\r\n\r\n\r\nif real and K.apWill and (f[1] or \"\"):match(\"^%a+ save$\") then\r\nlocal add = K.AR.saveAdd(Cond.cur, Cond.cur, K.apWill)\r\nif add ~= 0 then\r\nreal = real + add\r\nif bonus == real - add then bonus = real; f[3] = string.format(\"%+d\", real) end\r\nend\r\nend\r\nif real == nil then\r\nbad[#bad + 1] = \"unknown skill\"; real = bonus or 0\r\nelseif bonus ~= real then\r\n\r\n\r\nlocal new = K.partySkillNew(f[1])\r\nif (new > 0 and bonus == real - new) or (bonus and bonus == K.oldBonus(Cond.cur, f[1])) then f[3] = string.format(\"%+d\", real)\r\nelse bad[#bad + 1] = string.format(\"bonus %+d->%+d\", bonus or 0, real) end\r\nend\r\n\r\n\r\nif not dc or dc < 1 or dc > 30 then bad[#bad + 1] = \"DC 1-30\" end\r\n\r\nlocal lockedNow = false\r\nif lock and not lock.used and lock.kind == f[1] then\r\nlock.used = true\r\nlockedNow = true\r\nif dc ~= lock.dc then\r\nbad[#bad + 1] = string.format(\"DC %s->%d (the option the user picked)\", tostring(f[4]), lock.dc)\r\ndc = lock.dc\r\nend\r\nend\r\n\r\nlocal floor = K.dcFloor()\r\nif floor and dc and dc < floor and not lockedNow and not (K.curC and K.curC.active) and not (f[1] or \"\"):match(\" save$\") then\r\nbad[#bad + 1] = string.format(\"DC %d->%d (the user's check difficulty)\", dc, floor)\r\ndc = floor\r\nend\r\nlocal total = roll + real\r\nlocal ab = f[1]:match(\"^(%a+) save$\")\r\n\r\nfor _, e in ipairs(Feat.fxOf(SHEET, \"total_floor\")) do\r\nif (ab or SKILL[f[1]] or f[1]) == e.ability and total < (SCORE[e.ability] or 0) then total = SCORE[e.ability] end\r\nend\r\n\r\n\r\nlocal gnote = \"\"\r\nlocal d20f = tostring(f[2] or \"\"):lower()\r\nif not ab and not d20f:find(\"guidance\", 1, true) and not d20f:find(\"안내\", 1, true) and K.buffBy(\"Guidance\", nil, Cond.cur) then\r\nlocal g = K.d(4)\r\ntotal = total + g\r\ngnote = string.format(\" (안내 +%d)\", g)\r\nend\r\n\r\n\r\nif SKILL[f[1] or \"\"] and not SKILL_PROF[f[1]] then\r\nfor _, e in ipairs(SHEET and Feat.fxOf(SHEET, \"unskilled_pb\") or {}) do\r\nlocal d = K.d(tonumber(e.die) or 6)\r\nif d >= (tonumber(e.need) or tonumber(e.die) or 6) then total = total + PROF; gnote = gnote .. string.format(\" (%s d%d %d: +%d)\", tostring(e.src), tonumber(e.die) or 6, d, PROF)\r\nelse gnote = gnote .. string.format(\" (%s d%d %d)\", tostring(e.src), tonumber(e.die) or 6, d) end\r\nend\r\nend\r\nlocal should = (dc and total >= dc) and \"success\" or \"failure\"\r\nif ab and fx.autofail[ab] then should = \"failure\" end\r\n\r\n\r\nfor _, e in ipairs(SHEET and Feat.fxOf(SHEET, \"check_fail\") or {}) do\r\nfor _, sk in ipairs(type(e.skills) == \"table\" and e.skills or {}) do\r\nif sk == f[1] or sk == kind then\r\nif not e.story then should = \"failure\"; gnote = gnote .. \" (\" .. tostring(e.src) .. \": it fails by itself)\"\r\nelseif f[5] == \"failure\" then should = \"failure\"; gnote = gnote .. \" (\" .. tostring(e.src) .. \": the story's failure)\" end\r\nend\r\nend\r\nend\r\nif f[5] == \"?\" then f[5] = should elseif f[5] ~= should then bad[#bad + 1] = \"result->\" .. should end\r\nreturn string.format(\"[CHECK|%s|%s|%s|%s|%s|%s|%d%s]\", f[1], f[2], f[3], f[4], f[5], verdictOf(bad), total, gnote), #bad == 0\r\nend\r\n\r\n\r\n\r\n\r\n\r\nK.BIND_HOLD = { Restrained = true, Grappled = true, Incapacitated = true, Unconscious = true, Paralyzed = true, Stunned = true, Petrified = true }\r\nfunction K.bindOf(t, name)\r\nif type(t) ~= \"table\" or type(t.cond) ~= \"table\" or not t.cond[name] then return nil end\r\nif type(t.cond[name]) == \"table\" and type(t.cond[name].bind) == \"table\" then return t.cond[name].bind end\r\nreturn type(t.condBind) == \"table\" and type(t.condBind[name]) == \"table\" and t.condBind[name] or nil\r\nend\r\n\r\nfunction K.bindCastBlock(r, sp)\r\nlocal cmp = type(sp) == \"table\" and sp.cmp\r\nif type(cmp) ~= \"string\" or not (K.AR and K.AR.on()) then return nil end\r\n\r\nlocal bound = {}\r\nif SHEET and #Feat.fxOf(SHEET, \"bind_cast\") > 0 then\r\nfor n in pairs(type(r.cond) == \"table\" and r.cond or {}) do if K.bindOf(r, n) then for x in pairs(K.condEff(n)) do bound[x] = true end end end\r\nend\r\nfor n, row in pairs(K.AR.condsOf(r)) do\r\nif not bound[n] then\r\nif row.no_verbal and cmp:find(\"V\", 1, true) then return n .. \": it can't speak (a Verbal component)\" end\r\nif row.no_somatic and cmp:find(\"S\", 1, true) then return n .. \": its hands can't make the Somatic component\" end\r\nend\r\nend\r\nreturn nil\r\nend\r\n\r\nfunction K.bindHeld(t, c, pc)\r\nif (tonumber(t.hp) or 1) <= 0 then return true end\r\nlocal names = {}\r\nif t == pc or t.sheet then\r\nif Cond.fx(t).incap then return true end\r\nnames = Cond.active(t)\r\nelse\r\nlocal fx = K.foeCondFx(t, pc)\r\nif fx.incap then return true end\r\nnames = fx.list\r\nend\r\nfor _, n in ipairs(names) do for x in pairs(K.condEff(n)) do if K.BIND_HOLD[x] then return true end end end\r\nreturn false\r\nend\r\n\r\n\r\nfunction K.bindDCs(srcName, binder, pc)\r\nlocal src, b = srcName, K.PACK.bonds and K.PACK.bonds[srcName]\r\nif not b then\r\nfor n, row in pairs(K.PACK.bonds or {}) do if NAMES_KO[n] == srcName or n:lower() == srcName:lower() then src, b = n, row end end\r\nend\r\nlocal esc, brk = 20, 20\r\nlocal br = Ally.rec(pc, binder)\r\nif b then esc, brk = tonumber(b.escape) or 20, tonumber(b[\"break\"]) or 20\r\nelse\r\nlocal sp = Canon.name(srcName)\r\nif SPELLS[sp] then\r\nsrc = sp\r\nif br then\r\nlocal dc = Ally.run(pc, br ~= pc and br or nil, function() local st = Spell.stats(sp); return st and st.dc end)\r\nif tonumber(dc) then esc, brk = dc, dc end\r\nend\r\nend\r\nend\r\nlocal dis\r\nif br then\r\nlocal add\r\nadd, dis = Ally.run(pc, br ~= pc and br or nil, function()\r\nlocal n, d = 0, nil\r\nfor _, e in ipairs(Feat.fxOf(SHEET, \"bind_dc\")) do n = n + K.fxNum(e.add or 0, SHEET, K.charLevel(SHEET)) end\r\nfor _, e in ipairs(Feat.fxOf(SHEET, \"bind_escape_dis\")) do d = d or e.src or \"bind_escape_dis\" end\r\nreturn n, d\r\nend)\r\nesc, brk = esc + (add or 0), brk + (add or 0)\r\nend\r\nreturn esc, brk, src, dis\r\nend\r\n\r\nfunction K.bindHolding(c, pc, src, binder, but)\r\nlocal o, seen = {}, {}\r\nlocal function look(nm, t)\r\nif nm == but or seen[t] or type(t) ~= \"table\" then return end\r\nseen[t] = true\r\nfor n in pairs(K.AR.condsOf(t)) do\r\nlocal b = K.bindOf(t, n)\r\nif b and b.src == src and (b.by or \"\") == binder then o[#o + 1] = nm; break end\r\nend\r\nend\r\nif type(c) == \"table\" and c.active then for nm, u in pairs(c.units or {}) do look(nm, u) end end\r\nif type(pc.scene) == \"table\" then for nm, u in pairs(pc.scene.units or {}) do look(nm, u) end end\r\nlook(\"Player\", pc)\r\nfor _, a in ipairs(Ally.list(pc)) do look(a.name, a) end\r\ntable.sort(o)\r\nreturn o\r\nend\r\n\r\n\r\nfunction K.holdsEnd(c, pc, src, by)\r\nlocal sp = SPELLS[src or \"\"]\r\nif not (sp and type(sp.m) == \"table\" and sp.m.holds_end) then return \"\" end\r\nif #K.bindHolding(c, pc, src, by or \"\") > 0 then return \"\" end\r\nlocal r = Ally.rec(pc, by or \"\")\r\nif not (r and type(r.conc) == \"table\" and r.conc.name == src) then return \"\" end\r\nr.conc = nil\r\nr.concEnd = { name = src, why = \"ended with no one inside\" }\r\nreturn \"; \" .. src .. \" ends, no one inside\"\r\nend\r\n\r\nfunction K.bindSpellLive(src, binder, pc)\r\nlocal sp = Canon.name(src or \"\")\r\nif not SPELLS[sp] then return false end\r\nlocal r = Ally.rec(pc, binder or \"\")\r\nif not r then return false end\r\nlocal me = r == pc and \"Player\" or r.name\r\n\r\nfor _, x in ipairs(Feat.cur.casts or {}) do if x.name == sp and (x.by or \"Player\") == me then return true end end\r\nif type(r.conc) == \"table\" and r.conc.name == sp then return not r.conc.lost end\r\nfor _, a in ipairs(Spell.active(r)) do if a.name == sp then return true end end\r\nreturn false\r\nend\r\nfunction K.bindName(raw)\r\nraw = trim(raw or \"\")\r\nlocal n = Canon.name(raw)\r\nif not CONDS[n] then for x in pairs(CONDS) do if NAMES_KO[x] == raw then n = x end end end\r\nreturn n\r\nend\r\n\r\n\r\nfunction K.cantAct(name, c, pc, skip)\r\nlocal r = Ally.rec(pc, name or \"\")\r\nlocal t = r or (K.AR and K.AR.target and K.AR.target(name, c, pc))\r\nif type(t) ~= \"table\" then return nil end\r\nif r then\r\nif r.dead then return \"dead\" end\r\nif not K.upNow(r) then return \"down\" end\r\nelseif tonumber(t.hp) and tonumber(t.hp) <= 0 then return \"down\" end\r\nif K.AR and K.AR.incapNow(t) then return \"Incapacitated (a climax)\" end\r\nlocal names = r and Cond.active(r) or (K.foeCondFx(t, pc).list or {})\r\nif r then for _, n in ipairs(K.afflictConds and K.afflictConds(r, K.curPc) or {}) do names[#names + 1] = n end end\r\nfor _, n in ipairs(names) do\r\nif n ~= skip then\r\nfor _, m in pairs(K.condEff(n)) do if m.incapacitated or m.no_actions then return n end end\r\nend\r\nend\r\nreturn nil\r\nend\r\nfunction K.bindTag(f, c, pc, clock)\r\nlocal head = \"[BIND|\" .. table.concat(f, \"|\", 1, math.min(#f, 6))\r\nlocal function no(why) return head .. \"|bad:\" .. why .. \"|-]\", false end\r\nif not (K.AR and K.AR.on() and K.PACK.bind) then return no(\"no module brings binding in this game\") end\r\nlocal binder, tname = trim(f[1] or \"\"), trim(f[2] or \"\")\r\nlocal t = K.AR.target(tname, c, pc)\r\nif not t then return no(\"target must be Player, a companion or a creature in the fight\") end\r\nt.cond = type(t.cond) == \"table\" and t.cond or {}\r\nif binder == \"-\" then\r\nlocal want = trim(f[3] or \"\")\r\nlocal gone = {}\r\nfor n in pairs(t.cond) do\r\nif (want:lower() == \"all\" and K.bindOf(t, n)) or n == K.bindName(want) then gone[#gone + 1] = n end\r\nend\r\nif #gone == 0 then return no(tname .. \" is not bound by \" .. want) end\r\ntable.sort(gone)\r\nlocal was = {}\r\nfor _, n in ipairs(gone) do\r\nwas[#was + 1] = K.bindOf(t, n)\r\nt.cond[n] = nil\r\nif type(t.condBind) == \"table\" then t.condBind[n] = nil end\r\nend\r\nlocal ends = \"\"\r\nfor _, b in ipairs(was) do ends = ends .. K.holdsEnd(c, pc, b.src, b.by) end\r\nreturn head .. \"|ok|free of \" .. table.concat(gone, \", \") .. ends .. \"]\", true\r\nend\r\nlocal why = binder ~= \"\" and K.cantAct(binder, c, pc)\r\nif why then return no(binder .. \" cannot act (\" .. why .. \")\") end\r\nlocal cname = K.bindName(f[3])\r\nif not (CONDS[cname] and CONDS[cname].pack) then return no(tostring(f[3]) .. \" is not a condition a module brings\") end\r\n\r\nif K.PACK.bindable and not (type(CONDS[cname].pack) == \"table\" and CONDS[cname].pack.bind) then\r\nreturn no(cname .. \" is not a restraint (BIND puts on the conditions a module marks as one)\")\r\nend\r\nlocal will = trim(f[5] or \"\"):lower()\r\nif will ~= \"willing\" and will ~= \"unwilling\" then return no(\"willing or unwilling after the restraint\") end\r\nif will == \"unwilling\" and not K.bindHeld(t, c, pc) and not K.bindSpellLive(trim(f[4] or \"\"), binder, pc) then\r\nreturn no(tname .. \" is not held: an unwilling creature is bound once it is Restrained, Grappled, Incapacitated or unconscious (the contest first), or by a spell cast now or still in effect\")\r\nend\r\nlocal esc, brk, src, dis = K.bindDCs(trim(f[4] or \"\"), binder, pc)\r\n\r\nlocal brow = K.PACK.bonds and K.PACK.bonds[src]\r\nlocal boff = type(brow) == \"table\" and K.d2need(brow)\r\nif boff then return no(tostring(src) .. \" is \" .. tostring(K.D2_WHY[boff] or boff)) end\r\nlocal sp = SPELLS[src]\r\n\r\n\r\nlocal hm = sp and type(sp.m) == \"table\" and tonumber(sp.m.holds)\r\nif hm and not Ally.rec(pc, binder) then return no(\"binder: Player or the companion who cast \" .. src) end\r\n\r\n\r\nif hm and not K.bindSpellLive(src, binder, pc) then\r\nreturn no(binder .. \" has no \" .. src .. \" cast in this reply or still in effect (a successful CAST first)\")\r\nend\r\nif hm then\r\nlocal lv\r\nfor _, x in ipairs(Feat.cur.casts or {}) do if x.name == src and (x.by or \"Player\") == binder then lv = tonumber(x.level) end end\r\nlocal br = Ally.rec(pc, binder)\r\nif not lv and br and type(br.conc) == \"table\" and br.conc.name == src then lv = tonumber(br.conc.level) end\r\nlocal most = hm + (tonumber(sp.m.holds_up) or 0) * math.max(0, (lv or sp.level) - sp.level)\r\nlocal held = K.bindHolding(c, pc, src, binder, tname)\r\nif #held >= most then return no(string.format(\"%s holds %d at a time: %s already\", src, most, table.concat(held, \", \"))) end\r\nend\r\nlocal dur = trim(f[6] or \"\") ~= \"\" and trim(f[6]) or ((sp and sp.m and sp.m.concentration) and \"conc\" or \"-\")\r\nlocal line, good = K.AR.condOn({ tname, \"+\" .. cname, dur, binder ~= \"\" and binder or nil }, c, pc, clock)\r\nif not good then return no(line:match(\"|bad:([^|]*)|\") or \"not put on\") end\r\nlocal rec = { by = binder, src = src ~= \"\" and src or nil, esc = esc, brk = brk, dis = dis }\r\nif type(t.cond[cname]) == \"table\" then t.cond[cname].bind = rec\r\nelse\r\nt.condBind = type(t.condBind) == \"table\" and t.condBind or {}\r\nt.condBind[cname] = rec\r\nend\r\nreturn head .. string.format(\"|ok|%s: escape DC %d, break DC %d%s]\", cname, esc, brk, dis and (\", escape at Disadvantage (\" .. dis .. \")\") or \"\"), true\r\nend\r\nfunction K.escapeTag(f, pools, cur, c, pc)\r\nlocal head = \"[ESCAPE|\" .. table.concat(f, \"|\", 1, math.min(#f, 7))\r\nlocal function no(why) return head .. \"|bad:\" .. why .. \"|-]\", false end\r\nlocal tname = trim(f[1] or \"\")\r\nlocal t = K.AR.target(tname, c, pc)\r\nif not t then return no(\"target must be Player, a companion or a creature in the fight\") end\r\nlocal cname = K.bindName(f[2])\r\nlocal b = K.AR.condsOf(t)[cname] and K.bindOf(t, cname)\r\nif not b then return no(tname .. \" is not bound by \" .. tostring(f[2]) .. \" (BIND puts a bond on)\") end\r\nlocal why = K.cantAct(tname, c, pc, cname)\r\nif why then return no(tname .. \" cannot act (\" .. why .. \"): no escape attempt now\") end\r\nlocal sk = Canon.name(trim(f[3] or \"\"))\r\nlocal brk = sk == \"Strength\" or sk == \"Athletics\"\r\nif not (brk or sk == \"Dexterity\" or sk == \"Acrobatics\" or sk == \"Sleight of Hand\") then\r\nreturn no(\"Dexterity, Acrobatics or Sleight of Hand slips out; Strength or Athletics breaks it\")\r\nend\r\nlocal dc = tonumber(brk and b.brk or b.esc) or 20\r\nlocal bad, total = {}, nil\r\nlocal d20, bonus = f[4], f[5]\r\nlocal r = Ally.rec(pc, tname)\r\nif r then\r\nlocal line = Ally.run(pc, r ~= pc and r or nil, function() return verifyCheck({ sk, f[4], f[5], tostring(dc), f[7] }, pools, cur, nil) end)\r\nlocal p = {}\r\nfor x in (line:sub(2, -2) .. \"|\"):gmatch(\"([^|]*)|\") do p[#p + 1] = x end\r\nd20, bonus, total = p[3], p[4], tonumber(p[#p])\r\nlocal v = p[#p - 1] or \"\"\r\nif v:match(\"^bad:\") then bad[#bad + 1] = v:sub(5) end\r\nelse\r\nlocal roll = takeD20(cur, pools, f[4], bad, nil, \"check\")\r\ntotal = (tonumber(roll) or 0) + (tonumber(f[5]) or 0)\r\nlocal should = total >= dc and \"success\" or \"failure\"\r\nif f[7] ~= should then bad[#bad + 1] = \"result->\" .. should end\r\nend\r\nif tonumber(f[6]) ~= dc then bad[#bad + 1] = string.format(\"DC %s->%d\", tostring(f[6]), dc) end\r\nlocal free = total and total >= dc\r\nlocal ends = \"\"\r\nif free then\r\nt.cond[cname] = nil\r\nif type(t.condBind) == \"table\" then t.condBind[cname] = nil end\r\nends = K.holdsEnd(c, pc, b.src, b.by)\r\nend\r\nlocal ok = #bad == 0\r\nreturn string.format(\"[ESCAPE|%s|%s|%s|%s|%s|%d|%s|%s|%s]\", tname, cname, sk, tostring(d20), tostring(bonus), dc, tostring(f[7]),\r\nok and \"ok\" or (\"bad:\" .. table.concat(bad, \", \")), tostring(total) .. (free and (brk and \", broken free\" or \", slipped free\") or \", still bound\") .. ends), ok\r\nend\r\n\r\n\r\n\r\n\r\n\r\n\r\nK.NATURAL_AC = { Beast = true, Monstrosity = true, Dragon = true, Ooze = true, Plant = true, Elemental = true, Aberration = true, Construct = true }\r\nfunction K.stripFloor(u)\r\nlocal m = MONSTERS[(K.kindOf and K.kindOf(u, K.partyPc)) or u.kind or \"\"] or {}\r\nlocal dx = math.min(tonumber(type(m.saves) == \"table\" and m.saves.Dexterity) or 0, tonumber(m.init) or 99)\r\nreturn 10 + dx\r\nend\r\n\r\nfunction K.foeAC(u, pc, st)\r\nst = st or statsOf(u, pc)\r\nreturn (tonumber(st and st.ac) or 10) + K.foeFx(u, pc).ac - (tonumber(u.strip) or 0)\r\nend\r\nfunction K.stripTag(f, pools, cur, c, pc)\r\nlocal head = \"[STRIP|\" .. table.concat(f, \"|\", 1, math.min(#f, 5))\r\nlocal function no(why)\r\nK.spendRefused(pools, cur, f[2])\r\nreturn head .. \"|bad:\" .. why .. \"|-]\", false\r\nend\r\nlocal who, tname = (f[1] or \"\"):match(\"^(.-)/(.+)$\")\r\nwho, tname = trim(who or \"Player\"), trim(tname or f[1] or \"\")\r\nlocal r = Ally.rec(pc, who ~= \"\" and who or \"Player\")\r\nif not r then return no(who .. \": Player or a companion\") end\r\nlocal sh = K.ownSheet(r, pc)\r\nif not (sh and #Feat.fxOf(sh, \"strip_armor\") > 0) then return no((r == pc and \"Player\" or r.name) .. \" has no feature that takes armor off (Clasp Master)\") end\r\nlocal u = K.AR.target(tname, c, pc)\r\nif not u or Ally.rec(pc, tname) then return no(\"target must be a creature in the fight or in the scene\") end\r\nlocal why = K.cantAct(r == pc and \"Player\" or r.name, c, pc)\r\nif why then return no((r == pc and \"Player\" or r.name) .. \" cannot act (\" .. why .. \")\") end\r\nlocal m = MONSTERS[(K.kindOf(u, pc)) or u.kind or \"\"] or {}\r\nfor _, ty in ipairs(type(m.ctypes) == \"table\" and m.ctypes or {}) do\r\nif K.NATURAL_AC[ty] then return no(tname .. \"'s AC is natural armor (\" .. ty .. \"): nothing to take off\") end\r\nend\r\nlocal ac = K.foeAC(u, pc)\r\nlocal floor = K.stripFloor(u)\r\nif ac - K.foeFx(u, pc).ac <= floor then return no(tname .. \" has no armor piece left (AC \" .. ac .. \", its unarmored \" .. floor .. \")\") end\r\nlocal hostile = c.active and u.side == \"enemy\"\r\nlocal bad = {}\r\nif hostile and not tostring(f[2] or \"\"):match(\"^%s*dis%s\") then bad[#bad + 1] = \"a hostile target: Disadvantage (dis A,B)\" end\r\nlocal line = Ally.run(pc, r ~= pc and r or nil, function() return verifyCheck({ \"Sleight of Hand\", f[2], f[3], tostring(ac), f[5] }, pools, cur, nil) end)\r\nlocal p = {}\r\nfor x in (line:sub(2, -2) .. \"|\"):gmatch(\"([^|]*)|\") do p[#p + 1] = x end\r\nlocal total = tonumber(p[#p])\r\nlocal v = p[#p - 1] or \"\"\r\nif v:match(\"^bad:\") then bad[#bad + 1] = v:sub(5) end\r\nif tonumber(f[4]) ~= ac then bad[#bad + 1] = string.format(\"AC %s->%d\", tostring(f[4]), ac) end\r\nlocal took = total and total >= ac and not (hostile and not tostring(f[2] or \"\"):match(\"^%s*dis%s\"))\r\nlocal note\r\nif took then\r\nu.strip = (tonumber(u.strip) or 0) + 1\r\nFeat.cur.sfxNew = Feat.cur.sfxNew or {}\r\nFeat.cur.sfxNew[u] = true\r\nnote = string.format(\"a piece off: AC %d now\", K.foeAC(u, pc))\r\nelse\r\nnote = \"nothing off\"\r\nend\r\nif c.active then c.last = r == pc and \"Player\" or r.name end\r\nreturn string.format(\"[STRIP|%s|%s|%s|%d|%s|%s|%s]\", tostring(f[1]), tostring(p[3] or f[2]), tostring(p[4] or f[3]), ac, tostring(f[5]),\r\n#bad == 0 and \"ok\" or (\"bad:\" .. table.concat(bad, \";\")), tostring(total) .. \", \" .. note), #bad == 0\r\nend\r\n\r\n\r\n\r\n\r\n\r\n\r\nK.SNAP_FIELDS = { buff = true, mode = true, form = true, equip = true, lasting = true, conc = true, cond = true, exh = true }\r\nfunction K.snapParty(pc)\r\nlocal out = {}\r\nlocal function copy(v)\r\nif type(v) ~= \"table\" then return v end\r\nlocal o = {}\r\nfor k, x in pairs(v) do o[k] = x end\r\nreturn o\r\nend\r\nlocal all = { pc, table.unpack(Ally.list(pc)) }\r\nfor _, g in ipairs(Ally.guests(pc)) do all[#all + 1] = g end\r\nfor _, r in ipairs(all) do\r\nCond.load(r)\r\nlocal s = {}\r\nfor k in pairs(K.SNAP_FIELDS) do s[k] = copy(r[k]) end\r\nout[r] = s\r\nend\r\nreturn out\r\nend\r\n\r\nfunction K.snapChanged(rec)\r\nlocal s = type(Feat.cur.snap) == \"table\" and Feat.cur.snap[rec]\r\nif not s then return false end\r\nfor k in pairs(K.SNAP_FIELDS) do\r\nlocal a, b = s[k], rec[k]\r\nif type(a) == \"table\" or type(b) == \"table\" then\r\na, b = type(a) == \"table\" and a or {}, type(b) == \"table\" and b or {}\r\nfor x, v in pairs(a) do if b[x] ~= v then return true end end\r\nfor x, v in pairs(b) do if a[x] ~= v then return true end end\r\nelseif a ~= b then\r\nreturn true\r\nend\r\nend\r\nreturn false\r\nend\r\n\r\nfunction K.withOld(rec, fn)\r\nif type(rec) ~= \"table\" or not K.snapChanged(rec) then return nil end\r\nlocal s, keep = Feat.cur.snap[rec], {}\r\nfor k in pairs(K.SNAP_FIELDS) do keep[k] = rec[k]; rec[k] = s[k] end\r\nlocal res = table.pack(pcall(fn))\r\nfor k in pairs(K.SNAP_FIELDS) do rec[k] = keep[k] end\r\nif not res[1] then return nil end\r\nreturn table.unpack(res, 2, res.n)\r\nend\r\n\r\n\r\n\r\nfunction K.oldBonus(rec, name)\r\nreturn K.withOld(rec, function()\r\nlocal b = bonusFor(name)\r\nreturn b and (b - Cond.fx(rec).pen) or nil\r\nend)\r\nend\r\nfunction K.oldLanded(rec, raw, dtype)\r\nlocal tr = K.withOld(rec, function() return Feat.traits(rec) end)\r\nreturn tr and (Feat.adjust(tr, raw, dtype)) or nil\r\nend\r\n\r\n\r\nfunction K.fitAttack(a, written, mode, nat)\r\nif not written then return true end\r\nlocal want = canon(written, false)\r\nfor _, crit in ipairs({ false, true }) do\r\nlocal function same(s)\r\nlocal q = parseFormula(s)\r\nreturn q ~= nil and canon(q, crit) == want\r\nend\r\nif a.adv and mode == \"adv\" and same(a.adv) then return true end\r\nlocal ex = a.extras or {}\r\nfor mask = 0, (1 << #ex) - 1 do\r\nlocal s, okm = a.dmg, true\r\nfor i = 1, #ex do\r\nif mask & (1 << (i - 1)) ~= 0 then\r\ns = s .. \"+\" .. ex[i].dice\r\nif (ex[i].plain and (mode == \"adv\" or mode == \"dis\")) or (ex[i].nat20 and nat ~= 20) then okm = false end\r\nend\r\nend\r\nif okm and same(s) then return true end\r\nend\r\nend\r\nreturn false\r\nend\r\n\r\nfunction K.formulaText(p)\r\nlocal o = {}\r\nfor _, d in ipairs(p.dice) do o[#o + 1] = d.n .. \"d\" .. d.s end\r\nlocal s = table.concat(o, \"+\")\r\nfor _, d in ipairs(type(p.neg) == \"table\" and p.neg or {}) do s = s .. \"-\" .. d.n .. \"d\" .. d.s end\r\nif p.mod ~= 0 or s == \"\" then s = s .. ((s ~= \"\" and p.mod > 0) and \"+\" or \"\") .. p.mod end\r\nreturn s\r\nend\r\n\r\n\r\nfunction K.restale(f, st, rec, old, mode, nat)\r\nif not K.snapChanged(rec) then return end\r\nlocal hitW = tonumber(f[4])\r\nlocal written = (f[7] or \"-\") ~= \"-\" and parseFormula(f[7]) or nil\r\nfor _, a in ipairs(st.attacks) do\r\nif a.hit == hitW and K.fitAttack(a, written, mode, nat) then return end\r\nend\r\nlocal ost = K.withOld(rec, old)\r\nfor _, o in ipairs(ost and ost.attacks or {}) do\r\nif o.hit == hitW and K.fitAttack(o, written, mode, nat) then\r\nfor _, a in ipairs(st.attacks) do\r\nif a.name == o.name then\r\nlocal dm = ((parseFormula(a.dmg) or { mod = 0 }).mod) - ((parseFormula(o.dmg) or { mod = 0 }).mod)\r\nf[4] = string.format(\"%+d\", a.hit)\r\nif written and dm ~= 0 then\r\nwritten.mod = written.mod + dm\r\nf[7] = K.formulaText(written)\r\nif tonumber(f[9]) and (f[6] == \"hit\" or f[6] == \"crit\") then f[9] = tostring(tonumber(f[9]) + dm) end\r\nend\r\nreturn\r\nend\r\nend\r\nreturn\r\nend\r\nend\r\nend\r\n\r\n\r\n\r\n\r\n\r\n\r\nfunction K.byKey(by)\r\nif by == nil or by == \"Player\" then return \"Player\" end\r\nlocal p = K.partyPc or K.curPc\r\nif type(by) == \"table\" then\r\nif by == p then return \"Player\" end\r\nreturn by.name or \"Player\"\r\nend\r\nif type(p) == \"table\" and p.name and by == p.name then return \"Player\" end\r\nreturn by\r\nend\r\nfunction K.tagFields(t)\r\nlocal o = {}\r\nfor v in ((t or \"\") .. \"|\"):gmatch(\"([^|]*)|\") do v = trim(v); if v == \"ok\" or v:match(\"^bad:\") then break end; o[#o + 1] = v end\r\nreturn o\r\nend\r\n\r\n\r\nfunction K.reactOf(tg, rs, persona, pc)\r\nlocal fl = K.tagFields(rs)\r\nlocal function party(n) return (n == \"Player\" or Ally.find(pc, n) ~= nil and not Ally.isGuest(pc, n)) and n or nil end\r\nif tg == \"CAST\" then\r\nlocal sp = SPELLS[Canon.name(fl[1] or \"\")]\r\nif not (sp and ((type(sp.m) == \"table\" and sp.m.cast == \"reaction\") or tostring(sp.casting_time or \"\"):match(\"^Reaction\"))) then return nil end\r\nreturn party((fl[3] and fl[3] ~= \"\") and Canon.actor(fl[3], persona) or \"Player\"), Canon.name(fl[1] or \"\")\r\nelseif tg == \"USE\" then\r\nlocal user, feat = (fl[1] or \"\"):match(\"^(.-)/(.+)$\")\r\nfeat = Canon.name(feat or fl[1] or \"\")\r\nlocal can = K.featCan and K.featCan(feat)\r\nif type(can) ~= \"table\" or #can == 0 then return nil end\r\nfor _, e in ipairs(can) do if e.when ~= \"react\" then return nil end end\r\nreturn party(user and Canon.actor(user, persona) or \"Player\"), feat\r\nelseif tg == \"REACT\" then\r\nreturn party(Canon.actor(fl[1] or \"\", persona)), fl[2] or \"REACT\"\r\nend\r\nreturn nil\r\nend\r\nfunction K.insteadOf(tg, rs, persona)\r\nif tg ~= \"CAST\" then return nil end\r\nlocal fl = K.tagFields(rs)\r\nlocal sp = Canon.name(fl[1] or \"\")\r\nlocal m = SPELLS[sp] and SPELLS[sp].m\r\nif not (type(m) == \"table\" and (m.instead_of == \"ADVANCE\" or m.instead_of == \"damage\")) then return nil end\r\nreturn m.instead_of, (fl[3] and fl[3] ~= \"\") and Canon.actor(fl[3], persona) or \"Player\", sp\r\nend\r\n\r\n\r\n\r\nfunction K.advGoneLine(c, Y, fa, line)\r\nif not (type(c) == \"table\" and c.active and type(c.units) == \"table\" and c.units[Y]) then return line end\r\nlocal last0 = c.last\r\nc.last = Y\r\nreturn K.roundMark(c, \"ADVANCE\", fa, true, line, last0)\r\nend\r\n\r\nfunction K.noteGone(rest, line, persona)\r\nlocal cs = Spell.cur\r\nlocal m = type(cs) == \"table\" and SPELLS[cs.name or \"\"] and SPELLS[cs.name].m\r\nif not (type(m) == \"table\" and m.instead_of == \"ADVANCE\") then return end\r\nif K.saveResultOf(line) ~= \"failure\" then return end\r\nlocal y = Canon.actor(K.tagFields(rest)[1] or \"\", persona)\r\nFeat.cur.advGone = Feat.cur.advGone or {}\r\nFeat.cur.advGone[y] = { by = K.byKey(cs.by), spell = cs.name }\r\nend\r\n\r\nfunction K.noteShield(rest, line, persona)\r\nlocal kind, by, sp = K.insteadOf(\"CAST\", rest, persona)\r\nif kind ~= \"damage\" or not tostring(line or \"\"):find(\"|ok|\", 1, true) then return end\r\nFeat.cur.dmgShield = Feat.cur.dmgShield or {}\r\nFeat.cur.dmgShield[by] = sp\r\nend\r\n\r\nfunction K.dmgTargetOf(tg, rs, persona, pc, c)\r\nlocal fl = K.tagFields(rs)\r\nlocal function who(v) return Canon.actor(v or \"\", persona) end\r\nlocal function ours(n) return n == \"Player\" or Ally.find(pc, n) ~= nil end\r\nif tg == \"ATTACK\" then\r\nlocal t = who(fl[2])\r\nif not ours(t) and fl[3] and ours(who(fl[3])) then table.remove(fl, 2); t = who(fl[2]) end\r\nif (fl[6] or \"\"):lower() == \"miss\" then return nil end\r\nreturn ours(t) and t or nil\r\nelseif tg == \"SAVE\" or tg == \"DAMAGE\" then\r\nlocal t = who(fl[1])\r\nlocal amt = tg == \"SAVE\" and fl[9] or fl[4]\r\nif amt ~= nil and (trim(amt) == \"0\" or trim(amt) == \"-\") then return nil end\r\nreturn ours(t) and t or nil\r\nend\r\nreturn nil\r\nend\r\n\r\nfunction K.saveResultOf(line)\r\nline = tostring(line or \"\")\r\nline = line:match(\"%[SAVE|[^%]]*%]\") or line\r\nif line:find(\"|-]\", 1, true) and line:find(\"|bad:\", 1, true) and not line:find(\"result%->\") then return nil end\r\nlocal r = line:match(\"result%->(%a+)\")\r\nif r then return r:lower() end\r\nlocal fl = K.tagFields((line:gsub(\"^%[SAVE|\", \"\"):gsub(\"%]$\", \"\")))\r\nreturn (fl[6] or \"\"):lower()\r\nend\r\n\r\n\r\n\r\nfunction K.climaxReplaced(tags, i, rest, persona)\r\nlocal function fields(t)\r\nlocal o = {}\r\nfor v in ((t or \"\") .. \"|\"):gmatch(\"([^|]*)|\") do v = trim(v); if v == \"ok\" or v:match(\"^bad:\") then break end; o[#o + 1] = v end\r\nreturn o\r\nend\r\nlocal cf = fields(rest)\r\nif not (cf[2] or \"\"):find(\"%d\") then return nil end\r\nlocal x = Canon.actor(cf[1] or \"\", persona)\r\nfor j = (tonumber(i) or 0) + 1, #tags do\r\nlocal tg, fl = tags[j][1], fields(tags[j][2])\r\nif tg == \"CLIMAX\" and Canon.actor(fl[1] or \"\", persona) == x then return nil end\r\nif tg == \"CAST\" then\r\nlocal sp = Canon.name(fl[1] or \"\")\r\nlocal m = SPELLS[sp] and SPELLS[sp].m\r\nif type(m) == \"table\" and m.instead_of == \"CLIMAX\" then\r\nfor k = j + 1, #tags do\r\nlocal tk, fk = tags[k][1], fields(tags[k][2])\r\nif tk == \"CAST\" then break end\r\nif tk == \"CLIMAX\" and Canon.actor(fk[1] or \"\", persona) == x then break end\r\nif (tk == \"DAMAGE\" or tk == \"STIM\" or tk == \"SOOTHE\" or tk == \"SAVE\") and Canon.actor(fk[1] or \"\", persona) == x then\r\nreturn sp .. \" is cast in place of this climax save (its CAST later in this reply)\"\r\nend\r\nend\r\nend\r\nend\r\nend\r\nreturn nil\r\nend\r\n\r\n\r\n\r\nfunction K.answersAttack(tg, rs, atkRest, nextTag, persona, pc, c)\r\nif tg ~= \"CAST\" and tg ~= \"USE\" then return false end\r\n\r\nlocal function fields(t)\r\nlocal o = {}\r\nfor v in ((t or \"\") .. \"|\"):gmatch(\"([^|]*)|\") do\r\nv = trim(v)\r\nif v == \"ok\" or v:match(\"^bad:\") then break end\r\no[#o + 1] = v\r\nend\r\nreturn o\r\nend\r\nlocal fl = fields(rs)\r\nlocal units = type(c) == \"table\" and type(c.units) == \"table\" and c.units or {}\r\nlocal function who(v) return Canon.actor(v or \"\", persona) end\r\nlocal function isWho(n) return n == \"Player\" or units[n] ~= nil or Ally.find(pc, n) ~= nil end\r\nlocal function atkOf(t)\r\nlocal af = fields(t)\r\nif not isWho(who(af[2])) and af[3] and isWho(who(af[3])) then table.remove(af, 2) end\r\nreturn who(af[1]), who(af[2]), (af[6] or \"\"):lower()\r\nend\r\nlocal atk, tgt, res = atkOf(atkRest)\r\nlocal kind\r\nlocal by\r\nif tg == \"CAST\" then\r\nlocal m = SPELLS[Canon.name(fl[1] or \"\")] and SPELLS[Canon.name(fl[1] or \"\")].m\r\nif not (type(m) == \"table\" and m.cast == \"reaction\" and m.ac_bonus) then return false end\r\nkind, by = \"def\", (fl[3] and fl[3] ~= \"\") and who(fl[3]) or \"Player\"\r\nelse\r\nlocal user, feat = (fl[1] or \"\"):match(\"^(.-)/(.+)$\")\r\nuser = user and who(user) or \"Player\"\r\nfeat = feat or fl[1] or \"\"\r\nlocal rec = user == \"Player\" and pc or Ally.find(pc, user)\r\nlocal sh = rec == pc and SHEET or (type(rec) == \"table\" and rec.sheet)\r\nby = (fl[2] or \"\") ~= \"\" and who(fl[2]) or user\r\nfor _, e in ipairs(type(sh) == \"table\" and Feat.fxOf(sh, \"use_mod\") or {}) do\r\nif e.use == feat or e.use == Canon.name(feat) then\r\nkind = (e.ac_bonus or e.dmg_reduce or e.auto_miss) and \"def\" or ((e.attack_bonus or e.auto_hit) and \"atk\") or nil\r\nend\r\nend\r\nif not kind then return false end\r\nend\r\nif kind == \"def\" and not (by == tgt and (res == \"hit\" or res == \"crit\")) then return false end\r\nif kind == \"atk\" and not (by == atk and res == \"miss\") then return false end\r\nif type(nextTag) == \"table\" and nextTag[1] == \"ATTACK\" then\r\nlocal na, nt = atkOf(nextTag[2])\r\nif (kind == \"def\" and nt == by) or (kind == \"atk\" and na == by) then return false end\r\nend\r\nreturn true\r\nend\r\n\r\n\r\n\r\n\r\nfunction K.castAllDown(tags, i, by, a, c, pc, persona)\r\nif not (c and c.active and type(c.units) == \"table\" and type(tags) == \"table\") then return nil end\r\nlocal name = Canon.name(trim(a[1] or \"\"))\r\nlocal m = SPELLS[name] and SPELLS[name].m\r\nif not (type(m) == \"table\" and m.kind == \"attack\" and m.attack ~= \"weapon\") then return nil end\r\nlocal first, n = nil, 0\r\nfor j = (tonumber(i) or 0) + 1, #tags do\r\nlocal tg, rs = tags[j][1], tags[j][2] or \"\"\r\nif tg == \"CAST\" then break end\r\nif tg == \"ATTACK\" then\r\nlocal f = {}\r\nfor v in (rs .. \"|\"):gmatch(\"([^|]*)|\") do f[#f + 1] = trim(v) end\r\nif Canon.actor(f[1] or \"\", persona) == by then\r\nlocal t = Canon.actor(f[2] or \"\", persona)\r\nif not c.units[t] and f[3] and c.units[Canon.actor(f[3], persona)] then\r\nt = Canon.actor(f[3], persona)\r\ntable.remove(f, 2)\r\nend\r\nlocal u = c.units[t]\r\nif not (u and u.side == \"enemy\" and not K.foeUp(u)) then return nil end\r\nlocal acW, cands = tonumber(f[5]), 0\r\nfor _, v in pairs(c.units) do\r\nif v.side == \"enemy\" and K.foeUp(v) and acW and statsOf(v, pc).ac == acW then cands = cands + 1 end\r\nend\r\nif cands == 1 then return nil end\r\nn = n + 1\r\nfirst = first or t\r\nend\r\nend\r\nend\r\nif n == 0 then return nil end\r\nreturn first .. \" is down: no standing target for \" .. name .. \" (nothing spent)\"\r\nend\r\n\r\n\r\n\r\n\r\nfunction K.kindOfSet(list, isMon)\r\nlocal kind\r\nfor _, a in ipairs(list or {}) do\r\nlocal k\r\nif a.srange == \"melee\" then k = \"melee\"\r\nelseif a.srange == \"ranged\" then k = \"far\"\r\nelseif a.spell then k = \"?\"\r\nelseif isMon or a.beast then k = (a.k == \"b\" and \"?\") or (a.k == \"r\" and \"far\") or \"melee\"\r\nelseif a.thrown then k = \"?\"\r\nelseif a.melee then k = \"melee\"\r\nelseif a.weapon then k = \"far\"\r\nelse k = \"?\" end\r\nif k == \"?\" or (kind and kind ~= k) then return nil end\r\nkind = k\r\nend\r\nreturn kind\r\nend\r\nfunction K.noteMelee(c, atk, tgt, kind)\r\nlocal foe = (atk == \"Player\" and tgt) or (tgt == \"Player\" and atk) or nil\r\nlocal u = foe and type(c.units) == \"table\" and c.units[foe]\r\nif not (u and u.side == \"enemy\" and c.active) then return end\r\nif kind == \"melee\" then\r\nc.melee = type(c.melee) == \"table\" and c.melee or {}\r\nc.melee[foe] = tonumber(c.round) or 1\r\nelseif kind == \"far\" and type(c.melee) == \"table\" then\r\nc.melee[foe] = nil\r\nend\r\nend\r\nfunction K.meleeNote(c)\r\nif type(c.melee) ~= \"table\" then return \"\" end\r\nlocal rd, names = tonumber(c.round) or 1, {}\r\nfor _, name in ipairs(c.order or {}) do\r\nlocal u, r = c.units[name], tonumber(c.melee[name])\r\nif r and rd - r <= 1 and type(u) == \"table\" and (tonumber(u.hp) or 0) > 0 then names[#names + 1] = name end\r\nend\r\nif #names == 0 then return \"\" end\r\nreturn \"\\nPlayer last traded melee blows with: \" .. table.concat(names, \", \") .. \". Lua keeps no distances and this holds nobody in place: if Player has backed away\"\r\n.. \" since, or stays in reach, nothing follows. Only if Player's turn now takes it out of such a creature's reach without Disengage (say, over to an enemy at range),\"\r\n.. \" write that creature's Opportunity Attack first, one ATTACK right before the move. After that, it closes the gap only as \\\"Moving and fleeing\\\" says.\"\r\nend\r\nlocal function verifyAttack(f, pools, cur, c, pc)\r\nlocal named = K.atkNamed\r\nK.atkNamed = nil\r\nK.atkKindLast = nil\r\n\r\nlocal bad = {}\r\n\r\nlocal riposte = type(c.riposte) == \"table\" and c.riposte.by == f[1] and c.riposte.vs == f[2]\r\nif type(c.riposte) == \"table\" and not riposte and f[1] ~= c.riposte.vs then c.riposte = nil end\r\nlocal atkU, tgtU = c.units[f[1]], c.units[f[2]]\r\nK.curAttacker = f[1]\r\nif not c.active then bad[#bad + 1] = \"no combat\" end\r\nif not atkU then bad[#bad + 1] = \"unknown attacker\" end\r\nif not tgtU then bad[#bad + 1] = \"unknown target\" end\r\n\r\nlocal atkR, tgtR = atkU and Ally.rec(pc, f[1], atkU), tgtU and Ally.rec(pc, f[2], tgtU)\r\nK.d20Foe, K.d20FoeName, K.d20Tgt = (atkU and atkU.side == \"enemy\") and atkU or nil, f[1], tgtR or tgtU\r\nlocal roll, mode, nat = takeD20(cur, pools, f[3], bad, atkR, \"attack\")\r\nK.d20Foe, K.d20FoeName, K.d20Tgt = nil, nil, nil\r\n\r\n\r\nlocal noAdvSrc\r\nif mode == \"adv\" and tgtR and type(K.d20Got) == \"table\" and tonumber(K.d20Got[1]) then\r\nlocal tsh = K.ownSheet(tgtR, pc)\r\nlocal e = tsh and Feat.fxOf(tsh, \"no_adv_against\")[1]\r\nif e then\r\nlocal d1 = tonumber(K.d20Got[1])\r\nroll, nat, mode = roll - (nat or roll) + d1, d1, \"normal\"\r\nnoAdvSrc = e.src or \"no Advantage\"\r\nend\r\nend\r\ndo\r\nlocal fl = atkR and K.d20Floor(atkR.sheet or SHEET, \"attack\", nil)\r\nif fl and nat and nat < fl then roll, nat = roll + fl - nat, fl end\r\nend\r\nnat = nat or roll\r\nlocal hpText = \"-\"\r\nif not (c.active and atkU and tgtU) then\r\nK.spendRefused(pools, cur, nil, f[7], f[8])\r\nreturn string.format(\"[ATTACK|%s|bad:%s|%s]\", table.concat(f, \"|\", 1, 9), table.concat(bad, \";\"), hpText), false\r\nend\r\n\r\n\r\nif atkU.summon and (atkU.noatk or pc.mount == f[1]) then\r\nlocal p = parseFormula(f[7] or \"\")\r\nif p then spendDice(p, f[8], pools, cur, {}) end\r\nreturn string.format(\"[ATTACK|%s|bad:%s|-]\", table.concat(f, \"|\", 1, 9),\r\natkU.noatk and \"a familiar cannot attack (it can Help, Dodge or Dash)\" or (f[1] .. \" is ridden by Player: a controlled mount takes only Dash, Disengage or Dodge\")), false\r\nend\r\nlocal pactNote = atkR and K.pactFromAttack(atkR, f, named, pc, atkU, statsOf) or \"\"\r\nlocal atkSt, tgtSt = statsOf(atkU, pc), statsOf(tgtU, pc)\r\n\r\nif atkU.side == \"enemy\" then\r\natkSt = K.situational(atkSt, atkU, tgtR or tgtU)\r\nif not riposte and atkU.acUp and not atkU.acUpKeep then atkU.acUp, atkU.acUpWhy = nil, nil end\r\nend\r\n\r\n\r\n\r\n\r\n\r\nif tgtU.side == \"enemy\" and not K.foeUp(tgtU) then\r\nlocal acW0 = tonumber(f[5])\r\nlocal cands, standing = {}, {}\r\nfor name, u in pairs(c.units) do\r\nif u.side == \"enemy\" and K.foeUp(u) then\r\nstanding[#standing + 1] = name\r\nif acW0 and statsOf(u, pc).ac == acW0 then cands[#cands + 1] = name end\r\nend\r\nend\r\ntable.sort(standing)\r\nif #cands == 1 then\r\nbad[#bad + 1] = \"target \" .. f[2] .. \"->\" .. cands[1] .. \" (\" .. f[2] .. \" was down)\"\r\nf[2] = cands[1]\r\ntgtU = c.units[f[2]]\r\ntgtSt = statsOf(tgtU, pc)\r\nelse\r\nlocal wr = (f[7] or \"-\") ~= \"-\" and parseFormula(f[7])\r\nif wr then spendDice(wr, f[8], pools, cur, {}) end\r\nreturn string.format(\"[ATTACK|%s|bad:%s is down: attack a standing enemy%s|-]\", table.concat(f, \"|\", 1, 9), f[2],\r\n#standing > 0 and (\" (\" .. table.concat(standing, \", \") .. \")\") or \"\"), false\r\nend\r\nend\r\nif #atkSt.attacks == 0 then\r\n\r\nbad[#bad + 1] = \"no modelled attack\"\r\nK.spendRefused(pools, cur, nil, f[7], f[8])\r\nreturn string.format(\"[ATTACK|%s|bad:%s|%s]\", table.concat(f, \"|\", 1, 9), table.concat(bad, \";\"), hpText), false\r\nend\r\nlocal atkHp = atkR and (atkR.dead and 0 or atkR.hp) or atkU.hp\r\nif atkHp <= 0 and not (atkR and K.upNow(atkR)) then bad[#bad + 1] = \"attacker is down\" end\r\nlocal fx = Cond.fx(atkR)\r\nif atkR and fx.incap then bad[#bad + 1] = f[1] .. \" is \" .. fx.incap end\r\n\r\nlocal foeIncap = atkU.side == \"enemy\" and K.foeCondFx(atkU, pc).incap\r\nif foeIncap then bad[#bad + 1] = f[1] .. \" is \" .. foeIncap end\r\n\r\nlocal sancNo = tgtR and type(Feat.cur.sanct) == \"table\" and type(Feat.cur.sanct[f[1]]) == \"table\" and Feat.cur.sanct[f[1]][f[2]]\r\nif sancNo then bad[#bad + 1] = f[1] .. \" failed its save against the ward on \" .. f[2] .. \": another target, or the attack is lost\" end\r\nlocal charmNo = atkU.side == \"enemy\" and tgtU and K.charmedBy(atkU, pc, f[2])\r\n\r\nlocal calmNo = (atkU.side == \"enemy\" and K.foeCondFx(atkU, pc).nohostile) or (atkR and Cond.fx(atkR).nohostile) or nil\r\nif calmNo then bad[#bad + 1] = f[1] .. \" is \" .. calmNo .. \": no hostile action\" end\r\nif charmNo then bad[#bad + 1] = f[1] .. \" is \" .. charmNo .. \" by \" .. f[2] .. \": it can't attack its charmer\" end\r\nlocal sancEnd = \"\"\r\nif atkR and type(atkR.buff) == \"table\" then\r\nfor bn, b in pairs(atkR.buff) do if type(b) == \"table\" and b.asave then atkR.buff[bn] = nil; sancEnd = \" (\" .. bn .. \" ends: it attacked)\" end end\r\nend\r\n\r\nif f[4] == \"?\" then f[4] = string.format(\"%+d\", atkSt.attacks[1].hit) end\r\n\r\n\r\n\r\nif atkR then K.restale(f, atkSt, atkR, function() return statsOf(atkU, pc) end, mode, nat) end\r\nlocal hitB = tonumber(f[4])\r\nlocal known = {}\r\n\r\n\r\nlocal noDmgW = trim(f[7] or \"-\") == \"-\" and (trim(f[9] or \"0\") == \"0\" or trim(f[9] or \"\") == \"-\")\r\nlocal function ndOk(a)\r\nreturn (Spell.cur and Spell.cur.name == a.spell and K.byKey(Spell.cur.by) == K.byKey(f[1])) or named == a.spell\r\nend\r\n\r\n\r\nlocal sundNote\r\nlocal sund = type(Feat.cur.sunder) == \"table\" and Feat.cur.sunder[f[2]]\r\nif sund and atkU.side ~= \"enemy\" and K.byKey(sund) ~= K.byKey(f[1]) and hitB then\r\nlocal plainH, minus5 = false, false\r\nfor _, a in ipairs(atkSt.attacks) do\r\nif a.hit == hitB then plainH = true end\r\nif a.hit == hitB - 5 then minus5 = true end\r\nend\r\nif not plainH and minus5 then\r\nhitB, roll, sundNote = hitB - 5, roll + 5, \" (Sundering Blow: +5)\"\r\nFeat.cur.sunder[f[2]] = nil\r\nend\r\nend\r\n\r\nlocal lash = atkR and type(atkR.lash) == \"table\" and atkR.lash.from == f[2] and atkR.lash or nil\r\nif lash then\r\nlocal s4 = {}\r\nfor k, v in pairs(atkSt) do s4[k] = v end\r\ns4.attacks = {}\r\nfor _, a in ipairs(atkSt.attacks) do\r\nlocal b = {}\r\nfor k, v in pairs(a) do b[k] = v end\r\nb.extras = {}\r\nfor _, x in ipairs(a.extras or {}) do b.extras[#b.extras + 1] = x end\r\nb.extras[#b.extras + 1] = { dice = tostring(lash.n), src = lash.src, lashOf = atkR }\r\ns4.attacks[#s4.attacks + 1] = b\r\nend\r\natkSt = s4\r\nend\r\n\r\nlocal cmd = atkU.side ~= \"enemy\" and K.cmdDie(pc, f[1]) or nil\r\nif cmd then\r\nlocal s3 = {}\r\nfor k, v in pairs(atkSt) do s3[k] = v end\r\ns3.attacks = {}\r\nfor _, a in ipairs(atkSt.attacks) do\r\nlocal b = {}\r\nfor k, v in pairs(a) do b[k] = v end\r\nif not b.spell then\r\nb.extras = {}\r\nfor _, x in ipairs(a.extras or {}) do b.extras[#b.extras + 1] = x end\r\nb.extras[#b.extras + 1] = { dice = cmd.dice, src = \"Commander's Strike\", cmdBy = cmd.by }\r\nend\r\ns3.attacks[#s3.attacks + 1] = b\r\nend\r\natkSt = s3\r\nend\r\nfor _, a in ipairs(atkSt.attacks) do if a.hit == hitB and (not a.nodmg or (noDmgW and ndOk(a))) then known[#known + 1] = a end end\r\nlocal ndA\r\nfor _, a in ipairs(known) do if a.nodmg then ndA = ndA or a end end\r\nif ndA and #known > 1 then for i2 = #known, 1, -1 do if not known[i2].nodmg then table.remove(known, i2) end end end\r\n\r\n\r\n\r\n\r\n\r\nlocal function stale(a)\r\nlocal k = (hitB and atkR) and (hitB - a.hit) or 0\r\nreturn k >= 1 and k <= K.lost(atkR, a.item)\r\nend\r\nlocal written = (f[7] or \"-\") ~= \"-\" and parseFormula(f[7])\r\nlocal rangeSet\r\nif written then\r\nlocal want = canon(written, false)\r\nlocal cl = Feat.cur.cleave and Feat.cur.cleave[f[1]]\r\n\r\n\r\nlocal function fits(a)\r\nfor _, crit in ipairs({ false, true }) do\r\nlocal function same(s)\r\nlocal q = parseFormula(s)\r\nreturn q ~= nil and canon(q, crit) == want\r\nend\r\nif a.adv and mode == \"adv\" and same(a.adv) then return true end\r\nlocal ex = a.extras or {}\r\nfor mask = 0, (1 << #ex) - 1 do\r\nlocal s, okm = a.dmg, true\r\nfor i = 1, #ex do\r\nif mask & (1 << (i - 1)) ~= 0 then\r\ns = s .. \"+\" .. ex[i].dice\r\n\r\nif (ex[i].plain and (mode == \"adv\" or mode == \"dis\")) or (ex[i].nat20 and nat ~= 20) then okm = false end\r\nend\r\nend\r\nif okm and same(s) then return true end\r\nif okm then\r\nfor i = 1, #ex do\r\nif mask & (1 << (i - 1)) ~= 0 and ex[i].less then\r\nfor _, s2 in ipairs(K.lessForms(s, ex[i].dice)) do if same(s2) then return true end end\r\nend\r\nend\r\nend\r\nend\r\nif a.mastery == \"Cleave\" and a.melee and cl and cl ~= f[2] then\r\nlocal q = parseFormula(a.dmg)\r\nq.mod = q.mod - math.max(0, a.mod or 0)\r\nif canon(q, crit) == want then return true end\r\nend\r\nend\r\nreturn false\r\nend\r\nlocal fit = false\r\nfor _, a in ipairs(known) do if fits(a) then fit = true break end end\r\nif fit then\r\nrangeSet = {}\r\nfor _, a in ipairs(known) do if fits(a) then rangeSet[#rangeSet + 1] = a end end\r\nelse\r\nlocal pick\r\nfor _, a in ipairs(atkSt.attacks) do\r\nif fits(a) and (not pick or (stale(a) and not stale(pick))) then pick = a end\r\nend\r\nif pick then\r\nif not stale(pick) then bad[#bad + 1] = string.format(\"hit %+d->%+d\", hitB or 0, pick.hit) end\r\nhitB, known = pick.hit, { pick }\r\nend\r\nend\r\nelse\r\nfor _, a in ipairs(atkSt.attacks) do\r\nif stale(a) then\r\nhitB, known = a.hit, { a }\r\nbreak\r\nend\r\nend\r\nend\r\nK.atkKindLast = K.kindOfSet(rangeSet or known, atkU.side == \"enemy\" or atkU.side == \"friend\")\r\nif #known == 0 then\r\nbad[#bad + 1] = string.format(\"hit %+d->%+d\", hitB or 0, atkSt.attacks[1].hit)\r\nhitB = atkSt.attacks[1].hit\r\nknown = atkSt.attacks\r\nend\r\n\r\n\r\nif #known > 1 and Spell.cur and Spell.cur.name and (Spell.cur.by or \"Player\") == ((atkR and atkR.name) or \"Player\") then\r\nfor i, a in ipairs(known) do\r\nif a.spell == Spell.cur.name and i > 1 then table.insert(known, 1, table.remove(known, i)); break end\r\nend\r\nend\r\n\r\nlocal acW, acLost = tonumber(f[5]), 0\r\nif tgtR and type(tgtR.equip) == \"table\" then\r\nacLost = K.lost(tgtR, tgtR.equip.armor) + (K.isShield(tgtR, tgtR.equip.off) and K.lost(tgtR, tgtR.equip.off) or 0)\r\nend\r\n\r\nlocal cov = K.coverOf(tgtU)\r\nlocal acT = K.coverAC(rangeSet or known, tgtSt.ac, cov, acW)\r\n\r\nif tgtU.side == \"enemy\" and tonumber(tgtU.acUp) then\r\nif (tonumber(c.round) or 1) > (tonumber(tgtU.acUpRound) or 0) + 1 then tgtU.acUp, tgtU.acUpWhy, tgtU.acUpKeep = nil, nil, nil\r\nelse acT = acT + tgtU.acUp end\r\nend\r\n\r\nlocal sfxAC = (tgtU.side == \"enemy\" and K.foeFx(tgtU, pc).ac or 0) - (tonumber(tgtU.strip) or 0)\r\nif sfxAC ~= 0 then\r\nacT = acT + sfxAC\r\nif acW == acT - sfxAC and type(Feat.cur.sfxNew) == \"table\" and Feat.cur.sfxNew[tgtU] then f[5], acW = tostring(acT), acT end\r\nend\r\nif f[5] == \"?\" then f[5], acW = tostring(acT), acT end\r\n\r\n\r\n\r\nlocal acOld\r\nif acW ~= acT and tgtR then\r\nlocal o = K.withOld(tgtR, function() return statsOf(tgtU, pc) end)\r\nacOld = o and K.coverAC(rangeSet or known, o.ac, cov, acW)\r\nend\r\n\r\nlocal cov0 = type(Feat.cur.cover0) == \"table\" and Feat.cur.cover0[f[2]]\r\nif acW ~= acT and acW ~= acOld and cov0 and cov0 ~= cov then acOld = K.coverAC(rangeSet or known, tgtSt.ac, cov0, acW) end\r\nlocal acBadAt\r\nif acW ~= acT and acW == acOld then\r\nf[5], acW = tostring(acT), acT\r\nelseif acW ~= acT and not (acW and acW > acT and acW - acT <= acLost) then\r\nbad[#bad + 1] = \"AC \" .. f[5] .. \"->\" .. acT\r\nacBadAt = #bad\r\nend\r\n\r\n\r\nlocal critOn = 20\r\nfor _, a in ipairs(known) do if a.critOn then critOn = math.min(critOn, a.critOn) end end\r\nif tgtR and K.PG and K.PG.showing(tgtR) then critOn = math.min(critOn, 18) end\r\nlocal result\r\nif nat >= critOn then result = \"crit\"\r\nelseif nat == 1 then result = \"miss\"\r\nelseif roll + hitB >= acT then result = \"hit\"\r\nelse result = \"miss\" end\r\n\r\nlocal gmr = tgtU.side == \"enemy\" and (MONSTERS[tgtU.kind or \"\"] or {}).mres == 2 and ((rangeSet and rangeSet[1]) or known[1] or {}).spell\r\nif gmr then result = \"miss\" end\r\n\r\nlocal pick0 = (rangeSet and rangeSet[1]) or known[1] or {}\r\nlocal refl = tgtU.side == \"enemy\" and (MONSTERS[tgtU.kind or \"\"] or {}).reflect and pick0.spell and pick0.srange == \"ranged\"\r\nif refl then result = \"miss\" end\r\n\r\n\r\n\r\n\r\nlocal rxNote = noAdvSrc and (\" (\" .. noAdvSrc .. \": no Advantage, the first d20)\") or \"\"\r\nif sundNote then rxNote = rxNote .. sundNote end\r\nif result == \"hit\" and f[6] == \"miss\" and tgtU.side == \"enemy\" then\r\nlocal tm = MONSTERS[tgtU.kind or \"\"] or {}\r\nlocal rx = tm.react or tm.shield\r\nlocal melee = false\r\nfor _, a in ipairs(rangeSet or known) do if a.melee or a.srange == \"melee\" then melee = true end end\r\nlocal left = tm.shield and tm.shield.uses and (tonumber(tgtU.shieldLeft) or tm.shield.uses) or 1\r\nif rx and (tm.reactive or tgtU.reactRound ~= (c.round or 1)) and left > 0 and (not rx.melee or melee) and roll + hitB < acT + rx.n\r\nand not K.foeCondFx(tgtU, pc).incap then\r\nresult = \"miss\"\r\ntgtU.reactRound = c.round or 1\r\n\r\n\r\nif acBadAt and acW == acT + rx.n then table.remove(bad, acBadAt); acBadAt = nil end\r\nif tm.shield then\r\nif tm.shield.uses then tgtU.shieldLeft = left - 1 end\r\ntgtU.acUp, tgtU.acUpRound, tgtU.acUpWhy = rx.n, c.round or 1, \"Shield, until its turn\"\r\nrxNote = string.format(\" (Shield: +%d AC until its turn)\", rx.n)\r\nelse\r\nrxNote = string.format(\" (%s: +%d AC)\", rx.name, rx.n)\r\nif rx.back then c.riposte = { by = f[2], vs = f[1] } end\r\nend\r\nend\r\nend\r\n\r\n\r\nif result == \"miss\" and f[6] == \"hit\" and atkR and not gmr and not refl then\r\nlocal ash = K.AR.sheetOf(atkR, pc)\r\nlocal inFight = type(c) == \"table\" and c.active\r\nif type(ash) == \"table\" and type(ash.picks) == \"table\" and ash.picks.boon == \"Boon of Combat Prowess\"\r\nand not (inFight and type(c.aim) == \"table\" and c.aim[f[1]] == (c.round or 1)) then\r\nresult = \"hit\"\r\nif inFight then c.aim = type(c.aim) == \"table\" and c.aim or {}; c.aim[f[1]] = c.round or 1 end\r\nrxNote = rxNote .. \" (Peerless Aim)\"\r\nend\r\nend\r\n\r\n\r\nlocal umAtk = K.useModTake(f[1], \"atk\")\r\nlocal umAdd, umSure = 0, false\r\nif umAtk and result == \"miss\" and not gmr and not refl and nat ~= 1 then\r\nif umAtk.auto_hit or roll + hitB + (umAtk.attack_bonus or 0) >= acT then\r\nresult = \"hit\"\r\numAdd, umSure = umAtk.attack_bonus or 0, umAtk.auto_hit and true or false\r\nrxNote = rxNote .. \" (\" .. umAtk.src .. (umAtk.attack_bonus and string.format(\": %+d\", umAtk.attack_bonus) or \"\") .. \")\"\r\nend\r\nelseif umAtk and result == \"hit\" and not gmr and not refl then\r\n\r\numAdd, umSure = umAtk.attack_bonus or 0, umAtk.auto_hit and true or false\r\nend\r\n\r\nlocal umMiss = not umSure and K.useModTake(f[2], \"miss\") or nil\r\nif umMiss and (result == \"hit\" or result == \"crit\") then\r\nresult = \"miss\"\r\nrxNote = rxNote .. \" (\" .. umMiss.src .. \": misses)\"\r\nend\r\nlocal umDef = result == \"hit\" and not umSure and K.useModTake(f[2], \"def\") or nil\r\nif umDef and roll + hitB + umAdd < acT + (umDef.ac_bonus or 0) then\r\nresult = \"miss\"\r\nrxNote = rxNote .. string.format(\" (%s: %+d AC)\", umDef.src, umDef.ac_bonus)\r\nend\r\n\r\n\r\nlocal downed = tgtR and tgtR.hp <= 0\r\n\r\nlocal foeCrit = tgtU.side == \"enemy\" and K.foeCondFx(tgtU, pc).crit\r\nif result == \"hit\" and (downed or (tgtR and Cond.fx(tgtR).crit) or foeCrit) and f[6] == \"crit\" then\r\nresult = \"crit\"\r\nif foeCrit then rxNote = rxNote .. \" (\" .. foeCrit .. \": a hit within 5 ft is a Critical Hit)\" end\r\nend\r\n\r\nif result == \"crit\" and tgtR and #K.MI.powers(tgtR, \"nocrit\") > 0 then result = \"hit\" end\r\n\r\n\r\nif f[6] == \"?\" then f[6] = result elseif f[6] ~= result then bad[#bad + 1] = \"result->\" .. result end\r\nif f[8] == \"?\" and result == \"miss\" then f[8] = \"-\" end\r\n\r\nif ndA then\r\nf[7], f[8], f[9] = \"-\", \"-\", \"0\"\r\nlocal cn = \"\"\r\nlocal cantAct = atkHp <= 0 and not (atkR and K.upNow(atkR)) or (atkR and fx.incap) or foeIncap\r\nif result ~= \"miss\" and not cantAct and tgtU and tgtU.side ~= \"pc\" and tgtU.side ~= \"ally\" then\r\ncn = K.foeCondApply(tgtU, ndA.spell, false, f[1] == \"Player\" and \"Player\" or f[1])\r\nend\r\ncn = \" (\" .. ndA.spell .. \")\" .. cn\r\nc.last = f[1]\r\nlocal hp = tgtR and (tgtR.dead and \"dead\" or (tgtR.hp .. \"/\" .. tgtR.max)) or ((tgtU and tgtU.hp or 0) .. \"/\" .. (tgtU and tgtU.max or 0))\r\nreturn string.format(\"[ATTACK|%s|%s|%s]\", table.concat(f, \"|\", 1, 9), verdictOf(bad), hp .. rxNote .. cn), #bad == 0\r\nend\r\nif f[7] == \"?\" then\r\nf[7] = result == \"miss\" and \"-\" or (result == \"crit\" and (known[1].dmg:gsub(\"(%d+)d(%d+)\", function(n, s) return (2 * tonumber(n)) .. \"d\" .. s end))\r\nor known[1].dmg)\r\nend\r\n\r\nlocal damage, extra = 0, \"\"\r\nlocal critPlain, critLoose\r\nlocal used, usedGiant\r\nlocal cleft = false\r\n\r\nif result ~= \"miss\" and atkR and tgtU then\r\nFeat.cur.lastHit = Feat.cur.lastHit or {}\r\nFeat.cur.lastHit[(atkR == pc and \"Player\") or atkR.name or \"Player\"] = tgtR or tgtU\r\nend\r\nif result ~= \"miss\" then\r\nlocal p = parseFormula(f[7])\r\nlocal allowed = false\r\nif p then\r\nlocal want = canon(p, false)\r\n\r\n\r\nlocal nW = 0\r\nif result == \"crit\" and not tostring(f[8] or \"\"):find(\"/\", 1, true) then for _ in tostring(f[8] or \"\"):gmatch(\"%-?%d+\") do nW = nW + 1 end end\r\nlocal function try(a, formula, picked, post)\r\nlocal q = parseFormula(formula)\r\nlocal nD, nN = 0, 0\r\nfor _, d in ipairs(q and q.dice or {}) do nD = nD + d.n end\r\nfor _, d in ipairs(q and q.neg or {}) do nN = nN + d.n end\r\nlocal hit1 = q and canon(q, result == \"crit\") == want\r\n\r\nif q and post and not hit1 then\r\nlocal qp = parseFormula(canon(q, result == \"crit\") .. \"+\" .. post)\r\nhit1 = qp and canon(qp, false) == want\r\nif hit1 then nD = nD + 0.5 end\r\nend\r\n\r\n\r\nif hit1 and result == \"crit\" and nW > 0 and nW ~= math.floor(2 * nD) + nN then\r\ncritLoose = critLoose or { a, picked }\r\nhit1 = false\r\nend\r\nlocal plain = false\r\nif not hit1 and q and result == \"crit\" and canon(q, false) == want then plain = nD > 0 and nW == 2 * nD + nN end\r\nif hit1 or plain then\r\nallowed = true\r\nif not used then used, usedGiant = a, picked; if plain then critPlain = q end end\r\nend\r\nend\r\n\r\n\r\nFeat.cur.cleave = Feat.cur.cleave or {}\r\nlocal cl = Feat.cur.cleave[f[1]]\r\nfor _, a in ipairs(known) do\r\nif a.mastery == \"Cleave\" and a.melee and cl and cl ~= f[2] then\r\nlocal q = parseFormula(a.dmg)\r\nq.mod = q.mod - math.max(0, a.mod or 0)\r\nif canon(q, result == \"crit\") == want and not allowed then\r\nallowed, used, cleft = true, a, true\r\nend\r\nend\r\nend\r\nfor _, a in ipairs(known) do\r\nif a.adv and mode == \"adv\" then try(a, a.adv) end\r\n\r\nlocal ex = a.extras or {}\r\nfor mask = 0, (1 << #ex) - 1 do\r\nlocal formula, picked, okm = a.dmg, {}, true\r\nlocal post\r\nlocal need = {}\r\nfor i = 1, #ex do\r\nif mask & (1 << (i - 1)) ~= 0 then\r\nif ex[i].critExtra then\r\npost = (post and (post .. \"+\") or \"\") .. ex[i].dice\r\nif result ~= \"crit\" then okm = false end\r\nelse\r\nformula = formula .. \"+\" .. ex[i].dice\r\nend\r\npicked[#picked + 1] = ex[i]\r\nif (ex[i].plain and (mode == \"adv\" or mode == \"dis\")) or (ex[i].nat20 and nat ~= 20) then okm = false end\r\nif ex[i].res then need[ex[i].res] = (need[ex[i].res] or 0) + (tonumber(ex[i].cost) or 1) end\r\nend\r\nend\r\nfor k, n in pairs(need) do\r\nif (tonumber(atkR and type(atkR.res) == \"table\" and atkR.res[k]) or 0) < n then okm = false end\r\nend\r\nif okm then\r\ntry(a, formula, picked, post)\r\nfor _, x in ipairs(picked) do\r\nif x.less then for _, f2 in ipairs(K.lessForms(formula, x.dice)) do try(a, f2, picked, post) end end\r\nend\r\nend\r\nend\r\nend\r\nend\r\nif not allowed and critLoose then allowed, used, usedGiant = true, critLoose[1], critLoose[2] end\r\nif critPlain and not cleft then\r\nfor _, x in ipairs(critPlain.dice) do x.n = x.n * 2 end\r\np = critPlain\r\nf[7] = K.formulaText(p)\r\nend\r\nif cleft then\r\np = parseFormula(used.dmg)\r\np.mod = p.mod - math.max(0, used.mod or 0)\r\nif result == \"crit\" then for _, x in ipairs(p.dice) do x.n = x.n * 2 end end\r\nFeat.cur.cleave[f[1]] = nil\r\nelseif not allowed then\r\nbad[#bad + 1] = \"formula \" .. f[7] .. \"->\" .. canon(parseFormula(known[1].dmg), result == \"crit\")\r\np = parseFormula(known[1].dmg)\r\nif result == \"crit\" then for _, x in ipairs(p.dice) do x.n = x.n * 2 end end\r\nend\r\n\r\nif not cleft and used and used.mastery == \"Cleave\" and used.melee then\r\nFeat.cur.cleave = Feat.cur.cleave or {}\r\nFeat.cur.cleave[f[1]] = f[2]\r\nend\r\n\r\nlocal a1 = used or known[1]\r\nK.MAXDICE = (Feat.cur.overchannel and a1 and a1.spell) and true or nil\r\n\r\n\r\nif not (f[8] or \"\"):find(\"/\", 1, true) and a1 and a1.weapon and not Feat.cur.savage[f[1]] then\r\nlocal shS = atkR and (atkR.sheet or SHEET)\r\nlocal q, vals, nd = parseFormula(f[7] or \"\"), {}, 0\r\nfor _, x in ipairs(K.diceSeq(q)) do nd = nd + x.n end\r\nfor v in (f[8] or \"\"):gmatch(\"%-?%d+\") do vals[#vals + 1] = v end\r\nif shS and Feat.has(shS, \"Savage Attacker\") and nd > 0 and #vals == 2 * nd then\r\nf[8] = table.concat(vals, \",\", 1, nd) .. \" / \" .. table.concat(vals, \",\", nd + 1)\r\nend\r\nend\r\nlocal set1, set2 = (f[8] or \"\"):match(\"^(.-)/(.*)$\")\r\nif not set1 then set1 = f[8] end\r\nlocal vals\r\nlocal pModel = K.wroteF(f[7], set1)\r\nlocal rawD\r\ndamage, vals, rawD = spendDice(p, set1, pools, cur, bad, pModel)\r\nif f[8] == \"?\" then\r\nlocal o = {}\r\nfor _, x in ipairs(vals or {}) do o[#o + 1] = tostring(x.v) end\r\nf[8] = #o > 0 and table.concat(o, \",\") or \"-\"\r\nend\r\ndamage, extra = Feat.gwf(a1, vals, (rawD and rawD < 0) and rawD or damage)\r\ndamage = math.max(0, damage)\r\nif a1 and a1.cutw then K.cutSpend(pc); extra = extra .. \" (Cutting Words)\" end\r\nif a1 and a1.min1 and damage < 1 then damage = 1 end\r\nif a1 and a1.spell then\r\ndamage = damage + K.adeptOnes(atkR or pc, a1.type, vals, result == \"crit\" and canon(parseFormula(a1.dmg) or { dice = {}, mod = 0 }, true) or a1.dmg)\r\nend\r\nK.hitVals = vals\r\nif set2 then\r\nlocal d2, v2 = spendDice(p, set2, pools, cur, bad, pModel)\r\nd2 = Feat.gwf(a1, v2, d2)\r\nlocal sh = atkR and (atkR.sheet or SHEET)\r\nif not (a1.weapon and sh and Feat.has(sh, \"Savage Attacker\")) then\r\nbad[#bad + 1] = \"two sets of dice only with Savage Attacker\"\r\nelseif Feat.cur.savage[f[1]] then\r\nbad[#bad + 1] = \"Savage Attacker once per reply\"\r\nelse\r\nFeat.cur.savage[f[1]] = true\r\nif d2 > damage then damage, vals = d2, v2; K.hitVals = v2 end\r\nextra = extra .. \" (Savage Attacker)\"\r\nend\r\nend\r\n\r\nfor _, x in ipairs(usedGiant or {}) do\r\n\r\n\r\nif (x.src == \"Brutal Strike\" or x.src == \"Improved Brutal Strike\") and atkR and K.cl(K.ownSheet(atkR, pc) or SHEET, \"Barbarian\") >= 13 then\r\nFeat.cur.sunder = Feat.cur.sunder or {}\r\nFeat.cur.sunder[f[2]] = f[1]\r\nend\r\nif x.cmdBy then Feat.cur.cmdUsed = Feat.cur.cmdUsed or {}; Feat.cur.cmdUsed[x.cmdBy] = true end\r\nif x.lashOf then x.lashOf.lash = nil end\r\nlocal xc = tonumber(x.cost) or 1\r\nif x.smite then Feat.cur.smiteAuto = Feat.cur.smiteAuto or {}; Feat.cur.smiteAuto[(atkR and atkR.name) or \"Player\"] = true end\r\nif x.res and atkR and type(atkR.res) == \"table\" and (atkR.res[x.res] or 0) >= xc then\r\natkR.res[x.res] = atkR.res[x.res] - xc\r\nif x.cost then extra = extra .. string.format(\" (%s: %s %d left)\", x.src or \"die\", x.res, atkR.res[x.res]) end\r\nend\r\nif x.once then\r\nFeat.cur.spent[((atkR and atkR.name) or \"Player\") .. \"|\" .. x.once] = true\r\n\r\nif atkR and type(atkR.lasting) == \"table\" then atkR.lasting[x.once] = nil end\r\nend\r\nend\r\nelseif known[1].mastery == \"Graze\" and atkHp > 0 then\r\n\r\ndamage, extra = math.max(0, known[1].mod or 0), \" (Graze)\"\r\nK.spendWritten(f, pools, cur)\r\nelseif known[1].spell and SPELLS[known[1].spell] and SPELLS[known[1].spell].level == 0 and atkHp > 0 and Feat.potent(atkR) then\r\n\r\nlocal p = parseFormula(known[1].dmg)\r\nif (f[7] or \"-\") == \"-\" then\r\nbad[#bad + 1] = \"Potent Cantrip: roll the damage on a miss and write half\"\r\nelse\r\nlocal given = parseFormula(f[7])\r\nif not given or canon(given, false) ~= canon(p, false) then bad[#bad + 1] = \"formula \" .. f[7] .. \"->\" .. canon(p, false) end\r\nlocal pd, pv = spendDice(p, f[8], pools, cur, bad, K.wroteF(f[7], f[8]))\r\nif known[1].spell then pd = pd + K.adeptOnes(atkR or pc, known[1].type, pv, known[1].dmg) end\r\ndamage = math.floor(pd / 2)\r\nextra = \" (Potent Cantrip)\"\r\nend\r\nelse\r\nK.spendWritten(f, pools, cur)\r\nend\r\n\r\n\r\n\r\nif c.underwater and mode ~= \"dis\" then\r\nlocal w = used or known[1] or {}\r\nlocal wd = WEAPONS[w.base or w.item or \"\"] or WEAPONS[w.name or \"\"]\r\nlocal swim = atkU.kind and MONSTERS[atkU.kind] and MONSTERS[atkU.kind].swim\r\nif wd and (wd.ranged or (not swim and wd.type ~= \"Piercing\")) then\r\nbad[#bad + 1] = \"underwater: \" .. (wd.ranged and \"a ranged weapon attack\" or \"a melee weapon that deals no Piercing damage\") .. \" has Disadvantage (dis A,B)\"\r\nend\r\nend\r\nif gmr then extra = extra .. \" (Greater Magic Resistance)\" end\r\nif refl then extra = extra .. \" (Reflective Carapace)\" end\r\nextra = extra .. rxNote .. pactNote\r\n\r\n\r\nlocal sa = used or known[1] or {}\r\nif not sa.stim and sa.weapon and atkR and K.AR and K.AR.on() then\r\nfor _, ac in ipairs(Spell.active(atkR)) do\r\nlocal wm = SPELLS[ac.name] and SPELLS[ac.name].m and SPELLS[ac.name].m.weapon_stim\r\nif wm and not ac.lost then sa = setmetatable({ stim = true, type = type(wm) == \"table\" and wm.type or sa.type }, { __index = sa }) end\r\nend\r\nend\r\nif sa.stim then\r\nif not K.AR.on() then bad[#bad + 1] = \"arousal is not in this game (no module brings it): nothing lands\" end\r\nif f[9] == \"?\" then f[9] = tostring(damage) elseif tonumber(f[9]) ~= damage and not (damage == 0 and trim(f[9] or \"\") == \"-\") then\r\nbad[#bad + 1] = \"stim \" .. tostring(f[9]) .. \"->\" .. damage\r\nend\r\nlocal text, more = sa.type .. \" -\", \"\"\r\nif K.AR.on() and result ~= \"miss\" and damage > 0 and atkHp > 0 and not (atkR and fx.incap) and not foeIncap then\r\nlocal t = tgtR or tgtU\r\ntext, more = K.AR.give(t, damage, pc, c, result == \"crit\", f[2], (atkR == pc and \"Player\") or (atkR and atkR.name) or f[1], { type = sa.type, magical = true })\r\ntext = sa.type .. \" \" .. text .. K.AR.drain(sa, atkR or atkU, tgtR, tgtU, pc, c, f[2])\r\nend\r\nif riposte then c.riposte = nil else c.last = f[1] end\r\nreturn string.format(\"[ATTACK|%s|%s|%s]\", table.concat(f, \"|\", 1, 9), verdictOf(bad), text .. extra) .. more, #bad == 0\r\nend\r\n\r\nlocal note\r\nlocal dodged = false\r\nlocal umMult = result ~= \"miss\" and damage > 0 and K.useModTake(f[1], \"mult\") or nil\r\nif umMult then damage = damage * umMult.dmg_mult; extra = extra .. string.format(\" (%s: x%s)\", umMult.src, tostring(umMult.dmg_mult)) end\r\nlocal raw, dtype = damage, (used or known[1] or {}).type\r\nlocal traits = tgtR and Feat.traits(tgtR) or MONSTERS[K.kindOf(tgtU, pc) or \"\"]\r\ntraits = K.pierce(traits, atkR)\r\n\r\n\r\nlocal a0 = used or known[1] or {}\r\nif a0.spell then\r\nlocal spN\r\ndtype, spN = K.spellDtype(dtype, traits, damage)\r\nextra = extra .. ((damage > 0 and result ~= \"miss\") and spN or \"\")\r\nend\r\n\r\nif atkR and damage > 0 then\r\nlocal swN\r\ndtype, swN = K.swapType(atkR, pc, { spell = a0.spell, form = a0.beast, unarmed = (a0.name or \"\"):match(\"^Unarmed Strike\") ~= nil, pact = a0.pact }, dtype, traits, damage)\r\nextra = extra .. swN\r\nend\r\n\r\n\r\nlocal vb = tgtU.side == \"enemy\" and (MONSTERS[tgtU.kind or \"\"] or {}).vulbless\r\nif vb and a0.weapon and atkR and type(atkR.buff) == \"table\" and type(atkR.buff.Bless) == \"table\" and K.buffBy(\"Bless\", nil, atkR) then\r\nlocal t2 = {}\r\nfor k, v in pairs(traits or {}) do t2[k] = v end\r\nt2.vul = {}\r\nfor _, x in ipairs((traits or {}).vul or {}) do t2.vul[#t2.vul + 1] = x end\r\nfor _, x in ipairs(vb) do t2.vul[#t2.vul + 1] = x end\r\ntraits = t2\r\nend\r\n\r\n\r\nlocal parts = {}\r\nif K.hitVals and damage > 0 then\r\nlocal taken = {}\r\nlocal function take(dice, ty)\r\nlocal lp = parseFormula(dice or \"\")\r\nif not lp then return end\r\nlocal part = 0\r\nfor _, d in ipairs(lp.dice) do\r\nlocal n = d.n * (result == \"crit\" and 2 or 1)\r\nfor i = #K.hitVals, 1, -1 do\r\nif n <= 0 then break end\r\nif not taken[i] and K.hitVals[i].s == d.s and not K.hitVals[i].neg then part = part + K.hitVals[i].v; taken[i] = true; n = n - 1 end\r\nend\r\nend\r\npart = part + (lp.mod or 0)\r\nif part > 0 then parts[#parts + 1] = { type = ty, n = part } end\r\nend\r\nif a0.lootDmg and a0.lootDie and a0.lootDmg ~= dtype then take(a0.lootDie, a0.lootDmg) end\r\nfor _, x in ipairs(usedGiant or {}) do if x.type and x.type ~= dtype then take(x.dice, x.type) end end\r\nend\r\nK.hitVals = nil\r\n\r\nlocal ss = a0.spell and atkR and K.spellStimOf(atkR, a0.spell, pc) or nil\r\nlocal ssx = \"\"\r\nif ss then\r\nnote = \"\"\r\nelseif #parts > 0 then\r\nlocal rest = damage\r\nfor _, x in ipairs(parts) do\r\nx.n = math.min(math.floor(x.n * (umMult and tonumber(umMult.dmg_mult) or 1)), rest)\r\nrest = rest - x.n\r\nend\r\nlocal w, n1 = Feat.adjust(traits, rest, dtype)\r\ndamage, note = w, n1\r\nfor _, x in ipairs(parts) do\r\nlocal l, n2 = Feat.adjust(traits, x.n, x.type)\r\ndamage = damage + l\r\nnote = note .. (n2 ~= \"\" and (\" (\" .. x.type .. \" part\" .. n2:gsub(\"^ %(\", \" \")) or \"\")\r\nif tgtU and tgtU.side == \"enemy\" then\r\nlocal m = MONSTERS[tgtU.kind] or {}\r\nfor _, s in ipairs(m.regen and m.regen.stop or {}) do if s == x.type and l > 0 then tgtU.burned = true end end\r\nend\r\nend\r\nelse\r\nK.ignoreRes = (a0.spell and K.adeptTypes((atkR and atkR.sheet) or SHEET)[dtype or \"\"]) and dtype or nil\r\ndamage, note, dtype = K.typedAdjust(traits, damage, dtype, a0.spell and SPELLS[a0.spell] and SPELLS[a0.spell].m)\r\nK.ignoreRes = nil\r\nend\r\nnote = extra .. note .. (acT > tgtSt.ac and K.coverNote(cov) or \"\")\r\n\r\nlocal resHas = false\r\nfor _, x in ipairs(tgtR and type(traits) == \"table\" and traits.res or {}) do if x == dtype then resHas = true end end\r\nlocal natural = not a0.spell and not WEAPONS[Canon.name(((a0.name or \"\"):gsub(\" %(.*%)$\", \"\")))] and not a0.weapon\r\nif tgtR and damage > 0 and atkU.side == \"enemy\" and natural and type(tgtR.buff) == \"table\" and not resHas then\r\nfor bn, b in pairs(tgtR.buff) do\r\nif type(b) == \"table\" and b.resist_natural then damage = math.floor(damage / 2); note = note .. \" (\" .. bn .. \": natural weapons resisted)\" break end\r\nend\r\nend\r\nlocal umRed = damage > 0 and K.useModTake(f[2], \"reduce\") or nil\r\nlocal preRed\r\nif umRed then\r\npreRed = damage\r\nlocal q = parseFormula(umRed.dmg_reduce) or { dice = {}, mod = 0 }\r\nlocal x = q.mod or 0\r\nfor _, dd in ipairs(q.dice) do for _ = 1, dd.n do x = x + K.d(dd.s) end end\r\ndamage = math.max(0, damage - x)\r\nnote = note .. string.format(\" (%s: -%d)\", umRed.src, x)\r\nend\r\n\r\n\r\nif tgtR and damage > 0 and not ss then\r\nlocal tsh = tgtR.sheet or SHEET\r\nlocal _, ta = gearOf(tgtR, (type(tgtR.equip) == \"table\" and tgtR.equip or {}).armor)\r\nfor _, e in ipairs(ta and Feat.fxOf(tsh, \"armor_reduce\") or {}) do\r\nlocal fits = not e.armor or ta.cat == e.armor\r\nlocal okT = false\r\nfor _, ty in ipairs(type(e.types) == \"table\" and e.types or { \"Bludgeoning\", \"Piercing\", \"Slashing\" }) do if ty == dtype then okT = true end end\r\nlocal x = (fits and okT) and K.fxNum(e.n, tsh, e.srcLv) or 0\r\nif x > 0 and damage > 0 then\r\npreRed = preRed or damage\r\ndamage = math.max(0, damage - x)\r\nnote = note .. string.format(\" (%s: -%d)\", e.src, x)\r\nend\r\nend\r\nend\r\n\r\nif tgtR and damage > 0 and not ss then\r\nlocal rx = K.resD4Take(tgtR, dtype, f[1], pools, cur, bad, pc)\r\nif rx then\r\npreRed = preRed or damage\r\ndamage = math.max(0, damage - rx.n)\r\nnote = note .. string.format(\" (%s: -%d)\", rx.src, rx.n)\r\nend\r\nend\r\nif tgtR and damage > 0 and not ss then\r\nlocal sh = tgtR.sheet or SHEET\r\nif K.cl(sh, \"Rogue\") >= 5 and not Feat.cur.dodge[f[2]] then\r\nFeat.cur.dodge[f[2]] = true\r\ndamage, note = math.floor(damage / 2), note .. \" (Uncanny Dodge)\"\r\ndodged = true\r\nend\r\nend\r\nif f[9] == \"?\" then f[9] = tostring(damage)\r\nelseif tonumber(f[9]) ~= damage then\r\n\r\n\r\nlocal old = tgtR and K.oldLanded(tgtR, raw, dtype)\r\nif old and dodged then old = math.floor(old / 2) end\r\nif old and tonumber(f[9]) == old then f[9] = tostring(damage)\r\n\r\nelseif preRed and (tonumber(f[9]) == preRed or tonumber(f[9]) == raw) then f[9] = tostring(damage)\r\nelse bad[#bad + 1] = \"damage \" .. tostring(f[9]) .. \"->\" .. damage end\r\nend\r\n\r\n\r\nif atkU.side == \"pc\" then\r\nlocal ammo\r\nif used then\r\nammo = used.ammo\r\nelse\r\n\r\nfor i, a in ipairs(known) do\r\nif i == 1 then ammo = a.ammo elseif a.ammo ~= ammo then ammo = nil; break end\r\nend\r\nend\r\nif ammo then\r\nif (pc.items[ammo] or 0) < 1 then\r\n\r\nfor i = #bad, 1, -1 do if bad[i]:match(\"^damage \") then table.remove(bad, i) end end\r\nbad[#bad + 1] = \"no \" .. ammo\r\ndamage, raw, f[9] = 0, 0, \"0\"\r\nelse\r\npc.items[ammo] = pc.items[ammo] - 1\r\nif pc.items[ammo] <= 0 then pc.items[ammo] = nil end\r\nend\r\nend\r\nend\r\n\r\n\r\n\r\nif atkHp <= 0 or (atkR and fx.incap) or foeIncap or sancNo or charmNo or calmNo then damage, raw = 0, 0 end\r\nnote = note .. sancEnd\r\n\r\n\r\nif a0.poisoned and (result == \"hit\" or result == \"crit\") and damage > 0 and atkR and type(atkR.buff) == \"table\" then\r\nlocal b = atkR.buff[\"Basic Poison\"]\r\nif type(b) == \"table\" then\r\nb.n = (tonumber(b.n) or 1) - 1\r\nif b.n <= 0 then atkR.buff[\"Basic Poison\"] = nil end\r\nnote = note .. \" (Basic Poison spent)\"\r\nend\r\nend\r\n\r\n\r\nif tgtR and not ss and (result == \"hit\" or result == \"crit\") and damage > 0 then\r\nlocal left = K.mirrorLeft(tgtR)\r\nif left > 0 then\r\nlocal rolls, any = {}, false\r\nfor _ = 1, left do\r\nlocal d = K.d(6)\r\nrolls[#rolls + 1] = tostring(d)\r\nif d >= 3 then any = true end\r\nend\r\nif any then\r\ndamage, raw = 0, 0\r\ntgtR.mirror.n = left - 1\r\nnote = note .. string.format(\" (Mirror Image: d6 %s, a duplicate is hit instead, %d left)\", table.concat(rolls, \",\"), left - 1)\r\nif left - 1 <= 0 then\r\nif type(tgtR.lasting) == \"table\" then tgtR.lasting[tgtR.mirror.spell or \"Mirror Image\"] = nil end\r\ntgtR.mirror = nil\r\nend\r\nelse\r\nnote = note .. string.format(\" (Mirror Image: d6 %s, no duplicate)\", table.concat(rolls, \",\"))\r\nend\r\nend\r\nend\r\nif tgtR and ss then\r\nlocal st\r\nst, ssx = K.spellStimGive(f[2], tgtR, damage, dtype, atkR, pc, c, result == \"crit\")\r\nhpText = (tgtR.dead and \"dead\" or (tgtR.hp .. \"/\" .. tgtR.max)) .. note .. st\r\nelseif tgtR then\r\nnote = note .. hurtPC(tgtR, damage, result == \"crit\")\r\nhpText = (tgtR.dead and \"dead\" or (tgtR.hp .. \"/\" .. tgtR.max)) .. note\r\nelse\r\nlocal was = tgtU.hp\r\nif ss then\r\nlocal st\r\nst, ssx = K.spellStimGive(f[2], tgtU, damage, dtype, atkR, pc, c, result == \"crit\")\r\nnote = note .. st\r\nelse\r\nK.koMelee = atkR ~= nil and a0 and a0.melee and true or nil\r\nnote = note .. K.hurtFoe(tgtU, raw, damage, dtype, result == \"crit\")\r\nK.koMelee = nil\r\nnote = note .. K.afterHit(c, f[2], tgtU, damage, raw, dtype, f[1], was, pc)\r\nif was > 0 and tgtU.hp == 0 then note = note .. Feat.blessing(atkR) end\r\nend\r\nhpText = tgtU.hp .. \"/\" .. tgtU.max .. note\r\nend\r\n\r\nif atkU.side == \"enemy\" and atkU.burned and atkHp > 0 then atkU.burned = nil end\r\nif riposte then c.riposte = nil else c.last = f[1] end\r\n\r\nif atkU.side == \"enemy\" and result ~= \"miss\" then c.hitBy = type(c.hitBy) == \"table\" and c.hitBy or {}; c.hitBy[f[2]] = f[1] end\r\nreturn string.format(\"[ATTACK|%s|%s|%s]\", table.concat(f, \"|\", 1, 9), verdictOf(bad), hpText) .. ssx, #bad == 0\r\nend\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\nfunction K.spellTerms(text, name, by, pc)\r\nif type(text) ~= \"string\" or not (text:find(\"MOD\", 1, true) or text:find(\"PB\", 1, true)) then return text end\r\nlocal function nums()\r\nlocal st = name and Spell.stats(name) or Spell.stats(nil)\r\nreturn (st and st.mod) or 0, PROF or 2\r\nend\r\nlocal mod, pb\r\nif by ~= nil and pc ~= nil then mod, pb = Ally.run(pc, by, nums) else mod, pb = nums() end\r\nlocal out = text:gsub(\"%f[%w]MOD%f[%W]\", tostring(mod)):gsub(\"%f[%w]PB%f[%W]\", tostring(pb)):gsub(\"%+%-\", \"-\")\r\nreturn out\r\nend\r\n\r\n\r\nfunction K.failText(m)\r\nlocal s = tostring(m.fail or \"\")\r\nif K.LITE then s = s:gsub(\"; its slot is not spent\", \"\") end\r\nreturn s\r\nend\r\n\r\nfunction K.castBy(src, pc)\r\nlocal n = Canon.name(src or \"\")\r\nfor _, x in ipairs(Feat.cur.casts or {}) do if x.name == n then return x.by and Ally.find(pc, x.by) or pc, n end end\r\nfor _, x in ipairs(Spell.all(pc)) do if x[1].name == n then return x[2], n end end\r\nreturn pc, SPELLS[n] and n or nil\r\nend\r\nfunction K.hpBuffWhat(name, m, lv, who)\r\n\r\nif tonumber(m.temp_share) then\r\nreturn string.format(\"Temporary HP %d in all, divided among up to %d creatures of Player's side as the caster picks: right after the CAST one\"\r\n.. \" [HEAL|Target|%s|N|-|N] each with its share (Lua gives them)\", m.temp_share, tonumber(m.targets) or 6, name)\r\nend\r\nlocal up = type(m.upcast) == \"table\" and (m.upcast.hp_bonus or m.upcast.temp_hp)\r\nlocal v = K.spellTerms(m.hp_bonus or m.temp_hp, name)\r\nlocal amt = tostring(v) .. (up and string.format(\" (+%s per level above %d%s)\", tostring(up), lv, type(v) == \"string\" and \", in the formula\" or \"\") or \"\")\r\n\r\nlocal form = (type(v) == \"number\" and type(up) ~= \"string\") and \"N|-|N\" or (tostring(v) .. (type(up) == \"string\" and (\"+\" .. up .. \" a level above\") or \"\") .. \"|dice|N\")\r\nlocal how = m.hp_bonus and (\"HP maximum and current HP +\" .. amt .. \" for \" .. ((m.dur_mins or 480) >= 1440 and\r\n(math.floor((m.dur_mins or 480) / 1440) .. \" day\") or (math.floor((m.dur_mins or 480) / 60) .. \" hours\"))) or (\"Temporary HP \" .. amt)\r\nreturn how .. (m.self and (\" for its caster: right after the CAST [HEAL|\" .. who .. \"|\" .. name .. \"|\" .. form .. \"]\")\r\nor (\", up to \" .. (m.targets or 1) .. \" targets: right after the CAST one [HEAL|Target|\" .. name .. \"|\" .. form .. \"] each\"))\r\n.. (m.hp_bonus and \" (Lua adds it and takes it off when it ends)\" or \"\")\r\nend\r\nfunction K.hpBuff(f, pools, cur, c, pc, name, m)\r\nlocal head = \"[HEAL|\" .. table.concat(f, \"|\", 1, 5)\r\nlocal function fail(why)\r\nK.spendRefused(pools, cur, nil, f[3], f[4])\r\nreturn head .. \"|bad:\" .. why .. \"|-]\", false\r\nend\r\nlocal t = Ally.rec(pc, f[1]) or K.healShim\r\nif not t then return fail(\"target must be Player or a companion\") end\r\nif t.dead then return fail((t.name or \"Player\") .. \" is dead\") end\r\nFeat.cur.hpbuff = Feat.cur.hpbuff or {}\r\nlocal casting, any = nil, false\r\nfor _, x in ipairs(Feat.cur.casts or {}) do\r\nif x.name == name then\r\nany = true\r\nlocal used, n = Feat.cur.hpbuff[x] or {}, 0\r\nfor _ in pairs(used) do n = n + 1 end\r\nif not casting and not used[t] and n < (m.self and 1 or (m.targets or 1)) then casting = x end\r\nend\r\nend\r\nif not casting then\r\nreturn fail(any and (name .. \" already reached its targets this casting\") or (\"cast \" .. name .. \" with CAST first\"))\r\nend\r\nlocal by = casting.by and Ally.find(pc, casting.by) or pc\r\nif m.self and t ~= by then return fail(name .. \" is only for its caster\") end\r\n\r\nif tonumber(m.temp_share) then\r\nlocal n = tonumber(trim(f[5] or \"\"))\r\nif not n or n < 1 then return fail(\"write its share: [HEAL|Target|\" .. name .. \"|N|-|N]\") end\r\nFeat.cur.hpShare = Feat.cur.hpShare or {}\r\nlocal was = Feat.cur.hpShare[casting] or 0\r\nif was + n > m.temp_share then return fail(string.format(\"%d Temporary HP in all: %d left\", m.temp_share, m.temp_share - was)) end\r\nFeat.cur.hpShare[casting] = was + n\r\nlocal bad0 = {}\r\nif trim(f[3] or \"\") ~= tostring(n) then bad0[#bad0 + 1] = \"formula \" .. tostring(f[3]) .. \"->\" .. n end\r\nt.thp = math.max(tonumber(t.thp) or 0, n)\r\nlocal used0 = Feat.cur.hpbuff[casting] or {}\r\nused0[t] = true\r\nFeat.cur.hpbuff[casting] = used0\r\nif c.active then c.last = by.name or \"Player\" end\r\nreturn head .. \"|\" .. verdictOf(bad0) .. \"|\" .. t.hp .. \"/\" .. t.max .. \", \" .. t.thp .. \" temporary HP (\" .. (m.temp_share - was - n) .. \" left to give)]\", #bad0 == 0\r\nend\r\nlocal lv = tonumber(casting.level) or SPELLS[name].level\r\nlocal v = K.spellTerms(m.hp_bonus or m.temp_hp, name, by, pc)\r\nlocal up = type(m.upcast) == \"table\" and (m.upcast.hp_bonus or m.upcast.temp_hp) or 0\r\nlocal above = math.max(0, lv - SPELLS[name].level)\r\nlocal extra = tonumber(up) and (tonumber(up) * above) or 0\r\n\r\nlocal upN, upS\r\nif type(up) == \"string\" then upN, upS = up:match(\"^(%d*)d(%d+)$\") end\r\nif upS and above > 0 then\r\nv = tostring(v) .. \"+\" .. ((tonumber(upN) or 1) * above) .. \"d\" .. upS\r\nif type(m.hp_bonus or m.temp_hp) == \"number\" then v = tostring(m.hp_bonus or m.temp_hp) .. \"+\" .. ((tonumber(upN) or 1) * above) .. \"d\" .. upS end\r\nend\r\nlocal bad, amount = {}, 0\r\nif type(v) == \"number\" or tonumber(v) then\r\namount = tonumber(v) + extra\r\nif trim(f[3] or \"\") ~= tostring(amount) then bad[#bad + 1] = \"formula \" .. tostring(f[3]) .. \"->\" .. amount end\r\nelse\r\nlocal want = parseFormula(v .. (extra > 0 and (\"+\" .. extra) or \"\"))\r\nlocal given = parseFormula(f[3] or \"\")\r\nif not given or canon(given, false) ~= canon(want, false) then bad[#bad + 1] = \"formula \" .. tostring(f[3]) .. \"->\" .. canon(want, false) end\r\n\r\nK.MAXDICE = (name == \"False Life\" and Ally.run(pc, by, function() return Feat.invoked(SHEET, \"Fiendish Vigor\") end)) or nil\r\namount = spendDice(want, f[4], pools, cur, bad, K.wroteF(f[3], f[4]))\r\nK.MAXDICE = nil\r\nend\r\nif tonumber(f[5]) ~= amount then bad[#bad + 1] = \"amount \" .. tostring(f[5]) .. \"->\" .. amount end\r\nif m.hp_bonus then\r\nt.buff = type(t.buff) == \"table\" and t.buff or {}\r\nlocal old = t.buff[name]\r\nif type(old) == \"table\" and tonumber(old.maxhp) then t.max = t.max - old.maxhp; t.hp = math.min(t.hp, t.max) end\r\nt.buff[name] = { maxhp = amount, ends = (tonumber(K.replyClock) or 0) + (m.dur_mins or 480), res = m.resist, cimm = m.cimm }\r\nt.max = t.max + amount\r\nif t.hp <= 0 then t.ds = { s = 0, f = 0 }; t.stable = false end\r\nt.hp = math.max(0, t.hp) + amount\r\nt.wake = nil\r\nelse\r\nt.thp = math.max(tonumber(t.thp) or 0, amount)\r\nend\r\nlocal used = Feat.cur.hpbuff[casting] or {}\r\nused[t] = true\r\nFeat.cur.hpbuff[casting] = used\r\nif c.active then c.last = by.name or \"Player\" end\r\nreturn head .. \"|\" .. verdictOf(bad) .. \"|\" .. t.hp .. \"/\" .. t.max .. ((tonumber(t.thp) or 0) > 0 and (\", \" .. t.thp .. \" temporary HP\") or \"\") .. \"]\", #bad == 0\r\nend\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\nfunction K.hdGain(pc, who, n, clock)\r\nn = tonumber(n) or 0\r\nif n < 1 then return end\r\nlocal now = tonumber(clock and clock.min) or 0\r\nif type(pc.echo) ~= \"table\" or pc.echo.at ~= now then pc.echo = { at = now, list = {} } end\r\npc.echo.list[#pc.echo.list + 1] = { who = who, n = n }\r\nend\r\nfunction K.echoOpen(pc, c, clock)\r\nlocal e = type(pc) == \"table\" and pc.echo\r\nif type(e) ~= \"table\" or type(e.list) ~= \"table\" or #e.list == 0 or (type(c) == \"table\" and c.active) then return nil end\r\nlocal now = tonumber(clock and clock.min)\r\nif now and now - (tonumber(e.at) or 0) > 10 then return nil end\r\nreturn e.list\r\nend\r\n\r\nfunction K.echoBy(pc, name)\r\nfor _, r in ipairs({ pc, table.unpack(Ally.list(pc)) }) do\r\nif not r.dead and (tonumber(r.hp) or 0) > 0 then\r\nfor _, e in ipairs(Feat.fxOf(r.sheet or SHEET, \"heal_echo\")) do\r\nif name == nil or e.src == name then return r, e.src end\r\nend\r\nend\r\nend\r\nreturn nil\r\nend\r\n\r\nfunction K.echoText(pc, clock, c)\r\nlocal list = K.echoOpen(pc, c, clock)\r\nif not list then return nil end\r\nlocal by, name = K.echoBy(pc)\r\nif not by then return nil end\r\nlocal o = {}\r\nfor _, x in ipairs(list) do o[#o + 1] = x.who .. \" \" .. x.n end\r\nreturn string.format(\"%s open (%s's Reaction; HP just regained from Hit Point Dice, one HEAL for each, on another creature than that one): %s.\",\r\nname, by.name or \"Player\", table.concat(o, \", \"))\r\nend\r\nfunction K.healBonus(healer, t, slot)\r\nif type(healer) ~= \"table\" or type(t) ~= \"table\" then return 0, nil end\r\nlocal sh = healer.sheet or SHEET\r\nif type(sh) ~= \"table\" or not sh.class then return 0, nil end\r\nlocal n, src = 0, nil\r\nfor _, e in ipairs(Feat.fxOf(sh, \"heal_bonus\")) do\r\nlocal fits = not (e.slot and (tonumber(slot) or 0) < 1)\r\nif fits and e.buff then\r\nlocal b = type(t.buff) == \"table\" and t.buff[e.buff]\r\nlocal now = K.clockRef and tonumber(K.clockRef.min)\r\nfits = type(b) == \"table\" and b.by == (healer.name or \"Player\") and not (b.ends and now and b.ends <= now)\r\nend\r\n\r\nif fits and type(e.if_cond) == \"table\" and K.AR then\r\nlocal hc, tc = K.AR.condsOf(healer), K.AR.condsOf(t)\r\nfits = false\r\nfor _, cn in ipairs(e.if_cond) do if hc[cn] or tc[cn] then fits = true end end\r\nend\r\nif fits then\r\n\r\nlocal v\r\nif type(e.amount) == \"string\" and e.amount:find(\"%dd%d\") and Feat.cur then\r\nFeat.cur.hbRoll = Feat.cur.hbRoll or {}\r\nlocal key = tostring(healer.name or \"Player\") .. \"|\" .. tostring(e.src) .. \"|\" .. tostring(e.amount) .. \"|\" .. tostring(t)\r\nFeat.cur.hbRoll[key] = Feat.cur.hbRoll[key] or K.fxRoll(e.amount, sh, e.srcLv)\r\nv = Feat.cur.hbRoll[key]\r\nelse\r\nv = K.fxNum(e.amount, sh, e.srcLv)\r\nend\r\nn = n + v; src = e.src\r\nif e.stim and Feat.cur then Feat.cur.healStim = Feat.cur.healStim or {}; Feat.cur.healStim[t] = { n = v, src = e.src } end\r\nend\r\nend\r\nreturn math.max(0, n), src\r\nend\r\nlocal function verifyHeal0(f, pools, cur, c, pc)\r\n\r\n\r\nlocal foe = type(c.units) == \"table\" and c.units[f[1] or \"\"]\r\nif foe and foe.side == \"enemy\" then return K.foeHeal(f, pools, cur, c, foe) end\r\nif K.LITE and ((f[2] or \"\"):lower() == \"rest\" or f[2] == \"휴식\") then return K.MP.restHeal(f, c, pc) end\r\nlocal hsName = Canon.name(f[2] or \"\")\r\nlocal hsM = SPELLS[hsName] and SPELLS[hsName].m\r\nif hsM and (hsM.hp_bonus or hsM.temp_hp or hsM.temp_share) then return K.hpBuff(f, pools, cur, c, pc, hsName, hsM) end\r\n\r\nif hsM and hsM.raise then\r\nK.spendRefused(pools, cur, nil, f[3], f[4])\r\nreturn \"[HEAL|\" .. table.concat(f, \"|\", 1, 5) .. \"|bad:bring back the dead with [REVIVE|\" .. (f[1] or \"Target\") .. \"|\" .. hsName\r\n.. \"] right after its CAST, not HEAL|-]\", false\r\nend\r\nlocal bad = {}\r\nlocal src = HEAL_SRC[f[2]]\r\nlocal spell, caster, casting = false, nil, nil\r\nif not src then\r\nfor _, x in ipairs(Spell.all(pc)) do\r\nlocal a = x[1]\r\nlocal m = a.name == f[2] and SPELLS[a.name] and SPELLS[a.name].m\r\nif m and (m.heal_all or m.heal_share) and not spell then\r\ncaster, casting = x[2], a\r\nsrc = { dmg = \"0\", all = m.heal_all, share = m.heal_share }\r\nspell = true\r\nelseif m and m.heal and not spell then\r\ncaster, casting = x[2], a\r\nsrc = { dmg = Ally.run(pc, caster, function()\r\nlocal base = Spell.formula(a.name, m.heal, a.level)\r\n\r\nlocal slotted = a.slot == true or (a.slot == nil and (a.level or 0) >= 1)\r\nif K.subHas(SHEET, \"Disciple of Life\") and slotted then\r\nbase = canon(parseFormula(base .. \"+\" .. (2 + a.level)), false)\r\nend\r\nlocal hb = K.healBonus(caster, Ally.rec(pc, f[1]), slotted and a.level or 0)\r\nif hb > 0 then base = canon(parseFormula(base .. \"+\" .. hb), false) end\r\nreturn base\r\nend) }\r\nspell = true\r\nend\r\nend\r\nend\r\n\r\nif src and src.packFx then\r\nlocal tt = Ally.rec(pc, f[1] or \"\") or K.healShim\r\nif not tt or tt.dead then\r\nK.spendRefused(pools, cur, nil, f[3], f[4])\r\nreturn \"[HEAL|\" .. table.concat(f, \"|\", 1, 5) .. \"|bad:\" .. (tt and ((f[1] or \"\") .. \" is dead\") or \"target must be Player, a companion or a helper\") .. \"|-]\", false\r\nend\r\nlocal own, hasAny\r\n\r\n\r\nlocal function slotHeals(r)\r\nlocal n = 0\r\nfor _, x in ipairs(Feat.cur.casts or {}) do\r\nlocal m = SPELLS[x.name or \"\"] and SPELLS[x.name].m\r\nif (x.by or \"Player\") == (r.name or \"Player\") and x.slot and type(m) == \"table\" and (m.heal or m.heal_all or m.heal_share) then n = n + 1 end\r\nend\r\nreturn n - ((Feat.cur.healAfter or {})[src.packFx .. \"|\" .. tostring(r.name or \"Player\")] or 0)\r\nend\r\nfor _, r in ipairs({ pc, table.unpack(Ally.list(pc)) }) do\r\nlocal sh = (r == pc and SHEET) or r.sheet\r\nlocal has = false\r\nfor _, e in ipairs(sh and Feat.fxOf(sh, \"heal_source\") or {}) do if (e.name or e.src) == src.packFx then has = true end end\r\nif has then hasAny = true end\r\nif not own and has and not r.dead and (not src.pool or (type(r.res) == \"table\" and (r.res[src.pool] or 0) > 0))\r\nand (src.after ~= \"heal_slot\" or slotHeals(r) > 0) then own = r end\r\nif own == r and src.selfOnly and Ally.rec(pc, f[1] or \"\") ~= r then own = nil end\r\nend\r\nif not own and hasAny and src.after == \"heal_slot\" then\r\nK.spendRefused(pools, cur, nil, f[3], f[4])\r\nreturn \"[HEAL|\" .. table.concat(f, \"|\", 1, 5) .. \"|bad:\" .. src.packFx .. \": once for each healing spell cast with a slot in this reply, after its CAST|-]\", false\r\nend\r\nif not own then\r\nK.spendRefused(pools, cur, nil, f[3], f[4])\r\nreturn \"[HEAL|\" .. table.concat(f, \"|\", 1, 5) .. \"|bad:no one in the party has \" .. src.packFx .. (src.pool and (\" with \" .. src.pool .. \" left\") or \"\") .. \"|-]\", false\r\nend\r\n\r\n\r\nif src.after == \"heal_slot\" then\r\nFeat.cur.healAfter = Feat.cur.healAfter or {}\r\nlocal k = src.packFx .. \"|\" .. tostring(own.name or \"Player\")\r\nFeat.cur.healAfter[k] = (Feat.cur.healAfter[k] or 0) + 1\r\nend\r\n\r\nlocal hitT = Feat.cur.lastHit and Feat.cur.lastHit[(own == pc and \"Player\") or own.name or \"Player\"]\r\nlocal tTerm, tMiss = false, false\r\nlocal tDmg = src.dmg:gsub(\"%f[%a]T(%u%u%u)%f[%A]\", function(a3)\r\nif not ABBR[a3] then return nil end\r\ntTerm = true\r\nif not hitT then tMiss = true; return \"0\" end\r\nreturn tostring(math.max(0, K.abModOf(hitT, ABBR[a3], pc)))\r\nend)\r\nif tMiss then\r\nK.spendRefused(pools, cur, nil, f[3], f[4])\r\nreturn \"[HEAL|\" .. table.concat(f, \"|\", 1, 5) .. \"|bad:\" .. src.packFx .. \" heals by the numbers of the creature it hit: write it after that hit (ATTACK or ADVANCE), in the same reply|-]\", false\r\nend\r\nlocal dmg = Ally.run(pc, own ~= pc and own or nil, function()\r\nlocal lv = K.charLevel(SHEET)\r\n\r\nlocal fx = tDmg:gsub(\"%f[%a]MA%f[%A]\", function() return tostring(K.rowOf(SHEET, \"Monk\").martial_arts or \"1d6\") end)\r\n:gsub(\"(%u%u%u)|(%u%u%u)\", function(a1, a2) return tostring(K.fxNum(a1 .. \"|\" .. a2, SHEET)) end)\r\n:gsub(\"LEVEL\", tostring(lv)):gsub(\"PB\", tostring(PROF)):gsub(\"CON\", tostring(MOD.Constitution)):gsub(\"WIS\", tostring(MOD.Wisdom))\r\n:gsub(\"CHA\", tostring(MOD.Charisma)):gsub(\"INT\", tostring(MOD.Intelligence)):gsub(\"DEX\", tostring(MOD.Dexterity)):gsub(\"STR\", tostring(MOD.Strength))\r\n\r\nlocal p = { dice = {}, mod = 0 }\r\nfor sign, part in (\"+\" .. fx:gsub(\"%s\", \"\")):gmatch(\"([%+%-])([^%+%-]+)\") do\r\nlocal dn, ds = part:match(\"^(%d*)d(%d+)$\")\r\nif dn then p.dice[#p.dice + 1] = { n = tonumber(dn) or 1, s = tonumber(ds) }\r\nelseif tonumber(part) then p.mod = p.mod + (sign == \"-\" and -1 or 1) * tonumber(part) end\r\nend\r\nif #p.dice > 0 then for _, at in ipairs(src.dice_at or {}) do if lv >= (tonumber(at) or 99) then p.dice[1].n = p.dice[1].n + 1 end end end\r\nreturn canon(p, false)\r\nend)\r\nif src.pool then own.res[src.pool] = own.res[src.pool] - 1 end\r\nsrc = { dmg = dmg, free = true, nonmagical = src.nonmagical, tTerm = tTerm }\r\nend\r\n\r\nif not src then\r\nlocal now = K.clockRef and tonumber(K.clockRef.min) or 0\r\nfor _, r in ipairs({ pc, table.unpack(Ally.list(pc)) }) do\r\nlocal h = type(r.heals) == \"table\" and r.heals[f[2] or \"\"]\r\n\r\nlocal held = not (type(h) == \"table\" and h.conc) or (type(r.conc) == \"table\" and r.conc.name == (f[2] or \"\") and not r.conc.lost)\r\nif not src and type(h) == \"table\" and (tonumber(h.ends) or 0) > now and held then src = { dmg = h.formula, free = true } end\r\nend\r\nend\r\nlocal head = \"[HEAL|\" .. table.concat(f, \"|\", 1, 5)\r\n\r\nlocal t = Ally.rec(pc, f[1]) or K.healShim\r\n\r\n\r\nlocal user\r\n\r\n\r\n\r\nlocal poolBy, poolLeft = nil, nil\r\nif not src and K.AR and K.AR.on() then poolBy, poolLeft = K.AR.poolOf(pc, Canon.name(f[2] or \"\")) end\r\nif poolBy then\r\nlocal tr = t\r\nlocal n = tonumber(f[3] or \"\")\r\nlocal pn = Canon.name(f[2] or \"\")\r\nif not tr then return head .. \"|bad:target must be Player, a companion or a helper|-]\", false end\r\nif tr.dead then return head .. \"|bad:\" .. f[1] .. \" is dead|-]\", false end\r\nif not n or n < 1 or n ~= math.floor(n) then return head .. \"|bad:write the amount: [HEAL|\" .. f[1] .. \"|\" .. pn .. \"|N|-|N], at most \" .. poolLeft .. \"|-]\", false end\r\nlocal bad2 = {}\r\nif n > poolLeft then bad2[#bad2 + 1] = \"amount \" .. n .. \"->\" .. poolLeft .. \" (what is left of it)\"; n = poolLeft end\r\nlocal wOk, wWant = K.healWrote(f[5], n, tr)\r\nif not wOk then bad2[#bad2 + 1] = \"amount \" .. tostring(f[5]) .. \"->\" .. wWant end\r\nlocal leftNow = K.AR.poolTake(poolBy, pn, n)\r\nlocal was = tr.hp\r\nif was <= 0 then tr.ds, tr.stable, tr.wake = { s = 0, f = 0 }, false, nil end\r\ntr.hp = math.max(0, tr.hp)\r\nhealPC(tr, n)\r\nreturn head .. \"|\" .. verdictOf(bad2) .. \"|\" .. tr.hp .. \"/\" .. tr.max .. string.format(\" (%s: %d left)\", pn, leftNow) .. (K.healRecvLast or \"\") .. \"]\", #bad2 == 0\r\nend\r\nlocal echoBy = not src and K.echoBy(pc, Canon.name(f[2] or \"\"))\r\nif echoBy then\r\nlocal tr = t\r\nlocal n = tonumber(f[3] or \"\")\r\nlocal list = K.echoOpen(pc, c, K.clockRef)\r\nif not tr then return head .. \"|bad:target must be Player, a companion or a helper|-]\", false end\r\nif tr.dead then return head .. \"|bad:\" .. f[1] .. \" is dead|-]\", false end\r\nif not list then return head .. \"|bad:no Hit Point Dice spent just now (a Short Rest's, 10 minutes at most, outside a fight)|-]\", false end\r\nlocal tn, pick, own, open = tr.name or \"Player\", nil, false, {}\r\nfor i, x in ipairs(list) do\r\nopen[#open + 1] = x.who .. \" \" .. x.n\r\nif n and tonumber(x.n) == n then\r\nif x.who == tn then own = true elseif not pick then pick = i end\r\nend\r\nend\r\nif not pick then\r\nreturn head .. \"|bad:\" .. (own and (\"not on \" .. tn .. \", who regained it\") or (\"N is one of the HP just regained: \" .. table.concat(open, \", \"))) .. \"|-]\", false\r\nend\r\ntable.remove(list, pick)\r\nlocal hb, hbSrc = K.healBonus(echoBy, tr, 0)\r\nlocal wOk, wWant = K.healWrote(f[5], n + hb, tr)\r\nif not wOk then bad[#bad + 1] = \"amount \" .. tostring(f[5]) .. \"->\" .. wWant end\r\nhealPC(tr, n + hb)\r\ntr.wake = nil\r\nreturn head .. \"|\" .. verdictOf(bad) .. \"|\" .. tr.hp .. \"/\" .. tr.max .. (hb > 0 and string.format(\" (%s +%d)\", hbSrc or \"bonus\", hb) or \"\") .. (K.healRecvLast or \"\") .. \"]\", #bad == 0\r\nend\r\n\r\n\r\nif src and src.preserve and t then\r\nFeat.cur.preserve = Feat.cur.preserve or {}\r\nlocal pv = Feat.cur.preserve\r\nif not pv.user then\r\nfor _, r in ipairs({ pc, table.unpack(Ally.list(pc)) }) do\r\nlocal sh = r.sheet or SHEET\r\nif not pv.user and K.subHas(sh, \"Preserve Life\") and not r.dead and (r.hp or 0) > 0 and not Cond.fx(r).incap\r\nand type(r.res) == \"table\" and (r.res[\"Channel Divinity\"] or 0) > 0 then pv.user = r end\r\nend\r\nif not pv.user then return head .. \"|bad:no Channel Divinity left (a Life Domain Cleric's, level 3 or more)|-]\", false end\r\npv.user.res[\"Channel Divinity\"] = pv.user.res[\"Channel Divinity\"] - 1\r\npv.left = 5 * K.cl(pv.user.sheet or SHEET, \"Cleric\")\r\nend\r\nlocal n = tonumber(f[3] or \"\")\r\nif not n or n < 1 then return head .. \"|bad:write the HP as the formula: [HEAL|target|Preserve Life|N|-|N]|-]\", false end\r\nif t.dead then return head .. \"|bad:\" .. f[1] .. \" is dead|-]\", false end\r\nlocal hp, half = math.max(0, t.hp), math.floor(t.max / 2)\r\nif hp * 2 > t.max then return head .. \"|bad:\" .. f[1] .. \" is not Bloodied (more than half its HP)|-]\", false end\r\nlocal give = math.min(n, pv.left, half - hp)\r\nif give < n then\r\nbad[#bad + 1] = string.format(\"formula %d->%d (%s)\", n, give, give == pv.left and (pv.left .. \" HP left of this Preserve Life\")\r\nor (\"no higher than half its maximum, \" .. half))\r\nend\r\nlocal hb = K.healBonus(pv.user, t, 0)\r\nlocal wOk, wWant = K.healWrote(f[5], give + hb, t)\r\nif not wOk then bad[#bad + 1] = \"amount \" .. tostring(f[5]) .. \"->\" .. wWant end\r\npv.left = pv.left - give\r\nhealPC(t, give + hb)\r\nt.wake = nil\r\nif c.active then c.last = pv.user.name or \"Player\" end\r\nreturn head .. \"|\" .. verdictOf(bad) .. \"|\" .. t.hp .. \"/\" .. t.max .. string.format(\" (Preserve Life: %d left)\", pv.left) .. (K.healRecvLast or \"\") .. \"]\", #bad == 0\r\nend\r\n\r\n\r\nif src and src.vigor and t then\r\nlocal by\r\nfor _, r in ipairs({ pc, table.unpack(Ally.list(pc)) }) do\r\nlocal sh = r.sheet or SHEET\r\nlocal p = type(sh.picks) == \"table\" and sh.picks or {}\r\nif not by and K.cl(sh, \"Cleric\") >= 14 and p.blessed == \"Potent Spellcasting\" and not r.dead then by = r end\r\nend\r\nif not by then return head .. \"|bad:a Cleric of level 14 or more with Potent Spellcasting gives this|-]\", false end\r\nlocal hit = Feat.cur.cantripHit and Feat.cur.cantripHit[by.name or \"Player\"]\r\nlocal isCleric = false\r\nfor _, cl in ipairs(hit and SPELLS[hit] and SPELLS[hit].classes or {}) do if cl == \"Cleric\" then isCleric = true end end\r\nif not isCleric then return head .. \"|bad:no Cleric cantrip of \" .. (by.name or \"Player\") .. \"'s dealt damage in this reply (its SAVE first)|-]\", false end\r\nFeat.cur.vigor = Feat.cur.vigor or {}\r\nif Feat.cur.vigor[by] then return head .. \"|bad:once per casting|-]\", false end\r\nFeat.cur.vigor[by] = true\r\nlocal n = 2 * math.max(0, Ally.run(pc, by, function() return MOD.Wisdom end) or 0)\r\nif tonumber(f[3]) ~= n then bad[#bad + 1] = \"formula \" .. tostring(f[3]) .. \"->\" .. n end\r\nif tonumber(f[5]) ~= n then bad[#bad + 1] = \"amount \" .. tostring(f[5]) .. \"->\" .. n end\r\nt.thp = math.max(tonumber(t.thp) or 0, n)\r\nreturn head .. \"|\" .. verdictOf(bad) .. \"|\" .. t.hp .. \"/\" .. t.max .. \", \" .. t.thp .. \" temporary HP]\", #bad == 0\r\nend\r\n\r\nif src and src.points and t then\r\nlocal n = tonumber(f[3] or \"\")\r\nlocal cands = { pc, table.unpack(Ally.list(pc)) }\r\nfor _, r in ipairs(cands) do\r\nlocal sh = r.sheet or SHEET\r\nif not user and K.cl(sh, src.class) > 0 and not r.dead and r.hp > 0 and not Cond.fx(r).incap and type(r.res) == \"table\" and (r.res[src.points] or 0) >= (n or 1) then user = r end\r\nend\r\nif not n or n < 1 then\r\nbad[#bad + 1] = \"write the points as the formula: [HEAL|target|Lay On Hands|5|-|5]\"\r\nelseif not user then\r\nbad[#bad + 1] = K.LITE and \"not enough MP for Lay On Hands (1 per 5 HP)\" or \"not enough Lay On Hands points\"\r\nend\r\nif #bad > 0 then return \"[HEAL|\" .. table.concat(f, \"|\", 1, 5) .. \"|bad:\" .. table.concat(bad, \";\") .. \"|-]\", false end\r\nuser.res[src.points] = user.res[src.points] - n\r\nlocal hb, hbSrc = K.healBonus(user, t, 0)\r\nlocal wOk, wWant = K.healWrote(f[5], n + hb, t)\r\nif not wOk then bad[#bad + 1] = \"amount \" .. tostring(f[5]) .. \"->\" .. wWant end\r\nhealPC(t, n + hb)\r\nt.wake = nil\r\nif c.active then c.last = user.name or \"Player\" end\r\nreturn \"[HEAL|\" .. table.concat(f, \"|\", 1, 5) .. \"|\" .. verdictOf(bad) .. \"|\" .. t.hp .. \"/\" .. t.max\r\n.. (hb > 0 and string.format(\" (%s +%d)\", hbSrc or \"bonus\", hb) or \"\") .. (K.healRecvLast or \"\") .. \"]\", #bad == 0\r\nend\r\n\r\nif src and src.class and not src.pool and not src.points and t then\r\nlocal sh = t.sheet or SHEET\r\nif K.cl(sh, src.class) < (src.from or 1) then\r\nbad[#bad + 1] = f[2] .. \" is a \" .. src.class .. \" feature\"\r\nelse\r\nlocal dmg = Ally.run(pc, t, function() return (src.dmg:gsub(\"DEX\", tostring(MOD.Dexterity)):gsub(\"CON\", tostring(MOD.Constitution))) end)\r\nsrc = { dmg = dmg, free = true, lessens = src.lessens }\r\nend\r\nend\r\nif src and src.pool and t then\r\nlocal cands = src.self and { t } or { pc, table.unpack(Ally.list(pc)) }\r\nlocal selfOnly = false\r\nfor _, r in ipairs(cands) do\r\nlocal sh = r.sheet or SHEET\r\nlocal ok = (not src.class or K.cl(sh, src.class) > 0) and not r.dead and r.hp > 0 and not Cond.fx(r).incap\r\nand type(r.res) == \"table\" and (r.res[src.pool] or 0) > 0\r\n\r\nif ok and f[2] == \"Divine Spark\" and r == t then ok, selfOnly = false, true end\r\nif ok and not user then user = r end\r\nend\r\nif not user and selfOnly then\r\nK.spendRefused(pools, cur, nil, f[3], f[4])\r\nreturn head .. \"|bad:Divine Spark points at another creature, not the Cleric itself|-]\", false\r\nend\r\nif user then\r\nlocal dmg = Ally.run(pc, user, function()\r\nlocal ma = K.rowOf(SHEET, \"Monk\").martial_arts or \"1d4\"\r\nreturn (src.dmg:gsub(\"SPARK\", tostring(K.sparkDice(K.cl(SHEET, \"Cleric\")))):gsub(\"WIS\", tostring(MOD.Wisdom)):gsub(\"CON\", tostring(MOD.Constitution)):gsub(\"MA\", ma))\r\nend)\r\nlocal hb = K.healBonus(user, t, 0)\r\nif hb > 0 then dmg = dmg .. \"+\" .. hb end\r\nsrc = { dmg = dmg, pool = src.pool, refill = f[2] == \"Uncanny Metabolism\" and \"Focus Points\" or nil }\r\nelse\r\nbad[#bad + 1] = (K.MP.price(src.pool) and (\"not enough MP for \" .. src.pool .. \" (\" .. K.MP.price(src.pool) .. \")\") or (\"no \" .. src.pool .. \" left\"))\r\n.. (src.self and \"\" or \" (a Cleric's)\")\r\nend\r\nend\r\n\r\nlocal miBad = false\r\nif not src and t then\r\nlocal cn = f[2] or \"\"\r\nlocal p = not K.MI.has(t, cn) and K.MI.parse(cn)\r\nif p then cn = K.MI.canon(p) end\r\nlocal l = K.MI.has(t, cn) and t.loot[cn]\r\nlocal u = l and l.srd and K.MAGIC[l.srd] and type(K.MAGIC[l.srd].use) == \"table\" and K.MAGIC[l.srd].use\r\n\r\n\r\nlocal chHeal = u and u.heal and l.chmax and not u.day and not K.MI.keeps(K.MAGIC[l.srd])\r\nif chHeal then\r\nif l.wornReq and not l.worn then\r\nbad[#bad + 1] = cn .. \" works only worn: [EQUIP|\" .. cn .. \"] first\"\r\nmiBad = true\r\nelseif (tonumber(l.ch) or 0) < 1 then\r\nbad[#bad + 1] = cn .. \" has no charges left\"\r\nmiBad = true\r\nelse\r\nsrc = { dmg = u.heal, mi = l, ch = true, name = cn }\r\nend\r\nelseif u and u.heal then\r\nlocal worn = false\r\nfor _, x in ipairs(LOOT.inUse(t)) do if x[1] == cn then worn = true end end\r\nl.left = type(l.left) == \"table\" and l.left or {}\r\nif not worn then\r\nbad[#bad + 1] = cn .. \" is not worn\" .. ((l.att and not l.attuned) and \" (attune it first)\" or \"\")\r\nmiBad = true\r\nelseif (tonumber(l.left.use) or 0) < 1 then\r\nbad[#bad + 1] = cn .. \" again only after the next dawn (a Long Rest)\"\r\nmiBad = true\r\nelse\r\nsrc = { dmg = u.heal, mi = l }\r\nend\r\nend\r\nend\r\nif not t then bad[#bad + 1] = \"target must be Player or a companion\" end\r\nif not src and not miBad then bad[#bad + 1] = \"unknown source\" end\r\nif t and t.dead then bad[#bad + 1] = f[1] .. \" is dead\" end\r\nif src and src.item and (pc.items[f[2]] or 0) < 1 then bad[#bad + 1] = \"no \" .. f[2] .. \" in items\" end\r\nif t and src and src.res and (t.res[f[2]] or 0) < 1 then bad[#bad + 1] = \"no uses left\" end\r\nif #bad > 0 then\r\nK.spendRefused(pools, cur, nil, f[3], f[4])\r\nreturn head .. \"|bad:\" .. table.concat(bad, \";\") .. \"|-]\", false\r\nend\r\n\r\nlocal amount\r\nif src.all or src.share then\r\n\r\nlocal want = math.max(0, t.max - math.max(0, t.hp))\r\nif src.share then\r\nFeat.cur.share = Feat.cur.share or {}\r\nlocal left = Feat.cur.share[casting.name] or src.share\r\nwant = math.min(want, left, tonumber(f[3]) or tonumber(f[5]) or want)\r\nFeat.cur.share[casting.name] = left - want\r\n\r\nwant = want + K.healBonus(caster, t, (casting.slot == true or (casting.slot == nil and (casting.level or 0) >= 1)) and casting.level or 0)\r\nend\r\namount = want\r\nelse\r\nlocal p = parseFormula((src.dmg:gsub(\"LEVEL\", tostring((user or t).level or pc.level))))\r\np = parseFormula(canon(p, false))\r\nlocal given = parseFormula(f[3])\r\nif src.tTerm then\r\nf[3] = canon(p, false)\r\nhead = \"[HEAL|\" .. table.concat(f, \"|\", 1, 5)\r\nelseif not given or canon(given, false) ~= canon(p, false) then bad[#bad + 1] = \"formula \" .. f[3] .. \"->\" .. canon(p, false) end\r\n\r\nlocal healer = (spell and caster) or (f[2] == \"Divine Spark\" and user) or nil\r\n\r\n\r\nlocal supreme = healer and #Feat.fxOf(healer.sheet or SHEET, \"max_heal\") > 0\r\nlocal beacon = K.maxHealOn(t)\r\nlocal early = beacon and not supreme and K.buffNewMax(t) and not K.allMax(f[4], p)\r\nK.MAXDICE = supreme or (beacon and not early) or nil\r\namount = spendDice(p, f[4], pools, cur, bad, K.wroteF(f[3], f[4]))\r\nK.MAXDICE = nil\r\nif early then\r\nlocal full = p.mod\r\nfor _, d in ipairs(p.dice) do full = full + d.n * d.s end\r\nif tonumber(f[5]) == amount then\r\nf[5] = tostring(math.max(0, full))\r\nhead = \"[HEAL|\" .. table.concat(f, \"|\", 1, 5)\r\nend\r\namount = math.max(0, full)\r\nend\r\nend\r\n\r\nlocal halfNote = \"\"\r\nlocal halfBy = not spell and K.healHalf(t, pc)\r\nlocal mundane = src.nonmagical or ((src.mi or src.item) and type(K.MAGIC) == \"table\" and type(K.MAGIC[src.name or f[2]]) == \"table\" and K.MAGIC[src.name or f[2]].mundane)\r\nif halfBy and mundane and amount > 0 then amount = math.floor(amount / 2); halfNote = \" (\" .. halfBy .. \": half from nonmagical healing)\" end\r\n\r\nlocal hrAdd = (amount > 0 and not src.lessens) and K.healRecv(t, false) or 0\r\nif src.tTerm and tonumber(f[5]) ~= amount and tonumber(f[5]) ~= amount + hrAdd then\r\nf[5] = tostring(amount + hrAdd)\r\nhead = \"[HEAL|\" .. table.concat(f, \"|\", 1, 5)\r\nend\r\nif tonumber(f[5]) ~= amount and tonumber(f[5]) ~= amount + hrAdd then bad[#bad + 1] = \"amount \" .. tostring(f[5]) .. \"->\" .. (amount + hrAdd) end\r\n\r\n\r\nlocal lessNote = \"\"\r\nif src.lessens then\r\nlocal lk = K.byKey(t)\r\nlocal lost = Feat.cur and type(Feat.cur.hpLost) == \"table\" and tonumber(Feat.cur.hpLost[lk]) or 0\r\nif amount > lost then lessNote = string.format(\" (%s: the hit took %d)\", f[2], lost); amount = lost end\r\nif Feat.cur and type(Feat.cur.hpLost) == \"table\" then Feat.cur.hpLost[lk] = nil end\r\nend\r\n\r\nif src.item then\r\npc.items[f[2]] = pc.items[f[2]] - 1\r\nif pc.items[f[2]] <= 0 then pc.items[f[2]] = nil end\r\nelseif src.pool then\r\nuser.res[src.pool] = user.res[src.pool] - 1\r\ncaster = user\r\n\r\nif src.refill then\r\nAlly.run(pc, user, function() if PC.res[src.refill] then user.res[src.refill] = PC.res[src.refill].max end end)\r\nend\r\nelseif src.free then\r\ncaster = t\r\nelseif src.mi and src.ch then\r\nif (tonumber(src.mi.ch) or 0) > 1 then src.mi.ch = src.mi.ch - 1\r\nelse\r\nt.items[src.name] = (tonumber(t.items[src.name]) or 1) - 1\r\nif t.items[src.name] <= 0 then t.items[src.name] = nil; t.loot[src.name] = nil end\r\nend\r\ncaster = t\r\nelseif src.mi then\r\nsrc.mi.left.use = src.mi.left.use - 1\r\ncaster = t\r\nelseif not spell then\r\nt.res[f[2]] = t.res[f[2]] - 1\r\nend\r\nhealPC(t, amount, src.lessens)\r\nlocal hrNote = K.healRecvLast or \"\"\r\nt.wake = nil\r\n\r\n\r\nlocal note = \"\"\r\nif spell and caster and caster ~= t and (casting.level or 0) >= 1 and not caster.dead and (caster.hp or 0) > 0 then\r\nFeat.cur.blessed = Feat.cur.blessed or {}\r\nif not Feat.cur.blessed[casting] and #Feat.fxOf(caster.sheet or SHEET, \"self_heal_on_heal\") > 0 then\r\nFeat.cur.blessed[casting] = true\r\nhealPC(caster, 2 + casting.level)\r\nnote = string.format(\" (Blessed Healer: %s +%d, %d/%d)\", caster.name or \"Player\", 2 + casting.level, caster.hp, caster.max) .. (K.healRecvLast or \"\")\r\nend\r\nend\r\nif c.active then c.last = caster and (caster.name or \"Player\") or f[1] end\r\nreturn head .. \"|\" .. verdictOf(bad) .. \"|\" .. t.hp .. \"/\" .. t.max .. lessNote .. halfNote .. hrNote .. note .. \"]\", #bad == 0\r\nend\r\n\r\n\r\n\r\nFeat.MODES = { Rage = \"Rage\", [\"Innate Sorcery\"] = \"Innate Sorcery\", [\"Sacred Weapon\"] = \"Channel Divinity\" }\r\n\r\n\r\n\r\n\r\nlocal function verifyHeal(f, pools, cur, c, pc)\r\nlocal u = type(c.units) == \"table\" and c.units[f[1] or \"\"]\r\nif not (u and u.side == \"friend\") then return verifyHeal0(f, pools, cur, c, pc) end\r\nK.healShim = { name = f[1], hp = u.hp, max = u.max, items = {}, res = {}, equip = {}, ds = { s = 0, f = 0 }, stable = false, dead = false }\r\nlocal ok, line, good = pcall(verifyHeal0, f, pools, cur, c, pc)\r\nlocal shim = K.healShim\r\nK.healShim = nil\r\nif not ok then error(line) end\r\nu.hp = math.max(0, math.min(u.max, tonumber(shim.hp) or u.hp))\r\nreturn line, good\r\nend\r\n\r\n\r\n\r\n\r\n\r\nfunction K.pactUse(f, c, pc, head)\r\nif pc.dead then return head .. \"|bad:\" .. (pc.name or \"Player\") .. \" is dead|-]\", false end\r\nlocal want = trim(f[2] or \"\")\r\nlocal low = want:lower()\r\nif low == \"end\" or low == \"dismiss\" or want == \"끝\" or want == \"해제\" then\r\npc.pactW = nil\r\nreturn head .. \"|ok|pact weapon gone]\", true\r\nend\r\nlocal nm = want ~= \"\" and K.lootName(pc, Canon.name(want)) or nil\r\nif not (nm and gearOf(pc, nm)) then\r\nlocal mn = type(pc.equip) == \"table\" and pc.equip.main\r\nlocal mw = mn and gearOf(pc, mn)\r\nnm = (mw and not mw.ranged and mn) or pc.pactW or \"Longsword\"\r\nend\r\nlocal w = gearOf(pc, nm)\r\nif not w or w.ranged then return head .. \"|bad:a melee weapon only: a Simple or Martial melee weapon|-]\", false end\r\nif not WEAPONS[nm] and (tonumber(type(pc.items) == \"table\" and pc.items[nm]) or 0) < 1 then return head .. \"|bad:\" .. nm .. \" is not in items|-]\", false end\r\npc.pactW = nm\r\nif c.active then c.last = pc.name or \"Player\" end\r\nreturn head .. \"|ok|\" .. nm .. \" (pact weapon)]\", true\r\nend\r\n\r\nfunction K.smiteKey(sh)\r\nlocal lv = #((K.rowOf(sh, \"Warlock\") or {}).slots or {})\r\nif lv < 1 then return nil end\r\nreturn PC.res[\"Pact Slot \" .. lv] and (\"Pact Slot \" .. lv) or (\"Spell Slot \" .. lv)\r\nend\r\n\r\n\r\nK.PACT_DIE = { [\"1d4\"] = \"Dagger\", [\"1d6\"] = \"Shortsword\", [\"1d8\"] = \"Longsword\", [\"1d10\"] = \"Halberd\", [\"1d12\"] = \"Greataxe\", [\"2d6\"] = \"Greatsword\" }\r\nfunction K.pactFromAttack(rec, f, named, pc, unit, stats)\r\nlocal sh = K.ownSheet(rec, pc)\r\nif not (sh and Feat.invoked(sh, \"Pact of the Blade\")) then return \"\" end\r\nlocal p = (f[7] or \"-\") ~= \"-\" and parseFormula(f[7])\r\nlocal d = p and p.dice and p.dice[1]\r\nif not d then return \"\" end\r\nlocal n = d.n\r\nif f[6] == \"crit\" and n % 2 == 0 then n = n // 2 end\r\nlocal hitW = tonumber(f[4])\r\nfor _, a in ipairs(stats(unit, pc).attacks or {}) do\r\nlocal q = parseFormula(a.dmg or \"\")\r\nlocal x = q and q.dice and q.dice[1]\r\nif x and x.n == n and x.s == d.s and (a.spell or a.pact or not hitW or a.hit == hitW) then return \"\" end\r\nend\r\nlocal die = n .. \"d\" .. d.s\r\nlocal function fits(w0) local w = w0 and gearOf(rec, w0); return w and not w.ranged and w.dmg == die end\r\nlocal eq = type(rec.equip) == \"table\" and rec.equip or {}\r\nlocal carried = {}\r\nfor k, v in pairs(type(rec.items) == \"table\" and rec.items or {}) do if (tonumber(v) or 0) > 0 and fits(k) then carried[#carried + 1] = k end end\r\ntable.sort(carried)\r\nlocal nm = (named and gearOf(rec, named) and not gearOf(rec, named).ranged and named) or (fits(eq.main) and eq.main) or (fits(eq.off) and eq.off) or carried[1] or K.PACT_DIE[die]\r\nif not nm or not gearOf(rec, nm) then return \"\" end\r\nif named == nil and nm == rec.pactW then return \"\" end\r\nrec.pactW = nm\r\nreturn \" (Pact of the Blade: \" .. nm .. \")\"\r\nend\r\n\r\nfunction K.sheetHas(sh, name)\r\nif type(sh) ~= \"table\" or (name or \"\") == \"\" then return false end\r\nif Feat.invoked(sh, name) or K.subHas(sh, name) then return true end\r\nfor _, x in ipairs(Feat.list(sh)) do if x == name then return true end end\r\nfor _, cl in ipairs(K.classes(sh)) do if K.classFeat(cl.name, cl.level, name) then return true end end\r\nreturn false\r\nend\r\n\r\nlocal function verifyUse(f, c, pc, root, persona)\r\nlocal name = f[1] or \"\"\r\nlocal head = \"[USE|\" .. name .. ((f[2] or \"\") ~= \"\" and (\"|\" .. f[2]) or \"\")\r\nif name == \"Pact of the Blade\" and Feat.invoked(SHEET, name) then return K.pactUse(f, c, pc, head) end\r\n\r\nlocal smiteSlot\r\nif Feat.invoked(SHEET, \"Eldritch Smite\") and K.cl(SHEET, \"Warlock\") > 0 then\r\nlocal smK = K.smiteKey(SHEET)\r\nif smK and K.LITE and name == \"Eldritch Smite\" then return verifyUse({ smK }, c, pc, root, persona) end\r\nif smK and not K.LITE and (name == \"Eldritch Smite\" or (name == smK and (trim(f[2] or \"\") == \"\" or tonumber(f[2])))) then\r\nlocal whoS = pc.name or \"Player\"\r\nif Feat.cur.smiteAuto and Feat.cur.smiteAuto[whoS] then\r\nFeat.cur.smiteAuto[whoS] = nil\r\nreturn head .. \"|ok|already spent by the hit]\", true\r\nend\r\nif name == \"Eldritch Smite\" then\r\nif (tonumber(pc.res[smK]) or 0) < 1 then return head .. \"|bad:no \" .. smK .. \" left|-]\", false end\r\npc.res[smK] = pc.res[smK] - 1\r\nFeat.cur.smitePaid = Feat.cur.smitePaid or {}\r\nFeat.cur.smitePaid[whoS] = true\r\nreturn head .. string.format(\"|ok|%d/%d]\", pc.res[smK], PC.res[smK].max), true\r\nend\r\nsmiteSlot = true\r\nend\r\nend\r\n\r\nif name == \"Wild Shape\" then\r\nlocal form = Canon.name(f[2] or \"\")\r\nif form == \"end\" or form == \"\" then\r\nif not pc.form then return head .. \"|bad:not in Wild Shape|-]\", false end\r\npc.form = nil\r\nreturn head .. \"|ok|end]\", true\r\nend\r\nlocal mon = MONSTERS[form]\r\nlocal row = K.rowOf(SHEET, \"Druid\")\r\nlocal cr = K.crNum\r\nif not row.forms then return head .. \"|bad:no Wild Shape|-]\", false end\r\nif not (mon and mon.beast) then return head .. \"|bad:not a Beast|-]\", false end\r\n\r\nif (mon.fly and not row.fly) or cr(mon.cr) > cr(row.forms) then return head .. \"|bad:CR \" .. row.forms .. \" at most\" .. (row.fly and \"\" or \", no flying\") .. \"|-]\", false end\r\nif (pc.res[\"Wild Shape\"] or 0) < 1 then return head .. \"|bad:\" .. (K.MP.short(pc, \"Wild Shape\") or \"no uses left\") .. \"|-]\", false end\r\npc.res[\"Wild Shape\"] = pc.res[\"Wild Shape\"] - 1\r\npc.form = form\r\n\r\npc.wsForms = type(pc.wsForms) == \"table\" and pc.wsForms or {}\r\nfor i2 = #pc.wsForms, 1, -1 do if pc.wsForms[i2] == form then table.remove(pc.wsForms, i2) end end\r\ntable.insert(pc.wsForms, 1, form)\r\nwhile #pc.wsForms > 8 do table.remove(pc.wsForms) end\r\npc.formEnds = (K.clockRef and tonumber(K.clockRef.min) or 0) + math.max(1, math.floor(K.cl(SHEET, \"Druid\") / 2)) * 60\r\nlocal fthp = K.cl(SHEET, \"Druid\")\r\nfor _, e in ipairs(Feat.fxOf(SHEET, \"form_thp\")) do fthp = math.max(fthp, K.fxNum(e.thp, SHEET, e.srcLv)) end\r\npc.thp = math.max(tonumber(pc.thp) or 0, fthp)\r\npc.conc = pc.conc\r\nif c.active then c.last = pc.name or \"Player\" end\r\nreturn head .. \"|ok|\" .. form .. \"]\", true\r\nend\r\n\r\n\r\n\r\n\r\nlocal fmLv = tonumber(trim(f[2] or \"\"):lower():match(\"^slot%s*(%d)$\") or \"\")\r\nif name == \"Sorcery Points\" and fmLv then\r\nif K.LITE then return head .. \"|bad:the light build keeps it in MP|-]\", false end\r\nif not K.upNow(pc) or Cond.fx(pc).incap then return head .. \"|bad:\" .. (pc.name or \"Player\") .. (pc.dead and \" is dead\" or \" can't act now\") .. \"|-]\", false end\r\nlocal COST, MIN = { 2, 3, 5, 6, 7 }, { 2, 3, 5, 7, 9 }\r\nif fmLv < 1 or fmLv > 5 then return head .. \"|bad:a slot of level 1 to 5|-]\", false end\r\nif K.cl(SHEET, \"Sorcerer\") < MIN[fmLv] then return head .. \"|bad:a level \" .. fmLv .. \" slot from Sorcerer level \" .. MIN[fmLv] .. \"|-]\", false end\r\nlocal key = \"Spell Slot \" .. fmLv\r\nif not PC.res[key] or not PC.res[\"Sorcery Points\"] then return head .. \"|bad:no level \" .. fmLv .. \" slots on this sheet|-]\", false end\r\nlocal have = tonumber(pc.res[\"Sorcery Points\"]) or 0\r\nif have < COST[fmLv] then return head .. \"|bad:\" .. COST[fmLv] .. \" Sorcery Points needed, \" .. have .. \" left|-]\", false end\r\npc.res[\"Sorcery Points\"] = have - COST[fmLv]\r\npc.res[key] = (tonumber(pc.res[key]) or 0) + 1\r\nif c.active then c.last = pc.name or \"Player\" end\r\nreturn head .. string.format(\"|ok|Sorcery Points %d/%d, %s %d/%d]\", pc.res[\"Sorcery Points\"], PC.res[\"Sorcery Points\"].max, key, pc.res[key], PC.res[key].max), true\r\nend\r\nlocal cvLv = tonumber(name:match(\"^Spell Slot (%d)$\") or name:match(\"^Pact Slot (%d)$\") or \"\")\r\nif cvLv and trim(f[2] or \"\"):lower() == \"points\" then\r\nif K.LITE then return head .. \"|bad:the light build keeps it in MP|-]\", false end\r\nif not K.upNow(pc) or Cond.fx(pc).incap then return head .. \"|bad:\" .. (pc.name or \"Player\") .. (pc.dead and \" is dead\" or \" can't act now\") .. \"|-]\", false end\r\nif K.cl(SHEET, \"Sorcerer\") < 2 or not PC.res[\"Sorcery Points\"] then return head .. \"|bad:Font of Magic is a Sorcerer's (level 2)|-]\", false end\r\nif (tonumber(pc.res[name]) or 0) < 1 then return head .. \"|bad:no \" .. name .. \" left|-]\", false end\r\nlocal mx = PC.res[\"Sorcery Points\"].max\r\nlocal have = tonumber(pc.res[\"Sorcery Points\"]) or 0\r\nif have >= mx then return head .. \"|bad:Sorcery Points are full (\" .. have .. \"/\" .. mx .. \")|-]\", false end\r\npc.res[name] = pc.res[name] - 1\r\npc.res[\"Sorcery Points\"] = math.min(mx, have + cvLv)\r\nreturn head .. string.format(\"|ok|%s %d/%d, Sorcery Points %d/%d]\", name, pc.res[name], PC.res[name] and PC.res[name].max or 0, pc.res[\"Sorcery Points\"], mx), true\r\nend\r\n\r\n\r\nif tonumber(f[2]) then\r\nfor _, e in ipairs(Feat.fxOf(SHEET, \"use_from_slot\")) do\r\nif (e.use or e.src) == name and PC.res[name] then\r\nif K.LITE then return head .. \"|bad:the light build keeps it in MP|-]\", false end\r\nlocal lv = tonumber(f[2])\r\nif lv < (tonumber(e.min) or 1) then return head .. \"|bad:a level \" .. (tonumber(e.min) or 1) .. \" or higher slot|-]\", false end\r\nlocal key\r\nfor _, k in ipairs({ \"Spell Slot \" .. lv, \"Pact Slot \" .. lv }) do\r\nif not key and PC.res[k] and (pc.res[k] or 0) > 0 then key = k end\r\nend\r\nif not key then return head .. \"|bad:no level \" .. lv .. \" slot left|-]\", false end\r\nif (pc.res[name] or 0) >= PC.res[name].max then return head .. \"|bad:\" .. name .. \" is full|-]\", false end\r\npc.res[key] = pc.res[key] - 1\r\npc.res[name] = (pc.res[name] or 0) + 1\r\nreturn head .. \"|ok|\" .. name .. \" \" .. pc.res[name] .. \"/\" .. PC.res[name].max .. \", \" .. key .. \" \" .. pc.res[key] .. \"/\" .. PC.res[key].max .. \"]\", true\r\nend\r\nend\r\nend\r\n\r\n\r\nlocal modePick, mpWhy = K.useModePick(SHEET, name, f[2])\r\nif mpWhy then return head .. \"|bad:\" .. mpWhy .. \"|-]\", false end\r\nlocal modeRes = Feat.MODES[name]\r\n\r\nif modeRes and not PC.res[name] and PC.res[modeRes] and (name ~= \"Sacred Weapon\" or K.subHas(SHEET, name)) then\r\nif (pc.res[modeRes] or 0) < 1 then return head .. \"|bad:\" .. (K.MP.short(pc, modeRes) or (\"no \" .. modeRes .. \" left\")) .. \"|-]\", false end\r\npc.res[modeRes] = pc.res[modeRes] - 1\r\npc.mode = { name = name, picks = modePick }\r\nlocal mt = K.modeThp(pc, SHEET, name)\r\nreturn head .. \"|ok|\" .. (K.MP.after(pc, modeRes) or (modeRes .. \" \" .. pc.res[modeRes] .. \"/\" .. PC.res[modeRes].max)) .. mt .. \"]\", true\r\nend\r\n\r\nfor _, e in ipairs(Feat.fxOf(SHEET, \"summon\")) do\r\nif e.name == name then\r\nreturn head .. \"|bad:write [SUMMON|\" .. (pc.name and (pc.name .. \"/\") or \"\") .. name .. \"|creature|count]: the SUMMON spends \" .. (e.pool or \"nothing (a ritual)\") .. \"|-]\", false\r\nend\r\nend\r\n\r\n\r\nlocal fxBlocked\r\nfor _, x in ipairs(Feat.fxList(SHEET)) do\r\nfor _, e in ipairs(x.rec.fx) do\r\nif e.use == name and not K.fxOk(e, x, SHEET) and (e.t == \"use_mod\" or e.t == \"ward\") then fxBlocked = e end\r\nif e.use == name and K.fxOk(e, x, SHEET) then\r\n\r\nif e.t == \"overchannel\" and (pc.res[name] or 0) >= 1 then Feat.cur.overchannel = true end\r\nif e.t == \"reaction_resist\" then\r\nlocal t = Canon.name(trim(f[2] or \"\"))\r\nif not K.DMG_KO[t] then return head .. \"|bad:write the damage type: [USE|\" .. name .. \"|Fire]|-]\", false end\r\nFeat.cur.rresist = Feat.cur.rresist or {}\r\nFeat.cur.rresist[pc.name or \"Player\"] = t\r\nreturn head .. \"|ok|Resistance to \" .. t .. \" this turn]\", true\r\nend\r\n\r\n\r\n\r\n\r\nif e.t == \"use_pool\" then\r\nlocal k, n = e.pool, e.n or 1\r\nif (pc.res[k] or 0) < n then return head .. \"|bad:\" .. (K.MP.short(pc, k, n) or (\"no \" .. k .. \" uses left\")) .. \"|-]\", false end\r\npc.res[k] = pc.res[k] - n\r\nreturn head .. \"|ok|\" .. (K.MP.after(pc, k, n) or (k .. \" \" .. pc.res[k] .. \"/\" .. (PC.res[k] and PC.res[k].max or pc.res[k]))) .. \"]\", true\r\nend\r\nif e.t == \"use_resist\" then\r\nlocal line, good = verifyUse({ e.pool, tostring(e.n or 1) }, c, pc)\r\nif not good then return head .. \"|\" .. (line:match(\"|(bad:[^|%]]*)\") or \"bad:no uses left\") .. \"|-]\", false end\r\nlocal res = {}\r\nfor ty in pairs(K.DMG_KO) do if ty ~= e.except then res[#res + 1] = ty end end\r\ntable.sort(res)\r\npc.buff = type(pc.buff) == \"table\" and pc.buff or {}\r\npc.buff[name] = { res = res, by = pc.name or \"Player\", ends = (tonumber(K.replyClock) or 0) + (e.mins or 1) }\r\nlocal after = line:match(\"|ok|(.*)%]$\") or \"\"\r\nif after:match(\"^%d\") then after = e.pool .. \" \" .. after end\r\nreturn head .. \"|ok|\" .. K.buffMechText(name, pc.buff[name]) .. \", \" .. after .. \"]\", true\r\nend\r\nif e.t == \"temp_hp_use\" then return Feat.tempUse(e, c, pc, head, f, x) end\r\n\r\n\r\nif e.t == \"use_gain\" then\r\nlocal k = trim(f[2] or \"\")\r\nif not (PC.res[k] and k:sub(1, #tostring(e.res)) == tostring(e.res)) then\r\nreturn head .. \"|bad:write the use: [USE|\" .. name .. \"|\" .. tostring(e.res) .. (tostring(e.res):find(\"%(\") and \"\" or \" (7)\") .. \"]|-]\", false\r\nend\r\nif e.cond and not (Cond.load(pc)[e.cond] or (K.AR and K.AR.condsOf(pc)[e.cond])) then\r\nreturn head .. \"|bad:only while \" .. e.cond .. \" is on: [COND|\" .. (pc.name or \"Player\") .. \"|+\" .. e.cond .. \"|duration] first|-]\", false\r\nend\r\nlocal base = SHEET.base or SHEET\r\nbase.pickLR = type(base.pickLR) == \"table\" and base.pickLR or {}\r\nif base.pickLR[\"gain:\" .. name] then return head .. \"|bad:\" .. name .. \" again only after the next Long Rest|-]\", false end\r\nbase.pickLR[\"gain:\" .. name] = k\r\npc.res[k] = (pc.res[k] or 0) + 1\r\nreturn head .. \"|ok|\" .. k .. \" \" .. pc.res[k] .. \"/\" .. PC.res[k].max .. \" (one more, until the next Long Rest)]\", true\r\nend\r\n\r\n\r\nif e.t == \"use_pick\" then\r\nlocal v = Canon.name(trim(f[2] or \"\"))\r\nlocal base = SHEET.base or SHEET\r\nbase.picks = type(base.picks) == \"table\" and base.picks or {}\r\nif base.picks[e.key] then return head .. \"|bad:\" .. name .. \" is on \" .. tostring(base.picks[e.key]) .. \" until the next Long Rest|-]\", false end\r\nif e.kind == \"spell\" then\r\nlocal sp = SPELLS[v]\r\nif not sp then return head .. \"|bad:write the spell: [USE|\" .. name .. \"|Hold Person]|-]\", false end\r\nlocal mx = e.max_level ~= nil and K.fxNum(e.max_level, SHEET, x.lv) or 9\r\nif (tonumber(sp.level) or 0) > mx then return head .. \"|bad:\" .. v .. \" is level \" .. sp.level .. \": \" .. mx .. \" at most|-]\", false end\r\nelseif not SKILL[v] then\r\nreturn head .. \"|bad:write the skill: [USE|\" .. name .. \"|History]|-]\", false\r\nend\r\nif e.res then\r\nif (pc.res[e.res] or 0) < 1 then return head .. \"|bad:no \" .. e.res .. \" left|-]\", false end\r\npc.res[e.res] = pc.res[e.res] - 1\r\nend\r\nbase.picks[e.key] = v\r\nbase.pickLR = type(base.pickLR) == \"table\" and base.pickLR or {}\r\nbase.pickLR[e.key] = name\r\napplySheet(SHEET)\r\nreturn head .. \"|ok|\" .. name .. \": \" .. v .. \" until the next Long Rest]\", true\r\nend\r\n\r\nif e.t == \"use_buff\" and e.targets == \"allies\" then\r\n\r\n\r\nlocal top = root or pc\r\nlocal k, n = e.pool, tonumber(e.n) or 1\r\nif (pc.res[k] or 0) < n then return head .. \"|bad:\" .. (K.MP.short(pc, k, n) or (\"no \" .. k .. \" left\")) .. \"|-]\", false end\r\nif not c.active then return head .. \"|bad:in a fight only (for rounds)|-]\", false end\r\npc.res[k] = pc.res[k] - n\r\nlocal amt = e.add == \"INHIB\" and math.max(0, K.AR.inhib(pc, top)) or K.fxNum(e.add or 0, SHEET, e.srcLv)\r\nlocal untilR = (tonumber(c.round) or 1) + (tonumber(e.rounds) or 1)\r\nlocal on = {}\r\nfor _, x in ipairs(type(e.on) == \"table\" and e.on or { \"attack\", \"save\" }) do on[x] = true end\r\nlocal got = {}\r\nfor _, r in ipairs({ top, table.unpack(Ally.list(top)) }) do\r\nif r ~= pc and not r.dead then\r\nr.buff = type(r.buff) == \"table\" and r.buff or {}\r\nr.buff[name] = { by = pc.name or \"Player\", untilR = untilR, fid = c.fid, fight = true,\r\natk = on.attack and amt or nil, save = on.save and amt or nil }\r\ngot[#got + 1] = r == top and \"Player\" or r.name\r\nend\r\nend\r\nfor _, cn in ipairs(type(e.self_cond) == \"table\" and e.self_cond or {}) do\r\npc.cond = type(pc.cond) == \"table\" and pc.cond or {}\r\npc.condR = type(pc.condR) == \"table\" and pc.condR or {}\r\npc.cond[cn], pc.condR[cn] = -3, { to = untilR, fid = c.fid }\r\nend\r\nc.last = pc.name or \"Player\"\r\nreturn head .. \"|ok|\" .. string.format(\"+%d to %s for %s until round %d\", amt, table.concat(type(e.on) == \"table\" and e.on or { \"attack\", \"save\" }, \" and \"),\r\n#got > 0 and table.concat(got, \", \") or \"nobody\", untilR)\r\n.. (type(e.self_cond) == \"table\" and #e.self_cond > 0 and (\"; \" .. (pc.name or \"Player\") .. \" is \" .. table.concat(e.self_cond, \" and \")) or \"\") .. \"]\", true\r\nend\r\nif e.t == \"use_buff\" then\r\nlocal top = root or pc\r\nlocal who = trim(f[2] or \"\")\r\nlocal actor = who ~= \"\" and Canon.actor(who, persona) or (pc.name or \"Player\")\r\nlocal tgt = (actor == \"Player\") and top or Ally.find(top, actor)\r\nif not tgt then return head .. \"|bad:write who: [USE|\" .. name .. \"|Player or a companion]|-]\", false end\r\nif tgt.dead then return head .. \"|bad:\" .. actor .. \" is dead|-]\", false end\r\nlocal k, n = e.pool, tonumber(e.n) or 1\r\nif (pc.res[k] or 0) < n then return head .. \"|bad:\" .. (K.MP.short(pc, k, n) or (\"no \" .. k .. \" left\")) .. \"|-]\", false end\r\npc.res[k] = pc.res[k] - n\r\ntgt.buff = type(tgt.buff) == \"table\" and tgt.buff or {}\r\n\r\n\r\nlocal now = (K.clockRef and tonumber(K.clockRef.min)) or tonumber(K.replyClock) or 0\r\nlocal plus = 0\r\nfor _, h in ipairs(Feat.fxOf(SHEET, \"heal_bonus\")) do if h.buff == name then plus = plus + K.fxNum(h.amount, SHEET, h.srcLv) end end\r\ntgt.buff[name] = { by = pc.name or \"Player\", ends = now + (tonumber(e.mins) or 1), fight = (tonumber(e.mins) or 1) <= 1 or nil,\r\ndeath_adv = e.death_adv and true or nil, note = e.note, heal_plus = plus > 0 and plus or nil,\r\nresist_natural = e.resist_natural and true or nil }\r\nif c.active then c.last = pc.name or \"Player\" end\r\nreturn head .. \"|ok|on \" .. actor .. \", \" .. (K.MP.after(pc, k, n) or (k .. \" \" .. pc.res[k] .. \"/\" .. (PC.res[k] and PC.res[k].max or pc.res[k]))) .. \"]\", true\r\nend\r\n\r\n\r\n\r\nlocal pickNote = \"\"\r\nfor _, v in pairs(modePick or {}) do pickNote = \" (\" .. v .. \")\" end\r\nif e.t == \"mode\" and e.free then\r\nif pc.dead then return head .. \"|bad:\" .. (pc.name or \"Player\") .. \" is dead|-]\", false end\r\npc.mode = { name = name, picks = modePick }\r\nif c.active then c.last = pc.name or \"Player\" end\r\nreturn head .. \"|ok|\" .. name .. \" on\" .. pickNote .. K.modeThp(pc, SHEET, name) .. \"]\", true\r\nend\r\nif e.t == \"mode\" then\r\nlocal k = e.res or name\r\nif not PC.res[k] then return head .. \"|bad:not a feature with uses|-]\", false end\r\nif pc.dead then return head .. \"|bad:\" .. (pc.name or \"Player\") .. \" is dead|-]\", false end\r\nif (pc.res[k] or 0) < 1 then return head .. \"|bad:\" .. (K.MP.short(pc, k) or (\"no \" .. k .. \" left\")) .. \"|-]\", false end\r\npc.res[k] = pc.res[k] - 1\r\npc.mode = { name = name, picks = modePick }\r\npickNote = pickNote .. K.modeThp(pc, SHEET, name)\r\nif e.hours then\r\npc.mode.ends = (K.clockRef and tonumber(K.clockRef.min) or 0) + math.max(1, K.fxNum(e.hours, SHEET, e.srcLv)) * 60\r\nend\r\nif c.active then c.last = pc.name or \"Player\" end\r\nreturn head .. \"|ok|\" .. (K.MP.after(pc, k) or (k .. \" \" .. pc.res[k] .. \"/\" .. PC.res[k].max)) .. (pc.mode.ends and (\", until \" .. clockEn(pc.mode.ends)) or \"\") .. pickNote .. \"]\", true\r\nend\r\nif e.t == \"ward\" then\r\n\r\nlocal wl = tonumber(f[2] or \"\")\r\nif not wl then return head .. \"|bad:write the slot level: [USE|\" .. name .. \"|1]|-]\", false end\r\nif not pc.wardMade then return head .. \"|bad:no \" .. name .. \" yet (an Abjuration spell cast with a slot makes it)|-]\", false end\r\nlocal key = \"Spell Slot \" .. wl\r\nif not PC.res[key] or (pc.res[key] or 0) < 1 then return head .. \"|bad:no level \" .. wl .. \" slot left|-]\", false end\r\npc.res[key] = pc.res[key] - 1\r\nlocal _, mx = K.wardOf(SHEET)\r\npc.ward = math.min(mx or 0, (tonumber(pc.ward) or 0) + 2 * wl)\r\nif c.active then c.last = pc.name or \"Player\" end\r\nreturn head .. string.format(\"|ok|%s %d/%d, %s %d/%d]\", name, pc.ward, mx or 0, key, pc.res[key], PC.res[key].max), true\r\nend\r\nif e.t == \"up_half\" then\r\n\r\n\r\nlocal tn = trim(f[2] or \"\")\r\nlocal t = tn ~= \"\" and Ally.rec(K.curPc or pc, tn) or (tn == \"\" and pc) or nil\r\nif not t then return head .. \"|bad:target must be Player or a companion|-]\", false end\r\nif t.dead then return head .. \"|bad:\" .. (t.name or \"Player\") .. \" is dead|-]\", false end\r\nif (tonumber(t.hp) or 0) > 0 then return head .. \"|bad:\" .. (t == pc and \"Player\" or t.name) .. \" is not at 0 HP|-]\", false end\r\nlocal k, cost = e.pool or (PC.res[name] and name) or nil, tonumber(e.n) or 1\r\nif k and (pc.res[k] or 0) < cost then return head .. \"|bad:\" .. (K.MP.short(pc, k, cost) or (\"no \" .. k .. \" left\")) .. \"|-]\", false end\r\nif k then pc.res[k] = pc.res[k] - cost end\r\nt.hp = math.max(1, math.floor((tonumber(t.max) or 1) / 2))\r\nt.stable, t.wake, t.ds = false, nil, { s = 0, f = 0 }\r\nif c.active then c.last = pc.name or \"Player\" end\r\nreturn head .. \"|ok|\" .. (t == (K.curPc or pc) and \"Player\" or t.name) .. \" \" .. t.hp .. \"/\" .. t.max .. (k and (\", \" .. k .. \" \" .. pc.res[k]) or \"\") .. \"]\", true\r\nend\r\nif e.t == \"use_mod\" then\r\n\r\nlocal k, cost = e.pool, tonumber(e.n) or 1\r\nlocal lv = x.lv or tonumber(SHEET.level) or 1\r\n\r\n\r\nlocal nd\r\nif type(e.dmg_reduce) == \"string\" and e.dmg_reduce:find(\"%f[%w]Nd%d\") then\r\nnd = tonumber(trim(f[3] or \"\"))\r\nlocal most = e.max and math.max(1, K.fxNum(e.max, SHEET, lv)) or 5\r\nif not nd or nd < 1 or nd ~= math.floor(nd) or nd > most then\r\nreturn head .. \"|bad:write how many dice: [USE|\" .. name .. \"|Target|N] (1-\" .. most .. \")|-]\", false\r\nend\r\ncost = cost * nd\r\nend\r\nif k and (pc.res[k] or 0) < cost then return head .. \"|bad:\" .. (K.MP.short(pc, k, cost) or (\"no \" .. k .. \" left\")) .. \"|-]\", false end\r\nif pc.dead then return head .. \"|bad:\" .. (pc.name or \"Player\") .. \" is dead|-]\", false end\r\nlocal who = trim(f[2] or \"\")\r\nwho = who ~= \"\" and Canon.actor(who, persona) or (pc.name or \"Player\")\r\n\r\n\r\nlocal biRec\r\nif e.needs == \"bi\" then\r\nbiRec = Ally.rec(K.curPc or pc, who)\r\nif not (biRec and biRec.bi) then return head .. \"|bad:\" .. who .. \" holds no Bardic Inspiration die|-]\", false end\r\nend\r\n\r\nif e.ac_turn ~= nil and not Ally.rec(K.curPc or pc, who) then return head .. \"|bad:\" .. who .. \" is not Player or a companion|-]\", false end\r\nif k then pc.res[k] = pc.res[k] - cost end\r\nif biRec then biRec.bi, biRec.biEnds = nil, nil end\r\n\r\nlocal function term(v)\r\nif type(v) == \"string\" and (v:find(\"%dd%d\") or v:find(\"^d%d\") or v:find(\"{\", 1, true) or v:find(\"%f[%a]MA%f[%A]\")) then\r\nlocal p = parseFormula(K.dieText({ dice = v, srcClass = x.class, srcLv = lv }, SHEET))\r\nif p then\r\nlocal n = p.mod or 0\r\nfor _, d in ipairs(p.dice) do for _ = 1, d.n do n = n + K.d(d.s) end end\r\nreturn n\r\nend\r\nend\r\nreturn K.fxNum(v, SHEET, lv)\r\nend\r\n\r\nlocal acTurnNote\r\nif e.ac_turn ~= nil then\r\nlocal n = term(e.ac_turn)\r\nlocal rec = Ally.rec(K.curPc or pc, who)\r\nrec.buff = type(rec.buff) == \"table\" and rec.buff or {}\r\nrec.buff[name] = { bonus = n, ends = -2 }\r\nacTurnNote = string.format(\"%+d AC for %s until its next turn\", n, who)\r\nif not (e.auto_hit or e.attack_bonus or e.ac_bonus or e.dmg_mult or e.dmg_reduce or e.auto_miss) then\r\nif c.active then c.last = pc.name or \"Player\" end\r\nreturn head .. (nd and (\"|\" .. nd) or \"\") .. \"|ok|\" .. acTurnNote .. (k and (\", \" .. (K.MP.after(pc, k, cost) or (k .. \" \" .. pc.res[k] .. \"/\" .. (PC.res[k] and PC.res[k].max or pc.res[k])))) or \"\") .. \"]\", true\r\nend\r\nend\r\nlocal red = e.dmg_reduce and (nd and (e.dmg_reduce:gsub(\"%f[%w]N(d%d)\", tostring(nd) .. \"%1\")) or e.dmg_reduce) or nil\r\nlocal m = { who = who, src = name, auto_hit = e.auto_hit and true or nil, auto_miss = e.auto_miss and true or nil,\r\nattack_bonus = e.attack_bonus and term(e.attack_bonus) or nil,\r\nac_bonus = e.ac_bonus and term(e.ac_bonus) or nil,\r\ndmg_mult = tonumber(e.dmg_mult), dmg_reduce = red and K.dieText({ dice = red, srcClass = x.class, srcLv = lv }, SHEET) or nil }\r\nFeat.cur.useMod = Feat.cur.useMod or {}\r\ntable.insert(Feat.cur.useMod, m)\r\nif c.active then c.last = pc.name or \"Player\" end\r\nreturn head .. (nd and (\"|\" .. nd) or \"\") .. \"|ok|\" .. K.useModText(m) .. (k and (\", \" .. (K.MP.after(pc, k, cost) or (k .. \" \" .. pc.res[k] .. \"/\" .. (PC.res[k] and PC.res[k].max or pc.res[k])))) or \"\") .. \"]\", true\r\nend\r\nif e.t == \"free_cast\" then return head .. \"|bad:write [CAST|Spell|free] for \" .. name .. \"|-]\", false end\r\nif e.t == \"slot_recovery\" then return head .. \"|bad:Lua uses \" .. name .. \" in a Short Rest by itself|-]\", false end\r\n\r\n\r\nif e.mode and name ~= \"Focus Points\" then return head .. \"|bad:write the d20 as \\\"\" .. e.mode .. \" A,B\\\" for \" .. name .. \"|-]\", false end\r\nend\r\nend\r\nend\r\nif fxBlocked then\r\nreturn head .. \"|bad:\" .. name .. \" not now\" .. (fxBlocked[\"while\"] and (\": only during \" .. fxBlocked[\"while\"]) or \"\") .. \"|-]\", false\r\nend\r\n\r\n\r\nfor spell, x in pairs(Feat.extras(SHEET)) do\r\nif x.free == name and not x.only then\r\nreturn head .. \"|bad:write [CAST|\" .. spell .. \"|\" .. ((SPELLS[spell] or {}).level or 1) .. \"]: the CAST spends \" .. name .. \" first|-]\", false\r\nend\r\nend\r\n\r\nif name == \"Heroic Inspiration\" then\r\nreturn head .. \"|bad:write the d20 of the roll as \\\"insp A,B\\\" (one tag); that spends it|-]\", false\r\nend\r\nlocal freeSpell = name:match(\"^(.-) %(free%)$\")\r\nif freeSpell and SPELLS[freeSpell] then\r\nreturn head .. \"|bad:write [CAST|\" .. freeSpell .. \"|\" .. SPELLS[freeSpell].level .. \"]: the CAST spends \" .. name .. \" first|-]\", false\r\nend\r\n\r\nif name == \"Font of Inspiration\" then\r\nif K.LITE then return head .. \"|bad:the light build keeps it in MP|-]\", false end\r\nif K.cl(SHEET, \"Bard\") < 5 then return head .. \"|bad:a Bard of level 5 or higher|-]\", false end\r\nlocal bi = PC.res[\"Bardic Inspiration\"]\r\nif not bi then return head .. \"|bad:no Bardic Inspiration|-]\", false end\r\nif (pc.res[\"Bardic Inspiration\"] or 0) >= bi.max then return head .. \"|bad:Bardic Inspiration is full|-]\", false end\r\nlocal want = tonumber(f[2] or \"\")\r\nlocal key\r\nfor l = want or 1, want or 9 do\r\nfor _, k in ipairs({ \"Spell Slot \" .. l, \"Pact Slot \" .. l }) do\r\nif not key and PC.res[k] and (pc.res[k] or 0) > 0 then key = k end\r\nend\r\nend\r\nif not key then return head .. \"|bad:no spell slot\" .. (want and (\" of level \" .. want) or \"\") .. \" left|-]\", false end\r\npc.res[key] = pc.res[key] - 1\r\npc.res[\"Bardic Inspiration\"] = (pc.res[\"Bardic Inspiration\"] or 0) + 1\r\nreturn head .. \"|ok|\" .. key .. \" spent, Bardic Inspiration \" .. pc.res[\"Bardic Inspiration\"] .. \"/\" .. bi.max .. \"]\", true\r\nend\r\n\r\nif K.PACK.feat and K.PACK.feat[name] == \"metamagic\" then\r\nlocal picked = false\r\nfor _, x in ipairs(type(Feat.picks(SHEET).metamagic) == \"table\" and Feat.picks(SHEET).metamagic or {}) do if x == name then picked = true end end\r\nif not picked then return head .. \"|bad:\" .. name .. \" is not one of \" .. (pc.name or \"Player\") .. \"'s Metamagic options|-]\", false end\r\nlocal cost = tonumber(K.FX[name].cost) or 1\r\nlocal left = tonumber(pc.res[\"Sorcery Points\"]) or 0\r\nif left < cost then return head .. \"|bad:\" .. cost .. \" Sorcery Points needed, \" .. left .. \" left|-]\", false end\r\npc.res[\"Sorcery Points\"] = left - cost\r\nFeat.cur.used = Feat.cur.used or {}\r\nFeat.cur.used[pc] = Feat.cur.used[pc] or {}\r\nFeat.cur.used[pc][name] = true\r\nlocal top = PC.res[\"Sorcery Points\"] and PC.res[\"Sorcery Points\"].max or left\r\nreturn head .. string.format(\"|ok|Sorcery Points %d/%d]\", pc.res[\"Sorcery Points\"], top), true\r\nend\r\nlocal r = PC.res[name]\r\nif not r then\r\n\r\nif HEAL_SRC[name] and K.sheetHas(SHEET, name) then return head .. \"|bad:write HEAL for \" .. name .. \"|-]\", false end\r\nif K.sheetHas(SHEET, name) then\r\n\r\nlocal cost\r\nfor _, e in ipairs(K.featCan(name) or {}) do if e.res and PC.res[e.res] then cost = e.res end end\r\nfor _, e in ipairs(type(K.FX[name]) == \"table\" and type(K.FX[name].fx) == \"table\" and K.FX[name].fx or {}) do\r\nlocal u = type(e) == \"table\" and (e.use or e.res or e.pool)\r\nif type(u) == \"string\" and PC.res[u] then cost = u end\r\nend\r\nif cost then return head .. \"|bad:\" .. name .. \" spends \" .. cost .. \": USE that by its name|-]\", false end\r\nreturn head .. \"|ok|no uses to spend]\", true\r\nend\r\nreturn head .. \"|bad:not a feature with uses|-]\", false\r\nend\r\nif name == \"Rage\" then\r\nlocal _, worn = gearOf(pc, pc.equip and pc.equip.armor)\r\nif worn and worn.cat == \"heavy\" then return head .. \"|bad:no Rage in Heavy armor|-]\", false end\r\nend\r\nif HEAL_SRC[name] then return head .. \"|bad:write HEAL for \" .. name .. \"|-]\", false end\r\nif pc.dead then return head .. \"|bad:\" .. (pc.name or \"Player\") .. \" is dead|-]\", false end\r\n\r\nif name == \"Action Surge\" and c.active and pc.surgeAt == (tostring(c.fid) .. \":\" .. tostring(c.round or 1)) then\r\nreturn head .. \"|bad:Action Surge once a turn|-]\", false\r\nend\r\nlocal left = pc.res[name] or 0\r\n\r\nlocal n = math.max(1, math.floor(tonumber(f[2] or \"\") or 1))\r\nif left < n then\r\nlocal why = K.MP.short(pc, name, n)\r\nif why then return head .. \"|bad:\" .. why .. \"|-]\", false end\r\nreturn head .. \"|bad:no uses left|\" .. left .. \"/\" .. r.max .. \"]\", false\r\nend\r\npc.res[name] = left - n\r\nif smiteSlot then Feat.cur.smitePaid = Feat.cur.smitePaid or {}; Feat.cur.smitePaid[pc.name or \"Player\"] = true end\r\nif name == \"Action Surge\" and c.active then pc.surgeAt = tostring(c.fid) .. \":\" .. tostring(c.round or 1) end\r\n\r\nFeat.cur.used = Feat.cur.used or {}\r\nFeat.cur.used[pc] = Feat.cur.used[pc] or {}\r\nFeat.cur.used[pc][name] = true\r\nif name == \"Adrenaline Rush\" then pc.thp = math.max(tonumber(pc.thp) or 0, PROF) end\r\nif Feat.MODES[name] then pc.mode = { name = name, picks = modePick } end\r\nlocal pickNote = \"\"\r\nfor _, v in pairs(modePick or {}) do pickNote = \" (\" .. v .. \")\" end\r\nif Feat.MODES[name] then pickNote = pickNote .. K.modeThp(pc, SHEET, name) end\r\n\r\nif name == \"Rage\" and type(pc.conc) == \"table\" and pc.conc.name then\r\npc.concEnd = { name = pc.conc.name, why = \"ended by the Rage\" }\r\nFeat.cur.rageConc = pc.conc.name\r\npc.conc = nil\r\nend\r\n\r\nif name == \"Rage\" then\r\nfor _, e in ipairs(Feat.fxOf(SHEET, \"cond_immune\")) do\r\nif e.when == \"raging\" then\r\nCond.load(pc)\r\nfor _, cn in ipairs(e.conds or {}) do pc.cond[cn] = nil end\r\nend\r\nend\r\nend\r\n\r\nif name == \"Magical Cunning\" then\r\nlocal all = #Feat.fxOf(SHEET, \"cunning_all\") > 0\r\nlocal pat = K.pactApart(SHEET) and \"^Pact Slot\" or \"^Spell Slot\"\r\nfor k, rr in pairs(PC.res) do\r\nif k:match(pat) then pc.res[k] = all and rr.max or math.min(rr.max, (pc.res[k] or 0) + math.ceil(rr.max / 2)) end\r\nend\r\nend\r\nif c.active then c.last = pc.name or \"Player\" end\r\nlocal rc = name == \"Rage\" and Feat.cur.rageConc\r\nFeat.cur.rageConc = nil\r\nreturn head .. \"|ok|\" .. (K.MP.after(pc, name, n) or (pc.res[name] .. \"/\" .. r.max)) .. pickNote .. (rc and (\", Concentration on \" .. rc .. \" ends\") or \"\") .. \"]\", true\r\nend\r\n\r\n\r\n\r\nlocal function verifyPassive(f, pc)\r\nlocal skill, dcText, result, mode = f[1] or \"\", f[2] or \"\", f[3] or \"\", f[4] or \"\"\r\nlocal head = \"[PASSIVE|\" .. table.concat(f, \"|\")\r\nlocal bonus, dc = bonusFor(skill), tonumber(dcText)\r\nif not bonus then return head .. \"|bad:unknown skill|-]\", false end\r\nif not dc then return head .. \"|bad:DC|-]\", false end\r\nlocal score = 10 + bonus + ((mode == \"adv\" and 5) or (mode == \"dis\" and -5) or 0)\r\nlocal want = score >= dc and \"success\" or \"failure\"\r\nif result ~= want then return head .. \"|bad:\" .. result .. \"->\" .. want .. \"|\" .. score .. \"]\", false end\r\nreturn head .. \"|ok|\" .. score .. \"]\", true\r\nend\r\n\r\n\r\n\r\nlocal function verifySpells(f, c, sh)\r\nlocal head = f.head or (\"[SPELLS|\" .. (f[1] or \"\") .. \"|\" .. (f[2] or \"\"))\r\n\r\nlocal base = sh\r\nsh = K.casterView(base, f.cls) or base\r\nlocal cl = CLASSES[sh.class]\r\nif not cl or not cl.spell_ability then\r\nreturn head .. (sh.default and \"|bad:no character yet: write the PC tag first|-]\" or \"|bad:not a spellcaster|-]\"), false\r\nend\r\nif c.active then return head .. \"|bad:not during a fight|-]\", false end\r\nlocal row = K.rowAt(sh, sh.class, sh.level)\r\nlocal maxLv = K.rowMaxLv(row)\r\n\r\n\r\nif (tonumber(row.cantrips) or 0) == 0 and (tonumber(row.prepared) or 0) == 0 and maxLv == 0 then\r\nlocal from = K.spellsFrom(sh.class, sh.level)\r\nreturn head .. string.format(\"|bad:%s %d has no spells yet%s: write no SPELLS tag|-]\", sh.class, sh.level,\r\nfrom and (\" (they start at level \" .. from .. \")\") or \"\"), false\r\nend\r\nlocal cans, preps, bad = splitNames(f[1]), splitNames(f[2]), {}\r\n\r\n\r\nlocal moved = 0\r\ndo\r\nlocal c2, p2 = {}, {}\r\nfor _, n in ipairs(cans) do if SPELLS[n] and SPELLS[n].level > 0 then p2[#p2 + 1] = n; moved = moved + 1 else c2[#c2 + 1] = n end end\r\nfor _, n in ipairs(preps) do if SPELLS[n] and SPELLS[n].level == 0 then c2[#c2 + 1] = n; moved = moved + 1 else p2[#p2 + 1] = n end end\r\ncans, preps = c2, p2\r\nend\r\n\r\n\r\nlocal always, dropped, kept = {}, {}, {}\r\nfor _, n in ipairs(Feat.always(sh)) do always[n] = true end\r\nfor _, n in ipairs(preps) do\r\nif always[n] then dropped[#dropped + 1] = n else kept[#kept + 1] = n end\r\nend\r\npreps = kept\r\nlocal note = #dropped > 0 and (\" (\" .. table.concat(dropped, \", \") .. \" always prepared, not counted)\") or \"\"\r\nif moved > 0 then note = note .. string.format(\" (%d in the wrong field, Lua moved them: cantrips first, then the prepared spells)\", moved) end\r\n\r\n\r\nlocal ex = Feat.extras(sh)\r\nlocal exDropped = {}\r\nlocal function noExtra(list)\r\nlocal o = {}\r\nfor _, n in ipairs(list) do if ex[n] then exDropped[#exDropped + 1] = n else o[#o + 1] = n end end\r\nreturn o\r\nend\r\nlocal nC = #cans\r\ncans, preps = noExtra(cans), noExtra(preps)\r\nlocal exC = nC - #cans\r\nif #exDropped > 0 then note = note .. \" (\" .. table.concat(exDropped, \", \") .. \" already from a feat or species, not counted)\" end\r\n\r\n\r\nlocal room, exLists, prepLists = 0, {}, {}\r\nfor _, e in ipairs(Feat.fxOf(sh, \"spell_extra\")) do\r\nroom = room + (e.count or 0)\r\nfor _, l in ipairs(e.lists or {}) do exLists[l] = true end\r\nend\r\nfor _, e in ipairs(Feat.fxOf(sh, \"spell_lists\")) do for _, l in ipairs(e.lists or {}) do prepLists[l] = true end end\r\n\r\nlocal off, flex = { [true] = 0, [false] = 0 }, { [true] = 0, [false] = 0 }\r\nlocal had = {}\r\nfor _, n in ipairs(sh.spells or {}) do had[n] = true end\r\nfor _, n in ipairs(sh.cantrips or {}) do had[n] = true end\r\nlocal function check(list, cantrip)\r\nlocal seen = {}\r\nfor _, n in ipairs(list) do\r\nlocal sp = SPELLS[n]\r\nif not sp then\r\nbad[#bad + 1] = \"unknown \" .. n\r\nelseif not had[n] and K.spellOff(n) then\r\nbad[#bad + 1] = K.spellOff(n)\r\nelse\r\nlocal mine, other = false, false\r\nfor _, k in ipairs(sp.classes) do\r\nif k == sh.class or (not cantrip and prepLists[k]) then mine = true end\r\nif exLists[k] then other = true end\r\nend\r\n\r\nif not cantrip and ((prepLists[\"Module\"] and sp.fromPack) or (prepLists[\"Adult Module\"] and sp.fromAdult)) then mine = true end\r\nif mine and other then flex[cantrip] = flex[cantrip] + 1 end\r\nif not mine and other and room > 0 then off[cantrip] = off[cantrip] + 1\r\nelseif not mine then bad[#bad + 1] = n .. \" not a \" .. sh.class .. \" spell\" end\r\nif cantrip and sp.level ~= 0 then bad[#bad + 1] = n .. \" is not a cantrip\" end\r\nif not cantrip and sp.level == 0 then bad[#bad + 1] = n .. \" is a cantrip\" end\r\nif not cantrip and sp.level > maxLv then bad[#bad + 1] = n .. \" level \" .. sp.level .. \" > \" .. maxLv end\r\nend\r\nif seen[n] then bad[#bad + 1] = \"twice \" .. n end\r\nseen[n] = true\r\nend\r\nend\r\ncheck(cans, true)\r\ncheck(preps, false)\r\nlocal wantCantrips = Spell.cantripsWant(sh, row)\r\n\r\n\r\nlocal eC = math.max(0, #cans - wantCantrips)\r\nlocal eP = math.max(0, #preps - row.prepared)\r\n\r\n\r\nlocal first = #(sh.cantrips or {}) == 0 and #(sh.spells or {}) == 0\r\nlocal short = ((first and sh.level > 1 and #cans >= 1) or #cans + exC >= wantCantrips or Spell.cantripsOpen(sh, row, cans) == 0)\r\nand #cans < wantCantrips and off[true] == 0\r\nif (#cans < wantCantrips + off[true] and not short) or eC > room or eC > off[true] + flex[true] then\r\nbad[#bad + 1] = room > 0 and string.format(\"cantrips %d, need %d (+ up to %d from the other lists)\", #cans, wantCantrips, room)\r\nor string.format(\"cantrips %d, need %d\", #cans, wantCantrips)\r\nend\r\nlocal maxP = row.prepared + math.max(0, room - eC)\r\nif #preps == 0 or #preps > maxP or eP > off[false] + flex[false] then bad[#bad + 1] = string.format(\"prepared %d, need 1-%d\", #preps, maxP) end\r\nif room > 0 and eC + math.max(eP, off[false]) > room then\r\nbad[#bad + 1] = string.format(\"%d spells from the other lists, at most %d\", eC + math.max(eP, off[false]), room)\r\nend\r\nlocal book = K.isBook(sh.class) and type(sh.book) == \"table\" and #sh.book > 0 and sh.book\r\nif book then\r\nfor _, n in ipairs(preps) do\r\nlocal inBook = false\r\nfor _, b in ipairs(book) do if b == n then inBook = true end end\r\nif not inBook then bad[#bad + 1] = n .. \" not in the spellbook\" end\r\nend\r\nend\r\nif #bad > 0 then return head .. \"|bad:\" .. table.concat(bad, \";\") .. note .. \"|-]\", false end\r\nK.setLists(base, sh.class, cans, preps)\r\nif K.isBook(sh.class) and not book then\r\nbase.book = {}\r\nfor _, n in ipairs(preps) do base.book[#base.book + 1] = n end\r\nend\r\n\r\nlocal open = {}\r\nlocal oc = Spell.cantripsOpen(sh, row, cans)\r\nif oc > 0 then open[#open + 1] = oc .. \" cantrips\" end\r\nif #preps < row.prepared then open[#open + 1] = (row.prepared - #preps) .. \" prepared spells\" end\r\nif #open > 0 then note = note .. \" (still open: \" .. table.concat(open, \", \") .. \")\" end\r\nreturn head .. \"|ok|\" .. #cans .. \"+\" .. #preps .. note .. \"]\", true\r\nend\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\nSpell.SWAP_LONG = setmetatable({}, { __index = function(_, k)\r\nlocal sw = (CLASSES[k or \"\"] or {}).swap\r\nreturn (sw == \"long_all\" and \"all\") or (sw == \"long_one\" and \"one\") or nil\r\nend })\r\nSpell.SWAP_LEVEL = setmetatable({}, { __index = function(_, k) return (CLASSES[k or \"\"] or {}).swap == \"level_one\" or nil end })\r\n\r\n\r\n\r\n\r\nfunction Spell.tagClass(sh, a)\r\nlocal casters = K.casters(sh)\r\nlocal function clsOf(s)\r\ns = trim(s or \"\")\r\nfor en in pairs(CLASSES) do\r\nif en:sub(1, 1) ~= \"_\" and (en:lower() == s:lower() or (NAMES_KO[en] and NAMES_KO[en] == s)) then return en end\r\nend\r\nreturn nil\r\nend\r\nlocal named = #a >= 3 and clsOf(a[1])\r\nif named then\r\nlocal head = \"[SPELLS|\" .. (a[1] or \"\") .. \"|\" .. (a[2] or \"\") .. \"|\" .. (a[3] or \"\")\r\nfor _, c in ipairs(casters) do if c == named then return named, a[2], a[3], head end end\r\nreturn nil, a[2], a[3], head, \"Player casts no \" .. named .. \" spells\"\r\nend\r\n\r\n\r\nnamed = #a == 2 and clsOf(a[1])\r\nif named then\r\nlocal head = \"[SPELLS|\" .. (a[1] or \"\") .. \"|\" .. (a[2] or \"\")\r\nfor _, c in ipairs(casters) do if c == named then return named, \"\", a[2], head end end\r\nreturn nil, \"\", a[2], head, \"Player casts no \" .. named .. \" spells\"\r\nend\r\nlocal head = \"[SPELLS|\" .. (a[1] or \"\") .. \"|\" .. (a[2] or \"\")\r\nif #casters <= 1 then return casters[1], a[1], a[2], head end\r\nlocal fits = {}\r\nfor _, c in ipairs(casters) do\r\nlocal all = true\r\nfor _, field in ipairs({ a[1], a[2] }) do\r\nfor _, n in ipairs(splitNames(field)) do\r\nlocal on = false\r\nfor _, k in ipairs((SPELLS[n] or {}).classes or {}) do if k == c then on = true end end\r\nif SPELLS[n] and not on then all = false end\r\nend\r\nend\r\nif all then fits[#fits + 1] = c end\r\nend\r\nif #fits == 1 then return fits[1], a[1], a[2], head end\r\nreturn nil, a[1], a[2], head, \"name the class: [SPELLS|\" .. table.concat(casters, \" or \") .. \"|cantrips|prepared spells]\"\r\nend\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\nK.OTHER_BOOKS = { \"Toll the Dead\", \"Word of Radiance\", \"Booming Blade\", \"Green-Flame Blade\", \"Mind Sliver\", \"Frostbite\", \"Infestation\",\r\n\"Thunderclap\", \"Create Bonfire\", \"Primal Savagery\", \"Lightning Lure\", \"Sword Burst\" }\r\nfunction K.notHere()\r\nlocal o = {}\r\nfor _, n in ipairs(K.OTHER_BOOKS) do if not SPELLS[n] then o[#o + 1] = n end end\r\nreturn o\r\nend\r\nK.NOT_SRD = setmetatable({}, { __concat = function(a, b)\r\nlocal o = K.notHere()\r\nlocal s = (#o > 0 and (\" Spells from other books are not in this game, however well known (\" .. table.concat(o, \", \") .. \");\") or \"\")\r\n.. \" Use the Korean names given here, never a translation of your own.\"\r\nreturn (type(a) == \"table\" and s or a) .. (type(b) == \"table\" and s or b)\r\nend })\r\nfunction Spell.choiceText(cl, sh)\r\nlocal by = { [0] = {}, [1] = {} }\r\nfor n, sp in pairs(SPELLS) do\r\nif (sp.level == 0 or sp.level == 1) and type(sp.classes) == \"table\" then\r\nfor _, k in ipairs(sp.classes) do\r\nif k == cl then by[sp.level][#by[sp.level] + 1] = n .. (NAMES_KO[n] and (\" (\" .. NAMES_KO[n] .. \")\") or \"\") end\r\nend\r\nend\r\nend\r\ntable.sort(by[0])\r\ntable.sort(by[1])\r\n\r\n\r\nlocal mine = {}\r\nif type(sh) == \"table\" then\r\nfor n in pairs(K.allLists(sh)) do\r\nlocal s = SPELLS[n]\r\nif s and (s.level == 0 or s.level == 1) then mine[#mine + 1] = n end\r\nend\r\ntable.sort(mine)\r\nend\r\nreturn string.format(\"Magic Initiate choices on the %s list (in Korean call them by these names): cantrips %s; level 1 %s.\"\r\n.. \" Only these spells exist in this game (\" .. (#K.expansionNames() > 0 and \"the SRD's and the rule expansions'\" or \"the SRD's\") .. \"): recommend none outside them.\" .. K.NOT_SRD .. \"%s\",\r\ncl, table.concat(by[0], \", \"), table.concat(by[1], \", \"),\r\n#mine > 0 and (\" Player already has \" .. table.concat(mine, \", \") .. \": do not offer them again.\") or \"\")\r\nend\r\n\r\n\r\n\r\n\r\n\r\nfunction Spell.cantripsOpen(sh, row, cans)\r\nsh = K.casterView(sh) or sh\r\nlocal want = Spell.cantripsWant(sh, row)\r\ncans = cans or sh.cantrips or {}\r\nreturn math.max(0, math.min(want - #cans, #Spell.cantripsLeft(sh, cans)))\r\nend\r\n\r\n\r\nfunction Spell.cantripsLeft(sh, cans)\r\nsh = K.casterView(sh) or sh\r\nlocal have, ex, o = {}, Feat.extras(sh), {}\r\nfor _, n in ipairs(cans or sh.cantrips or {}) do have[n] = true end\r\nfor n, sp in pairs(SPELLS) do\r\nif sp.level == 0 and not have[n] and not ex[n] and not K.d2need(sp) then\r\nfor _, k in ipairs(sp.classes or {}) do if k == sh.class then o[#o + 1] = n; break end end\r\nend\r\nend\r\ntable.sort(o)\r\nreturn o\r\nend\r\n\r\nfunction Spell.cantripsWant(sh, row)\r\nlocal pk = type(sh.picks) == \"table\" and sh.picks or {}\r\n\r\nreturn (row.cantrips or 0) + (((pk.order == \"Thaumaturge\" and sh.class == \"Cleric\") or (pk.primal == \"Magician\" and sh.class == \"Druid\")) and 1 or 0)\r\nend\r\n\r\n\r\n\r\nfunction Spell.changeRule(sh)\r\nsh = K.casterView(sh) or sh\r\nlocal k = sh.class\r\nif K.isBook(k) then\r\nreturn \"change the prepared spells after a Long Rest, until the first fight after it (any of them, for spells in the spellbook)\"\r\n.. ((K.classFeat(k, sh.level, \"Memorize Spell\") and not K.LITE) and \"; Memorize Spell: after a Short Rest, until the next fight, one prepared spell for another from the book\" or \"\")\r\n.. \"; at a level-up only add spells as the number grows\"\r\nelseif Spell.SWAP_LONG[k] == \"all\" then\r\nreturn \"change the prepared spells after a Long Rest, until the first fight after it (any of them); at a level-up only add spells as the number grows\"\r\nelseif Spell.SWAP_LONG[k] == \"one\" then\r\nreturn \"after a Long Rest, until the first fight after it, replace at most one prepared spell; at a level-up only add spells as the number grows\"\r\nelseif Spell.SWAP_LEVEL[k] then\r\nreturn \"when Player gains a level, until the first fight after it, replace at most one prepared spell and add spells as the number grows; a rest changes none\"\r\nend\r\nreturn \"change the prepared spells after a Long Rest or a level-up, until the first fight after it\"\r\nend\r\n\r\n\r\nfunction Spell.opensAgain(sh)\r\nsh = K.casterView(sh) or sh\r\nlocal k = sh.class\r\nif K.isBook(k) then\r\nreturn \"after the next Long Rest\" .. ((K.classFeat(k, sh.level, \"Memorize Spell\") and not K.LITE) and \" (or one from the book after a Short Rest)\" or \"\") .. \", until the first fight after it\"\r\nelseif Spell.SWAP_LONG[k] == \"all\" then return \"after the next Long Rest, until the first fight after it\"\r\nelseif Spell.SWAP_LONG[k] == \"one\" then return \"after the next Long Rest (one spell), until the first fight after it\"\r\nelseif Spell.SWAP_LEVEL[k] then return \"at the next level-up (one spell), until the first fight after it\" end\r\nreturn \"after the next Long Rest or level-up, until the first fight after it\"\r\nend\r\n\r\n\r\nfunction Spell.changeRuleKo(sh)\r\nsh = K.casterView(sh) or sh\r\nlocal k = sh.class\r\nlocal when = K.isBook(k) and (\"긴 휴식 뒤 첫 싸움 전까지 마음대로\" .. ((K.classFeat(k, sh.level, \"Memorize Spell\") and not K.LITE) and \", 주문 암기로 짧은 휴식 뒤에 하나\" or \"\"))\r\nor Spell.SWAP_LONG[k] == \"all\" and \"긴 휴식 뒤 첫 싸움 전까지 마음대로\" or Spell.SWAP_LONG[k] == \"one\" and \"긴 휴식 뒤 첫 싸움 전까지 하나\"\r\nor Spell.SWAP_LEVEL[k] and \"레벨이 오른 뒤 첫 싸움 전까지 하나\" or \"긴 휴식이나 레벨 업 뒤 첫 싸움 전까지\"\r\nreturn \"준비 바꾸기: \" .. when .. \". 그때 이 칸에서 주문을 눌러 넣고 뺍니다. 레벨이 올라 칸이 늘면 언제든 더할 수 있습니다.\"\r\nend\r\n\r\n\r\n\r\nfunction Spell.windowBad(pc, sh, a, newChar)\r\nlocal v = K.casterView(sh, a.cls) or sh\r\nif newChar or type(v.spells) ~= \"table\" or #v.spells == 0 then return nil end\r\nlocal new, always = {}, {}\r\nfor _, n in ipairs(splitNames(a[2] or \"\")) do new[n] = true end\r\nfor _, n in ipairs(Feat.always(v)) do always[n] = true end\r\nlocal w = Spell.win(pc, sh, v.class)\r\nlocal out = 0\r\nfor _, n in ipairs((w and w.orig) or v.spells) do if not new[n] and not always[n] then out = out + 1 end end\r\nif out == 0 then return nil end\r\nif not w or w.kind == \"none\" then return \"the prepared spells cannot change now (\" .. Spell.changeRule(v) .. \")\" end\r\nif w.kind == \"one\" and out > 1 then return \"only one prepared spell may change now\" end\r\nreturn nil\r\nend\r\n\r\n\r\nfunction Spell.win(pc, sh, cls)\r\nif not cls or cls == K.castCl(sh.base or sh) then return pc.prep end\r\nreturn type(pc.prepx) == \"table\" and pc.prepx[cls] or nil\r\nend\r\nfunction Spell.setWin(pc, sh, cls, w)\r\nif not cls or cls == K.castCl(sh.base or sh) then pc.prep = w; return end\r\npc.prepx = type(pc.prepx) == \"table\" and pc.prepx or {}\r\npc.prepx[cls] = w\r\nend\r\n\r\n\r\nfunction Spell.restWindow(pc, sh, kind)\r\nif type(sh) ~= \"table\" then return end\r\nfor _, v in ipairs(K.casterViews(sh)) do\r\nlocal k = (kind == \"long\" and Spell.SWAP_LONG[v.class]) or (kind == \"short\" and K.isBook(v.class) and K.classFeat(v.class, v.level, \"Memorize Spell\") and \"one\") or nil\r\n\r\nlocal w = Spell.win(pc, sh, v.class)\r\nif k and not (k == \"one\" and w and w.kind == \"all\") then Spell.setWin(pc, sh, v.class, { kind = k, why = kind, orig = deepCopy(v.spells or {}) }) end\r\nend\r\nend\r\n\r\nfunction Spell.key(n) return (n:gsub(\" \", \"_\"):gsub(\"'\", \"\")) end\r\n\r\n\r\n\r\nfunction Spell.prepChoices(sh)\r\nsh = K.casterView(sh) or sh\r\nlocal row = K.rowAt(sh, sh.class, sh.level)\r\nlocal maxLv = K.rowMaxLv(row)\r\nlocal skip, out = {}, {}\r\nfor _, n in ipairs(Feat.always(sh)) do skip[n] = true end\r\nlocal function add(n, prepared)\r\nlocal sp = SPELLS[n]\r\nif skip[n] or not sp or (sp.level or 0) < 1 or sp.level > maxLv then return end\r\nif not prepared and K.spellOff(n) then return end\r\nskip[n] = true\r\nout[#out + 1] = n\r\nend\r\nfor _, n in ipairs(sh.spells or {}) do add(n, true) end\r\nif K.isBook(sh.class) then\r\nfor _, n in ipairs(type(sh.book) == \"table\" and sh.book or {}) do add(n) end\r\nelse\r\nlocal names = {}\r\nfor n, sp in pairs(SPELLS) do\r\nfor _, k in ipairs(sp.classes or {}) do if k == sh.class then names[#names + 1] = n end end\r\nend\r\ntable.sort(names)\r\nfor _, n in ipairs(names) do add(n) end\r\nend\r\nreturn out\r\nend\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\nK.SUB_WORDS = { \"하위 클래스\", \"하위클래스\", \"서브클래스\", \"서브 클래스\", \"subclass\", \"맹세\", \"권역\", \"회합\", \"학파\", \"후견자\", \"후원자\",\r\n\"oath\", \"domain\", \"circle\", \"college\", \"patron\" }\r\nfunction K.subTalk(t)\r\nif type(t) ~= \"string\" or t == \"\" then return false end\r\nlocal lt = t:lower()\r\nfor _, w in ipairs(K.SUB_WORDS) do if lt:find(w, 1, true) then return true end end\r\nreturn false\r\nend\r\nfunction K.subListText(sh, t)\r\nlocal want, seen = {}, {}\r\nlocal function add(cl) if CLASSES[cl] and not seen[cl] then seen[cl] = true; want[#want + 1] = cl end end\r\nfor _, cx in ipairs(K.classes(sh)) do add(cx.name) end\r\nfor _, cl in ipairs(K.classNames()) do\r\nif tostring(t or \"\"):find(cl, 1, true) or (NAMES_KO[cl] and tostring(t or \"\"):find(NAMES_KO[cl], 1, true)) then add(cl) end\r\nend\r\nlocal o = {}\r\nfor _, cl in ipairs(want) do\r\nlocal l = {}\r\nfor _, n in ipairs(K.subOptions(cl)) do l[#l + 1] = n .. (NAMES_KO[n] and (\" (\" .. NAMES_KO[n] .. \")\") or \"\") end\r\nif #l > 0 then o[#o + 1] = cl .. \": \" .. table.concat(l, \", \") end\r\nend\r\nif #o == 0 then return nil end\r\nreturn \"Subclasses in this game (\" .. (#K.expansionNames() > 0 and \"the SRD's and the rule expansions'\" or \"the SRD's\") .. \"), the whole list: \"\r\n.. table.concat(o, \"; \") .. \". No other subclass exists here, however well known (other books'): never offer or describe one,\"\r\n.. \" and in Korean call these by the names given.\"\r\nend\r\n\r\n\r\n\r\nK.PICK_WORDS = { \"추천\", \"골라\", \"고를\", \"고르\", \"뭘 찍\", \"뭐 찍\", \"뭘로 하\", \"뭐로 하\", \"뭐가 좋\", \"뭐가 나\", \"recommend\", \"which should\",\r\n\"what should i pick\", \"what should i take\", \"what should i choose\" }\r\nfunction K.pickTalk(t)\r\nif type(t) ~= \"string\" or t == \"\" then return false end\r\nlocal lt = t:lower()\r\nfor _, w in ipairs(K.PICK_WORDS) do if lt:find(w, 1, true) then return true end end\r\nreturn false\r\nend\r\nfunction K.pickAdvice(sh, pc)\r\nif type(sh) ~= \"table\" or sh.default then return nil end\r\nlocal o = {}\r\nlocal w = Feat.waiting(sh, pc, true)\r\nif w then o[#o + 1] = (w:gsub(\"^Choices waiting on the character tab %b(): \", \"\"):gsub(\"%.$\", \"\")) end\r\nif sh.asi_pending then\r\nlocal sc = {}\r\nfor _, a in ipairs(ABILS) do sc[#sc + 1] = a:sub(1, 3):upper() .. \" \" .. tostring((sh.scores or {})[a] or 10) end\r\nlocal feats = {}\r\nif sh.feat4 ~= \"Grappler\" and K.grappleOk(sh) then feats[#feats + 1] = \"Grappler 잡기 전문가\" end\r\nfor _, fn in ipairs(K.gfeatList(sh, K.charLevel(sh))) do feats[#feats + 1] = fn .. (NAMES_KO[fn] and (\" \" .. NAMES_KO[fn]) or \"\") end\r\no[#o + 1] = string.format(\"Ability Score Improvement (%d): +2 to one score or +1 to two, 20 at most (now %s)%s\", tonumber(sh.asi_pending) or 1,\r\ntable.concat(sc, \", \"), #feats > 0 and (\"; or a general feat in its place: \" .. table.concat(feats, \", \")) or \"\")\r\nend\r\nif sh.hp_pending then o[#o + 1] = \"hit points for the levels after 1: the average (fixed) or a roll each level (it cannot be undone; the average is the higher on the whole)\" end\r\nlocal ec = K.expertiseChoices and select(2, K.expertiseChoices(sh)) or 0\r\nif (tonumber(ec) or 0) > 0 then o[#o + 1] = \"Expertise (\" .. ec .. \"): skills Player is proficient in\" end\r\nif Feat.miOpen(sh) then o[#o + 1] = \"Magic Initiate: two cantrips and one level 1 spell of the \" .. tostring(Feat.miList(sh)) .. \" list (the user tells the GM; the list is below)\" end\r\nfor _, v in ipairs(K.casterViews(sh)) do\r\nlocal vr = K.rowOf(sh, v.class)\r\nlocal open = (tonumber(vr.prepared) or 0) - #(v.spells or {})\r\nif open > 0 then o[#o + 1] = string.format(\"%s prepared spells: %d open (the list is below)\", v.class, open) end\r\nend\r\nif #o == 0 then return nil end\r\n\r\nreturn \"[CHOICES] The user asks which to take of the choices waiting on the character tab. Answer out of the story, the story staying\"\r\n.. \" where it is: a one-line [GM|…] head, then the advice as plain lines under it (no tag or bracket around them): for each choice,\"\r\n.. \" recommend one (two at most) with a short reason that fits this character (its\"\r\n.. \" class and subclass, scores, spells, how it plays, the party), in Korean with the names the tab shows; then say where each is\"\r\n.. \" taken (❖ 설정 → the character tab; Magic Initiate's spells by telling the GM). Write no tag that makes these choices, and offer\"\r\n.. \" nothing outside these lists. The choices: \" .. table.concat(o, \" | \") .. \".\"\r\nend\r\nfunction K.spellTalk(t)\r\n\r\nreturn type(t) == \"string\" and (t:find(\"주문\", 1, true) ~= nil or t:find(\"소마법\", 1, true) ~= nil or t:lower():find(\"spell\", 1, true) ~= nil\r\nor t:lower():find(\"cantrip\", 1, true) ~= nil)\r\nend\r\n\r\nfunction Spell.prepText(sh)\r\nsh = K.casterView(sh) or sh\r\nlocal row = K.rowAt(sh, sh.class, sh.level)\r\nlocal function named(list)\r\nlocal o = {}\r\nfor _, n in ipairs(list) do o[#o + 1] = n .. (NAMES_KO[n] and (\" (\" .. NAMES_KO[n] .. \")\") or \"\") end\r\nreturn table.concat(o, \", \")\r\nend\r\nlocal always = Feat.always(sh)\r\n\r\nlocal cl = Spell.cantripsLeft(sh)\r\nlocal oc = Spell.cantripsOpen(sh, row)\r\nreturn string.format(\"Spells Player may prepare%s (%d at a time; only these, and in Korean call them by these names): %s.\" .. K.NOT_SRD,\r\n#K.casters(sh.base or sh) > 1 and (\" as a \" .. sh.class) or \"\", row.prepared or 0, named(Spell.prepChoices(sh)))\r\n.. (#always > 0 and (\" Always prepared, not counted: \" .. named(always) .. \".\") or \"\")\r\n.. ((row.cantrips or 0) > 0 and (\" Cantrips it can still learn (\" .. oc .. \" places open): \" .. (#cl > 0 and named(cl) or \"none\") .. \".\") or \"\")\r\nend\r\n\r\n\r\n\r\nfunction Spell.toggle(id, key, cls)\r\nlocal sh = loadSheet(id)\r\napplySheet(sh)\r\nlocal pc, c = loadPC(id), loadCombat(id)\r\nlocal ri = K.replyIdx(id)\r\nsetChatVar(id, \"dnd_book_open\", tostring(ri))\r\n\r\nlocal tagCls = (cls and #K.casters(sh) > 1) and (cls .. \"|\") or \"\"\r\nlocal function say(msg) setChatVar(id, \"dnd_prep_msg\", ri .. \"|\" .. tagCls .. msg) end\r\nif c.active then return say(\"전투 중에는 바꿀 수 없습니다.\") end\r\n\r\nlocal v = K.casterView(sh, cls)\r\nif not v then return say(\"\") end\r\nlocal name\r\nfor _, n in ipairs(Spell.prepChoices(v)) do if Spell.key(n) == key then name = n end end\r\nif not name then return say(\"\") end\r\nlocal row = K.rowOf(sh, v.class)\r\nlocal w = Spell.win(pc, sh, v.class) or { kind = \"none\", why = \"add\", orig = deepCopy(v.spells or {}) }\r\nlocal function has(list, n)\r\nfor _, x in ipairs(list or {}) do if x == n then return true end end\r\nreturn false\r\nend\r\nlocal new = {}\r\nif has(v.spells, name) then\r\nfor _, n in ipairs(v.spells) do if n ~= name then new[#new + 1] = n end end\r\nif has(w.orig, name) then\r\nlocal out = 0\r\nfor _, n in ipairs(w.orig) do if not has(new, n) then out = out + 1 end end\r\nif w.kind == \"none\" then return say(\"지금은 준비한 주문을 뺄 수 없습니다. \" .. Spell.changeRuleKo(v):match(\"^준비 바꾸기: ([^.]*)\") .. \" 바꿀 수 있습니다.\") end\r\nif w.kind == \"one\" and out > 1 then return say(\"이번에는 하나만 바꿀 수 있습니다. 뺀 주문을 다시 넣으면 다른 주문을 뺄 수 있습니다.\") end\r\nend\r\nif #new == 0 then return say(\"준비한 주문이 하나는 있어야 합니다.\") end\r\nelse\r\nif #(v.spells or {}) >= (row.prepared or 0) then return say(\"준비 칸이 다 찼습니다. 먼저 하나를 빼야 고를 수 있습니다.\") end\r\nfor _, n in ipairs(v.spells or {}) do new[#new + 1] = n end\r\nnew[#new + 1] = name\r\nend\r\n\r\nlocal res, ok = verifySpells({ table.concat(v.cantrips or {}, \", \"), table.concat(new, \", \"), cls = v.class }, c, deepCopy(sh))\r\nif not ok then\r\nfor item in ((res:match(\"|bad:(.-)|%-%]$\") or \"?\") .. \";\"):gmatch(\"([^;]*);\") do\r\nif item ~= \"\" and not item:match(\"^cantrips \") then return say(\"이 목록은 규칙에 맞지 않습니다 (\" .. item .. \").\") end\r\nend\r\nend\r\nlocal cls1 = v.class\r\nK.setLists(sh, cls1, v.cantrips or {}, new)\r\nSpell.setWin(pc, sh, cls1, w)\r\nsetState(id, \"dnd_sheet\", sh)\r\nsetState(id, \"dnd_pc\", pc)\r\nsay(\"\")\r\nsyncBases(id, function(s)\r\nif s.sheet.class ~= sh.class or s.sheet.level ~= sh.level or K.charLevel(s.sheet) ~= K.charLevel(sh) then return false end\r\nK.setLists(s.sheet, cls1, (K.lists(s.sheet, cls1)), deepCopy(new))\r\nend)\r\nend\r\n\r\n\r\n\r\nfunction Spell.cantState(id, sh, pc, idx, cls)\r\nlocal v = K.casterView(sh, cls)\r\nif not v then return nil end\r\nlocal row = K.rowOf(sh, v.class)\r\nif not row or (row.cantrips or 0) < 1 then return nil end\r\nlocal oc = Spell.cantripsOpen(v, row)\r\nlocal undo = type(pc) == \"table\" and pc.making and #(v.cantrips or {}) > 0 or false\r\nif oc < 1 and not undo then return nil end\r\nlocal at, msg = tostring(getChatVar(id, \"dnd_prep_msg\") or \"\"):match(\"^(%d+)|(.*)$\")\r\nlocal mc, m2 = (msg or \"\"):match(\"^(%u%a+)|(.*)$\")\r\nif mc and CLASSES[mc] then msg = m2 else mc = nil end\r\nreturn { open = oc, list = oc > 0 and Spell.cantripsLeft(v) or {}, undo = undo, cls = v.class, msg = tonumber(at) == idx and msg or \"\", msgCls = mc,\r\nshown = getChatVar(id, \"dnd_book_open\") == tostring(idx) }\r\nend\r\n\r\nfunction Spell.cantTap(id, key, cls)\r\nlocal sh = loadSheet(id)\r\napplySheet(sh)\r\nlocal pc, c = loadPC(id), loadCombat(id)\r\nlocal ri = K.replyIdx(id)\r\nsetChatVar(id, \"dnd_book_open\", tostring(ri))\r\nlocal tagCls = (cls and #K.casters(sh) > 1) and (cls .. \"|\") or \"\"\r\nlocal function say(msg) setChatVar(id, \"dnd_prep_msg\", ri .. \"|\" .. tagCls .. msg) end\r\nif c.active then return say(\"전투 중에는 소마법을 고를 수 없습니다.\") end\r\nlocal v = K.casterView(sh, cls)\r\nif not v then return say(\"\") end\r\nlocal row = K.rowOf(sh, v.class)\r\nlocal cans, at = {}, nil\r\nfor i, n in ipairs(v.cantrips or {}) do cans[#cans + 1] = n; if Spell.key(n) == key then at = i end end\r\nif at then\r\nif not pc.making then return say(\"배운 소마법은 바꿀 수 없습니다(첫 싸움 전까지만 빼고 다시 고를 수 있습니다).\") end\r\ntable.remove(cans, at)\r\nelse\r\nlocal name\r\nfor _, n in ipairs(Spell.cantripsLeft(v)) do if Spell.key(n) == key then name = n end end\r\nif not name then return say(\"\") end\r\nif Spell.cantripsOpen(v, row) < 1 then return say(\"소마법 칸이 다 찼습니다.\") end\r\ncans[#cans + 1] = name\r\nend\r\nlocal cls1 = v.class\r\nK.setLists(sh, cls1, cans, v.spells or {})\r\nsetState(id, \"dnd_sheet\", sh)\r\nsay(\"\")\r\nsyncBases(id, function(s0)\r\nif s0.sheet.class ~= sh.class or s0.sheet.level ~= sh.level or K.charLevel(s0.sheet) ~= K.charLevel(sh) then return false end\r\nlocal _, sp = K.lists(s0.sheet, cls1)\r\nK.setLists(s0.sheet, cls1, deepCopy(cans), sp)\r\nend)\r\nend\r\n\r\n\r\n\r\nfunction Spell.formSave(id, cls, data)\r\nlocal function list(v) return type(v) == \"table\" and v or (type(v) == \"string\" and { v }) or {} end\r\nlocal want, wantC = {}, {}\r\nfor _, k in ipairs(list(data.f_sp)) do want[tostring(k)] = true end\r\nfor _, k in ipairs(list(data.f_ct)) do wantC[tostring(k)] = true end\r\nlocal msgs, seen = {}, {}\r\nlocal function run(fn, key)\r\nfn(id, key, cls)\r\nlocal m = tostring(getChatVar(id, \"dnd_prep_msg\") or \"\"):match(\"^%d+|(.*)$\") or \"\"\r\nlocal mc, m2 = m:match(\"^(%u%a+)|(.*)$\")\r\nif mc and CLASSES[mc] then m = m2 end\r\nif m ~= \"\" and not seen[m] then seen[m] = true; msgs[#msgs + 1] = m end\r\nend\r\nlocal sh = loadSheet(id)\r\napplySheet(sh)\r\nlocal v = K.casterView(sh, cls)\r\nif not v then return end\r\n\r\nif data.f_hsp then\r\nlocal offered, prep = {}, {}\r\nfor _, n in ipairs(Spell.prepChoices(v)) do offered[Spell.key(n)] = n end\r\nfor _, n in ipairs(v.spells or {}) do prep[Spell.key(n)] = true end\r\nfor _, n in ipairs(v.spells or {}) do local k = Spell.key(n); if offered[k] and not want[k] then run(Spell.toggle, k) end end\r\nfor _, k in ipairs(list(data.f_sp)) do k = tostring(k); if offered[k] and not prep[k] then run(Spell.toggle, k) end end\r\nend\r\nif data.f_hct then\r\nlocal pc = loadPC(id)\r\nlocal have = {}\r\nfor _, n in ipairs(v.cantrips or {}) do have[Spell.key(n)] = true end\r\nif pc.making then for _, n in ipairs(v.cantrips or {}) do local k = Spell.key(n); if not wantC[k] then run(Spell.cantTap, k) end end end\r\nfor _, k in ipairs(list(data.f_ct)) do k = tostring(k); if not have[k] then run(Spell.cantTap, k) end end\r\nend\r\nlocal ri = K.replyIdx(id)\r\nlocal tagCls = (cls and #K.casters(sh) > 1) and (cls .. \"|\") or \"\"\r\nsetChatVar(id, \"dnd_prep_msg\", ri .. \"|\" .. tagCls .. table.concat(msgs, \" \"))\r\nsetChatVar(id, \"dnd_book_open\", tostring(ri))\r\nend\r\n\r\nfunction Spell.cardState(id, sh, pc, idx, cls)\r\nlocal v = K.casterView(sh, cls) or sh\r\nlocal n, max = #(v.spells or {}), K.rowOf(sh, v.class).prepared or 0\r\nlocal w = Spell.win(pc, sh, v.class)\r\nif not w and n >= max then return nil end\r\nif #Spell.prepChoices(v) == 0 then return nil end\r\nlocal at, msg = tostring(getChatVar(id, \"dnd_prep_msg\") or \"\"):match(\"^(%d+)|(.*)$\")\r\nlocal mc, m2 = (msg or \"\"):match(\"^(%u%a+)|(.*)$\")\r\nif mc and CLASSES[mc] then msg = m2 else mc = nil end\r\nreturn { w = w, n = n, max = max, open = getChatVar(id, \"dnd_book_open\") == tostring(idx), msg = tonumber(at) == idx and msg or \"\", msgCls = mc, cls = v.class }\r\nend\r\n\r\n\r\nfunction Spell.windowKo(tg)\r\nlocal w = tg.w\r\nlocal t\r\n\r\nif w and w.kind == \"all\" and w.why == \"new\" then t = \"새 캐릭터라 첫 싸움 전까지 준비한 주문을 마음대로 바꿀 수 있습니다.\"\r\nelseif w and w.kind == \"all\" and w.why == \"newcls\" then t = \"처음 고른 주문이라 첫 싸움 전까지 준비한 주문을 마음대로 바꿀 수 있습니다.\"\r\nelseif w and w.kind == \"all\" then t = \"긴 휴식 뒤라 첫 싸움 전까지 준비한 주문을 마음대로 바꿀 수 있습니다.\"\r\nelseif w and w.kind == \"one\" and w.why == \"short\" then t = \"주문 암기: 짧은 휴식 뒤라 첫 싸움 전까지 준비한 주문 하나를 주문책의 다른 주문으로 바꿀 수 있습니다.\"\r\nelseif w and w.kind == \"one\" and w.why == \"level\" then t = \"레벨이 올라 첫 싸움 전까지 준비한 주문 하나를 바꿀 수 있습니다.\"\r\nelseif w and w.kind == \"one\" then t = \"긴 휴식 뒤라 첫 싸움 전까지 준비한 주문 하나를 바꿀 수 있습니다.\"\r\nelseif tg.n < tg.max then t = string.format(\"준비 칸이 %d개 남았습니다. 주문을 눌러 더합니다.\", tg.max - tg.n)\r\nelse t = \"방금 더한 주문은 다시 눌러 뺄 수 있습니다.\" end\r\nreturn string.format(\"준비 %d / %d · \", tg.n, tg.max) .. t\r\nend\r\n\r\nlocal function verifyDeath(f, pools, cur, c, pc)\r\n\r\nlocal bad = {}\r\nif pc.dead then bad[#bad + 1] = \"Player is dead\"\r\nelseif pc.hp > 0 then bad[#bad + 1] = \"not at 0 HP\"\r\nelseif pc.stable then bad[#bad + 1] = \"already stable\" end\r\n\r\nlocal roll, _, nat = takeD20(cur, pools, f[1] or \"\", bad, pc, \"save\")\r\nlocal dfl = K.d20Floor(SHEET, \"save\", nil)\r\nif dfl and nat and nat < dfl then roll, nat = roll + dfl - nat, dfl end\r\n\r\nlocal surv\r\nfor _, e in ipairs(Feat.fxOf(SHEET, \"death_crit\")) do\r\nif nat and nat < 20 and nat >= (tonumber(e.min) or 20) then surv, nat = nat, 20 end\r\nend\r\nlocal head = \"[DEATH|\" .. (f[1] or \"\") .. \"|\" .. (f[2] or \"\")\r\nif pc.dead or pc.hp > 0 or pc.stable then return head .. \"|bad:\" .. table.concat(bad, \";\") .. \"|-]\", false end\r\n\r\n\r\nlocal aura = K.PARTY and tonumber(K.PARTY.aura) or 0\r\nlocal ar = K.PARTY and K.PARTY.auraRec\r\nif type(ar) == \"table\" and (ar == pc or ar.dead or (tonumber(ar.hp) or 0) <= 0 or Cond.fx(ar).incap) then aura = 0 end\r\nroll = roll - (tonumber(Cond.fx(pc).pen) or 0) + aura\r\n+ (K.lootSave and tonumber(K.lootSave(pc)) or 0) + (K.buffSum and tonumber(K.buffSum(pc, \"save\")) or 0)\r\n\r\n\r\n\r\n\r\nlocal insp\r\nlocal res = type(pc.res) == \"table\" and pc.res or {}\r\n\r\nlocal closure\r\nif nat ~= 20 and roll < 10 and #K.MI.powers(pc, \"deathsave\") > 0 then closure, roll = roll, 10 end\r\nif nat ~= 20 and roll < 10 and pc.ds.f + (nat == 1 and 2 or 1) >= 3 and (tonumber(res[\"Heroic Inspiration\"]) or 0) > 0 then\r\nres[\"Heroic Inspiration\"] = res[\"Heroic Inspiration\"] - 1\r\nlocal d = K.d(20)\r\ninsp = string.format(\"Heroic Inspiration %d->%d\", nat, d)\r\nroll = roll - nat + d\r\nnat = d\r\nend\r\nlocal should, note\r\nif nat == 20 then\r\nshould = \"success\"\r\nhealPC(pc, 1)\r\nnote = \"HP 1\"\r\nelseif roll >= 10 and (nat ~= 1 or closure) then\r\nshould = \"success\"\r\npc.ds.s = pc.ds.s + 1\r\nelse\r\nshould = \"failure\"\r\npc.ds.f = pc.ds.f + (nat == 1 and 2 or 1)\r\nend\r\nif pc.ds.f >= 3 then\r\npc.dead = true\r\nnote = \"dead\"\r\nelseif pc.ds.s >= 3 then\r\npc.stable = true\r\npc.ds = { s = 0, f = 0 }\r\nnote = \"stable\"\r\nend\r\nnote = note or string.format(\"%d successes, %d failures\", pc.ds.s, pc.ds.f)\r\nif surv then note = note .. \" (Survivor: \" .. surv .. \" counts as 20)\" end\r\nif closure then note = note .. \" (Periapt of Wound Closure: \" .. closure .. \" counts as 10)\" end\r\nif insp then\r\nnote = note .. \" (\" .. insp .. \")\"\r\nif Feat.cur and Feat.cur.flips then\r\nFeat.cur.flips[#Feat.cur.flips + 1] = \"insp|\" .. insp:match(\"(%d+)%->\") .. \"|\" .. nat .. \"|\" .. (pc.dead and \"dead\" or nat == 20 and \"rose\" or should)\r\nend\r\nend\r\n\r\nif f[2] ~= should and not insp then bad[#bad + 1] = \"result->\" .. should end\r\nif c.active then c.last = \"Player\" end\r\nreturn head .. \"|\" .. verdictOf(bad) .. \"|\" .. note .. \"]\", #bad == 0\r\nend\r\n\r\n\r\n\r\nlocal function verifyTrap(f, pools, cur, pc)\r\nlocal bad = {}\r\n\r\n\r\nlocal ft = tonumber(trim(f[1] or \"\"):match(\"^[Ff]all%s*(%d+)\") or trim(f[1] or \"\"):match(\"^낙하%s*(%d+)\") or \"\")\r\nif ft then\r\nlocal head = \"[TRAP|\" .. table.concat(f, \"|\", 1, 9)\r\nlocal n = math.min(20, math.floor(ft / 10))\r\nif pc.dead or n < 1 then\r\nK.spendRefused(pools, cur, nil, f[7], f[8])\r\nreturn head .. \"|bad:\" .. (pc.dead and ((pc.name or \"Player\") .. \" is dead\") or \"a fall under 10 feet does no damage\") .. \"|-]\", false\r\nend\r\nlocal p = parseFormula(n .. \"d6\")\r\nlocal given = parseFormula(f[7] or \"\")\r\nif not given or canon(given, false) ~= canon(p, false) then bad[#bad + 1] = \"formula \" .. (f[7] or \"\") .. \"->\" .. n .. \"d6\" end\r\nlocal dmg = spendDice(p, f[8], pools, cur, bad, K.wroteF(f[7], f[8]))\r\nif tonumber(f[9]) ~= dmg then bad[#bad + 1] = \"damage \" .. tostring(f[9]) .. \"->\" .. dmg end\r\nlocal landed, an = Feat.adjust(Feat.traits(pc), dmg, \"Bludgeoning\")\r\nlocal note = (an or \"\") .. hurtPC(pc, landed, false)\r\nif landed > 0 and not pc.dead then\r\nCond.load(pc)\r\npc.cond.Prone = pc.cond.Prone or -1\r\nnote = note .. \" (lands Prone)\"\r\nend\r\nreturn head .. \"|\" .. verdictOf(bad) .. \"|\" .. (pc.dead and \"dead\" or (pc.hp .. \"/\" .. pc.max)) .. note .. \"]\", #bad == 0\r\nend\r\nlocal sev = f[1]\r\nif sev ~= \"nuisance\" and sev ~= \"deadly\" then bad[#bad + 1] = \"severity nuisance or deadly\"; sev = \"nuisance\" end\r\nlocal save = f[2] or \"\"\r\nlocal ab = save:match(\"^(%a+) save$\")\r\nif not (ab and MOD[ab]) then bad[#bad + 1] = \"write an ability save\"; save = \"Dexterity save\" end\r\nlocal head = \"[TRAP|\" .. table.concat(f, \"|\", 1, 9)\r\nif pc.dead then\r\nK.spendRefused(pools, cur, f[3], f[7], f[8])\r\nreturn head .. \"|bad:\" .. (pc.name or \"Player\") .. \" is dead|-]\", false\r\nend\r\nlocal roll = takeD20(cur, pools, f[3] or \"\", bad, pc, \"save\")\r\nlocal fx = Cond.fx(pc)\r\nlocal real = bonusFor(save) - fx.pen\r\n\r\nif tonumber(f[4]) ~= real and tonumber(f[4]) and tonumber(f[4]) == K.oldBonus(pc, save) then\r\nf[4] = string.format(\"%+d\", real)\r\nhead = \"[TRAP|\" .. table.concat(f, \"|\", 1, 9)\r\nend\r\nif tonumber(f[4]) ~= real then bad[#bad + 1] = string.format(\"bonus %s->%+d\", f[4] or \"\", real) end\r\nlocal row = TRAP.row(sev, pc.level)\r\nif tonumber(f[5]) ~= row[1] then bad[#bad + 1] = \"DC \" .. (f[5] or \"\") .. \"->\" .. row[1] end\r\nlocal ok = roll + real >= row[1] and not fx.autofail[ab or \"\"]\r\nlocal should = ok and \"success\" or \"failure\"\r\nif f[6] ~= should then bad[#bad + 1] = \"result->\" .. should end\r\nlocal p = parseFormula(row[2])\r\nlocal given = parseFormula(f[7] or \"\")\r\nif not given or canon(given, false) ~= canon(p, false) then bad[#bad + 1] = \"formula \" .. (f[7] or \"\") .. \"->\" .. row[2] end\r\nlocal dmg = spendDice(p, f[8], pools, cur, bad, K.wroteF(f[7], f[8]))\r\n\r\n\r\nlocal evade = ab == \"Dexterity\" and not fx.incap and #Feat.fxOf(pc.sheet or SHEET, \"evasion\") > 0\r\nif evade then dmg = ok and 0 or math.floor(dmg / 2) elseif ok then dmg = math.floor(dmg / 2) end\r\nif tonumber(f[9]) ~= dmg then bad[#bad + 1] = \"damage \" .. tostring(f[9]) .. \"->\" .. dmg .. (evade and \" (Evasion)\" or \"\") end\r\nlocal note = hurtPC(pc, dmg, false)\r\nreturn head .. \"|\" .. verdictOf(bad) .. \"|\" .. (pc.dead and \"dead\" or (pc.hp .. \"/\" .. pc.max)) .. note .. \"]\", #bad == 0\r\nend\r\n\r\n\r\nK.TIME_UNIT = { m = 1, h = 60, d = 1440, w = 10080, M = 43200, y = 518400 }\r\nK.TIME_MAX = 100 * 518400\r\n\r\nlocal function verifyTime(f, clock)\r\n\r\n\r\nlocal body = (f[1] or \"\"):gsub(\"%s\", \"\"):lower():gsub(\"years?\", \"y\"):gsub(\"months?\", \"M\"):gsub(\"mo\", \"M\"):gsub(\"weeks?\", \"w\")\r\n:gsub(\"days?\", \"d\"):gsub(\"hours?\", \"h\"):gsub(\"minutes?\", \"m\"):gsub(\"mins?\", \"m\")\r\n:gsub(\"시간\", \"h\"):gsub(\"분\", \"m\"):gsub(\"개월\", \"M\"):gsub(\"달\", \"M\"):gsub(\"주일\", \"w\"):gsub(\"주\", \"w\"):gsub(\"년\", \"y\"):gsub(\"일\", \"d\"):match(\"^%+?(.*)$\") or \"\"\r\nlocal add = 0\r\nfor n, u in body:gmatch(\"(%d+)([mhdwMy])\") do add = add + tonumber(n) * K.TIME_UNIT[u] end\r\nif body == \"\" or body:gsub(\"%d+[mhdwMy]\", \"\") ~= \"\" or add <= 0 then\r\nreturn \"[TIME|\" .. (f[1] or \"\") .. \"|bad:write +30m, +2h, +1d, +2w, +3mo, +1y or +1h 30m|\" .. clockKo(clock.min) .. \"]\", false\r\nend\r\nlocal bad = {}\r\nif add > K.TIME_MAX then bad[#bad + 1] = \"more than 100 years\"; add = K.TIME_MAX end\r\nclock.min = clock.min + add\r\nreturn \"[TIME|\" .. f[1] .. \"|\" .. verdictOf(bad) .. \"|\" .. clockKo(clock.min) .. \"]\", #bad == 0\r\nend\r\n\r\n\r\n\r\nfunction K.restThp(pc, kind)\r\nkind = tostring(kind or \"\"):lower()\r\nlocal o = {}\r\nlocal party = { pc, table.unpack(Ally.list(pc)) }\r\nfor _, giver in ipairs(party) do\r\nlocal sh = giver == pc and SHEET or giver.sheet\r\nif not giver.dead and type(sh) == \"table\" then\r\nfor _, e in ipairs(Feat.fxOf(sh, \"rest_thp\")) do\r\nlocal w = tostring(e.when or \"any\"):lower()\r\nif w == \"any\" or w == kind then\r\nlocal function amt(term)\r\nif term == nil then return 0 end\r\nreturn Ally.run(pc, giver ~= pc and giver or nil, function() return math.max(0, tonumber(K.fxNum(term, sh, e.srcLv)) or 0) end)\r\nend\r\nlocal selfN, partyN = amt(e.self), amt(e.party)\r\nfor _, r in ipairs(party) do\r\nlocal n = r == giver and math.max(selfN, partyN) or partyN\r\nif not r.dead and n > (tonumber(r.thp) or 0) then\r\nr.thp = n\r\no[#o + 1] = string.format(\"temporary HP %d (%s, %s)\", n, r.name or \"Player\", e.src or \"?\")\r\nend\r\nend\r\nend\r\nend\r\nend\r\nend\r\nreturn table.concat(o, \", \")\r\nend\r\n\r\nfunction K.modeThp(rec, sh, modeName)\r\nlocal got = 0\r\nfor _, e in ipairs(type(sh) == \"table\" and Feat.fxOf(sh, \"mode_thp\") or {}) do\r\nif e.mode == modeName then got = math.max(got, tonumber(K.fxNum(e.thp, sh, e.srcLv)) or 0) end\r\nend\r\nif got > (tonumber(rec.thp) or 0) then rec.thp = got; return string.format(\", temporary HP %d\", got) end\r\nreturn \"\"\r\nend\r\nlocal function verifyRest(f, c, pc, clock)\r\n\r\nlocal kind, want = f[1], tonumber(f[2] or \"\")\r\nlocal head = \"[REST|\" .. table.concat(f, \"|\")\r\nlocal bad = {}\r\nif kind ~= \"short\" and kind ~= \"long\" then bad[#bad + 1] = \"short or long\" end\r\nif K.LITE and kind == \"short\" then\r\nreturn head .. \"|bad:no Short Rest in this game: outside a fight give back some HP and MP as the story fits with\"\r\n.. \" [HEAL|Target|Rest|N|-|N] and [MP|Target|+N]|-]\", false\r\nend\r\nif c.active then bad[#bad + 1] = \"in combat\" end\r\nlocal wait = kind == \"long\" and pc.long_end and clock.min - pc.long_end < K.LONG_WAIT\r\n\r\nlocal ahead = kind == \"long\" and 8 * 60 or 60\r\nif #bad == 0 and not wait then K.wakeDue(pc, c, clock, ahead, true) end\r\nif pc.dead then bad[#bad + 1] = \"Player is dead\"\r\nelseif pc.hp < 1 then bad[#bad + 1] = \"needs at least 1 HP\" end\r\nif wait then\r\nbad[#bad + 1] = string.format(\"next Long Rest in %dh\", math.ceil((K.LONG_WAIT - (clock.min - pc.long_end)) / 60))\r\nend\r\nif #bad > 0 then return head .. \"|bad:\" .. table.concat(bad, \";\") .. \"|-]\", false end\r\nK.wakeDue(pc, c, clock, ahead)\r\n\r\nlocal before = pc.hp\r\nlocal note\r\npc.echo = nil\r\nif kind == \"short\" then\r\nclock.min = clock.min + 60\r\nlocal used, rolls = 0, {}\r\nlocal halfBy = K.healHalf(pc, pc)\r\nlocal noHp = K.restNoHp(SHEET, \"short\")\r\nwhile not noHp and pc.hd > 0 and pc.hp < pc.max and (want == nil or used < want) do\r\nlocal r = K.dieFor(pc, K.hdNext(SHEET, pc.hd))\r\nrolls[#rolls + 1] = r\r\nlocal g = math.max(1, r + MOD.Constitution)\r\nif halfBy then g = math.floor(g / 2) end\r\npc.hp = math.min(pc.max, pc.hp + g)\r\npc.hd = pc.hd - 1\r\nused = used + 1\r\nend\r\nK.hdGain(pc, pc.name or \"Player\", pc.hp - before, clock)\r\nfor name, r in pairs(PC.res) do pc.res[name] = math.min(r.max + K.gainExtra(SHEET, name), (pc.res[name] or 0) + r.short) end\r\npc.rr = nil\r\nnote = string.format(\"HP %d->%d, Hit Point Dice %d (%s)\", before, pc.hp, used, #rolls > 0 and table.concat(rolls, \",\") or \"-\")\r\n.. ((halfBy and used > 0) and (\" (\" .. halfBy .. \": half)\") or \"\") .. (noHp and (\" (\" .. noHp .. \": no HP from a rest)\") or \"\")\r\n.. Feat.arcane(pc) .. Feat.restoration(pc) .. Feat.shortRest(pc)\r\nlocal arN = K.joinNote(K.AR.short(pc, pc), K.drainRest(pc, pc, \"short\"))\r\nif arN ~= \"\" then note = note .. \"; \" .. arN end\r\nelse\r\nclock.min = clock.min + 8 * 60\r\nlocal noHpL = K.restNoHp(SHEET, \"long\")\r\nif not noHpL then pc.hp = pc.max end\r\npc.hd = pc.level\r\nfor name, r in pairs(PC.res) do pc.res[name] = r.max end\r\npc.rr, pc.hi = nil, nil\r\npc.long_end = clock.min\r\npc.wardMade = nil\r\nfor _, a in ipairs(Ally.list(pc)) do a.wardMade = nil end\r\npc.form, pc.mode = nil, nil\r\npc.thp = nil\r\nCond.load(pc)\r\nif pc.exh > 0 then pc.exh = pc.exh - 1 end\r\n\r\nif (tonumber(pc.ordeal) or 0) > 0 then pc.ordeal = pc.ordeal - 1 end\r\npc.taxed = nil\r\nLOOT.refill(pc)\r\nnote = string.format(\"HP %d->%d\", before, pc.hp) .. (noHpL and (\" (\" .. noHpL .. \": no HP from a rest)\") or \"\") .. K.portentRoll(pc, SHEET)\r\nlocal arL = K.joinNote(K.joinNote(K.AR.long(pc, pc), K.drainRest(pc, pc, \"long\")), K.viceRest(pc, pc))\r\nif arL ~= \"\" then note = note .. \"; \" .. arL end\r\nend\r\npc.rests = (tonumber(pc.rests) or 0) + 1\r\nreturn head .. \"|ok|\" .. note .. \"]\", true\r\nend\r\n\r\n\r\n\r\n\r\nfunction K.MP.restHeal(f, c, pc)\r\nlocal head = \"[HEAL|\" .. table.concat(f, \"|\", 1, 5)\r\nlocal t = Ally.rec(pc, f[1])\r\nlocal n = tonumber(f[5] or \"\") or tonumber(f[3] or \"\")\r\nlocal why\r\nif not t then why = \"target must be Player or a companion\"\r\nelseif c.active then why = \"not during a fight: there a potion, a spell or a feature heals\"\r\nelseif t.dead then why = (t.name or \"Player\") .. \" is dead\"\r\nelseif not n or n < 1 or n ~= math.floor(n) then why = \"write the HP as [HEAL|Target|Rest|N|-|N]\" end\r\nif why then return head .. \"|bad:\" .. why .. \"|-]\", false end\r\nhealPC(t, n)\r\nt.wake = nil\r\nreturn head .. \"|ok|\" .. t.hp .. \"/\" .. t.max .. \"]\", true\r\nend\r\nfunction K.MP.give(f, c, pc)\r\nlocal head = \"[MP|\" .. (f[1] or \"\") .. \"|\" .. (f[2] or \"\")\r\nlocal t = Ally.rec(pc, f[1])\r\nlocal n = tonumber(((f[2] or \"\"):gsub(\"^%s*%+%s*\", \"\")))\r\n\r\nlocal recall = (f[3] or \"\") == \"Boon of Spell Recall\" and t and t.sheet == nil and type(SHEET.picks) == \"table\" and SHEET.picks.boon == \"Boon of Spell Recall\"\r\nif recall then head = head .. \"|\" .. f[3] end\r\nlocal why\r\nif not K.LITE then why = \"no MP in this game\"\r\nelseif not t then why = \"target must be Player or a companion\"\r\nelseif (f[3] or \"\") ~= \"\" and not recall then why = \"only Boon of Spell Recall gives MP back this way\"\r\nelseif recall and n and n > K.MP.SPELL[4] then why = \"Boon of Spell Recall: a level 1-4 spell, \" .. K.MP.SPELL[4] .. \" MP at most\"\r\nelseif c.active and not recall then why = \"not during a fight\"\r\nelseif t.dead then why = (t.name or \"Player\") .. \" is dead\"\r\nelseif not n or n < 1 or n ~= math.floor(n) then why = \"write [MP|Target|+N]\" end\r\nif why then return head .. \"|bad:\" .. why .. \"|-]\", false end\r\nreturn Ally.run(pc, t, function()\r\nif not (PC.res.MP and PC.res.MP.max > 0) then return head .. \"|bad:\" .. (t.name or \"Player\") .. \" has no MP|-]\", false end\r\nrawset(t.res, \"MP\", math.min(PC.res.MP.max, (tonumber(rawget(t.res, \"MP\")) or 0) + n))\r\nreturn head .. \"|ok|\" .. K.MP.text(t) .. \"]\", true\r\nend)\r\nend\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\nfunction K.wplus(lv) lv = tonumber(lv) or 2; return lv >= 6 and 3 or lv >= 3 and 2 or 1 end\r\nfunction K.buffWhat(name, m, lv)\r\nif type(m.party_skill) == \"table\" then\r\nlocal o = {}\r\nfor k, v in pairs(m.party_skill) do o[#o + 1] = \"+\" .. v .. \" \" .. k end\r\ntable.sort(o)\r\nreturn \"Lua adds \" .. table.concat(o, \", \") .. \" to the checks of Player and every companion while it lasts (in the bonuses); no BUFF tag\"\r\nend\r\nlocal cap = tonumber(m.btargets) or tonumber(m.targets) or 1\r\nlocal up = type(m.upcast) == \"table\" and tonumber(m.upcast.targets)\r\nlocal pick = m.resist_pick or m.pick\r\nlocal mt = K.buffMechText(name, { ward = m.ward, cimm = m.cimm, imm = m.imm, res = m.resist, floor = m.ac_floor, base = m.ac_base,\r\nbonus = m.ac_bonus, wplus = m.wplus and \"1 (+2 when cast at level 3-5, +3 at 6+)\",\r\nthp = m.turn_thp and \"= your spellcasting modifier\", revive = m.revive, maxheal = m.maxheal,\r\n\r\nresd4 = m.res_d4, d4minus = m.atk_d4_minus, speedAdd = m.speed_add, fly = m.fly, asave = m.attacker_save,\r\nsnone = m.save_none, sizeAny = m.size_dice })\r\n\r\n\r\n\r\nlocal counted = m.res_d4 or m.atk_d4_minus or m.speed_add or m.fly or m.attacker_save or m.save_none or m.size_dice or m.resist_pick or mt ~= \"\"\r\nlocal said = type(m.say) == \"string\" and m.say ~= \"\" and (K.spellTerms(m.say, name) .. (counted and \"\" or \" (narrated)\")) or (not counted and \"effect narrated\") or nil\r\nlocal pickW = pick and (#pick <= 3 and table.concat(pick, \" or \") or table.concat(pick, \"/\"))\r\nreturn (said and (said .. \"; \") or \"\") .. \"right after the CAST one [BUFF|Target|\" .. name .. (m.wplus and \"|its weapon\" or pickW and (\"|\" .. pickW) or \"\") .. \"]\"\r\n.. (m.self and \" on its caster\" or (\" per target (up to \" .. cap .. (up and (\", +\" .. up .. \" per level above \" .. lv) or \"\") .. \")\"))\r\n.. \", so Lua keeps it on them until it ends\"\r\n.. (m.resist_pick and \"; Lua: Resistance to the type named\" or (mt ~= \"\" and (\"; Lua: \" .. mt) or \"\"))\r\nend\r\nfunction K.buffMechText(name, b)\r\nlocal o = {}\r\nif b.ward then o[#o + 1] = \"Lua makes the first drop to 0 HP 1 HP instead\" end\r\n\r\nif b.death_adv then o[#o + 1] = \"Advantage on death saving throws (write adv A,B)\" end\r\nif b.resist_natural then o[#o + 1] = \"Resistance to the damage of an enemy's natural weapons (Lua halves it)\" end\r\nif b.heal_plus then o[#o + 1] = string.format(\"%s's healing on it restores %d more (in the formula)\", b.by or \"its giver\", b.heal_plus) end\r\nif b.note then o[#o + 1] = tostring(b.note) end\r\nif type(b.cimm) == \"table\" and #b.cimm > 0 then o[#o + 1] = \"cannot be \" .. table.concat(b.cimm, \" or \") end\r\nif type(b.imm) == \"table\" and #b.imm > 0 then o[#o + 1] = \"immune to \" .. table.concat(b.imm, \", \") .. \" damage\" end\r\nif type(b.res) == \"table\" and #b.res > 0 then\r\nlocal force = false\r\nfor _, x in ipairs(b.res) do if x == \"Force\" then force = true end end\r\nlocal psy = false\r\nfor _, x in ipairs(b.res) do if x == \"Psychic\" then psy = true end end\r\no[#o + 1] = \"Resistance to \" .. (#b.res >= 13 and \"all damage\" or (#b.res == 12 and not force) and \"all damage but Force\"\r\nor (#b.res == 12 and not psy) and \"all damage but Psychic\" or table.concat(b.res, \", \"))\r\nend\r\nif b.base then o[#o + 1] = \"AC \" .. b.base .. \" + Dexterity without armor\" end\r\nif b.floor then o[#o + 1] = \"AC at least \" .. b.floor end\r\nif b.bonus then o[#o + 1] = \"+\" .. b.bonus .. \" AC\" end\r\nif b.wplus then o[#o + 1] = \"+\" .. b.wplus .. \" to attack and damage rolls with \" .. (b.choice or \"that weapon\") .. \" (in the attack list)\" end\r\nif b.thp then o[#o + 1] = \"Temporary HP \" .. b.thp .. \" at the start of each of their turns in a fight (Lua gives it)\" end\r\nif b.revive then o[#o + 1] = \"at 0 HP in a fight, Lua brings them to 1 HP at their turn\" end\r\nif b.maxheal then o[#o + 1] = \"healing on them is at its maximum: write each healing die as its maximum (Lua takes none from the pool)\" end\r\nif b.tell then o[#o + 1] = b.tell end\r\n\r\nif b.resd4 then o[#o + 1] = (b.choice or \"that type's\") .. \" damage on it takes the pool's next d4 off, once for each attacker's turn (Lua takes it: write the damage with it off)\" end\r\nif b.d4minus then o[#o + 1] = \"an attack roll against it takes the next d4 off: write the attacker's d20 field \\\"14 ward 3\\\"\" end\r\nif tonumber(b.speedAdd) then o[#o + 1] = string.format(\"Speed %+d ft (on the Equipped line)\", b.speedAdd) end\r\nif tonumber(b.fly) then o[#o + 1] = string.format(\"fly %d ft, hover (on the Equipped line)\", b.fly) end\r\nif b.snone then o[#o + 1] = \"a success on a save against a spell or a magical effect that halves damage takes none: write the damage 0 (Lua takes it)\" end\r\nif b.asave then o[#o + 1] = \"a creature that attacks it makes a \" .. b.asave .. \" SAVE first (the caster's DC): on a failure it picks another target or loses the attack; it ends if this one attacks\" end\r\nif b.choice == \"Enlarge\" then o[#o + 1] = \"+1d4 on its weapon hits (Lua lists it as \\\"may add\\\")\" end\r\nif b.choice == \"Reduce\" then o[#o + 1] = \"its weapon hits deal 1d4 less (in its formulas)\" end\r\nif b.sizeAny then o[#o + 1] = \"Enlarge: +\" .. b.sizeAny .. \" on its weapon hits (Lua lists it as \\\"may add\\\"); Reduce: \" .. b.sizeAny .. \" less on them (in its formulas)\" end\r\nreturn table.concat(o, \"; \")\r\nend\r\nfunction K.buffTag(f, c, pc, clock)\r\nlocal head = \"[BUFF|\" .. table.concat(f, \"|\")\r\nlocal function fail(why) return head .. \"|bad:\" .. why .. \"|-]\", false end\r\nlocal name = Canon.name(trim(f[2] or \"\"))\r\n\r\nif name == \"Gentle Repose\" then\r\nlocal t = Ally.rec(pc, f[1])\r\nif not t then return fail(\"target must be Player or a companion\") end\r\nif not t.dead then return fail(\"Gentle Repose is cast on a corpse\") end\r\nlocal cast = false\r\nfor _, x in ipairs(Feat.cur.casts or {}) do if x.name == name then cast = true end end\r\nif not cast then return fail(\"cast Gentle Repose with CAST first\") end\r\nlocal now = (type(clock) == \"table\" and tonumber(clock.min)) or tonumber(K.replyClock) or 0\r\nt.repose = { from = now, to = now + 10 * 1440 }\r\nreturn head .. \"|ok|\" .. (t.name or \"Player\") .. \": the next 10 days do not count toward raising]\", true\r\nend\r\nlocal sp = SPELLS[name]\r\nlocal m = sp and sp.m\r\nif m and m.form_beast then return K.polyTag(f, c, pc, name, m) end\r\nif not (m and m.kind == \"buff\") then return fail(\"not a spell that stays on someone: write its own tags\") end\r\nif m.hp_bonus or m.temp_hp or m.temp_share then return fail(\"write the HEAL tag for \" .. name) end\r\nif type(m.party_skill) == \"table\" then return fail(\"no BUFF tag: Lua counts \" .. name .. \" for the whole party while its caster concentrates\") end\r\nlocal t = Ally.rec(pc, f[1])\r\nif not t then return fail(\"target must be Player or a companion\") end\r\nif t.dead then return fail((t.name or \"Player\") .. \" is dead\") end\r\nFeat.cur.buffs = Feat.cur.buffs or {}\r\nlocal casting, any = nil, false\r\nfor _, x in ipairs(Feat.cur.casts or {}) do\r\nif x.name == name then\r\nany = true\r\nlocal used, n = Feat.cur.buffs[x] or {}, 0\r\nfor _ in pairs(used) do n = n + 1 end\r\nlocal cap = tonumber(m.btargets) or tonumber(m.targets) or 1\r\nif type(m.upcast) == \"table\" and tonumber(m.upcast.targets) then\r\ncap = cap + m.upcast.targets * math.max(0, (tonumber(x.level) or sp.level) - sp.level)\r\nend\r\nif not casting and not used[t] and n < cap then casting = x end\r\nend\r\nend\r\nif not casting then\r\nreturn fail(any and (name .. \" already reached its targets this casting\") or (\"cast \" .. name .. \" with CAST first\"))\r\nend\r\nlocal choice = trim(f[3] or \"\")\r\nlocal pick = m.resist_pick or m.pick\r\nif pick then\r\nchoice = Canon.name(choice)\r\nlocal okp = false\r\nfor _, ty in ipairs(pick) do if ty == choice then okp = true end end\r\nif not okp then return fail((m.resist_pick and \"name the damage type, one of \" or (m.pick_what and (\"name \" .. m.pick_what .. \", one of \")) or \"name the ability, one of \") .. table.concat(pick, \", \")) end\r\nend\r\nlocal by = casting.by and Ally.find(pc, casting.by) or pc\r\nif m.self and t ~= by then return fail(name .. \" is only on its caster (\" .. (by.name or \"Player\") .. \")\") end\r\n\r\nif m.wplus then\r\nlocal eq = type(t.equip) == \"table\" and t.equip or {}\r\nlocal w = choice == \"\" and eq.main or ((choice == eq.main or choice == eq.off) and choice) or Canon.name(choice)\r\nif not w or (w ~= eq.main and w ~= eq.off) then\r\nreturn fail(\"name a weapon \" .. (t.name or \"Player\") .. \" holds\" .. (eq.main and (\" (\" .. eq.main .. \")\") or \"\"))\r\nend\r\nlocal wd, _, plus = gearOf(t, w)\r\nif not wd then return fail(w .. \" is not a weapon\") end\r\nif (plus or 0) > 0 then return fail(w .. \" is already a magic weapon\") end\r\nchoice = w\r\nend\r\nlocal now = (type(clock) == \"table\" and tonumber(clock.min)) or tonumber(K.replyClock) or 0\r\nt.buff = type(t.buff) == \"table\" and t.buff or {}\r\nlocal e = {}\r\nif (m.ac_base or m.ac_bonus) and type(by.buff) == \"table\" and type(by.buff[name]) == \"table\" then\r\ne = by.buff[name]\r\nif t ~= by then by.buff[name] = nil end\r\nend\r\ne.base, e.bonus, e.floor = e.base or m.ac_base, e.bonus or m.ac_bonus, m.ac_floor\r\ne.ward, e.cimm, e.imm = m.ward, m.cimm, m.imm\r\ne.maxdice, e.noover = m.max_dice and true or nil, m.no_overstim and true or nil\r\ne.res = m.resist_pick and { choice } or m.resist\r\ne.choice = choice ~= \"\" and choice or nil\r\ne.by = by.name or \"Player\"\r\n\r\n\r\ne.wplus = m.wplus and K.wplus(casting.level or sp.level) or nil\r\ne.thp = nil\r\nif m.turn_thp then\r\nlocal s = Ally.run(pc, by, function() return Spell.stats(name) end)\r\ne.thp = (s and s.mod > 0) and s.mod or nil\r\nend\r\ne.revive, e.maxheal = m.revive, m.maxheal\r\n\r\ne.resd4, e.d4minus, e.speedAdd, e.fly, e.asave = m.res_d4 or nil, m.atk_d4_minus or nil, tonumber(m.speed_add), tonumber(m.fly), m.attacker_save\r\ne.snone = m.save_none or nil\r\ne.tell = m.tell and (m.tell:gsub(\"{PICK}\", choice)) or nil\r\nif m.wplus then\r\nfor _, r in ipairs({ pc, table.unpack(Ally.list(pc)) }) do\r\nif type(r.buff) == \"table\" and type(r.buff[name]) == \"table\" and r.buff[name].by == e.by then r.buff[name] = nil end\r\nend\r\nend\r\n\r\nlocal cConc = casting.conc\r\nif cConc == nil then cConc = m.concentration end\r\nif cConc then\r\ne.conc, e.concBy = true, e.by\r\ne.ends = now + (casting.durMins or sp.mins or 1)\r\nelseif e.ends == nil or e.ends < 0 then\r\ne.conc, e.concBy = nil, nil\r\ne.ends = now + (casting.durMins or sp.bmins or 60)\r\nend\r\nt.buff[name] = e\r\nlocal used = Feat.cur.buffs[casting] or {}\r\nused[t] = true\r\nFeat.cur.buffs[casting] = used\r\nlocal mt = K.buffMechText(name, e)\r\nreturn head .. \"|ok|on \" .. (t.name or \"Player\") .. (mt ~= \"\" and (\": \" .. mt) or \"\") .. \"]\", true\r\nend\r\n\r\nfunction K.buffConc(pc)\r\nlocal all = { pc, table.unpack(Ally.list(pc)) }\r\nfor _, g in ipairs(Ally.guests(pc)) do all[#all + 1] = g end\r\nfor _, r in ipairs(all) do\r\nfor name, b in pairs(type(r.buff) == \"table\" and r.buff or {}) do\r\nif type(b) == \"table\" and b.concBy then\r\nlocal caster = (b.concBy == \"Player\") and pc or Ally.find(pc, b.concBy)\r\nif not (caster and type(caster.conc) == \"table\" and caster.conc.name == name) then r.buff[name] = nil end\r\nend\r\nend\r\nend\r\nend\r\n\r\nfunction K.buffText(r, who)\r\nlocal o = {}\r\nfor name, b in pairs(type(r.buff) == \"table\" and r.buff or {}) do\r\nif type(b) == \"table\" and b.by and not b.maxhp then\r\nlocal mt = K.buffMechText(name, b)\r\no[#o + 1] = name .. (b.choice and (\" (\" .. b.choice .. \")\") or \"\") .. (mt ~= \"\" and (\": \" .. mt) or \"\")\r\nelseif type(b) == \"table\" and b.maxhp and (b.res or b.cimm) then\r\no[#o + 1] = name .. \": \" .. K.buffMechText(name, b)\r\nend\r\nend\r\ntable.sort(o)\r\nreturn #o > 0 and (\"Spells on \" .. who .. \" (Lua ends them): \" .. table.concat(o, \"; \") .. \".\") or nil\r\nend\r\n\r\n\r\nfunction K.buffLive(pc, name, b)\r\nif not b.concBy then return true end\r\nlocal cr = (b.concBy == \"Player\") and pc or Ally.find(pc, b.concBy)\r\nreturn cr ~= nil and not cr.dead and (tonumber(cr.hp) or 0) > 0 and type(cr.conc) == \"table\" and cr.conc.name == name\r\nand not Cond.fx(cr).incap and not cr.conc.lost\r\nend\r\n\r\n\r\nfunction K.buffTurn(pc)\r\nlocal out = {}\r\nfor _, r in ipairs({ pc, table.unpack(Ally.list(pc)) }) do\r\nlocal names = {}\r\nfor name in pairs(type(r.buff) == \"table\" and r.buff or {}) do names[#names + 1] = name end\r\ntable.sort(names)\r\nfor _, name in ipairs(names) do\r\nlocal b = r.buff[name]\r\nif type(b) == \"table\" and not r.dead and K.buffLive(pc, name, b) then\r\nlocal who = r.name or \"Player\"\r\nif b.revive and (tonumber(r.hp) or 0) <= 0 then\r\nhealPC(r, 1)\r\nr.wake = nil\r\nout[#out + 1] = \"[BUFF|\" .. who .. \"|\" .. name .. \"|auto|up at 1 HP]\"\r\nend\r\nlocal n = tonumber(b.thp) or 0\r\nif n > (tonumber(r.thp) or 0) and (tonumber(r.hp) or 0) > 0 then\r\nr.thp = n\r\nout[#out + 1] = \"[BUFF|\" .. who .. \"|\" .. name .. \"|auto|temporary HP \" .. n .. \"]\"\r\nend\r\nend\r\nend\r\nend\r\nreturn out\r\nend\r\n\r\n\r\nfunction K.buffNewMax(rec)\r\nfor _, x in ipairs(Feat.cur.casts or {}) do\r\nlocal m = SPELLS[x.name] and SPELLS[x.name].m\r\nif m and m.maxheal and Feat.cur.buffs and Feat.cur.buffs[x] and Feat.cur.buffs[x][rec] then return true end\r\nend\r\nreturn false\r\nend\r\n\r\nfunction K.allMax(text, p)\r\nlocal given, i = {}, 0\r\nfor v in (text or \"\"):gmatch(\"%-?%d+\") do given[#given + 1] = tonumber(v) end\r\nfor _, x in ipairs(p and p.dice or {}) do\r\nfor _ = 1, x.n do\r\ni = i + 1\r\nif given[i] ~= x.s then return false end\r\nend\r\nend\r\nreturn i > 0\r\nend\r\n\r\nfunction K.partySkillNew(skill)\r\nfor _, x in ipairs(Feat.cur.casts or {}) do\r\nlocal m = SPELLS[x.name] and SPELLS[x.name].m\r\nlocal v = m and type(m.party_skill) == \"table\" and tonumber(m.party_skill[skill])\r\nif v then return v end\r\nend\r\nreturn 0\r\nend\r\n\r\nfunction K.maxHealOn(r)\r\nfor _, b in pairs(type(r) == \"table\" and type(r.buff) == \"table\" and r.buff or {}) do\r\nif type(b) == \"table\" and b.maxheal then return true end\r\nend\r\nreturn nil\r\nend\r\n\r\n\r\nfunction K.pierce(traits, atkR)\r\nif type(traits) ~= \"table\" or type(traits.res) ~= \"table\" or type(atkR) ~= \"table\" then return traits end\r\nlocal ig = {}\r\nfor _, e in ipairs(Feat.fxOf(atkR.sheet or SHEET, \"ignore_resist\")) do for _, ty in ipairs(e.types or {}) do ig[ty] = true end end\r\nif next(ig) == nil then return traits end\r\nlocal copy, res = {}, {}\r\nfor k, v in pairs(traits) do copy[k] = v end\r\nfor _, x in ipairs(traits.res) do if not ig[x] then res[#res + 1] = x end end\r\ncopy.res = res\r\nreturn copy\r\nend\r\n\r\nlocal function addXP(pc, n)\r\npc.xp = pc.xp + n\r\nend\r\n\r\nlocal function xpText(pc)\r\nreturn xpNext(pc) and string.format(\"XP %d/%d\", pc.xp, xpNext(pc)) or (\"XP \" .. pc.xp)\r\nend\r\n\r\nlocal function verifyXP(f, pc, budget)\r\n\r\nlocal amount = tonumber(f[1] or \"\")\r\nlocal head = \"[XP|\" .. (f[1] or \"\") .. \"|\" .. (f[2] or \"\")\r\nif not amount or amount <= 0 or amount ~= math.floor(amount) then\r\nreturn head .. \"|bad:amount|\" .. xpText(pc) .. \"]\", false\r\nend\r\n\r\nif not xpNext(pc) then return head .. \"|ok|\" .. xpText(pc) .. \" (max level)]\", true end\r\nlocal bad = {}\r\nlocal give = math.min(amount, budget.left)\r\nif give < amount then bad[#bad + 1] = \"cap \" .. give end\r\nbudget.left = budget.left - give\r\naddXP(pc, give)\r\nreturn head .. \"|\" .. verdictOf(bad) .. \"|\" .. xpText(pc) .. \"]\", #bad == 0\r\nend\r\n\r\nK.DON = { light = { 1, 1 }, medium = { 5, 1 }, heavy = { 10, 5 } }\r\n\r\nlocal function equippedCount(eq, name)\r\nlocal n = 0\r\nfor _, slot in ipairs({ \"armor\", \"main\", \"off\" }) do if eq[slot] == name then n = n + 1 end end\r\nreturn n\r\nend\r\n\r\n\r\nlocal function fixEquip(pc)\r\nlocal eq = pc.equip\r\nfor _, slot in ipairs({ \"off\", \"main\", \"armor\" }) do\r\nlocal name = eq[slot]\r\nif name and equippedCount(eq, name) > (pc.items[name] or 0) then eq[slot] = nil end\r\nend\r\nif not eq.main and eq.off and not K.isShield(pc, eq.off) then eq.main, eq.off = eq.off, nil end\r\nend\r\n\r\nlocal function isLoot(pc, name) return type(pc.loot) == \"table\" and type(pc.loot[name]) == \"table\" end\r\n\r\n\r\n\r\n\r\nfunction K.lootName(rec, name)\r\nname = trim(name or \"\")\r\nif name == \"\" or ITEMS[name] or type(rec) ~= \"table\" or type(rec.loot) ~= \"table\" or rec.loot[name] then return name end\r\nlocal words = {}\r\nfor w in name:gmatch(\"%S+\") do words[w] = true end\r\nlocal best, score, tie = nil, 0, false\r\nfor ln, l in pairs(rec.loot) do\r\nif type(l) == \"table\" and (tonumber((rec.items or {})[ln]) or 0) > 0 then\r\nlocal s = 0\r\nfor w in ln:gmatch(\"%S+\") do if words[w] then s = s + 1 end end\r\nif s > score then best, score, tie = ln, s, false elseif s == score and s > 0 then tie = true end\r\nend\r\nend\r\nif best and score >= 2 and not tie then return best end\r\nreturn name\r\nend\r\n\r\n\r\n\r\n\r\nK.STORY_GEAR = {\r\n[\"Backpack\"] = \"배낭\", [\"Ball Bearings\"] = \"쇠구슬\", [\"Barrel\"] = \"통\", [\"Basket\"] = \"바구니\", [\"Bedroll\"] = \"침낭\",\r\n[\"Bell\"] = \"종\", [\"Blanket\"] = \"담요\", [\"Block and Tackle\"] = \"도르래\", [\"Book\"] = \"책\", [\"Bottle\"] = \"병\", [\"Bucket\"] = \"양동이\",\r\n[\"Caltrops\"] = \"마름쇠\", [\"Candle\"] = \"양초\", [\"Case\"] = \"통\", [\"Chain\"] = \"쇠사슬\", [\"Chest\"] = \"상자\", [\"Climber's Kit\"] = \"등반 도구\",\r\n[\"Clothes\"] = \"옷\", [\"Component Pouch\"] = \"구성요소 주머니\", [\"Costume\"] = \"변장 의상\", [\"Crowbar\"] = \"쇠지렛대\", [\"Flask\"] = \"플라스크\",\r\n[\"Grappling Hook\"] = \"갈고리\", [\"Holy Symbol\"] = \"성표\", [\"Hunting Trap\"] = \"사냥 덫\", [\"Ink\"] = \"잉크\", [\"Ink Pen\"] = \"펜\",\r\n[\"Jug\"] = \"항아리\", [\"Ladder\"] = \"사다리\", [\"Lamp\"] = \"등잔\", [\"Lantern\"] = \"랜턴\", [\"Lock\"] = \"자물쇠\",\r\n[\"Magnifying Glass\"] = \"돋보기\", [\"Manacles\"] = \"수갑\", [\"Map\"] = \"지도\", [\"Mirror\"] = \"거울\", [\"Paper\"] = \"종이\",\r\n[\"Parchment\"] = \"양피지\", [\"Perfume\"] = \"향수\", [\"Pole\"] = \"장대\", [\"Pot\"] = \"솥\", [\"Pouch\"] = \"주머니\", [\"Quiver\"] = \"화살통\",\r\n[\"Ram\"] = \"충차\", [\"Rations\"] = \"식량\", [\"Robe\"] = \"로브\", [\"Rope\"] = \"밧줄\", [\"Sack\"] = \"자루\", [\"Shovel\"] = \"삽\",\r\n[\"Signal Whistle\"] = \"호루라기\", [\"Spikes\"] = \"쇠못\", [\"Spyglass\"] = \"망원경\", [\"String\"] = \"끈\", [\"Tent\"] = \"천막\",\r\n[\"Tinderbox\"] = \"부싯깃 통\", [\"Torch\"] = \"횃불\", [\"Vial\"] = \"유리병\", [\"Waterskin\"] = \"물주머니\", [\"Arcane Focus\"] = \"비전 매개체\",\r\n[\"Druidic Focus\"] = \"드루이드 매개체\", [\"Thieves' Tools\"] = \"도둑 도구\", [\"Rope (Hempen)\"] = \"밧줄\",\r\n}\r\n\r\n\r\nK.STORY_EXACT = {\r\n[\"Burglar's Pack\"] = true, [\"Diplomat's Pack\"] = \"외교관 꾸러미\", [\"Dungeoneer's Pack\"] = true, [\"Entertainer's Pack\"] = true,\r\n[\"Explorer's Pack\"] = true, [\"Priest's Pack\"] = true, [\"Scholar's Pack\"] = true, [\"Spellbook\"] = true, [\"Artisan's Tools\"] = true, [\"Net\"] = \"그물\",\r\n[\"Crystal\"] = \"수정\", [\"Orb\"] = \"구슬\", [\"Rod\"] = \"막대\", [\"Staff\"] = \"지팡이\", [\"Wand\"] = \"완드\", [\"Sprig of Mistletoe\"] = \"겨우살이 가지\",\r\n[\"Wooden Staff\"] = \"나무 지팡이\", [\"Yew Wand\"] = \"주목 완드\", [\"Amulet\"] = \"부적\", [\"Emblem\"] = \"문장\", [\"Reliquary\"] = \"성유물함\",\r\n[\"Dice\"] = \"주사위\", [\"Dragonchess\"] = \"드래곤 체스\", [\"Playing Cards\"] = \"카드\", [\"Three-Dragon Ante\"] = \"세 용 앤티\",\r\n[\"Bagpipes\"] = \"백파이프\", [\"Drum\"] = \"북\", [\"Dulcimer\"] = \"덜시머\", [\"Flute\"] = \"플루트\", [\"Horn\"] = \"뿔피리\", [\"Lute\"] = \"류트\", [\"Lyre\"] = \"리라\",\r\n[\"Pan Flute\"] = \"팬플루트\", [\"Shawm\"] = \"숌\", [\"Viol\"] = \"비올\",\r\n[\"Horse\"] = \"말\", [\"Camel\"] = \"낙타\", [\"Elephant\"] = \"코끼리\", [\"Draft Horse\"] = \"짐말\", [\"Riding Horse\"] = \"승용마\", [\"Mastiff\"] = \"마스티프\",\r\n[\"Mule\"] = \"노새\", [\"Pony\"] = \"조랑말\", [\"Warhorse\"] = \"전투마\", [\"Saddle\"] = \"안장\", [\"Exotic Saddle\"] = \"특수 안장\", [\"Military Saddle\"] = \"군용 안장\",\r\n[\"Riding Saddle\"] = \"승마용 안장\", [\"Feed\"] = \"사료\", [\"Carriage\"] = \"마차\", [\"Cart\"] = \"수레\", [\"Chariot\"] = \"전차\", [\"Sled\"] = \"썰매\", [\"Wagon\"] = \"짐마차\",\r\n[\"Airship\"] = \"비행선\", [\"Galley\"] = \"갤리선\", [\"Keelboat\"] = \"용골선\", [\"Longship\"] = \"롱십\", [\"Rowboat\"] = \"노 젓는 배\", [\"Sailing Ship\"] = \"범선\", [\"Warship\"] = \"전함\",\r\n}\r\n\r\nfunction K.storyGear(name)\r\nlocal n = trim(((name or \"\"):gsub(\"%b()\", \"\"):gsub(\",.*$\", \"\")))\r\nlocal function find(x)\r\nfor k, ko in pairs(K.STORY_GEAR) do if k:lower() == x:lower() then return k, ko end end\r\nend\r\nlocal function whole(x)\r\nfor k, ko in pairs(K.STORY_EXACT) do if k:lower() == x:lower() then return k, ko == true and (NAMES_KO[k] or k) or ko end end\r\nfor k, row in pairs(K.TOOLS or {}) do if k:lower() == x:lower() then return k, row.ko or k end end\r\nend\r\nlocal wk, wko = whole(n)\r\nif not wk then wk, wko = whole((n:gsub(\"s$\", \"\"))) end\r\nif wk then return wk, wko end\r\nlocal k, ko = find(n)\r\nif not k then k, ko = find((n:gsub(\"es$\", \"\"))) end\r\nif not k then k, ko = find((n:gsub(\"s$\", \"\"))) end\r\nif not k then k, ko = find((n:gsub(\"^%a+%s+\", \"\"))) end\r\nif not k then k, ko = find((n:gsub(\"^%a+%s+\", \"\"):gsub(\"s$\", \"\"))) end\r\nif not k then k, ko = find((n:gsub(\"^[%a']+%s+\", \"\"))) end\r\nreturn k, ko\r\nend\r\n\r\n\r\nlocal function dropLoot(pc, name)\r\nif isLoot(pc, name) and not pc.items[name] then pc.loot[name] = nil end\r\nend\r\n\r\nlocal function verifyItem(f, pc)\r\n\r\nlocal sign, name = (f[1] or \"\"):match(\"^([+-])%s*(.-)%s*$\")\r\n\r\nif name and name:match(\"^[123] \") and not ITEMS[name] and K.MI.parse(\"+\" .. name) then name = \"+\" .. name end\r\n\r\nif name then\r\nlocal nm, each = K.itemName(name, pc)\r\nif nm ~= name then\r\nname, f[1] = nm, sign .. nm\r\nif each then f[2] = tostring((tonumber(f[2] or \"1\") or 1) * each) end\r\nend\r\nend\r\nif sign == \"-\" then name = K.lootName(pc, name) end\r\nlocal n = tonumber(f[2] or \"1\")\r\nlocal head = \"[ITEM|\" .. (f[1] or \"\") .. \"|\" .. (f[2] or \"1\")\r\nif not sign or name == \"\" then return head .. \"|bad:write +Name or -Name|-]\", false end\r\n\r\n\r\nif name and name ~= \"\" and not ITEMS[name] and not isLoot(pc, name) then\r\nlocal p, why = K.MI.parse(name)\r\nif p then\r\nlocal cn = K.MI.canon(p)\r\nif sign == \"-\" and not isLoot(pc, cn) then return head .. \"|bad:not in items|0]\", false end\r\nif sign == \"+\" and not isLoot(pc, cn) then\r\nlocal okm, whyc = K.MI.allowed(p, pc)\r\nif not okm then return head .. \"|bad:\" .. whyc .. \"|-]\", false end\r\nif not n or n <= 0 or n ~= math.floor(n) then return head .. \"|bad:count|0]\", false end\r\npc.loot = type(pc.loot) == \"table\" and pc.loot or {}\r\npc.loot[cn] = K.MI.record(p)\r\nend\r\nname = cn\r\nhead = \"[ITEM|\" .. sign .. cn .. \"|\" .. (f[2] or \"1\")\r\nelseif why then\r\nreturn head .. \"|bad:\" .. why .. \"|-]\", false\r\nend\r\nend\r\nif not ITEMS[name] and not isLoot(pc, name) and K.storyGear(name) then\r\nreturn head .. \"|bad:story gear: Lua does not count it, the story carries it (no ITEM tag)|-]\", false\r\nend\r\nif not ITEMS[name] and not isLoot(pc, name) then\r\nreturn head .. \"|bad:unknown item\" .. (sign == \"+\" and \" (a new magic or unusual item: LOOT)\" or \"\") .. \"|-]\", false\r\nend\r\nif not n or n <= 0 or n ~= math.floor(n) then return head .. \"|bad:count|\" .. (pc.items[name] or 0) .. \"]\", false end\r\nif sign == \"-\" then local ch = K.MI.cursedHold(pc, name); if ch then return head .. \"|bad:\" .. ch .. \"|\" .. (pc.items[name] or 0) .. \"]\", false end end\r\n\r\n\r\nif sign == \"-\" and name == K.KIT and (pc.items[name] or 0) > 0 then\r\nlocal left = K.kitLeft(pc)\r\nlocal kb = {}\r\nif n > left then kb[#kb + 1] = \"only \" .. left .. \" uses\"; n = left end\r\nfor _ = 1, n do K.kitSpend(pc) end\r\nfixEquip(pc)\r\nreturn head .. \"|\" .. verdictOf(kb) .. \"|\" .. (pc.items[name] or 0) .. \"|kit uses \" .. K.kitLeft(pc) .. \"]\", #kb == 0\r\nend\r\nlocal bad = {}\r\nlocal have = pc.items[name] or 0\r\nif sign == \"+\" then\r\nhave = have + n\r\nelse\r\nif n > have then bad[#bad + 1] = \"only had \" .. have; n = have end\r\nhave = have - n\r\nend\r\npc.items[name] = (have > 0) and have or nil\r\nfixEquip(pc)\r\ndropLoot(pc, name)\r\nreturn head .. \"|\" .. verdictOf(bad) .. \"|\" .. have .. \"]\", #bad == 0\r\nend\r\n\r\n\r\nlocal function coinsOf(s)\r\ns = (s or \"\"):lower():gsub(\",\", \"\")\r\nif s:match(\"^%s*%d+%s*$\") then return tonumber(s) * COIN.gp end\r\nlocal cp, seen = 0, false\r\nfor n, u in s:gmatch(\"(%d+)%s*(%a+)\") do\r\nif not COIN[u] then return nil end\r\ncp, seen = cp + tonumber(n) * COIN[u], true\r\nend\r\nreturn seen and cp or nil\r\nend\r\n\r\nlocal function verifyGold(f, pc)\r\n\r\n\r\nlocal sign, rest = (f[1] or \"\"):match(\"^%s*([+-])%s*(.-)%s*$\")\r\nlocal head = \"[GOLD|\" .. (f[1] or \"\")\r\nlocal cp = sign and coinsOf(rest)\r\nif not cp then return head .. \"|bad:write +5 gp, -3 sp or -1 gp 5 sp (pp, gp, sp, cp)|\" .. moneyText(pc.cp) .. \"]\", false end\r\nlocal delta = cp * (sign == \"-\" and -1 or 1)\r\nif pc.cp + delta < 0 then return head .. \"|bad:not enough|\" .. moneyText(pc.cp) .. \"]\", false end\r\npc.cp = pc.cp + delta\r\nreturn head .. \"|ok|\" .. moneyText(pc.cp) .. \"]\", true\r\nend\r\n\r\n\r\n\r\n\r\n\r\nlocal function verifyTrade(f, pc, tag)\r\nlocal TRADE_RANGE = { BUY = { 0.5, 2 }, SELL = { 0, 1 } }\r\nlocal name, count, priceText = f[1] or \"\", tonumber(f[2] or \"\"), f[3] or \"\"\r\nlocal head = \"[\" .. tag .. \"|\" .. name .. \"|\" .. (f[2] or \"\") .. \"|\" .. priceText\r\nlocal function fail(why) return head .. \"|bad:\" .. why .. \"|\" .. moneyText(pc.cp) .. \"|-]\", false end\r\nif name == \"\" then return fail(\"name\") end\r\nif not count or count <= 0 or count ~= math.floor(count) then return fail(\"count\") end\r\nlocal cp = coinsOf(priceText)\r\nif not cp then return fail(\"write the total price, e.g. 10 gp\") end\r\nlocal bad = {}\r\n\r\n\r\nlocal made\r\nif not ITEMS[name] and not isLoot(pc, name) then\r\nlocal p, why = K.MI.parse(name)\r\nif p then\r\nlocal cn = K.MI.canon(p)\r\nif p.r == \"X\" then return fail(\"an Artifact is not for sale\") end\r\nif not isLoot(pc, cn) then\r\nif tag == \"SELL\" then return fail(\"not in items\") end\r\nlocal okm, whyc = K.MI.allowed(p, pc)\r\nif not okm then return fail(whyc) end\r\npc.loot = type(pc.loot) == \"table\" and pc.loot or {}\r\npc.loot[cn] = K.MI.record(p)\r\nmade = cn\r\nend\r\nname = cn\r\nhead = \"[\" .. tag .. \"|\" .. cn .. \"|\" .. (f[2] or \"\") .. \"|\" .. priceText\r\nelseif why then\r\nreturn fail(why)\r\nend\r\nend\r\nlocal loot = isLoot(pc, name) and pc.loot[name]\r\nlocal gm = loot and loot.srd and K.MAGIC and K.MAGIC[loot.srd]\r\nlocal unit = loot and ((gm and gm.mundane and coinsOf(gm.cost)) or (loot.cost and coinsOf(loot.cost)))\r\nor loot and (loot.srd and (math.floor((K.MI.VALUE[loot.grade] or 0) * (loot.consumable and 0.5 or 1)) + (PRICE[loot.base] or 0))\r\nor ((LOOT.VALUE[loot.grade] or 0) + (PRICE[loot.base] or 0))) or (ITEMS[name] and PRICE[name])\r\nlocal counted = unit and true or false\r\nif counted then\r\nlocal list = unit * count\r\nlocal r = TRADE_RANGE[tag]\r\nlocal lo, hi = math.floor(list * r[1]), math.max(1, math.ceil(list * r[2]))\r\nlocal fixed = math.max(lo, math.min(hi, cp))\r\nif fixed ~= cp then\r\nbad[#bad + 1] = \"price \" .. moneyText(cp) .. \"->\" .. moneyText(fixed) .. \" (SRD \" .. moneyText(math.ceil(list)) .. \")\"\r\ncp = fixed\r\nend\r\nend\r\nif tag == \"SELL\" then local chs = K.MI.cursedHold(pc, name); if chs then return fail(chs) end end\r\nif tag == \"BUY\" then\r\nif pc.cp < cp then\r\nif made then pc.loot[made] = nil end\r\nreturn fail(\"not enough money\")\r\nend\r\npc.cp = pc.cp - cp\r\nif counted then pc.items[name] = (pc.items[name] or 0) + count end\r\nelse\r\nif counted then\r\nlocal free = (pc.items[name] or 0) - equippedCount(pc.equip, name)\r\nif free < count then return fail(((pc.items[name] or 0) >= count) and \"equipped: unequip first\" or (\"only had \" .. math.max(0, free))) end\r\npc.items[name] = pc.items[name] - count\r\nif pc.items[name] <= 0 then pc.items[name] = nil end\r\ndropLoot(pc, name)\r\nend\r\npc.cp = pc.cp + cp\r\nend\r\nreturn head .. \"|\" .. verdictOf(bad) .. \"|\" .. moneyText(pc.cp) .. \"|\" .. (counted and tostring(pc.items[name] or 0) or \"-\") .. \"]\", #bad == 0\r\nend\r\n\r\n\r\n\r\n\r\n\r\n\r\nfunction K.ownMode(rec, what, ab, spell)\r\nlocal adv, dis = false, false\r\nfor name in pairs(type(rec) == \"table\" and Cond.load(rec) or {}) do\r\nlocal m = CONDS[name]\r\nlocal v = m and ((what == \"attack\" and m.own_attacks) or (what == \"check\" and m.own_checks)) or nil\r\nif v == \"advantage\" then adv = true elseif v == \"disadvantage\" then dis = true end\r\nend\r\nlocal mode = type(rec) == \"table\" and type(rec.mode) == \"table\" and rec.mode.name\r\nif what == \"attack\" and spell and mode == \"Innate Sorcery\" then adv = true end\r\nif (what == \"check\" or what == \"save\") and ab == \"Strength\" and mode == \"Rage\" then adv = true end\r\nif adv and dis then return nil, adv, dis end\r\nreturn adv and \"adv\" or (dis and \"dis\") or nil, adv, dis\r\nend\r\n\r\n\r\n\r\nfunction K.checkOdds(r, nm)\r\nlocal isSave = nm:match(\" save$\") ~= nil\r\nlocal ab = isSave and nm:gsub(\" save$\", \"\") or (type(SKILL[nm]) == \"string\" and SKILL[nm]) or (MOD[nm] and nm) or nil\r\nlocal tool = not (SKILL[nm] or MOD[nm] or isSave) and K.toolOf(nm) or nil\r\nlocal o = { mode = K.ownMode(r, isSave and \"save\" or \"check\", ab) }\r\nif isSave and ab and Cond.fx(r).autofail[ab] then o.auto0 = true end\r\nif SHEET and ((SKILL[nm] and SKILL_PROF[nm]) or (tool and K.toolProfs(SHEET)[tool])) then\r\nfor _, e in ipairs(Feat.fxOf(SHEET, \"d20_floor\")) do\r\nif (e.on == nil or e.on == \"proficient_check\") and tonumber(e.value) then o.floor = math.max(o.floor or 0, tonumber(e.value)) end\r\nend\r\nend\r\nlocal fl = SHEET and K.d20Floor(SHEET, isSave and \"save\" or \"check\", ab)\r\nif fl then o.floor = math.max(o.floor or 0, fl) end\r\nreturn o\r\nend\r\nlocal function verifyOpt(f, pc, c)\r\nlocal kind, dcText = f[2] or \"-\", f[3] or \"\"\r\nlocal head = \"[OPT|\" .. (f[1] or \"\") .. \"|\" .. kind .. \"|\" .. dcText\r\n\r\nlocal hz = K.HAZ[Canon.name(kind)]\r\nlocal u = c and c.units and c.units[trim(dcText)]\r\nif hz and (hz.save or hz.either) then\r\nif not u then return head .. \"|bad:write the target's name for \" .. kind .. \"|-]\" end\r\nlocal sv = MONSTERS[u.kind].saves or {}\r\nlocal bonus = hz.either and math.max(sv[hz.either[1]] or 0, sv[hz.either[2]] or 0) or (sv[hz.save] or 0)\r\nlocal dc = hz.shove and K.shoveDC() or (8 + K.abMod(\"Dexterity\") + PROF)\r\nlocal fails = 0\r\nfor r = 1, 20 do if r + bonus < dc then fails = fails + 1 end end\r\nreturn head .. \"|ok|\" .. (fails * 5) .. \"]\"\r\nend\r\n\r\nlocal kl = kind:lower()\r\nif kind == \"-\" or kind == \"\" or kl == \"spellcasting\" or kl == \"spell\" or kl == \"magic\" or SPELLS[kind] then return head .. \"|ok|-]\" end\r\nif trim(dcText) == \"\" or trim(dcText) == \"-\" then return head .. \"|ok|-]\" end\r\nlocal dc = tonumber(dcText)\r\nif not dc or dc < 1 or dc > 30 then return head .. \"|bad:DC 1-30|-]\" end\r\n\r\n\r\nlocal implR, implN\r\nif kind ~= \"Attack\" and K.AR and K.AR.on() and K.PACK.impl then implR, implN = K.AR.impl(kind, pc, pc, true) end\r\nif implR and not K.AR.implHas(SHEET, implR, implN) then return head .. \"|bad:Player has no \" .. implN .. \"|-]\" end\r\n\r\n\r\n\r\nlocal sk = kind:match(\"/%s*(.+)$\") or kind\r\nlocal passKey = (sk == \"Stealth\" or sk == \"Sleight of Hand\") and \"pp\" or sk == \"Deception\" and \"pi\" or nil\r\nlocal planDc\r\nif passKey and K.planNow and not (c and c.active) then\r\nfor _, n in ipairs(K.planNow) do\r\nlocal v = MONSTERS[n] and tonumber(MONSTERS[n][passKey])\r\nif v and (not planDc or v > planDc) then planDc = v end\r\nend\r\nend\r\nif planDc then\r\ndc, dcText = planDc, tostring(planDc)\r\nhead = \"[OPT|\" .. (f[1] or \"\") .. \"|\" .. kind .. \"|\" .. dcText\r\nend\r\n\r\nlocal fl = K.dcFloor()\r\nif fl and not planDc and kind ~= \"Attack\" and not implR and dc < fl and not (c and c.active) then\r\ndc = fl\r\ndcText = tostring(fl)\r\nhead = \"[OPT|\" .. (f[1] or \"\") .. \"|\" .. kind .. \"|\" .. dcText\r\nend\r\nlocal bonus, mode, floor, auto0\r\nif kind == \"Attack\" then\r\nfor _, a in ipairs(pcStats(pc).attacks) do if not bonus or a.hit > bonus then bonus = a.hit end end\r\nmode = K.ownMode(pc, \"attack\")\r\nfloor = SHEET and K.d20Floor(SHEET, \"attack\", nil)\r\nelseif implR then\r\nbonus = K.AR.implNums(pc, implR, implN, pc)\r\nmode = K.ownMode(pc, \"attack\")\r\nelse\r\n\r\n\r\nlocal rec, rest = Ally.prefix(pc, kind)\r\nlocal odds\r\nif rec then\r\nbonus = Ally.with(rec, function()\r\nlocal b = bonusFor(rest)\r\nodds = K.checkOdds(rec, rest)\r\nreturn b and (b - Cond.fx(rec).pen)\r\nend)\r\nelseif rec == nil then\r\nbonus = bonusFor(rest or kind)\r\nif bonus then bonus = bonus - Cond.fx(pc).pen end\r\n\r\nodds = K.checkOdds(pc, rest or kind)\r\nend\r\nif odds then mode, floor, auto0 = odds.mode, odds.floor, odds.auto0 end\r\nend\r\nif not bonus then return head .. \"|bad:unknown skill|-]\" end\r\nif auto0 then return head .. \"|ok|0]\" end\r\nlocal wins = 0\r\nfor r = 1, 20 do\r\nlocal rr = math.max(r, floor or 0)\r\nlocal hit = rr + bonus >= dc\r\nif kind == \"Attack\" or implR then hit = rr == 20 or (rr ~= 1 and hit) end\r\nif hit then wins = wins + 1 end\r\nend\r\nlocal p = wins / 20\r\nif mode == \"adv\" then p = 1 - (1 - p) ^ 2 elseif mode == \"dis\" then p = p * p end\r\nreturn head .. \"|ok|\" .. math.floor(p * 100 + 0.5) .. \"]\"\r\nend\r\n\r\n\r\n\r\n\r\nlocal function verifyLoot(f, pc, ctx)\r\n\r\nlocal function cutText(s, n)\r\nif (utf8.len(s) or #s) <= n then return s end\r\nreturn s:sub(1, (utf8.offset(s, n + 1) or (#s + 1)) - 1)\r\nend\r\nlocal name = cutText(trim((f[1] or \"\"):gsub(\"[%^;]\", \"\")), 40)\r\nlocal fx = cutText(trim(f[4] or \"\"), 80)\r\nlocal head = \"[LOOT|\" .. name .. \"|\" .. (f[2] or \"\") .. \"|\" .. (f[3] or \"-\") .. \"|\" .. fx\r\nlocal function fail(why) return head .. \"|bad:\" .. why .. \"|-]\", false end\r\nif name == \"\" then return fail(\"name\") end\r\nif ITEMS[name] then return fail(\"an SRD item: write ITEM\") end\r\n\r\nif K.MI.parse(name) then return verifyItem({ \"+\" .. name, \"1\" }, pc) end\r\nlocal bad = {}\r\nlocal grade = (f[2] or \"\"):upper():match(\"^%s*([CBAS])%s*$\")\r\nif not grade then bad[#bad + 1] = \"grade C, B, A or S\"; grade = \"C\" end\r\nlocal cap = LOOT.maxGrade(pc.level)\r\nif LOOT.GRADE[grade] > LOOT.GRADE[cap] then\r\nbad[#bad + 1] = string.format(\"grade %s->%s at level %d\", grade, cap, pc.level)\r\ngrade = cap\r\nend\r\n\r\n\r\nif LOOT.GRADE[grade] > LOOT.GRADE.C then\r\nif ctx.loot then return fail(\"one LOOT of grade B or higher per reply (grade C story objects any number)\") end\r\nctx.loot = true\r\nend\r\nlocal base = Canon.name(f[3] or \"-\")\r\nlocal a = ARMOR[base]\r\nif base == \"-\" or base == \"\" then\r\nbase = nil\r\nelseif not (WEAPONS[base] or a) then\r\nbad[#bad + 1] = \"base is an SRD weapon, armor or Shield (kept as a trinket)\"\r\nbase = nil\r\nend\r\n\r\nlocal pw, words = {}, {}\r\nfor i = 5, #f do\r\nfor w in ((f[i] or \"\") .. \",\"):gmatch(\"([^,]*),\") do if trim(w) ~= \"\" then words[#words + 1] = trim(w) end end\r\nend\r\nlocal weapon = base and WEAPONS[base] ~= nil\r\nlocal had = type(pc.loot) == \"table\" and pc.loot[name]\r\nlocal keepPw = type(had) == \"table\" and type(had.pw) == \"table\" and #had.pw > 0\r\n\r\n\r\nlocal fixing = type(had) == \"table\" and type(had.pwFix) == \"table\"\r\nif fixing then keepPw = false; grade = had.grade or grade end\r\nlocal tooHigh\r\nfor _, w in ipairs(words) do\r\nlocal lw = w:lower()\r\nlocal spellName = lw:match(\"^spell%s+(.+)$\") and Canon.name(trim(w:sub(6)))\r\nif spellName then\r\nlocal sp = SPELLS[spellName]\r\nif not sp then\r\nbad[#bad + 1] = \"power \" .. w .. \": an \" .. K.srdX() .. \" spell\"\r\nelseif K.spellOff(spellName) then\r\nbad[#bad + 1] = \"power \" .. w .. \": \" .. K.spellOff(spellName)\r\nelseif sp.level > (LOOT.SPELL_MAX[grade] or 0) then\r\n\r\n\r\n\r\nlocal up\r\nfor _, g in ipairs({ \"A\", \"S\" }) do\r\nif not up and LOOT.GRADE[grade] >= LOOT.GRADE.B and LOOT.GRADE[g] > LOOT.GRADE[grade] and LOOT.GRADE[g] <= LOOT.GRADE[cap]\r\nand sp.level <= LOOT.SPELL_MAX[g] then up = g end\r\nend\r\nif up and #pw < LOOT.MAXPW[up] and not keepPw and not fixing then\r\nbad[#bad + 1] = string.format(\"grade %s->%s: %s is a level %d spell\", grade, up, spellName, sp.level)\r\ngrade = up\r\npw[#pw + 1] = { k = \"spell\", spell = spellName, uses = LOOT.SPELL_USES[grade] }\r\nelse\r\nbad[#bad + 1] = string.format(\"power %s: grade %s casts up to level %d\", w, grade, LOOT.SPELL_MAX[grade] or 0)\r\ntooHigh = tooHigh or spellName\r\nend\r\nelseif #pw >= LOOT.MAXPW[grade] then\r\nbad[#bad + 1] = string.format(\"power %s: grade %s has %d\", w, grade, LOOT.MAXPW[grade])\r\nelse\r\npw[#pw + 1] = { k = \"spell\", spell = spellName, uses = LOOT.SPELL_USES[grade] }\r\nend\r\ngoto continue\r\nend\r\nlocal dt\r\nfor word in lw:gmatch(\"%a+\") do if K.DTYPES[word] then dt = word:sub(1, 1):upper() .. word:sub(2) end end\r\nlocal k = (lw:find(\"resist\", 1, true) and \"resist\") or ((lw:find(\"dmg\", 1, true) or lw:find(\"damage\", 1, true)) and \"dmg\")\r\nor (lw:find(\"crit\", 1, true) and \"crit\") or (lw:find(\"save\", 1, true) and \"save\") or nil\r\nif not k or ((k == \"dmg\" or k == \"resist\") and not dt) then\r\nbad[#bad + 1] = \"power \" .. w .. \": dmg Type, crit, resist Type, save or spell Name\"\r\nelseif (k == \"dmg\" or k == \"crit\") and not weapon then\r\nbad[#bad + 1] = \"power \" .. w .. \": dmg and crit on a weapon\"\r\nelseif (k == \"resist\" or k == \"save\") and weapon then\r\nbad[#bad + 1] = \"power \" .. w .. \": resist and save on armor, a Shield or a trinket\"\r\nelseif k == \"crit\" and LOOT.GRADE[grade] < 2 and grade == \"B\" and LOOT.GRADE[cap] >= LOOT.GRADE.A and weapon and #pw < LOOT.MAXPW.A and not keepPw then\r\n\r\nbad[#bad + 1] = \"grade B->A: crit is grade A's\"\r\ngrade = \"A\"\r\npw[#pw + 1] = { k = \"crit\" }\r\nelseif k == \"crit\" and LOOT.GRADE[grade] < 2 then\r\nbad[#bad + 1] = \"power crit: grade A or S\"\r\nelseif #pw >= LOOT.MAXPW[grade] then\r\nbad[#bad + 1] = string.format(\"power %s: grade %s has %d\", w, grade, LOOT.MAXPW[grade])\r\nelse\r\npw[#pw + 1] = { k = k, type = dt, dice = k == \"dmg\" and LOOT.DIE[grade] or nil }\r\nend\r\n::continue::\r\nend\r\npc.loot = type(pc.loot) == \"table\" and pc.loot or {}\r\nlocal l = pc.loot[name]\r\n\r\nif fixing and type(l) == \"table\" then\r\nlocal added = false\r\nl.pw = type(l.pw) == \"table\" and l.pw or {}\r\nfor _, p in ipairs(pw) do\r\nif p.k == \"spell\" and #l.pw < (LOOT.MAXPW[l.grade] or 0) then l.pw[#l.pw + 1] = p; added = true end\r\nend\r\nif #l.pw == 0 then l.pw = nil end\r\nif added then l.pwFix = nil; LOOT.refill({ loot = { [name] = l } })\r\nelse bad[#bad + 1] = string.format(\"write its spell power: spell Name, level %d or lower\", LOOT.SPELL_MAX[l.grade] or 0) end\r\nlocal pwt = LOOT.pwText(l.pw)\r\nreturn head .. (#words > 0 and (\"|\" .. table.concat(words, \", \")) or \"\") .. \"|\" .. verdictOf(bad) .. \"|\" .. (l.base and (\"+\" .. l.plus) or \"-\")\r\n.. (pwt ~= \"\" and (\"|\" .. pwt) or \"\") .. (added and \" (its spell power set)\" or \"\") .. \"]\", #bad == 0\r\nend\r\nif type(l) == \"table\" then\r\nif LOOT.GRADE[grade] > (LOOT.GRADE[l.grade] or 0) then\r\nl.grade = grade\r\nif l.base then l.plus = LOOT.GRADE[grade] end\r\nelseif (LOOT.GRADE[l.grade] or 0) > LOOT.GRADE[grade] then\r\nbad[#bad + 1] = string.format(\"grade %s->%s: %s is grade %s already\", grade, l.grade, name, l.grade)\r\nend\r\nif #pw > 0 and not keepPw then l.pw = pw end\r\nelse\r\nl = { grade = grade, base = base, plus = base and LOOT.GRADE[grade] or 0, fx = fx, pw = #pw > 0 and pw or nil }\r\npc.loot[name] = l\r\nend\r\n\r\nfor _, p in ipairs(type(l.pw) == \"table\" and l.pw or {}) do\r\nif p.k == \"spell\" then p.uses = LOOT.SPELL_USES[l.grade] elseif p.k == \"dmg\" then p.dice = LOOT.DIE[l.grade] end\r\nend\r\npc.items[name] = (pc.items[name] or 0) + 1\r\n\r\nif tooHigh and #(type(l.pw) == \"table\" and l.pw or {}) < (LOOT.MAXPW[l.grade] or 0) and (LOOT.SPELL_MAX[l.grade] or 0) > 0 then\r\nl.pwFix = { want = tooHigh, max = LOOT.SPELL_MAX[l.grade] }\r\nend\r\nLOOT.refill({ loot = { [name] = l } })\r\nlocal pwt = LOOT.pwText(l.pw)\r\nreturn head .. (#words > 0 and (\"|\" .. table.concat(words, \", \")) or \"\") .. \"|\" .. verdictOf(bad) .. \"|\" .. (l.base and (\"+\" .. l.plus) or \"-\")\r\n.. (pwt ~= \"\" and (\"|\" .. pwt) or \"\") .. \"]\", #bad == 0\r\nend\r\n\r\n\r\n\r\n\r\n\r\n\r\nfunction Quest.cut(s)\r\ns = trim((s or \"\"):gsub(\"[%^;]\", \"\"))\r\nif (utf8.len(s) or #s) <= 40 then return s end\r\nreturn s:sub(1, (utf8.offset(s, 41) or (#s + 1)) - 1)\r\nend\r\n\r\nfunction Quest.load(pc)\r\nlocal q = type(pc.quests) == \"table\" and pc.quests or {}\r\nq.next = tonumber(q.next) or 1\r\nq.list = type(q.list) == \"table\" and q.list or {}\r\npc.quests = q\r\nreturn q\r\nend\r\n\r\n\r\nfunction Quest.foes(place, level, boss)\r\nlocal b = BUDGET[level] or BUDGET[#BUDGET]\r\nlocal cand = {}\r\nfor name, m in pairs(MONSTERS) do\r\nlocal here = false\r\nfor _, h in ipairs(m.hab or {}) do if h == place then here = true end end\r\nif here and #m.attacks > 0 then\r\nif boss and m.xp <= b[3] and m.xp >= b[2] / 2 then cand[#cand + 1] = name end\r\nif not boss and m.xp <= b[2] and m.xp * 4 >= b[2] / 2 then cand[#cand + 1] = name end\r\nend\r\nend\r\nif #cand == 0 then return {} end\r\ntable.sort(cand)\r\nlocal kind = cand[math.random(1, #cand)]\r\nif boss then return { kind } end\r\nlocal n = math.max(1, math.min(4, math.floor(b[2] / MONSTERS[kind].xp)))\r\nlocal out = {}\r\nfor i = 1, n do out[i] = kind end\r\nreturn out\r\nend\r\n\r\nfunction Quest.foeText(foes)\r\nlocal count, order = {}, {}\r\nfor _, k in ipairs(foes or {}) do\r\nif not count[k] then order[#order + 1] = k end\r\ncount[k] = (count[k] or 0) + 1\r\nend\r\nlocal parts = {}\r\nfor _, k in ipairs(order) do\r\n\r\nlocal m = MONSTERS[k]\r\nlocal about = m and table.concat({ m.ko or nil, (m.what ~= \"\" and m.what) or nil }, \"; \") or \"\"\r\nparts[#parts + 1] = (count[k] > 1 and (count[k] .. \" \" .. k) or k) .. (about ~= \"\" and (\" (\" .. about .. \")\") or \"\")\r\nend\r\nreturn #parts > 0 and table.concat(parts, \" and \") or \"a foe that fits the place\"\r\nend\r\n\r\n\r\n\r\n\r\n\r\nK.READY_PLACES = { \"Ruins\", \"Underdark\", \"Forest\" }\r\n\r\n\r\nfunction K.readyFoes(pc, clock, salt)\r\nif pc.place ~= \"wild\" then return nil end\r\nlocal bi = ({ easy = 1, hard = 3 })[K.FIGHT_D or \"mid\"] or 2\r\nlocal budget, cap = Ally.budget(pc, bi), 3\r\nlocal day = math.floor((tonumber(type(clock) == \"table\" and clock.min) or 0) / 1440)\r\nlocal out = {}\r\nfor i, place in ipairs(K.READY_PLACES) do\r\nlocal cand = {}\r\nfor name, m in pairs(MONSTERS) do\r\nlocal here = false\r\nfor _, h in ipairs(m.hab or {}) do if h == place then here = true end end\r\nif here and #m.attacks > 0 and m.xp <= budget and m.xp * cap >= budget / 2 then cand[#cand + 1] = name end\r\nend\r\nif #cand > 0 then\r\ntable.sort(cand)\r\nlocal kind = cand[(day * 7 + i * 13 + (tonumber(salt) or 0)) % #cand + 1]\r\nlocal foes = {}\r\nfor j = 1, math.max(1, math.min(cap, math.floor(budget / MONSTERS[kind].xp))) do foes[j] = kind end\r\nout[#out + 1] = place .. \": \" .. Quest.foeText(foes)\r\nend\r\nend\r\nif #out == 0 then return nil end\r\nreturn \"Ready fights at the \" .. (({ \"Low\", \"Moderate\", \"High\" })[bi] or \"Moderate\") .. \" budget, only if the story brings a fight (take the one that fits the place, or your own): \"\r\n.. table.concat(out, \"; \") .. \".\"\r\nend\r\n\r\n\r\nfunction Quest.payLeft(x, ending)\r\nlocal base = ending == \"success\" and x.gp or ending == \"partial\" and math.floor(x.gp / 2) or 0\r\nreturn math.max(0, base - (tonumber(x.adv) or 0))\r\nend\r\n\r\nfunction Quest.find(q, idText)\r\nlocal num = tonumber((idText or \"\"):match(\"#?(%d+)\") or \"\")\r\nfor i, x in ipairs(q.list) do\r\nif (num and x.id == num) or (not num and #q.list == 1) then return x, i end\r\nend\r\nreturn nil, nil\r\nend\r\n\r\nQuest.SCALE_KO = { [\"마을\"] = \"village\", [\"촌락\"] = \"village\", [\"시골\"] = \"village\", [\"도시\"] = \"city\", [\"town\"] = \"city\", [\"귀족\"] = \"noble\",\r\n[\"영주\"] = \"noble\", [\"왕국\"] = \"kingdom\", [\"국가\"] = \"kingdom\", [\"나라\"] = \"kingdom\" }\r\nQuest.PLACE_KO = { [\"숲\"] = \"Forest\", [\"폐허\"] = \"Ruins\", [\"유적\"] = \"Ruins\", [\"탑\"] = \"Ruins\", [\"도시\"] = \"Urban\", [\"시가지\"] = \"Urban\", [\"초원\"] = \"Grassland\",\r\n[\"평원\"] = \"Grassland\", [\"언덕\"] = \"Hill\", [\"구릉\"] = \"Hill\", [\"이계\"] = \"Planar\", [\"언더다크\"] = \"Underdark\", [\"지하\"] = \"Underdark\",\r\n[\"산\"] = \"Mountain\", [\"산악\"] = \"Mountain\", [\"늪\"] = \"Swamp\", [\"습지\"] = \"Swamp\", [\"사막\"] = \"Desert\", [\"해안\"] = \"Coastal\",\r\n[\"바닷가\"] = \"Coastal\", [\"물속\"] = \"Underwater\", [\"수중\"] = \"Underwater\", [\"극지\"] = \"Arctic\", [\"설원\"] = \"Arctic\" }\r\n\r\n\r\n\r\n\r\n\r\nfunction Quest.coin(s)\r\nlocal n = (s or \"\"):lower():gsub(\"백금화\", \"pp\"):gsub(\"금화\", \"gp\"):gsub(\"은화\", \"sp\"):gsub(\"동화\", \"cp\")\r\nn = n:gsub(\"([gscp]p)%s*(%d+)\", \"%2 %1\")\r\nlocal rest = n:gsub(\"%d+%s*[gscp]p\", \"\"):gsub(\"[%s,]\", \"\")\r\nif rest ~= \"\" and not rest:match(\"^%d+$\") then return nil end\r\nreturn coinsOf(n)\r\nend\r\nfunction Quest.reward(v, guide)\r\nv = trim(v or \"\")\r\nif v == \"\" or v == \"-\" then return guide, nil end\r\nlocal low = v:lower()\r\nif low == \"none\" or v == \"없음\" or v == \"무보수\" then return 0, nil end\r\nlocal cp = Quest.coin(v)\r\nif cp and cp >= 0 then return cp // COIN.gp, nil end\r\nlocal a, b = v:match(\"^(.-)%s*%+%s*(.+)$\")\r\nif a and Quest.coin(a) then return Quest.coin(a) // COIN.gp, Quest.cut(b) end\r\nif b and Quest.coin(b) then return Quest.coin(b) // COIN.gp, Quest.cut(a) end\r\nreturn 0, Quest.cut(v)\r\nend\r\nfunction Quest.rewardText(x)\r\nlocal coin = (tonumber(x.gp) or 0) > 0 and (x.gp .. \" gp\") or nil\r\nif x.prize and coin then return coin .. \" + \" .. x.prize end\r\nreturn x.prize or coin or \"none\"\r\nend\r\n\r\nfunction Quest.verify(f, pc)\r\nlocal q = Quest.load(pc)\r\nlocal raw = \"[QUEST|\" .. table.concat(f, \"|\")\r\nlocal function fail(why) return raw .. \"|bad:\" .. why .. \"|-]\", false end\r\nlocal title = (f[1] or \"\"):match(\"^%s*%+%s*(.-)%s*$\")\r\nif title then\r\nif title == \"\" then return fail(\"title\") end\r\nif #q.list >= Quest.MAX then return fail(\"already \" .. Quest.MAX .. \" jobs\") end\r\nlocal bad = {}\r\n\r\nlocal function scaleOf(v) v = (v or \"\"):lower():gsub(\"%s\", \"\"); v = Quest.SCALE_KO[v] or v; return Quest.SCALE[v] and v or nil end\r\nlocal function placeOf(v)\r\nv = trim(v or \"\")\r\nv = Quest.PLACE_KO[v:gsub(\"%s\", \"\")] or v\r\nfor _, p in ipairs(Quest.PLACES) do if p:lower() == v:lower() then return p end end\r\nend\r\nlocal scale, place = scaleOf(f[4]), placeOf(f[5])\r\nif not scale and not place and scaleOf(f[5]) and placeOf(f[4]) then scale, place = scaleOf(f[5]), placeOf(f[4]) end\r\nif not scale then bad[#bad + 1] = \"scale village, city, noble or kingdom\"; scale = \"village\" end\r\nif not place then bad[#bad + 1] = \"place from the list\"; place = \"Ruins\" end\r\n\r\nlocal kinds = {}\r\nfor i, k in ipairs(Quest.KINDS) do kinds[i] = k end\r\nfor i = #kinds, 2, -1 do\r\nlocal j = math.random(1, i)\r\nkinds[i], kinds[j] = kinds[j], kinds[i]\r\nend\r\n\r\n\r\nlocal cw = K.CW or \"mid\"\r\nif cw ~= \"mid\" then\r\nfor i = #kinds, 1, -1 do if kinds[i] == \"combat\" then table.remove(kinds, i) end end\r\nif cw == \"high\" then\r\ntable.insert(kinds, 1, \"combat\")\r\nif kinds[3] then kinds[3] = \"combat\" end\r\nend\r\nend\r\n\r\n\r\nlocal cl = trim(f[2] or \"\"):lower()\r\nlocal own = cl == \"\" or cl == \"-\" or cl == \"self\" or cl == \"player\" or cl == \"본인\" or cl == \"나\" or cl == \"스스로\"\r\nor cl:find(\"^자체\") ~= nil\r\nlocal stages = {}\r\nfor i = 1, own and 0 or math.min(#kinds, math.random(3, 5) - 1) do\r\nlocal k = kinds[i]\r\nstages[i] = { kind = k, foes = (k == \"combat\") and Quest.foes(place, pc.level, false) or nil }\r\nend\r\nif not own then stages[#stages + 1] = { kind = \"boss\", foes = Quest.foes(place, pc.level, true) } end\r\n\r\nlocal b = BUDGET[pc.level] or BUDGET[#BUDGET]\r\nlocal guide = own and 0 or 10 * pc.level * Quest.SCALE[scale]\r\nlocal gp, prize = Quest.reward(f[6], guide)\r\nlocal x = { id = q.next, title = Quest.cut(title), client = trim(f[2] or \"\"), goal = trim(f[3] or \"\"), scale = scale, place = place,\r\nstages = stages, at = 1, xp = own and 0 or b[2], gp = gp, prize = prize, guide = guide, own = own or nil }\r\nq.next = q.next + 1\r\nq.list[#q.list + 1] = x\r\nlocal given = trim(f[6] or \"\") ~= \"\" and trim(f[6] or \"\") ~= \"-\"\r\nreturn string.format(\"[QUEST|+%s|%s|%s|%s|%s%s|%s|#%d|%s]\", x.title, x.client, x.goal, scale, place,\r\ngiven and (\"|\" .. trim(f[6])) or \"\", verdictOf(bad), x.id, Quest.rewardText(x)), #bad == 0\r\nend\r\n\r\n\r\n\r\nif f[1] == \"advance\" then\r\nlocal idText, amount = f[2], f[3]\r\nif not (idText or \"\"):match(\"^%s*#%d+%s*$\") then idText, amount = nil, f[2] end\r\nlocal x = idText and Quest.find(q, idText) or q.list[#q.list]\r\nif not x then return fail(\"unknown job\") end\r\nlocal cp = coinsOf(amount or \"\")\r\nif not cp or cp <= 0 or cp % COIN.gp ~= 0 then return fail(\"an advance in whole gp, e.g. 5 gp\") end\r\nlocal gp = cp // COIN.gp\r\nif (x.adv or 0) + gp > x.gp then return fail(string.format(\"at most %d gp (the reward %d gp)\", x.gp - (x.adv or 0), x.gp)) end\r\nx.adv = (x.adv or 0) + gp\r\npc.cp = pc.cp + cp\r\nreturn string.format(\"[QUEST|advance|#%d|%d gp|ok|%s|%d]\", x.id, gp, x.title, x.gp - x.adv), true\r\nend\r\n\r\nif f[1] == \"reward\" then\r\nlocal x = Quest.find(q, f[2])\r\nif not x then return fail(\"unknown job\") end\r\nx.gp, x.prize = Quest.reward(f[3], x.guide or x.gp)\r\nif (tonumber(x.adv) or 0) > x.gp then x.gp = tonumber(x.adv) end\r\nreturn string.format(\"[QUEST|reward|#%d|%s|ok|%s]\", x.id, trim(f[3] or \"\"), Quest.rewardText(x)), true\r\nend\r\nif f[1] == \"done\" then\r\nlocal x, i = Quest.find(q, f[2])\r\nif not x then return fail(\"unknown job\") end\r\nlocal ending = trim(f[3] or \"\"):lower()\r\n\r\n\r\nending = ({ [\"성공\"] = \"success\", [\"부분 성공\"] = \"partial\", [\"일부 성공\"] = \"partial\", [\"실패\"] = \"fail\" })[ending] or ending\r\nif ending == \"\" and x.at > #x.stages then ending = \"success\" end\r\nif ending ~= \"success\" and ending ~= \"partial\" and ending ~= \"fail\" then return fail(\"ending success, partial or fail\") end\r\n\r\n\r\nlocal xp = ending == \"success\" and x.xp or ending == \"partial\" and math.floor(x.xp / 2) or 0\r\nlocal gp = Quest.payLeft(x, ending)\r\ntable.remove(q.list, i)\r\nif not pc.dead then\r\npc.xp = pc.xp + xp\r\npc.cp = pc.cp + gp * COIN.gp\r\nend\r\n\r\nreturn string.format(\"[QUEST|done|#%d|%s|ok|%s|%d|%d%s]\", x.id, ending, x.title, xp, gp,\r\n(x.prize and ending ~= \"fail\") and (\"|give \" .. x.prize .. \" with ITEM or LOOT\") or \"\"), true\r\nend\r\nreturn fail(\"write +title or done\")\r\nend\r\n\r\n\r\nfunction Quest.stage(f, pc, ctx)\r\nlocal q = Quest.load(pc)\r\nlocal raw = \"[STAGE|\" .. table.concat(f, \"|\")\r\nlocal x = Quest.find(q, f[2])\r\nif not x then return raw .. \"|bad:unknown job|-]\", false end\r\nif x.own then return raw .. \"|bad:Player's own aim has no parts: end it with QUEST done when it is reached|-]\", false end\r\nif x.at > #x.stages then return raw .. \"|bad:all parts done: end the job with QUEST done|-]\", false end\r\nctx.staged = ctx.staged or {}\r\nif ctx.staged[x.id] then return raw .. \"|bad:one part per reply|-]\", false end\r\nctx.staged[x.id] = true\r\nx.at = x.at + 1\r\n\r\nreturn string.format(\"[STAGE|done|#%d|ok|%d/%d done]\", x.id, x.at - 1, #x.stages), true\r\nend\r\n\r\nfunction Quest.text(pc, fightEnded)\r\nlocal q = Quest.load(pc)\r\nif #q.list == 0 then return nil end\r\nlocal lines = { \"[JOBS] Jobs Player has taken, kept by Lua. Each has a hidden plan: never mention parts, stages or their numbers to the user.\" }\r\nfor _, x in ipairs(q.list) do\r\n\r\nlocal adv = tonumber(x.adv) or 0\r\nif x.own then\r\n\r\nlines[#lines + 1] = string.format(\"#%d \\\"%s\\\": Player's own aim: %s. Lua keeps no plan for it: follow the story. When it is reached\"\r\n.. \" write [QUEST|done|#%d|success], when given up [QUEST|done|#%d|fail]%s.\", x.id, x.title, x.goal, x.id, x.id,\r\n(x.prize or (tonumber(x.gp) or 0) > 0) and (\" (promised: \" .. Quest.rewardText(x) .. \")\") or \"\")\r\ngoto nextJob\r\nend\r\nlines[#lines + 1] = string.format(\"#%d \\\"%s\\\" for %s: %s (%s, %s). Promised on success: %s%s and %d XP (half the coin for a partial success).\",\r\nx.id, x.title, x.client, x.goal, x.scale, x.place, x.prize and (Quest.rewardText(x) .. \" (the thing is handed over in the story: ITEM or LOOT)\")\r\nor ((tonumber(x.gp) or 0) .. \" gp\"),\r\nadv > 0 and string.format(\" (%d gp of it paid in advance, %d gp left)\", adv, x.gp - adv) or \"\", x.xp)\r\n\r\n.. \" If the story changes the promise, write [QUEST|reward|#\" .. x.id .. \"|new promise].\"\r\nlocal s = x.stages[x.at]\r\nif s then\r\nlocal todo = (Quest.TODO[s.kind]:gsub(\"{SRD}\", K.srdX()))\r\nif s.foes then todo = string.format(todo, Quest.foeText(s.foes)) end\r\nlocal nx = x.stages[x.at + 1]\r\n\r\nlocal later = nx and Quest.HINT[nx.kind] .. (nx.foes and (\" (for example \" .. Quest.foeText(nx.foes) .. \"; whatever the story sets up now decides it)\") or \"\")\r\nlines[#lines + 1] = \"   Now: \" .. todo .. \".\" .. (nx and (\" Later: \" .. later .. \". Do not pull it into this reply.\") or \" This is the last part.\")\r\nelse\r\nlines[#lines + 1] = \"   Every part is done: close the job in the story and write [QUEST|done|#\" .. x.id .. \"|success], partial or fail by how it went.\"\r\n.. \" That tag pays the promised gold and XP: no GOLD or XP tag for the reward.\"\r\nend\r\n::nextJob::\r\nend\r\nlines[#lines + 1] = \"When the current part is resolved in the story, write [STAGE|done|#id] once. If the user wants to hurry past or skip this part,\"\r\n.. \" wrap it up in a few lines and write it. The parts are only a guide: when the story ends the job, write [QUEST|done|#id|...]\"\r\n.. \" even with parts left, success if its goal was reached, partial (half the reward) if Player gave up partway or reached only\"\r\n.. \" part of it, fail if it can no longer be done.\"\r\n\r\n\r\nif fightEnded then\r\nlines[#lines + 1] = \"The last reply ended a fight: if that fight was the current part, or the story has gone past it, write [STAGE|done|#id] in this reply.\"\r\nend\r\nreturn table.concat(lines, \"\\n\")\r\nend\r\n\r\n\r\n\r\n\r\n\r\nfunction K.wear(f, rec)\r\nlocal name = K.itemName(Canon.name(f[1] or \"\"), rec)\r\nlocal how = trim((f[2] or \"-1\"):lower())\r\nlocal head = \"[WEAR|\" .. (f[1] or \"\") .. \"|\" .. (f[2] or \"-1\")\r\nlocal function fail(why) return head .. \"|bad:\" .. why .. \"|-]\", false end\r\nlocal w, a, plus = gearOf(rec, name)\r\nif not (w or a) then return fail(\"not a weapon or armor\") end\r\nif (rec.items[name] or 0) < 1 then return fail(\"not in the pack\") end\r\nrec.wear = type(rec.wear) == \"table\" and rec.wear or {}\r\nFeat.cur.wear = Feat.cur.wear or {}\r\nif how == \"repair\" or how == \"fix\" or how == \"0\" or how == \"수리\" then\r\nif not rec.wear[name] then return fail(\"not damaged\") end\r\nrec.wear[name] = nil\r\nFeat.cur.wear[K.wearKey(rec, name)] = nil\r\nreturn head .. \"|ok|repaired]\", true\r\nend\r\nif (plus or 0) > 0 then return fail(\"a magic item: not affected\") end\r\nlocal n = (tonumber(rec.wear[name]) or 0) + 1\r\nlocal broke\r\nif w then broke = n >= 5\r\nelseif a.cat == \"shield\" then broke = n >= 2\r\nelse broke = a.base - n <= 10 end\r\nif broke then\r\nrec.wear[name] = nil\r\nrec.items[name] = rec.items[name] - 1\r\nif rec.items[name] <= 0 then rec.items[name] = nil end\r\nfixEquip(rec)\r\ndropLoot(rec, name)\r\nreturn head .. \"|ok|destroyed]\", true\r\nend\r\nrec.wear[name] = n\r\nlocal key = K.wearKey(rec, name)\r\nFeat.cur.wear[key] = (Feat.cur.wear[key] or 0) + 1\r\nreturn head .. \"|ok|\" .. (w and (\"attack -\" .. n) or (\"AC -\" .. n)) .. \"]\", true\r\nend\r\n\r\n\r\n\r\nfunction K.wearKey(rec, item) return ((type(rec) == \"table\" and rec.name) or \"Player\") .. \"|\" .. item end\r\nfunction K.lost(rec, item)\r\nreturn item and type(Feat.cur.wear) == \"table\" and Feat.cur.wear[K.wearKey(rec, item)] or 0\r\nend\r\n\r\n\r\nfunction K.wearText(rec)\r\nlocal o = {}\r\nfor name, n in pairs(type(rec) == \"table\" and type(rec.wear) == \"table\" and rec.wear or {}) do\r\nlocal w = gearOf(rec, name)\r\nif (tonumber(n) or 0) > 0 then o[#o + 1] = string.format(\"%s -%d %s\", name, n, w and \"to attack rolls\" or \"AC\") end\r\nend\r\ntable.sort(o)\r\nreturn #o > 0 and table.concat(o, \", \") or nil\r\nend\r\n\r\n\r\nfunction K.wearFight(c)\r\nfor _, u in pairs(c.units or {}) do\r\nif u.side == \"enemy\" and u.hp > 0 and MONSTERS[u.kind] and MONSTERS[u.kind].wear then return true end\r\nend\r\nreturn false\r\nend\r\n\r\nlocal function verifyEquip(f, c, pc, clock, on)\r\n\r\n\r\nlocal function handOf(v) v = trim(v or \"\"):lower(); return ((v == \"main\" or v == \"main hand\") and \"main\") or ((v == \"off\" or v == \"off hand\") and \"off\") or nil end\r\nlocal hand = handOf(f[2])\r\nif handOf(f[1]) and trim(f[2] or \"\") ~= \"\" then hand, f = handOf(f[1]), { Canon.name(f[2]) } end\r\nlocal name = K.lootName(pc, (K.itemName(f[1] or \"\", pc)))\r\nlocal head = \"[\" .. (on and \"EQUIP\" or \"UNEQUIP\") .. \"|\" .. name .. ((on and hand) and (\"|\" .. hand) or \"\")\r\nlocal eq = pc.equip\r\nlocal w, a = gearOf(pc, name)\r\nlocal function two(n) local mw = gearOf(pc, n); return mw and mw.two end\r\nlocal function fail(why) return head .. \"|bad:\" .. why .. \"|AC \" .. pcStats(pc).ac .. \"]\", false end\r\n\r\nlocal wl = not (w or a) and isLoot(pc, name) and pc.loot[name] or nil\r\nlocal wm = wl and wl.srd and K.MAGIC[wl.srd]\r\nif type(wm) == \"table\" and wm.worn then\r\nif on then\r\nif (pc.items[name] or 0) < 1 then return fail(\"not in items\") end\r\nif wl.worn then return fail(\"already worn\") end\r\nwl.worn = true\r\nelse\r\nif not wl.worn then return fail(\"not worn\") end\r\nlocal ch = K.MI.cursedHold(pc, name)\r\nif ch then return fail(ch) end\r\nwl.worn = nil\r\nend\r\nreturn head .. \"|ok|\" .. (on and \"worn\" or \"taken off\") .. \", AC \" .. pcStats(pc).ac .. \"]\", true\r\nend\r\nif not (w or a) then return fail(\"not a weapon or armor\") end\r\nif not on then local ch = K.MI.cursedHold(pc, name); if ch then return fail(ch) end end\r\nif on then\r\nif (pc.items[name] or 0) <= equippedCount(eq, name) then\r\n\r\nif w and not w.ranged and WEAPONS[name] and Feat.invoked(SHEET, \"Pact of the Blade\") then return K.pactUse({ \"Pact of the Blade\", name }, c, pc, head) end\r\nreturn fail(\"not in items\")\r\nend\r\nif a and a.cat ~= \"shield\" then\r\nif c.active then return fail(\"not during a fight\") end\r\nlocal chw = eq.armor and K.MI.cursedHold(pc, eq.armor)\r\nif chw then return fail(chw) end\r\nlocal mins = K.DON[a.cat][1]\r\nlocal _, worn = gearOf(pc, eq.armor)\r\nif worn then mins = mins + K.DON[worn.cat][2] end\r\neq.armor = name\r\nclock.min = clock.min + mins\r\nelseif a then\r\nif eq.off then return fail(\"off hand holds \" .. eq.off) end\r\nif eq.main and two(eq.main) then return fail(eq.main .. \" needs both hands\") end\r\neq.off = name\r\nelseif hand == \"main\" and eq.main and eq.main ~= name and not (w.two and eq.off) then\r\nlocal chm = K.MI.cursedHold(pc, eq.main)\r\nif chm then return fail(chm) end\r\neq.main = name\r\nelseif hand == \"off\" and not w.two and not (eq.main and two(eq.main)) then\r\nlocal chm = eq.off and K.MI.cursedHold(pc, eq.off)\r\nif chm then return fail(chm) end\r\neq.off = name\r\nelseif w.two then\r\nif eq.main or eq.off then return fail(\"needs both hands free\") end\r\neq.main = name\r\nelseif not eq.main then\r\neq.main = name\r\nelseif not eq.off and not two(eq.main) then\r\neq.off = name\r\nelse\r\nreturn fail(\"hands full\")\r\nend\r\nelse\r\nlocal slot\r\nfor _, sl in ipairs({ \"off\", \"main\", \"armor\" }) do if eq[sl] == name then slot = sl; break end end\r\nif not slot then return fail(\"not equipped\") end\r\nif slot == \"armor\" then\r\nif c.active then return fail(\"not during a fight\") end\r\nclock.min = clock.min + K.DON[a.cat][2]\r\nend\r\neq[slot] = nil\r\nif slot == \"main\" and eq.off and not K.isShield(pc, eq.off) then eq.main, eq.off = eq.off, nil end\r\nend\r\nreturn head .. \"|ok|AC \" .. pcStats(pc).ac .. \"]\", true\r\nend\r\n\r\n\r\n\r\nK.STANDARD = { 15, 14, 13, 12, 10, 8 }\r\nK.POINT_COST = { [8] = 0, [9] = 1, [10] = 2, [11] = 3, [12] = 4, [13] = 5, [14] = 7, [15] = 9 }\r\n\r\nlocal function sameSet(a, b)\r\nif #a ~= #b then return false end\r\nlocal x, y = {}, {}\r\nfor i = 1, #a do x[i], y[i] = a[i], b[i] end\r\ntable.sort(x); table.sort(y)\r\nfor i = 1, #x do if x[i] ~= y[i] then return false end end\r\nreturn true\r\nend\r\n\r\nlocal function listOf(v)\r\nlocal out = {}\r\nfor part in (v or \"\"):gmatch(\"[^,]+\") do\r\npart = trim(part)\r\nif part ~= \"\" then out[#out + 1] = part end\r\nend\r\nreturn out\r\nend\r\n\r\nlocal function abilityName(v)\r\nreturn ABBR[(v or \"\"):upper()] or (MOD[v] and v) or nil\r\nend\r\n\r\nlocal function rollStats()\r\nlocal out = {}\r\nfor i = 1, 6 do\r\nlocal d = { K.d(6), K.d(6), K.d(6), K.d(6) }\r\ntable.sort(d)\r\nout[i] = d[2] + d[3] + d[4]\r\nend\r\ntable.sort(out, function(a, b) return a > b end)\r\nreturn out\r\nend\r\n\r\n\r\nlocal function applyASI(sh, pick)\r\n\r\nlocal fn = type(pick) == \"string\" and pick:match(\"^F_(.+)$\")\r\nif fn then\r\nlocal name, ab = fn:match(\"^(.-)__(%a+)$\")\r\nname = (name or fn):gsub(\"_Q_\", \"'\"):gsub(\"_\", \" \")\r\nlocal rec = K.FX[name]\r\nif not (rec and K.PACK.feat[name] == \"general\") then return \"?\" end\r\nlocal allowed = K.gfeatAsi(sh, name)\r\nlocal okAb = false\r\nif ab and sh.scores[ab] then for _, x in ipairs(allowed) do if x == ab then okAb = true end end end\r\nif rec.asi_save and not okAb then return \"?\" end\r\nsh.gfeats = type(sh.gfeats) == \"table\" and sh.gfeats or {}\r\nsh.gfeats[#sh.gfeats + 1] = { name = name, at = K.charLevel(sh), ab = rec.asi_save and ab or nil }\r\nif okAb then sh.scores[ab] = math.max(sh.scores[ab], math.min(20, sh.scores[ab] + 1)) end\r\nreturn name .. (ab and (\", \" .. ab .. \" +1\") or \"\")\r\nend\r\n\r\nlocal h1, h2 = (pick or \"\"):match(\"^Half_(%a+)_(%a+)$\")\r\nif h1 and h1 ~= h2 and sh.scores[h1] and sh.scores[h2] then\r\n\r\nsh.scores[h1] = math.max(sh.scores[h1], math.min(20, sh.scores[h1] + 1))\r\nsh.scores[h2] = math.max(sh.scores[h2], math.min(20, sh.scores[h2] + 1))\r\nreturn h1 .. \" +1, \" .. h2 .. \" +1\"\r\nend\r\nif pick == \"GrapplerStr\" or pick == \"GrapplerDex\" then\r\nlocal a = pick == \"GrapplerStr\" and \"Strength\" or \"Dexterity\"\r\nsh.scores[a] = math.max(sh.scores[a], math.min(20, sh.scores[a] + 1))\r\nsh.feat4 = \"Grappler\"\r\nreturn \"Grappler\"\r\nend\r\nif pick and sh.scores[pick] then\r\nsh.scores[pick] = math.max(sh.scores[pick], math.min(20, sh.scores[pick] + 2))\r\nreturn pick\r\nend\r\nlocal p = CLASSES[sh.class].primary[1]\r\nlocal add = math.max(0, math.min(2, 20 - sh.scores[p]))\r\nsh.scores[p] = sh.scores[p] + add\r\nif add < 2 then sh.scores.Constitution = math.max(sh.scores.Constitution, math.min(20, sh.scores.Constitution + 2 - add)) end\r\nreturn p\r\nend\r\n\r\n\r\n\r\nlocal SCHOLAR_SKILLS = { Arcana = true, History = true, Investigation = true, Medicine = true, Nature = true, Religion = true }\r\nlocal expertiseChoices\r\nfunction K.expertiseChoices(sh) return expertiseChoices(sh) end\r\nexpertiseChoices = function(sh)\r\n\r\nlocal need, ok, anyFree = 0, nil, false\r\nfor _, c in ipairs(K.classes(sh)) do\r\nlocal cl = CLASSES[c.name]\r\nlocal n = c.row.expertise or 0\r\nif n > 0 then\r\nneed = need + n\r\nif cl.expertise_from then\r\nok = ok or {}\r\nfor _, k in ipairs(cl.expertise_from) do ok[k] = true end\r\nelse\r\nanyFree = true\r\nend\r\nend\r\nend\r\nif anyFree then ok = nil end\r\nlocal have = {}\r\nfor _, s in ipairs(sh.expertise or {}) do have[s] = true end\r\nlocal left = need - #(sh.expertise or {})\r\nif left <= 0 then return {}, 0 end\r\nlocal out = {}\r\nfor _, s in ipairs(K.profSkills(sh)) do\r\nif not have[s] and (not ok or ok[s]) then out[#out + 1] = s end\r\nend\r\nreturn out, left\r\nend\r\n\r\n\r\nlocal function autoEquip(pc)\r\nlocal names = {}\r\nfor name in pairs(pc.items) do names[#names + 1] = name end\r\ntable.sort(names)\r\nlocal eq = {}\r\nfor _, name in ipairs(names) do\r\nlocal a = ARMOR[name]\r\nif a and a.cat ~= \"shield\" and armorProf(a.cat) and (not eq.armor or a.base > ARMOR[eq.armor].base) then eq.armor = name end\r\nend\r\nlocal function size(w)\r\nlocal n, sd = w.dmg:match(\"^(%d*)d(%d+)$\")\r\nreturn (tonumber(n) or 1) * (tonumber(sd) or 1)\r\nend\r\nfor _, name in ipairs(names) do\r\nlocal w = WEAPONS[name]\r\nif w and not w.ranged and weaponProf(w) and (not eq.main or size(w) > size(WEAPONS[eq.main])) then eq.main = name end\r\nend\r\nlocal mw = eq.main and WEAPONS[eq.main]\r\nif pc.items.Shield and armorProf(\"shield\") and not (mw and mw.two) then\r\neq.off = \"Shield\"\r\nelseif mw and mw.light then\r\nfor _, name in ipairs(names) do\r\nlocal w = WEAPONS[name]\r\nif w and w.light and not w.ranged and (name ~= eq.main or pc.items[name] >= 2) then eq.off = name; break end\r\nend\r\nend\r\npc.equip = eq\r\nend\r\n\r\nlocal function freshPC(sh, items, cp)\r\napplySheet(sh)\r\nlocal res = {}\r\nfor name, r in pairs(PC.res) do res[name] = r.max end\r\nlocal pc = { hp = PC.hp, max = PC.hp, level = sh.level, xp = XP_LEVEL[sh.level], hd = sh.level, cp = cp, items = items,\r\nres = res, equip = {}, ds = { s = 0, f = 0 }, stable = false, dead = false }\r\nautoEquip(pc)\r\nreturn K.MP.wrap(pc)\r\nend\r\n\r\nlocal function verifyPC(f, rolled, avgGold)\r\n\r\nlocal bad = {}\r\nlocal sp, pk = K.species(f[1])\r\nlocal cl, bg, method = f[2], f[3], (f[4] or \"\"):lower()\r\nif not sp then bad[#bad + 1] = \"species\"\r\nelseif K.d2need(SPECIES[sp]) then bad[#bad + 1] = \"species \" .. sp .. \" is \" .. K.D2_WHY[K.d2need(SPECIES[sp])] end\r\nif not CLASSES[cl] then bad[#bad + 1] = \"class\"\r\nelseif K.d2need(CLASSES[cl]) then bad[#bad + 1] = \"class \" .. cl .. \" is \" .. K.D2_WHY[K.d2need(CLASSES[cl])] end\r\nif not BACKGROUNDS[bg] then bad[#bad + 1] = \"background\"\r\nelseif K.d2need(BACKGROUNDS[bg]) then\r\nbad[#bad + 1] = \"background \" .. bg .. \" is \" .. K.D2_WHY[K.d2need(BACKGROUNDS[bg])]\r\nend\r\nlocal base = {}\r\nfor n in (f[5] or \"\"):gmatch(\"%d+\") do base[#base + 1] = tonumber(n) end\r\nif #base ~= 6 then bad[#bad + 1] = \"six scores\" end\r\n\r\n\r\nlocal fixedScores\r\nif #base == 6 then\r\nlocal function fits(b)\r\nif method == \"standard\" then return sameSet(b, K.STANDARD) end\r\nif method == \"pointbuy\" then\r\nlocal cost = 0\r\nfor _, v in ipairs(b) do cost = cost + (K.POINT_COST[v] or 99) end\r\nreturn cost <= 27\r\nend\r\nif method == \"roll\" then return type(rolled) == \"table\" and sameSet(b, rolled) end\r\nreturn true\r\nend\r\nif not fits(base) then\r\nlocal less, any = {}, false\r\nfor i = 1, 6 do less[i] = base[i] end\r\nfor n, ab in (f[6] or \"\"):gmatch(\"%+%s*(%d)%s*(%a+)\") do\r\nlocal a = abilityName(ab)\r\nfor i, x in ipairs(ABILS) do if x == a then less[i] = less[i] - tonumber(n); any = true end end\r\nend\r\nif any and fits(less) then\r\nfixedScores = \"scores before the bonus \" .. table.concat(less, \",\")\r\nbase = less\r\nend\r\nend\r\nend\r\nif #base == 6 then\r\nif method == \"standard\" then\r\nif not sameSet(base, K.STANDARD) then bad[#bad + 1] = \"standard array is 15,14,13,12,10,8\" end\r\nelseif method == \"pointbuy\" then\r\nlocal cost = 0\r\nfor _, v in ipairs(base) do cost = cost + (K.POINT_COST[v] or 99) end\r\nif cost > 27 then bad[#bad + 1] = \"point buy: 8-15, at most 27 points\" end\r\nelseif method == \"roll\" then\r\nif type(rolled) ~= \"table\" or not sameSet(base, rolled) then bad[#bad + 1] = \"scores are not the rolled ones\" end\r\nelse\r\nbad[#bad + 1] = \"method standard, pointbuy or roll\"\r\nend\r\nend\r\nlocal scores = {}\r\nfor i, a in ipairs(ABILS) do scores[a] = base[i] or 10 end\r\n\r\n\r\n\r\n\r\nlocal fixedBonus\r\nif BACKGROUNDS[bg] then\r\nlocal allowedList = BACKGROUNDS[bg].abilities or {}\r\nlocal allowed, used, amounts, parts, moved = {}, {}, {}, {}, {}\r\nfor _, a in ipairs(allowedList) do allowed[a] = true end\r\nfor n, ab in (f[6] or \"\"):gmatch(\"%+%s*(%d)%s*(%a+)\") do parts[#parts + 1] = { n = tonumber(n), a = abilityName(ab), raw = ab } end\r\nfor _, p in ipairs(parts) do\r\nif p.a and allowed[p.a] and not used[p.a] then used[p.a], p.ok = true, true end\r\nend\r\nlocal AB3 = { Strength = \"STR\", Dexterity = \"DEX\", Constitution = \"CON\", Intelligence = \"INT\", Wisdom = \"WIS\", Charisma = \"CHA\" }\r\nfor _, p in ipairs(parts) do\r\nif not p.ok then\r\nlocal best\r\nfor _, a in ipairs(allowedList) do\r\nif not used[a] and (not best or (scores[a] or 0) > (scores[best] or 0)) then best = a end\r\nend\r\nif not best then bad[#bad + 1] = \"bonus \" .. p.raw; break end\r\nmoved[#moved + 1] = (AB3[p.a or \"\"] or p.raw:upper()) .. \" moved to \" .. AB3[best]\r\nused[best], p.a, p.ok = true, best, true\r\nend\r\nend\r\nfor _, p in ipairs(parts) do\r\nif p.ok then\r\namounts[#amounts + 1] = p.n\r\nscores[p.a] = math.min(20, scores[p.a] + p.n)\r\nend\r\nend\r\ntable.sort(amounts)\r\nlocal shape = table.concat(amounts, \",\")\r\nif shape ~= \"1,2\" and shape ~= \"1,1,1\" then bad[#bad + 1] = \"bonus is +2/+1 or +1/+1/+1\"\r\nelseif #moved > 0 then\r\nlocal al = {}\r\nfor _, a in ipairs(allowedList) do al[#al + 1] = AB3[a] or a end\r\nfixedBonus = \"bonus \" .. table.concat(moved, \", \") .. \" (\" .. bg .. \": \" .. table.concat(al, \", \") .. \")\"\r\nlocal fb = {}\r\nfor _, p in ipairs(parts) do fb[#fb + 1] = \"+\" .. p.n .. \" \" .. AB3[p.a] end\r\nf[6] = table.concat(fb, \" \")\r\nend\r\nend\r\n\r\nlocal skills = listOf(f[7])\r\nlocal chosen = {}\r\nif CLASSES[cl] and BACKGROUNDS[bg] then\r\nlocal inClass, fromBg, outside = {}, {}, 0\r\nfor _, k in ipairs(CLASSES[cl].skills.from) do inClass[k] = true end\r\nfor _, k in ipairs(BACKGROUNDS[bg].skills) do fromBg[k] = true end\r\nlocal want = CLASSES[cl].skills.choose + (sp == \"Human\" and 1 or 0)\r\nlocal off = {}\r\nfor _, k in ipairs(skills) do\r\n\r\nif not SKILL[k] or fromBg[k] or chosen[k] then\r\nbad[#bad + 1] = \"skill \" .. k .. (not SKILL[k] and \" (no such skill)\" or fromBg[k] and \" (the background's: it comes with it)\" or \" (twice)\")\r\nbreak\r\nend\r\nchosen[k] = true\r\nif not inClass[k] then outside = outside + 1; off[#off + 1] = k end\r\nend\r\nif #skills ~= want then bad[#bad + 1] = \"choose \" .. want .. \" skills\" end\r\nif outside > (sp == \"Human\" and 1 or 0) then\r\n\r\nbad[#bad + 1] = string.format(\"skills from the class list (%s %d of %s%s): %s not on it\", cl, CLASSES[cl].skills.choose,\r\ntable.concat(CLASSES[cl].skills.from, \", \"), sp == \"Human\" and \", a Human one more of any\" or \"\", table.concat(off, \", \"))\r\nend\r\nend\r\nlocal opt = listOf((f[8] or \"A,A\"):gsub(\"%s\", \"\"))\r\nlocal copt, bopt = (opt[1] or \"A\"):upper(), (opt[2] or \"A\"):upper()\r\nif CLASSES[cl] and not CLASSES[cl].equipment[copt] then bad[#bad + 1] = \"class equipment \" .. copt end\r\nif BACKGROUNDS[bg] and not BACKGROUNDS[bg].equipment[bopt] then bad[#bad + 1] = \"background equipment \" .. bopt end\r\nlocal level = tonumber(f[9] or \"1\")\r\nlocal top = K.maxLevel(cl)\r\nif not level or level < 1 or level > top or level ~= math.floor(level) then bad[#bad + 1] = \"level 1-\" .. top end\r\nif fixedScores and #bad == 0 then f[5] = table.concat(base, \",\") end\r\nlocal raw = \"[PC|\" .. table.concat(f, \"|\", 1, math.min(#f, 9))\r\nif #bad > 0 then return raw .. \"|bad:\" .. table.concat(bad, \";\") .. \"|-]\", false end\r\n\r\nlocal sheet = { species = sp, class = cl, background = bg, level = level, scores = scores, method = method, gear = {},\r\nskills = {}, expertise = {}, picks = pk }\r\nfor _, k in ipairs(BACKGROUNDS[bg].skills) do sheet.skills[#sheet.skills + 1] = k end\r\nfor _, k in ipairs(skills) do sheet.skills[#sheet.skills + 1] = k end\r\n\r\n\r\nlocal asis = 0\r\nfor l = 1, level do if K.asiLevel(cl, l) then asis = asis + 1 end end\r\nif asis > 0 then sheet.asi_pending = asis end\r\nif level >= 2 then sheet.hp_pending = true end\r\nlocal items, gp = {}, 0\r\nfor _, o in ipairs({ CLASSES[cl].equipment[copt], BACKGROUNDS[bg].equipment[bopt] }) do\r\nfor k, n in pairs(o.items) do items[k] = (items[k] or 0) + n end\r\ngp = gp + o.gp\r\nfor _, g in ipairs(o.other) do sheet.gear[#sheet.gear + 1] = g end\r\nend\r\nif level >= 5 then gp = gp + 500 + (avgGold and 125 or K.d(10) * 25) end\r\nlocal pc = freshPC(sheet, items, gp * 100)\r\n\r\nlocal fixes = {}\r\nif fixedScores then fixes[#fixes + 1] = fixedScores end\r\nif fixedBonus then fixes[#fixes + 1] = fixedBonus end\r\npc.making = true\r\nreturn raw .. string.format(\"|%s|%s %s %d]\", #fixes > 0 and (\"bad:\" .. table.concat(fixes, \";\")) or \"ok\", sp, cl, level), true, sheet, pc\r\nend\r\n\r\n\r\n\r\n\r\n\r\nK.Form = {}\r\nK.Form.TEMPLATE = \"종족: 엘프\\n클래스: 파이터\\n배경: 군인\\n능력치: 표준 배열\\n보너스:\\n기술:\\n장비:\\n레벨: 1\"\r\nK.Form.TEMPLATE_BR = (K.Form.TEMPLATE:gsub(\"\\n\", \"<br>\"))\r\nK.Form.LABELS = { [\"종족\"] = \"species\", species = \"species\", race = \"species\", [\"클래스\"] = \"class\", [\"직업\"] = \"class\", class = \"class\",\r\n[\"배경\"] = \"background\", background = \"background\", [\"능력치\"] = \"scores\", scores = \"scores\", abilities = \"scores\",\r\n[\"보너스\"] = \"bonus\", [\"능력치 보너스\"] = \"bonus\", bonus = \"bonus\", [\"기술\"] = \"skills\", skills = \"skills\",\r\n[\"장비\"] = \"equipment\", equipment = \"equipment\", [\"레벨\"] = \"level\", level = \"level\" }\r\n\r\n\r\nfunction K.Form.fields(text)\r\nif type(text) ~= \"string\" or not (text:find(\":\", 1, true) or text:find(\"：\", 1, true)) then return nil end\r\n\r\nif not (text:find(\"종족\", 1, true) or text:find(\"[Ss]pecies\") or text:find(\"[Rr]ace\")) then return nil end\r\nlocal f = {}\r\nfor line in (text:gsub(\"：\", \":\") .. \"\\n\"):gmatch(\"([^\\n]*)\\n\") do\r\nlocal k, v = line:match(\"^%s*[%-%*]?%s*([^:]-)%s*:%s*(.-)%s*$\")\r\nlocal key = k and K.Form.LABELS[k:lower()]\r\nif key then f[key] = v end\r\nend\r\nif not (f.species and f.class) then return nil end\r\nreturn f\r\nend\r\n\r\n\r\nfunction K.Form.commas(v)\r\nreturn (v or \"\"):gsub(\"/\", \",\"):gsub(\"·\", \",\"):gsub(\"、\", \",\")\r\nend\r\n\r\n\r\nfunction K.Form.name(v, set)\r\nv = trim(v or \"\")\r\nif v == \"\" then return nil end\r\nlocal low = v:lower():gsub(\"[%s_]\", \"\")\r\nfor en in pairs(set) do\r\nif type(en) == \"string\" then\r\nif en:lower():gsub(\"[%s_]\", \"\") == low then return en end\r\nlocal ko = NAMES_KO[en]\r\nif ko and ko:gsub(\"%s\", \"\") == low then return en end\r\nend\r\nend\r\nfor en in pairs(set) do\r\nlocal ko = type(en) == \"string\" and NAMES_KO[en]\r\nif ko and v:find(ko, 1, true) then return en end\r\nend\r\nreturn nil\r\nend\r\nK.Form.ABSET = {}\r\nfor _, a in ipairs(ABILS) do K.Form.ABSET[a] = true end\r\n\r\n\r\n\r\nfunction K.Form.build(f, rolled)\r\nlocal why = {}\r\nlocal sp, pk = K.species(f.species)\r\nsp = sp or K.Form.name(f.species, SPECIES)\r\nlocal cl = K.Form.name(f.class, CLASSES)\r\nlocal bg = K.Form.name(f.background or \"\", BACKGROUNDS)\r\nif not sp then why[#why + 1] = \"종족 '\" .. (f.species or \"\") .. \"'을(를) 모르겠습니다\" end\r\nif not cl then why[#why + 1] = \"클래스 '\" .. (f.class or \"\") .. \"'을(를) 모르겠습니다\" end\r\n\r\nif not bg then why[#why + 1] = (f.background or \"\") == \"\" and \"배경을 적어 주십시오\" or (\"배경 '\" .. f.background .. \"'을(를) 모르겠습니다. 직접 지은 배경은 채팅으로 먼저 정해 주십시오 (예: GM: 배경은 등대지기로 하고 싶어)\") end\r\nif #why > 0 then return nil, why end\r\n\r\nlocal sv = f.scores or \"\"\r\nlocal labeled, nl = {}, 0\r\nfor word, n in sv:gmatch(\"([^%d%s,/]+)%s*(%d+)\") do\r\nlocal a = K.Form.name(word, K.Form.ABSET) or abilityName(word)\r\nif a and not labeled[a] then labeled[a] = tonumber(n); nl = nl + 1 end\r\nend\r\nlocal nums = {}\r\nfor n in sv:gmatch(\"%d+\") do nums[#nums + 1] = tonumber(n) end\r\nlocal scores, method = {}, nil\r\nif nl == 6 then\r\nfor i, a in ipairs(ABILS) do scores[i] = labeled[a] end\r\nelseif #nums == 6 then\r\nscores = nums\r\nelseif #nums == 0 then\r\nlocal pool = K.STANDARD\r\nmethod = \"standard\"\r\nif sv:find(\"굴\", 1, true) or sv:lower():find(\"roll\", 1, true) then\r\nif type(rolled) ~= \"table\" or #rolled ~= 6 then return nil, { \"굴린 능력치가 아직 없습니다\" }, \"roll\" end\r\npool, method = rolled, \"roll\"\r\nend\r\nlocal sorted = {}\r\nfor i, v in ipairs(pool) do sorted[i] = v end\r\ntable.sort(sorted, function(a, b) return a > b end)\r\nlocal byAb = {}\r\nfor i, ab in ipairs(Ally.cdata(cl, \"order\")) do byAb[ab] = sorted[i] end\r\nfor i, a in ipairs(ABILS) do scores[i] = byAb[a] end\r\nelse\r\nreturn nil, { \"능력치는 숫자 6개(근력 민첩 건강 지능 지혜 매력 순)나 '표준 배열'·'굴림'으로 적어 주십시오\" }\r\nend\r\nif not method then\r\nif sameSet(scores, K.STANDARD) then method = \"standard\"\r\nelseif type(rolled) == \"table\" and sameSet(scores, rolled) then method = \"roll\"\r\nelse method = \"pointbuy\" end\r\nend\r\n\r\nlocal bonus = {}\r\nlocal bv = K.Form.commas(f.bonus)\r\nfor _, seg in ipairs(listOf(bv)) do\r\nlocal n = seg:match(\"(%d)\")\r\nlocal word = trim((seg:gsub(\"[%+%d]\", \"\")))\r\nlocal a = K.Form.name(word, K.Form.ABSET) or abilityName(word)\r\nif not (n and a) then return nil, { \"보너스 '\" .. seg .. \"': '민첩 +2, 건강 +1'처럼 적어 주십시오\" } end\r\nbonus[#bonus + 1] = \"+\" .. n .. \" \" .. a\r\nend\r\nif #bonus == 0 then\r\nlocal allowed = {}\r\nfor _, a in ipairs(BACKGROUNDS[bg].abilities) do allowed[a] = true end\r\nlocal plus = 2\r\nfor _, a in ipairs(Ally.cdata(cl, \"order\")) do\r\nif allowed[a] and plus > 0 then bonus[#bonus + 1] = \"+\" .. plus .. \" \" .. a; plus = plus - 1 end\r\nend\r\nend\r\n\r\nlocal skills = {}\r\nfor _, k in ipairs(listOf((K.Form.commas(f.skills)))) do\r\nlocal en = K.Form.name(k, SKILL)\r\nif not en then return nil, { \"기술 '\" .. k .. \"'을(를) 모르겠습니다\" } end\r\nskills[#skills + 1] = en\r\nend\r\nif #skills == 0 then\r\nlocal want = CLASSES[cl].skills.choose + (sp == \"Human\" and 1 or 0)\r\nlocal skip = {}\r\nfor _, k in ipairs(BACKGROUNDS[bg].skills) do skip[k] = true end\r\nlocal from = {}\r\nfor _, k in ipairs(Ally.cdata(cl, \"skills\") or {}) do from[#from + 1] = k end\r\nfor _, k in ipairs(CLASSES[cl].skills.from) do from[#from + 1] = k end\r\nfor _, k in ipairs(from) do\r\nif #skills < want and not skip[k] then skills[#skills + 1] = k; skip[k] = true end\r\nend\r\nend\r\n\r\nlocal opt = {}\r\nfor x in (f.equipment or \"\"):upper():gmatch(\"[ABC]\") do opt[#opt + 1] = x end\r\nif not opt[1] then opt[1] = (cl == \"Fighter\" and (scores[2] or 0) > (scores[1] or 0)) and \"B\" or \"A\" end\r\nopt[2] = opt[2] or \"A\"\r\nlocal level = tonumber((f.level or \"\"):match(\"%d+\") or \"1\")\r\n\r\nreturn { pk and trim(f.species) or sp, cl, bg, method, table.concat(scores, \",\"), table.concat(bonus, \" \"), table.concat(skills, \",\"),\r\nopt[1] .. \",\" .. opt[2], tostring(level) }\r\nend\r\n\r\n\r\nK.Form.WHY = { species = \"종족\", class = \"클래스\", background = \"배경\", [\"six scores\"] = \"능력치 6개\",\r\n[\"standard array is 15,14,13,12,10,8\"] = \"표준 배열은 15·14·13·12·10·8\",\r\n[\"point buy: 8-15, at most 27 points\"] = \"포인트 구매는 8~15, 27점까지 (아니면 '표준 배열')\",\r\n[\"scores are not the rolled ones\"] = \"굴린 능력치와 다릅니다\", [\"bonus is +2/+1 or +1/+1/+1\"] = \"보너스는 +2/+1이나 +1/+1/+1\",\r\n[\"skills from the class list\"] = \"기술은 클래스 목록에서 (인간은 하나 자유)\" }\r\n\r\nfunction K.Form.skillWhy(part)\r\nlocal cl, n, list, human, off = part:match(\"^skills from the class list %((.-) (%d+) of (.-)(, a Human one more of any)%): (.-) not on it$\")\r\nif not cl then cl, n, list, off = part:match(\"^skills from the class list %((.-) (%d+) of (.-)%): (.-) not on it$\") end\r\nif cl then\r\nlocal ko, offKo = {}, {}\r\nfor x in (list .. \", \"):gmatch(\"(.-), \") do ko[#ko + 1] = NAMES_KO[x] or x end\r\nfor x in (off .. \", \"):gmatch(\"(.-), \") do offKo[#offKo + 1] = NAMES_KO[x] or x end\r\nreturn string.format(\"기술은 %s 목록에서 %s개: %s%s. %s%s 목록에 없습니다\", NAMES_KO[cl] or cl, n, table.concat(ko, \"·\"),\r\nhuman and \" (인간은 하나 더 아무 기술)\" or \"\", table.concat(offKo, \"·\"), K.josa(offKo[#offKo] or \"\", \"은\", \"는\"))\r\nend\r\nlocal sk, why = part:match(\"^skill (.-) %((.-)%)$\")\r\nif sk then\r\nlocal k = NAMES_KO[sk] or sk\r\nreturn \"기술 \" .. k .. \": \" .. (why == \"twice\" and \"두 번 골랐습니다\" or why == \"no such skill\" and \"없는 기술입니다\"\r\nor \"배경이 주는 기술이라 따로 고르지 않습니다\")\r\nend\r\nreturn nil\r\nend\r\nfunction K.Form.why(line)\r\nlocal r = (line or \"\"):match(\"|bad:([^|]*)|\") or \"\"\r\nlocal out = {}\r\nfor part in (r .. \";\"):gmatch(\"([^;]*);\") do\r\nif part ~= \"\" then\r\nlocal n = part:match(\"^choose (%d+) skills$\")\r\nlocal sk = part:match(\"^skill (.+)$\")\r\nlocal bo = part:match(\"^bonus (.+)$\")\r\nlocal top = part:match(\"^level 1%-(%d+)$\")\r\nout[#out + 1] = K.Form.WHY[part] or K.Form.skillWhy(part) or (n and (\"기술은 \" .. n .. \"개\")) or (top and (\"레벨은 1~\" .. top))\r\nor (sk and (\"기술 \" .. (NAMES_KO[sk] or sk) .. \": 배경 기술과 겹치거나 고를 수 없습니다\"))\r\nor (bo and (\"보너스 \" .. (NAMES_KO[bo] or bo) .. \": 배경이 올려 주는 능력치가 아닙니다\")) or part\r\nend\r\nend\r\nreturn table.concat(out, \" · \")\r\nend\r\n\r\n\r\nfunction K.Form.apply(text, rolled, inFight)\r\nreturn K.Form.applyFields(K.Form.fields(text), rolled, inFight)\r\nend\r\nfunction K.Form.applyFields(f, rolled, inFight)\r\nif not f then return nil end\r\nif inFight then return \"bad\", \"전투 중에는 캐릭터를 새로 만들 수 없습니다\" end\r\nlocal fields, why, need = K.Form.build(f, rolled)\r\nif not fields then return \"bad\", table.concat(why, \" · \"), nil, nil, need end\r\nlocal line, good, nsh, npc = verifyPC(fields, rolled, true)\r\nif not good then return \"bad\", K.Form.why(line) end\r\nreturn \"ok\", string.format(\"%s %s %d레벨\", NAMES_KO[nsh.species] or nsh.species, NAMES_KO[nsh.class] or nsh.class, nsh.level), nsh, npc\r\nend\r\n\r\n\r\nfunction K.Form.atSend(id)\r\nlocal last = getChat(id, -1)\r\nlocal text = last and last.role == \"user\" and tostring(last.data or \"\") or \"\"\r\nif not K.Form.fields(text) then return end\r\nlocal rolled = getState(id, \"dnd_rolled\")\r\nlocal inFight = loadCombat(id).active\r\nlocal st, note, nsh, npc, need = K.Form.apply(text, rolled, inFight)\r\nif need == \"roll\" then\r\n\r\nrolled = rollStats()\r\nsetState(id, \"dnd_rolled\", rolled)\r\nst, note, nsh, npc = K.Form.apply(text, rolled, inFight)\r\nend\r\nif st == \"ok\" then\r\nlocal pc = loadPC(id)\r\nnpc.allies = pc.allies\r\nsetState(id, \"dnd_sheet\", nsh)\r\nsetState(id, \"dnd_pc\", npc)\r\nend\r\nsetChatVar(id, \"dnd_form\", (st or \"\") .. \"|\" .. (note or \"\"))\r\nend\r\n\r\n\r\nK.B64 = \"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/\"\r\nfunction K.b64enc(str)\r\nlocal o, A = {}, K.B64\r\nfor i = 1, #str, 3 do\r\nlocal a, b, c = str:byte(i, i + 2)\r\nlocal n = a * 65536 + (b or 0) * 256 + (c or 0)\r\nlocal c1, c2, c3, c4 = n // 262144, (n // 4096) % 64, (n // 64) % 64, n % 64\r\no[#o + 1] = A:sub(c1 + 1, c1 + 1) .. A:sub(c2 + 1, c2 + 1) .. (b and A:sub(c3 + 1, c3 + 1) or \"=\") .. (c and A:sub(c4 + 1, c4 + 1) or \"=\")\r\nend\r\nreturn table.concat(o)\r\nend\r\nfunction K.b64dec(str)\r\nlocal idx = K.B64I\r\nif not idx then idx = {}; for i = 1, #K.B64 do idx[K.B64:sub(i, i)] = i - 1 end; K.B64I = idx end\r\nstr = tostring(str or \"\"):gsub(\"[^%w%+/=]\", \"\")\r\nlocal o = {}\r\nfor i = 1, #str, 4 do\r\nlocal q = { str:sub(i, i), str:sub(i + 1, i + 1), str:sub(i + 2, i + 2), str:sub(i + 3, i + 3) }\r\nlocal v = {}\r\nfor k = 1, 4 do v[k] = idx[q[k]] end\r\nif not (v[1] and v[2]) then break end\r\nlocal n = v[1] * 262144 + v[2] * 4096 + (v[3] or 0) * 64 + (v[4] or 0)\r\no[#o + 1] = string.char(n // 65536)\r\nif v[3] then o[#o + 1] = string.char((n // 256) % 256) end\r\nif v[4] then o[#o + 1] = string.char(n % 256) end\r\nend\r\nreturn table.concat(o)\r\nend\r\n\r\n\r\nK.CharCode = K.CharCode or {}\r\nfunction K.CharCode.strip(messages)\r\nfor _, m in ipairs(type(messages) == \"table\" and messages or {}) do\r\nif type(m) == \"table\" and type(m.content) == \"string\" and m.content:find(\"DNDCHAR1:\", 1, true) then\r\nm.content = m.content:gsub(\"DNDCHAR1:[%w%+/=]+\", \"(a character code: Lua loaded it)\")\r\nend\r\nend\r\nend\r\n\r\n\r\nK.CharCode.KEEP = { \"items\", \"loot\", \"cp\", \"xp\", \"equip\", \"preg\", \"pregMore\", \"badRes\", \"resMax\", \"maxDown\" }\r\n\r\nfunction K.CharCode.cleanSheet(sh)\r\nif type(sh) ~= \"table\" then return end\r\nif type(sh.pickLR) == \"table\" then\r\nfor k in pairs(sh.pickLR) do if type(sh.picks) == \"table\" and not tostring(k):find(\"^gain:\") then sh.picks[k] = nil end end\r\nsh.pickLR = nil\r\nend\r\nif type(sh.sdrain) == \"table\" then\r\nfor ab, e in pairs(sh.sdrain) do\r\nif type(e) == \"table\" and (tonumber(e.ends) or e.untilK == \"rest\" or e.untilK == \"longrest\" or e.untilK == \"longrest_noclimax\") then sh.sdrain[ab] = nil end\r\nend\r\nend\r\nend\r\n\r\nfunction K.CharCode.keepDown(md)\r\nif type(md) ~= \"table\" then return nil end\r\nlocal o\r\nfor w, e in pairs(md) do if type(e) == \"table\" and e.untilK == \"restore\" and not tonumber(e.ends) then o = o or {}; o[w] = e end end\r\nreturn o\r\nend\r\n\r\nfunction K.CharCode.shiftPreg(r, delta)\r\nif type(r) ~= \"table\" or delta == 0 then return end\r\nlocal all = { r.preg }\r\nfor _, p in ipairs(type(r.pregMore) == \"table\" and r.pregMore or {}) do all[#all + 1] = p end\r\nfor _, p in ipairs(all) do\r\nif type(p) == \"table\" then for _, k in ipairs({ \"at\", \"shows\", \"ends\" }) do if tonumber(p[k]) then p[k] = p[k] + delta end end end\r\nend\r\nend\r\nfunction K.CharCode.find(text) return tostring(text or \"\"):match(\"DNDCHAR1:([%w%+/=]+)\") end\r\nfunction K.CharCode.make(sh, pc, nowMin)\r\nif type(sh) ~= \"table\" or sh.default or type(pc) ~= \"table\" then return nil end\r\nlocal carry = {}\r\nfor _, k in ipairs(K.CharCode.KEEP) do carry[k] = pc[k] end\r\nif type(pc.ar) == \"table\" and tonumber(pc.ar.overstim) then carry.ar = { overstim = tonumber(pc.ar.overstim) } end\r\ncarry.allies = {}\r\nfor _, a in ipairs(Ally.list(pc)) do if type(a) == \"table\" and not a.dead and type(a.sheet) == \"table\" then carry.allies[#carry.allies + 1] = a end end\r\nlocal ok, js = pcall(function() return json.encode({ v = 1, at = tonumber(nowMin) or 0, sheet = sh.base or sh, pc = carry }) end)\r\nif not ok or type(js) ~= \"string\" then return nil end\r\nreturn \"DNDCHAR1:\" .. K.b64enc(js)\r\nend\r\n\r\nfunction K.CharCode.apply(text, inFight, curSh, curPc, nowMin)\r\nlocal b = K.CharCode.find(text)\r\nif not b then return nil end\r\nif inFight then return \"bad\", \"전투 중에는 캐릭터를 불러올 수 없습니다\" end\r\nif not (type(curSh) == \"table\" and curSh.default) and not (type(curPc) == \"table\" and curPc.making) then\r\nreturn \"bad\", \"이 채팅에는 이미 캐릭터가 있습니다(첫 싸움 전에만 다시 불러올 수 있습니다). 새 채팅의 첫 메시지로 붙여 넣어야 합니다\"\r\nend\r\nlocal okd, data = pcall(function() return json.decode(K.b64dec(b)) end)\r\nif not okd or type(data) ~= \"table\" or type(data.sheet) ~= \"table\" or type(data.pc) ~= \"table\" then\r\nreturn \"bad\", \"코드를 읽지 못했습니다(잘렸거나 바뀐 것 같습니다). 코드를 처음부터 끝까지 그대로 붙여 넣어야 합니다\"\r\nend\r\nif tonumber(data.v) ~= 1 then return \"bad\", \"이 봇이 읽지 못하는 코드입니다\" end\r\nlocal nsh = data.sheet\r\nnsh.default = nil\r\nif not CLASSES[nsh.class or \"\"] then return \"bad\", tostring(nsh.class) .. \" 클래스가 든 모듈이 꺼져 있습니다\" end\r\nif not SPECIES[nsh.species or \"\"] then return \"bad\", tostring(nsh.species) .. \" 종족이 든 모듈이 꺼져 있습니다\" end\r\n\r\nfor _, a in ipairs(type(data.pc.allies) == \"table\" and data.pc.allies or {}) do\r\nif type(a) == \"table\" and type(a.sheet) == \"table\" and not a.dead then\r\nif not CLASSES[a.sheet.class or \"\"] then return \"bad\", \"동료 \" .. tostring(a.name) .. \"의 클래스(\" .. tostring(a.sheet.class) .. \")가 든 모듈이 꺼져 있습니다\" end\r\nif not SPECIES[a.sheet.species or \"\"] then return \"bad\", \"동료 \" .. tostring(a.name) .. \"의 종족(\" .. tostring(a.sheet.species) .. \")이 든 모듈이 꺼져 있습니다\" end\r\nend\r\nend\r\nK.CharCode.cleanSheet(nsh)\r\nlocal delta = (tonumber(nowMin) or 0) - (tonumber(data.at) or tonumber(nowMin) or 0)\r\nlocal p = data.pc\r\nlocal npc = freshPC(nsh, type(p.items) == \"table\" and p.items or {}, tonumber(p.cp) or 0)\r\nnpc.xp = tonumber(p.xp) or npc.xp\r\nnpc.level, npc.hd = K.charLevel(nsh), K.charLevel(nsh)\r\nif type(p.loot) == \"table\" then npc.loot = p.loot end\r\nif type(p.equip) == \"table\" then npc.equip = p.equip; fixEquip(npc) end\r\nnpc.preg, npc.pregMore, npc.badRes, npc.resMax = p.preg, p.pregMore, p.badRes, p.resMax\r\nK.CharCode.shiftPreg(npc, delta)\r\nif type(p.ar) == \"table\" and tonumber(p.ar.overstim) then npc.ar = { overstim = tonumber(p.ar.overstim) } end\r\nnpc.maxDown = K.CharCode.keepDown(p.maxDown)\r\nnpc.max = math.max(1, PC.hp + K.maxBonus(npc))\r\nnpc.hp = npc.max\r\n\r\nnpc.allies = {}\r\nfor _, a in ipairs(type(p.allies) == \"table\" and p.allies or {}) do\r\nif type(a) == \"table\" and type(a.sheet) == \"table\" and not a.dead then\r\na.cond, a.condR, a.condSpell, a.buff, a.conc, a.thp, a.wake = {}, nil, nil, nil, nil, nil, nil\r\na.form, a.formBy, a.formEnds, a.mode, a.lasting, a.lastingEnds, a.summons, a.bi = nil, nil, nil, nil, nil, nil, nil, nil\r\na.ds, a.stable, a.dead, a.exh = { s = 0, f = 0 }, false, false, 0\r\na.ar = (type(a.ar) == \"table\" and tonumber(a.ar.overstim)) and { overstim = tonumber(a.ar.overstim) } or nil\r\nK.CharCode.shiftPreg(a, delta)\r\nK.CharCode.cleanSheet(a.sheet)\r\na.maxDown, a.taxed, a.ordeal = K.CharCode.keepDown(a.maxDown), nil, nil\r\na.hd = tonumber(a.level) or a.hd\r\na.res = type(a.res) == \"table\" and a.res or {}\r\nAlly.with(a, function()\r\nfor k, r in pairs(PC.res) do a.res[k] = r.max end\r\na.max = math.max(1, PC.hp + K.maxBonus(a))\r\nend)\r\na.hp = tonumber(a.max) or a.hp\r\nnpc.allies[#npc.allies + 1] = a\r\nend\r\nend\r\nif K.MP and K.MP.wrapAll then K.MP.wrapAll(npc) end\r\napplySheet(nsh)\r\nreturn \"ok\", string.format(\"%s %s %d레벨%s\", NAMES_KO[nsh.species] or nsh.species, NAMES_KO[nsh.class] or nsh.class, K.charLevel(nsh),\r\n#npc.allies > 0 and (\" · 동료 \" .. #npc.allies .. \"명\") or \"\"), nsh, npc\r\nend\r\nfunction K.CharCode.atSend(id)\r\nlocal last = getChat(id, -1)\r\nlocal text = last and last.role == \"user\" and tostring(last.data or \"\") or \"\"\r\nif not K.CharCode.find(text) then return end\r\nlocal st, note, nsh, npc = K.CharCode.apply(text, loadCombat(id).active, loadSheet(id), loadPC(id), loadClock(id).min)\r\nif st == \"ok\" then\r\nsetState(id, \"dnd_sheet\", nsh)\r\nsetState(id, \"dnd_pc\", npc)\r\nend\r\nsetChatVar(id, \"dnd_charcode\", (st or \"\") .. \"|\" .. (note or \"\"))\r\nend\r\n\r\nfunction K.CharCode.esc(v)\r\nreturn (tostring(v or \"\"):gsub(\"&\", \"&amp;\"):gsub(\"<\", \"&lt;\"):gsub(\">\", \"&gt;\"):gsub('\"', \"&quot;\"))\r\nend\r\n\r\nfunction K.CharCode.row(id, sh, pc)\r\nif type(sh) ~= \"table\" or sh.default or loadCombat(id).active then return \"\" end\r\nlocal code = getChatVar(id, \"dnd_export_show\") == \"1\" and tostring(getChatVar(id, \"dnd_export_code\") or \"\") or \"\"\r\nif code ~= \"\" then\r\nreturn '<div style=\"margin-top:12px\"><div class=\"dnd-opt-t\">캐릭터 코드</div><div class=\"dnd-opt-d\">아래 글을 처음부터 끝까지 복사해서, 새 채팅의 첫 메시지로 그대로 보내면'\r\n.. ' 이 캐릭터가 이어집니다(시트, 소지품, 마법 물건, 돈, 경험치, 동료). 새 모험이라 생명력과 자원은 가득 찬 채로 시작합니다.</div>'\r\n.. '<textarea readonly rows=\"3\" style=\"width:100%;box-sizing:border-box;font-size:11px;word-break:break-all\">' .. K.CharCode.esc(code) .. '</textarea>'\r\n.. K.btnRows({ K.btnFn(\"닫기\", \"dnd_charexport_hide\", false) }) .. '</div>'\r\nend\r\nreturn '<div class=\"dnd-opt-btns\" style=\"margin-top:12px\">' .. K.btnFn(\"다른 채팅으로 캐릭터 옮기기 (코드 만들기)\", \"dnd_charexport\", false) .. '</div>'\r\nend\r\n\r\nfunction K.CharCode.html(id, text, idx)\r\nlocal st, note = \"\", \"\"\r\nif idx and idx >= getChatLength(id) - 2 then st, note = tostring(getChatVar(id, \"dnd_charcode\") or \"\"):match(\"^(%a*)|(.*)$\") end\r\nst, note = st or \"\", note or \"\"\r\nlocal rest = trim((tostring(text):gsub(\"DNDCHAR1:[%w%+/=]+\", \"\")))\r\nlocal sub = st == \"ok\" and '<span class=\"dnd-vd\">Lua ok</span> · 다른 모험에서 이어 왔습니다'\r\nor st == \"bad\" and ('<span class=\"dnd-vd\">Lua bad</span> · ' .. K.CharCode.esc(note)) or \"캐릭터 코드\"\r\nlocal box = string.format('<div class=\"dnd-tag chk\" data-v=\"%s\"><div class=\"dnd-h\"><span class=\"dnd-chip\">❖ 캐릭터 불러오기</span><b>%s</b></div><div class=\"dnd-sub\">%s</div></div>',\r\nst == \"bad\" and \"bad:code\" or \"ok\", K.CharCode.esc(st == \"ok\" and note or \"캐릭터 코드\"), sub)\r\nreturn (rest ~= \"\" and (rest .. \"\\n\\n\") or \"\") .. box\r\nend\r\n\r\n\r\nlocal function setHpRoll(sh, lv, r)\r\nsh.hp_rolls = sh.hp_rolls or {}\r\nfor i = 1, lv do sh.hp_rolls[i] = tonumber(sh.hp_rolls[i]) or 0 end\r\nsh.hp_rolls[lv] = r\r\nend\r\n\r\n\r\nlocal function refitHp(sh, pc)\r\nlocal bonus = K.maxBonus(pc)\r\nlocal oldMax = (pc.max or PC.hp) - bonus\r\napplySheet(sh)\r\nlocal gain = PC.hp - oldMax\r\npc.max = math.max(1, PC.hp + bonus)\r\nlocal up = math.min(pc.max, (pc.hp or 0) + gain)\r\nif (pc.hp or 0) > 0 then up = math.max(1, up) else up = math.max(0, math.min(pc.hp or 0, pc.max)) end\r\npc.hp = up\r\nreturn gain\r\nend\r\n\r\n\r\n\r\nfunction K.MI.syncAll(pc, sh)\r\n\r\nfor _, r in ipairs({ pc, table.unpack(Ally.list(pc)) }) do\r\nfor n, k in pairs(type(r.items) == \"table\" and r.items or {}) do\r\nif not ITEMS[n] and not K.MI.has(r, n) and (tonumber(k) or 0) > 0 and K.MI.maybe(n) then\r\nlocal p = K.MI.parse(n)\r\nif p and K.MI.canon(p) == n then\r\nr.loot = type(r.loot) == \"table\" and r.loot or {}\r\nr.loot[n] = K.MI.record(p)\r\nend\r\nend\r\nend\r\nend\r\nif type(sh) == \"table\" and K.MI.sync(pc, sh) then refitHp(sh, pc) end\r\nfor _, r in ipairs(Ally.list(pc)) do\r\nif type(r.sheet) == \"table\" and type(r.sheet.scores) == \"table\" and K.MI.sync(r, r.sheet) then Ally.with(r, refitHp, r.sheet, r) end\r\nend\r\nend\r\n\r\n\r\n\r\n\r\nfunction K.MI.attuned(rec)\r\nlocal o = {}\r\nfor n, l in pairs(type(rec) == \"table\" and type(rec.loot) == \"table\" and rec.loot or {}) do\r\nif type(l) == \"table\" and l.attuned then o[#o + 1] = n end\r\nend\r\ntable.sort(o)\r\nreturn o\r\nend\r\nfunction K.MI.caster(sh)\r\nif K.castCl(sh) then return true end\r\nfor _, x in pairs(Feat.extras(sh)) do if x.src ~= \"item\" then return true end end\r\nreturn false\r\nend\r\nfunction K.MI.attune(f, rec, c, clock, tctx)\r\nlocal raw = trim(f[1] or \"\")\r\nlocal off = raw:match(\"^%-%s*(.-)$\")\r\nlocal name = trim(off or (raw:gsub(\"^%+%s*\", \"\")))\r\nlocal head = \"[ATTUNE|\" .. raw\r\nlocal function list() local o = K.MI.attuned(rec); return \"attuned \" .. #o .. \"/3\" .. (#o > 0 and (\": \" .. table.concat(o, \", \")) or \"\") end\r\nlocal function fail(why) return head .. \"|bad:\" .. why .. \"|\" .. list() .. \"]\", false end\r\nif name == \"\" then return fail(\"write the item's name\") end\r\nif not K.MI.has(rec, name) then\r\nlocal p = K.MI.parse(name)\r\nif p and K.MI.has(rec, K.MI.canon(p)) then name = K.MI.canon(p) end\r\nend\r\nif not K.MI.has(rec, name) then name = K.lootName(rec, name) end\r\nlocal l = K.MI.has(rec, name) and rec.loot[name]\r\nif not l or (tonumber((rec.items or {})[name]) or 0) < 1 then return fail(\"not in the pack\") end\r\nhead = \"[ATTUNE|\" .. (off and \"-\" or \"\") .. name\r\nif not l.att then return fail(name .. \" needs no attunement: it works as it is\") end\r\nif c.active then return fail(\"attuning takes a Short Rest: not in a fight\") end\r\nif rec.dead or (tonumber(rec.hp) or 0) < 1 then\r\nreturn fail((rec.name or \"Player\") .. (rec.dead and \" is dead\" or \" is at 0 HP: a Short Rest needs at least 1 HP\"))\r\nend\r\nif off then\r\nif not l.attuned then return fail(\"not attuned to \" .. name) end\r\nlocal ch = K.MI.cursedHold(rec, name)\r\nif ch then return fail(ch) end\r\nl.attuned = nil\r\nelse\r\nif l.attuned then return fail(\"already attuned\") end\r\nif #K.MI.attuned(rec) >= 3 then return fail(\"3 items attuned already: end one first, [ATTUNE|-Item]\") end\r\nif type(l.by) == \"table\" then\r\nlocal sh = rec.sheet or SHEET\r\nlocal okb = false\r\nfor _, w in ipairs(l.by) do\r\n\r\nif w == \"Spellcaster\" then okb = okb or K.MI.caster(sh)\r\nelseif w == \"Dwarf\" then okb = okb or (sh and sh.species == \"Dwarf\")\r\nelseif w == \"Belt of Dwarvenkind\" then okb = okb or (K.MI.has(rec, w) and rec.loot[w].attuned == true)\r\nelse okb = okb or K.cl(sh, w) > 0 end\r\nend\r\nif not okb then return fail(name .. \" attunes only to a \" .. table.concat(l.by, \" or \")) end\r\nend\r\nl.attuned = true\r\nend\r\nlocal note\r\nif tctx.shortRest then\r\ntctx.shortRest = nil\r\nnote = \"the Short Rest taken\"\r\nelse\r\nif clock then clock.min = clock.min + 60 end\r\nnote = \"1 hour\"\r\nend\r\nreturn head .. \"|ok|\" .. list() .. \" (\" .. note .. \")]\", true\r\nend\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\nK.MI.ALL_DMG = { \"Acid\", \"Bludgeoning\", \"Cold\", \"Fire\", \"Force\", \"Lightning\", \"Necrotic\", \"Piercing\", \"Poison\", \"Psychic\", \"Radiant\",\r\n\"Slashing\", \"Thunder\" }\r\nK.MI.AMMO = K.AMMO\r\nfunction K.MI.use(f, rec, c, clock)\r\nlocal name = trim(f[1] or \"\")\r\nif not K.MI.has(rec, name) then\r\nlocal p = K.MI.parse(name)\r\nif p and K.MI.has(rec, K.MI.canon(p)) then name = K.MI.canon(p) end\r\nend\r\nlocal l = K.MI.has(rec, name) and rec.loot[name]\r\nlocal m = l and l.srd and K.MAGIC[l.srd]\r\nlocal u = m and type(m.use) == \"table\" and m.use\r\n\r\n\r\nif not u and l and m and tonumber(l.chmax) and not (type(m.sp) == \"table\" and #m.sp > 0) then\r\nlocal arg = trim(f[2] or \"\")\r\nlocal n = tonumber(arg) or 1\r\nlocal head = \"[USE|\" .. name .. (arg ~= \"\" and (\"|\" .. arg) or \"\")\r\nlocal function fail(why) return head .. \"|bad:\" .. why .. \"|-]\", false end\r\nif (tonumber((rec.items or {})[name]) or 0) < 1 then return fail(\"not in the pack\") end\r\nif rec.dead then return fail((rec.name or \"Player\") .. \" is dead\") end\r\nlocal off = K.MI.off(l)\r\nif off then return fail(K.MI.offWhy(name, off)) end\r\nif l.att and not l.attuned then return fail(name .. \" needs attunement first: [ATTUNE|\" .. name .. \"]\") end\r\n\r\nif l.wornReq and not l.worn then return fail(name .. \" works only worn: [EQUIP|\" .. name .. \"] first\") end\r\nif not K.upNow(rec) or Cond.fx(rec).incap then return fail((rec.name or \"Player\") .. \" can't act now\") end\r\nlocal cap\r\nfor _, pw in ipairs(type(m.pw) == \"table\" and m.pw or {}) do\r\nlocal c0 = type(pw.t) == \"string\" and pw.t:match(\"up to (%d+) charges\")\r\nif c0 then cap = tonumber(c0) end\r\nend\r\nif n < 1 or n ~= math.floor(n) or (cap and n > cap) then return fail(\"write how many charges: [USE|\" .. name .. \"|N] (1-\" .. (cap or l.chmax) .. \")\") end\r\nif (tonumber(l.ch) or 0) < n then return fail(name .. \" has \" .. (tonumber(l.ch) or 0) .. \" charges\") end\r\nl.ch = l.ch - n\r\nlocal note = K.MI.lastCharge(rec, name, l, m)\r\nreturn head .. string.format(\"|ok|%s %d/%d charges%s]\", name, tonumber(l.ch) or 0, tonumber(l.chmax) or 0, note), true\r\nend\r\nif not u then return nil end\r\nlocal arg = trim(f[2] or \"\")\r\nlocal head = \"[USE|\" .. name .. (arg ~= \"\" and (\"|\" .. arg) or \"\")\r\nlocal function fail(why) return head .. \"|bad:\" .. why .. \"|-]\", false end\r\nlocal who = rec.name or \"Player\"\r\nif (tonumber((rec.items or {})[name]) or 0) < 1 then return fail(\"not in the pack\") end\r\nif rec.dead then return fail(who .. \" is dead\") end\r\nlocal off = K.MI.off(l)\r\nif off then return fail(K.MI.offWhy(name, off)) end\r\nif u.heal then return fail(\"its healing is a HEAL: [HEAL|\" .. who .. \"|\" .. name .. \"|\" .. u.heal .. \"|dice|amount]\") end\r\nif l.att and not l.attuned then return fail(name .. \" needs attunement first: [ATTUNE|\" .. name .. \"]\") end\r\nif l.wornReq and not l.worn then return fail(name .. \" works only worn: [EQUIP|\" .. name .. \"] first\") end\r\nif not K.upNow(rec) or Cond.fx(rec).incap then return fail(who .. \" can't act now\") end\r\nl.left = type(l.left) == \"table\" and l.left or {}\r\nif u.day and (tonumber(l.left.use) or 0) < 1 then return fail(name .. \" again only after the next dawn (a Long Rest)\") end\r\n\r\nlocal chUse = l.chmax and not u.day and not K.MI.keeps(m)\r\nif chUse and (tonumber(l.ch) or 0) < 1 then return fail(name .. \" has no charges left\") end\r\nif u.perm and c.active then return fail(\"its study takes 48 hours: not in a fight\") end\r\nlocal now = (type(clock) == \"table\" and tonumber(clock.min)) or tonumber(K.replyClock) or 0\r\nlocal o = {}\r\nlocal function buff(e, mins)\r\nrec.buff = type(rec.buff) == \"table\" and rec.buff or {}\r\ne.by = name\r\nmins = tonumber(mins) or 60\r\nif mins <= 1 then e.fight, e.ends = true, now + 1 else e.ends = now + mins end\r\nrec.buff[name] = e\r\nlocal mt = K.buffMechText(name, e)\r\nif mt ~= \"\" then o[#o + 1] = mt end\r\no[#o + 1] = mins <= 1 and \"1 minute (ends with the fight)\" or K.spanText(mins)\r\nend\r\n\r\nlocal sharp\r\nif u.sharp then\r\nlocal eq = type(rec.equip) == \"table\" and rec.equip or {}\r\nlocal w = arg ~= \"\" and K.itemName(Canon.name(arg), rec) or eq.main or \"\"\r\nlocal wd = WEAPONS[w]\r\nif not (K.MI.AMMO[w] or wd) then return fail(\"name a nonmagical Melee weapon or ammunition in the pack: [USE|\" .. name .. \"|Longsword]\") end\r\nif wd and (wd.ranged or not (wd.type == \"Slashing\" or wd.type == \"Piercing\")) then return fail(w .. \": only a Melee weapon that deals Slashing or Piercing damage\") end\r\nif (tonumber((rec.items or {})[w]) or 0) < 1 then return fail(\"no \" .. w .. \" in the pack\") end\r\nlocal p = K.MI.parse(\"+\" .. u.sharp .. \" \" .. w)\r\nif not p then return fail(w .. \" cannot take it\") end\r\nsharp = { w = w, p = p, n = K.MI.AMMO[w] and math.min(20, rec.items[w]) or 1, eq = eq }\r\nend\r\nlocal slotKey\r\nif u.slot and not K.LITE then\r\nlocal want = tonumber(arg)\r\nfor lv = math.min(u.slot, want or u.slot), (want and math.min(u.slot, want) or 1), -1 do\r\nfor _, k in ipairs({ \"Spell Slot \" .. lv, \"Pact Slot \" .. lv }) do\r\nif not slotKey and PC.res[k] and (tonumber(rec.res[k]) or 0) < PC.res[k].max then slotKey = k end\r\nend\r\nend\r\nif not slotKey then return fail(\"no spent spell slot of level \" .. math.min(u.slot, want or u.slot) .. (want and \"\" or \" or lower\")) end\r\nend\r\nif u.slot and K.LITE and not (PC.res.MP and PC.res.MP.max > 0) then return fail(who .. \" has no MP\") end\r\nif u.perm and (tonumber(SHEET.scores[u.perm]) or 10) >= 30 then return fail(u.perm .. \" is 30 already\") end\r\nif u.thp then\r\nrec.thp = math.max(tonumber(rec.thp) or 0, u.thp)\r\no[#o + 1] = \"Temporary HP \" .. rec.thp\r\nend\r\nif u.bless then buff({ bless = true, tell = \"Bless without Concentration: +1d4 to attack rolls and saving throws (\\\"bless N\\\" in the d20 field)\" }, u.bless) end\r\nif u.resist then buff({ res = u.resist == \"all\" and K.MI.ALL_DMG or { u.resist == \"var\" and l.var or u.resist } }, u.mins) end\r\nif u.set then\r\nlocal n = (u.n == \"var\" and type(m.var) == \"table\" and type(m.var[l.var or \"\"]) == \"table\") and m.var[l.var].n or tonumber(u.n)\r\nbuff({ sets = { [u.set] = n }, tell = u.set .. \" \" .. tostring(n) .. \" (unless higher)\" }, u.mins)\r\nend\r\nif u.haste then\r\nbuff({ bonus = 2, speedx = 2, tell = \"Haste without Concentration: Advantage on Dexterity saving throws, Speed doubled, one more action each turn\"\r\n.. \" (one weapon attack, Dash, Disengage, Hide or Utilize), no lethargy after\" }, 1)\r\nend\r\nif u.exh0 and (tonumber(rec.exh) or 0) > 0 then rec.exh = 0; o[#o + 1] = \"Exhaustion 0\" end\r\nfor _, cn in ipairs(u.uncond or {}) do\r\nif type(rec.cond) == \"table\" and rec.cond[cn] then rec.cond[cn] = nil; o[#o + 1] = cn .. \" ended\" end\r\nend\r\nif u.cimm then buff({ cimm = u.cimm, tell = \"Freedom of Movement\" }, u.mins) end\r\n\r\nif u.preg_auto then buff({ pregAuto = true, tell = u.narr or \"every IMPREG at it succeeds by itself\" }, u.mins or 480) end\r\nif sharp then\r\nlocal cn = K.MI.canon(sharp.p)\r\nrec.items[sharp.w] = rec.items[sharp.w] - sharp.n\r\nif rec.items[sharp.w] <= 0 then rec.items[sharp.w] = nil end\r\nrec.items[cn] = (rec.items[cn] or 0) + sharp.n\r\nrec.loot = type(rec.loot) == \"table\" and rec.loot or {}\r\nrec.loot[cn] = rec.loot[cn] or K.MI.record(sharp.p)\r\n\r\nif sharp.eq.main == sharp.w then sharp.eq.main = cn elseif sharp.eq.off == sharp.w then sharp.eq.off = cn end\r\nfixEquip(rec)\r\no[#o + 1] = (sharp.n > 1 and (sharp.n .. \" \") or \"\") .. sharp.w .. \" -> \" .. cn\r\nend\r\nif u.perm then\r\nlocal s = tonumber(SHEET.scores[u.perm]) or 10\r\nSHEET.scores[u.perm] = math.min(30, s + 2)\r\no[#o + 1] = string.format(\"%s %d -> %d (48 hours of study within 6 days: the story's time)\", u.perm, s, SHEET.scores[u.perm])\r\nif u.perm == \"Constitution\" then refitHp(SHEET, rec) end\r\nend\r\nif slotKey then\r\nrec.res[slotKey] = rec.res[slotKey] + 1\r\no[#o + 1] = string.format(\"%s back: %d/%d\", slotKey, rec.res[slotKey], PC.res[slotKey].max)\r\nelseif u.slot then\r\nlocal lv = math.min(u.slot, tonumber(arg) or u.slot)\r\nrawset(rec.res, \"MP\", math.min(PC.res.MP.max, (tonumber(rawget(rec.res, \"MP\")) or 0) + K.MP.SPELL[lv]))\r\no[#o + 1] = K.MP.text(rec)\r\nend\r\nif u.narr then\r\nif u.preg_auto then\r\nelseif tonumber(u.mins) and not (u.resist or u.set or u.cimm) then buff({ tell = u.narr }, u.mins) else o[#o + 1] = u.narr .. \" (the story's)\" end\r\nend\r\nif u.day then\r\nl.left.use = l.left.use - 1\r\no[#o + 1] = string.format(\"%d/%d per dawn\", l.left.use, u.day)\r\nelseif chUse and (tonumber(l.ch) or 0) > 1 then\r\nl.ch = l.ch - 1\r\no[#o + 1] = string.format(\"%d/%d charges\", l.ch, l.chmax)\r\nelseif K.MI.keeps(m) then\r\no[#o + 1] = \"kept (how often: the story's)\"\r\nelse\r\nrec.items[name] = rec.items[name] - 1\r\nif rec.items[name] <= 0 then rec.items[name] = nil; rec.loot[name] = nil end\r\nfixEquip(rec)\r\no[#o + 1] = \"used up\"\r\nend\r\nreturn head .. \"|ok|\" .. table.concat(o, \"; \") .. \"]\", true\r\nend\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\nK.RAISE = { \"Revivify\", \"Raise Dead\", \"Reincarnate\", \"Resurrection\", \"True Resurrection\" }\r\nK.REINC = { false, \"Dragonborn\", \"Dwarf\", \"Elf\", \"Gnome\", \"Goliath\", \"Halfling\", \"Human\", \"Orc\", \"Tiefling\" }\r\nfunction K.spanText(min)\r\nmin = tonumber(min) or 0\r\nif min < 1 then return \"moments\" end\r\nlocal function n(v, one, many) v = math.floor(v); return v .. \" \" .. (v == 1 and one or many) end\r\nif min < 60 then return n(min, \"minute\", \"minutes\") end\r\nif min < 1440 then return n(min / 60, \"hour\", \"hours\") end\r\nif min < 525600 then return n(min / 1440, \"day\", \"days\") end\r\nreturn n(min / 525600, \"year\", \"years\")\r\nend\r\n\r\nfunction K.deadFor(r, clock, c)\r\nlocal now = (type(clock) == \"table\" and tonumber(clock.min)) or tonumber(K.replyClock) or 0\r\nlocal d = type(r.died) == \"table\" and r.died or { min = now }\r\nlocal from = tonumber(d.min) or now\r\nlocal e = now - from\r\nif type(c) == \"table\" and c.active and tonumber(d.round) and tonumber(c.round) then e = math.max(e, (tonumber(c.round) - tonumber(d.round)) / 10) end\r\nlocal gr = type(r.repose) == \"table\" and r.repose\r\nif gr then\r\nlocal a, b = math.max(tonumber(gr.from) or 0, from), math.min(tonumber(gr.to) or 0, now)\r\nif b > a then e = e - (b - a) end\r\nend\r\nreturn math.max(0, e)\r\nend\r\n\r\nfunction K.stampDeaths(pc, clock, c)\r\nlocal now = (type(clock) == \"table\" and tonumber(clock.min)) or 0\r\nfor _, r in ipairs({ pc, table.unpack(Ally.list(pc)) }) do\r\nif type(r) == \"table\" then\r\nif r.dead and type(r.died) ~= \"table\" then\r\nr.pactW = nil\r\nr.died = { min = now, round = (type(c) == \"table\" and c.active) and tonumber(c.round) or nil }\r\nelseif not r.dead and (r.died or r.repose) then\r\nr.died, r.repose = nil, nil\r\nend\r\nend\r\nend\r\nend\r\n\r\nfunction K.servicePrice(name)\r\nlocal sp = SPELLS[name]\r\nif not sp then return nil end\r\nlocal lv = sp.level or 0\r\nlocal base = lv == 0 and 30 or lv == 1 and 50 or lv == 2 and 200 or lv == 3 and 300 or lv <= 5 and 2000 or lv <= 8 and 20000 or 100000\r\nlocal mat = tonumber((((sp.cost or \"\"):match(\"([%d,]+)%+? ?GP\") or \"0\"):gsub(\",\", \"\"))) or 0\r\nreturn base + mat\r\nend\r\n\r\n\r\n\r\n\r\n\r\nK.NPC_MOD = 3\r\nK.NPC_HEALS = { \"Cure Wounds\", \"Healing Word\", \"Prayer of Healing\", \"Mass Healing Word\", \"Mass Cure Wounds\", \"Heal\" }\r\nfunction K.isNpc(v)\r\nv = trim(v or \"\"):lower():gsub(\"%s+free$\", \"\"):gsub(\"%s+무료$\", \"\")\r\nreturn v == \"npc\" or v == \"service\" or v == \"사제\"\r\nend\r\n\r\n\r\n\r\nfunction K.npcFree(v)\r\nv = trim(v or \"\"):lower()\r\nreturn v:find(\"%sfree$\") ~= nil or v:find(\"%s무료$\") ~= nil\r\nend\r\nfunction K.isAid(v)\r\nif SPELLS[Canon.name(trim(v or \"\"))] or HEAL_SRC[trim(v or \"\")] then return false end\r\nv = trim(v or \"\"):lower()\r\nreturn v == \"first aid\" or v == \"응급 치료\" or v == \"응급치료\"\r\nend\r\nK.AID_DICE, K.AID_HOURS = \"1d4+1\", 8\r\n\r\nfunction K.stableRng(salt)\r\nFeat.cur.rngN = (tonumber(Feat.cur.rngN) or 0) + 1\r\nlocal h = ((tonumber(K.REPLY) or 0) * 7919 + Feat.cur.rngN * 104729) % 2147483647\r\nlocal s0 = tostring(salt or \"\") .. \"|\" .. tostring(K.clockRef and K.clockRef.min or \"\")\r\nfor i = 1, #s0 do h = (h * 31 + s0:byte(i)) % 2147483647 end\r\nreturn function(n) h = (1103515245 * h + 12345) % 2147483648; return (h // 65536) % n + 1 end\r\nend\r\nfunction K.firstAid(a, c, pc)\r\nlocal head = \"[HEAL|\" .. table.concat(a, \"|\", 1, #a)\r\nlocal function fail(why) return head .. \"|bad:\" .. why .. \"|-]\", false end\r\nif c.active then return fail(\"first aid is out of a fight; in a fight a potion, a spell or a feature heals\") end\r\nlocal t = Ally.rec(pc, a[1] or \"\")\r\nif not t then return fail(\"target must be Player or a companion\") end\r\nif t.dead then return fail((t.name or \"Player\") .. \" is dead\") end\r\nlocal now = K.clockRef and tonumber(K.clockRef.min)\r\nif now and tonumber(t.aidAt) and now - t.aidAt < K.AID_HOURS * 60 then\r\nreturn fail(string.format(\"%s had first aid %d minutes ago: once per %d hours\", t.name or \"Player\", now - t.aidAt, K.AID_HOURS))\r\nend\r\nif (t.hp or 0) >= (t.max or 0) then return fail((t.name or \"Player\") .. \" is at full HP\") end\r\nlocal p = parseFormula(K.AID_DICE)\r\nlocal d = K.stableRng(\"aid|\" .. tostring(t.name or \"Player\"))\r\nlocal vals, sum = {}, p.mod\r\nfor _, x in ipairs(p.dice) do for _ = 1, x.n do local v = d(x.s); vals[#vals + 1] = v; sum = sum + v end end\r\nhealPC(t, sum)\r\nt.wake = nil\r\nt.aidAt = now\r\nreturn head .. string.format(\"|ok|%d/%d (+%d: first aid, %s = %s)%s]\", t.hp, t.max, sum, K.AID_DICE, table.concat(vals, \",\"), K.healRecvLast or \"\"), true\r\nend\r\nfunction K.npcHealText(pc)\r\nlocal o = {}\r\nfor _, n in ipairs(K.NPC_HEALS) do\r\nlocal sp = SPELLS[n]\r\nlocal m = sp and sp.m\r\nif type(m) == \"table\" and m.heal then\r\nlocal t = tonumber(m.htargets) or 1\r\no[#o + 1] = string.format(\"%s %d gp%s\", n, K.servicePrice(n), t > 1 and (\" for up to \" .. t) or \"\")\r\nend\r\nend\r\nreturn \" A priest outside the party (a temple, a shrine, a passing healer) heals out of a fight for the SRD spellcasting price: [HEAL|Target|Spell|npc],\"\r\n.. \" one tag for each one healed (\" .. table.concat(o, \", \") .. \"; the party has \" .. moneyText(pc.cp or 0) .. \"); Lua rolls it and takes the gold;\"\r\n.. \" [HEAL|Target|Spell|npc free] when the story has that healer ask nothing. Herbs or bandages without a spell (anyone, out of a fight):\"\r\n.. \" [HEAL|Target|First Aid], \" .. K.AID_DICE .. \" by Lua, once for each one per \" .. K.AID_HOURS .. \" hours.\"\r\nend\r\nfunction K.npcHeal(a, c, pc)\r\nlocal name = Canon.name(trim(a[2] or \"\"))\r\nlocal head = \"[HEAL|\" .. table.concat(a, \"|\", 1, 3)\r\nlocal function fail(why) return head .. \"|bad:\" .. why .. \"|-]\", false end\r\nlocal sp = SPELLS[name]\r\nlocal m = sp and sp.m\r\nif not (type(m) == \"table\" and m.heal and (sp.level or 0) >= 1) then return fail(\"a priest's healing spell: \" .. table.concat(K.NPC_HEALS, \", \")) end\r\nif c.active then return fail(\"a priest's healing is out of a fight; in a fight a potion, a spell or a feature heals\") end\r\nlocal t = Ally.rec(pc, a[1] or \"\")\r\nif not t then return fail(\"target must be Player or a companion\") end\r\nif t.dead then return fail((t.name or \"Player\") .. \" is dead: a priest brings back the dead with REVIVE and npc\") end\r\nFeat.cur.npcHeal = Feat.cur.npcHeal or {}\r\nlocal left = Feat.cur.npcHeal[name]\r\nlocal paid = \"\"\r\nif K.npcFree(a[3]) then\r\npaid = \"; free\"\r\nelseif not (left and left > 0) then\r\nlocal gp = K.servicePrice(name)\r\nif (pc.cp or 0) < gp * 100 then return fail(string.format(\"the priest's %s costs %d gp, the party has %s\", name, gp, moneyText(pc.cp or 0))) end\r\npc.cp = pc.cp - gp * 100\r\nleft = tonumber(m.htargets) or 1\r\npaid = string.format(\"; paid %d gp, %s left\", gp, moneyText(pc.cp))\r\nend\r\nif not K.npcFree(a[3]) then Feat.cur.npcHeal[name] = left - 1 end\r\nlocal p = parseFormula((tostring(m.heal):gsub(\"MOD\", tostring(K.NPC_MOD)):gsub(\"LVL\", tostring(sp.level))))\r\nif not p then return fail(name .. \": its healing is no formula\") end\r\nlocal vals, sum = {}, p.mod\r\nlocal roll = K.stableRng(\"npc|\" .. tostring(t.name or \"Player\") .. \"|\" .. name)\r\nfor _, d in ipairs(p.dice) do for _ = 1, d.n do local v = roll(d.s); vals[#vals + 1] = v; sum = sum + v end end\r\nsum = math.max(0, sum)\r\nhealPC(t, sum)\r\nt.wake = nil\r\nreturn head .. string.format(\"|ok|%d/%d (+%d: a priest's healing, %s%s%s)%s]\", t.hp, t.max, sum, canon(p, false),\r\n#vals > 0 and (\" = \" .. table.concat(vals, \",\")) or \"\", paid, K.healRecvLast or \"\"), true\r\nend\r\n\r\n\r\nfunction K.reincarnate(pc, t, new)\r\nlocal function body()\r\nlocal sh = SHEET\r\nif sh.species == new then return end\r\nlocal before = {}\r\nfor k in pairs(PC.res) do before[k] = true end\r\nlocal old = sh.species\r\nsh.picks = type(sh.picks) == \"table\" and sh.picks or {}\r\nlocal p = sh.picks\r\nfor _, k in ipairs({ \"dragon\", \"lineage\", \"keen\", \"gnome\", \"giant\", \"legacy\", \"beast\", \"spellab\", \"skillful\" }) do p[k] = nil end\r\nif old == \"Human\" then\r\np.feat = nil\r\n\r\nlocal skills = type(sh.skills) == \"table\" and sh.skills or {}\r\nlocal from, bgs = {}, {}\r\nfor _, k in ipairs((((CLASSES[sh.class] or {}).skills or {}).from) or {}) do from[k] = true end\r\nfor _, k in ipairs(((BACKGROUNDS[sh.background or \"\"] or {}).skills) or {}) do bgs[k] = true end\r\nlocal at, off\r\nfor i, k in ipairs(skills) do\r\nif not bgs[k] then\r\nat = i\r\nif not from[k] then off = i end\r\nend\r\nend\r\nat = off or at\r\nlocal gone = at and table.remove(skills, at)\r\nif gone and type(sh.expertise) == \"table\" then\r\nfor i = #sh.expertise, 1, -1 do if sh.expertise[i] == gone then table.remove(sh.expertise, i) end end\r\nend\r\nend\r\nsh.species = new\r\nsh.skillful_due = (new == \"Human\") or nil\r\nrefitHp(sh, t)\r\nt.res = type(t.res) == \"table\" and t.res or {}\r\nfor k in pairs(before) do if PC.res[k] == nil then t.res[k] = nil end end\r\nFeat.fillRes(t)\r\nend\r\nif t == pc then body() else Ally.with(t, body); Ally.autoPick(t) end\r\nend\r\n\r\nfunction K.raiseTag(a, c, pc, clock, persona)\r\nlocal who = Canon.actor(trim(a[1] or \"\"), persona)\r\nlocal name = Canon.name(trim(a[2] or \"\"))\r\nlocal head = \"[REVIVE|\" .. table.concat(a, \"|\")\r\nlocal function fail(why) return head .. \"|bad:\" .. why .. \"|-]\", false end\r\nlocal sp = SPELLS[name]\r\nlocal rz = sp and sp.m and sp.m.raise\r\nif not rz then return fail(\"a spell that brings back the dead: \" .. table.concat(K.RAISE, \", \")) end\r\nlocal t = Ally.rec(pc, who)\r\nif not t then return fail(\"Player or a companion\") end\r\nif not t.dead then return fail((t.name or \"Player\") .. \" is not dead\") end\r\nlocal npc, species = false, nil\r\nfor i = 3, #a do\r\nlocal v = trim(a[i] or \"\")\r\nif v:lower() == \"npc\" or v:lower() == \"service\" or v == \"사제\" then npc = true\r\nelseif v ~= \"\" then species = Canon.name(v) end\r\nend\r\nlocal e = K.deadFor(t, clock, c)\r\nif e > rz.within then\r\nreturn fail(string.format(\"%s died %s ago: %s reaches %s\", t.name or \"Player\", K.spanText(e), name, K.spanText(rz.within)))\r\nend\r\nif species and not rz.species then return fail(\"a species only with Reincarnate\") end\r\nif species and not SPECIES[species] then return fail(species .. \" is not a playable species\") end\r\nif species and K.d2need(SPECIES[species]) then return fail(\"species \" .. species .. \" is \" .. K.D2_WHY[K.d2need(SPECIES[species])]) end\r\nlocal by, note = nil, \"\"\r\nif npc then\r\n\r\nif pc.place == \"wild\" then return fail(\"a priest who casts it lives in a town or a city ([PLACE|town] first)\") end\r\nlocal gp = K.servicePrice(name)\r\nif (pc.cp or 0) < gp * 100 then\r\nreturn fail(string.format(\"the service costs %d gp with its material, the party has %s\", gp, moneyText(pc.cp or 0)))\r\nend\r\npc.cp = pc.cp - gp * 100\r\nnote = string.format(\" (paid %d gp, %s left)\", gp, moneyText(pc.cp))\r\nelse\r\nFeat.cur.raised = Feat.cur.raised or {}\r\nlocal casting\r\nfor _, x in ipairs(Feat.cur.casts or {}) do\r\nif x.name == name and not Feat.cur.raised[x] and not casting then casting = x end\r\nend\r\nif not casting then\r\nreturn fail(\"cast \" .. name .. \" with CAST first, or a priest's for its price: [REVIVE|\" .. who .. \"|\" .. name .. \"|npc]\")\r\nend\r\nFeat.cur.raised[casting] = true\r\nby = casting.by and Ally.find(pc, casting.by) or pc\r\nend\r\nlocal newSp\r\nif rz.species then\r\nnewSp = species\r\nif not newSp then\r\n\r\nlocal cands = {}\r\nfor i = 2, #K.REINC do if K.REINC[i] and SPECIES[K.REINC[i]] and not K.d2need(SPECIES[K.REINC[i]]) then cands[#cands + 1] = K.REINC[i] end end\r\nif #cands == 0 then\r\nfor s in pairs(SPECIES) do cands[#cands + 1] = s end\r\ntable.sort(cands)\r\nend\r\nnewSp = cands[K.d(#cands)]\r\nend\r\nK.reincarnate(pc, t, newSp)\r\nend\r\nt.dead, t.stable, t.wake = false, false, nil\r\nt.ds = { s = 0, f = 0 }\r\nt.died, t.repose = nil, nil\r\nif (tonumber(t.exh) or 0) >= 6 then t.exh = 5 end\r\nt.hp = rz.hp == \"max\" and t.max or 1\r\nif rz.ordeal then t.ordeal = rz.ordeal end\r\n\r\nif rz.tax and by and e >= rz.tax then\r\nby.taxed = true\r\nnote = note .. \" (\" .. (by.name or \"Player\") .. \" taxed: no spells and Disadvantage on D20 Tests until a Long Rest)\"\r\nend\r\nif c.active and by then c.last = by.name or \"Player\" end\r\nlocal res = string.format(\"%d/%d\", t.hp, t.max)\r\nif newSp then res = res .. \" (new body: \" .. newSp .. \")\" end\r\nif rz.ordeal then res = res .. \" (ordeal: -\" .. rz.ordeal .. \" to D20 Tests, one less per Long Rest)\" end\r\nreturn head .. \"|ok|\" .. res .. note .. \"]\", true\r\nend\r\n\r\nfunction K.raiseNote(pc, clock, c)\r\nif K.DEATH == \"gentle\" then return nil end\r\nlocal parts = {}\r\nfor _, r in ipairs({ pc, table.unpack(Ally.list(pc)) }) do\r\nif type(r) == \"table\" and r.dead then\r\nlocal e = K.deadFor(r, clock, c)\r\nlocal opts = {}\r\nfor _, n in ipairs(K.RAISE) do\r\nlocal rz = SPELLS[n] and SPELLS[n].m and SPELLS[n].m.raise\r\nif rz and e <= rz.within then opts[#opts + 1] = n end\r\nend\r\nparts[#parts + 1] = string.format(\"%s died %s ago%s, still in time for %s\", r.name or \"Player\", K.spanText(e),\r\ntype(r.repose) == \"table\" and \" (Gentle Repose on the body)\" or \"\", #opts > 0 and table.concat(opts, \", \") or \"none\")\r\nend\r\nend\r\nif #parts == 0 then return nil end\r\nlocal price = {}\r\nfor _, n in ipairs(K.RAISE) do price[#price + 1] = n .. \" \" .. K.servicePrice(n) .. \" gp\" end\r\nreturn \"Bringing back the dead (SRD, Lua checks it): \" .. table.concat(parts, \"; \") .. \". A caster in the party casts the spell and\"\r\n.. \" right after the CAST writes [REVIVE|Name|Spell]: Revivify within 1 minute of the death, 1 HP; Raise Dead within 10 days, 1 HP;\"\r\n.. \" Reincarnate within 10 days, a new body with all its HP ([REVIVE|Name|Reincarnate|Species] for a playable species the GM picks,\"\r\n.. \" else Lua rolls it); Resurrection within a century, all HP; True Resurrection within 200 years, all HP. Raise Dead and\"\r\n.. \" Resurrection leave -4 to D20 Tests, one less per Long Rest. A priest outside the party, in a town or a city, casts it for the\"\r\n.. \" SRD price with its material, which Lua takes from the purse: [REVIVE|Name|Spell|npc] (\" .. table.concat(price, \", \")\r\n.. \"; the party has \" .. moneyText(pc.cp or 0) .. \"). Gentle Repose on the body stops the count: its CAST, then [BUFF|Name|Gentle Repose].\"\r\nend\r\n\r\nfunction K.raiseWhat(name, rz)\r\nreturn \"brings back one who died within \" .. K.spanText(rz.within) .. \": right after the CAST, [REVIVE|Name|\" .. name\r\n.. (rz.species and \"|Species\" or \"\") .. \"]; Lua sets \" .. (rz.hp == \"max\" and \"all its HP\" or \"1 HP\")\r\n.. (rz.species and \", in a new body (a playable species the tag names, else Lua rolls it)\" or \"\")\r\n.. (rz.ordeal and (\"; then -\" .. rz.ordeal .. \" to its D20 Tests, one less per Long Rest\") or \"\")\r\n.. (rz.tax and \"; dead a year or more: its caster casts no spells until a Long Rest\" or \"\")\r\nend\r\n\r\n\r\n\r\nlocal function levelUp(sh, pc, pick, hpRoll, cls, hist)\r\ncls = cls or sh.class\r\nlocal can, why = K.mcCan(sh, cls)\r\nif not can then return false, why end\r\napplySheet(sh)\r\nlocal oldMax, oldRes = PC.hp, PC.res\r\nlocal lv = K.addLevel(sh, cls)\r\nlocal total = K.charLevel(sh)\r\nsetHpRoll(sh, total, hpRoll or 0)\r\nlocal note = \"\"\r\nif hist and K.AR and K.AR.on() and K.AR.histOpen(hist, pc) then note = K.AR.histSet(sh, total, hist) end\r\nif K.asiLevel(cls, lv) then\r\n\r\nlocal before, f4 = deepCopy(sh.scores), sh.feat4\r\nlocal g0 = type(sh.gfeats) == \"table\" and #sh.gfeats or 0\r\nnote = note .. \", ASI \" .. applyASI(sh, pick)\r\nlocal d = {}\r\nfor k, v in pairs(sh.scores) do if v ~= before[k] then d[k] = v - (before[k] or v) end end\r\nsh.asiLog = type(sh.asiLog) == \"table\" and sh.asiLog or {}\r\nsh.asiLog[tostring(total)] = { d = d, feat4 = sh.feat4 ~= f4 and sh.feat4 or nil, gfeat = (type(sh.gfeats) == \"table\" and #sh.gfeats > g0) or nil }\r\nend\r\napplySheet(sh)\r\nlocal gain = PC.hp - oldMax\r\npc.max = PC.hp + K.maxBonus(pc)\r\npc.hp = math.min(pc.max, pc.hp + gain)\r\npc.level = total\r\npc.hd = (pc.hd or 0) + 1\r\npc.resMax = type(pc.resMax) == \"table\" and pc.resMax or {}\r\nfor name, r in pairs(PC.res) do\r\nlocal was = oldRes[name] and oldRes[name].max or 0\r\npc.res[name] = math.min(r.max, (pc.res[name] or 0) + r.max - was)\r\npc.resMax[name] = math.max(tonumber(pc.resMax[name]) or 0, tonumber(r.max) or 0)\r\nend\r\nAlly.sync(pc)\r\nreturn true, string.format(\"Lv %d, HP +%d%s\", total, gain, note)\r\nend\r\n\r\n\r\n\r\n\r\n\r\nfunction K.levelDown(sh, pc)\r\nlocal total = K.charLevel(sh)\r\nif total <= 1 then return \"already level 1, no level to lose\" end\r\nlocal lvc = type(sh.lvcls) == \"table\" and (sh.lvcls[total] or sh.lvcls[tostring(total)]) or sh.class\r\nlocal m\r\nfor _, x in ipairs(K.mcList(sh)) do if x.class == lvc then m = x end end\r\nif lvc ~= sh.class and not m then lvc = sh.class end\r\nif lvc == sh.class and (tonumber(sh.level) or 1) <= 1 then\r\nlocal mc = K.mcList(sh)\r\nm = mc[#mc]\r\nlvc = m and m.class or lvc\r\nend\r\nlocal note = \"\"\r\nlocal log = type(sh.asiLog) == \"table\" and sh.asiLog[tostring(total)]\r\nif type(log) == \"table\" then\r\nfor k, v in pairs(type(log.d) == \"table\" and log.d or {}) do\r\nif sh.scores[k] then sh.scores[k] = sh.scores[k] - (tonumber(v) or 0) end\r\nend\r\nif log.feat4 and sh.feat4 == log.feat4 then sh.feat4 = nil end\r\nif log.gfeat and type(sh.gfeats) == \"table\" and #sh.gfeats > 0 then table.remove(sh.gfeats) end\r\nsh.asiLog[tostring(total)] = nil\r\nnote = note .. \", its Ability Score Improvement given back\"\r\nelseif K.asiLevel(lvc, K.cl(sh, lvc)) then\r\nnote = note .. \", its Ability Score Improvement kept (made before it was recorded)\"\r\nend\r\nif lvc == sh.class then\r\nsh.level = (tonumber(sh.level) or 1) - 1\r\nelse\r\nm.level = (tonumber(m.level) or 1) - 1\r\nif m.level <= 0 then\r\nlocal keep = {}\r\nfor _, x in ipairs(sh.mc) do if x ~= m then keep[#keep + 1] = x end end\r\nsh.mc = keep\r\nif type(sh.mcspells) == \"table\" then sh.mcspells[lvc] = nil end\r\nend\r\nend\r\nif type(sh.lvcls) == \"table\" then sh.lvcls[total], sh.lvcls[tostring(total)] = nil, nil end\r\nif type(sh.hp_rolls) == \"table\" then sh.hp_rolls[total] = nil end\r\nif K.AR and K.AR.histDrop then note = note .. K.AR.histDrop(sh, total) end\r\nlocal oldMax = pc.max\r\nrefitHp(sh, pc)\r\npc.level = total - 1\r\npc.hd = math.min(tonumber(pc.hd) or pc.level, pc.level)\r\npc.xp = math.min(tonumber(pc.xp) or 0, XP_LEVEL[pc.level] or 0)\r\nfor name, n in pairs(pc.res or {}) do\r\nlocal r = PC.res[name]\r\nif not r then pc.res[name] = nil elseif n > r.max then pc.res[name] = r.max end\r\nend\r\n\r\nlocal cut = {}\r\nfor _, v in ipairs(K.casterViews(sh)) do\r\nlocal row = (CLASSES[v.class].levels or {})[v.level] or {}\r\nlocal maxLv = K.rowMaxLv(row)\r\nlocal cans, preps = K.lists(sh, v.class)\r\nlocal keep = {}\r\nfor _, n in ipairs(preps) do\r\nif SPELLS[n] and SPELLS[n].level > maxLv then cut[#cut + 1] = n else keep[#keep + 1] = n end\r\nend\r\nwhile row.prepared and #keep > row.prepared do cut[#cut + 1] = table.remove(keep) end\r\nlocal wantC = Spell.cantripsWant(v, row)\r\nlocal cs = {}\r\nfor _, n in ipairs(cans) do cs[#cs + 1] = n end\r\nwhile wantC and #cs > wantC do cut[#cut + 1] = table.remove(cs) end\r\nK.setLists(sh, v.class, cs, keep)\r\nend\r\nif #cut > 0 then note = note .. \", no longer prepared: \" .. table.concat(cut, \", \") end\r\nfor _, a in ipairs(Ally.list(pc)) do a.lvOff = (tonumber(a.lvOff) or 0) + 1 end\r\nAlly.sync(pc)\r\napplySheet(sh)\r\nreturn string.format(\"level %d->%d (%s %d), HP max %d->%d\", total, total - 1, lvc, K.cl(sh, lvc), oldMax or 0, pc.max or 0) .. note,\r\n{ cls = lvc, from = K.cl(sh, lvc) + 1, to = K.cl(sh, lvc) }\r\nend\r\n\r\n\r\n\r\n\r\nfunction Feat.adjust(t, dmg, dtype)\r\nlocal d, note = Feat.adjust0(t, dmg, dtype)\r\n\r\nif type(t) == \"table\" and t.rec and dtype and (tonumber(d) or 0) > 0 then\r\nif not (K.lastAdj and K.lastAdj.rec == t.rec) then K.lastAdj = { rec = t.rec, parts = {} } end\r\nK.lastAdj.parts[dtype] = (K.lastAdj.parts[dtype] or 0) + d\r\nend\r\nreturn d, note\r\nend\r\nfunction Feat.adjust0(t, dmg, dtype)\r\nif dmg <= 0 or not dtype or type(t) ~= \"table\" then return dmg, \"\" end\r\nlocal function has(list)\r\nfor _, x in ipairs(list or {}) do if x == dtype then return true end end\r\nreturn false\r\nend\r\nif has(t.imm) then return 0, \" (immune)\" end\r\nlocal note = \"\"\r\nif has(t.res) and K.ignoreRes == dtype then note = \" (resistance ignored: Elemental Adept)\"\r\nelseif has(t.res) then dmg, note = math.floor(dmg / 2), \" (resisted)\"\r\nelseif K.UNDERWATER and dtype == \"Fire\" and K.ignoreRes ~= dtype then dmg, note = math.floor(dmg / 2), \" (resisted: underwater)\" end\r\nif has(t.vul) then dmg, note = dmg * 2, note .. \" (vulnerable)\" end\r\nreturn dmg, note\r\nend\r\n\r\n\r\n\r\n\r\n\r\nfunction K.spellRiderFor(rec, spellName, dtype)\r\nlocal sh = type(rec) == \"table\" and rec.sheet or SHEET\r\nif type(sh) ~= \"table\" then return nil end\r\nfor _, e in ipairs(Feat.fxOf(sh, \"weapon_die\")) do\r\nlocal ty = true\r\nif type(e.spell_types) == \"table\" then ty = false; for _, t in ipairs(e.spell_types) do if t == dtype then ty = true end end end\r\nif e.spells and ty and type(e.dice) == \"string\" and not e.dice:find(\"d%d\") and not e.dice:find(\"{\", 1, true) then\r\nlocal key = tostring(K.byKey and K.byKey(rec) or \"Player\") .. \"|\" .. tostring(e.src)\r\nif not (Feat.cur and Feat.cur.riderUsed and Feat.cur.riderUsed[key]) then\r\nlocal n = Ally.run(K.partyPc or rec, rec ~= (K.partyPc or rec) and rec or nil, function() return K.fxNum(e.dice, sh, e.srcLv) end)\r\nreturn tonumber(n), e.src, key\r\nend\r\nend\r\nend\r\nreturn nil\r\nend\r\nfunction K.adeptTypes(sh)\r\nlocal out = {}\r\nif type(sh) ~= \"table\" then return out end\r\nlocal p = type(sh.picks) == \"table\" and sh.picks or {}\r\nfor _, e in ipairs(Feat.fxOf(sh, \"elem_adept\")) do\r\nlocal key = type(e.pick) == \"string\" and e.pick or \"eadept\"\r\nfor k, v in pairs(p) do\r\nif k == key or tostring(k):match(\"^\" .. key .. \"_%d+$\") then\r\nfor _, t in ipairs(type(v) == \"table\" and v or { v }) do if type(t) == \"string\" then out[t] = true end end\r\nend\r\nend\r\nfor _, t in ipairs(type(e.types) == \"table\" and e.types or {}) do out[t] = true end\r\nend\r\nreturn out\r\nend\r\nfunction K.adeptOnes(rec, dtype, vals, formula)\r\nlocal sh = type(rec) == \"table\" and rec.sheet or SHEET\r\nif not (dtype and K.adeptTypes(sh)[dtype]) then return 0 end\r\n\r\nlocal left\r\nif formula then\r\nleft = {}\r\nfor _, d in ipairs((parseFormula(formula) or { dice = {} }).dice) do left[d.s] = (left[d.s] or 0) + d.n end\r\nend\r\nlocal n = 0\r\nfor _, x in ipairs(vals or {}) do\r\nlocal mine = not left or (left[x.s] or 0) > 0\r\nif left and mine then left[x.s] = left[x.s] - 1 end\r\nif mine and tonumber(x.v) == 1 then n = n + 1 end\r\nend\r\nreturn n\r\nend\r\n\r\nFeat.LEGACY = { Abyssal = \"Poison\", Chthonic = \"Necrotic\", Infernal = \"Fire\" }\r\nfunction Feat.resists(r)\r\nlocal sh = r.sheet or SHEET\r\nlocal p = type(sh.picks) == \"table\" and sh.picks or {}\r\nlocal out = {}\r\nif sh.species == \"Dwarf\" then out[#out + 1] = \"Poison\" end\r\nif sh.species == \"Dragonborn\" and p.dragon then out[#out + 1] = p.dragon end\r\nif sh.species == \"Tiefling\" and Feat.LEGACY[p.legacy or \"\"] then out[#out + 1] = Feat.LEGACY[p.legacy] end\r\n\r\nfor _, t in ipairs(Feat.fxResists(sh)) do out[#out + 1] = t end\r\nfor _, t in ipairs(LOOT.resists(r)) do out[#out + 1] = t end\r\nreturn out\r\nend\r\n\r\nfunction Feat.traits(r)\r\nlocal res = Feat.resists(r)\r\nif type(r.mode) == \"table\" and r.mode.name == \"Rage\" then\r\nfor _, t in ipairs({ \"Bludgeoning\", \"Piercing\", \"Slashing\" }) do res[#res + 1] = t end\r\nend\r\nfor _, e in ipairs(K.modeFx(r, r.sheet or SHEET)) do\r\nfor _, t in ipairs(type(e.resist) == \"table\" and e.resist or {}) do res[#res + 1] = t end\r\nend\r\n\r\nlocal rr = Feat.cur and Feat.cur.rresist and Feat.cur.rresist[r.name or \"Player\"]\r\nif rr then res[#res + 1] = rr end\r\n\r\nlocal imm = {}\r\nfor _, b in pairs(type(r.buff) == \"table\" and r.buff or {}) do\r\nif type(b) == \"table\" then\r\nfor _, x in ipairs(type(b.res) == \"table\" and b.res or {}) do res[#res + 1] = x end\r\nfor _, x in ipairs(type(b.imm) == \"table\" and b.imm or {}) do imm[#imm + 1] = x end\r\nend\r\nend\r\n\r\nlocal vul = {}\r\n\r\nlocal tsh = r.sheet or SHEET\r\nfor _, k in ipairs({ \"vuln\", \"immune\" }) do\r\nfor _, e in ipairs(type(tsh) == \"table\" and Feat.fxOf(tsh, k) or {}) do\r\nif K.charLevel(tsh) >= (tonumber(e.from) or 0) then\r\nfor _, x in ipairs(e.types or {}) do if k == \"vuln\" then vul[#vul + 1] = x else imm[#imm + 1] = x end end\r\nend\r\nend\r\nend\r\nif K.MI then\r\nfor _, x in ipairs(K.MI.powers(r, \"imm\")) do imm[#imm + 1] = x[1].type end\r\nfor _, x in ipairs(K.MI.powers(r, \"vuln\")) do vul[#vul + 1] = x[1].type end\r\nend\r\n\r\nlocal drop = {}\r\nfor _, e in ipairs(type(tsh) == \"table\" and Feat.fxOf(tsh, \"vuln_ignore\") or {}) do for _, x in ipairs(e.types or {}) do drop[x] = true end end\r\nif next(drop) then\r\nlocal v2 = {}\r\nfor _, x in ipairs(vul) do if not drop[x] then v2[#v2 + 1] = x end end\r\nvul = v2\r\nend\r\nreturn { res = res, imm = imm, vul = #vul > 0 and vul or nil, rec = r }\r\nend\r\n\r\n\r\nfunction Feat.traitText(st)\r\nlocal parts = {}\r\nif st.res then parts[#parts + 1] = \"resists \" .. table.concat(st.res, \", \") end\r\nif st.imm then parts[#parts + 1] = \"immune to \" .. table.concat(st.imm, \", \") end\r\nif st.vul then parts[#parts + 1] = \"vulnerable to \" .. table.concat(st.vul, \", \") end\r\nif st.cimm then parts[#parts + 1] = \"cannot be \" .. table.concat(st.cimm, \", \") end\r\n\r\nif st.vulbless then parts[#parts + 1] = \"vulnerable to \" .. table.concat(st.vulbless, \", \") .. \" damage from a weapon wielded by someone under Bless\" end\r\nif st.mres == 2 then\r\nparts[#parts + 1] = \"Greater Magic Resistance: it succeeds on every save against a spell or other magical effect, and a spell's attack roll misses it\"\r\nelseif st.mres == 1 then\r\nparts[#parts + 1] = \"Magic Resistance: Advantage on its saves against spells and other magical effects (write adv A,B)\"\r\nend\r\n\r\nif st.react then\r\nparts[#parts + 1] = string.format(\"%s (its reaction, once a round%s): +%d AC against one %s that hits it, not a critical hit\"\r\n.. \" (write that attack as a miss)%s\", st.react.name, st.reactive and \"; Reactive: one on every turn\" or \"\", st.react.n,\r\nst.react.melee and \"melee attack\" or \"attack\", st.react.back and \"; then one Rapier attack back at the attacker, an ATTACK tag right after\"\r\nor st.react.name == \"Whirlwind of Sand\" and (\"; then it teleports up to 60 ft, and creatures of its choice within 5 ft of\"\r\n.. \" where it lands are Blinded until the end of its next turn (a COND tag for each of ours)\") or \"\")\r\nend\r\nif st.shield then\r\nparts[#parts + 1] = string.format(\"Protective Magic (its reaction%s): Shield, +%d AC against the attack that hits it and every\"\r\n.. \" attack until its next turn (write those misses), or Counterspell\", st.shield.uses and (\", \" .. st.shield.uses .. \" a day\") or \"\", st.shield.n)\r\nend\r\nif st.evasion then parts[#parts + 1] = \"Evasion: a Dexterity save that halves damage takes none on a success and half on a failure\" end\r\nif st.reflect then parts[#parts + 1] = \"Reflective Carapace: Magic Missile and spells with a ranged attack roll do not affect it\" end\r\nif st.bfrenzy then parts[#parts + 1] = \"Bloodied Frenzy: while Bloodied, Advantage on its attack rolls and saves (write adv A,B)\" end\r\nif st.split then\r\nparts[#parts + 1] = \"Split (its reaction): at 10+ HP while Large or Medium, when it becomes Bloodied or takes \"\r\n.. table.concat(st.split, \" or \") .. \" damage (even what it is immune to), it splits in two; Lua adds the new one and halves the HP\"\r\nend\r\nif st.limbs then\r\nparts[#parts + 1] = \"Loathsome Limbs: Bloodied and 15+ Slashing damage in one creature's turn severs a limb that becomes a Troll Limb\"\r\n.. \" (Lua adds it, \" .. st.limbs .. \" a day; each missing limb is 1 Exhaustion level, -2 to its d20 tests, until it regains HP)\"\r\nend\r\nreturn #parts > 0 and (\". \" .. table.concat(parts, \"; \")) or \"\"\r\nend\r\n\r\n\r\n\r\nFeat.STYLES = { \"Archery\", \"Defense\", \"Great Weapon Fighting\", \"Two-Weapon Fighting\" }\r\nFeat.DRAGON = { \"Acid\", \"Cold\", \"Fire\", \"Lightning\", \"Poison\" }\r\nFeat.GIANT = { \"Cloud\", \"Fire\", \"Frost\", \"Hill\", \"Stone\", \"Storm\" }\r\nFeat.ORIGIN = { \"Alert\", \"Magic Initiate\", \"Savage Attacker\", \"Skilled\" }\r\nFeat.MI_LISTS = { \"Cleric\", \"Druid\", \"Wizard\" }\r\nFeat.MI_AB = { Cleric = \"Wisdom\", Druid = \"Wisdom\", Wizard = \"Intelligence\" }\r\n\r\nFeat.BG = { Acolyte = { \"Magic Initiate\", \"Cleric\" }, Criminal = { \"Alert\" }, Sage = { \"Magic Initiate\", \"Wizard\" }, Soldier = { \"Savage Attacker\" } }\r\n\r\n\r\n\r\nfunction K.originNames()\r\nlocal o = {}\r\nfor _, f in ipairs(K.d2names(Feat.ORIGIN)) do o[#o + 1] = f == \"Magic Initiate\" and \"Magic Initiate (Cleric, Druid or Wizard)\" or f end\r\nif #o < 2 then return table.concat(o, \"\") end\r\nreturn table.concat(o, \", \", 1, #o - 1) .. \" or \" .. o[#o]\r\nend\r\nfunction K.bgFeat(name)\r\nlocal f = Feat.BG[name or \"\"]\r\nif f then return f end\r\nlocal b = BACKGROUNDS[name or \"\"]\r\nlocal t = type(b) == \"table\" and type(b.feat) == \"string\" and b.feat\r\nif not t then return nil end\r\nlocal feat, list = t:match(\"^(.-)%s*%((%a+)%)$\")\r\nreturn { feat or t, list }\r\nend\r\n\r\n\r\n\r\n\r\nK.ABIL_KO = { [\"근력\"] = \"Strength\", [\"민첩\"] = \"Dexterity\", [\"건강\"] = \"Constitution\", [\"지능\"] = \"Intelligence\", [\"지혜\"] = \"Wisdom\", [\"매력\"] = \"Charisma\" }\r\n\r\nfunction K.addBg(name, rec)\r\nlocal gear = { items = {}, gp = 50, other = {} }\r\nBACKGROUNDS[name] = { abilities = rec.abilities, skills = rec.skills, feat = rec.list and (rec.feat .. \" (\" .. rec.list .. \")\") or rec.feat,\r\ncustom = true, equipment = { A = gear, B = gear }, tool = rec.tool }\r\nFeat.BG[name] = { rec.feat, rec.list }\r\nend\r\n\r\nfunction K.customBg(id)\r\nlocal t = stateOf(id, \"dnd_bgx\")\r\nif type(t) ~= \"table\" then return end\r\nfor name, rec in pairs(t) do\r\nif type(rec) == \"table\" and not (BACKGROUNDS[name] and not BACKGROUNDS[name].custom) then K.addBg(name, rec) end\r\nend\r\nend\r\n\r\nfunction K.verifyBackground(a, id)\r\nlocal name = trim(a[1] or \"\")\r\nlocal head = \"[BACKGROUND|\" .. table.concat(a, \"|\")\r\nlocal bad = {}\r\nif name == \"\" then bad[#bad + 1] = \"name\" end\r\nif BACKGROUNDS[name] and not BACKGROUNDS[name].custom then bad[#bad + 1] = name .. \" is a background this game has: use it as it is\" end\r\nlocal abil, seenA = {}, {}\r\nfor _, v in ipairs(listOf(a[2])) do\r\nlocal ab = abilityName(v) or K.ABIL_KO[v]\r\nif not ab or seenA[ab] then bad[#bad + 1] = \"ability \" .. v; break end\r\nseenA[ab] = true\r\nabil[#abil + 1] = ab\r\nend\r\nif #abil ~= 3 then bad[#bad + 1] = \"three abilities\" end\r\nlocal skills, seenS = {}, {}\r\nfor _, v in ipairs(listOf(a[3])) do\r\nlocal s = Canon.name(v)\r\nif not SKILL[s] or seenS[s] then bad[#bad + 1] = \"skill \" .. v; break end\r\nseenS[s] = true\r\nskills[#skills + 1] = s\r\nend\r\nif #skills ~= 2 then bad[#bad + 1] = \"two skills\" end\r\nlocal fraw = trim(a[4] or \"\")\r\nlocal feat, list = fraw:match(\"^(.-)%s*%((%a+)%)$\")\r\nfeat = Canon.name(feat or fraw)\r\nif list then list = list:sub(1, 1):upper() .. list:sub(2):lower() end\r\nif feat == \"Magic Initiate\" and not list then list = \"?\" end\r\nlocal okFeat = false\r\nfor _, f in ipairs(Feat.ORIGIN) do if f == feat then okFeat = true end end\r\nif not okFeat then bad[#bad + 1] = \"Origin feat: \" .. K.originNames() end\r\nif list then\r\nlocal okList = false\r\nfor _, l in ipairs(Feat.MI_LISTS) do if l == list then okList = true end end\r\nif feat ~= \"Magic Initiate\" or not okList then bad[#bad + 1] = \"Magic Initiate (Cleric, Druid or Wizard)\" end\r\nend\r\n\r\nlocal tool\r\nif trim(a[5] or \"\") ~= \"\" and trim(a[5]) ~= \"-\" then\r\ntool = K.toolOf(a[5])\r\nif not tool then bad[#bad + 1] = \"tool: an SRD tool (Thieves' Tools, Herbalism Kit, Smith's Tools ...)\" end\r\nend\r\nif #bad > 0 then return head .. \"|bad:\" .. table.concat(bad, \";\") .. \"|-]\", false end\r\nlocal rec = { abilities = abil, skills = skills, feat = feat, list = list, tool = tool }\r\nK.addBg(name, rec)\r\nlocal t = stateOf(id, \"dnd_bgx\")\r\nt = type(t) == \"table\" and t or {}\r\nt[name] = rec\r\nsetState(id, \"dnd_bgx\", t)\r\nif K.SC then K.SC[\"dnd_bgx\"] = t end\r\nreturn head .. \"|ok|custom background]\", true\r\nend\r\n\r\n\r\nFeat.SPECIES_SPELLS = {\r\nElf = { Drow = { \"Dancing Lights\", \"Faerie Fire\", \"Darkness\" }, [\"High Elf\"] = { \"Prestidigitation\", \"Detect Magic\", \"Misty Step\" },\r\n[\"Wood Elf\"] = { \"Druidcraft\", \"Longstrider\", \"Pass without Trace\" } },\r\nTiefling = { Abyssal = { \"Poison Spray\", \"Ray of Sickness\", \"Hold Person\" }, Chthonic = { \"Chill Touch\", \"False Life\", \"Ray of Enfeeblement\" },\r\nInfernal = { \"Fire Bolt\", \"Hellish Rebuke\", \"Darkness\" } },\r\nGnome = { Forest = { \"Minor Illusion\", \"Speak with Animals\" }, Rock = { \"Mending\", \"Prestidigitation\" } },\r\n}\r\nFeat.LINEAGE_KEY = { Elf = \"lineage\", Tiefling = \"legacy\", Gnome = \"gnome\" }\r\nFeat.MASTERY_N = { Fighter = { 3, 3, 3, 4, 4 }, Rogue = { 2, 2, 2, 2, 2 } }\r\n\r\nfunction Feat.picks(sh)\r\nif type(sh.picks) ~= \"table\" then sh.picks = {} end\r\nreturn sh.picks\r\nend\r\n\r\n\r\nfunction Feat.list(sh)\r\nlocal out, p = {}, Feat.picks(sh)\r\nlocal bg = K.bgFeat(sh.background)\r\nif bg then out[#out + 1] = bg[1] end\r\nif sh.species == \"Human\" and p.feat then out[#out + 1] = p.feat end\r\nif sh.feat4 then out[#out + 1] = sh.feat4 end\r\nfor _, g in ipairs(type(sh.gfeats) == \"table\" and sh.gfeats or {}) do out[#out + 1] = type(g) == \"table\" and g.name or g end\r\nreturn out\r\nend\r\n\r\nfunction K.gfeatOk(sh, name, rec, nextTotal)\r\nif not (type(rec) == \"table\" and K.PACK.feat[name] == \"general\") or not K.d2ok(rec) then return false end\r\nlocal had = 0\r\nfor _, g in ipairs(type(sh.gfeats) == \"table\" and sh.gfeats or {}) do if (type(g) == \"table\" and g.name or g) == name then had = had + 1 end end\r\nlocal cap = rec[\"repeat\"] == true and 99 or tonumber(rec[\"repeat\"]) or 1\r\nif had >= cap then return false end\r\nlocal p = type(rec.pre) == \"table\" and rec.pre or {}\r\nif tonumber(p.level) and (nextTotal or K.charLevel(sh)) < tonumber(p.level) then return false end\r\n\r\n\r\nif p.ability then\r\nlocal need, any = tonumber(p.min) or 13, false\r\nfor _, a in ipairs(type(p.ability) == \"table\" and p.ability or { p.ability }) do\r\nif (tonumber((sh.scores or {})[a]) or 0) >= need then any = true end\r\nend\r\nif not any then return false end\r\nend\r\nif rec.asi_save and #K.gfeatAsi(sh, name) == 0 then return false end\r\nlocal function inList(list, v) for _, x in ipairs(list or {}) do if x == v then return true end end return false end\r\n\r\n\r\nif type(p.any) == \"table\" then\r\nlocal okAny = false\r\nfor _, q in ipairs(p.any) do\r\nif type(q) == \"table\" then\r\nlocal qok = true\r\nif type(q.species) == \"table\" and not inList(q.species, sh.species) then qok = false end\r\nif type(q.backgrounds) == \"table\" and not inList(q.backgrounds, sh.background) then qok = false end\r\nif type(q.classes) == \"table\" then\r\nlocal anyC = false\r\nfor _, c in ipairs(q.classes) do if K.cl(sh, c) > 0 then anyC = true end end\r\nif not anyC then qok = false end\r\nend\r\nif qok then okAny = true end\r\nend\r\nend\r\nif not okAny then return false end\r\nend\r\nif type(p.species) == \"table\" and not inList(p.species, sh.species) then return false end\r\nif type(p.backgrounds) == \"table\" and not inList(p.backgrounds, sh.background) then return false end\r\nif type(p.classes) == \"table\" then\r\nlocal any = false\r\nfor _, c in ipairs(p.classes) do if K.cl(sh, c) > 0 then any = true end end\r\nif not any then return false end\r\nend\r\nif p.caster and not (K.castCl(sh) or next(Feat.extras(sh))) then return false end\r\nlocal feats = {}\r\nfor _, x in ipairs(Feat.fxList(sh)) do feats[x.name] = true end\r\nfor _, x in ipairs(Feat.levelFeatures(sh)) do feats[(x:gsub(\" %(.-%)$\", \"\"))] = true end\r\nif p.feature and not feats[p.feature] then return false end\r\nif type(p.feature_any) == \"table\" then\r\nlocal any = false\r\nfor _, f in ipairs(p.feature_any) do if feats[f] then any = true end end\r\nif not any then return false end\r\nend\r\nreturn true\r\nend\r\nfunction K.gfeatList(sh, nextTotal)\r\nlocal o = {}\r\nfor name, cat in pairs(K.PACK.feat) do\r\nif cat == \"general\" and K.gfeatOk(sh, name, K.FX[name], nextTotal) then o[#o + 1] = name end\r\nend\r\ntable.sort(o)\r\nreturn o\r\nend\r\n\r\n\r\nfunction K.gfeatAsi(sh, name)\r\nlocal rec = K.FX[name] or {}\r\nif rec.asi_once then\r\nfor _, g in ipairs(type(sh.gfeats) == \"table\" and sh.gfeats or {}) do if (type(g) == \"table\" and g.name or g) == name then return {} end end\r\nend\r\nlocal list = type(rec.asi) == \"table\" and rec.asi or {}\r\nif rec.asi_save then\r\nlocal have, o = K.saveProfOf(sh), {}\r\nfor _, a in ipairs(list) do if not have[a] then o[#o + 1] = a end end\r\nreturn o\r\nend\r\nreturn list\r\nend\r\n\r\nfunction K.saveProfOf(sh)\r\nlocal o = {}\r\nfor _, a in ipairs((CLASSES[sh.class or \"\"] or {}).saves or {}) do o[a] = true end\r\nif Feat.fxOf then for _, e in ipairs(Feat.fxOf(sh, \"save_prof\")) do for _, a in ipairs(e.abilities or {}) do o[a] = true end end end\r\nfor _, g in ipairs(type(sh.gfeats) == \"table\" and sh.gfeats or {}) do\r\nif type(g) == \"table\" and g.ab and (K.FX[g.name] or {}).asi_save then o[g.ab] = true end\r\nend\r\nreturn o\r\nend\r\nfunction K.gfeatPay(name, ab) return \"F_\" .. name:gsub(\"'\", \"_Q_\"):gsub(\" \", \"_\") .. (ab and (\"__\" .. ab) or \"\") end\r\n\r\n\r\nfunction Feat.spellType(name, rec)\r\nif name ~= \"Breath Weapon\" then return nil end\r\nlocal sh = rec and rec.sheet or SHEET\r\nreturn sh and type(sh.picks) == \"table\" and sh.picks.dragon or nil\r\nend\r\n\r\nfunction Feat.has(sh, name)\r\nfor _, f in ipairs(Feat.list(sh)) do if f == name then return true end end\r\nreturn false\r\nend\r\n\r\n\r\nfunction Feat.miList(sh)\r\nlocal bg = K.bgFeat(sh.background)\r\nif bg and bg[1] == \"Magic Initiate\" then return bg[2] end\r\nreturn Feat.picks(sh).milist\r\nend\r\n\r\n\r\n\r\nfunction Feat.miOpen(sh)\r\nreturn Feat.has(sh, \"Magic Initiate\") and Feat.miList(sh) ~= nil and not (type(sh.mi) == \"table\" and sh.mi.spell)\r\nend\r\n\r\n\r\nfunction K.miTalk(t)\r\nreturn type(t) == \"string\" and (t:find(\"입문\", 1, true) ~= nil or t:lower():find(\"initiate\", 1, true) ~= nil)\r\nend\r\n\r\n\r\nfunction Feat.potent(rec)\r\nlocal sh = rec and (rec.sheet or SHEET)\r\nreturn sh ~= nil and K.subHas(sh, \"Potent Cantrip\")\r\nend\r\n\r\n\r\nfunction Feat.mental(sh)\r\nlocal pk = type(sh.picks) == \"table\" and sh.picks.spellab\r\nif pk == \"Intelligence\" or pk == \"Wisdom\" or pk == \"Charisma\" then return pk end\r\nlocal best, ab = -99, \"Charisma\"\r\nfor _, a in ipairs({ \"Intelligence\", \"Wisdom\", \"Charisma\" }) do\r\nlocal m = abilityMod(K.score(sh, a))\r\nif m > best then best, ab = m, a end\r\nend\r\nreturn ab\r\nend\r\n\r\n\r\nfunction Feat.extras(sh)\r\nlocal out, p = {}, Feat.picks(sh)\r\nlocal key = Feat.LINEAGE_KEY[sh.species or \"\"]\r\nlocal list = key and p[key] and Feat.SPECIES_SPELLS[sh.species][p[key]]\r\n\r\nif list then\r\nlocal ab = Feat.mental(sh)\r\nout[list[1]] = { ab = ab, src = \"species\" }\r\nif sh.species == \"Gnome\" then\r\nif list[2] == \"Speak with Animals\" then out[list[2]] = { ab = ab, free = \"Speak with Animals (free)\", src = \"species\" } else out[list[2]] = { ab = ab, src = \"species\" } end\r\nelse\r\n\r\nif K.charLevel(sh) >= 3 then out[list[2]] = { ab = ab, free = list[2] .. \" (free)\", src = \"species\" } end\r\nif K.charLevel(sh) >= 5 then out[list[3]] = { ab = ab, free = list[3] .. \" (free)\", src = \"species\" } end\r\nend\r\nend\r\nif sh.species == \"Tiefling\" then out.Thaumaturgy = out.Thaumaturgy or { ab = Feat.mental(sh), src = \"species\" } end\r\nif sh.species == \"Beastfolk\" and p.beast == \"Fox\" then out[\"Minor Illusion\"] = out[\"Minor Illusion\"] or { ab = Feat.mental(sh), src = \"species\" } end\r\nif sh.species == \"Dragonborn\" and p.dragon then out[\"Breath Weapon\"] = { ab = \"Constitution\", free = \"Breath Weapon\", only = true } end\r\nif sh.species == \"Goliath\" and p.giant == \"Storm\" then out[\"Storm's Thunder\"] = { ab = \"Constitution\", free = \"Giant Ancestry\", only = true } end\r\n\r\nif K.subHas(sh, \"Land's Aid\") then out[\"Land's Aid\"] = { ab = \"Wisdom\", free = \"Wild Shape\", only = true } end\r\nif Feat.invoked(sh, \"Armor of Shadows\") then out[\"Mage Armor\"] = { ab = \"Charisma\", atwill = true, src = \"invocation\" } end\r\nif Feat.invoked(sh, \"Fiendish Vigor\") then out[\"False Life\"] = { ab = \"Charisma\", atwill = true, src = \"invocation\" } end\r\nif Feat.invoked(sh, \"Mask of Many Faces\") then out[\"Disguise Self\"] = { ab = \"Charisma\", atwill = true, src = \"invocation\" } end\r\nif Feat.invoked(sh, \"Misty Visions\") then out[\"Silent Image\"] = { ab = \"Charisma\", atwill = true, src = \"invocation\" } end\r\n\r\nif Feat.invoked(sh, \"Otherworldly Leap\") then out[\"Jump\"] = { ab = \"Charisma\", atwill = true, src = \"invocation\" } end\r\nif Feat.invoked(sh, \"Whispers of the Grave\") then out[\"Speak with Dead\"] = { ab = \"Charisma\", atwill = true, src = \"invocation\" } end\r\nif Feat.invoked(sh, \"Visions of Distant Realms\") then out[\"Arcane Eye\"] = { ab = \"Charisma\", atwill = true, src = \"invocation\" } end\r\n\r\nlocal rec = Cond.cur\r\nif type(rec) == \"table\" and ((rec.sheet and rec.sheet == sh) or (not rec.sheet and sh == SHEET)) then\r\nfor spell, x in pairs(LOOT.spells(rec)) do\r\nif not out[spell] then out[spell] = { ab = Feat.mental(sh), item = x[1], src = \"item\", row = x[3] } end\r\nend\r\nend\r\n\r\n\r\nfor _, e in ipairs(Feat.fxOf(sh, \"free_cast\")) do\r\nif e.ability and ABBR[e.ability] then\r\nlocal names = e.spells or {}\r\n\r\nif e.pick then\r\nlocal v = type(sh.picks) == \"table\" and sh.picks[e.pick]\r\nnames = type(v) == \"table\" and v or (type(v) == \"string\" and { v }) or {}\r\nend\r\nfor _, n in ipairs(names) do\r\nif not out[n] then out[n] = { ab = ABBR[e.ability], free = e.use, atwill = e.at_will or nil, src = \"feature\", fx = e } end\r\nend\r\nend\r\nend\r\nlocal mi = type(sh.mi) == \"table\" and sh.mi\r\nif mi and Feat.MI_AB[mi.list or \"\"] then\r\nfor _, n in ipairs(mi.cantrips or {}) do out[n] = out[n] or { ab = Feat.MI_AB[mi.list], src = \"mi\", list = mi.list } end\r\nif mi.spell then out[mi.spell] = { ab = Feat.MI_AB[mi.list], free = \"Magic Initiate\", src = \"mi\", list = mi.list } end\r\nend\r\nreturn out\r\nend\r\n\r\n\r\n\r\nfunction K.weaponIs(a, kinds)\r\nif type(kinds) ~= \"table\" then return true end\r\nlocal b = tostring(a.base or a.item or a.name or \"\"):gsub(\"^%+%d+%s*\", \"\"):gsub(\",?%s*%+%d+$\", \"\")\r\nfor _, k in ipairs(kinds) do if k == b or k == a.base then return true end end\r\nreturn false\r\nend\r\n\r\n\r\n\r\nFeat.GIANT_DICE = { Fire = { \"1d10\", \"Fire\" }, Frost = { \"1d6\", \"Cold\" } }\r\nfunction Feat.weaponFx(attacks, pc)\r\nlocal sh = SHEET\r\nlocal p = Feat.picks(sh)\r\nlocal mastered = {}\r\nfor _, n in ipairs(type(p.mastery) == \"table\" and p.mastery or {}) do mastered[n] = true end\r\nlocal giant = sh.species == \"Goliath\" and type(pc.res) == \"table\" and (pc.res[\"Giant Ancestry\"] or 0) > 0 and Feat.GIANT_DICE[p.giant or \"\"]\r\nlocal row = K.rowOf(sh, \"Barbarian\")\r\nlocal mode = type(pc.mode) == \"table\" and pc.mode.name\r\nlocal modeFx = K.modeFx(pc, sh)\r\n\r\nlocal over = #Feat.fxOf(sh, \"nat20_score\") > 0 and type(p.boonab) == \"string\" and tonumber(SCORE[p.boonab]) or nil\r\nfor _, a in ipairs(attacks) do\r\na.extras = a.extras or {}\r\nif over then a.extras[#a.extras + 1] = { dice = tostring(over), src = \"Overwhelming Strike (a d20 of 20 only)\", nat20 = true } end\r\n\r\nif mode == \"Rage\" and a.str and row.rage then\r\na.dmg = withMod(a.dmg, row.rage)\r\nif K.subHas(sh, \"Frenzy\") then a.extras[#a.extras + 1] = { dice = row.rage .. \"d6\", src = \"Frenzy\" } end\r\nend\r\n\r\nif mode == \"Sacred Weapon\" and a.melee and not a.name:find(\"^Unarmed Strike\") then a.hit = a.hit + math.max(1, MOD.Charisma) end\r\n\r\nfor _, e in ipairs(modeFx) do\r\nif K.modeFits(e, a) then\r\nif e.hit then a.hit = a.hit + K.fxNum(e.hit, sh, e.srcLv) end\r\nif e.dmg and a.dmg then a.dmg = withMod(a.dmg, K.fxNum(e.dmg, sh, e.srcLv)) end\r\nend\r\nend\r\n\r\nif a.sneak then a.extras[#a.extras + 1] = { dice = a.sneak, src = \"Sneak Attack\", less = K.cl(SHEET, \"Rogue\") >= 5 or nil } end\r\n\r\nif p.prey == \"Colossus Slayer\" and a.weapon and not a.beast and K.subHas(sh, \"Hunter's Prey\") then a.extras[#a.extras + 1] = { dice = \"1d8\", src = \"Colossus Slayer\" } end\r\nif a.weapon then\r\nif K.subHas(sh, \"Improved Critical\") then a.critOn = 19 end\r\n\r\nfor _, e in ipairs(Feat.fxOf(sh, \"crit_range\")) do a.critOn = math.min(a.critOn or 20, tonumber(e.min) or 20) end\r\nif Feat.styled(sh, \"Archery\") and a.ranged then a.hit = a.hit + 2 end\r\nif Feat.styled(sh, \"Great Weapon Fighting\") and a.twohand and not a.ranged then a.gwf = true end\r\nif a.base and mastered[a.base] and WEAPONS[a.base] then a.mastery = WEAPONS[a.base].mastery end\r\n\r\n\r\nif a.offhand and a.mastery == \"Nick\" then\r\na.name = a.name:gsub(\" %(off%-hand, Bonus Action%)$\", \" (off-hand, in the Attack action: Nick)\")\r\nend\r\nif giant then a.extras[#a.extras + 1] = { dice = giant[1], src = \"Giant Ancestry\", res = \"Giant Ancestry\" } end\r\nend\r\nend\r\nFeat.fxDice(attacks)\r\nend\r\n\r\n\r\n\r\n\r\nfunction Feat.fxDice(attacks)\r\n\r\nlocal life = Feat.invoked(SHEET, \"Lifedrinker\")\r\nlocal smite = Feat.invoked(SHEET, \"Eldritch Smite\")\r\nlocal wrow = K.rowOf(SHEET, \"Warlock\")\r\nlocal slotLv = #(wrow.slots or {})\r\n\r\n\r\nlocal whoS = (function() local o = K.recOfSheet(SHEET); return type(o) == \"table\" and o.name or \"Player\" end)()\r\nlocal spentK = Feat.cur.spent or {}\r\nlocal smK = smite and not K.LITE and K.smiteKey(SHEET) or nil\r\nlocal smPaid = Feat.cur.smitePaid and Feat.cur.smitePaid[whoS]\r\nfor _, a in ipairs(attacks) do\r\nif a.pact and life and not spentK[whoS .. \"|Lifedrinker\"] then a.extras = a.extras or {}; a.extras[#a.extras + 1] = { dice = \"1d6\", src = \"Lifedrinker\", once = \"Lifedrinker\" } end\r\nif a.pact and smite and K.cl(SHEET, \"Warlock\") > 0 and slotLv > 0 and not spentK[whoS .. \"|Eldritch Smite\"] then\r\na.extras = a.extras or {}\r\nlocal free = smPaid or not smK\r\na.extras[#a.extras + 1] = { dice = (1 + slotLv) .. \"d8\", src = \"Eldritch Smite\", once = \"Eldritch Smite\", type = \"Force\",\r\nres = not free and smK or nil, cost = not free and 1 or nil, smite = not free or nil }\r\nend\r\nend\r\n\r\n\r\nfor _, e in ipairs(Feat.fxOf(SHEET, \"crit_die\")) do\r\nfor _, a in ipairs(attacks) do\r\nlocal fits = false\r\nfor _, t in ipairs(type(e.types) == \"table\" and e.types or { e.types }) do if t == a.type then fits = true end end\r\nlocal d1 = fits and (parseFormula(a.dmg or \"\") or { dice = {} }).dice[1]\r\nif d1 then a.extras = a.extras or {}; a.extras[#a.extras + 1] = { dice = \"1d\" .. d1.s, src = e.src, critExtra = true } end\r\nend\r\nend\r\nlocal list = Feat.fxOf(SHEET, \"weapon_die\")\r\nif #list == 0 then return end\r\nlocal owner = K.recOfSheet(SHEET)\r\n\r\n\r\nlocal function wdType(e)\r\nlocal t = e.types\r\nif type(t) == \"table\" and #t == 1 then t = t[1] end\r\nif type(t) == \"string\" and K.DTYPES[t:lower()] then return (t:gsub(\"^%l\", string.upper)) end\r\nreturn nil\r\nend\r\nfor _, a in ipairs(attacks) do\r\nlocal fist = a.name:find(\"^Unarmed Strike\") ~= nil\r\nfor _, e in ipairs(list) do\r\n\r\n\r\nlocal spellOk = e.spells and a.spell and (type(e.spell_types) ~= \"table\" or (function()\r\nfor _, t in ipairs(e.spell_types) do if t == a.type then return true end end\r\nreturn false\r\nend)())\r\nif ((a.weapon and not e.no_weapons) or spellOk) and (not a.beast or e.beast) and (not fist or e.unarmed) and (not e.str or a.str) and (not e.melee or a.melee)\r\nand (spellOk or K.weaponIs(a, e.weapons)) then\r\nif e.always then\r\n\r\nlocal pf = parseFormula(a.dmg .. \"+\" .. K.dieText(e, SHEET))\r\nif pf then a.dmg = canon(pf, false) end\r\nlocal ty = wdType(e)\r\nif ty and ty ~= a.type and not a.lootDmg then a.lootDmg, a.lootDie = ty, K.dieText(e, SHEET) end\r\nelse\r\n\r\n\r\nlocal cost = tonumber(e.cost) or 1\r\nlocal left = e.res and owner and type(owner.res) == \"table\" and (tonumber(owner.res[e.res]) or 0) or nil\r\nif not e.res or (left and left >= cost) then\r\na.extras = a.extras or {}\r\nlocal dt = (type(e.dice) == \"string\" and not e.dice:find(\"d%d\") and not e.dice:find(\"{\", 1, true))\r\nand tostring(K.fxNum(e.dice, SHEET, e.srcLv)) or K.dieText(e, SHEET)\r\na.extras[#a.extras + 1] = { dice = dt, src = e.src, plain = e.plain or nil, res = e.res, cost = e.res and cost or nil,\r\ntype = wdType(e) }\r\nend\r\nend\r\nend\r\nend\r\nend\r\nend\r\n\r\n\r\n\r\nfunction K.wardOf(sh)\r\nlocal e = Feat.fxOf(sh, \"ward\")[1]\r\nif not e then return nil end\r\nreturn e, math.max(1, K.fxNum(e.max or \"2*LEVEL+INT\", sh, e.srcLv))\r\nend\r\nfunction K.wardCast(rec, sh, name, level)\r\nlocal e, mx = K.wardOf(sh)\r\nlocal sp = SPELLS[name or \"\"]\r\nif not e or not sp then return \"\" end\r\nlocal en = (K.SCHOOL_EN and K.SCHOOL_EN[sp.school or \"\"]) or sp.school\r\nif en ~= (e.school or \"Abjuration\") then return \"\" end\r\nif not rec.wardMade then\r\nrec.wardMade, rec.ward = true, mx\r\nreturn string.format(\", Arcane Ward made: %d/%d\", mx, mx)\r\nend\r\nlocal add = 2 * (tonumber(level) or 1)\r\nrec.ward = math.min(mx, (tonumber(rec.ward) or 0) + add)\r\nreturn string.format(\", Arcane Ward +%d: %d/%d\", add, rec.ward, mx)\r\nend\r\nfunction K.wardText(pc)\r\nlocal o = {}\r\nfor _, r in ipairs({ pc, table.unpack(Ally.list(pc)) }) do\r\nlocal sh = (r == pc and SHEET) or r.sheet\r\nlocal e, mx = nil, nil\r\nif type(sh) == \"table\" then e, mx = K.wardOf(sh) end\r\nif e then\r\nlocal nm = r == pc and \"Player\" or r.name\r\no[#o + 1] = r.wardMade and string.format(\"%s %d/%d\", nm, tonumber(r.ward) or 0, mx)\r\nor string.format(\"%s none yet (its first %s spell cast with a slot makes it, %d)\", nm, e.school or \"Abjuration\", mx)\r\nend\r\nend\r\nif #o == 0 then return nil end\r\nreturn \"Arcane Ward (Lua keeps it; it takes damage before HP; an Abjuration spell cast with a slot adds 2 per slot level; a Bonus Action [USE|Arcane Ward|slot level] spends a slot for the same): \"\r\n.. table.concat(o, \"; \") .. \".\"\r\nend\r\n\r\n\r\nfunction K.useModTake(who, kind)\r\nlocal list = Feat.cur.useMod\r\nif type(list) ~= \"table\" then return nil end\r\n\r\nlocal keys = ({ atk = { \"auto_hit\", \"attack_bonus\" }, def = { \"ac_bonus\" }, mult = { \"dmg_mult\" }, reduce = { \"dmg_reduce\" }, miss = { \"auto_miss\" } })[kind] or {}\r\nfor i, m in ipairs(list) do\r\nlocal got\r\nfor _, k in ipairs(keys) do if m[k] ~= nil then got = got or { who = m.who, src = m.src }; got[k] = m[k] end end\r\nif m.who == who and got then\r\nfor _, k in ipairs(keys) do m[k] = nil end\r\nif not (m.auto_hit or m.attack_bonus or m.ac_bonus or m.dmg_mult or m.dmg_reduce or m.auto_miss) then table.remove(list, i) end\r\nreturn got\r\nend\r\nend\r\nreturn nil\r\nend\r\nfunction K.useModText(m)\r\nlocal o = {}\r\nif m.auto_hit then o[#o + 1] = m.who .. \"'s next attack roll hits\" end\r\nif m.attack_bonus then o[#o + 1] = string.format(\"%+d to %s's next attack roll\", m.attack_bonus, m.who) end\r\nif m.dmg_mult then o[#o + 1] = string.format(\"%s's next hit deals x%s damage\", m.who, tostring(m.dmg_mult)) end\r\nif m.ac_bonus then o[#o + 1] = string.format(\"%+d AC against the next attack on %s\", m.ac_bonus, m.who) end\r\nif m.auto_miss then o[#o + 1] = \"the next attack on \" .. m.who .. \" misses (a Critical Hit too)\" end\r\nif m.dmg_reduce then o[#o + 1] = \"the next hit on \" .. m.who .. \" takes \" .. m.dmg_reduce .. \" less (Lua rolls it and takes it off: write the damage before it)\" end\r\nreturn table.concat(o, \"; \") .. \" (Lua counts it)\"\r\nend\r\n\r\n\r\nfunction K.dieText(e, sh)\r\nlocal d = tostring(e.dice or \"\")\r\nif not (d:find(\"{\", 1, true) or d:find(\"%u\")) then return d end\r\nlocal row = (e.srcClass and K.rowAt(sh, e.srcClass, tonumber(e.srcLv) or K.cl(sh, e.srcClass))) or {}\r\nd = d:gsub(\"{ROW:([%w_]+)}\", function(k) return tostring(row[k] or \"\") end)\r\nd = d:gsub(\"%f[%a]MA%f[%A]\", function() return tostring(K.rowOf(sh, \"Monk\").martial_arts or \"1d6\") end)\r\nlocal dice, n = {}, 0\r\nfor part in (d .. \"+\"):gmatch(\"([^+]*)%+\") do\r\npart = trim(part)\r\nif part:match(\"^%d*d%d+$\") then dice[#dice + 1] = part:match(\"^d\") and (\"1\" .. part) or part\r\nelseif part ~= \"\" then n = n + K.fxNum(part, sh, tonumber(e.srcLv)) end\r\nend\r\nlocal s0 = table.concat(dice, \"+\")\r\nif n ~= 0 then s0 = s0 .. string.format(\"%+d\", n) end\r\nreturn s0\r\nend\r\n\r\n\r\n\r\nFeat.cur = { savage = {}, dodge = {}, spent = {}, cleave = {}, wear = {}, view = {}, view0 = {}, flips = {}, blessed = {} }\r\n\r\n\r\n\r\nfunction Feat.riders(attacks, pc)\r\nlocal who = pc.name or \"Player\"\r\nfor _, act in ipairs(Spell.active(pc)) do\r\nlocal sp = SPELLS[act.name]\r\nlocal m = sp and sp.m\r\nif m and m.rider and not Feat.cur.spent[who .. \"|\" .. act.name] then\r\nlocal f = parseFormula(m.rider)\r\nlocal up = (act.level or sp.level) - sp.level\r\nif m.upcast and m.upcast.dice and up > 0 then\r\nfor _, d in ipairs(parseFormula(m.upcast.dice).dice) do f.dice[#f.dice + 1] = { n = d.n * up, s = d.s } end\r\nend\r\n\r\nfor _, e in ipairs(Feat.fxOf(SHEET, \"rider_die\")) do\r\nif e.spell == act.name then for _, d in ipairs(f.dice) do d.s = e.die end end\r\nend\r\nlocal dice = canon(f, false)\r\nfor _, a in ipairs(attacks) do\r\nlocal fits\r\nif not m.rider_each then fits = a.weapon and a.melee and not a.beast\r\nelseif m.lasting then fits = a.weapon\r\nelse fits = true end\r\nif fits and a.stim then fits = false end\r\nif fits then\r\na.extras = a.extras or {}\r\na.extras[#a.extras + 1] = { dice = dice, src = act.name, once = not m.rider_each and act.name or nil, type = m.rider_type }\r\nend\r\nend\r\nend\r\nend\r\n\r\n\r\nfor _, a in ipairs(attacks) do\r\nlocal sp = a.spell and SPELLS[a.spell]\r\nlocal m = sp and sp.m\r\nif m and (m.rays or m.beams) and not a.stim and not a.nodmg and not Feat.cur.spent[who .. \"|\" .. a.spell .. \" +mod\"] then\r\nlocal n, src = Feat.spellMod(a.spell, sp, m, m.damage, true)\r\nif (tonumber(n) or 0) > 0 then\r\na.extras = a.extras or {}\r\na.extras[#a.extras + 1] = { dice = tostring(n), src = src or \"bonus\", once = a.spell .. \" +mod\" }\r\nend\r\nend\r\nend\r\nend\r\n\r\n\r\nfunction Feat.exText(a)\r\nlocal t = {}\r\n\r\nfor _, x in ipairs(a.extras or {}) do t[#t + 1] = \"+\" .. x.dice .. \" \" .. x.src .. ((x.cost and x.res) and (\" (spends \" .. x.cost .. \" \" .. x.res .. \")\") or \"\") end\r\nreturn #t > 0 and (\" (may add \" .. table.concat(t, \", \") .. \")\") or \"\"\r\nend\r\n\r\n\r\nfunction Feat.gwf(a, vals, damage)\r\nif not (a and a.gwf) then return damage, \"\" end\r\nlocal sizes = {}\r\nfor _, d in ipairs((parseFormula(a.dmg) or { dice = {} }).dice) do sizes[d.s] = true end\r\nlocal add = 0\r\nfor _, x in ipairs(vals or {}) do if sizes[x.s] and x.v < 3 and not x.neg then add = add + 3 - x.v end end\r\nif add == 0 then return damage, \"\" end\r\nreturn damage + add, \" (Great Weapon Fighting +\" .. add .. \")\"\r\nend\r\n\r\n\r\nfunction Feat.init()\r\nlocal r = K.d(20)\r\n\r\nif K.subHas(SHEET, \"Remarkable Athlete\") or #Feat.fxOf(SHEET, \"init_adv\") > 0 then r = math.max(r, K.d(20)) end\r\n\r\nlocal ib = 0\r\nfor _, e in ipairs(Feat.fxOf(SHEET, \"init_bonus\")) do ib = ib + K.fxNum(e.add or 0, SHEET, e.srcLv) end\r\nreturn r + K.abMod(\"Dexterity\") + (Feat.has(SHEET, \"Alert\") and PROF or 0) + ib\r\nend\r\n\r\n\r\n\r\n\r\nfunction Feat.arcane(r)\r\nlocal uses = {}\r\n\r\nlocal from = {}\r\nif K.cl(SHEET, \"Wizard\") > 0 then uses[1] = \"Arcane Recovery\"; from[\"Arcane Recovery\"] = \"Wizard\" end\r\nfor _, e in ipairs(Feat.fxOf(SHEET, \"slot_recovery\")) do uses[#uses + 1] = e.use; from[e.use] = e.srcClass end\r\nlocal out = \"\"\r\nfor _, use in ipairs(uses) do\r\nif (r.res[use] or 0) >= 1 then\r\nlocal budget, got = math.ceil(K.cl(SHEET, from[use] or SHEET.class) / 2), {}\r\nfor lv = 5, 1, -1 do\r\nlocal key = \"Spell Slot \" .. lv\r\nwhile PC.res[key] and budget >= lv and (r.res[key] or 0) < PC.res[key].max do\r\nr.res[key] = (r.res[key] or 0) + 1\r\nbudget = budget - lv\r\ngot[#got + 1] = lv\r\nend\r\nend\r\nif #got > 0 then\r\nr.res[use] = r.res[use] - 1\r\nout = out .. \", \" .. use .. \": slots \" .. table.concat(got, \",\")\r\nend\r\nend\r\nend\r\nreturn out\r\nend\r\n\r\n\r\n\r\n\r\n\r\nfunction Feat.gloss(key, v)\r\nlocal ko = Feat.KO[key] and Feat.KO[key][v]\r\nreturn ko and (v .. \" (\" .. ko .. \")\") or v\r\nend\r\n\r\nFeat.KO = {\r\nstyle = { Archery = \"궁술\", Defense = \"방어술\", [\"Great Weapon Fighting\"] = \"대형 무기 전투술\", [\"Two-Weapon Fighting\"] = \"쌍수 전투술\" },\r\norder = { Protector = \"수호자\", Thaumaturge = \"기적술사\" },\r\ndragon = { Acid = \"산성 (검정·구리)\", Cold = \"냉기 (은·백색)\", Fire = \"화염 (금·놋쇠·적색)\", Lightning = \"번개 (청색·청동)\", Poison = \"독 (녹색)\" },\r\nlineage = { Drow = \"드로우\", [\"High Elf\"] = \"하이 엘프\", [\"Wood Elf\"] = \"우드 엘프\" },\r\ngnome = { Forest = \"숲 노움\", Rock = \"바위 노움\" },\r\nbeast = { Dog = \"개\", Cat = \"고양이\", Fox = \"여우\", Bear = \"곰\" },\r\ngiant = { Cloud = \"구름\", Fire = \"화염\", Frost = \"서리\", Hill = \"언덕\", Stone = \"바위\", Storm = \"폭풍\" },\r\nlegacy = { Abyssal = \"심연\", Chthonic = \"저승\", Infernal = \"지옥\" },\r\nfeat = { Alert = \"경계심\", [\"Magic Initiate\"] = \"마법 입문자\", [\"Savage Attacker\"] = \"야만적인 공격자\", Skilled = \"숙련자\",\r\nGrappler = \"잡기 전문가\" },\r\nmilist = { Cleric = \"클레릭\", Druid = \"드루이드\", Wizard = \"위저드\" },\r\nspellab = { Intelligence = \"지능\", Wisdom = \"지혜\", Charisma = \"매력\" },\r\nboonab = { Strength = \"근력\", Dexterity = \"민첩\", Constitution = \"건강\", Intelligence = \"지능\", Wisdom = \"지혜\", Charisma = \"매력\" },\r\nmastery = { Cleave = \"가르기\", Graze = \"스치기\", Nick = \"잇기\", Push = \"밀치기\", Sap = \"약화\", Slow = \"둔화\", Topple = \"넘어뜨리기\", Vex = \"괴롭히기\" },\r\nprimal = { Magician = \"주술사\", Warden = \"수호자\" },\r\nland = { Arid = \"건조 지대\", Polar = \"극지\", Temperate = \"온대\", Tropical = \"열대\" },\r\nprey = { [\"Colossus Slayer\"] = \"거체 학살자\", [\"Horde Breaker\"] = \"무리 파쇄자\" },\r\n}\r\nFeat.TITLE = {\r\nstyle = \"전투 유파 · 하나\", order = \"신성한 소임 · 하나\", dragon = \"용의 혈통 · 숨결과 저항의 피해 종류\", lineage = \"엘프 혈통\",\r\ngnome = \"노움 혈통\", giant = \"거인 혈통\", legacy = \"악마의 유산\", keen = \"예리한 감각 · 기술 하나\", feat = \"다재다능 · 출신 재주 하나\",\r\nskillful = \"숙련 · 기술 하나\",\r\nmilist = \"마법 입문자 · 주문 목록\", skilled = \"숙련자 · 기술 셋\", mastery = \"무기 통달 · 가진 무기 종류\",\r\nspellab = \"종족 주문 · 주문시전 능력치\",\r\nprimal = \"원시의 소임 · 하나\", land = \"대지의 회합 · 땅 하나\", prey = \"사냥꾼의 사냥감 · 하나\",\r\nxskill = \"추가 기술 숙련\", mcskill = \"멀티클래스 기술 숙련\", metamagic = \"마법변형\", invocations = \"섬뜩한 영창\",\r\nblessed = \"축복받은 일격 · 하나\", fury = \"원소의 분노 · 하나\", affinity = \"원소 친화 · 피해 종류 하나\",\r\nresilience = \"악마의 탄성 · 저항할 피해 종류\", xstyle = \"추가 전투 유파 · 하나\", size = \"체격 · 하나\", lustbrand = \"낙인 · 고르기\", heatday = \"다음 히트까지 · 하나\",\r\nboon = \"에픽 은혜 · 하나\", boonab = \"에픽 은혜 +1 · 능력치 하나 (최대 30)\", beast = \"수인 혈통 · 하나\",\r\nmastone = \"주문 통달 · 1레벨 주문 하나\", masttwo = \"주문 통달 · 2레벨 주문 하나\", sig = \"대표 주문 · 3레벨 주문 둘\",\r\n}\r\n\r\nsetmetatable(Feat.TITLE, { __index = function(_, k)\r\nlocal cl = K.subClassOf(k)\r\nreturn cl and (\"하위 클래스 · \" .. (NAMES_KO[cl] or cl)) or nil\r\nend })\r\nFeat.EFFECT = {\r\nArchery = \"+2 to attack rolls with ranged weapons (Lua adds it)\", Defense = \"+1 AC while wearing armor (Lua adds it)\",\r\n[\"Great Weapon Fighting\"] = \"with a two-handed melee weapon, damage dice of 1 or 2 count as 3 (write the dice as rolled, the damage with them as 3)\",\r\n[\"Two-Weapon Fighting\"] = \"the off-hand attack adds the ability modifier (in the formula)\",\r\nCleave = \"on a melee hit, one more attack against a second creature within 5 ft: its damage adds no ability modifier (Rage and other bonuses still add), once per turn\",\r\nGraze = \"a miss still deals the ability modifier: write the miss with that damage, [ATTACK|...|miss|-|-|N]\",\r\nNick = \"the off-hand Light attack is part of the Attack action, not a Bonus Action\",\r\nPush = \"on a hit, push a Large or smaller target 10 ft away\",\r\nSap = \"on a hit, the target has Disadvantage on its next attack roll before the start of the attacker's next turn\",\r\nSlow = \"on a hit with damage, the target's Speed -10 ft until the start of the attacker's next turn (not more than -10 from several hits)\",\r\n\r\nTopple = \"on a hit, the target makes a Constitution save (DC %d) or falls Prone: [HAZARD|Name|Topple|Constitution|d20|+bonus|DC|success/failure|-|-|0] (Lua keeps the Prone)\",\r\nVex = \"on a hit with damage, the same attacker has Advantage on its own next attack against that target (no one else's), until the end of its next turn\",\r\n}\r\n\r\nfunction Feat.label(key, v)\r\nif K.subClassOf(key) then return NAMES_KO[v] or v end\r\nif key == \"keen\" or key == \"skillful\" or key == \"skilled\" or key == \"xskill\" or key == \"mcskill\" or key == \"metamagic\" or key == \"invocations\" or Feat.isMany(key) then return NAMES_KO[v] or v end\r\n\r\nif K.FX[v] then return NAMES_KO[v] or v end\r\nif key == \"affinity\" or key == \"resilience\" then return (K.DMG_KO and K.DMG_KO[v]) or v end\r\nif key == \"size\" then return K.SIZE_KO[v] or v end\r\nif key == \"heatday\" then return v .. \"일 뒤\" end\r\nif key == \"xstyle\" then key = \"style\" end\r\nif Feat.KO[key] and Feat.KO[key][v] then return Feat.KO[key][v] end\r\n\r\n\r\nif NAMES_KO[v] then return NAMES_KO[v] end\r\nif K.DMG_KO and K.DMG_KO[v] then return K.DMG_KO[v] end\r\nfor ko, en in pairs(K.ABIL_KO or {}) do if en == v then return ko end end\r\nreturn v\r\nend\r\n\r\n\r\nfunction Feat.ownWeapons(pc)\r\nlocal out, seen = {}, {}\r\nlocal names = {}\r\nfor n in pairs(type(pc.items) == \"table\" and pc.items or {}) do names[#names + 1] = n end\r\ntable.sort(names)\r\nfor _, n in ipairs(names) do\r\nlocal base = WEAPONS[n] and n or (type(pc.loot) == \"table\" and type(pc.loot[n]) == \"table\" and pc.loot[n].base)\r\nif base and WEAPONS[base] and weaponProf(WEAPONS[base]) and not seen[base] then\r\nseen[base] = true\r\nout[#out + 1] = base\r\nend\r\nend\r\nreturn out\r\nend\r\n\r\n\r\nfunction Feat.pending(sh, pc)\r\nlocal p, out = Feat.picks(sh), {}\r\nlocal function one(key, opts) if p[key] == nil then out[#out + 1] = { key = key, need = 1, opts = opts } end end\r\n\r\nfor _, c in ipairs(K.classes(sh)) do\r\nif c.level >= K.subLevel(c.name) then\r\nlocal o = K.subOptions(c.name)\r\nif #o > 1 then one(K.subKey(c.name), o) end\r\nend\r\nend\r\nif Feat.hasStyle(sh) then one(\"style\", K.d2names(Feat.STYLES)) end\r\nif K.AR and K.AR.on() and #K.AR.names() > 0 then one(\"sexhist\", K.AR.names()) end\r\nif K.AR and K.AR.on() then one(\"inhib\", { \"Intelligence\", \"Wisdom\", \"Charisma\" }) end\r\n\r\nif K.cl(sh, \"Cleric\") > 0 then one(\"order\", { \"Protector\", \"Thaumaturge\" }) end\r\nif K.cl(sh, \"Druid\") > 0 then one(\"primal\", { \"Magician\", \"Warden\" }) end\r\nif K.subHas(sh, \"Circle of the Land Spells\") then one(\"land\", { \"Arid\", \"Polar\", \"Temperate\", \"Tropical\" }) end\r\nif K.subHas(sh, \"Hunter's Prey\") then one(\"prey\", { \"Colossus Slayer\", \"Horde Breaker\" }) end\r\nlocal function many(key, n, opts)\r\nlocal have = type(p[key]) == \"table\" and p[key] or {}\r\nif #have < n then\r\nlocal mine, o = {}, {}\r\nfor _, x in ipairs(have) do mine[x] = true end\r\nfor _, x in ipairs(opts) do if not mine[x] then o[#o + 1] = x end end\r\nif #o > 0 then out[#out + 1] = { key = key, need = n - #have, opts = o } end\r\nend\r\nend\r\n\r\nlocal hist = K.AR and K.AR.on() and K.PACK.ar and K.PACK.ar.hist[p.sexhist or \"\"]\r\nif hist and (tonumber(hist.tools) or 0) > 0 then\r\nlocal o = {}\r\nfor n, impl in pairs(K.PACK.impl) do if impl.kind == \"tool\" and K.d2ok(impl) then o[#o + 1] = n end end\r\ntable.sort(o)\r\nmany(\"imptools\", tonumber(hist.tools), o)\r\nend\r\n\r\nif #Feat.fxOf(sh, \"heat_cycle\") > 0 then one(\"heatday\", { \"1\", \"3\", \"5\", \"7\", \"10\", \"14\", \"21\", \"30\" }) end\r\n\r\n\r\nif K.AR and K.AR.on() and K.PACK.afflict then\r\nlocal n, kinds = 0, {}\r\nfor _, e in ipairs(Feat.fxOf(sh, \"brand_slots\")) do\r\nn = n + (tonumber(e.n) or 1)\r\nfor _, k in ipairs(type(e.kinds) == \"table\" and e.kinds or { \"brand\" }) do kinds[k] = true end\r\nend\r\nif n > 0 then\r\nlocal o = {}\r\nfor nm, r in pairs(K.PACK.afflict) do if type(r) == \"table\" and kinds[r.kind] and not K.d2need(r) then o[#o + 1] = nm end end\r\ntable.sort(o)\r\nmany(\"lustbrand\", n, o)\r\nend\r\nend\r\n\r\nif K.PACK.afflict and K.AR and K.AR.on() then\r\nlocal fn, fon, fopts = K.fetishSlots(sh)\r\nif fn > 0 then\r\nmany(\"fetish\", fn, fopts)\r\nlocal have = type(p.fetish) == \"table\" and p.fetish or {}\r\nif fon and #have > fon then many(\"fetishon\", fon, have) end\r\nend\r\nend\r\n\r\nlocal mcN, mcFrom, mcAny = 0, {}, false\r\nfor _, m in ipairs(K.mcList(sh)) do\r\nlocal g = K.mcGains(m.class).skill\r\nif g then\r\nmcN = mcN + 1\r\nif g == \"any\" then mcAny = true else for _, k in ipairs(CLASSES[m.class].skills.from or {}) do mcFrom[k] = true end end\r\nend\r\nend\r\nif mcN > 0 then\r\nlocal o, names = {}, {}\r\nfor k in pairs(SKILL) do names[#names + 1] = k end\r\ntable.sort(names)\r\nlocal mine = {}\r\nfor _, k in ipairs(type(p.mcskill) == \"table\" and p.mcskill or {}) do mine[k] = true end\r\nfor _, k in ipairs(names) do if (mcAny or mcFrom[k]) and (not SKILL_PROF[k] or mine[k]) then o[#o + 1] = k end end\r\nmany(\"mcskill\", mcN, o)\r\nend\r\nlocal xrow = {}\r\nfor _, c in ipairs(K.classes(sh)) do if c.row.extra_skill then xrow = { extra_skill = c.row.extra_skill, cls = c.name } end end\r\nif xrow.extra_skill then\r\nlocal row = xrow\r\nlocal from = xrow.cls == \"Barbarian\" and CLASSES.Barbarian.skills.from or nil\r\nlocal o, names = {}, {}\r\nfor k in pairs(SKILL) do names[#names + 1] = k end\r\ntable.sort(names)\r\nfor _, k in ipairs(from or names) do if not SKILL_PROF[k] or (type(p.xskill) == \"table\" and table.concat(p.xskill, \",\"):find(k, 1, true)) then o[#o + 1] = k end end\r\nmany(\"xskill\", row.extra_skill, o)\r\nend\r\n\r\n\r\n\r\n\r\nfor _, e in ipairs(Feat.fxOf(sh, \"choice\")) do\r\nlocal o = Feat.choiceOpts(sh, e)\r\nif #o > 0 and not e.on_use then\r\nif e.count or e.count_at then many(e.key, K.choiceCount(e, sh), o) else one(e.key, o) end\r\nend\r\nend\r\nfor _, e in ipairs(Feat.fxOf(sh, \"resist\")) do if e.pick then one(e.pick, e.opts or {}) end end\r\n\r\nfor _, e in ipairs(Feat.fxOf(sh, \"spell_pick\")) do many(e.key, e.count or 1, Feat.spellPickOpts(sh, e)) end\r\n\r\nif type(p.boon) == \"string\" and p.boonab == nil then\r\nlocal o = {}\r\nfor _, a in ipairs(Feat.boonAbils(p.boon)) do if (sh.scores[a] or 10) < 30 then o[#o + 1] = a end end\r\nif #o > 0 then out[#out + 1] = { key = \"boonab\", need = 1, opts = o } end\r\nend\r\nif p.style then\r\nfor _, e in ipairs(Feat.fxOf(sh, \"style_pick\")) do\r\nlocal o = {}\r\nfor _, s in ipairs(K.d2names(Feat.STYLES)) do if s ~= p.style then o[#o + 1] = s end end\r\none(e.key, o)\r\nend\r\nend\r\nlocal srow, wrow = K.rowOf(sh, \"Sorcerer\"), K.rowOf(sh, \"Warlock\")\r\n\r\nlocal packMM, packInv = {}, {}\r\nfor n, cat in pairs(K.PACK.feat or {}) do\r\nif cat == \"metamagic\" and K.d2ok(K.FX[n]) then packMM[#packMM + 1] = n end\r\nif cat == \"invocation\" and K.d2ok(K.FX[n]) then packInv[#packInv + 1] = n end\r\nend\r\ntable.sort(packMM); table.sort(packInv)\r\nif srow.metamagic then\r\nlocal o = {}\r\nfor _, x in ipairs(Feat.METAMAGIC) do o[#o + 1] = x end\r\nfor _, x in ipairs(packMM) do o[#o + 1] = x end\r\nmany(\"metamagic\", srow.metamagic, o)\r\nend\r\nif wrow.invocations then\r\nlocal o = {}\r\nfor _, x in ipairs(Feat.INVOCATIONS) do\r\nif K.cl(sh, \"Warlock\") >= x[2] and (not x[3] or Feat.invoked(sh, x[3])) then o[#o + 1] = x[1] end\r\nend\r\nfor _, n in ipairs(packInv) do\r\nlocal r = K.FX[n]\r\nif K.cl(sh, \"Warlock\") >= (tonumber(r.level) or 1) and (not r.requires or Feat.invoked(sh, r.requires))\r\nand (not r.requires_spell or K.knowsSpell(sh, r.requires_spell)) then o[#o + 1] = n end\r\nend\r\nmany(\"invocations\", wrow.invocations, o)\r\nend\r\nif sh.species == \"Dragonborn\" then one(\"dragon\", Feat.DRAGON) end\r\nif sh.species == \"Elf\" then one(\"lineage\", { \"Drow\", \"High Elf\", \"Wood Elf\" }) end\r\nif sh.species == \"Gnome\" then one(\"gnome\", { \"Forest\", \"Rock\" }) end\r\nif sh.species == \"Goliath\" then one(\"giant\", Feat.GIANT) end\r\nif sh.species == \"Tiefling\" then one(\"legacy\", { \"Abyssal\", \"Chthonic\", \"Infernal\" }) end\r\nif sh.species == \"Beastfolk\" then one(\"beast\", { \"Dog\", \"Cat\", \"Fox\", \"Bear\" }) end\r\nif sh.species == \"Elf\" and p.keen == nil then\r\nlocal o = {}\r\nfor _, k in ipairs({ \"Insight\", \"Perception\", \"Survival\" }) do if not SKILL_PROF[k] then o[#o + 1] = k end end\r\nif #o == 0 then o = { \"Insight\", \"Perception\", \"Survival\" } end\r\nout[#out + 1] = { key = \"keen\", need = 1, opts = o }\r\nend\r\nif sh.species == \"Human\" then\r\n\r\n\r\nlocal bg, o = K.bgFeat(sh.background), {}\r\nfor _, x in ipairs(K.d2names(Feat.ORIGIN)) do if not (bg and bg[1] == x) then o[#o + 1] = x end end\r\none(\"feat\", o)\r\n\r\n\r\nif sh.skillful_due and p.skillful == nil then\r\nlocal so, names = {}, {}\r\nfor k in pairs(SKILL) do names[#names + 1] = k end\r\ntable.sort(names)\r\nfor _, k in ipairs(names) do if not SKILL_PROF[k] then so[#so + 1] = k end end\r\none(\"skillful\", so)\r\nend\r\nend\r\nif Feat.LINEAGE_KEY[sh.species or \"\"] then one(\"spellab\", { \"Intelligence\", \"Wisdom\", \"Charisma\" }) end\r\n\r\nif K.AR and K.AR.on() then\r\nlocal s1, s2 = tostring((SPECIES[sh.species or \"\"] or {}).size or \"\"):match(\"^(%a+) or (%a+)$\")\r\nif s1 and s2 then one(\"size\", { s1, s2 }) end\r\nend\r\nif Feat.has(sh, \"Magic Initiate\") and not Feat.miList(sh) then one(\"milist\", Feat.MI_LISTS) end\r\nif Feat.has(sh, \"Skilled\") then\r\nlocal have = type(p.skilled) == \"table\" and p.skilled or {}\r\nif #have < 3 then\r\nlocal o, names = {}, {}\r\nfor k in pairs(SKILL) do names[#names + 1] = k end\r\ntable.sort(names)\r\nfor _, k in ipairs(names) do if not SKILL_PROF[k] then o[#o + 1] = k end end\r\nout[#out + 1] = { key = \"skilled\", need = 3 - #have, opts = o }\r\nend\r\nend\r\nlocal n = Feat.masteryN(sh)\r\nif n > 0 then\r\nlocal have = type(p.mastery) == \"table\" and p.mastery or {}\r\nif #have < n then\r\n\r\nlocal mine, o = {}, {}\r\nfor _, w in ipairs(have) do mine[w] = true end\r\nfor _, w in ipairs(Feat.ownWeapons(pc)) do if not mine[w] then o[#o + 1] = w; mine[w] = true end end\r\nlocal owned, rest = #o, {}\r\nfor w, row in pairs(WEAPONS) do\r\nif not mine[w] and row.mastery and not Shop.NO_SALE[w] and weaponProf(row) then rest[#rest + 1] = w end\r\nend\r\ntable.sort(rest)\r\nfor _, w in ipairs(rest) do o[#o + 1] = w end\r\nif #o > 0 then out[#out + 1] = { key = \"mastery\", need = n - #have, opts = o, owned = owned } end\r\nend\r\nend\r\nreturn out\r\nend\r\n\r\n\r\n\r\nfunction Feat.choiceOpts(sh, e)\r\nlocal o = {}\r\n\r\nlocal taken = {}\r\nlocal base = e.copyBase or (type(e.key) == \"string\" and e.key) or nil\r\nif base then\r\nlocal p = type(sh.picks) == \"table\" and sh.picks or {}\r\n\r\nlocal function take(v) if type(v) == \"string\" then taken[v] = true elseif type(v) == \"table\" then for _, x in ipairs(v) do taken[x] = true end end end\r\nif e.copyBase then take(p[base]) end\r\nfor j = 2, 9 do if j ~= e.copyN then take(p[base .. \"_\" .. j]) end end\r\nend\r\nfor _, x in ipairs(e.options or {}) do if taken[x] then goto nextOpt end\r\nlocal only = K.FX[x] and K.FX[x].classes\r\nlocal fits = type(only) ~= \"table\" and not (K.FX[x] and K.d2need(K.FX[x]))\r\nfor _, c in ipairs(type(only) == \"table\" and only or {}) do if K.cl(sh.base or sh, c) > 0 and not K.d2need(K.FX[x]) then fits = true end end\r\nif fits then o[#o + 1] = x end\r\n::nextOpt::\r\nend\r\nreturn o\r\nend\r\n\r\n\r\nfunction K.choiceCount(e, sh)\r\nlocal lv = tonumber(e.srcLv) or tonumber(sh and sh.level) or 1\r\nlocal n, at = e.count or 1, -1\r\nfor k, v in pairs(type(e.count_at) == \"table\" and e.count_at or {}) do\r\nif tonumber(k) and tonumber(k) <= lv and tonumber(k) > at then at, n = tonumber(k), v end\r\nend\r\nreturn math.max(0, math.floor(K.fxNum(n, sh, lv)))\r\nend\r\n\r\nfunction K.pickHas(pv, v)\r\nif pv == v then return true end\r\nif type(pv) == \"table\" then for _, x in ipairs(pv) do if x == v then return true end end end\r\nreturn false\r\nend\r\nfunction Feat.isMany(key)\r\nif key == \"imptools\" or key == \"fetish\" or key == \"fetishon\" or key == \"lustbrand\" then return true end\r\n\r\nif not Feat.manyKeys or Feat.manyGen ~= K.PACK.gen then\r\nlocal o = {}\r\nfor _, rec in pairs(K.FX) do\r\nfor _, e in ipairs(rec.fx) do\r\nif (e.t == \"spell_pick\" and e.key) or (e.t == \"choice\" and e.key and (e.count or e.count_at)) then o[e.key] = true end\r\nend\r\nend\r\nFeat.manyKeys, Feat.manyGen = o, K.PACK.gen\r\nend\r\nif Feat.manyKeys[key] == true then return true end\r\nlocal baseKey = tostring(key):match(\"^(.-)_%d+$\")\r\nreturn baseKey ~= nil and Feat.manyKeys[baseKey] == true\r\nend\r\n\r\n\r\nfunction Feat.spellPickOpts(sh, e)\r\nlocal own, mine, all, names = {}, {}, {}, {}\r\nlocal was = {}\r\nlocal pv = type(sh.picks) == \"table\" and sh.picks[e.key]\r\nfor _, n in ipairs(type(pv) == \"table\" and pv or { pv }) do if type(n) == \"string\" then was[n] = true end end\r\nfor _, l in ipairs({ sh.book, (select(2, K.lists(sh, e.srcClass or \"Wizard\"))) }) do for _, n in ipairs(type(l) == \"table\" and l or {}) do own[n] = true end end\r\nfor n in pairs(SPELLS) do names[#names + 1] = n end\r\ntable.sort(names)\r\nfor _, n in ipairs(names) do\r\nlocal sp = SPELLS[n]\r\nlocal inList = false\r\nfor _, c in ipairs(sp.classes or {}) do if c == e.list then inList = true end end\r\nif inList and sp.level == e.level and (not e.cast or (sp.m and sp.m.cast) == e.cast) and (was[n] or not K.spellOff(n)) and K.schoolOk(sp, e.schools) then\r\nall[#all + 1] = n\r\nif own[n] then mine[#mine + 1] = n end\r\nend\r\nend\r\nreturn #mine > 0 and mine or all\r\nend\r\n\r\nfunction K.schoolOk(sp, schools)\r\nif type(schools) ~= \"table\" or #schools == 0 then return true end\r\nlocal en = (K.SCHOOL_EN and K.SCHOOL_EN[sp.school or \"\"]) or sp.school\r\nfor _, x in ipairs(schools) do if x == en then return true end end\r\nreturn false\r\nend\r\n\r\nfunction K.knowsSpell(sh, name)\r\nfor _, l in ipairs({ sh.cantrips or {}, sh.spells or {}, sh.book or {} }) do for _, x in ipairs(l) do if x == name then return true end end end\r\nlocal base = sh.base or sh\r\nfor _, lists in pairs(type(base.mcspells) == \"table\" and base.mcspells or {}) do\r\nfor _, l in ipairs(type(lists) == \"table\" and { lists.cantrips or {}, lists.spells or {} } or {}) do for _, x in ipairs(l) do if x == name then return true end end end\r\nend\r\nreturn Feat.extras(sh)[name] ~= nil\r\nend\r\n\r\nfunction Feat.boonAbils(boon)\r\nlocal rec = K.FX[boon or \"\"]\r\nreturn (rec and type(rec.abilities) == \"table\") and rec.abilities or ABILS\r\nend\r\n\r\n\r\nfunction Feat.pick(sh, key, v, pc)\r\nlocal p = Feat.picks(sh)\r\nif key == \"mastery\" and v == \"RESET\" then\r\nif not Feat.masteryFree(sh, pc) then return false end\r\np.mastery, p.mastery_at = {}, tonumber(pc.long_end) or -1\r\nreturn true\r\nend\r\n\r\nif (key == \"mastone\" or key == \"masttwo\") and v == \"RESET\" then\r\nif not Feat.smFree(sh, pc) or type(p[key]) ~= \"table\" or #p[key] == 0 then return false end\r\np[key], p.sm_at = {}, tonumber(pc and pc.long_end) or -1\r\nreturn true\r\nend\r\n\r\nif key == \"fetishon\" and v == \"RESET\" then\r\nif not Feat.fetishFree(sh, pc) or type(p.fetishon) ~= \"table\" then return false end\r\np.fetishon, p.fetishon_at = nil, tonumber(pc and pc.long_end) or -1\r\nreturn true\r\nend\r\n\r\nif type(v) == \"string\" and v:sub(1, 5) == \"DROP \" then\r\nlocal name = v:sub(6)\r\nfor _, row in ipairs(K.histOver(sh)) do\r\nif row.key == key and K.pickHas(row.opts, name) and type(p[key]) == \"table\" then\r\nfor i = #p[key], 1, -1 do if p[key][i] == name then table.remove(p[key], i); break end end\r\nif #p[key] == 0 then p[key] = nil end\r\nif key == \"fetish\" then p.fetishon = nil end\r\nreturn true\r\nend\r\nend\r\nreturn false\r\nend\r\n\r\nif v == \"UNDO\" then\r\nif not (pc and pc.making) or not K.undoKey(sh, key) or p[key] == nil then return false end\r\nK.pickUndo(sh, key, pc)\r\nreturn true\r\nend\r\n\r\nif key == \"resilience\" and v == \"RESET\" then\r\nif not Feat.resilienceFree(sh, pc) then return false end\r\np.resilience = nil\r\nreturn true\r\nend\r\nlocal ok = false\r\nfor _, row in ipairs(Feat.pending(sh, pc)) do\r\nif row.key == key then\r\nfor _, o in ipairs(row.opts) do if o == v then ok = true end end\r\nend\r\nend\r\nif not ok then return false end\r\nif key == \"skilled\" or key == \"mastery\" or key == \"xskill\" or key == \"mcskill\" or key == \"metamagic\" or key == \"invocations\" or Feat.isMany(key) then\r\np[key] = type(p[key]) == \"table\" and p[key] or {}\r\ntable.insert(p[key], v)\r\nelse\r\np[key] = v\r\nend\r\nif key == \"resilience\" then p.resilience_at = tonumber(pc and pc.rests) or 0 end\r\n\r\n\r\nif key == \"lustbrand\" and K.PACK.afflict and type(K.PACK.afflict[v]) == \"table\" then\r\nlocal r = K.PACK.afflict[v]\r\nsh.afflict = type(sh.afflict) == \"table\" and sh.afflict or {}\r\nlocal have = false\r\nfor _, e in ipairs(sh.afflict) do if type(e) == \"table\" and e.name == v and not e.over then have = true end end\r\nif not have then\r\n\r\nlocal srcOf = K.brandSlotsFill(sh, p.lustbrand)\r\nif not srcOf then table.remove(p.lustbrand); return false end\r\nlocal src = srcOf[v]\r\nsh.afflict[#sh.afflict + 1] = { name = v, kind = r.kind, at = (K.clockRef and tonumber(K.clockRef.min)) or 0,\r\nlevel = r.kind == \"brand\" and 1 or tonumber(r.level), src = src }\r\nend\r\nend\r\nif key == \"boonab\" then sh.scores[v] = math.min(30, (sh.scores[v] or 10) + 1) end\r\nreturn true\r\nend\r\n\r\n\r\n\r\n\r\n\r\nK.UNDO_KEYS = { style = 1, xstyle = 1, order = 1, primal = 1, land = 1, prey = 1, dragon = 1, lineage = 1, gnome = 1, giant = 1, legacy = 1,\r\nspellab = 1, keen = 1, skillful = 1, feat = 1, milist = 1, blessed = 1, fury = 1, affinity = 1, boon = 1, boonab = 1, sexhist = 1, inhib = 1,\r\nxskill = 1, mcskill = 1, metamagic = 1, invocations = 1, sig = 1, imptools = 1, fetish = 1, skilled = 1, lustbrand = 1 }\r\nfunction K.undoKey(sh, key)\r\nif K.UNDO_KEYS[key] then return true end\r\nfor _, c in ipairs(K.classes(sh)) do if K.subKey(c.name) == key then return false end end\r\nfor _, e in ipairs(Feat.fxOf(sh, \"choice\")) do if e.key == key then return true end end\r\nreturn false\r\nend\r\nfunction K.pickUndo(sh, key, pc)\r\nlocal p = Feat.picks(sh)\r\nlocal function drop(k)\r\nlocal v = p[k]\r\nif k == \"boonab\" and type(v) == \"string\" and type(sh.scores) == \"table\" then sh.scores[v] = math.max(1, (tonumber(sh.scores[v]) or 10) - 1) end\r\nif k == \"lustbrand\" and type(sh.afflict) == \"table\" then\r\nfor _, nm in ipairs(type(v) == \"table\" and v or { v }) do\r\nfor i = #sh.afflict, 1, -1 do\r\nlocal e = sh.afflict[i]\r\nif type(e) == \"table\" and e.name == nm and not e.over then table.remove(sh.afflict, i); break end\r\nend\r\nend\r\nend\r\nif k == \"milist\" then sh.mi = nil end\r\nif k == \"sexhist\" then sh.histlv = nil end\r\np[k] = nil\r\nend\r\ndrop(key)\r\nfor _ = 1, 8 do\r\nlocal keys = {}\r\nfor k in pairs(p) do if k ~= key and K.undoKey(sh, k) then keys[#keys + 1] = k end end\r\ntable.sort(keys)\r\nlocal changed = false\r\nfor _, k in ipairs(keys) do\r\nlocal held = p[k]\r\np[k] = nil\r\nlocal offered = {}\r\nfor _, row in ipairs(Feat.pending(sh, pc)) do if row.key == k then for _, o in ipairs(row.opts or {}) do offered[o] = true end end end\r\np[k] = held\r\nlocal fits = true\r\nfor _, x in ipairs(type(held) == \"table\" and held or { held }) do if not offered[x] then fits = false end end\r\nif not fits then drop(k); changed = true end\r\nend\r\nif not changed then break end\r\nend\r\nif type(sh.mi) == \"table\" and not Feat.has(sh, \"Magic Initiate\") then sh.mi = nil end\r\nend\r\n\r\n\r\nfunction K.brandSlotsFill(sh, list)\r\nlocal slots = {}\r\nfor i, e in ipairs(Feat.fxOf(sh, \"brand_slots\")) do\r\nlocal kinds, nk = {}, 0\r\nfor _, k in ipairs(type(e.kinds) == \"table\" and e.kinds or { \"brand\" }) do kinds[k] = true; nk = nk + 1 end\r\nfor j = 1, tonumber(e.n) or 1 do slots[#slots + 1] = { kinds = kinds, nk = nk, src = e.source or e.src, i = i * 100 + j } end\r\nend\r\ntable.sort(slots, function(x, y) if x.nk ~= y.nk then return x.nk < y.nk end return x.i < y.i end)\r\nlocal srcOf = {}\r\nfor _, nm in ipairs(type(list) == \"table\" and list or {}) do\r\nlocal r = K.PACK.afflict and K.PACK.afflict[nm]\r\nlocal put\r\nfor _, sl in ipairs(slots) do if not sl.used and type(r) == \"table\" and sl.kinds[r.kind] then sl.used = true; put = sl; break end end\r\nif not put then return nil end\r\nsrcOf[nm] = put.src\r\nend\r\nreturn srcOf\r\nend\r\nfunction Feat.fetishFree(sh, pc)\r\nlocal p = Feat.picks(sh)\r\nif p.fetishon_at == nil then return true end\r\nreturn (tonumber(pc and pc.long_end) or -1) ~= p.fetishon_at\r\nend\r\n\r\nfunction Feat.smFree(sh, pc)\r\nlocal p = Feat.picks(sh)\r\nif p.sm_at == nil then return true end\r\nreturn (tonumber(pc and pc.long_end) or -1) ~= p.sm_at\r\nend\r\n\r\n\r\nfunction Feat.resilienceFree(sh, pc)\r\nlocal p = Feat.picks(sh)\r\nif p.resilience == nil then return false end\r\nreturn (tonumber(pc and pc.rests) or 0) > (tonumber(p.resilience_at) or 0)\r\nend\r\n\r\n\r\nfunction Feat.masteryFree(sh, pc)\r\nlocal p = Feat.picks(sh)\r\nif p.mastery_at == nil then return true end\r\nreturn (tonumber(pc.long_end) or -1) ~= p.mastery_at\r\nend\r\n\r\n\r\nfunction Feat.fillRes(pc)\r\npc.res = type(pc.res) == \"table\" and pc.res or {}\r\n\r\n\r\n\r\npc.resMax = type(pc.resMax) == \"table\" and pc.resMax or {}\r\nfor name, r in pairs(PC.res) do\r\nlocal mx = tonumber(r.max) or 0\r\nif pc.res[name] == nil then\r\npc.res[name] = r.max\r\nelseif tonumber(pc.resMax[name]) and mx > pc.resMax[name] then\r\npc.res[name] = math.min(mx, (tonumber(pc.res[name]) or 0) + mx - pc.resMax[name])\r\nend\r\nif not tonumber(pc.resMax[name]) or mx > pc.resMax[name] then pc.resMax[name] = mx end\r\nend\r\nend\r\n\r\n\r\nfunction Ally.autoPick(a)\r\nlocal sh = a.sheet\r\nlocal p = Feat.picks(sh)\r\nAlly.with(a, function()\r\nif Feat.hasStyle(sh) and not p.style then\r\n\r\nlocal w = a.equip and a.equip.main and WEAPONS[a.equip.main]\r\np.style = (w and w.ranged) and \"Archery\" or (w and (w.two or (w.vers and not a.equip.off))) and \"Great Weapon Fighting\" or \"Defense\"\r\nend\r\n\r\nif K.cl(sh, \"Cleric\") > 0 and not p.order then p.order = \"Protector\" end\r\nif K.cl(sh, \"Druid\") > 0 and not p.primal then p.primal = \"Warden\" end\r\nif K.subHas(sh, \"Circle of the Land Spells\") and not p.land then p.land = \"Temperate\" end\r\nif K.subHas(sh, \"Hunter's Prey\") and not p.prey then p.prey = \"Colossus Slayer\" end\r\nlocal first = { dragon = \"Fire\", lineage = \"High Elf\", gnome = \"Rock\", giant = \"Stone\", legacy = \"Infernal\", feat = \"Alert\", spellab = Feat.mental(sh),\r\nbeast = \"Dog\" }\r\n\r\nfor _, e in ipairs(Feat.fxOf(sh, \"choice\")) do first[e.key] = (type(e.by_class) == \"table\" and e.by_class[sh.class]) or e.default end\r\nfor _, e in ipairs(Feat.fxOf(sh, \"resist\")) do if e.pick then first[e.pick] = e.default end end\r\nfirst.xstyle = p.style ~= \"Defense\" and \"Defense\" or \"Archery\"\r\nif K.AR and K.AR.on() then first.inhib = K.AR.bestMental(sh) end\r\n\r\nfor _, c in ipairs(K.classes(sh)) do first[K.subKey(c.name)] = Ally.cdata(c.name, \"subclass\") end\r\nif Feat.has(sh, \"Magic Initiate\") and not (type(sh.mi) == \"table\" and sh.mi.spell) then\r\nlocal list = Feat.miList(sh) or \"Wizard\"\r\nlocal prefC = { Cleric = { \"Guidance\", \"Light\", \"Sacred Flame\", \"Thaumaturgy\", \"Spare the Dying\", \"Resistance\" },\r\nWizard = { \"Light\", \"Mage Hand\", \"Fire Bolt\", \"Prestidigitation\", \"Minor Illusion\", \"Ray of Frost\" },\r\nDruid = { \"Guidance\", \"Druidcraft\", \"Produce Flame\", \"Shillelagh\" } }\r\nlocal prefS = { Cleric = { \"Bless\", \"Cure Wounds\", \"Healing Word\", \"Shield of Faith\" }, Wizard = { \"Shield\", \"Magic Missile\", \"Mage Armor\", \"Sleep\" },\r\nDruid = { \"Cure Wounds\", \"Healing Word\", \"Entangle\", \"Faerie Fire\" } }\r\nlocal known = {}\r\nfor _, l in ipairs({ sh.cantrips or {}, sh.spells or {} }) do for _, n in ipairs(l) do known[n] = true end end\r\nlocal cans, spell = {}, nil\r\nfor _, n in ipairs(prefC[list] or {}) do if #cans < 2 and SPELLS[n] and not known[n] then cans[#cans + 1] = n end end\r\nfor _, n in ipairs(prefS[list] or {}) do if not spell and SPELLS[n] and not known[n] then spell = n end end\r\nif #cans == 2 and spell then sh.mi = { list = list, cantrips = cans, spell = spell } end\r\nend\r\nfor _, row in ipairs(Feat.pending(sh, a)) do\r\nif row.key == \"mastery\" or row.key == \"skilled\" or row.key == \"keen\" or Ally.PREFER[row.key] or Feat.isMany(row.key) then\r\np[row.key] = row.key == \"keen\" and row.opts[1] or (type(p[row.key]) == \"table\" and p[row.key] or {})\r\nif row.key ~= \"keen\" then\r\nlocal want = { a.equip and a.equip.main, a.equip and a.equip.off }\r\nfor _, o in ipairs(Ally.PREFER[row.key] or {}) do want[#want + 1] = o end\r\nfor _, o in ipairs(row.opts) do want[#want + 1] = o end\r\nlocal seen = {}\r\nfor _, x in ipairs(p[row.key]) do seen[x] = true end\r\nfor _, o in ipairs(want) do\r\nlocal okOpt = false\r\nfor _, y in ipairs(row.opts) do if y == o then okOpt = true end end\r\nif okOpt and not seen[o] and #p[row.key] < #p[row.key] + row.need and row.need > 0 then\r\nseen[o] = true\r\ntable.insert(p[row.key], o)\r\nrow.need = row.need - 1\r\nend\r\nend\r\nend\r\nelseif K.subClassOf(row.key) then\r\n\r\n\r\nlocal want = first[row.key]\r\nfor _, o in ipairs(row.opts) do if o == want then p[row.key] = want end end\r\nelseif row.key == \"sexhist\" then\r\n\r\nelseif p[row.key] == nil then\r\nlocal want = first[row.key]\r\nlocal fits = false\r\nfor _, o in ipairs(row.opts) do if o == want then fits = true end end\r\np[row.key] = fits and want or row.opts[1]\r\nend\r\nend\r\n\r\nfor _, row in ipairs(Feat.pending(sh, a)) do\r\nif row.key == \"boonab\" then\r\nlocal pick = row.opts[1]\r\nfor i = #CLASSES[sh.class].primary, 1, -1 do\r\nfor _, o in ipairs(row.opts) do if o == CLASSES[sh.class].primary[i] then pick = o end end\r\nend\r\nFeat.pick(sh, \"boonab\", pick, a)\r\nend\r\nend\r\nend)\r\nend\r\n\r\n\r\n\r\nfunction Feat.classText(sh, pc, who, p, out)\r\nif K.subHas(sh, \"Improved Critical\") then out[#out + 1] = \"Champion: weapon attacks crit on \" .. (K.subHas(sh, \"Superior Critical\") and \"18-20\" or \"19-20\") .. \"; Advantage on Athletics checks\" end\r\nif sh.class == \"Rogue\" and sh.level >= 3 then\r\nout[#out + 1] = \"Steady Aim: a Bonus Action if \" .. who .. \" has not moved this turn: Advantage on its next attack this turn, then Speed 0 until the turn ends\"\r\nif K.subHas(sh, \"Fast Hands\") then out[#out + 1] = \"Fast Hands (Thief): a Bonus Action for a Sleight of Hand check, the Utilize action, or using a magic item\" end\r\nend\r\nif sh.class == \"Rogue\" and sh.level >= 5 then\r\nout[#out + 1] = string.format(\"Cunning Strike: trade Sneak Attack dice, save DC %d: Poison (1d6, a Poisoner's Kit: Constitution save or Poisoned for 1 minute, a save at the end of each of its turns),\"\r\n.. \" Trip (1d6, Large or smaller: Dexterity save or Prone), Withdraw (1d6: move half Speed with no Opportunity Attacks)\", 8 + MOD.Dexterity + PROF)\r\n.. \"; the Sneak Attack dice left in the hit's formula, then \"\r\n.. (pc.name and \"the save as the story's and a failure's [COND|Name|+Poisoned|1m|Cunning Strike] or [COND|Name|+Prone|-|Cunning Strike]\"\r\nor (\"[HAZARD|Name|Cunning Strike (Poison)|Constitution|d20|+bonus|\" .. (8 + MOD.Dexterity + PROF) .. \"|success/failure|-|-|0] or (Trip)|Dexterity\"\r\n.. \" (Lua keeps Poisoned and Prone; Poisoned's save at the end of each of its turns is the same HAZARD, a success ends it)\"))\r\nout[#out + 1] = \"Uncanny Dodge: the first hit on \" .. who .. \" each reply is halved (round down; write the halved damage)\"\r\nend\r\nif sh.class == \"Cleric\" then\r\nif p.order then out[#out + 1] = \"Divine Order \" .. Feat.gloss(\"order\", p.order) .. (p.order == \"Protector\" and \": Martial weapons and Heavy armor\" or \": one more cantrip, + Wisdom to Arcana and Religion (in the bonuses)\") end\r\nif sh.level >= 2 then\r\n\r\n\r\nlocal spark, dc = string.format(\"%dd8%+d\", K.sparkDice(sh.level), MOD.Wisdom), 8 + MOD.Wisdom + PROF\r\nlocal sear = math.max(1, MOD.Wisdom) .. \"d8\"\r\nlocal noTurn = K.replaced(sh, \"Turn Undead\")\r\nif pc.name and noTurn then\r\nout[#out + 1] = string.format(\"Channel Divinity: Divine Spark heals another creature (not \" .. who .. \") %s, written [HEAL|target|Divine Spark|%s|dice|amount] (Lua spends the use)\",\r\nspark, spark)\r\nelseif noTurn then\r\nout[#out + 1] = string.format(\"Channel Divinity (a Magic action; Lua spends one use per effect): Divine Spark at another creature within 30 ft (not \" .. who .. \"),\"\r\n.. \" heal %s: [HEAL|target|Divine Spark|%s|dice|amount], or harm: [HAZARD|Name|Divine Spark (Radiant)|Constitution|d20|+bonus|%d|success/failure|%s|dice|damage]\"\r\n.. \" (or (Necrotic); half on a success)\", spark, spark, dc, spark)\r\nelseif pc.name then\r\nout[#out + 1] = string.format(\"Channel Divinity: Divine Spark heals another creature (not \" .. who .. \") %s, written [HEAL|target|Divine Spark|%s|dice|amount] (Lua spends the use);\"\r\n.. \" Turn Undead: Undead within 30 ft, Wisdom save DC %d or Frightened and Incapacitated%s, written [USE|Channel Divinity]\"\r\n.. \" and for each that fails [COND|Name|+Frightened|1m,dmg|Turn Undead] and [COND|Name|+Incapacitated|1m,dmg|Turn Undead]\",\r\nspark, spark, dc, sh.level >= 5 and (\", and \" .. sear .. \" Radiant to each that fails (Sear Undead, narrated)\") or \"\")\r\nelse\r\nout[#out + 1] = string.format(\"Channel Divinity (a Magic action; Lua spends one use per effect): Divine Spark at another creature within 30 ft (not \" .. who .. \"),\"\r\n.. \" heal %s: [HEAL|target|Divine Spark|%s|dice|amount], or harm: [HAZARD|Name|Divine Spark (Radiant)|Constitution|d20|+bonus|%d|success/failure|%s|dice|damage]\"\r\n.. \" (or (Necrotic); half on a success). Turn Undead: each Undead of %s's choice within 30 ft,\"\r\n.. \" one [HAZARD|Name|Turn Undead|Wisdom|d20|+bonus|%d|success/failure|%s] each (a failure: Frightened and Incapacitated for 1 minute, Lua keeps them; other damage ends it)%s\",\r\nspark, spark, dc, spark, who, dc, sh.level >= 5 and (sear .. \"|dice|damage\") or \"-|-|0\",\r\nsh.level >= 5 and string.format(\"; Sear Undead: one roll of %s Radiant for every Undead that fails (the same dice in each, - - 0 on a success; it does not end the turn)\", sear) or \"\")\r\nend\r\nend\r\nif K.subHas(sh, \"Disciple of Life\") then\r\nout[#out + 1] = \"Life Domain: healing spells cast with a slot restore 2 + the slot level more (in the formula); always prepared: \"\r\n.. table.concat(Feat.always(sh), \", \")\r\nout[#out + 1] = string.format(\"Preserve Life (Channel Divinity, a Magic action): %d HP shared among Bloodied creatures within 30 ft (%s too),\"\r\n.. \" none raised above half its maximum: one [HEAL|target|Preserve Life|N|-|N] each (Lua spends the use with the first)\", 5 * sh.level, who)\r\nend\r\nend\r\nlocal row = CLASSES[sh.class].levels[sh.level] or {}\r\nif sh.class == \"Barbarian\" then\r\nout[#out + 1] = string.format(\"Rage: [USE|Rage] (Bonus Action, not in Heavy armor): while it lasts (Lua ends it with the fight) Resistance to Bludgeoning, Piercing, Slashing\"\r\n.. \" (Lua halves them), +%d damage on Strength attacks (in the formulas), Advantage on Strength checks and saves, no spells\"\r\n.. (K.udClass(sh) == \"Barbarian\" and \". Unarmored Defense: AC 10 + Dex + Con\" or \"\"), row.rage or 2)\r\n\r\nif sh.level >= 2 then out[#out + 1] = \"Reckless Attack: Advantage on \" .. who .. \"'s Strength attacks this turn, and attack rolls against \" .. who\r\n.. \" have Advantage until the start of \" .. who .. \"'s next turn; Danger Sense: Advantage on Dexterity saves\" end\r\nif K.subHas(sh, \"Frenzy\") then out[#out + 1] = string.format(\"Frenzy (Berserker): while raging and attacking recklessly, the first hit each turn adds %dd6 (in the formula)\", row.rage or 2) end\r\nelseif sh.class == \"Bard\" then\r\nout[#out + 1] = string.format(\"Bardic Inspiration (%s): [USE|Bardic Inspiration|Target] gives another the die for an hour; on its next failing d20 it writes the d20 as \\\"bi A,B\\\"\"\r\n.. \" (A the d20, B the next %s from the pool) and the total counts. %s.\", row.bi or \"1d6\", (row.bi or \"1d6\"):sub(2),\r\nK.LITE and \"Each use costs MP\" or (\"Uses: Charisma modifier per Long Rest\" .. (sh.level >= 5 and \" (Short Rest too)\" or \"\")))\r\nif sh.level >= 2 then out[#out + 1] = \"Jack of All Trades: + half the Proficiency Bonus on unproficient skills (in the bonuses)\" end\r\nif sh.level >= 5 and not K.LITE then out[#out + 1] = \"Font of Inspiration: [USE|Font of Inspiration|slot level] spends a spell slot for one Bardic Inspiration back (no action); Bardic Inspiration also comes back on a Short Rest\" end\r\n\r\nif K.subHas(sh, \"Cutting Words\") then\r\nlocal cwd = \"d\" .. (tostring((K.rowOf(sh, \"Bard\") or {}).bi or \"d6\"):match(\"d(%d+)\") or \"6\")\r\nout[#out + 1] = \"Cutting Words (Lore): a Reaction spends a Bardic Inspiration to subtract its die (\" .. cwd .. \"): off a creature's attack roll, its d20 field\"\r\n.. \" \\\"14 cut 3\\\" (the next \" .. cwd .. \"); off its damage, its formula ends with -1\" .. cwd .. \", that die written last (Lua spends the use either way); off a check: narrated\"\r\nend\r\nelseif sh.class == \"Druid\" then\r\nif p.primal then out[#out + 1] = \"Primal Order \" .. Feat.gloss(\"primal\", p.primal) .. (p.primal == \"Warden\" and \": Martial weapons and Medium armor\" or \": one more cantrip, + Wisdom to Arcana and Nature (in the bonuses)\") end\r\nif sh.level >= 2 then\r\n\r\n\r\nlocal wr = K.rowOf(sh, \"Druid\")\r\nout[#out + 1] = string.format(\"Wild Shape: [USE|Wild Shape|Beast] (a Beast of CR %s or lower%s, by its stat block's English name); Lua takes its AC, Speed and attacks,\"\r\n.. \" gives Temporary HP = Druid level, keeps HP; %s; [USE|Wild Shape|end] to return. In it Lua uses the Beast's Strength, Dexterity and\"\r\n.. \" Constitution and its skill and save bonuses where higher (the numbers above follow). It lasts %d hours at most and ends when\"\r\n.. \" Incapacitated (Lua ends it); the forms are Beasts it knows (four at first, the story's)\", wr.forms or row.forms or \"1/4\", wr.fly and \"\" or \" without a Fly Speed\",\r\nsh.level >= 18 and \"spells in that form too, except one whose material has a stated cost or is consumed (Beast Spells)\" or \"no spells in that form\",\r\nmath.max(1, math.floor(sh.level / 2)))\r\n\r\n\r\nlocal wrec = (type(pc) == \"table\" and type(pc.res) == \"table\") and pc or Cond.cur\r\nlocal fo = {}\r\nfor _, fm in ipairs(type(wrec) == \"table\" and type(wrec.wsForms) == \"table\" and wrec.wsForms or {}) do\r\nlocal mm = MONSTERS[fm]\r\nif type(mm) == \"table\" then\r\n\r\nlocal fac = tonumber(mm.ac) or 10\r\nfor _, e in ipairs(Feat.fxOf(sh, \"form_ac\")) do fac = math.max(fac, K.fxNum(e.ac, sh, e.srcLv)) end\r\nlocal list = {}\r\nfor _, x in ipairs(mm.attacks or {}) do list[#list + 1] = { name = x.name, hit = x.hit, dmg = x.dmg, type = x.type, beast = true, weapon = true } end\r\npcall(Feat.fxDice, list)\r\nlocal at = {}\r\nfor _, x in ipairs(list) do at[#at + 1] = string.format(\"%s %+d, %s%s\", x.name or \"?\", tonumber(x.hit) or 0, tostring(x.dmg or \"\"), x.type and (\" \" .. x.type) or \"\") end\r\nfo[#fo + 1] = string.format(\"%s (AC %d; %s)\", fm, fac, table.concat(at, \"; \"))\r\nend\r\nend\r\nif #fo > 0 then out[#out] = out[#out] .. \". Forms taken before, Lua's numbers (use them in the reply it changes): \" .. table.concat(fo, \", \") end\r\nend\r\nif K.subHas(sh, \"Land's Aid\") then\r\nlocal n = (2 + (sh.level >= 10 and 1 or 0) + (sh.level >= 14 and 1 or 0)) .. \"d6\"\r\nout[#out + 1] = \"Land's Aid: [CAST|Land's Aid|0] spends Wild Shape: Constitution saves for \" .. n .. \" Necrotic (SAVE), and one creature heals \" .. n .. \" (HEAL|target|Land's Aid)\"\r\nend\r\nelseif sh.class == \"Monk\" then\r\nout[#out + 1] = string.format(\"Martial Arts (no armor or Shield): Unarmed Strike and Monk weapons use %s and the better of Strength or Dexterity; one Unarmed Strike as a Bonus Action.\"\r\n.. (K.udClass(sh) == \"Monk\" and \" Unarmored Defense: AC 10 + Dex + Wis\" or \"\"), row.martial_arts or \"1d6\")\r\nif sh.level >= 2 and K.LITE then\r\nout[#out + 1] = string.format(\"Focus Points (MP, 1 a point): [USE|Focus Points|1] for Flurry of Blows (two Bonus Action strikes), Patient Defense (paid: Disengage and Dodge), Step of the Wind (paid: Disengage and Dash, jump doubled); unpaid, those two are a Bonus Action Disengage / Dash with no USE; save DC %d.\",\r\n8 + MOD.Wisdom + PROF)\r\nelseif sh.level >= 2 then out[#out + 1] = string.format(\"Focus Points (%d): [USE|Focus Points|1] for Flurry of Blows (two Bonus Action strikes), Patient Defense (paid: Disengage and Dodge), Step of the Wind (paid: Disengage and Dash, jump doubled); unpaid, those two are a Bonus Action Disengage / Dash with no USE; save DC %d.\"\r\n.. \" Uncanny Metabolism once per Long Rest at initiative: [HEAL|%s|Uncanny Metabolism|%s+%d|dice|amount] (refills Focus Points)\",\r\nsh.level, 8 + MOD.Wisdom + PROF, who, row.martial_arts or \"1d6\", sh.level) end\r\n\r\nif sh.level >= 10 and out[#out] then out[#out] = (out[#out]:gsub(\"Flurry of Blows %(two Bonus Action strikes%)\", \"Flurry of Blows (three Bonus Action strikes: Heightened Focus)\")) end\r\nif sh.level >= 3 then out[#out + 1] = string.format(\"Deflect Attacks: a Reaction when hit by Bludgeoning, Piercing or Slashing: [HEAL|%s|Deflect Attacks|1d10%+d|dice|amount] right after the hit;\"\r\n.. \" when it takes the damage to 0, one Focus Point sends a strike back at a creature within 5 ft (60 ft for a ranged attack)\"\r\n.. (pc.name and \" (narrated)\" or (\": [HAZARD|Name|Deflect Attacks (the attack's type)|Dexterity|d20|+bonus|\" .. (8 + MOD.Wisdom + PROF) .. \"|success/failure|\"\r\n.. string.format(\"2%s%+d\", tostring(row.martial_arts or \"1d6\"):match(\"(d%d+)\") or \"d6\", MOD.Dexterity) .. \"|dice|damage] (Lua spends the point)\")), who, MOD.Dexterity + sh.level) end\r\n\r\nif sh.level >= 13 and out[#out] then out[#out] = (out[#out]:gsub(\"when hit by Bludgeoning, Piercing or Slashing\", \"when hit by an attack of any damage type (Deflect Energy)\")) end\r\n\r\nif sh.level >= 5 then\r\nlocal dcS = 8 + MOD.Wisdom + PROF\r\nout[#out + 1] = \"Stunning Strike (once a turn): [USE|Focus Points|1] after a hit, then the target's save \"\r\n.. (pc.name and \"as the story's, and on a failure [COND|Name|+Stunned|turn|Stunning Strike]\" or (\"[HAZARD|Name|Stunning Strike|Constitution|d20|+bonus|\" .. dcS .. \"|success/failure|-|-|0]\"))\r\n.. \" (a failure: Stunned until the start of \" .. who .. \"'s next turn, Lua keeps it); on a success its Speed is halved and the next attack at it before \"\r\n.. who .. \"'s next turn has Advantage\"\r\nend\r\nif K.subHas(sh, \"Open Hand Technique\") then\r\nlocal dcO = 8 + MOD.Wisdom + PROF\r\nout[#out + 1] = \"Open Hand Technique (on a Flurry of Blows hit): Addle (no Opportunity Attacks until its next turn, narrated), Push (\"\r\n.. (pc.name and \"Strength save as the story's\" or (\"[HAZARD|Name|Open Hand Technique (Push)|Strength|d20|+bonus|\" .. dcO .. \"|success/failure|-|-|0]\")) .. \": pushed up to 15 ft), or Topple (\"\r\n.. (pc.name and \"Dexterity save as the story's, a failure [COND|Name|+Prone|-|Open Hand Technique]\" or (\"[HAZARD|Name|Open Hand Technique (Topple)|Dexterity|d20|+bonus|\" .. dcO .. \"|success/failure|-|-|0]: Prone on a failure, Lua keeps it\")) .. \")\"\r\nend\r\nelseif sh.class == \"Paladin\" then\r\nout[#out + 1] = K.LITE and \"Lay On Hands: [HEAL|target|Lay On Hands|N|-|N] heals N HP for 1 MP per 5 HP\"\r\nor \"Lay On Hands: [HEAL|target|Lay On Hands|N|-|N] spends N points of the pool (in the uses)\"\r\nif sh.level >= 2 then out[#out + 1] = \"Divine Smite: cast it right after a melee hit and add its dice to that attack's formula: write [CAST|Divine Smite|slot] first, then the ATTACK with +2d8\"\r\n.. (K.LITE and \"\" or \" (once a Long Rest without a slot)\") end\r\nif K.subHas(sh, \"Sacred Weapon\") then out[#out + 1] = string.format(\"Sacred Weapon: [USE|Sacred Weapon] spends Channel Divinity: +%d to hit with a melee weapon for the fight (Lua adds it)\", math.max(1, MOD.Charisma)) end\r\n\r\nif sh.level >= 3 then out[#out + 1] = \"Divine Sense: a Bonus Action and [USE|Channel Divinity]: for 10 minutes \" .. who .. \" knows where every Celestial, Fiend and Undead within 60 ft is, and any consecrated or desecrated place (narrate)\" end\r\nelseif sh.class == \"Ranger\" then\r\n\r\nout[#out + 1] = \"Hunter's Mark is always prepared\" .. (K.LITE and \"\" or \" and cast free a few times per Long Rest (in the uses)\") .. \": while concentrating, +1d\" .. (sh.level >= 20 and 10 or 6) .. \" Force on every hit\"\r\n.. \" against the marked creature (in the formula; not on other targets)\"\r\nif K.subHas(sh, \"Hunter's Prey\") and type(sh.picks) == \"table\" and sh.picks.prey then\r\nout[#out + 1] = sh.picks.prey == \"Colossus Slayer\" and \"Colossus Slayer: +1d8 once per turn on a weapon hit against a wounded creature (in the formula)\"\r\nor \"Horde Breaker: once per turn, one more attack against a different creature within 5 ft of the first\"\r\nend\r\nelseif sh.class == \"Sorcerer\" then\r\nout[#out + 1] = \"Innate Sorcery: [USE|Innate Sorcery] (Bonus Action): +1 spell save DC (Lua) and Advantage on spell attacks for the fight\"\r\nif sh.level >= 2 then\r\nlocal mm = type(sh.picks) == \"table\" and type(sh.picks.metamagic) == \"table\" and table.concat(sh.picks.metamagic, \", \") or \"not chosen\"\r\nout[#out + 1] = K.LITE and (\"Sorcery Points (MP, 1 a point): Metamagic \" .. mm .. \", spent with [USE|Sorcery Points|N]\")\r\nor string.format(\"Sorcery Points (%d): Metamagic %s, spent with [USE|Sorcery Points|N]; Font of Magic: a slot becomes as many points as its level with\"\r\n.. \" [USE|Spell Slot N|points] (no action), points become a slot with [USE|Sorcery Points|slot N] (a Bonus Action; level 1-5 for 2, 3, 5, 6, 7 points%s)\",\r\nsh.level, mm, sh.level < 9 and string.format(\", up to level %d now\", sh.level >= 7 and 4 or sh.level >= 5 and 3 or sh.level >= 3 and 2 or 1) or \"\")\r\nend\r\nif K.subHas(sh, \"Draconic Resilience\") then out[#out + 1] = \"Draconic Sorcery: AC 10 + Dex + Cha without armor, more HP (Lua)\" end\r\nelseif sh.class == \"Warlock\" then\r\nlocal inv = type(sh.picks) == \"table\" and type(sh.picks.invocations) == \"table\" and table.concat(sh.picks.invocations, \", \") or \"not chosen\"\r\nout[#out + 1] = (K.LITE and \"\" or \"Pact Magic: all slots are of the highest level and come back on a Short Rest. \") .. \"Eldritch Invocations: \" .. inv\r\n.. string.format(\". Eldritch Blast: %d beam%s, each its own ATTACK\", K.cantripTier(K.charLevel(sh)), K.cantripTier(K.charLevel(sh)) > 1 and \"s\" or \"\")\r\n\r\nif Feat.invoked(sh, \"Pact of the Blade\") then out[#out + 1] = \"Pact of the Blade: [USE|Pact of the Blade|Weapon] (a Bonus Action) calls any Simple or Martial melee weapon\"\r\n.. \" or bonds one in hand, [USE|Pact of the Blade|end] dismisses it; Lua lists it with the attacks (Charisma if better, proficiency; no pack item) and deals its type or\"\r\n.. \" Necrotic, Psychic or Radiant, whichever the target fares worst against\" end\r\n\r\nif Feat.invoked(sh, \"Devouring Blade\") then out[#out + 1] = \"Devouring Blade: the Attack action with the pact weapon is three attacks\"\r\nelseif Feat.invoked(sh, \"Thirsting Blade\") then out[#out + 1] = \"Thirsting Blade: the Attack action with the pact weapon is two attacks\" end\r\nif Feat.invoked(sh, \"Lifedrinker\") then out[#out + 1] = \"Lifedrinker: once per turn a pact weapon hit adds 1d6 Necrotic, Psychic or Radiant (in the formula)\"\r\n.. (K.LITE and \"\" or \"; then a Hit Point Die may heal (a HEAL)\") end\r\nif Feat.invoked(sh, \"Eldritch Smite\") then out[#out + 1] = \"Eldritch Smite: once per turn on a pact weapon hit, 1d8 Force plus 1d8 per slot level in that ATTACK's formula\"\r\n.. (K.LITE and \", with [USE|Spell Slot N] (MP by level N)\" or \" (Lua spends the Pact slot: no USE)\") .. \"; a Huge or smaller target falls Prone\" end\r\nif sh.level >= 2 and not K.LITE then out[#out + 1] = \"Magical Cunning: [USE|Magical Cunning] once per Long Rest brings back \" .. (sh.level >= 20 and \"all\" or \"half\") .. \" the slots\" end\r\nif K.subHas(sh, \"Dark One's Blessing\") then out[#out + 1] = \"Dark One's Blessing (Fiend): Lua gives Temporary HP when \" .. who .. \" drops an enemy\" end\r\nend\r\nif sh.class == \"Wizard\" then\r\n\r\nif not K.LITE then out[#out + 1] = \"Arcane Recovery: Lua uses it by itself in a Short Rest ([REST|short]) when slots are spent; write no USE for it\" end\r\nif K.subHas(sh, \"Potent Cantrip\") then out[#out + 1] = \"Potent Cantrip: a damage cantrip that misses or is saved against still deals half; on a miss roll it anyway: [ATTACK|...|miss|formula|dice|half]\" end\r\nend\r\n\r\nlocal sub = K.subOf(sh, sh.class)\r\nlocal srec = sub ~= K.subDefault(sh.class) and K.subRec(sh.class, sub)\r\nif srec and srec.request and sh.level >= K.subLevel(sh.class) then out[#out + 1] = tostring(srec.request) end\r\nend\r\n\r\nfunction Feat.text(sh, pc)\r\nlocal p, out = Feat.picks(sh), {}\r\nlocal who = pc.name or \"Player\"\r\nif p.style and Feat.EFFECT[p.style] then out[#out + 1] = \"Fighting Style \" .. Feat.gloss(\"style\", p.style) .. \": \" .. Feat.styleText(p.style, sh, who) end\r\n\r\n\r\nfor _, c in ipairs(K.classes(sh)) do Feat.classText(K.view(sh, c.name, c.level), pc, who, p, out) end\r\nlocal swings = K.Card.swings(sh)\r\nif swings >= 2 then\r\nlocal n = ({ \"one\", \"two\", \"three\", \"four\" })[swings] or \"two\"\r\nout[#out + 1] = \"Extra Attack: the Attack action is \" .. n .. \" attacks, \" .. n .. \" ATTACK tags\"\r\nend\r\n\r\n\r\nif p.xstyle and Feat.EFFECT[p.xstyle] then out[#out + 1] = \"Fighting Style \" .. Feat.gloss(\"style\", p.xstyle) .. \": \" .. Feat.styleText(p.xstyle, sh, who) end\r\nfor _, x in ipairs(Feat.fxList(sh)) do\r\nlocal narrated = true\r\nfor _, e in ipairs(x.rec.fx) do if e.t ~= \"note\" then narrated = false end end\r\n\r\n\r\nlocal styleLine = (x.name == p.style or x.name == p.xstyle) and Feat.EFFECT[x.name]\r\nif x.rec.text ~= \"\" and not (pc.name and narrated) and not styleLine then out[#out + 1] = Feat.fill(x.rec.text, K.view(sh, x.class or sh.class, x.lv or sh.level), who, x.name) end\r\nend\r\nfor _, e in ipairs(Feat.fxOf(sh, \"summon\")) do out[#out + 1] = K.summonFeatLine(e, sh, pc) end\r\nlocal feats = Feat.list(sh)\r\nfor _, f in ipairs(feats) do\r\n\r\nif f == \"Alert\" then\r\n\r\nelseif f == \"Savage Attacker\" and pc.name then out[#out + 1] = \"Savage Attacker (once per reply: the weapon's damage dice rolled twice, the sets apart with \\\"/\\\": \\\"a,b / c,d\\\" for 2d6, \\\"a / b\\\" for 1d8; the higher counts)\"\r\nelseif f == \"Savage Attacker\" then out[#out + 1] = \"Savage Attacker: once per reply, on a weapon hit, take the weapon's damage dice twice from the pool and write both sets in the dice field apart with \\\"/\\\" (\\\"a,b / c,d\\\" for 2d6, \\\"a / b\\\" for a one-die weapon such as 1d8); the higher set counts\"\r\nelseif f == \"Grappler\" then out[#out + 1] = \"Grappler: Unarmed Strike can damage and grapple at once; Advantage on attacks against a creature \" .. who .. \" grapples\"\r\nelseif f == \"Magic Initiate\" and not (type(sh.mi) == \"table\" and sh.mi.spell) and not pc.name then\r\nout[#out + 1] = string.format(\"Magic Initiate (%s list): spells not chosen yet; when the user wants (OOC), write [INITIATE|two cantrips, comma-separated|one level 1 spell] from the %s list\",\r\nFeat.miList(sh) or \"Cleric, Druid or Wizard\", Feat.miList(sh) or \"chosen\")\r\nend\r\nend\r\nlocal sp = sh.species\r\nif sp == \"Dragonborn\" and p.dragon then out[#out + 1] = \"Draconic Ancestry \" .. p.dragon .. \": Resistance to \" .. p.dragon .. \" (Lua halves it); Breath Weapon is cast with CAST (in the spells)\" end\r\nif sp == \"Dwarf\" then out[#out + 1] = \"Dwarf: Resistance to Poison (Lua halves it), Advantage on saves against Poisoned, Darkvision 120 ft\" end\r\nif sp == \"Elf\" then out[#out + 1] = \"Elf\" .. (p.lineage and (\" (\" .. p.lineage .. \")\") or \"\") .. \": Darkvision, Advantage on saves against Charmed\"\r\n.. (K.LITE and \"\" or \", no sleep (Trance)\") end\r\nif sp == \"Beastfolk\" then\r\nlocal b = { Dog = \"Dog: Advantage on Survival checks to track by scent, and on saves against Frightened while an ally is within 5 ft\",\r\nCat = \"Cat: a Climb Speed equal to the Speed; falling damage is reduced by 5 x level (write the reduced damage)\",\r\nFox = \"Fox: Minor Illusion (in the spells) and Deception proficiency (in the bonuses)\",\r\nBear = \"Bear: carries as one size larger, Advantage on checks to end Grappled, +1 HP per level (in the HP)\" }\r\nout[#out + 1] = \"Beastfolk: Darkvision 60 ft, Perception proficiency (in the bonuses), claws and fangs in the Unarmed Strike (1d6)\"\r\n.. (p.beast and (\"; \" .. b[p.beast]) or \"\")\r\nend\r\nif sp == \"Gnome\" then out[#out + 1] = \"Gnome: Advantage on Intelligence, Wisdom and Charisma saves\" end\r\nif K.PACK.sp[sp or \"\"] then\r\nlocal r = SPECIES[sp]\r\nout[#out + 1] = string.format(\"%s: %s%s\", sp, r.size or \"Medium\", (tonumber(r.darkvision) or 0) > 0 and (\", Darkvision \" .. r.darkvision .. \" ft\") or \"\")\r\nend\r\nif sp == \"Goliath\" and p.giant then\r\nlocal g = { Cloud = \"Cloud's Jaunt: Bonus Action teleport 30 ft\", Fire = \"Fire's Burn: on a hit add 1d10 Fire to the formula (Lua spends the use)\",\r\nFrost = \"Frost's Chill: on a hit add 1d6 Cold to the formula and Speed -10 ft (Lua spends the use)\", Hill = \"Hill's Tumble: on a hit knock a Large or smaller target Prone\",\r\nStone = \"Stone's Endurance: Reaction when hit, written [HEAL|\" .. who .. \"|Stone's Endurance|1d12\" .. string.format(\"%+d\", MOD.Constitution) .. \"|dice|amount]\",\r\nStorm = \"Storm's Thunder: Reaction when hit, cast with CAST then DAMAGE (in the spells)\" }\r\nout[#out + 1] = \"Giant Ancestry \" .. p.giant .. \" (uses in the uses list): \" .. g[p.giant] .. ((p.giant == \"Cloud\" or p.giant == \"Hill\") and \"; write [USE|Giant Ancestry]\" or \"\")\r\nend\r\nif sp == \"Halfling\" then out[#out + 1] = \"Halfling Luck: a natural 1 on a d20 is rerolled: write the d20 as \\\"luck 1,N\\\" with the next pool die; Advantage on saves against Frightened\" end\r\nif sp == \"Human\" then\r\nout[#out + 1] = pc.name and \"Heroic Inspiration: one d20 reroll (\\\"insp A,B\\\")\"\r\n\r\nor \"Heroic Inspiration (uses list): when the user wants it, reroll a d20: write \\\"insp A,B\\\" as the d20 of that one tag (A the first die,\"\r\n.. \" B the next pool die; e.g. [DEATH|insp 5,20|success]); Lua spends it. Never a second tag for the reroll, never USE\"\r\nend\r\nif sp == \"Orc\" then out[#out + 1] = \"Orc: Adrenaline Rush [USE|Adrenaline Rush] = Dash as a Bonus Action and Temporary HP equal to the Proficiency Bonus (Lua); Relentless Endurance: Lua leaves 1 HP once per Long Rest\" end\r\nif sp == \"Tiefling\" and p.legacy then out[#out + 1] = \"Fiendish Legacy \" .. p.legacy .. \": Resistance to \" .. Feat.LEGACY[p.legacy] .. \" (Lua halves it); its spells are in the spells\" end\r\nlocal mastered = type(p.mastery) == \"table\" and p.mastery or {}\r\nif #mastered > 0 then\r\nlocal m = {}\r\nfor _, w in ipairs(mastered) do m[#m + 1] = w .. \" \" .. WEAPONS[w].mastery end\r\nout[#out + 1] = \"Weapon Mastery: \" .. table.concat(m, \", \") .. \" (effects in the attack list during a fight)\"\r\nend\r\nif #out == 0 then return nil end\r\nlocal s = who .. \"'s features: \" .. table.concat(out, \". \") .. \".\"\r\nif pc.name then s = K.allyTags(s, pc.name) end\r\nreturn s\r\nend\r\n\r\n\r\n\r\nfunction K.allyTags(s, name)\r\ns = s:gsub(\"%[USE|([^%]|]*)\", function(x)\r\nif x:find(\"/\", 1, true) or x == \"Name\" or x == \"name\" then return nil end\r\nreturn \"[USE|\" .. name .. \"/\" .. x\r\nend)\r\nreturn (s:gsub(\"%[CAST|([^%]|]*)|([^%]|]*)%]\", function(sp, lv) return \"[CAST|\" .. sp .. \"|\" .. lv .. \"|\" .. name .. \"]\" end))\r\nend\r\n\r\n\r\nfunction Feat.initiate(f, c, sh)\r\nlocal head = \"[INITIATE|\" .. (f[1] or \"\") .. \"|\" .. (f[2] or \"\")\r\nlocal list = Feat.miList(sh)\r\nif not Feat.has(sh, \"Magic Initiate\") then return head .. \"|bad:no Magic Initiate feat|-]\", false end\r\nif not list then return head .. \"|bad:pick the spell list on the character tab first|-]\", false end\r\nif c.active then return head .. \"|bad:not during a fight|-]\", false end\r\nlocal cans, spell, bad = splitNames(f[1]), Canon.name(f[2] or \"\"), {}\r\nlocal function inList(n, lv)\r\nlocal sp = SPELLS[n]\r\nif not sp then bad[#bad + 1] = \"unknown \" .. n; return end\r\n\r\nlocal mi = type(sh.mi) == \"table\" and sh.mi or {}\r\nlocal hadMi = mi.spell == n\r\nfor _, x in ipairs(mi.cantrips or {}) do if x == n then hadMi = true end end\r\nif not hadMi and K.spellOff(n) then bad[#bad + 1] = K.spellOff(n); return end\r\nlocal mine = false\r\nfor _, k in ipairs(sp.classes) do if k == list then mine = true end end\r\nif not mine then bad[#bad + 1] = n .. \" not on the \" .. list .. \" list\" end\r\nif sp.level ~= lv then bad[#bad + 1] = n .. (lv == 0 and \" is not a cantrip\" or \" is not level 1\") end\r\nend\r\nfor i, n in ipairs(cans) do cans[i] = Canon.name(n); inList(cans[i], 0) end\r\nif #cans ~= 2 or cans[1] == cans[2] then bad[#bad + 1] = \"two different cantrips\" end\r\ninList(spell, 1)\r\nif #bad > 0 then return head .. \"|bad:\" .. table.concat(bad, \";\") .. \"|-]\", false end\r\nsh.mi = { list = list, cantrips = cans, spell = spell }\r\nreturn head .. \"|ok|\" .. list .. \"]\", true\r\nend\r\n\r\n\r\nFeat.INVOCATIONS = {\r\n{ \"Agonizing Blast\", 2 }, { \"Armor of Shadows\", 1 }, { \"Devil's Sight\", 2 }, { \"Eldritch Mind\", 1 }, { \"Fiendish Vigor\", 2 },\r\n{ \"Mask of Many Faces\", 2 }, { \"Misty Visions\", 2 }, { \"Pact of the Blade\", 1 }, { \"Pact of the Chain\", 1 }, { \"Pact of the Tome\", 1 },\r\n{ \"Repelling Blast\", 2 }, { \"Thirsting Blade\", 5, \"Pact of the Blade\" }, { \"One with Shadows\", 5 }, { \"Master of Myriad Forms\", 5 },\r\n{ \"Ascendant Step\", 5 }, { \"Gift of the Depths\", 5 },\r\n\r\n{ \"Eldritch Spear\", 2 }, { \"Otherworldly Leap\", 2 }, { \"Gaze of Two Minds\", 5 }, { \"Eldritch Smite\", 5, \"Pact of the Blade\" },\r\n{ \"Investment of the Chain Master\", 5, \"Pact of the Chain\" }, { \"Whispers of the Grave\", 7 }, { \"Lifedrinker\", 9, \"Pact of the Blade\" },\r\n{ \"Visions of Distant Realms\", 9 }, { \"Gift of the Protectors\", 9, \"Pact of the Tome\" }, { \"Devouring Blade\", 12, \"Thirsting Blade\" },\r\n{ \"Witch Sight\", 15 },\r\n}\r\nFeat.METAMAGIC = { \"Careful Spell\", \"Distant Spell\", \"Empowered Spell\", \"Extended Spell\", \"Heightened Spell\", \"Quickened Spell\", \"Seeking Spell\",\r\n\"Subtle Spell\", \"Transmuted Spell\", \"Twinned Spell\" }\r\nFeat.LAND = {\r\nArid = { \"Blur\", \"Burning Hands\", \"Fire Bolt\", \"Fireball\", \"Blight\", \"Wall of Stone\" },\r\nPolar = { \"Fog Cloud\", \"Hold Person\", \"Ray of Frost\", \"Sleet Storm\", \"Ice Storm\", \"Cone of Cold\" },\r\nTemperate = { \"Misty Step\", \"Shocking Grasp\", \"Sleep\", \"Lightning Bolt\", \"Freedom of Movement\", \"Tree Stride\" },\r\nTropical = { \"Acid Splash\", \"Ray of Sickness\", \"Web\", \"Stinking Cloud\", \"Polymorph\", \"Insect Plague\" },\r\n}\r\nFeat.LAND_AT = { 3, 3, 3, 5, 7, 9 }\r\n\r\nfunction Feat.invoked(sh, name)\r\nfor _, n in ipairs(type(sh.picks) == \"table\" and type(sh.picks.invocations) == \"table\" and sh.picks.invocations or {}) do\r\nif n == name then return true end\r\nend\r\nreturn false\r\nend\r\n\r\n\r\nfunction Feat.inspire(f, rec, root, c)\r\nlocal head = \"[USE|Bardic Inspiration|\" .. (f[2] or \"\")\r\nlocal sh = rec.sheet or SHEET\r\nlocal row = K.rowOf(sh, \"Bard\")\r\nif not row.bi then return head .. \"|bad:not a Bard|-]\", false end\r\nif (type(rec.res) == \"table\" and rec.res[\"Bardic Inspiration\"] or 0) < 1 then return head .. \"|bad:no uses left|-]\", false end\r\nlocal t = Ally.rec(root, Canon.actor(f[2] or \"\"))\r\nif not t or t == rec then return head .. \"|bad:give it to another: Player or a companion|-]\", false end\r\nrec.res[\"Bardic Inspiration\"] = rec.res[\"Bardic Inspiration\"] - 1\r\nt.bi = row.bi\r\nt.biEnds = (K.clockRef and tonumber(K.clockRef.min) or 0) + 60\r\nif c.active then c.last = rec.name or \"Player\" end\r\nreturn head .. \"|ok|\" .. row.bi .. \"]\", true\r\nend\r\n\r\n\r\nfunction Feat.restoration(r)\r\nif K.cl(SHEET, \"Sorcerer\") < 1 or not PC.res[\"Sorcerous Restoration\"] or (r.res[\"Sorcerous Restoration\"] or 0) < 1 then return \"\" end\r\nlocal maxp = PC.res[\"Sorcery Points\"] and PC.res[\"Sorcery Points\"].max or 0\r\nlocal got = math.min(math.floor(K.cl(SHEET, \"Sorcerer\") / 2), maxp - (r.res[\"Sorcery Points\"] or 0))\r\nif got <= 0 then return \"\" end\r\nr.res[\"Sorcery Points\"] = (r.res[\"Sorcery Points\"] or 0) + got\r\nr.res[\"Sorcerous Restoration\"] = r.res[\"Sorcerous Restoration\"] - 1\r\nreturn \", Sorcerous Restoration: +\" .. got .. \" Sorcery Points\"\r\nend\r\n\r\n\r\n\r\n\r\nfunction K.fxNum(v, sh, lv)\r\nif v == nil then return 0 end\r\nif tonumber(v) then return tonumber(v) end\r\nlocal total = 0\r\nfor term in tostring(v):gmatch(\"[^+]+\") do\r\nterm = term:gsub(\"%s\", \"\")\r\nlocal ab, one = term:match(\"^(%u%u%u)(1?)$\")\r\nlocal ab1, ab2 = term:match(\"^(%u%u%u)|(%u%u%u)$\")\r\nlocal k, what = term:match(\"^(%d+)%*?(%u+)$\")\r\nlocal hw, hd = term:match(\"^(%u+)/(%d+)$\")\r\nif hw then total = total + math.floor(K.fxNum(hw, sh, lv) / tonumber(hd))\r\nelseif k and not tonumber(term) then total = total + tonumber(k) * K.fxNum(what, sh, lv)\r\nelseif tonumber(term) then total = total + tonumber(term)\r\nelseif term == \"LEVEL\" then total = total + (tonumber(lv) or tonumber(sh.level) or 1)\r\nelseif term == \"PB\" then total = total + 2 + math.floor((K.charLevel(sh) - 1) / 4)\r\nelseif term == \"RAGE\" then total = total + (tonumber(K.rowOf(sh, \"Barbarian\").rage) or 0)\r\nelseif term == \"PACT\" then\r\nlocal pcl = K.pactClass(sh)\r\ntotal = total + (pcl and #((K.rowOf(sh, pcl.name) or {}).slots or {}) or 0)\r\nelseif ab and ABBR[ab] then\r\nlocal m = abilityMod(K.score(sh, ABBR[ab]))\r\ntotal = total + (one == \"1\" and math.max(1, m) or m)\r\nelseif ab1 and ABBR[ab1] and ABBR[ab2] then\r\ntotal = total + math.max(abilityMod(K.score(sh, ABBR[ab1])), abilityMod(K.score(sh, ABBR[ab2])))\r\nend\r\nend\r\nreturn total\r\nend\r\n\r\nfunction K.fxRoll(v, sh, lv)\r\nif type(v) ~= \"string\" or not v:find(\"%dd%d\") then return K.fxNum(v, sh, lv) end\r\nlocal rolled = v:gsub(\"(%d*)d(%d+)\", function(n, m)\r\nlocal t = 0\r\nfor _ = 1, tonumber(n) or 1 do t = t + K.d(tonumber(m)) end\r\nreturn tostring(t)\r\nend)\r\nreturn K.fxNum(rolled, sh, lv)\r\nend\r\n\r\nfunction K.modeFx(r, sh)\r\nlocal mode = type(r) == \"table\" and type(r.mode) == \"table\" and r.mode.name\r\nlocal out = {}\r\nif not mode or not Feat.fxOf or type(sh) ~= \"table\" then return out end\r\nfor _, e in ipairs(Feat.fxOf(sh, \"mode\")) do if e.use == mode then out[#out + 1] = e end end\r\nreturn out\r\nend\r\n\r\n\r\nfunction K.modeFits(e, a)\r\nlocal sc = e.scope or \"weapon\"\r\nif a.spell then return false end\r\nif sc == \"all\" then return true end\r\nif (sc == \"weapon\" or sc == \"melee\" or sc == \"ranged\") and tostring(a.name or \"\"):find(\"^Unarmed Strike\") then return false end\r\nif sc == \"weapon\" then return a.weapon and true or false end\r\nif sc == \"melee\" then return (a.melee and a.weapon) and true or false end\r\nif sc == \"ranged\" then return (a.weapon and not a.melee) and true or false end\r\nif sc == \"str\" then return a.str and true or false end\r\nreturn false\r\nend\r\n\r\n\r\nfunction Feat.blessing(rec)\r\nlocal sh = rec and (rec.sheet or SHEET)\r\nlocal note = \"\"\r\nif K.subHas(sh, \"Dark One's Blessing\") then\r\nlocal n = math.max(1, abilityMod(K.score(sh, \"Charisma\")) + K.cl(sh, \"Warlock\"))\r\nrec.thp = math.max(tonumber(rec.thp) or 0, n)\r\nnote = \" (Dark One's Blessing +\" .. n .. \" temporary HP)\"\r\nend\r\nfor _, e in ipairs(type(sh) == \"table\" and sh.class and Feat.fxOf(sh, \"on_kill\") or {}) do\r\nlocal n = math.max(tonumber(e.min) or 1, K.fxNum(e.thp, sh, e.srcLv))\r\nrec.thp = math.max(tonumber(rec.thp) or 0, n)\r\nnote = note .. \" (\" .. e.src .. \" +\" .. n .. \" temporary HP)\"\r\nend\r\nreturn note\r\nend\r\n\r\n\r\nfunction Feat.now(r)\r\nlocal out = {}\r\nlocal mode = type(r.mode) == \"table\" and r.mode.name\r\n\r\nlocal dsh = r.sheet or SHEET\r\nif dsh and (tonumber(r.hp) or 1) <= 0 and not r.dead and #Feat.fxOf(dsh, \"death_adv\") > 0 then out[#out + 1] = \"Advantage on death saving throws (write adv A,B)\" end\r\nif mode == \"Rage\" then out[#out + 1] = \"RAGING (Resistance to Bludgeoning, Piercing, Slashing; Rage damage in the formulas; no spells)\"\r\nelseif mode == \"Innate Sorcery\" then out[#out + 1] = \"Innate Sorcery (spell save DC +1, Advantage on spell attacks)\"\r\nelseif mode == \"Sacred Weapon\" then out[#out + 1] = \"Sacred Weapon (Charisma to melee weapon hits, in the attack list)\" end\r\n\r\nfor _, e in ipairs(K.modeFx(r, r.sheet or SHEET)) do\r\nout[#out + 1] = mode .. \" (on until the fight ends\" .. (e.on and (\"; \" .. e.on) or \"\") .. ((e.hit or e.dmg or e.ac or e.resist) and \"; Lua adds its numbers\" or \"\")\r\n.. (e.no_spells and \"; no spells\" or \"\") .. \")\"\r\nend\r\nif r.form then\r\n\r\nlocal fsh = r.sheet or SHEET\r\nlocal can = type(fsh) == \"table\" and ((K.cl(fsh, \"Druid\") >= 18 and \"spells as Beast Spells allows, none with a costly or consumed Material\")\r\nor (#Feat.fxOf(fsh, \"form_cast\") > 0 and \"only the spells its features allow in a form\")) or nil\r\nif type(r.formBy) == \"table\" then can = nil end\r\nout[#out + 1] = (type(r.formBy) == \"table\" and r.formBy.spell or \"Wild Shape\") .. \": \" .. r.form .. \" (its attacks in the attack list; \" .. (can or \"no spells\") .. \")\"\r\nend\r\nif type(r.lasting) == \"table\" then\r\nfor name in pairs(r.lasting) do if type(name) == \"string\" then out[#out + 1] = name end end\r\nend\r\nif r.bi then out[#out + 1] = \"holds a Bardic Inspiration die (\" .. r.bi .. \"): on a failed d20 write \\\"bi A,B\\\"\" .. (tonumber(r.biEnds) and (\", until \" .. clockEn(r.biEnds)) or \"\") end\r\nif #out == 0 then return nil end\r\ntable.sort(out)\r\nreturn \"Active now: \" .. table.concat(out, \"; \")\r\nend\r\n\r\n\r\nfunction Feat.styleText(v, sh, who)\r\nlocal t = Feat.EFFECT[v]\r\nif type(t) == \"string\" and t:find(\"{\", 1, true) and type(sh) == \"table\" then t = Feat.fill(t, sh, who or \"Player\", v) end\r\nreturn t\r\nend\r\n\r\n\r\nFeat.WAIT_NAME = { style = \"Fighting Style\", order = \"Divine Order\", primal = \"Primal Order\", land = \"Circle of the Land land\", prey = \"Hunter's Prey\",\r\ndragon = \"Draconic Ancestry\", lineage = \"Elven Lineage\", gnome = \"Gnomish Lineage\", giant = \"Giant Ancestry\", legacy = \"Fiendish Legacy\",\r\nkeen = \"Keen Senses skill\", feat = \"Versatile origin feat\", milist = \"Magic Initiate list\", skilled = \"Skilled skills\",\r\nskillful = \"Skillful skill (a Human by Reincarnate)\",\r\nmastery = \"Weapon Mastery\", spellab = \"species spellcasting ability\", xskill = \"extra skill proficiency\", mcskill = \"multiclass skill proficiency\",\r\nmetamagic = \"Metamagic\", invocations = \"Eldritch Invocations\", blessed = \"Blessed Strikes\", fury = \"Elemental Fury\",\r\naffinity = \"Elemental Affinity damage type\", resilience = \"Fiendish Resilience damage type\", xstyle = \"Additional Fighting Style\",\r\nboon = \"Epic Boon\", boonab = \"Epic Boon ability +1\", beast = \"Beast Lineage\", mastone = \"Spell Mastery level 1 spell\",\r\nmasttwo = \"Spell Mastery level 2 spell\", sig = \"Signature Spells\", size = \"Size\", lustbrand = \"Brand (a feature gives it)\", heatday = \"Days to the next heat\" }\r\nsetmetatable(Feat.WAIT_NAME, { __index = function(_, k)\r\nlocal cl = K.subClassOf(k)\r\nreturn cl and (cl .. \" subclass\") or nil\r\nend })\r\nfunction Feat.waiting(sh, pc, full)\r\nlocal rows = Feat.pending(sh, pc)\r\nlocal over = K.histOver(sh)\r\nif #rows == 0 and #over == 0 then return nil end\r\nlocal parts = {}\r\nlocal arNames = {}\r\nfor _, row in ipairs(rows) do\r\n\r\nif not full and ({ sexhist = true, inhib = true, imptools = true, fetish = true, fetishon = true })[row.key] then\r\narNames[#arNames + 1] = Feat.WAIT_NAME[row.key] or row.key\r\nelse\r\nlocal o = {}\r\nlocal last = row.key == \"mastery\" and row.owned or #row.opts\r\nfor i = 1, math.min(last, full and 40 or 12) do\r\nlocal v = row.opts[i]\r\nlocal ko = row.key == \"mastery\" and (NAMES_KO[v] or v) or Feat.label(row.key, v)\r\nlocal t = v .. (ko ~= v and (\" \" .. ko) or \"\")\r\nif (row.key == \"style\" or row.key == \"xstyle\") and Feat.EFFECT[v] then t = t .. \": \" .. Feat.styleText(v, sh, pc and pc.name):gsub(\" %(.-%)\", \"\") end\r\nif row.key == \"mastery\" then\r\nlocal m = WEAPONS[v].mastery\r\nt = t .. \" (\" .. m .. \" \" .. (Feat.KO.mastery[m] or m) .. \")\"\r\nend\r\no[#o + 1] = t\r\nend\r\nif row.key == \"mastery\" then o[#o + 1] = \"or any other weapon \" .. \"Player is proficient with (\\\"다른 무기 보기\\\")\" end\r\nif last > (full and 40 or 12) and row.key ~= \"mastery\" then o[#o + 1] = \"…\" end\r\nparts[#parts + 1] = string.format(\"%s%s: %s\", Feat.WAIT_NAME[row.key] or row.key, row.need > 1 and (\" (\" .. row.need .. \")\") or \"\", table.concat(o, \"; \"))\r\nend\r\nend\r\nfor _, row in ipairs(over) do arNames[#arNames + 1] = string.format(\"%s: %d to drop\", Feat.WAIT_NAME[row.key] or row.key, row.need) end\r\nif #arNames > 0 then parts[#parts + 1] = table.concat(arNames, \", \") .. \" (the module's picks; their options are on the tab)\" end\r\nreturn \"Choices waiting on the character tab (the user clicks them there; when asked, explain only these options, no others): \"\r\n.. table.concat(parts, \" | \") .. \".\" .. K.undoText(pc)\r\nend\r\n\r\nfunction K.undoText(pc)\r\nif not (type(pc) == \"table\" and pc.making) then return \"\" end\r\nreturn \" Until the first fight a pick already made can be taken back with its 다시 고르기 button on the character tab (under 고른 것), what hung on it too,\"\r\n.. \" or the whole sheet cleared with 시트 초기화 there to make the character anew (decisions-1.md 548); after that they stay.\"\r\nend\r\n\r\n\r\nfunction Feat.masteryText(a)\r\nlocal e = a.mastery and Feat.EFFECT[a.mastery]\r\nif not e then return \"\" end\r\nif a.mastery == \"Topple\" then e = string.format(e, 8 + (a.mod or 0) + PROF) end\r\nreturn \" (mastery \" .. a.mastery .. \": \" .. e .. \")\"\r\nend\r\n\r\n\r\nfunction Feat.deathRule(id)\r\nlocal v = getChatVar(id, \"dnd_death\")\r\nif v == \"gentle\" or v == \"harsh\" then return v end\r\nreturn \"srd\"\r\nend\r\n\r\n\r\nfunction Feat.always(sh)\r\nlocal out = {}\r\n\r\nlocal dl = K.cl(sh, \"Druid\")\r\nlocal land = dl > 0 and K.subHas(sh, \"Circle of the Land Spells\") and type(sh.picks) == \"table\" and Feat.LAND[sh.picks.land or \"\"]\r\nif land then\r\nfor i, n in ipairs(land) do if dl >= Feat.LAND_AT[i] then out[#out + 1] = n end end\r\nend\r\nlocal goneA = K.ownedGone(sh).always\r\nfor _, c in ipairs(K.classes(sh)) do\r\nlocal srec = K.subRec(c.name, K.subOf(sh, c.name)) or {}\r\nfor lv = 1, c.level do\r\n\r\n\r\nfor _, list in ipairs({ (type(srec.always) == \"table\" and srec.always or {})[tostring(lv)] or {},\r\n((CLASSES[c.name] or {}).always or {})[tostring(lv)] or {} }) do\r\nfor _, n in ipairs(list) do\r\nif type(n) == \"table\" then\r\nlocal pick\r\nfor _, x in ipairs(n) do if not pick and SPELLS[x] and not K.spellOff(x) then pick = x end end\r\nn = pick\r\nend\r\nif type(n) == \"string\" and SPELLS[n] and not goneA[n] then out[#out + 1] = n end\r\nend\r\nend\r\nend\r\nend\r\n\r\nfor _, e in ipairs(Feat.fxOf(sh, \"always_prepared\")) do\r\nfor _, n in ipairs(type(e.spells) == \"table\" and e.spells or {}) do if SPELLS[n] and not K.spellOff(n) then out[#out + 1] = n end end\r\nend\r\n\r\nlocal pk = type(sh.picks) == \"table\" and sh.picks or {}\r\nfor _, e in ipairs(Feat.fxOf(sh, \"spell_pick\")) do\r\nif e.always and type(pk[e.key]) == \"table\" then for _, n in ipairs(pk[e.key]) do out[#out + 1] = n end end\r\nend\r\nreturn out\r\nend\r\n\r\n\r\nfunction Feat.res(sh, res)\r\nlocal p, pb = Feat.picks(sh), 2 + math.floor((K.charLevel(sh) - 1) / 4)\r\nif sh.species == \"Dragonborn\" and p.dragon then res[\"Breath Weapon\"] = { max = pb, short = 0 } end\r\nif sh.species == \"Goliath\" and p.giant then res[\"Giant Ancestry\"] = { max = pb, short = 0 } end\r\nif sh.species == \"Human\" then res[\"Heroic Inspiration\"] = { max = 1, short = 0 } end\r\nif sh.species == \"Orc\" then\r\nres[\"Adrenaline Rush\"] = { max = pb, short = pb }\r\nres[\"Relentless Endurance\"] = { max = 1, short = 0 }\r\nend\r\nfor name, x in pairs(Feat.extras(sh)) do\r\nif x.free and not res[x.free] and x.src ~= \"feature\" then\r\nres[x.free] = { max = (x.free == \"Speak with Animals (free)\") and pb or 1, short = 0 }\r\nend\r\nend\r\n\r\nfor _, e in ipairs(Feat.fxOf(sh, \"resource\")) do\r\nif not res[e.name] then\r\nlocal max = e.max\r\n\r\nlocal at = -1\r\nfor k, v in pairs(type(e.max_at) == \"table\" and e.max_at or {}) do\r\nif tonumber(k) and tonumber(k) <= (tonumber(e.srcLv) or tonumber(sh.level) or 1) and tonumber(k) > at then at, max = tonumber(k), v end\r\nend\r\nif ABBR[max] then max = math.max(1, abilityMod(K.score(sh, ABBR[max]))) elseif max == \"L\" then max = e.srcLv or sh.level\r\nelseif max == \"PB\" then max = pb\r\nelseif type(max) == \"string\" then max = math.max(1, K.fxNum(max, sh, e.srcLv)) end\r\nmax = tonumber(max) or 1\r\nres[e.name] = { max = max, short = e.short == \"all\" and max or (tonumber(e.short) or 0) }\r\nend\r\nend\r\n\r\nfor _, e in ipairs(Feat.fxOf(sh, \"res_per_afflict\")) do\r\nlocal r = res[e.res or \"\"]\r\nif r then\r\nlocal n = 0\r\nfor _, x in ipairs(K.afflictOn(sh)) do for _, k in ipairs(type(e.kinds) == \"table\" and e.kinds or { \"curse\", \"brand\" }) do if x.rec.kind == k then n = n + 1 end end end\r\nif n > 0 then res[e.res] = { max = r.max + n, short = r.short } end\r\nend\r\nend\r\n\r\nif not res[\"Heroic Inspiration\"] and #Feat.fxOf(sh, \"insp_each_turn\") > 0 then res[\"Heroic Inspiration\"] = { max = 1, short = 0 } end\r\nend\r\n\r\n\r\nfunction Feat.masteryN(sh)\r\n\r\nlocal n = 0\r\nfor _, c in ipairs(K.classes(sh)) do n = math.max(n, c.row.mastery or 0) end\r\n\r\nfor _, e in ipairs(Feat.fxOf and Feat.fxOf(sh, \"mastery_add\") or {}) do n = n + (K.fxNum(e.n or 1, sh, e.srcLv) or 1) end\r\nreturn n\r\nend\r\n\r\n\r\nfunction Feat.hasStyle(sh)\r\nfor _, c in ipairs(K.classes(sh)) do\r\nlocal at = CLASSES[c.name].style_at\r\nif at ~= nil and c.level >= at then return true end\r\nend\r\nreturn false\r\nend\r\n\r\n\r\nfunction Feat.styled(sh, name)\r\nlocal p = type(sh) == \"table\" and type(sh.picks) == \"table\" and sh.picks or {}\r\nreturn p.style == name or p.xstyle == name\r\nend\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\nfunction Feat.levelFeaturesBy(sh, intro)\r\nlocal out, none = {}, {}\r\nlocal cls = K.classes(sh)\r\nfor _, c in ipairs(cls) do\r\nlocal cl = CLASSES[c.name or \"\"]\r\nif cl then\r\nlocal rec, at = K.subRec(c.name, K.subOf(sh, c.name)), K.subLevel(c.name)\r\nlocal lvs = rec and type(rec.levels) == \"table\" and rec.levels or none\r\nfor lv = 1, math.min(c.level, #cl.levels) do\r\nlocal row = cl.levels[lv] or {}\r\nlocal subs = (lv ~= at or intro) and lvs[tostring(lv)] or none\r\nlocal put = false\r\nfor _, x in ipairs(row.features or {}) do\r\nif x == \"Subclass feature\" then\r\nput = true\r\nfor _, n in ipairs(subs) do out[#out + 1] = { name = n, class = c.name, level = c.level } end\r\nelse\r\nout[#out + 1] = { name = x, class = c.name, level = c.level }\r\nend\r\nend\r\nif not put then for _, n in ipairs(subs) do out[#out + 1] = { name = n, class = c.name, level = c.level } end end\r\nend\r\nend\r\nend\r\n\r\nlocal gone = K.replacedIn(sh, out, cls)\r\nif next(gone) then\r\nlocal kept = {}\r\nfor _, x in ipairs(out) do\r\nlocal g = gone[x.name]\r\nif not (g and (g[x.class or \"*\"] or g[\"*\"])) then kept[#kept + 1] = x end\r\nend\r\nout = kept\r\nend\r\nreturn out\r\nend\r\nfunction Feat.levelFeatures(sh)\r\nlocal out = {}\r\nfor _, x in ipairs(Feat.levelFeaturesBy(sh)) do out[#out + 1] = x.name end\r\nreturn out\r\nend\r\n\r\n\r\nfunction Feat.fxList(sh)\r\n\r\n\r\nlocal memo = K.fxMemo and K.fxMemo[sh]\r\nif memo then return memo end\r\nlocal out = Feat.fxList0(sh)\r\nif K.fxMemo and type(sh) == \"table\" then K.fxMemo[sh] = out end\r\nreturn out\r\nend\r\nfunction Feat.fxList0(sh)\r\nlocal out, seen = {}, {}\r\nlocal p = type(sh.picks) == \"table\" and sh.picks or {}\r\n\r\nlocal function add(name, cls, lv)\r\nlocal key = name:gsub(\" %(.-%)$\", \"\")\r\nlocal rec = K.FX[key]\r\nif not rec or seen[key] then return end\r\nseen[key] = true\r\nout[#out + 1] = { name = key, rec = rec, class = cls, lv = lv }\r\nfor _, e in ipairs(rec.fx) do\r\nif e.t == \"choice\" and (type(p[e.key]) == \"string\" or type(p[e.key]) == \"table\") then\r\nfor _, o in ipairs(e.options or {}) do if K.pickHas(p[e.key], o) then add(o, cls, lv) end end\r\nend\r\nend\r\n\r\nfor _, w in ipairs(type(rec.with) == \"table\" and rec.with or {}) do\r\nif type(K.FX[w]) == \"table\" and not K.d2need(K.FX[w]) then add(w, cls, lv) end\r\nend\r\nend\r\n\r\ndo\r\nlocal ev = {}\r\nfor n, cat in pairs(K.PACK.feat or {}) do if cat == \"everyone\" and type(K.FX[n]) == \"table\" and not K.d2need(K.FX[n]) then ev[#ev + 1] = n end end\r\ntable.sort(ev)\r\nlocal base0 = sh.base or sh\r\nfor _, n in ipairs(ev) do add(n, nil, K.charLevel(base0)) end\r\nend\r\nfor _, x in ipairs(Feat.levelFeaturesBy(sh, true)) do add(x.name, x.class, x.level) end\r\n\r\n\r\nlocal base = sh.base or sh\r\nlocal bgr = BACKGROUNDS[base.background or \"\"]\r\nlocal spr = SPECIES[base.species or \"\"]\r\nfor _, row in ipairs({ bgr, spr }) do\r\nfor _, n in ipairs(type(row) == \"table\" and type(row.fx) == \"table\" and row.fx or {}) do\r\nif type(n) == \"string\" then add(n, nil, K.charLevel(base)) end\r\nend\r\nend\r\n\r\nfor _, n in ipairs(Feat.list(base)) do if K.PACK.feat[n] == \"origin\" then add(n, nil, K.charLevel(base)) end end\r\n\r\nlocal copies = {}\r\nfor _, g in ipairs(type(base.gfeats) == \"table\" and base.gfeats or {}) do\r\nlocal n = type(g) == \"table\" and g.name or g\r\ncopies[n] = (copies[n] or 0) + 1\r\nlocal rec = K.FX[n]\r\nif type(rec) == \"table\" then\r\nif copies[n] == 1 then add(n, nil, K.charLevel(base))\r\nelse\r\nlocal i = copies[n]\r\nlocal fx = {}\r\nfor _, e in ipairs(rec.fx or {}) do\r\nlocal c = {}\r\nfor k, v in pairs(e) do c[k] = v end\r\nif type(c.key) == \"string\" then c.key = c.key .. \"_\" .. i end\r\nif type(c.pick) == \"string\" then c.pick = c.pick .. \"_\" .. i end\r\nif type(c.if_pick) == \"table\" and type(c.if_pick[1]) == \"string\" then c.if_pick = { c.if_pick[1] .. \"_\" .. i, c.if_pick[2] } end\r\nif c.t == \"choice\" and type(e.key) == \"string\" then c.copyBase, c.copyN = e.key, i end\r\nfx[#fx + 1] = c\r\nif c.t == \"choice\" then\r\nfor _, pv in ipairs(type(p[c.key]) == \"table\" and p[c.key] or { p[c.key] }) do\r\nif type(pv) == \"string\" then add(pv, nil, K.charLevel(base)) end\r\nend\r\nend\r\nend\r\nout[#out + 1] = { name = n, rec = setmetatable({ fx = fx }, { __index = rec }), lv = K.charLevel(base), copy = i }\r\nend\r\nend\r\nend\r\n\r\nfor _, x in ipairs(K.afflictOn(sh)) do\r\nif not seen[x.e.name] then\r\nseen[x.e.name] = true\r\nout[#out + 1] = { name = x.e.name, rec = setmetatable({ fx = x.fx }, { __index = x.rec }), lv = K.charLevel(base) }\r\nend\r\nend\r\n\r\nfor _, key in ipairs(type(sh.itemFx) == \"table\" and sh.itemFx or type(base.itemFx) == \"table\" and base.itemFx or {}) do\r\nlocal m = K.MAGIC and K.MAGIC[key]\r\nif m and type(m.fx) == \"table\" and not K.d2need(m) and not seen[\"item:\" .. key] then\r\nseen[\"item:\" .. key] = true\r\nout[#out + 1] = { name = key, rec = { fx = m.fx, text = \"\", tip = \"\", item = true }, lv = K.charLevel(base) }\r\nend\r\nend\r\n\r\nfor _, k in ipairs({ \"invocations\", \"metamagic\" }) do\r\nfor _, v in ipairs(type(p[k]) == \"table\" and p[k] or {}) do\r\nif K.PACK.feat[v] == \"invocation\" or K.PACK.feat[v] == \"metamagic\" then add(v, nil, K.charLevel(base)) end\r\nend\r\nend\r\n\r\nfor _, k in ipairs({ \"style\", \"xstyle\" }) do\r\nlocal v = p[k]\r\nif type(v) == \"string\" and K.PACK.feat[v] == \"style\" then add(v, nil, nil) end\r\nend\r\nreturn out\r\nend\r\n\r\n\r\nfunction Feat.fxOf(sh, t)\r\nlocal out = {}\r\nif type(sh) ~= \"table\" then return out end\r\nlocal p = type(sh.picks) == \"table\" and sh.picks or {}\r\nfor _, x in ipairs(Feat.fxList(sh)) do\r\nfor _, e in ipairs(x.rec.fx) do\r\n\r\n\r\n\r\nif e.t == t and K.fxOk(e, x, sh, p) then\r\nlocal c = { src = x.name, srcClass = x.class, srcLv = x.lv }\r\nfor k, v in pairs(e) do c[k] = v end\r\nout[#out + 1] = c\r\nend\r\nend\r\nend\r\nreturn out\r\nend\r\n\r\n\r\n\r\nfunction K.foeSaveWhy(sh, what)\r\nif type(sh) ~= \"table\" then return nil end\r\nlocal p = type(sh.picks) == \"table\" and sh.picks or {}\r\nfor _, x in ipairs(Feat.fxList(sh)) do\r\nfor _, e in ipairs(x.rec.fx or {}) do\r\nif e.t == \"foe_save\" and type(e.name) == \"string\" and e.name:lower() == tostring(what or \"\"):lower() then\r\nlocal lv = x.lv or tonumber(sh.level) or 1\r\nif e[\"while\"] ~= nil and not K.fxWhile(e, sh) then return e.name .. \": only while \" .. tostring(e[\"while\"]) .. \" is on\" end\r\nif type(e.if_pick) == \"table\" and not K.pickHas(p[e.if_pick[1]], e.if_pick[2]) and K.modePickOf(sh, e.if_pick[1]) ~= e.if_pick[2] then\r\nreturn e.name .. \": only with \" .. tostring(e.if_pick[2]) .. \" chosen\"\r\nend\r\nif lv < (e.from or 0) then return e.name .. \": from level \" .. tostring(e.from) end\r\nif e.to ~= nil and lv >= (tonumber(e.to) or 99) then return e.name .. \": before level \" .. tostring(e.to) end\r\nend\r\nend\r\nend\r\nreturn nil\r\nend\r\n\r\n\r\nfunction K.fxOk(e, x, sh, p)\r\np = p or (type(sh.picks) == \"table\" and sh.picks) or {}\r\nlocal lv = x.lv or tonumber(sh.level) or 1\r\nif type(e.if_pick) == \"table\" and not K.pickHas(p[e.if_pick[1]], e.if_pick[2]) and K.modePickOf(sh, e.if_pick[1]) ~= e.if_pick[2] then return false end\r\nif lv < (e.from or 0) then return false end\r\nif e.to ~= nil and lv >= (tonumber(e.to) or 99) then return false end\r\nif e[\"while\"] ~= nil and not K.fxWhile(e, sh) then return false end\r\nreturn true\r\nend\r\n\r\nfunction K.recOfSheet(sh)\r\nlocal pc = K.curPc or K.partyPc\r\nif type(pc) ~= \"table\" or type(sh) ~= \"table\" then return nil end\r\nlocal s0 = sh.base or sh\r\nfor _, a in ipairs(Ally.list(pc)) do if a.sheet == s0 or a.sheet == sh then return a end end\r\n\r\nlocal cur = Cond and Cond.cur\r\nlocal cs = type(cur) == \"table\" and cur ~= pc and type(cur.sheet) == \"table\" and cur.sheet\r\nif cs and cs.class == s0.class and cs.level == s0.level and cs.species == s0.species and cs.background == s0.background then return cur end\r\nreturn pc\r\nend\r\nfunction K.fxWhile(e, sh)\r\nlocal w = e[\"while\"]\r\nif w == nil then return true end\r\nlocal r = K.recOfSheet(sh)\r\nif not r then return false end\r\nif w == \"Wild Shape\" then return r.form ~= nil end\r\nif type(r.mode) == \"table\" and r.mode.name == w then return true end\r\n\r\n\r\nlocal b = type(r.buff) == \"table\" and r.buff[w]\r\nif type(b) ~= \"table\" then return false end\r\n\r\nlocal now = (K.clockRef and tonumber(K.clockRef.min)) or tonumber(K.replyClock)\r\nif now and tonumber(b.ends) and b.ends >= 0 and b.ends <= now then return false end\r\nreturn true\r\nend\r\nfunction K.modePickOf(sh, key)\r\nlocal r = K.recOfSheet(sh)\r\nreturn r and type(r.mode) == \"table\" and type(r.mode.picks) == \"table\" and r.mode.picks[key] or nil\r\nend\r\n\r\nfunction K.useModePick(sh, name, v)\r\nlocal o, want = {}, trim(v or \"\")\r\nlocal opts, key\r\nfor _, e in ipairs(Feat.fxOf(sh, \"choice\")) do\r\nif e.on_use == name and not key then key, opts = e.key, e.options or {} end\r\nend\r\nif not key then return nil, nil end\r\nfor _, x in ipairs(opts) do\r\nif x == want or x:lower() == want:lower() or NAMES_KO[x] == want or Canon.name(want) == x then o[key] = x end\r\nend\r\nif not o[key] then return nil, \"write the choice as the second field: [USE|\" .. name .. \"|\" .. tostring(opts[1]) .. \"] (\" .. table.concat(opts, \", \") .. \")\" end\r\nreturn o\r\nend\r\n\r\nfunction Feat.fxResists(sh, only)\r\nlocal p, out = type(sh.picks) == \"table\" and sh.picks or {}, {}\r\nfor _, e in ipairs(Feat.fxOf(sh, \"resist\")) do\r\n\r\n\r\nlocal skip = (e.nonmagical and K.charLevel(sh) < (tonumber(e.magic_at) or 99)) or K.charLevel(sh) < (tonumber(e.from) or 0)\r\nif (not only or e.src == only) and not skip then\r\nfor _, t in ipairs(e.types or {}) do out[#out + 1] = t end\r\nlocal t = (e.pick and p[e.pick]) or (e.by_pick and e.map and e.map[p[e.by_pick] or \"\"])\r\nif type(t) == \"string\" then out[#out + 1] = t end\r\nend\r\nend\r\nreturn out\r\nend\r\n\r\n\r\n\r\nfunction Feat.immune(r, sh, cond)\r\n\r\nfor name, b in pairs(type(r.buff) == \"table\" and r.buff or {}) do\r\nif type(b) == \"table\" and type(b.cimm) == \"table\" then\r\nfor _, cn in ipairs(b.cimm) do if cn == cond then return name end end\r\nend\r\nend\r\n\r\nif K.MI then for _, x in ipairs(K.MI.powers(r, \"cimm\")) do if x[1].cond == cond then return x[3] end end end\r\nfor _, e in ipairs(Feat.fxOf(sh, \"cond_immune\")) do\r\nif e.scope ~= \"party\" and (e.when ~= \"raging\" or (type(r.mode) == \"table\" and r.mode.name == \"Rage\")) then\r\nfor _, cn in ipairs(e.conds or {}) do if cn == cond then return e.src end end\r\nend\r\nend\r\nreturn (K.PARTY and K.PARTY.immune or {})[cond]\r\nend\r\n\r\n\r\n\r\n\r\n\r\nK.PARTY = { aura = 0, immune = {} }\r\nfunction K.partyFx(pc, psh)\r\nlocal out = { aura = 0, immune = {} }\r\nlocal function from(r, sh)\r\nif type(r) ~= \"table\" or type(sh) ~= \"table\" or r.dead or (tonumber(r.hp) or 0) <= 0 or Cond.fx(r).incap then return end\r\nfor _, e in ipairs(Feat.fxOf(sh, \"save_bonus\")) do\r\nif e.scope == \"party\" then\r\nlocal n = math.max(e.min or -99, abilityMod((sh.scores or {})[e.amount] or 10))\r\nif n > out.aura then out.aura, out.auraBy, out.auraRec = n, e.src, r end\r\nend\r\nend\r\nfor _, e in ipairs(Feat.fxOf(sh, \"cond_immune\")) do\r\nif e.scope == \"party\" then\r\nfor _, cn in ipairs(e.conds or {}) do out.immune[cn] = out.immune[cn] or e.src end\r\nend\r\nend\r\nend\r\nif type(pc) == \"table\" then\r\nfrom(pc, psh)\r\nfor _, a in ipairs(Ally.list(pc)) do from(a, a.sheet) end\r\nend\r\nK.PARTY = out\r\nif type(pc) == \"table\" then K.partyPc = pc end\r\nreturn out\r\nend\r\n\r\n\r\n\r\n\r\n\r\n\r\nfunction Feat.pickedText(sh, name)\r\nlocal p = type(sh.picks) == \"table\" and sh.picks or {}\r\nlocal function list(v) return type(v) == \"table\" and v or ((type(v) == \"string\" and v ~= \"\") and { v } or {}) end\r\nlocal got = {}\r\nif name == \"Spell Mastery\" then\r\nfor _, n in ipairs(list(p.mastone)) do got[#got + 1] = n .. \" (level 1)\" end\r\nfor _, n in ipairs(list(p.masttwo)) do got[#got + 1] = n .. \" (level 2)\" end\r\nelseif name == \"Signature Spells\" then\r\nfor _, n in ipairs(list(p.sig)) do got[#got + 1] = n end\r\nelse\r\nreturn \"\"\r\nend\r\nif #got == 0 then return \". None picked yet, so none is free this way\" end\r\nreturn \". Picked: \" .. table.concat(got, \", \") .. \"; no other spell is free this way\"\r\nend\r\n\r\nfunction Feat.fill(text, sh, who, name, bare)\r\nlocal row = K.rowAt(sh, sh.class, tonumber(sh.level) or 1)\r\n\r\ntext = text:gsub(\"{ROW:([%w_]+)}\", function(k)\r\nlocal v = row[k]\r\nif v ~= nil and type(v) ~= \"table\" then return tostring(v) end\r\nend)\r\n\r\ntext = text:gsub(\"{WISx2}\", function() return tostring(2 * math.max(0, MOD.Wisdom or 0)) end)\r\nreturn (text:gsub(\"{(%u+)(1?)}\", function(k, one)\r\nlocal ab = ABBR[k]\r\nif ab then\r\nlocal m = MOD[ab] or 0\r\nreturn one == \"1\" and tostring(math.max(1, m)) or string.format(\"%+d\", m)\r\nend\r\nif k == \"LEVEL\" then return tostring(sh.level) end\r\nif k == \"HMD\" then return (tonumber(sh.level) or 1) >= 20 and \"1d10\" or \"1d6\" end\r\nif k == \"PB\" then return tostring(PROF) end\r\nif k == \"MA\" then return row.martial_arts or \"1d4\" end\r\nif k == \"WHO\" then return who end\r\n\r\nif k == \"DC\" then\r\nfor _, e in ipairs(Feat.fxOf(sh, \"foe_save\")) do if e.src == name and e.dc then return tostring(K.fxDC(e)) end end\r\n\r\n\r\n\r\nlocal cls\r\nfor _, x in ipairs(Feat.fxList(sh)) do\r\nif x.name == name then\r\ncls = cls or x.class\r\nfor _, e in ipairs(type(x.rec) == \"table\" and x.rec.fx or {}) do\r\nif e.t == \"foe_save\" and e.dc then return tostring(K.fxDC({ dc = e.dc, srcClass = x.class })) end\r\nend\r\nend\r\nend\r\nlocal cc = (cls and (CLASSES[cls] or {}).spell_ability and cls) or K.castCl(sh)\r\nif cc and (CLASSES[cc] or {}).spell_ability then return tostring(K.fxDC({ dc = \"SPELL\", srcClass = cc })) end\r\nreturn nil\r\nend\r\nif k == \"RES\" then\r\nlocal r = Feat.fxResists(sh, name)\r\nreturn #r > 0 and table.concat(r, \", \") or \"the damage type still to be picked on the character tab\"\r\nend\r\nreturn nil\r\nend)) .. (bare and \"\" or Feat.pickedText(sh, name))\r\nend\r\n\r\n\r\n\r\n\r\n\r\nfunction Feat.spellMod(name, sp, m, base, one)\r\nif (m.rays or m.darts or m.beams) and not one then return 0 end\r\nlocal sh = SHEET\r\nlocal p = type(sh.picks) == \"table\" and sh.picks or {}\r\nlocal add, src = 0, nil\r\nif sp.level == 0 and Spell.classKnown(name) then\r\nfor _, e in ipairs(Feat.fxOf(sh, \"cantrip_mod\")) do add = add + (MOD[e.ability] or 0); src = src or e.src end\r\nend\r\nfor _, e in ipairs(Feat.fxOf(sh, \"spell_damage_mod\")) do\r\nlocal fits = false\r\nif e.school then\r\nlocal mine = false\r\nfor _, c in ipairs(sp.classes or {}) do if c == sh.class then mine = true end end\r\nfits = mine and base == m.damage and K.SCHOOL_EN[sp.school or \"\"] == e.school\r\nelseif e.type_pick then\r\nlocal t = p[e.type_pick]\r\nlocal function has(x)\r\nreturn type(t) == \"string\" and type(x) == \"string\" and not x:find(\"^choice\") and x:find(t, 1, true) ~= nil\r\nend\r\nif base == m.damage then fits = has(m.type)\r\nelse fits = not has(m.type) and m.extra_save ~= nil and has(m.extra_save.type) end\r\nend\r\nif fits then add = add + (MOD[e.ability] or 0); src = src or e.src end\r\nend\r\nreturn add, src\r\nend\r\n\r\n\r\n\r\nfunction K.freeLevel(e, sp)\r\nif type(e) ~= \"table\" or e.level == nil then return sp.level end\r\nreturn math.max(sp.level, math.min(9, K.fxNum(e.level, SHEET, e.srcLv)))\r\nend\r\n\r\n\r\n\r\nfunction Feat.freeCast(sh, r, name, sp)\r\nlocal why = \"no feature casts \" .. name .. \" without a slot: write its level in place of free\"\r\nfor _, e in ipairs(Feat.fxOf(sh, \"free_cast\")) do\r\nlocal fits = false\r\nif e.list then\r\nfor _, c in ipairs(sp.classes or {}) do if c == e.list then fits = true end end\r\nfits = fits and sp.level >= (e.min_level or 1) and sp.level <= (e.max_level or 9)\r\nelseif e.spells then\r\nfor _, n in ipairs(e.spells) do if n == name then fits = true end end\r\nelseif e.land then\r\nlocal land = Feat.LAND[(type(sh.picks) == \"table\" and sh.picks.land) or \"\"] or {}\r\nfor i, n in ipairs(land) do if n == name and (e.srcLv or sh.level) >= Feat.LAND_AT[i] and sp.level >= 1 then fits = true end end\r\nelseif e.pick then\r\n\r\nlocal v = type(sh.picks) == \"table\" and sh.picks[e.pick]\r\nfor _, n in ipairs(type(v) == \"table\" and v or { v }) do if n == name then fits = true end end\r\nif fits and e.prepared and not Spell.classKnown(name) then fits = false; why = name .. \" is not prepared\" end\r\nend\r\nif fits and e.at_will then return e.use or e.src or name, nil, true, e end\r\nif fits then\r\nif (type(r.res) == \"table\" and r.res[e.use] or 0) >= 1 then return e.use, nil, nil, e end\r\nwhy = \"no \" .. e.use .. \" left\"\r\nend\r\nend\r\nreturn nil, why\r\nend\r\n\r\n\r\n\r\nfunction Feat.tempUse(e, c, pc, head, f, x)\r\nif pc.dead then return head .. \"|bad:\" .. (pc.name or \"Player\") .. \" is dead|-]\", false end\r\n\r\n\r\nlocal tgts = {}\r\nif e.target and type(f) == \"table\" and trim(f[2] or \"\") ~= \"\" then\r\nlocal root = K.curPc or pc\r\nfor nm in (f[2] .. \",\"):gmatch(\"([^,]*),\") do\r\nnm = trim(nm)\r\nif nm ~= \"\" then\r\nlocal r = Ally.rec(root, nm)\r\nif not r then return head .. \"|bad:\" .. nm .. \": Player or a companion|-]\", false end\r\nif r.dead then return head .. \"|bad:\" .. nm .. \" is dead|-]\", false end\r\ntgts[#tgts + 1] = r\r\nend\r\nend\r\nend\r\nif #tgts == 0 then tgts[1] = pc end\r\nlocal costs = e.costs or { [e.use] = 1 }\r\nlocal names = {}\r\nfor k in pairs(costs) do names[#names + 1] = k end\r\ntable.sort(names)\r\nfor _, k in ipairs(names) do\r\nif not PC.res[k] or (pc.res[k] or 0) < costs[k] then return head .. \"|bad:no \" .. k .. \" left|-]\", false end\r\nend\r\nlocal left = {}\r\nfor _, k in ipairs(names) do\r\npc.res[k] = pc.res[k] - costs[k]\r\nleft[#left + 1] = (k ~= e.use and (k .. \" \") or \"\") .. pc.res[k] .. \"/\" .. PC.res[k].max\r\nend\r\n\r\n\r\n\r\nlocal cls, slv = e.srcClass or (x and x.class), e.srcLv or (x and x.lv)\r\nlocal mult, rest = 0, {}\r\nfor part in (tostring(e.formula or \"\") .. \"+\"):gmatch(\"([^+]*)%+\") do\r\nlocal k2, die = trim(part):match(\"^(%d+)%s*%*%s*(.+)$\")\r\nlocal dp = die and parseFormula(K.dieText({ dice = die, srcClass = cls, srcLv = slv }, SHEET))\r\nif dp and #dp.dice > 0 then\r\nlocal v = dp.mod or 0\r\nfor _, d in ipairs(dp.dice) do for _ = 1, d.n do v = v + K.d(d.s) end end\r\nmult = mult + tonumber(k2) * v\r\nelseif trim(part) ~= \"\" then rest[#rest + 1] = trim(part) end\r\nend\r\nlocal p = (#rest > 0 and parseFormula(K.dieText({ dice = table.concat(rest, \"+\"), srcClass = cls, srcLv = slv }, SHEET))) or { dice = {}, mod = 0 }\r\nlocal n = (p.mod or 0) + mult\r\nfor _, d in ipairs(p.dice) do for _ = 1, d.n do n = n + K.d(d.s) end end\r\nn = math.max(1, n)\r\nlocal got = {}\r\n\r\n\r\nlocal share, extra1 = n, 0\r\nif e.split and #tgts > 1 then share, extra1 = math.floor(n / #tgts), n % #tgts end\r\nfor i, t in ipairs(tgts) do\r\nlocal mine = share + ((i <= extra1) and 1 or 0)\r\nt.thp = math.max(tonumber(t.thp) or 0, mine)\r\ngot[#got + 1] = (#tgts > 1 or t ~= pc) and ((t == (K.curPc or pc) and \"Player\" or t.name) .. \" \" .. t.thp) or tostring(t.thp)\r\nend\r\nif c.active then c.last = pc.name or \"Player\" end\r\nreturn head .. \"|ok|\" .. table.concat(left, \", \") .. \", temporary HP \" .. table.concat(got, \", \") .. \"]\", true\r\nend\r\n\r\n\r\nfunction Feat.shortRest(r)\r\nlocal out = \"\"\r\nfor _, e in ipairs(Feat.fxOf(SHEET, \"exhaustion_short_rest\")) do\r\nCond.load(r)\r\nif r.exh > 0 then\r\nr.exh = math.max(0, r.exh - (e.amount or 1))\r\nout = out .. \", \" .. e.src .. \": Exhaustion \" .. r.exh\r\nif type(r.ar) == \"table\" and (tonumber(r.ar.overstim) or 0) > 0 then\r\nr.ar.overstim = math.max(0, r.ar.overstim - (e.amount or 1))\r\nend\r\nend\r\nend\r\nreturn out\r\nend\r\n\r\n\r\n\r\nfunction Feat.heroic(pc, psh)\r\nfor _, r in ipairs({ pc, table.unpack(Ally.list(pc)) }) do\r\nlocal sh = (r == pc) and psh or r.sheet\r\nif type(sh) == \"table\" and not r.dead and #Feat.fxOf(sh, \"insp_each_turn\") > 0 then\r\nr.res = type(r.res) == \"table\" and r.res or {}\r\nr.res[\"Heroic Inspiration\"] = 1\r\nend\r\nend\r\nend\r\n\r\n\r\n\r\n\r\n\r\n\r\nfunction Ally.list(pc)\r\nif type(pc) ~= \"table\" or type(pc.allies) ~= \"table\" then return {} end\r\nreturn pc.allies\r\nend\r\n\r\nfunction Ally.find(pc, name)\r\nif not name then return nil end\r\nfor _, a in ipairs(Ally.list(pc)) do if a.name == name then return a end end\r\nfor _, a in ipairs(Ally.guests(pc)) do if a.name == name then return a end end\r\nreturn nil\r\nend\r\n\r\n\r\n\r\n\r\n\r\nfunction Ally.guests(pc)\r\nif type(pc) ~= \"table\" or type(pc.guests) ~= \"table\" then return {} end\r\nreturn pc.guests\r\nend\r\n\r\nfunction Ally.leaving(id)\r\nlocal v = tostring(getChatVar(id, \"dnd_party_leave\") or \"\")\r\nlocal out = {}\r\nif v == \"\" or v == \"null\" then return out end\r\nfor nm in (v .. \"|\"):gmatch(\"([^|]*)|\") do if trim(nm) ~= \"\" then out[#out + 1] = trim(nm) end end\r\nreturn out\r\nend\r\nfunction Ally.isGuest(pc, name)\r\nfor _, a in ipairs(Ally.guests(pc)) do if a.name == name then return a end end\r\nreturn nil\r\nend\r\n\r\n\r\nfunction Ally.rec(pc, name, u)\r\nif u then\r\nif u.side == \"pc\" then return pc end\r\nif u.side == \"ally\" then return Ally.find(pc, u.ally) end\r\nreturn nil\r\nend\r\nif name == \"Player\" then return pc end\r\nreturn Ally.find(pc, name)\r\nend\r\n\r\n\r\nfunction Ally.size(pc)\r\nlocal n = 1\r\nfor _, a in ipairs(Ally.list(pc)) do if not a.dead then n = n + 1 end end\r\nreturn n\r\nend\r\n\r\n\r\nfunction Ally.budget(pc, i)\r\nlocal function at(lv) return (BUDGET[tonumber(lv) or 1] or BUDGET[#BUDGET])[i] end\r\nlocal s = at(pc.level)\r\nfor _, a in ipairs(Ally.list(pc)) do if not a.dead then s = s + at(a.level or pc.level) end end\r\nreturn s\r\nend\r\n\r\nfunction Ally.caster(pc)\r\nfor _, a in ipairs(Ally.list(pc)) do\r\nif not a.dead and Ally.with(a, Spell.any) then return true end\r\nend\r\nreturn false\r\nend\r\n\r\n\r\nfunction Ally.with(a, fn, ...)\r\n\r\n\r\nif type(a.sheet) ~= \"table\" or not CLASSES[a.sheet.class or \"\"] then return fn(...) end\r\nlocal keep, cur, outer = SHEET, Cond.cur, K.outerSheet\r\nK.outerSheet = outer or keep\r\napplySheet(a.sheet)\r\nCond.cur = a\r\nlocal res = table.pack(pcall(fn, ...))\r\napplySheet(keep)\r\nCond.cur, K.outerSheet = cur, outer\r\nif not res[1] then error(res[2], 0) end\r\nreturn table.unpack(res, 2, res.n)\r\nend\r\n\r\n\r\nfunction Ally.run(pc, rec, fn)\r\nif not rec or rec == pc then return fn() end\r\nreturn Ally.with(rec, fn)\r\nend\r\n\r\n\r\n\r\n\r\nfunction Ally.prep(sh)\r\nlocal had = {}\r\nlocal function pick(list, n, lo, hi)\r\nlocal out = {}\r\nfor _, s in ipairs(list or {}) do\r\nlocal sp = SPELLS[s]\r\n\r\nif #out < n and sp and sp.level >= lo and sp.level <= hi and (not K.d2need(sp) or had[s]) then out[#out + 1] = s end\r\nend\r\nreturn out\r\nend\r\nfor _, c in ipairs(K.classes(sh)) do\r\nlocal cl = CLASSES[c.name]\r\nif cl.spell_ability then\r\nlocal row = c.row or cl.levels[c.level] or {}\r\nlocal maxLv = K.rowMaxLv(row)\r\nhad = {}\r\nlocal cv = K.casterView(sh, c.name) or {}\r\nfor _, l in ipairs({ cv.cantrips or {}, cv.spells or {} }) do for _, n in ipairs(l) do had[n] = true end end\r\nK.setLists(sh, c.name, pick(Ally.cdata(c.name, \"cantrips\"), Spell.cantripsWant(K.view(sh, c.name, c.level), row), 0, 0),\r\npick(Ally.cdata(c.name, \"spells\"), row.prepared or 0, 1, maxLv))\r\nend\r\nend\r\nend\r\n\r\n\r\n\r\n\r\nfunction Ally.nextCls(a)\r\nlocal sh = a.sheet\r\nlocal pick = a.lvPick\r\nif type(pick) == \"string\" and CLASSES[pick] and K.mcCan(sh, pick) then return pick end\r\nif K.mcCan(sh, sh.class) then return sh.class end\r\nfor _, m in ipairs(K.mcList(sh)) do if K.mcCan(sh, m.class) then return m.class end end\r\nreturn nil\r\nend\r\n\r\n\r\n\r\nfunction Ally.trimLevels(sh)\r\nlocal over = false\r\nfor _, c in ipairs(K.classes(sh)) do if c.level > K.maxLevel(c.name) then over = true end end\r\nif not over then return end\r\nlocal keep, path = {}, {}\r\nfor _, c in ipairs(K.classes(sh)) do keep[c.name] = K.maxLevel(c.name) end\r\nlocal old = type(sh.lvcls) == \"table\" and sh.lvcls or {}\r\nfor l = 1, K.charLevel(sh) do\r\nlocal c = old[l] or old[tostring(l)] or sh.class\r\nif (keep[c] or 0) > 0 then keep[c] = keep[c] - 1; path[#path + 1] = c end\r\nend\r\nsh.level = math.min(sh.level, K.maxLevel(sh.class))\r\nfor _, m in ipairs(K.mcList(sh)) do m.level = math.min(tonumber(m.level) or 0, K.maxLevel(m.class)) end\r\nif type(sh.lvcls) == \"table\" then sh.lvcls = path end\r\nend\r\n\r\n\r\n\r\n\r\n\r\nfunction Ally.fit(a, lv, path)\r\nlocal sh = a.sheet\r\nlocal old = K.charLevel(sh)\r\nlocal oldRes = Ally.with(a, function() return PC.res end)\r\nfor l = old + 1, math.min(lv, #XP_LEVEL) do\r\nlocal want = type(path) == \"table\" and (path[l] or path[tostring(l)]) or nil\r\nlocal cls = (type(want) == \"string\" and CLASSES[want] and K.mcCan(sh, want)) and want or Ally.nextCls(a)\r\nif not cls then break end\r\nif K.asiLevel(cls, K.addLevel(sh, cls)) then\r\nlocal before = {}\r\nfor k, v in pairs(sh.scores) do before[k] = v end\r\napplyASI(sh)\r\nlocal d = {}\r\nfor k, v in pairs(sh.scores) do if v ~= before[k] then d[k] = v - (before[k] or v) end end\r\nsh.allyAsi = type(sh.allyAsi) == \"table\" and sh.allyAsi or {}\r\nsh.allyAsi[#sh.allyAsi + 1] = { lv = K.charLevel(sh), d = d }\r\nend\r\nend\r\nAlly.trimLevels(sh)\r\n\r\nlocal pk = type(sh.picks) == \"table\" and sh.picks or {}\r\nif type(pk.mcskill) == \"table\" then\r\nlocal n = 0\r\nfor _, m in ipairs(K.mcList(sh)) do if (tonumber(m.level) or 0) > 0 and K.mcGains(m.class).skill then n = n + 1 end end\r\nwhile #pk.mcskill > n do table.remove(pk.mcskill) end\r\nend\r\nAlly.prep(sh)\r\nAlly.autoPick(a)\r\n\r\n\r\nsh.expertise = {}\r\npk = type(sh.picks) == \"table\" and sh.picks or {}\r\nlocal prof, seen = {}, {}\r\nfor _, k in ipairs(sh.skills or {}) do prof[k] = true end\r\nfor _, k in ipairs(type(pk.mcskill) == \"table\" and pk.mcskill or {}) do prof[k] = true end\r\nfor _, c in ipairs(K.classes(sh)) do\r\nlocal want, n = ((CLASSES[c.name].levels or {})[c.level] or {}).expertise or 0, 0\r\nfor _, list in ipairs({ Ally.cdata(c.name, \"expertise\") or {}, sh.skills or {} }) do\r\nfor _, s in ipairs(list) do\r\nif n < want and prof[s] and not seen[s] then seen[s] = true; n = n + 1; sh.expertise[#sh.expertise + 1] = s end\r\nend\r\nend\r\nend\r\nAlly.with(a, function()\r\nlocal bonus = K.maxBonus(a)\r\nlocal gain = PC.hp - ((a.max or (PC.hp + bonus)) - bonus)\r\na.max = PC.hp + bonus\r\nif a.hp > 0 then a.hp = math.max(1, math.min(a.max, a.hp + gain)) end\r\nlocal now = K.charLevel(sh)\r\na.hd = math.max(0, math.min(now, (a.hd or 0) + now - old))\r\na.resMax = type(a.resMax) == \"table\" and a.resMax or {}\r\nfor k, r in pairs(PC.res) do\r\nlocal was = oldRes[k] and oldRes[k].max or 0\r\na.res[k] = math.min(r.max, math.max(0, (a.res[k] or 0) + r.max - was))\r\na.resMax[k] = math.max(tonumber(a.resMax[k]) or 0, tonumber(r.max) or 0)\r\nend\r\nend)\r\na.level = K.charLevel(sh)\r\nend\r\n\r\n\r\n\r\n\r\n\r\nK.GEAR_EXTRA = { [\"미늘 갑옷\"] = \"Scale Mail\", [\"스케일 메일\"] = \"Scale Mail\", [\"체인 메일\"] = \"Chain Mail\", [\"사슬 셔츠\"] = \"Chain Shirt\",\r\n[\"판금 갑주\"] = \"Plate Armor\", [\"플레이트 아머\"] = \"Plate Armor\", [\"레더 아머\"] = \"Leather Armor\", [\"징 박은 가죽\"] = \"Studded Leather Armor\",\r\n[\"브레스트플레이트\"] = \"Breastplate\", [\"세검\"] = \"Rapier\", [\"곡도\"] = \"Scimitar\", [\"석궁\"] = \"Light Crossbow\", [\"지팡이\"] = \"Quarterstaff\",\r\n[\"전투 망치\"] = \"Warhammer\", [\"단창\"] = \"Spear\" }\r\nK.GEAR_SKIP = { [\"창\"] = true, [\"낫\"] = true, [\"장도\"] = true, [\"거창\"] = true }\r\n\r\n\r\nfunction K.gearWords()\r\nif K.gearList then return K.gearList end\r\nlocal list = {}\r\nlocal function add(word, en)\r\nword = trim(word or \"\")\r\nif word == \"\" or K.GEAR_SKIP[word] then return end\r\nlocal esc = word:gsub(\"[%^%$%(%)%%%.%[%]%*%+%-%?]\", \"%%%0\")\r\nlocal pat = word:find(\"^[%a%s']+$\") and (\"%f[%a]\" .. esc:lower():gsub(\"%s+\", \"%%s+\") .. \"%f[%A]\") or esc:gsub(\"%s+\", \"%%s*\")\r\nlist[#list + 1] = { word, en, pat, #word:gsub(\"%s\", \"\") }\r\nend\r\nfor en, w in pairs(WEAPONS) do add(en, en); add(NAMES_KO[en], en); add(w.gloss, en) end\r\nfor en in pairs(ARMOR) do add(en, en); add(NAMES_KO[en], en) end\r\nfor word, en in pairs(K.GEAR_EXTRA) do add(word, en) end\r\ntable.sort(list, function(x, y) if x[4] ~= y[4] then return x[4] > y[4] end return x[1] < y[1] end)\r\nK.gearList = list\r\nreturn list\r\nend\r\n\r\n\r\nfunction K.gearIn(text)\r\nlocal s = \" \" .. (text or \"\"):lower() .. \" \"\r\nlocal found, out, seen = {}, {}, {}\r\nfor _, g in ipairs(K.gearWords()) do\r\nlocal a, b = s:find(g[3])\r\nwhile a do\r\nfound[#found + 1] = { a, g[2] }\r\ns = s:sub(1, a - 1) .. string.rep(\" \", b - a + 1) .. s:sub(b + 1)\r\na, b = s:find(g[3], b + 1)\r\nend\r\nend\r\ntable.sort(found, function(x, y) return x[1] < y[1] end)\r\nfor _, f in ipairs(found) do\r\nif not seen[f[2]] then seen[f[2]] = true; out[#out + 1] = f[2] end\r\nend\r\nreturn out\r\nend\r\n\r\n\r\n\r\n\r\n\r\nfunction Ally.noteGear(a)\r\nlocal items, eq = a.items, a.equip\r\nlocal gold = 0\r\nfor _, o in pairs(CLASSES[a.sheet.class].equipment) do gold = math.max(gold, o.gp or 0) end\r\nlocal armor, main, off, shield\r\nfor _, n in ipairs(K.gearIn(a.note)) do\r\nlocal w, ar = WEAPONS[n], ARMOR[n]\r\nif ar and ar.cat == \"shield\" then\r\nshield = shield or armorProf(\"shield\")\r\nelseif ar then\r\nif not armor and armorProf(ar.cat) and (PRICE[n] or math.huge) <= gold * 100 then armor = n end\r\nelseif w and weaponProf(w) then\r\nitems[n] = math.max(items[n] or 0, 1)\r\nlocal mw = main and WEAPONS[main]\r\nif not main then main = n\r\nelseif not off and w.light and not w.ranged and mw.light and not mw.ranged then off = n end\r\nend\r\nend\r\nif armor then\r\nif eq.armor and eq.armor ~= armor then items[eq.armor] = nil end\r\nitems[armor] = math.max(items[armor] or 0, 1)\r\neq.armor = armor\r\nend\r\nif shield and not main and eq.main and WEAPONS[eq.main].two then\r\n\r\nlocal best, size = nil, 0\r\nfor n in pairs(items) do\r\nlocal w = WEAPONS[n]\r\nlocal d = w and not w.two and not w.ranged and weaponProf(w) and w.dmg:match(\"d(%d+)$\")\r\nif d and (tonumber(d) > size or (tonumber(d) == size and n < best)) then best, size = n, tonumber(d) end\r\nend\r\nif best then eq.main, eq.off = best, nil end\r\nend\r\nif main then\r\nlocal mw, old, oldOff = WEAPONS[main], eq.main, eq.off\r\nif old and old ~= main and old ~= off then items[old] = nil end\r\neq.main, eq.off = main, nil\r\nlocal ow = oldOff and WEAPONS[oldOff]\r\nif off then\r\neq.off = off\r\nelseif not mw.two and oldOff == \"Shield\" then\r\neq.off = \"Shield\"\r\nelseif mw.light and not mw.ranged and ow and ow.light and (items[oldOff] or 0) >= (oldOff == main and 2 or 1) then\r\neq.off = oldOff\r\nend\r\nif mw.ammo and (items[mw.ammo] or 0) < 20 then items[mw.ammo] = 20 end\r\nend\r\nif shield then\r\nitems.Shield = math.max(items.Shield or 0, 1)\r\nlocal mw = eq.main and WEAPONS[eq.main]\r\nif not (mw and mw.two) and not off then eq.off = \"Shield\" end\r\nend\r\nend\r\n\r\n\r\n\r\nfunction Ally.build(name, species, class, note, level, picks, path)\r\nlocal bg = Ally.cdata(class, \"bg\")\r\nif type(BACKGROUNDS[bg or \"\"]) ~= \"table\" or K.d2need(BACKGROUNDS[bg]) then\r\nbg = Ally.BG_BY[((CLASSES[class] or {}).primary or {})[1] or \"\"] or \"Soldier\"\r\nend\r\nlocal scores, allowed, plus = {}, {}, 2\r\nfor i, ab in ipairs(Ally.cdata(class, \"order\")) do scores[ab] = K.STANDARD[i] end\r\nfor _, ab in ipairs(BACKGROUNDS[bg].abilities) do allowed[ab] = true end\r\nfor _, ab in ipairs(Ally.cdata(class, \"order\")) do\r\nif allowed[ab] and plus > 0 then scores[ab] = scores[ab] + plus; plus = plus - 1 end\r\nend\r\nlocal skills = {}\r\nfor _, k in ipairs(BACKGROUNDS[bg].skills) do skills[#skills + 1] = k end\r\nfor i = 1, CLASSES[class].skills.choose + (species == \"Human\" and 1 or 0) do skills[#skills + 1] = Ally.cdata(class, \"skills\")[i] end\r\nlocal items = {}\r\nfor _, o in ipairs({ CLASSES[class].equipment.A, BACKGROUNDS[bg].equipment.A }) do\r\nfor k, n in pairs(o.items) do items[k] = (items[k] or 0) + n end\r\nend\r\nlocal a = { name = name, note = note or \"\", level = 1, hd = 1, items = items, equip = {}, res = {}, ds = { s = 0, f = 0 },\r\nstable = false, dead = false,\r\nsheet = { species = species, class = class, background = bg, level = 1, scores = scores, skills = skills,\r\nexpertise = {}, gear = {}, ally = true, picks = picks } }\r\nK.MP.wrap(a)\r\n\r\n\r\nlocal p = Feat.picks(a.sheet)\r\nif class == \"Cleric\" and not p.order then p.order = \"Protector\" end\r\nif class == \"Druid\" and not p.primal then p.primal = \"Warden\" end\r\nAlly.with(a, function() autoEquip(a); Ally.noteGear(a) end)\r\nAlly.autoPick(a)\r\nAlly.with(a, function()\r\na.max, a.hp = PC.hp, PC.hp\r\nfor k, r in pairs(PC.res) do a.res[k] = r.max end\r\nend)\r\nAlly.fit(a, level, path)\r\nreturn a\r\nend\r\n\r\n\r\n\r\nAlly.LV_SPREAD = 3\r\nfunction Ally.levelFor(pc, a)\r\nlocal off = math.max(-Ally.LV_SPREAD, math.min(Ally.LV_SPREAD, math.floor(tonumber(a.lvOff) or 0)))\r\nreturn math.max(1, (tonumber(pc.level) or 1) + off)\r\nend\r\n\r\n\r\n\r\n\r\nfunction Ally.setLevel(a, lv)\r\nif lv >= K.charLevel(a.sheet) then return Ally.fit(a, lv) end\r\nlocal adj = Ally.adjList(a.sheet)\r\nif #adj == 0 then adj = nil end\r\nlocal b\r\nif adj then\r\n\r\nb = Ally.build(a.name, a.sheet.species, a.sheet.class, a.note, 1, a.sheet.picks, a.sheet.lvcls)\r\nAlly.putAdj(b.sheet, adj, function(l) return l <= 1 end)\r\nfor l = 2, lv do\r\nAlly.fit(b, l, a.sheet.lvcls)\r\nAlly.putAdj(b.sheet, adj, function(x) return x == l end)\r\nend\r\nAlly.putAdj(b.sheet, adj, function(x) return x > lv end)\r\nb.sheet.abAdj = adj\r\nAlly.with(b, function() refitHp(b.sheet, b); Feat.fillRes(b) end)\r\nelse\r\nb = Ally.build(a.name, a.sheet.species, a.sheet.class, a.note, lv, a.sheet.picks, a.sheet.lvcls)\r\nend\r\nlocal share = (a.max or 0) > 0 and a.hp / a.max or 1\r\nb.sheet.sdrain = a.sheet.sdrain\r\nb.sheet.afflict, b.sheet.brandRegrow = a.sheet.afflict, a.sheet.brandRegrow\r\nfor _, x in ipairs(type(a.sheet.allyAsi) == \"table\" and a.sheet.allyAsi or {}) do\r\nif x.feat and (tonumber(x.lv) or 99) <= lv and Ally.featSwap(b.sheet, x.feat, x.lv) then b.featSwapped = true end\r\nend\r\nif b.featSwapped then\r\nb.featSwapped = nil\r\nAlly.autoPick(b)\r\nAlly.with(b, function() refitHp(b.sheet, b); Feat.fillRes(b) end)\r\nend\r\na.sheet, a.level, a.max, a.res = b.sheet, b.level, b.max + K.maxBonus(a), b.res\r\na.hd = math.min(a.hd or b.level, b.level)\r\nif a.hp > 0 then a.hp = math.max(1, math.floor(a.max * share + 0.5)) end\r\nend\r\n\r\n\r\n\r\nfunction Ally.adjList(sh)\r\nlocal adj = type(sh.abAdj) == \"table\" and sh.abAdj or {}\r\nif next(adj) and #adj == 0 then\r\nlocal o = {}\r\nfor ab, d in pairs(adj) do if type(ab) == \"string\" then o[#o + 1] = { ab = ab, d = tonumber(d) or 0, lv = K.charLevel(sh) } end end\r\nadj = o\r\nend\r\nsh.abAdj = next(adj) and adj or nil\r\nreturn adj\r\nend\r\nfunction Ally.putAdj(sh, adj, test)\r\nfor _, x in ipairs(adj) do\r\nif test(tonumber(x.lv) or 1) and sh.scores[x.ab] then sh.scores[x.ab] = math.max(1, math.min(30, (tonumber(sh.scores[x.ab]) or 10) + (tonumber(x.d) or 0))) end\r\nend\r\nend\r\nfunction Ally.dbgScore(a, ab, d)\r\nlocal sh = a.sheet\r\nlocal old = tonumber(sh.scores[ab]) or 10\r\nlocal new = math.max(1, math.min(30, old + d))\r\nif new == old then return end\r\nsh.scores[ab] = new\r\n\r\nlocal adj = Ally.adjList(sh)\r\nadj[#adj + 1] = { ab = ab, d = new - old, lv = K.charLevel(sh) }\r\nsh.abAdj = adj\r\nAlly.with(a, function() refitHp(sh, a); Feat.fillRes(a) end)\r\nend\r\n\r\n\r\nfunction Ally.sync(pc)\r\nfor _, a in ipairs(Ally.list(pc)) do\r\nlocal lv = Ally.levelFor(pc, a)\r\nif K.charLevel(a.sheet) ~= lv then Ally.setLevel(a, lv) end\r\nend\r\nend\r\n\r\n\r\nfunction Ally.lvOffOf(v, pc)\r\nv = trim(v or \"\")\r\nlocal sign, d = v:match(\"^([+-])%s*(%d+)$\")\r\nif sign then return (sign == \"-\" and -1 or 1) * tonumber(d) end\r\nlocal n = v:match(\"^[Ll][Vv]%.?%s*(%d+)$\") or v:match(\"^[Ll]evel%s*(%d+)$\") or v:match(\"^(%d+)%s*레벨$\") or v:match(\"^(%d+)$\")\r\nif n then return tonumber(n) - (tonumber(pc.level) or 1) end\r\nreturn nil\r\nend\r\n\r\n\r\n\r\n\r\n\r\nfunction Ally.wield(a, name, fight)\r\nlocal w, ar = gearOf(a, name)\r\nlocal eq = a.equip\r\nif ar and ar.cat == \"shield\" then\r\nlocal mw = gearOf(a, eq.main)\r\nif not armorProf(\"shield\") or (mw and mw.two) then return nil end\r\nif eq.off and K.MI.cursedHold(a, eq.off) then return nil end\r\n\r\nif K.isShield(a, eq.off) then\r\nlocal _, _, pNew = gearOf(a, name)\r\nlocal _, _, pOld = gearOf(a, eq.off)\r\nif (pNew or 0) <= (pOld or 0) then return nil end\r\nend\r\neq.off = name\r\nreturn \"off\"\r\nelseif ar then\r\nif fight or not armorProf(ar.cat) then return nil end\r\nif eq.armor and K.MI.cursedHold(a, eq.armor) then return nil end\r\nlocal was = eq.armor\r\nlocal before = pcStats(a).ac\r\neq.armor = name\r\nif pcStats(a).ac < before then eq.armor = was; return nil end\r\nreturn \"armor\"\r\nelseif w then\r\nif not weaponProf(w) then return nil end\r\nif (eq.main and K.MI.cursedHold(a, eq.main)) or (eq.off and K.MI.cursedHold(a, eq.off)) then return nil end\r\nlocal old = eq.main\r\neq.main = name\r\nif w.two then\r\neq.off = nil\r\nelseif eq.off and not K.isShield(a, eq.off) and not (w.light and gearOf(a, eq.off) and gearOf(a, eq.off).light) then\r\neq.off = nil\r\nend\r\nif eq.off == old then eq.off = nil end\r\nif w.ammo and (a.items[w.ammo] or 0) < 1 then a.items[w.ammo] = 20 end\r\nreturn \"main\"\r\nend\r\nreturn nil\r\nend\r\n\r\n\r\n\r\nfunction K.slotsLeft(rec)\r\nif K.LITE or type(rec) ~= \"table\" then return nil end\r\nlocal o = {}\r\nfor l = 1, 9 do\r\nlocal r = PC.res[\"Spell Slot \" .. l]\r\nif r and not r.virtual then o[#o + 1] = l .. \": \" .. (tonumber((rec.res or {})[\"Spell Slot \" .. l]) or 0) end\r\nend\r\nreturn #o > 0 and (\"Spell slots left by level: \" .. table.concat(o, \", \")) or nil\r\nend\r\nfunction K.slotsRule(rec)\r\nlocal sl = K.slotsLeft(rec)\r\nif not sl then return \"\" end\r\nreturn \" \" .. sl .. \". With no slot left at a spell's level, cast it at the lowest higher level that has one: write that level and its\"\r\n.. \" higher-level dice (Lua does it itself when a lower level is written, and says so).\"\r\nend\r\n\r\n\r\nfunction Ally.move(pc, from, to, name, n, fight)\r\nlocal chd = K.MI.cursedHold(from, name)\r\nif chd then return false, chd end\r\nfrom.items, to.items = from.items or {}, to.items or {}\r\nlocal have = from.items[name] or 0\r\nif have < n then return false, \"has \" .. have end\r\nfrom.items[name] = have - n > 0 and (have - n) or nil\r\nto.items[name] = (to.items[name] or 0) + n\r\nif isLoot(from, name) then\r\nto.loot = type(to.loot) == \"table\" and to.loot or {}\r\nto.loot[name] = to.loot[name] or deepCopy(from.loot[name])\r\n\r\nif to.loot[name].attuned and not ((to.items[name] or 0) > n) then to.loot[name].attuned = nil end\r\nend\r\nif type(from.wear) == \"table\" and from.wear[name] and not from.items[name] then\r\nto.wear = type(to.wear) == \"table\" and to.wear or {}\r\nto.wear[name], from.wear[name] = from.wear[name], nil\r\nend\r\nif from == pc then fixEquip(from) else Ally.with(from, fixEquip, from) end\r\ndropLoot(from, name)\r\nlocal slot\r\nif to ~= pc then slot = Ally.with(to, Ally.wield, to, name, fight) end\r\nreturn true, slot\r\nend\r\n\r\n\r\nfunction Ally.gearList(rec)\r\nlocal out = {}\r\nfor name, n in pairs(type(rec) == \"table\" and rec.items or {}) do\r\nlocal w, ar = gearOf(rec, name)\r\n\r\n\r\nlocal l = isLoot(rec, name) and rec.loot[name]\r\nif (w or ar or (l and not l.consumable)) and (tonumber(n) or 0) > 0 then out[#out + 1] = name end\r\nend\r\ntable.sort(out)\r\nreturn out\r\nend\r\n\r\n\r\nfunction K.give(f, pc, c, persona)\r\nlocal head = \"[GIVE|\" .. table.concat({ f[1] or \"\", f[2] or \"\", f[3] or \"\", f[4] or \"1\" }, \"|\")\r\nlocal function fail(why) return head .. \"|bad:\" .. why .. \"|-]\", false end\r\nlocal function rec(v)\r\nlocal who = Canon.actor(trim(v or \"\"), persona)\r\nif who == \"Player\" then return pc, \"Player\" end\r\nreturn Ally.find(pc, who), who\r\nend\r\nlocal from, fromName = rec(f[1])\r\nlocal to, toName = rec(f[2])\r\nif not from then return fail(\"giver: Player or a companion's name\") end\r\nif not to then return fail(\"receiver: Player or a companion's name\") end\r\nif from == to then return fail(\"the same one\") end\r\nif to ~= pc and to.dead then return fail(toName .. \" is dead\") end\r\nlocal written = Canon.name(trim(f[3] or \"\"))\r\nlocal nm586, each586 = K.itemName(written, from)\r\nif nm586 ~= written then\r\nf[3] = nm586\r\nif each586 then f[4] = tostring((tonumber(f[4] or \"1\") or 1) * each586) end\r\nhead = \"[GIVE|\" .. table.concat({ f[1] or \"\", f[2] or \"\", f[3] or \"\", f[4] or \"1\" }, \"|\")\r\nend\r\nlocal name = K.lootName(from, nm586)\r\nif not ITEMS[name] and not isLoot(from, name) and K.MI.parse(name) then\r\nname = K.MI.canon((K.MI.parse(name)))\r\nend\r\nif not ITEMS[name] and not isLoot(from, name) then\r\nif K.storyGear(name) then return fail(\"story gear: the story carries it (no tag)\") end\r\n\r\nreturn fail(\"unknown item: not in \" .. fromName .. \"'s items (a found one comes in by its LOOT first)\")\r\nend\r\nlocal n = tonumber(f[4] or \"1\") or 0\r\nif n < 1 or n ~= math.floor(n) then return fail(\"count\") end\r\nlocal chd = K.MI.cursedHold(from, name)\r\nif chd then return fail(chd) end\r\nlocal ok, why = Ally.move(pc, from, to, name, n, c.active)\r\nif not ok then return fail(fromName .. \" \" .. why) end\r\nlocal ac = to == pc and pcStats(pc).ac or Ally.with(to, function() return pcStats(to).ac end)\r\nreturn string.format(\"%s|ok|%s|AC %d]\", head, why and (\"worn \" .. why) or \"in the pack\", ac), true\r\nend\r\n\r\n\r\n\r\n\r\nAlly.REST_ORDER = { \"Constitution\", \"Dexterity\", \"Wisdom\", \"Charisma\", \"Intelligence\", \"Strength\" }\r\nAlly.BG_BY = { Strength = \"Soldier\", Dexterity = \"Criminal\", Constitution = \"Soldier\", Intelligence = \"Sage\", Wisdom = \"Acolyte\", Charisma = \"Acolyte\" }\r\nAlly.CDATA = { order = \"ORDER\", bg = \"BG\", skills = \"SKILLS\", expertise = \"EXPERT\", cantrips = \"CANTRIPS\", spells = \"SPELLS\" }\r\nfunction Ally.cdata(cl, key)\r\nlocal c = CLASSES[cl or \"\"]\r\nlocal own = nil\r\nif c and type(c.companion) == \"table\" then own = c.companion[key] end\r\nif own ~= nil then return own end\r\nlocal t = Ally[Ally.CDATA[key] or \"\"]\r\nif type(t) == \"table\" and t[cl] then return t[cl] end\r\nif not c then return nil end\r\nif key == \"order\" then\r\nlocal o, seen = {}, {}\r\nfor _, list in ipairs({ c.primary or {}, Ally.REST_ORDER }) do\r\nfor _, a in ipairs(list) do if not seen[a] then o[#o + 1], seen[a] = a, true end end\r\nend\r\nreturn o\r\nelseif key == \"bg\" then\r\nreturn Ally.BG_BY[(c.primary or {})[1] or \"\"] or \"Soldier\"\r\nelseif key == \"skills\" then\r\nreturn (c.skills or {}).from or {}\r\nelseif (key == \"cantrips\" or key == \"spells\") and c.spell_ability then\r\n\r\nlocal o = {}\r\nfor n, sp in pairs(SPELLS) do\r\nlocal on = false\r\nfor _, k in ipairs(sp.classes or {}) do if k == cl then on = true end end\r\nif on and ((key == \"cantrips\") == (sp.level == 0)) then o[#o + 1] = n end\r\nend\r\ntable.sort(o, function(x, y) return SPELLS[x].level < SPELLS[y].level or (SPELLS[x].level == SPELLS[y].level and x < y) end)\r\nreturn o\r\nend\r\nreturn {}\r\nend\r\n\r\n\r\nAlly.CLASS_WORDS = { warrior = \"Fighter\", soldier = \"Fighter\", guard = \"Fighter\", infantry = \"Fighter\", spearman = \"Fighter\",\r\nmercenary = \"Fighter\", sellsword = \"Fighter\", knight = \"Paladin\", archer = \"Ranger\", hunter = \"Ranger\",\r\nscout = \"Ranger\", priest = \"Cleric\", healer = \"Cleric\", acolyte = \"Cleric\", mage = \"Wizard\", thief = \"Rogue\",\r\n[\"전사\"] = \"Fighter\", [\"병사\"] = \"Fighter\", [\"경비\"] = \"Fighter\", [\"보초\"] = \"Fighter\", [\"창병\"] = \"Fighter\",\r\n[\"용병\"] = \"Fighter\", [\"기사\"] = \"Paladin\", [\"궁수\"] = \"Ranger\", [\"사냥꾼\"] = \"Ranger\", [\"사제\"] = \"Cleric\",\r\n[\"성직자\"] = \"Cleric\", [\"마법사\"] = \"Wizard\", [\"도적\"] = \"Rogue\" }\r\nfunction Ally.classOf(v)\r\nlocal cl = Canon.name(trim(v or \"\"))\r\nif CLASSES[cl] then return cl end\r\nfor w in (v or \"\"):gmatch(\"[^%s,/]+\") do\r\nlocal c2 = Canon.name(w)\r\nif CLASSES[c2] then return c2 end\r\nlocal x = Ally.CLASS_WORDS[w:lower()] or Ally.CLASS_WORDS[w]\r\nif x then return x end\r\nend\r\nreturn nil\r\nend\r\n\r\n\r\n\r\nK.COST_RULE = \"A spell marked \\\"needs\\\" a material with a GP value works only with that item on hand (a focus does not stand in\"\r\n.. \" for it), and a consumed one is used up by the casting. Lua does not track these: judge from the story whether the caster has\"\r\n.. \" it, and without it the spell is not cast (say so in a [GM|...] note).\"\r\n\r\nK.ALLY_NAME = \" Name: never a monster stat block's name (Raven, Wolf, Mage…: fight tags would mix them up); the name as the prose writes it is safest.\"\r\n\r\n\r\n\r\nfunction Ally.renote(f, pc)\r\nlocal name = trim(((f[1] or \"\"):gsub(\"^%s*=\", \"\")))\r\nlocal head = \"[ALLY|\" .. table.concat(f, \"|\")\r\nlocal a = Ally.find(pc, name)\r\nif not a then return head .. \"|bad:not a companion|-]\", false end\r\nif a.dead then return head .. \"|bad:\" .. name .. \" is dead|-]\", false end\r\nlocal note = trim((f[2] or \"\"):gsub(\"[%^;]\", \"\"))\r\nif note == \"\" or note == \"-\" then return head .. \"|bad:write the new note|-]\", false end\r\nlocal cut = utf8.offset(note, 81)\r\nif cut then note = note:sub(1, cut - 1) end\r\na.note = note\r\nreturn head .. \"|ok|note]\", true\r\nend\r\n\r\nfunction Ally.verify(f, pc, c, persona)\r\nif (f[1] or \"\"):match(\"^%s*=\") then return Ally.renote(f, pc) end\r\n\r\n\r\nif f[1] and not f[1]:match(\"^%s*[+-]\") and trim(f[1]) ~= \"\" and not Ally.find(pc, trim(f[1])) then f[1] = \"+\" .. trim(f[1]) end\r\n\r\nlocal lvOff = #f >= 5 and Ally.lvOffOf(f[#f], pc) or nil\r\nif (f[1] or \"\"):match(\"^%s*%+\") and not K.species(f[2] or \"\") and Ally.classOf(f[2]) then\r\nlocal cl = CLASSES[Canon.name(trim(f[3] or \"\"))] and Canon.name(trim(f[3])) or Ally.classOf(f[2])\r\nlocal note = CLASSES[Canon.name(trim(f[3] or \"\"))] and (f[4] or \"\") or (f[3] or \"\")\r\nf = { f[1], \"Human\", cl, note }\r\nend\r\nif (f[1] or \"\"):match(\"^%s*%+\") and K.species(f[2] or \"\") and not CLASSES[Canon.name(f[3] or \"\")] and Ally.classOf(f[3]) then\r\nf[3] = Ally.classOf(f[3])\r\nend\r\nlocal sign, name = (f[1] or \"\"):match(\"^%s*([+-])%s*(.-)%s*$\")\r\nlocal head = \"[ALLY|\" .. table.concat(f, \"|\")\r\nlocal function fail(why) return head .. \"|bad:\" .. why .. \"|-]\", false end\r\nif not sign or name == \"\" then return fail(\"write +Name or -Name\") end\r\nif c.active then return fail(\"not during a fight\") end\r\npc.allies = Ally.list(pc)\r\nif sign == \"-\" then\r\nfor i, a in ipairs(pc.allies) do\r\nif a.name == name then\r\ntable.remove(pc.allies, i)\r\n\r\n\r\nif not a.dead then\r\na.guest, a.parted = true, true\r\npc.guests = type(pc.guests) == \"table\" and pc.guests or {}\r\npc.guests[#pc.guests + 1] = a\r\nwhile #pc.guests > 6 do table.remove(pc.guests, 1) end\r\nend\r\nreturn head .. \"|ok|left]\", true\r\nend\r\nend\r\nreturn fail(\"not a companion\")\r\nend\r\nlocal kind = name:match(\"^(.-) %d+$\")\r\n\r\n\r\nif name:find(\"[/|%[%]]\") then return fail(\"no / [ ] in a name\") end\r\nif Canon.actor(name, persona) == \"Player\" then return fail(name .. \" is Player: the companion needs a name of its own\") end\r\nif K.monKind(name) then\r\nreturn fail(name .. \" is also a monster stat block's name, which fight tags would mix up: write the companion's name another way,\"\r\n.. \" with a family name or in Korean (\" .. name .. \" Ashe, or the Korean the story uses)\")\r\nend\r\nlocal cap = K.PCAP or Ally.MAX\r\nlocal guest = Ally.isGuest(pc, name)\r\nif guest then\r\n\r\nif Ally.size(pc) - 1 >= cap then return fail(\"party full: the settings allow \" .. cap .. \" companions\") end\r\nfor i, g in ipairs(pc.guests) do if g == guest then table.remove(pc.guests, i) break end end\r\nguest.guest, guest.parted = nil, nil\r\nif Ally.levelFor(pc, guest) ~= K.charLevel(guest.sheet) then Ally.setLevel(guest, Ally.levelFor(pc, guest)) end\r\nif (guest.note or \"\") == \"\" then guest.note = trim((f[4] or \"\"):gsub(\"[%^;]\", \"\")) end\r\npc.allies[#pc.allies + 1] = guest\r\nlocal gst = Ally.with(guest, pcStats, guest)\r\nreturn string.format(\"%s|ok|%s %s %d|HP %d AC %d]\", head, guest.sheet.species, guest.sheet.class, guest.level, guest.max, gst.ac), true\r\nend\r\nif Ally.find(pc, name) then return fail(\"already a companion\") end\r\nif Ally.size(pc) - 1 >= cap then return fail(\"party full: the settings allow \" .. cap .. \" companions\") end\r\nlocal sp, pk = K.species(f[2])\r\nlocal cl = Canon.name(f[3] or \"\")\r\nif not sp then return fail(\"species\") end\r\nif K.d2need(SPECIES[sp]) then return fail(\"species \" .. sp .. \" is \" .. K.D2_WHY[K.d2need(SPECIES[sp])]) end\r\nif not CLASSES[cl] then return fail(\"class: one of this game's classes (\" .. table.concat(K.classNames(), \", \") .. \")\") end\r\nif K.d2need(CLASSES[cl]) then return fail(\"class \" .. cl .. \" is \" .. K.D2_WHY[K.d2need(CLASSES[cl])]) end\r\nlocal note = trim((f[4] or \"\"):gsub(\"[%^;]\", \"\"))\r\nlocal cut = utf8.offset(note, 81)\r\nif cut then note = note:sub(1, cut - 1) end\r\nlocal a = Ally.build(name, sp, cl, note, 1, pk)\r\na.lvOff = lvOff and math.max(-Ally.LV_SPREAD, math.min(Ally.LV_SPREAD, lvOff)) or nil\r\nAlly.setLevel(a, Ally.levelFor(pc, a))\r\npc.allies[#pc.allies + 1] = a\r\nlocal st = Ally.with(a, pcStats, a)\r\nreturn string.format(\"%s|ok|%s %s %d|HP %d AC %d]\", head, sp, cl, a.level, a.max, st.ac), true\r\nend\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\nfunction K.canCast(r, name)\r\nlocal sp = SPELLS[name]\r\nif not sp then return false, \"not a spell\" end\r\nif not Spell.known(name) then return false, \"not among its spells\" end\r\nif sp.level == 0 then return true end\r\nlocal res = type(r.res) == \"table\" and r.res or {}\r\nlocal x = Feat.extras(SHEET)[name]\r\nif x and (x.atwill or ((x.free or x.only) and (res[x.free] or 0) > 0)) then return true end\r\nif (res[name .. \" (free)\"] or 0) > 0 then return true end\r\nfor l = sp.level, 9 do if (res[\"Spell Slot \" .. l] or 0) > 0 or (res[\"Pact Slot \" .. l] or 0) > 0 then return true end end\r\nreturn false, \"no spell slot left\"\r\nend\r\n\r\n\r\n\r\n\r\n\r\n\r\nK.ASK_AFTER = { \"을\", \"를\", \"부터\", \"은\", \"는\", \"도\", \"만\", \"이\", \"가\", \"으로\", \"로\", \" 주문\", \",\", \"!\" }\r\nfunction K.userAsk(said, a, pc)\r\nlocal s = tostring(said or \"\")\r\nlocal i\r\nlocal from = 1\r\nwhile true do\r\nlocal j = s:find(a.name, from, true)\r\nif not j then break end\r\ni, from = j, j + 1\r\nend\r\nif not i then return nil end\r\nlocal seg = s:sub(i + #a.name)\r\nlocal stop = #seg + 1\r\nfor _, b in ipairs(Ally.list(pc)) do\r\nlocal j = b ~= a and seg:find(b.name, 1, true)\r\nif j and j < stop then stop = j end\r\nend\r\nfor _, mark in ipairs({ \".\", \"!\", \"?\", \"\\n\" }) do\r\nlocal j = seg:find(mark, 1, true)\r\nif j and j < stop then stop = j end\r\nend\r\nseg = seg:sub(1, stop - 1)\r\nlocal known = {}\r\nAlly.with(a, function() for _, n in ipairs(Spell.names()) do known[n] = true end end)\r\nlocal best, at\r\nfor name in pairs(SPELLS) do\r\nfor _, w in ipairs({ name, NAMES_KO[name] }) do\r\nlocal len = type(w) == \"string\" and (utf8.len(w) or #w) or 0\r\nif len >= 2 and (known[name] or len >= 3) then\r\nlocal from = 1\r\nwhile true do\r\nlocal j = seg:find(w, from, true)\r\nif not j then break end\r\nlocal rest = seg:sub(j + #w)\r\nlocal ok = w == name or rest:match(\"^%s*$\") ~= nil\r\nfor _, p in ipairs(K.ASK_AFTER) do if rest:sub(1, #p) == p then ok = true end end\r\nif ok then\r\nif not at or j < at then best, at = name, j end\r\nbreak\r\nend\r\nfrom = j + 1\r\nend\r\nend\r\nend\r\nend\r\nreturn true, best\r\nend\r\n\r\nfunction Ally.plan(pc, c, said)\r\nlocal foes = {}\r\nfor _, name in ipairs(c.order or {}) do\r\nlocal u = c.units[name]\r\n\r\nlocal ko = type(u) == \"table\" and type(u.cond) == \"table\" and type(u.cond.Unconscious) == \"table\" and u.cond.Unconscious.ko\r\nif u and u.side == \"enemy\" and u.hp > 0 and MONSTERS[u.kind] and not ko then foes[#foes + 1] = { name = name, u = u, m = MONSTERS[u.kind] } end\r\nend\r\nif #foes == 0 then return nil end\r\ntable.sort(foes, function(x, y)\r\nif x.u.hp ~= y.u.hp then return x.u.hp < y.u.hp end\r\nreturn x.name < y.name\r\nend)\r\nlocal target = foes[1]\r\n\r\nlocal hurt\r\nlocal party = { { name = \"Player\", r = pc } }\r\nfor _, a in ipairs(Ally.list(pc)) do party[#party + 1] = { name = a.name, r = a } end\r\nfor _, p in ipairs(party) do\r\nlocal r = p.r\r\nif not r.dead and (tonumber(r.max) or 0) > 0 then\r\nlocal share = r.hp <= 0 and -1 or r.hp / r.max\r\nif share <= 1 / 3 and (not hurt or share < hurt.share) then hurt = { name = p.name, r = r, share = share } end\r\nend\r\nend\r\nlocal function avg(formula)\r\nlocal p = parseFormula(formula or \"\")\r\nif not p then return 0 end\r\nlocal s = p.mod\r\nfor _, d in ipairs(p.dice) do s = s + d.n * (d.s + 1) / 2 end\r\nreturn s\r\nend\r\nlocal function chance(x) return math.max(0.05, math.min(0.95, x)) end\r\nlocal lines = {}\r\nfor _, a in ipairs(Ally.list(pc)) do\r\nif not a.dead and a.hp > 0 and not Cond.fx(a).incap then\r\n\r\nlocal function pick() return Ally.with(a, function()\r\nlocal parts, sh = {}, SHEET\r\nlocal function slotFrom(lv)\r\n\r\nfor l = lv, 9 do if (a.res[\"Spell Slot \" .. l] or 0) > 0 or (a.res[\"Pact Slot \" .. l] or 0) > 0 then return l end end\r\nreturn nil\r\nend\r\nif hurt then\r\n\r\nlocal heal = K.cl(sh, \"Paladin\") > 0 and (a.res[\"Lay On Hands\"] or 0) > 0 and \"Lay On Hands\" or nil\r\nfor _, n in ipairs({ \"Healing Word\", \"Cure Wounds\" }) do\r\nif not heal and SPELLS[n] and Spell.known(n) and slotFrom(SPELLS[n].level) then heal = n end\r\nend\r\nif not heal and K.cl(sh, \"Cleric\") >= 2 and (a.res[\"Channel Divinity\"] or 0) > 0 then heal = \"Divine Spark\" end\r\nif heal then\r\nparts[#parts + 1] = string.format(\"%s on %s (%s)\", heal, hurt.name, hurt.r.hp <= 0 and \"down\" or (hurt.r.hp .. \"/\" .. hurt.r.max))\r\nhurt = nil\r\n\r\nif heal == \"Cure Wounds\" or heal == \"Divine Spark\" then return parts[1] end\r\nend\r\nend\r\nif K.cl(sh, \"Fighter\") > 0 and a.hp <= a.max / 2 and (a.res[\"Second Wind\"] or 0) > 0 then parts[#parts + 1] = \"Second Wind (Bonus Action)\" end\r\nif K.cl(sh, \"Barbarian\") > 0 and not (type(a.mode) == \"table\" and a.mode.name == \"Rage\") and (a.res[\"Rage\"] or 0) > 0 then\r\nparts[#parts + 1] = \"Rage (Bonus Action)\"\r\nend\r\n\r\n\r\n\r\nlocal style = (K.ALLY_STYLE == \"save\" or K.ALLY_STYLE == \"bold\") and K.ALLY_STYLE or \"normal\"\r\nlocal undead = 0\r\nfor _, x in ipairs(foes) do if x.m.undead then undead = undead + 1 end end\r\nif K.cl(sh, \"Cleric\") >= 2 and (a.res[\"Channel Divinity\"] or 0) > 0 and not c.turned and undead >= (style == \"save\" and 2 or 1)\r\nand not K.replaced(sh, \"Turn Undead\") then\r\nparts[#parts + 1] = \"Turn Undead (Channel Divinity, its action) on every Undead within 30 ft: a HAZARD each, Wisdom save\"\r\nreturn table.concat(parts, \", then \")\r\nend\r\n\r\n\r\n\r\n\r\nlocal best, bestV, sneak, risky, top, topV\r\nlocal ac = target.m.ac or 10\r\nlocal corrodes = target.m.wear\r\nlocal function weigh(name, v, sn, exposed)\r\nlocal r = corrodes and exposed or false\r\nif not topV or v > topV then top, topV = name, v end\r\nif not bestV or (risky and not r) or (r == risky and v > bestV) then best, bestV, sneak, risky = name, v, sn, r end\r\nend\r\nfor _, x in ipairs(pcStats(a).attacks) do\r\nif not x.name:find(\"Bonus Action\", 1, true) then\r\nweigh((x.name:gsub(\" %(spell%)$\", \"\")), chance((21 - (ac - x.hit)) / 20) * avg(x.dmg), x.sneak,\r\nx.weapon and x.melee and not x.magic)\r\nend\r\nend\r\nfor _, n in ipairs(Spell.names()) do\r\nlocal sp = SPELLS[n]\r\nlocal m = sp and sp.m\r\nlocal st = m and Spell.stats(n)\r\nif sp.level == 0 and m and m.kind == \"save\" and m.damage and st then\r\nlocal fail = chance((st.dc - ((target.m.saves or {})[m.save] or 0) - 1) / 20)\r\nweigh(n, (fail + (m.on_save == \"half\" and (1 - fail) / 2 or 0)) * avg(Spell.formula(n, m.damage, 0, m.type)), nil, false)\r\nend\r\nend\r\n\r\n\r\nif style ~= \"save\" then\r\nlocal bs, bsV, bsArea\r\nfor _, n in ipairs(Spell.names()) do\r\nlocal sp = SPELLS[n]\r\nlocal m = sp and sp.m\r\nif sp and sp.level >= 1 and m and m.damage and (m.kind == \"save\" or m.kind == \"attack\" or m.kind == \"auto\") and m.cast ~= \"reaction\"\r\nand m.attack ~= \"weapon\" and not K.SUMMON[n] and not (type(a.conc) == \"table\" and a.conc.name == n) and K.canCast(a, n) then\r\nlocal st = Spell.stats(n)\r\nif st then\r\nlocal dmg = avg(Spell.formula(n, m.damage, sp.level, m.type))\r\nlocal v\r\nif m.kind == \"save\" then\r\nlocal fail = chance((st.dc - ((target.m.saves or {})[m.save] or 0) - 1) / 20)\r\nv = (fail + (m.on_save == \"half\" and (1 - fail) / 2 or 0)) * dmg\r\nelseif m.kind == \"attack\" then\r\nv = chance((21 - (ac - st.atk)) / 20) * dmg * (tonumber(m.rays) or tonumber(m.beams) or 1)\r\nelse\r\nv = dmg * (tonumber(m.darts) or 1)\r\nend\r\nif m.area then v = v * math.min(#foes, 3) end\r\nlocal fits = style == \"bold\" or (m.area and #foes >= 3)\r\nif fits and (not bsV or v > bsV) then bs, bsV, bsArea = n, v, m.area end\r\nend\r\nend\r\nend\r\nif bs and bsV > (bestV or 0) * (style == \"bold\" and 1.2 or 1) then\r\nparts[#parts + 1] = string.format(\"%s (a level %d slot) %s\", bs, SPELLS[bs].level,\r\nbsArea and \"on the enemies close together\" or (\"at \" .. target.name .. string.format(\" (HP %d/%d)\", target.u.hp, target.u.max)))\r\nreturn table.concat(parts, \", then \")\r\nend\r\nend\r\nif best then\r\n\r\n\r\nlocal off\r\nfor _, x in ipairs(pcStats(a).attacks) do if x.offhand then off = x end end\r\nlocal offText = \"\"\r\nif off and type(a.equip) == \"table\" and best == a.equip.main then\r\noffText = string.format(\", then the %s off-hand attack (%s)\", (off.name:gsub(\" %(off%-hand[^%)]*%)$\", \"\")),\r\noff.mastery == \"Nick\" and \"Nick: in the same Attack action\" or \"Bonus Action\")\r\nend\r\nparts[#parts + 1] = string.format(\"%s at %s (HP %d/%d)%s%s%s\", best, target.name, target.u.hp, target.u.max,\r\nsneak and \" with Sneak Attack if an ally is next to it or with Advantage\" or \"\",\r\n(corrodes and best ~= top) and (\", not the \" .. top .. \" (it damages gear)\") or \"\", offText)\r\nend\r\nreturn table.concat(parts, \", then \")\r\nend) end\r\n\r\n\r\n\r\n\r\nlocal named, spell = K.userAsk(said, a, pc)\r\nlocal line\r\nif not named then\r\nline = pick()\r\nelseif spell and type(a.conc) == \"table\" and a.conc.name == spell then\r\nlocal p = pick()\r\nline = spell .. \" is already on (keep concentrating)\" .. ((p and p ~= \"\") and (\"; this turn: \" .. p) or \"\")\r\nelseif spell then\r\nlocal ok, why = Ally.with(a, K.canCast, a, spell)\r\nif ok then\r\nline = spell .. \" (the user asked)\"\r\nelse\r\nlocal p = pick()\r\nline = \"the user asked for \" .. spell .. \", but \" .. a.name .. \" cannot cast it (\" .. tostring(why) .. \")\"\r\n.. ((p and p ~= \"\") and (\"; instead: \" .. p) or \"\")\r\nend\r\nelse\r\nlocal p = pick()\r\nline = \"what the user's message asks, if \" .. a.name .. \" can do it\" .. ((p and p ~= \"\") and (\"; if not: \" .. p) or \"\")\r\nend\r\nif line and line ~= \"\" then lines[#lines + 1] = \"- \" .. a.name .. \": \" .. line end\r\nend\r\nend\r\nif #lines == 0 then return nil end\r\nreturn \"Companion plans for their turns in this reply (Lua's pick from their sheets: play them so, unless the story clearly calls for\"\r\n.. \" something else; if the target is already down, take the weakest enemy left):\\n\" .. table.concat(lines, \"\\n\")\r\nend\r\n\r\n\r\n\r\nfunction Ally.prefix(pc, v, persona)\r\nlocal n, rest = (v or \"\"):match(\"^%s*([^/]-)%s*/%s*(.-)%s*$\")\r\nif not n then return nil, v end\r\nif Canon.actor(n, persona) == \"Player\" then return nil, rest end\r\nreturn Ally.find(pc, n) or false, rest, n\r\nend\r\n\r\n\r\n\r\nfunction Ally.buffs(r, clock)\r\nif type(r.buff) == \"table\" then\r\nfor name, b in pairs(r.buff) do\r\nif type(b) ~= \"table\" or b.ends == -2 or (b.ends and b.ends >= 0 and b.ends <= clock.min)\r\nor (b.conc and not b.concBy and not (type(r.conc) == \"table\" and r.conc.name == name)) then\r\nif type(b) == \"table\" and tonumber(b.maxhp) then\r\nr.max = math.max(1, r.max - b.maxhp)\r\nr.hp = math.min(r.hp, r.max)\r\nend\r\nr.buff[name] = nil\r\nend\r\nend\r\nend\r\nlocal incap = Cond.fx(r).incap\r\nif type(r.conc) == \"table\" and (r.hp <= 0 or (incap and incap ~= \"Incapacitated (a climax)\") or r.conc.lost) then\r\n\r\n\r\nr.concEnd = { name = r.conc.name, why = r.conc.lost and \"broke after damage\" or (r.hp <= 0 and \"ended at 0 HP\") or \"ended when Incapacitated\" }\r\nr.conc = nil\r\nend\r\n\r\n\r\nif type(r.conc) == \"table\" and type(clock) == \"table\" and tonumber(clock.min) then\r\nif not tonumber(r.conc.ends) then r.conc.ends = clock.min + (SPELLS[r.conc.name] and SPELLS[r.conc.name].mins or 1) end\r\nif clock.min >= r.conc.ends then\r\nK.stoneRanOut(r.name or \"Player\", r.conc.name)\r\nr.concEnd = { name = r.conc.name, why = \"ran out\" }; r.conc = nil\r\nend\r\nend\r\n\r\nif type(r.lasting) == \"table\" and type(r.lastingEnds) == \"table\" and type(clock) == \"table\" and tonumber(clock.min) then\r\nfor n, e in pairs(r.lastingEnds) do\r\nif tonumber(e) and clock.min >= e then r.lasting[n], r.lastingEnds[n] = nil, nil end\r\nend\r\nend\r\nif K.AR and K.AR.edgeTick then K.AR.edgeTick(r, K.curPc or r, clock) end\r\nif type(r.scene) == \"table\" and type(clock) == \"table\" and tonumber(clock.min) and clock.min - (tonumber(r.scene.last) or clock.min) > 60 then r.scene = nil end\r\n\r\n\r\nK.timedEnd(r, clock)\r\nif r.form and incap and not r.formBy then r.form, r.formEnds = nil, nil end\r\n\r\nif r.form and type(r.formBy) == \"table\" and (not K.concOn(K.partyPc or r, r.formBy.by or \"Player\", r.formBy.spell) or (tonumber(r.thp) or 0) <= 0) then\r\nr.form, r.formBy, r.formEnds, r.thp = nil, nil, nil, nil\r\nend\r\nif type(r.mode) == \"table\" and tonumber(r.mode.ends) and type(clock) == \"table\" and tonumber(clock.min) and clock.min >= r.mode.ends then r.mode = nil end\r\nif r.zeroAct and ((tonumber(r.hp) or 0) > 0 or r.dead) then r.zeroAct = nil end\r\n\r\nfor n, b in pairs(type(r.buff) == \"table\" and r.buff or {}) do\r\nif type(b) == \"table\" and b.untilR and not (K.curC and K.curC.active and K.curC.fid == b.fid and (tonumber(K.curC.round) or 1) < b.untilR) then r.buff[n] = nil end\r\nend\r\nif r.form and (r.hp <= 0 or r.dead) then r.form, r.formBy = nil, nil end\r\nFeat.downFix(r)\r\nend\r\n\r\n\r\nfunction K.timedEnd(r, clock)\r\nlocal now = type(clock) == \"table\" and tonumber(clock.min)\r\nif not now then return end\r\nif r.bi and tonumber(r.biEnds) and now >= r.biEnds then r.bi, r.biEnds = nil, nil end\r\nif r.form and tonumber(r.formEnds) and now >= r.formEnds then r.form, r.formEnds = nil, nil end\r\nif type(r.mode) == \"table\" and tonumber(r.mode.ends) and now >= r.mode.ends then r.mode = nil end\r\nend\r\nfunction K.timedEnds(pc, clock)\r\nfor _, r in ipairs({ pc, table.unpack(Ally.list(pc)) }) do K.timedEnd(r, clock) end\r\nend\r\n\r\nfunction Ally.fightOver(pc)\r\nfor _, r in ipairs({ pc, table.unpack(Ally.list(pc)) }) do\r\nif not (type(r.mode) == \"table\" and tonumber(r.mode.ends)) then r.mode = nil end\r\nr.lasting = nil\r\nfor n, v in pairs(type(r.cond) == \"table\" and r.cond or {}) do if v == -3 then r.cond[n] = nil end end\r\nif type(r.ar) == \"table\" then r.ar.incapTo, r.ar.incapAt, r.ar.incapWho = nil, nil, nil end\r\nif type(r.ar) == \"table\" then r.ar.edge, r.ar.edgeSince, r.ar.edgeHours, r.ar.edgeGrace = nil, nil, nil, nil end\r\n\r\nif type(r.conc) == \"table\" and (SPELLS[r.conc.name] and SPELLS[r.conc.name].mins or 1) <= 1 then r.conc = nil end\r\n\r\nif type(r.cond) == \"table\" then r.cond.Grappled = nil end\r\n\r\nfor n, b in pairs(type(r.buff) == \"table\" and r.buff or {}) do if type(b) == \"table\" and b.fight then r.buff[n] = nil end end\r\n\r\nif type(r.summons) == \"table\" then\r\nfor i = #r.summons, 1, -1 do\r\nif r.summons[i].short then\r\nif r.mount == r.summons[i].name then r.mount = nil end\r\ntable.remove(r.summons, i)\r\nend\r\nend\r\nend\r\nend\r\nend\r\n\r\n\r\nfunction K.partyStands(pc)\r\nif K.upNow(pc) then return true end\r\nfor _, a in ipairs(Ally.list(pc)) do if K.upNow(a) then return true end end\r\nreturn false\r\nend\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\nK.KIT = \"Healer's Kit\"\r\nK.KIT_USES = 10\r\nfunction K.kitLeft(pc)\r\nlocal n = tonumber(type(pc.items) == \"table\" and pc.items[K.KIT]) or 0\r\nif n < 1 then return 0 end\r\nreturn (n - 1) * K.KIT_USES + math.max(1, math.min(K.KIT_USES, tonumber(pc.kit) or K.KIT_USES))\r\nend\r\nfunction K.kitSpend(pc)\r\nlocal cur = math.max(1, math.min(K.KIT_USES, tonumber(pc.kit) or K.KIT_USES)) - 1\r\nif cur > 0 then pc.kit = cur; return end\r\nlocal n = (tonumber(pc.items[K.KIT]) or 1) - 1\r\npc.items[K.KIT] = n > 0 and n or nil\r\npc.kit = nil\r\nend\r\n\r\nfunction K.healerKit(a, pc, user, persona)\r\nlocal head = \"[USE|\" .. table.concat(a, \"|\")\r\nlocal function fail(why) return head .. \"|bad:\" .. why .. \"|\" .. K.kitLeft(pc) .. \"]\", false end\r\nif K.kitLeft(pc) < 1 then return fail(\"no Healer's Kit in the pack\") end\r\nif user.dead or (tonumber(user.hp) or 0) <= 0 then return fail(\"the one using it is down\") end\r\nlocal tn = Canon.actor(trim(a[2] or \"\"), persona)\r\nlocal tgt = tn == \"Player\" and pc or Ally.find(pc, tn)\r\nif not tgt then return fail(\"target: Player or a companion at 0 HP\") end\r\nif tgt.dead then return fail(tn .. \" is dead\") end\r\nif (tonumber(tgt.hp) or 0) > 0 then return fail(tn .. \" is not at 0 HP\") end\r\nif tgt.stable then return fail(tn .. \" is already Stable\") end\r\nK.kitSpend(pc)\r\ntgt.stable, tgt.ds = true, { s = 0, f = 0 }\r\nreturn string.format(\"%s|ok|%s Stable, kit uses %d]\", head, tn, K.kitLeft(pc)), true\r\nend\r\n\r\nfunction K.stabilize(pc, who)\r\nif type(who) ~= \"table\" or who.dead or (tonumber(who.hp) or 0) <= 0 then return false end\r\nif pc.dead or (tonumber(pc.hp) or 0) > 0 or pc.stable then return false end\r\npc.stable, pc.ds = true, { s = 0, f = 0 }\r\nreturn true\r\nend\r\n\r\n\r\nfunction K.spareBy(pc)\r\nfor _, a in ipairs(Ally.list(pc)) do\r\nif not a.dead and (tonumber(a.hp) or 0) > 0 and type(a.sheet) == \"table\" then\r\nfor _, n in ipairs(a.sheet.cantrips or {}) do if n == \"Spare the Dying\" then return a.name end end\r\nend\r\nend\r\nend\r\n\r\n\r\n\r\nfunction K.wakeCap(pc, c, now)\r\nif K.DEATH ~= \"gentle\" or c.active then return end\r\nlocal cap = math.max(c.endedAt or 0, now) + 60\r\nfor _, r in ipairs({ pc, table.unpack(Ally.list(pc)) }) do\r\nif r.wake then r.wake = math.min(r.wake, cap) end\r\nend\r\nend\r\n\r\n\r\n\r\n\r\nK.COVER_WORD = { half = 2, [\"half cover\"] = 2, [\"절반\"] = 2, [\"절반 엄폐\"] = 2, [\"three-quarters\"] = 5, [\"three quarters\"] = 5,\r\n[\"three-quarters cover\"] = 5, [\"3/4\"] = 5, [\"3/4 엄폐\"] = 5, [\"-\"] = 0, none = 0, [\"없음\"] = 0 }\r\nK.COVER_EN = { [2] = \"Half Cover\", [5] = \"Three-Quarters Cover\" }\r\n\r\nfunction K.coverOf(u)\r\nreturn type(u) == \"table\" and tonumber(u.cover) or 0\r\nend\r\n\r\n\r\nfunction K.coverNote(cov)\r\nreturn (cov or 0) > 0 and string.format(\" (%s +%d)\", K.COVER_EN[cov], cov) or \"\"\r\nend\r\n\r\nfunction K.coverTag(a, c, persona)\r\nlocal head = \"[COVER|\" .. table.concat(a, \"|\")\r\nif not c.active then return head .. \"|bad:no fight|-]\", false end\r\nlocal name = Canon.actor(a[1] or \"\", persona)\r\nlocal u = c.units[name]\r\nif not u then return head .. \"|bad:not in this fight|-]\", false end\r\nlocal cov = K.COVER_WORD[trim(a[2] or \"\"):lower()]\r\nif not cov then return head .. \"|bad:half, three-quarters or -|-]\", false end\r\nu.cover = cov > 0 and cov or nil\r\nreturn head .. \"|ok|\" .. (cov > 0 and (\"+\" .. cov) or \"-\") .. \"]\", true\r\nend\r\n\r\n\r\n\r\n\r\nfunction K.coverAC(cands, base, cov, written)\r\nif cov <= 0 then return base end\r\nlocal melee, ranged = 0, 0\r\nfor _, a in ipairs(cands) do\r\nif (a.weapon and a.melee and not a.thrown) or a.srange == \"melee\" then melee = melee + 1\r\nelseif (a.weapon and a.ranged) or a.srange == \"ranged\" then ranged = ranged + 1 end\r\nend\r\nif #cands > 0 and melee == #cands then return base end\r\nif #cands > 0 and ranged == #cands then return base + cov end\r\nreturn (written == base + cov) and (base + cov) or base\r\nend\r\n\r\n\r\n\r\n\r\n\r\nfunction K.foeTargets(c, pc, fresh)\r\nlocal standing = {}\r\nif not pc.dead and (tonumber(pc.hp) or 0) > 0 then standing[#standing + 1] = \"Player\" end\r\nfor _, a in ipairs(Ally.list(pc)) do\r\nif not a.dead and (tonumber(a.hp) or 0) > 0 and c.units[a.name] then standing[#standing + 1] = a.name end\r\nend\r\n\r\nfor _, name in ipairs(c.order or {}) do\r\nlocal u = c.units[name]\r\nlocal g = u and u.side == \"ally\" and u.guest and Ally.isGuest(pc, u.ally)\r\nif (g and not g.dead and (tonumber(g.hp) or 0) > 0) or (u and u.side == \"friend\" and u.hp > 0) then standing[#standing + 1] = name end\r\nend\r\nlocal up = {}\r\nfor _, n in ipairs(standing) do up[n] = true end\r\n\r\nlocal finish = #standing == 0 and K.DEATH == \"srd\" and not pc.dead\r\n\r\n\r\n\r\n\r\nlocal count = {}\r\nif not fresh then\r\nfor _, name in ipairs(c.order or {}) do\r\nlocal u = c.units[name]\r\nif u and u.side == \"enemy\" and u.tgt and up[u.tgt] and (u.hp > 0 or K.foeUp(u)) then count[u.tgt] = (count[u.tgt] or 0) + 1 end\r\nend\r\nend\r\nlocal function pick()\r\nlocal total, w = 0, {}\r\nfor i, n in ipairs(standing) do w[i] = 1 / (1 + (count[n] or 0)); total = total + w[i] end\r\nlocal x = (K.d(32768) - 0.5) / 32768 * total\r\nfor i, n in ipairs(standing) do\r\nx = x - w[i]\r\nif x <= 0 then return n end\r\nend\r\nreturn standing[#standing]\r\nend\r\nlocal changed = false\r\nfor _, name in ipairs(c.order or {}) do\r\nlocal u = c.units[name]\r\nif u and u.side == \"enemy\" then\r\nlocal was = u.tgt\r\nif not (u.hp > 0 or K.foeUp(u)) then\r\nu.tgt = nil\r\nelseif finish then\r\nu.tgt = \"Player\"\r\nelseif #standing == 0 then\r\nu.tgt = nil\r\nelseif fresh or not (u.tgt and up[u.tgt]) then\r\nu.tgt = pick()\r\ncount[u.tgt] = (count[u.tgt] or 0) + 1\r\nend\r\nif u.tgt ~= was then changed = true end\r\nend\r\nend\r\nreturn changed\r\nend\r\n\r\n\r\n\r\n\r\nfunction K.wipeGo(c, pc)\r\nreturn \"decide once what they do: leave, rob the fallen ([GOLD|-amount] or [ITEM|-Name|count]), or take them captive\"\r\nend\r\n\r\n\r\nfunction K.wipeText(c, pc)\r\nreturn \" When nobody on Player's side stands, the enemies' next move is your one choice, from what they are and want:\"\r\n.. \" go on attacking Player, who is down, until Player dies; or stop: write [COMBAT_END|party defeated] at the next enemy's turn,\"\r\n.. \" then \" .. K.wipeGo(c, pc) .. \".\"\r\nend\r\n\r\n\r\nfunction K.fightDone(c, pc)\r\nif pc.dead or (K.DEATH == \"gentle\" and not K.partyStands(pc)) then return true end\r\nfor _, u in pairs(c.units) do\r\n\r\nif u.side == \"enemy\" and K.foeUp(u) then return false end\r\nend\r\nreturn true\r\nend\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\nfunction K.wakeDue(pc, c, clock, ahead, pcOnly)\r\nif c.active then return end\r\nlocal now = K.replyClock or clock.min\r\nK.wakeCap(pc, c, now)\r\nlocal function due(r, isPc)\r\nif r.dead or (tonumber(r.hp) or 0) > 0 or (isPc and not r.stable) then return end\r\nif not r.wake then r.wake = math.max(c.endedAt or 0, now) + 60 * (K.DEATH == \"gentle\" and 1 or K.d(4)) end\r\nif clock.min + (ahead or 0) >= r.wake then\r\nr.hp, r.wake, r.ds = 1, nil, { s = 0, f = 0 }\r\nif isPc then r.stable = false end\r\nend\r\nend\r\ndue(pc, true)\r\nif pcOnly then return end\r\nfor _, a in ipairs(Ally.list(pc)) do due(a, false) end\r\nfor _, a in ipairs(Ally.guests(pc)) do due(a, false) end\r\nend\r\n\r\n\r\nfunction Ally.tick(pc, clock)\r\nlocal all = { table.unpack(Ally.list(pc)) }\r\nfor _, g in ipairs(Ally.guests(pc)) do all[#all + 1] = g end\r\nfor _, a in ipairs(all) do\r\nif a.dead then a.hp = 0 end\r\nCond.expire(a, clock)\r\nAlly.buffs(a, clock)\r\nif a.dead or a.hp > 0 then a.wake = nil end\r\nend\r\nend\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\nK.AR = { DC = 15 }\r\nfunction K.AR.on() return K.PACK.ar ~= nil and not K.LITE end\r\nfunction K.AR.die(sh)\r\nlocal p = type(sh) == \"table\" and type(sh.picks) == \"table\" and sh.picks or {}\r\nlocal h = K.PACK.ar and K.PACK.ar.hist[p.sexhist or \"\"]\r\nlocal d = tonumber(h and h.die) or 8\r\n\r\nfor _, e in ipairs(type(sh) == \"table\" and Feat.fxOf and Feat.fxOf(sh, \"ar_die\") or {}) do d = math.max(d, tonumber(e.die) or 0) end\r\nreturn d\r\nend\r\n\r\n\r\n\r\n\r\nfunction K.AR.histAt(sh, lv)\r\nlocal p = type(sh) == \"table\" and type(sh.picks) == \"table\" and sh.picks or {}\r\nlocal name, best = p.sexhist, -1\r\nfor k, v in pairs(type(sh) == \"table\" and type(sh.histlv) == \"table\" and sh.histlv or {}) do\r\nlocal n = tonumber(k)\r\nif n and n <= lv and n > best and type(v) == \"string\" then name, best = v, n end\r\nend\r\nreturn name\r\nend\r\nfunction K.AR.dieAt(sh, lv)\r\nlocal h = K.PACK.ar and K.PACK.ar.hist[K.AR.histAt(sh, lv) or \"\"]\r\nreturn tonumber(h and h.die) or 8\r\nend\r\nfunction K.AR.histOpen(name, pc)\r\nlocal h = K.PACK.ar and K.PACK.ar.hist[name or \"\"]\r\nreturn h ~= nil and (tonumber(h.xp) or 0) <= (tonumber(type(pc) == \"table\" and pc.xp) or 0)\r\nend\r\n\r\nfunction K.AR.histSet(sh, lv, name)\r\nlocal p = Feat.picks(sh)\r\nif type(p.sexhist) ~= \"string\" or p.sexhist == name or not (K.PACK.ar and K.PACK.ar.hist[name or \"\"]) then return \"\" end\r\nsh.histlv = type(sh.histlv) == \"table\" and sh.histlv or { [\"1\"] = p.sexhist }\r\nsh.histlv[tostring(lv)] = name\r\np.sexhist, p.fetishon = name, nil\r\nreturn \", sexual history \" .. name\r\nend\r\n\r\nfunction K.AR.histDrop(sh, lv)\r\nif type(sh.histlv) ~= \"table\" or sh.histlv[tostring(lv)] == nil then return \"\" end\r\nsh.histlv[tostring(lv)] = nil\r\nlocal p = Feat.picks(sh)\r\np.sexhist, p.fetishon = K.AR.histAt(sh, lv - 1), nil\r\nlocal n = 0\r\nfor _ in pairs(sh.histlv) do n = n + 1 end\r\nif n <= 1 then sh.histlv = nil end\r\nreturn \", its sexual history back to \" .. tostring(p.sexhist)\r\nend\r\nfunction K.AR.names()\r\nlocal o = {}\r\nfor n in pairs(K.PACK.ar and K.PACK.ar.hist or {}) do o[#o + 1] = n end\r\ntable.sort(o)\r\nreturn o\r\nend\r\nfunction K.AR.st(rec)\r\nif type(rec.ar) ~= \"table\" then rec.ar = { cur = 0, used = 0, numb = 0 } end\r\nreturn rec.ar\r\nend\r\nfunction K.AR.sheetOf(rec, pc) return (type(rec) == \"table\" and rec.sheet) or (rec == pc and SHEET) or nil end\r\nfunction K.AR.max(rec, pc)\r\nreturn math.max(1, K.AR.max0(rec, pc))\r\nend\r\nfunction K.AR.max0(rec, pc)\r\nlocal down = K.maxDownOf and K.maxDownOf(rec, \"arousal\") or 0\r\nlocal sh = K.AR.sheetOf(rec, pc)\r\nif not sh then return math.max(1, tonumber(rec.max) or 1) - down end\r\nlocal con = abilityMod(K.score(sh, \"Constitution\"))\r\nif #Feat.fxOf(sh, \"ar_max_no_con\") > 0 then con = 0 end\r\n\r\nlocal total = math.max(1, K.AR.dieAt(sh, 1) + con)\r\nfor lv = 2, K.charLevel(sh) do total = total + math.max(1, math.floor(K.AR.dieAt(sh, lv) / 2) + 1 + con) end\r\nfor _, e in ipairs(Feat.fxOf and Feat.fxOf(sh, \"ar_max\") or {}) do total = total + K.fxNum(e.add or e.at_gain or 0, sh, K.charLevel(sh)) end\r\nreturn total - down\r\nend\r\n\r\n\r\nK.AR.SIZE_DIE = { Tiny = 4, Small = 6, Medium = 8, Large = 10, Huge = 12, Gargantuan = 20 }\r\nfunction K.AR.dieOf(rec, pc)\r\nlocal sh = K.AR.sheetOf(rec, pc)\r\nif sh then return K.AR.die(sh) end\r\nreturn K.AR.SIZE_DIE[K.unitSize(rec)] or 8\r\nend\r\nfunction K.AR.dice(rec, pc)\r\nlocal sh = K.AR.sheetOf(rec, pc)\r\nlocal all = sh and K.charLevel(sh) or math.max(1, math.floor((tonumber(rec.max) or 1) / (K.AR.dieOf(rec, pc) / 2 + 1)))\r\nreturn math.max(0, all - (tonumber(K.AR.st(rec).used) or 0)), all\r\nend\r\n\r\n\r\nK.AR.MENTAL = { Intelligence = true, Wisdom = true, Charisma = true }\r\nfunction K.AR.bestMental(sh)\r\nlocal best, bv = \"Wisdom\", -99\r\nfor _, ab in ipairs({ \"Intelligence\", \"Wisdom\", \"Charisma\" }) do\r\nlocal v = abilityMod(K.score(sh, ab))\r\nif v > bv then best, bv = ab, v end\r\nend\r\nreturn best\r\nend\r\nfunction K.AR.inhibBase(rec, pc)\r\nlocal sh = K.AR.sheetOf(rec, pc)\r\nif sh then\r\nlocal p = type(sh.picks) == \"table\" and sh.picks or {}\r\nlocal ab = K.AR.MENTAL[p.inhib or \"\"] and p.inhib or K.AR.bestMental(sh)\r\nreturn abilityMod(K.score(sh, ab))\r\nend\r\nlocal sv = (MONSTERS[rec.kind or \"\"] or {}).saves\r\nsv = type(sv) == \"table\" and sv or {}\r\nreturn math.max(tonumber(sv.Intelligence) or 0, tonumber(sv.Wisdom) or 0, tonumber(sv.Charisma) or 0)\r\nend\r\n\r\n\r\n\r\nfunction K.AR.inhib(rec, pc)\r\nlocal v = K.AR.inhibBase(rec, pc)\r\nlocal sh = K.AR.sheetOf(rec, pc)\r\nif sh and Feat.fxOf then\r\nlocal mode = type(rec.mode) == \"table\" and rec.mode.name\r\nfor _, e in ipairs(Feat.fxOf(sh, \"inhib\")) do\r\nif not e.mode or e.mode == mode then\r\nif e.set ~= nil then v = K.fxNum(e.set, sh, e.srcLv) end\r\nif e.add ~= nil then v = v + K.fxNum(e.add, sh, e.srcLv) end\r\nend\r\nend\r\nfor _, x in ipairs(K.afflictOn(sh)) do\r\nif x.rec.kind == \"brand\" then v = v - (tonumber(x.e.level) or tonumber(x.rec.level) or 1) end\r\nend\r\nend\r\nlocal a = type(rec) == \"table\" and type(rec.ar) == \"table\" and rec.ar\r\nlocal zeroBy\r\nif a and type(a.inhibAdj) == \"table\" then\r\nlocal total, floor = 0, nil\r\nlocal now = K.clockRef and tonumber(K.clockRef.min)\r\nfor by, n in pairs(a.inhibAdj) do\r\nlocal sp = SPELLS[by]\r\n\r\nif now and type(a.inhibEnds) == \"table\" and tonumber(a.inhibEnds[by]) and now >= a.inhibEnds[by] then a.inhibAdj[by], n = nil, 0 end\r\n\r\nlocal rr = type(a.inhibR) == \"table\" and a.inhibR[by]\r\nif type(rr) == \"table\" then\r\nlocal cc = K.curC\r\nlocal live = cc and cc.active and cc.fid == rr.fid\r\nif live and rr.at then\r\nlocal r1, i1 = K.AR.turnAt(cc, rr.who)\r\nlocal cur = tonumber(cc.round) or 1\r\n\r\nlocal nowI = 0\r\nfor k2, nm in ipairs(type(cc.order) == \"table\" and cc.order or {}) do if nm == K.AR.turnNow(cc) then nowI = k2 end end\r\nlive = cur < rr.to or (cur == rr.to and nowI < (tonumber(rr.at) or 0))\r\nelseif live then live = (tonumber(cc.round) or 1) < (tonumber(rr.to) or 0) end\r\nif not live then a.inhibAdj[by], n, a.inhibR[by] = nil, 0, nil; if type(a.inhibZero) == \"table\" then a.inhibZero[by] = nil end end\r\nend\r\nif type(a.inhibZero) == \"table\" and a.inhibZero[by] and a.inhibAdj[by] ~= nil then zeroBy = by end\r\n\r\nif not (sp and sp.m and sp.m.concentration and not K.AR.spellUp(by, pc, type(a.inhibBy) == \"table\" and a.inhibBy[by] or nil)) then\r\ntotal = total + (tonumber(n) or 0)\r\nlocal mn = tonumber(sp and sp.m and type(sp.m.inhib) == \"table\" and sp.m.inhib.min) or -6\r\nfloor = floor and math.max(floor, mn) or mn\r\nend\r\nend\r\n\r\nif total < 0 then v = math.max(math.min(v, floor or -6), v + total) elseif total > 0 then v = v + total end\r\nif zeroBy then v = 0 end\r\nend\r\n\r\nif type(rec) == \"table\" and type(rec.ar) == \"table\" and K.AR.overHard(rec.ar, rec) >= 3 and v > 0 then v = 0 end\r\nfor _, row in pairs(K.AR.condsOf(rec)) do\r\nlocal cap = tonumber(row.inhib_max)\r\nif cap and v > cap then v = cap end\r\nend\r\nreturn v\r\nend\r\n\r\nfunction K.AR.spellUp(name, pc, by)\r\npc = pc or K.curPc\r\nif not pc then return true end\r\n\r\nlocal br = by and Ally.rec(pc, by)\r\nif br then\r\nlocal sp0 = SPELLS[name]\r\nif sp0 and sp0.m and sp0.m.concentration then return type(br.conc) == \"table\" and br.conc.name == name and not br.conc.lost end\r\nfor _, x in ipairs(Feat.cur.casts or {}) do if x.name == name and (x.by or \"Player\") == by then return true end end\r\nfor _, a in ipairs(Spell.active(br)) do if a.name == name then return true end end\r\nreturn false\r\nend\r\nlocal sp = SPELLS[name]\r\nif not (sp and sp.m and sp.m.concentration) then\r\nfor _, x in ipairs(Feat.cur.casts or {}) do if x.name == name then return true end end\r\nfor _, x in ipairs(Spell.all(pc)) do if x[1].name == name then return true end end\r\nreturn false\r\nend\r\n\r\nfor _, r in ipairs(K.concRecs(pc)) do\r\nif type(r.conc) == \"table\" and r.conc.name == name and not r.conc.lost then return true end\r\nend\r\nreturn false\r\nend\r\n\r\n\r\nfunction K.AR.inhibTag(f, pools, cur, c, pc)\r\nlocal head = \"[INHIB|\" .. table.concat(f, \"|\", 1, math.min(#f, 4))\r\nlocal function no(why)\r\nif (f[3] or \"\"):find(\"d\", 1, true) then K.spendRefused(pools, cur, nil, (f[3] or \"\"):gsub(\"^[+-]\", \"\"), f[4]) end\r\nreturn head .. \"|bad:\" .. why .. \"|-]\", false\r\nend\r\nif not K.AR.on() then return no(\"arousal is not in this game (no module brings it)\") end\r\nlocal t = K.AR.target(f[1], c, pc)\r\nif not t then return no(\"target must be Player, a companion or a creature in the fight\") end\r\nlocal n = Canon.name(f[2] or \"\")\r\nlocal sp = SPELLS[n]\r\n\r\nlocal fe, owner\r\nif not sp then\r\nfor _, r in ipairs(K.concRecs(pc)) do\r\nlocal sh = K.AR.sheetOf(r, pc)\r\nfor _, x in ipairs(sh and Feat.fxOf(sh, \"inhib_src\") or {}) do if x.src == trim(f[2] or \"\") or x.use == trim(f[2] or \"\") then fe, owner = x, r; n = x.src or n end end\r\nend\r\nif not fe then return no(\"source must be a spell or a feature that changes inhibition (\" .. tostring(f[2]) .. \")\") end\r\nelseif not K.AR.spellUp(n, pc) and not (not (sp.m and sp.m.concentration) and type(t.ar) == \"table\" and type(t.ar.inhibAdj) == \"table\" and t.ar.inhibAdj[n]) then\r\nreturn no(n .. \" is not in effect (write its CAST first)\")\r\nend\r\nlocal before = K.AR.inhib(t, pc)\r\nif (f[3] or \"\"):lower() == \"end\" then\r\nlocal a0 = K.AR.st(t)\r\nif type(a0.inhibAdj) == \"table\" then a0.inhibAdj[n] = nil end\r\nreturn head .. \"|ok|\" .. string.format(\"inhibition %+d -> %+d\", before, K.AR.inhib(t, pc)) .. \"]\", true\r\nend\r\nif fe then\r\nlocal w = tonumber(((f[3] or \"\"):gsub(\"%s\", \"\")))\r\nif fe.amount == \"N\" and not fe.zero and not w then return no(\"write the change as a number: -3\") end\r\nif fe.res then\r\nlocal cost = tonumber(fe.cost) or 1\r\nif not (type(owner.res) == \"table\" and (tonumber(owner.res[fe.res]) or 0) >= cost) then return no(\"no \" .. fe.res .. \" left\") end\r\nowner.res[fe.res] = owner.res[fe.res] - cost\r\nend\r\nlocal amt\r\n\r\n\r\nif fe.zero then amt = 0\r\nelseif fe.amount == \"N\" then\r\nlocal mx = fe.max ~= nil and math.abs(K.fxNum(fe.max, K.AR.sheetOf(owner, pc), fe.srcLv)) or math.abs(w)\r\namt = -math.min(math.abs(w), mx)\r\nelse amt = -math.abs(K.fxNum(fe.amount or \"0\", K.AR.sheetOf(owner, pc), fe.srcLv)) end\r\nlocal bad0 = {}\r\nif not fe.zero and w ~= amt then bad0[#bad0 + 1] = \"change \" .. tostring(f[3]) .. \"->\" .. amt end\r\nlocal a0 = K.AR.st(t)\r\na0.inhibAdj = type(a0.inhibAdj) == \"table\" and a0.inhibAdj or {}\r\na0.inhibEnds = type(a0.inhibEnds) == \"table\" and a0.inhibEnds or {}\r\na0.inhibAdj[n] = amt\r\na0.inhibZero = type(a0.inhibZero) == \"table\" and a0.inhibZero or {}\r\na0.inhibZero[n] = fe.zero and true or nil\r\na0.inhibEnds[n] = (K.clockRef and tonumber(K.clockRef.min) or 0) + (tonumber(fe.mins) or 10)\r\n\r\nif tonumber(fe.rounds) and type(c) == \"table\" and c.active then\r\n\r\na0.inhibR = type(a0.inhibR) == \"table\" and a0.inhibR or {}\r\nlocal who = (t == pc and \"Player\") or t.name or f[1]\r\nlocal r0, i0 = K.AR.turnAt(c, who)\r\nlocal nowI = 0\r\nfor k2, nm in ipairs(type(c.order) == \"table\" and c.order or {}) do if nm == K.AR.turnNow(c) then nowI = k2 end end\r\nif i0 == nowI then r0 = r0 + 1 end\r\na0.inhibR[n] = { fid = c.fid, to = r0 + tonumber(fe.rounds) - 1, at = i0, who = who }\r\na0.inhibEnds[n] = (K.clockRef and tonumber(K.clockRef.min) or 0) + 1\r\nend\r\nFeat.cur.inhib0 = Feat.cur.inhib0 or {}\r\nif Feat.cur.inhib0[t] == nil then Feat.cur.inhib0[t] = before end\r\nreturn head .. \"|\" .. verdictOf(bad0) .. \"|\" .. string.format(\"inhibition %+d -> %+d\", before, K.AR.inhib(t, pc)) .. \"]\", #bad0 == 0\r\nend\r\n\r\nFeat.cur.inhib0 = Feat.cur.inhib0 or {}\r\nif Feat.cur.inhib0[t] == nil then Feat.cur.inhib0[t] = before end\r\nif (f[3] or \"\"):lower() == \"vs\" then\r\nif not (sp.m and sp.m.inhib_vs) then return no(n .. \" weighs no inhibition\") end\r\nlocal by = K.castBy(n, pc)\r\nlocal atk = Ally.run(pc, by ~= pc and by or nil, function() local st = Spell.stats(n); return st and st.atk or 0 end)\r\nlocal works = before < atk\r\nreturn head .. \"|ok|\" .. string.format(\"inhibition %+d %s spell attack %+d: %s\", before, works and \"<\" or \">=\", atk, works and \"it works\" or \"no effect\") .. \"]\", true\r\nend\r\nlocal sign, form = (f[3] or \"\"):match(\"^%s*([+-]?)%s*(.-)%s*$\")\r\nlocal p = parseFormula(form or \"\")\r\nif not p then return no(\"write the change: -1d4, +2 or -1\") end\r\nlocal bad = {}\r\nlocal amount = (#p.dice > 0) and spendDice(p, f[4], pools, cur, bad, K.wroteF(form, f[4])) or p.mod\r\namount = (tonumber(amount) or 0) * (sign == \"-\" and -1 or 1)\r\nlocal a = K.AR.st(t)\r\na.inhibAdj = type(a.inhibAdj) == \"table\" and a.inhibAdj or {}\r\na.inhibAdj[n] = (tonumber(a.inhibAdj[n]) or 0) + amount\r\nif not (sp.m and sp.m.concentration) and tonumber(sp.mins) and sp.mins > 0 then\r\na.inhibEnds = type(a.inhibEnds) == \"table\" and a.inhibEnds or {}\r\na.inhibEnds[n] = a.inhibEnds[n] or ((K.clockRef and tonumber(K.clockRef.min) or 0) + sp.mins)\r\nend\r\na.inhibBy = type(a.inhibBy) == \"table\" and a.inhibBy or {}\r\nlocal cb = K.castBy(n, pc)\r\na.inhibBy[n] = cb and ((cb == pc and \"Player\") or cb.name) or nil\r\nlocal after = K.AR.inhib(t, pc)\r\nreturn head .. \"|\" .. verdictOf(bad) .. \"|\" .. string.format(\"inhibition %+d -> %+d\", before, after) .. \"]\", #bad == 0\r\nend\r\n\r\nfunction K.AR.apNote(m)\r\nif not (type(m) == \"table\" and m.approach and K.AR.on() and K.D2.mode == \"hard\") then return \"\" end\r\nreturn \", an approach (a willing target's SAVE ends |willing)\"\r\nend\r\n\r\n\r\nfunction K.AR.saveAdd(t, pc, will, by)\r\nif not K.AR.on() then return 0 end\r\nlocal inh = K.AR.inhib(t, pc)\r\nif by and K.AR.ignores(by, pc) then inh = math.min(0, inh) end\r\nif K.D2.mode == \"hard\" and will ~= \"willing\" then return inh end\r\nreturn math.min(0, inh)\r\nend\r\n\r\n\r\nfunction K.AR.stimHeal(t, amount, src)\r\nif amount <= 0 or type(t.buff) ~= \"table\" or not tonumber(t.hp) or t.hp <= 0 or t.dead then return \"\" end\r\nlocal ty = type(src) == \"table\" and src.type or nil\r\nlocal note = \"\"\r\nfor name in pairs(t.buff) do\r\nlocal sh = SPELLS[name] and SPELLS[name].m and SPELLS[name].m.stim_heal\r\nif type(sh) == \"table\" then\r\nlocal skip = false\r\nfor _, x in ipairs(type(sh.not_types) == \"table\" and sh.not_types or {}) do if x == ty then skip = true end end\r\nlocal n = sh.part == \"all\" and amount or math.floor(amount / 2)\r\nif not skip and n > 0 then\r\nlocal was = t.hp\r\nt.hp = math.min(t.max, t.hp + n)\r\nnote = note .. string.format(\" (%s: +%d HP, %d/%d)\", name, t.hp - was, t.hp, t.max)\r\nend\r\nend\r\nend\r\nreturn note\r\nend\r\n\r\nfunction K.AR.stimHealEnds(t)\r\nif type(t) ~= \"table\" or type(t.buff) ~= \"table\" then return \"\" end\r\nlocal note = \"\"\r\nfor name in pairs(t.buff) do\r\nlocal sh = SPELLS[name] and SPELLS[name].m and SPELLS[name].m.stim_heal\r\nif type(sh) == \"table\" and sh.ends_on_damage then t.buff[name] = nil; note = note .. \" (\" .. name .. \" ends)\" end\r\nend\r\nreturn note\r\nend\r\n\r\n\r\nfunction K.AR.poolFill(t, pc)\r\nlocal note = \"\"\r\nif type(t) ~= \"table\" or not (t == pc or t.sheet) then return note end\r\n\r\nlocal srcs = {}\r\nlocal onSomeone = {}\r\nfor _, r in ipairs(K.concRecs(pc)) do\r\nfor bn in pairs(type(r.buff) == \"table\" and r.buff or {}) do onSomeone[bn] = true end\r\nend\r\nlocal function castLevel(bn)\r\nfor _, r in ipairs(K.concRecs(pc)) do\r\nfor _, a in ipairs(Spell.active(r)) do if a.name == bn then return tonumber(a.level) end end\r\nend\r\nreturn nil\r\nend\r\nfor bn in pairs(type(t.buff) == \"table\" and t.buff or {}) do\r\nlocal sp0 = SPELLS[bn]\r\nif sp0 and sp0.m and type(sp0.m.climax_pool) == \"table\" then srcs[#srcs + 1] = { name = bn, level = castLevel(bn) or sp0.level } end\r\nend\r\nif #srcs == 0 then\r\nfor _, a in ipairs(Spell.active(t)) do if not onSomeone[a.name] then srcs[#srcs + 1] = a end end\r\nend\r\nfor _, a in ipairs(srcs) do\r\nlocal sp = SPELLS[a.name]\r\nlocal cp = sp and sp.m and sp.m.climax_pool\r\nif type(cp) == \"table\" and not a.lost then\r\nlocal n = 0\r\nlocal function roll(txt) local p = parseFormula(txt or \"\"); for _, d in ipairs(p and p.dice or {}) do for _ = 1, d.n do n = n + K.d(d.s) end end; n = n + (p and p.mod or 0) end\r\nroll(cp.dice or \"1d4\")\r\nfor _ = 1, math.max(0, (tonumber(a.level) or sp.level) - sp.level) do roll(cp.per_level) end\r\n\r\nt.arPool = type(t.arPool) == \"table\" and t.arPool or {}\r\nlocal now = K.clockRef and tonumber(K.clockRef.min) or 0\r\nlocal list = type(t.arPool[a.name]) == \"table\" and t.arPool[a.name] or {}\r\nlist[#list + 1] = { n = n, ends = now + (tonumber(cp.mins) or 10) }\r\nt.arPool[a.name] = list\r\nnote = note .. string.format(\" (%s: +%d to give within %d minutes, %d in all)\", a.name, n, tonumber(cp.mins) or 10, K.AR.poolLeft(t, a.name))\r\nend\r\nend\r\nreturn note\r\nend\r\n\r\nfunction K.AR.poolLeft(r, name)\r\nlocal list = type(r.arPool) == \"table\" and r.arPool[name]\r\nif type(list) ~= \"table\" then return 0 end\r\nlocal now = K.clockRef and tonumber(K.clockRef.min) or 0\r\nlocal left, keep = 0, {}\r\nfor _, b in ipairs(list) do\r\nif (tonumber(b.ends) or 0) > now and (tonumber(b.n) or 0) > 0 then left = left + b.n; keep[#keep + 1] = b end\r\nend\r\nr.arPool[name] = keep\r\nreturn left\r\nend\r\nfunction K.AR.poolTake(r, name, n)\r\nfor _, b in ipairs(r.arPool[name] or {}) do\r\nlocal x = math.min(n, b.n)\r\nb.n, n = b.n - x, n - x\r\nif n <= 0 then break end\r\nend\r\nreturn K.AR.poolLeft(r, name)\r\nend\r\nfunction K.AR.poolOf(pc, name)\r\nfor _, r in ipairs(K.concRecs(pc)) do\r\nlocal left = K.AR.poolLeft(r, name)\r\nif left > 0 then return r, left end\r\nend\r\nreturn nil\r\nend\r\n\r\n\r\nfunction K.AR.swapOf(t, pc, c, ignoreUp)\r\nlocal a = type(t) == \"table\" and type(t.ar) == \"table\" and t.ar\r\nlocal sw = a and type(a.swap) == \"table\" and a.swap\r\nif not sw then return nil end\r\nif not ignoreUp and not K.AR.spellUp(sw.spell, pc, sw.by) then a.swap = nil; return nil end\r\nlocal p = K.AR.target(sw.with, c, pc)\r\nif not p or p == t then return nil end\r\nif p.dead or (tonumber(p.hp) or 1) <= 0 then return nil end\r\nreturn p, sw.with\r\nend\r\n\r\nfunction K.AR.swapGift(t, a, pc, c, causer)\r\nlocal partner, pname = K.AR.swapOf(t, pc, c, true)\r\nif not partner or K.AR.swapping then return \"\", \"\" end\r\nlocal sw = a.swap\r\nlocal sp = SPELLS[sw.spell]\r\nlocal m = sp.m.swap\r\nlocal n = 0\r\nlocal function roll(txt) local p = parseFormula(txt or \"\"); for _, d in ipairs(p and p.dice or {}) do for _ = 1, d.n do n = n + K.d(d.s) end end; n = n + (p and p.mod or 0) end\r\nroll(m.climax_stim or \"5d6\")\r\nfor _ = 1, math.max(0, (tonumber(sw.level) or sp.level) - sp.level) do roll(m.per_level) end\r\nK.AR.swapping = true\r\nlocal text, more = K.AR.give(partner, n, pc, c, false, pname, nil, { type = \"Psychic\", magical = true, swapped = true, by = causer })\r\nK.AR.swapping = nil\r\nreturn string.format(\" (%s: %s takes %d Psychic stimulation, %s)\", sw.spell, pname, n, text), more or \"\"\r\nend\r\n\r\nfunction K.AR.bondTag(f, c, pc)\r\nlocal head = \"[BOND|\" .. table.concat(f, \"|\", 1, 3)\r\nlocal function no(why) return head .. \"|bad:\" .. why .. \"|-]\", false end\r\nif not K.AR.on() then return no(\"arousal is not in this game (no module brings it)\") end\r\nlocal me, t = K.AR.target(f[1], c, pc), K.AR.target(f[2], c, pc)\r\nif not me or not t or me == t then return no(\"the caster and its target: Player, companions or creatures in the fight\") end\r\nlocal n = Canon.name(f[3] or \"\")\r\nlocal m = SPELLS[n] and SPELLS[n].m\r\nif not (m and type(m.bond) == \"table\") then return no(tostring(f[3]) .. \" makes no such bond\") end\r\nlocal cast\r\nFeat.cur.bondUsed = Feat.cur.bondUsed or {}\r\nlocal meName = (me == pc and \"Player\") or me.name\r\nfor _, x in ipairs(Feat.cur.casts or {}) do\r\nif x.name == n and not Feat.cur.bondUsed[x] and (x.by or \"Player\") == (meName or \"?\") then cast = x end\r\nend\r\nif not cast then return no(\"write \" .. (f[1] or \"?\") .. \"'s [CAST|\" .. n .. \"|level] first, in this reply (one CAST, one bond)\") end\r\nFeat.cur.bondUsed[cast] = true\r\nlocal by = cast.by and Ally.find(pc, cast.by) or pc\r\nlocal dc = Ally.run(pc, by ~= pc and by or nil, function() local st = Spell.stats(n); return st and st.dc or 13 end)\r\nK.AR.st(me).bond = { with = f[2], spell = n, dc = dc, by = cast.by or \"Player\" }\r\nreturn head .. \"|ok|bound while \" .. n .. \" lasts (save DC \" .. dc .. \")]\", true\r\nend\r\n\r\nfunction K.AR.saveRoll(t, pc, ab)\r\nlocal bonus\r\nif t == pc or (t.name and Ally.find(pc, t.name)) then\r\nbonus = Ally.run(pc, t ~= pc and t or nil, function() return bonusFor(ab .. \" save\") - Cond.fx(t).pen end)\r\nelse\r\nbonus = tonumber(((MONSTERS[t.kind or \"\"] or {}).saves or {})[ab]) or 0\r\nend\r\nlocal d = K.d(20)\r\nreturn d + bonus, d, bonus\r\nend\r\n\r\nfunction K.AR.bondHit(me, pc, c, amount, dice, ending)\r\nlocal a = type(me.ar) == \"table\" and me.ar\r\nlocal b = a and type(a.bond) == \"table\" and a.bond\r\nif not b or K.AR.bonding then return \"\" end\r\nif not ending and not K.AR.spellUp(b.spell, pc, b.by) then a.bond = nil; return \"\" end\r\nlocal t = K.AR.target(b.with, c, pc)\r\nif not t or t.dead or (tonumber(t.hp) or 0) <= 0 then return \"\" end\r\nlocal m = SPELLS[b.spell].m.bond\r\nlocal ab = m.save or \"Constitution\"\r\nlocal total, d, bonus = K.AR.saveRoll(t, pc, ab)\r\nlocal dmg = 0\r\nif total < b.dc then\r\nif dice then for _ = 1, dice do dmg = dmg + K.d(tonumber(m.climax_die) or 6) end else dmg = amount end\r\nend\r\nlocal note = string.format(\" (%s: %s %s save d20 %d%+d vs DC %d, %s\", b.spell, b.with, ab, d, bonus, b.dc, total >= b.dc and \"saved\" or \"failed\")\r\nif dmg > 0 then\r\nlocal ty = m.dmg_type or \"Force\"\r\nlocal tr = (t == pc or (t.name and Ally.find(pc, t.name))) and t or nil\r\nlocal landed, n2\r\nK.AR.bonding = true\r\nif tr then landed, n2 = Feat.adjust(Feat.traits(tr), dmg, ty); n2 = n2 .. hurtPC(tr, landed, false)\r\nelse landed, n2 = Feat.adjust(MONSTERS[t.kind], dmg, ty); n2 = n2 .. K.hurtFoe(t, dmg, landed, ty, false) end\r\nK.AR.bonding = nil\r\nnote = note .. string.format(\": %d %s damage%s, %s\", landed, ty, n2, tr and (tr.hp .. \"/\" .. tr.max) or (t.hp .. \"/\" .. t.max))\r\nend\r\nif dice then a.bond = nil; note = note .. \"; the bond ends\" end\r\nreturn note .. \")\"\r\nend\r\nfunction K.AR.swapTag(f, c, pc)\r\nlocal head = \"[SWAP|\" .. table.concat(f, \"|\", 1, 3)\r\nlocal function no(why) return head .. \"|bad:\" .. why .. \"|-]\", false end\r\nif not K.AR.on() then return no(\"arousal is not in this game (no module brings it)\") end\r\nlocal a1, a2 = K.AR.target(f[1], c, pc), K.AR.target(f[2], c, pc)\r\nif not a1 or not a2 or a1 == a2 then return no(\"two creatures: Player, companions or creatures in the fight\") end\r\nlocal n = Canon.name(f[3] or \"\")\r\nlocal m = SPELLS[n] and SPELLS[n].m\r\nif not (m and type(m.swap) == \"table\") then return no(tostring(f[3]) .. \" binds no sensations\") end\r\nlocal cast\r\nFeat.cur.swapUsed = Feat.cur.swapUsed or {}\r\nfor _, x in ipairs(Feat.cur.casts or {}) do if x.name == n and not Feat.cur.swapUsed[x] then cast = x end end\r\nif not cast then return no(\"write [CAST|\" .. n .. \"|level] first, in this reply (one CAST binds one pair)\") end\r\nFeat.cur.swapUsed[cast] = true\r\nfor _, x in ipairs({ a1, a2 }) do\r\nlocal old = type(x.ar) == \"table\" and type(x.ar.swap) == \"table\" and K.AR.target(x.ar.swap.with, c, pc)\r\nif old and type(old.ar) == \"table\" then old.ar.swap = nil end\r\nend\r\nK.AR.st(a1).swap = { with = f[2], spell = n, level = tonumber(cast.level) or SPELLS[n].level, by = cast.by or \"Player\" }\r\nK.AR.st(a2).swap = { with = f[1], spell = n, level = tonumber(cast.level) or SPELLS[n].level, by = cast.by or \"Player\" }\r\nreturn head .. \"|ok|bound while \" .. n .. \" lasts]\", true\r\nend\r\n\r\n\r\n\r\nfunction K.AR.drain(row, by, tgtR, tgtU, pc, c, tname)\r\nlocal sp = SPELLS[row.spell or \"\"]\r\nlocal dr = sp and sp.m and sp.m.drain\r\nif type(dr) ~= \"table\" then return \"\" end\r\nlocal n = (tonumber(dr.hd) or 1) + (tonumber(dr.per_level) or 0) * math.max(0, (tonumber(row.level) or sp.level) - sp.level)\r\nlocal t = tgtR or tgtU\r\nif (tgtR and (tgtR.dead or (tonumber(tgtR.hp) or 0) <= 0)) or (not tgtR and (tonumber(tgtU.hp) or 0) <= 0) then return \"\" end\r\nlocal sh = tgtR and K.AR.sheetOf(tgtR, pc)\r\nlocal con = sh and abilityMod(K.score(sh, \"Constitution\")) or tonumber(((MONSTERS[tgtU.kind or \"\"] or {}).saves or {}).Constitution) or 0\r\nlocal sum, used = 0, 0\r\nfor _ = 1, n do\r\nif sh and (tonumber(tgtR.hd) or 0) <= 0 then break end\r\nlocal die = sh and K.hdNext(sh, tgtR.hd) or (K.AR.SIZE_DIE[K.unitSize(tgtU)] or 8)\r\nsum = sum + math.max(1, K.d(die) + con)\r\nused = used + 1\r\nif sh then tgtR.hd = tgtR.hd - 1 end\r\nend\r\nif used == 0 then return \" (drain: no Hit Point Dice left)\" end\r\nlocal raw = sum\r\nlocal dmg, note\r\nif tgtR then\r\ndmg, note = Feat.adjust(Feat.traits(tgtR), sum, \"Necrotic\")\r\nnote = note .. hurtPC(tgtR, dmg, false)\r\nelse\r\ndmg, note = Feat.adjust(MONSTERS[tgtU.kind], sum, \"Necrotic\")\r\nnote = note .. K.hurtFoe(tgtU, raw, dmg, \"Necrotic\", false)\r\nend\r\nlocal healed = \"\"\r\nlocal rec = by and (by.side == \"pc\" and pc or by.side == \"ally\" and Ally.find(pc, by.ally) or (by.hp and by.max and by)) or nil\r\nif rec and dmg > 0 and not rec.dead and tonumber(rec.hp) and tonumber(rec.max) then\r\nlocal was = rec.hp\r\nrec.hp = math.min(rec.max, rec.hp + dmg)\r\nhealed = string.format(\"; %s regains %d HP, %d/%d\", rec == pc and \"Player\" or (rec.name or \"the caster\"), rec.hp - was, rec.hp, rec.max)\r\nend\r\nlocal hpNow = tgtR and (tgtR.dead and \"dead\" or (tgtR.hp .. \"/\" .. tgtR.max)) or (tgtU.hp .. \"/\" .. tgtU.max)\r\nreturn string.format(\" (drain: %d Hit Point Di%s, %d Necrotic%s, %s %s%s)\", used, used > 1 and \"ce\" or \"e\", dmg, note, tname or \"the target\", hpNow, healed)\r\nend\r\n\r\n\r\n\r\nfunction K.AR.dmgToStim(r, dmg)\r\nif not K.AR.on() or type(r) ~= \"table\" then return dmg, \"\" end\r\nlocal pcRec = K.curPc or r\r\nif Feat.cur.dtsGuard and Feat.cur.dtsGuard[r] and Feat.cur.dtsGuard[r].once and Feat.cur.dtsGuard[r].used then Feat.cur.dtsGuard[r] = nil end\r\n\r\nlocal g = K.AR.guardOf(r, pcRec)\r\nif g and g.by ~= r and not g.by.dead then\r\nif g.once then Feat.cur.dtsGuard[r] = nil end\r\nlocal sh0 = nil\r\nlocal to = g.by\r\nlocal mercyNote = \"\"\r\nif g.mercy then\r\nlocal m = K.AR.target(g.mercy, K.curC, pcRec)\r\nif m and m ~= g.by and not m.dead then\r\nlocal dc = Ally.run(pcRec, g.by ~= pcRec and g.by or nil, function() local st = Spell.stats(nil); return st and st.dc or 13 end)\r\nlocal tot, d, b = K.AR.saveRoll(m, pcRec, \"Charisma\")\r\nmercyNote = string.format(\"; %s Charisma save d20 %d%+d vs DC %d, %s\", g.mercy, d, b, dc, tot >= dc and \"saved\" or \"failed: it takes it\")\r\nif tot < dc then to = m end\r\nend\r\nend\r\nlocal text, extra = K.AR.give(to, dmg, pcRec, K.curC, false, to == pcRec and \"Player\" or to.name or g.mercy, nil, { type = g.type or \"Psychic\", magical = true, raw = true })\r\nif extra and extra ~= \"\" then Feat.cur.dtsLines = (Feat.cur.dtsLines or \"\") .. extra end\r\nreturn 0, string.format(\" (%s: %s takes the %d damage as stimulation, arousal %s%s)\", g.src, to == pcRec and \"Player\" or (to.name or g.mercy or \"?\"), dmg, text, mercyNote)\r\nend\r\nlocal sh = K.AR.sheetOf(r, r)\r\nif not (sh and Feat.fxOf) then return dmg, \"\" end\r\nFeat.cur.dts = Feat.cur.dts or {}\r\n\r\nlocal dl = type(r.dtsLast) == \"table\" and r.dtsLast\r\nif dl then\r\nlocal cc = K.curC\r\nlocal live = cc and cc.active and dl.fid == cc.fid\r\nif live then\r\nlocal rr, ii = K.AR.turnAt(cc, cc.rt)\r\nlive = rr < dl.untilR or (rr == dl.untilR and ii < dl.untilI)\r\nend\r\nif not live then r.dtsLast = nil\r\nelseif K.curAttacker == dl.from or dl.from == \"*\" then\r\nfor _, e in ipairs(Feat.fxOf(sh, \"dmg_to_stim\")) do\r\nif e.src == dl.src and e.use == dl.use then\r\nlocal part = e.part == \"all\" and dmg or math.floor(dmg / 2)\r\nif part > 0 then\r\nlocal text, extra = K.AR.give(r, part, pcRec, K.curC, false, r == pcRec and \"Player\" or r.name, nil, { type = e.type or \"Force\", magical = true, raw = e.raw })\r\nif extra and extra ~= \"\" then Feat.cur.dtsLines = (Feat.cur.dtsLines or \"\") .. extra end\r\nreturn dmg - part, string.format(\" (%s: %d of it as stimulation, arousal %s)\", e.src or \"dmg_to_stim\", part, text)\r\nend\r\nend\r\nend\r\nend\r\nend\r\nif Feat.cur.dts[r] then return dmg, \"\" end\r\nlocal mode = type(r.mode) == \"table\" and r.mode.name\r\nlocal armed = Feat.cur.dtsArm and Feat.cur.dtsArm[r]\r\nfor _, e in ipairs(Feat.fxOf(sh, \"dmg_to_stim\")) do\r\nlocal paid = not e.res or e.react or (type(r.res) == \"table\" and (tonumber(r.res[e.res]) or 0) > 0)\r\n\r\nlocal on = (not e.react and not e.ally) or (e.react and not e.ally and type(armed) == \"table\" and armed.src == e.src and armed.use == e.use)\r\nif on and (not e.mode or e.mode == mode) and paid then\r\nlocal part = e.part == \"all\" and dmg or math.floor(dmg / 2)\r\nif part > 0 then\r\nFeat.cur.dts[r] = true\r\nif e.res and not e.react then r.res[e.res] = r.res[e.res] - 1 end\r\nif e.lasts and K.curC and (K.curAttacker or e.lasts == \"all\") then\r\nlocal cc = K.curC\r\nlocal me = (r == pcRec or not r.name) and \"Player\" or r.name\r\nlocal r0, i0 = K.AR.turnAt(cc, me)\r\nif r0 == (tonumber(cc.round) or 1) and K.AR.turnNow(cc) == me then r0 = r0 + 1 end\r\nr.dtsLast = { src = e.src, use = e.use, from = e.lasts == \"all\" and \"*\" or K.curAttacker, untilR = r0, untilI = i0, fid = cc.fid }\r\nend\r\nlocal text, extra = K.AR.give(r, part, pcRec, K.curC, false, r == pcRec and \"Player\" or r.name, nil, { type = e.type or \"Force\", magical = true, raw = e.raw })\r\nif extra and extra ~= \"\" then Feat.cur.dtsLines = (Feat.cur.dtsLines or \"\") .. extra end\r\n\r\nif e.lash_back and K.curAttacker then r.lash = { from = K.curAttacker, n = part, src = e.src or \"lash_back\" } end\r\nreturn dmg - part, string.format(\" (%s: %d of it as stimulation, arousal %s)\", e.src or \"dmg_to_stim\", part, text)\r\nend\r\nend\r\nend\r\nreturn dmg, \"\"\r\nend\r\n\r\nfunction K.AR.guardOf(r, pc)\r\nlocal g = Feat.cur.dtsGuard and Feat.cur.dtsGuard[r]\r\nif g then return g end\r\nlocal gl = type(r) == \"table\" and type(r.dtsGuardLast) == \"table\" and r.dtsGuardLast\r\nif not gl then return nil end\r\nlocal cc = K.curC\r\nlocal live = cc and cc.active and gl.fid == cc.fid\r\nif live then\r\nlocal rr, ii = K.AR.turnAt(cc, cc.rt)\r\nlive = rr < gl.untilR or (rr == gl.untilR and ii < gl.untilI)\r\nend\r\nlocal by = live and Ally.rec(pc, gl.byName)\r\nif not by then r.dtsGuardLast = nil; return nil end\r\nreturn { by = by, src = gl.src, type = gl.type }\r\nend\r\n\r\n\r\nfunction K.AR.reactTag(f, c, pc)\r\nlocal head = \"[REACT|\" .. table.concat(f, \"|\", 1, math.min(#f, 3))\r\nlocal function no(why) return head .. \"|bad:\" .. why .. \"|-]\", false end\r\nif not K.AR.on() then return no(\"arousal is not in this game (no module brings it)\") end\r\nlocal r = Ally.rec(pc, f[1] or \"\")\r\nif not r then return no(\"Player or a companion\") end\r\nlocal sh = K.AR.sheetOf(r, pc)\r\nlocal want = trim(f[2] or \"\")\r\nlocal e\r\nfor _, x in ipairs(sh and Feat.fxOf(sh, \"dmg_to_stim\") or {}) do\r\nif (x.react or x.ally) and (x.use == want or x.src == want) then e = x end\r\nend\r\nif not e then return no((f[1] or \"\") .. \" has no reaction \" .. want .. \" that turns damage into stimulation\") end\r\nif e.res and not (type(r.res) == \"table\" and (tonumber(r.res[e.res]) or 0) > 0) then return no(\"no uses of \" .. e.res .. \" left\") end\r\nlocal who = trim(f[3] or \"\")\r\nlocal list = {}\r\nif e.ally then\r\nif who:lower() == \"all\" or who == \"\" then\r\nfor _, x in ipairs(K.concRecs(pc)) do if x ~= r then list[#list + 1] = x end end\r\nelse\r\nlocal x = Ally.rec(pc, who) or (type(c.units) == \"table\" and c.units[who])\r\nif not x or x == r then return no(\"another creature: Player, a companion or one in the fight other than \" .. (f[1] or \"\")) end\r\nlist[1] = x\r\nend\r\nend\r\nlocal slotNote = \"\"\r\nif e.cost_slot == \"pact\" then\r\nlocal k = K.pactSpend(r, pc)\r\nif not k then return no(\"no Warlock spell slot left\") end\r\nslotNote = string.format(\" (%s spent, %d left)\", k, r.res[k])\r\nend\r\nif e.res then r.res[e.res] = r.res[e.res] - 1 end\r\nlocal left = (e.res and string.format(\" (%s %d left)\", e.res, r.res[e.res]) or \"\") .. slotNote\r\nif e.ally then\r\nFeat.cur.dtsGuard = Feat.cur.dtsGuard or {}\r\nlocal mercy = trim(f[4] or \"\") ~= \"\" and trim(f[4]) or nil\r\nlocal untilR, untilI\r\nif e.lasts and c.active then\r\nlocal me = (r == pc or not r.name) and \"Player\" or r.name\r\nuntilR, untilI = K.AR.turnAt(c, me)\r\nif untilR == (tonumber(c.round) or 1) and K.AR.turnNow(c) == me then untilR = untilR + 1 end\r\nend\r\nfor _, x in ipairs(list) do\r\nlocal g = { by = r, src = e.src or want, type = e.type, once = (who:lower() ~= \"all\" and who ~= \"\") and not e.lasts, mercy = mercy }\r\nFeat.cur.dtsGuard[x] = g\r\nif e.lasts and c.active then x.dtsGuardLast = { byName = r == pc and \"Player\" or r.name, src = g.src, type = g.type, untilR = untilR, untilI = untilI, fid = c.fid } end\r\nend\r\nreturn head .. \"|ok|\" .. (#list == 1 and (\"takes \" .. (list[1] == pc and \"Player\" or list[1].name or who) .. \"'s next damage\") or \"takes the allies' damage in this reply\") .. \" as stimulation\" .. left .. \"]\", true\r\nend\r\nFeat.cur.dtsArm = Feat.cur.dtsArm or {}\r\nFeat.cur.dtsArm[r] = e\r\nlocal span = e.lasts == \"all\" and \"every hit on it until the start of its next turn\" or e.lasts and \"the next hit, and that attacker's until the start of its next turn\"\r\nor \"the next damage in this reply\"\r\nreturn head .. \"|ok|\" .. span .. (e.part == \"all\" and \"\" or \", half of it\") .. \" as stimulation\" .. left .. \"]\", true\r\nend\r\n\r\n\r\n\r\nfunction K.AR.overLow(t)\r\nlocal sh = type(t) == \"table\" and K.AR.sheetOf(t, K.curPc or t)\r\nif not (sh and Feat.fxOf) then return 0, nil end\r\nlocal mo = type(t.mode) == \"table\" and t.mode.name\r\nlocal n, src = 0, nil\r\nfor _, e in ipairs(Feat.fxOf(sh, \"overstim_lower\")) do if not e.mode or e.mode == mo then n = n + (tonumber(e.n) or 1); src = src or e.src end end\r\nreturn n, src\r\nend\r\nfunction K.AR.overHard(a, t)\r\nlocal n = tonumber(type(a) == \"table\" and a.overstim) or 0\r\nif t then n = math.max(0, n - K.AR.overLow(t)) end\r\nif K.D2.mode ~= \"hard\" then return math.min(n, 2) end\r\nreturn n\r\nend\r\nfunction K.AR.overAdd(t, pc, c, n, src)\r\nlocal a = K.AR.st(t)\r\nif n > 0 and K.buffHas(t, \"noover\") then return \" (overstimulation: immune)\" end\r\n\r\nlocal osh = K.AR.sheetOf(t, pc)\r\nlocal omode = type(t.mode) == \"table\" and t.mode.name\r\nif n > 0 and osh then\r\nfor _, e in ipairs(Feat.fxOf(osh, \"overstim_immune\")) do if not e.mode or e.mode == omode then return \" (overstimulation: immune, \" .. (e.src or \"overstim_immune\") .. \")\" end end\r\nend\r\nlocal low = K.AR.overLow(t)\r\nlocal was = tonumber(a.overstim) or 0\r\na.overstim = math.max(0, math.min(6 + low, was + n))\r\nif src and n > 0 then a.overSrc = src end\r\nlocal note = string.format(\" (overstimulation %d->%d%s)\", was, a.overstim, low > 0 and string.format(\", counted as %d\", math.max(0, a.overstim - low)) or \"\")\r\nlocal party = t == pc or (t.name and Ally.find(pc, t.name)) or t.sheet\r\nif a.overstim - low < 6 then a.overBadFired = nil end\r\n\r\nif n > 0 and a.overstim - low >= 6 and (was - low < 6 or not a.overBadFired) then\r\na.overBadFired = true\r\nif party then note = note .. K.AR.badEnd(t, pc, c, \"overstimulation 6\")\r\nelse t.hp, t.climaxOut = 0, true; note = note .. \", out of the fight, as one defeated\" end\r\nend\r\nreturn note\r\nend\r\n\r\n\r\nfunction K.AR.badEnd(t, pc, c, why)\r\nt.badEnd = { why = why, at = K.clockRef and tonumber(K.clockRef.min) or 0, level = (K.D2.perm == \"on\" and K.D2.lvdown == \"on\") or nil }\r\nlocal note = \", BAD END (\" .. why .. \")\"\r\nif type(c) == \"table\" and c.active then\r\nt.hp, t.stable = 0, true\r\nnote = note .. \": out of the fight as at 0 HP (Stable)\"\r\nend\r\nif K.D2.perm == \"on\" and K.D2.lvdown == \"on\" then\r\nif t == pc and SHEET and not SHEET.default then\r\nlocal ln, dn = K.levelDown(SHEET, pc)\r\nnote = note .. \"; permanent results on: \" .. ln\r\nt.badEnd.down = dn\r\nt.badDown = dn\r\nelseif t.sheet and K.charLevel(t.sheet) > 1 then\r\nlocal lv = K.charLevel(t.sheet) - 1\r\nt.lvOff = (tonumber(t.lvOff) or 0) - 1\r\nAlly.setLevel(t, lv)\r\nt.badEnd.down = { cls = t.sheet.class, from = lv + 1, to = K.charLevel(t.sheet) }\r\nt.badDown = t.badEnd.down\r\nnote = note .. string.format(\"; permanent results on: level %d->%d\", lv + 1, K.charLevel(t.sheet))\r\nend\r\nend\r\nreturn note\r\nend\r\n\r\nfunction K.knockoutTag(f, c, pc)\r\nlocal head = \"[KNOCKOUT|\" .. (f[1] or \"\")\r\nlocal u = type(c) == \"table\" and c.active and type(c.units) == \"table\" and c.units[trim(f[1] or \"\")]\r\nif not (u and u.side == \"enemy\") then return head .. \"|bad:a creature in the fight|-]\", false end\r\nif not (Feat.cur.dropped and Feat.cur.dropped[u]) then return head .. \"|bad:only right after our melee hit that drops it, in the same reply|-]\", false end\r\nu.ko, u.hp = true, 1\r\nu.cond = type(u.cond) == \"table\" and u.cond or {}\r\nu.cond.Unconscious = { ko = true }\r\nFeat.cur.dropped[u] = nil\r\nreturn head .. \"|ok|knocked out: 1 HP, Unconscious, alive]\", true\r\nend\r\n\r\n\r\n\r\nK.SCORE_UNTIL = { longrest = \"until a Long Rest\", rest = \"until a Short or Long Rest\", longrest_noclimax = \"until a Long Rest with no climax in it\",\r\nrestore = \"until Greater Restoration, Heal or Wish ([SCORE|Target|Ability|end])\" }\r\nfunction K.scoreTag(f, c, pc, clock)\r\nlocal head = \"[SCORE|\" .. table.concat(f, \"|\", 1, math.min(#f, 6))\r\nlocal function no(why) return head .. \"|bad:\" .. why .. \"|-]\", false end\r\nlocal t = K.AR.target(f[1], c, pc)\r\nif not t then return no(\"target: Player, a companion or a creature in the fight\") end\r\nlocal ab = Canon.ability and Canon.ability(f[2] or \"\") or trim(f[2] or \"\")\r\nif not K.score({ scores = {} }, ab) or not ({ Strength = 1, Dexterity = 1, Constitution = 1, Intelligence = 1, Wisdom = 1, Charisma = 1 })[ab] then return no(\"ability: one of the six\") end\r\nlocal rec = (t == pc and SHEET) or t.sheet or t\r\nlocal ch = (f[3] or \"\"):gsub(\"%s\", \"\")\r\nrec.sdrain = type(rec.sdrain) == \"table\" and rec.sdrain or {}\r\nif ch == \"end\" then\r\nif not rec.sdrain[ab] then return no((f[1] or \"\") .. \"'s \" .. ab .. \" is not lowered\") end\r\nrec.sdrain[ab] = nil\r\nK.drainRefit(t, pc)\r\nreturn head .. \"|ok|\" .. ab .. \" back]\", true\r\nend\r\nlocal setv = tonumber(ch:match(\"^=(%d+)$\") or \"\")\r\nif ch == \"=PB\" then\r\nlocal tsh = (t == pc and SHEET) or t.sheet\r\nsetv = tsh and (2 + math.floor((K.charLevel(tsh) - 1) / 4)) or 2\r\nend\r\nlocal n = tonumber(ch:match(\"^(%-%d+)$\") or \"\")\r\nif not setv and not n then return no(\"write -N, =N or end\") end\r\nlocal mn = tonumber(((f[4] or \"\"):match(\"(%d+)\")) or \"\")\r\nlocal u = trim(f[5] or \"\")\r\nif u == \"end\" then u = \"\" end\r\nlocal dn, du = u:match(\"^%+?(%d+)([mhd])$\")\r\nif not (dn or u == \"\" or K.SCORE_UNTIL[u]) then return no(\"until: longrest, rest, longrest_noclimax, restore, +30d, or empty\") end\r\nlocal e = rec.sdrain[ab] or {}\r\nif setv then e.set = math.min(tonumber(e.set) or 30, setv) else e.n = (tonumber(e.n) or 0) + n end\r\nif trim(f[6] or \"\") == \"keep_spell\" then e.keepSpell = true end\r\nif mn then e.min = math.max(tonumber(e.min) or 0, mn) end\r\nif dn then e.ends, e.untilK = (tonumber(clock and clock.min) or 0) + tonumber(dn) * K.TIME_UNIT[du], nil\r\nelseif u ~= \"\" then e.untilK, e.ends = u, nil end\r\nrec.sdrain[ab] = e\r\nK.drainRefit(t, pc)\r\nlocal now = (t == pc or t.sheet) and K.score(rec, ab) or nil\r\nreturn head .. \"|ok|\" .. ab .. (now and (\" \" .. now) or (\" save \" .. string.format(\"%+d\", K.foeDrain(t, ab, ((MONSTERS[t.kind or \"\"] or {}).saves or {})[ab] or 0))))\r\n.. (e.untilK and (\", \" .. K.SCORE_UNTIL[e.untilK]) or tonumber(e.ends) and (\", until \" .. clockEn(e.ends)) or \"\") .. \"]\", true\r\nend\r\n\r\n\r\nfunction K.maxDownOf(r, what)\r\nlocal m = type(r) == \"table\" and type(r.maxDown) == \"table\" and r.maxDown[what]\r\nif type(m) ~= \"table\" then return 0 end\r\nif tonumber(m.ends) and K.clockRef and tonumber(K.clockRef.min) and K.clockRef.min >= m.ends then r.maxDown[what] = nil; return 0 end\r\nreturn tonumber(m.n) or 0\r\nend\r\nfunction K.maxDownTag(f, c, pc, clock)\r\nlocal head = \"[MAXDOWN|\" .. table.concat(f, \"|\", 1, math.min(#f, 4))\r\nlocal function no(why) return head .. \"|bad:\" .. why .. \"|-]\", false end\r\nlocal t = K.AR.target(f[1], c, pc)\r\nif not t then return no(\"target: Player, a companion or a creature in the fight\") end\r\nlocal what = trim(f[2] or \"\"):lower()\r\nif what ~= \"hp\" and what ~= \"arousal\" then return no(\"write hp or arousal\") end\r\nif trim(f[3] or \"\"):lower() == \"end\" then\r\nlocal e0 = type(t.maxDown) == \"table\" and t.maxDown[what]\r\nif not e0 then return no((f[1] or \"\") .. \"'s \" .. what .. \" maximum is not lowered\") end\r\nt.maxDown[what] = nil\r\nif what == \"hp\" then\r\nif t == pc and SHEET then refitHp(SHEET, pc); applySheet(SHEET)\r\nelseif type(t.sheet) == \"table\" then Ally.with(t, refitHp, t.sheet, t); applySheet(SHEET)\r\nelse t.max = (tonumber(t.max) or 1) + (tonumber(e0.n) or 0) end\r\nend\r\nreturn head .. \"|ok|\" .. what .. \" maximum back]\", true\r\nend\r\nif what == \"arousal\" and not K.AR.on() then return no(\"arousal is not in this game (no module brings it)\") end\r\nlocal n = tonumber((f[3] or \"\"):match(\"^%s*%-?(%d+)%s*$\") or \"\")\r\nif not n or n < 1 then return no(\"write N, how much it goes down\") end\r\nlocal u = trim(f[4] or \"\")\r\nlocal dn, du = u:match(\"^%+?(%d+)([mhd])$\")\r\nif not (dn or u == \"\" or K.SCORE_UNTIL[u]) then return no(\"until: longrest, rest, restore, +30d, or empty (a Long Rest)\") end\r\nt.maxDown = type(t.maxDown) == \"table\" and t.maxDown or {}\r\nlocal e = t.maxDown[what] or { n = 0 }\r\ne.n = (tonumber(e.n) or 0) + n\r\nif dn then e.ends, e.untilK = (tonumber(clock and clock.min) or 0) + tonumber(dn) * K.TIME_UNIT[du], nil\r\nelse e.untilK, e.ends = u ~= \"\" and u or \"longrest\", nil end\r\nt.maxDown[what] = e\r\nlocal note\r\nif what == \"hp\" then\r\n\r\nt.max = math.max(1, (tonumber(t.max) or 1) - n)\r\nt.hp = math.min(tonumber(t.hp) or 0, t.max)\r\nnote = \"HP maximum \" .. t.max .. \", HP \" .. t.hp\r\nelse\r\nlocal mx = K.AR.max(t, pc)\r\nlocal a = K.AR.st(t)\r\na.cur = math.min(tonumber(a.cur) or 0, math.max(0, mx))\r\nnote = \"arousal maximum \" .. mx\r\nif K.AR.max0 and K.AR.max0(t, pc) <= 0 and (t == pc or t.sheet) and not t.badEnd then\r\nnote = note .. K.AR.badEnd(t, pc, c, \"an arousal maximum of 0\")\r\nend\r\nend\r\nreturn head .. \"|ok|\" .. note .. (e.untilK and (\", \" .. (K.SCORE_UNTIL[e.untilK] or e.untilK)) or tonumber(e.ends) and (\", until \" .. clockEn(e.ends)) or \"\") .. \"]\", true\r\nend\r\n\r\nfunction K.drainRefit(t, pc)\r\nif t == pc and SHEET then refitHp(SHEET, pc); applySheet(SHEET)\r\nelseif type(t.sheet) == \"table\" then Ally.with(t, refitHp, t.sheet, t); applySheet(SHEET) end\r\nend\r\n\r\nfunction K.drainRest(rec, pc, kind)\r\n\r\nlocal psh = (rec == pc and SHEET) or rec.sheet\r\npsh = type(psh) == \"table\" and (psh.base or psh) or nil\r\nif kind == \"long\" and psh and type(psh.pickLR) == \"table\" and next(psh.pickLR) then\r\nfor k in pairs(psh.pickLR) do if type(psh.picks) == \"table\" and not tostring(k):find(\"^gain:\") then psh.picks[k] = nil end end\r\npsh.pickLR = nil\r\nK.drainRefit(rec, pc)\r\nend\r\nlocal pg = K.PG and K.PG.rest(rec, pc) or \"\"\r\nif pg ~= \"\" then return K.joinNote(pg, K.drainRest0(rec, pc, kind)) end\r\nreturn K.drainRest0(rec, pc, kind)\r\nend\r\nfunction K.drainRest0(rec, pc, kind)\r\nlocal sh = (rec == pc and SHEET) or rec.sheet\r\n\r\nlocal mback = {}\r\nfor w, e in pairs(type(rec.maxDown) == \"table\" and rec.maxDown or {}) do\r\nlocal u = type(e) == \"table\" and e.untilK\r\nif u == \"rest\" or (kind == \"long\" and (u == \"longrest\" or (u == \"longrest_noclimax\" and not (type(rec.ar) == \"table\" and tonumber(rec.ar.lastClimax) and rec.ar.lastClimax > (K.clockRef and tonumber(K.clockRef.min) or 0) - 480)))) then\r\nrec.maxDown[w] = nil; mback[#mback + 1] = (w == \"hp\" and \"HP\" or \"arousal\") .. \" maximum\"\r\nif w == \"hp\" and rec ~= pc and type(rec.sheet) ~= \"table\" then rec.max = (tonumber(rec.max) or 1) + (tonumber(e.n) or 0) end\r\nend\r\nend\r\nif #mback > 0 then\r\nif rec == pc and SHEET then refitHp(SHEET, pc); applySheet(SHEET) elseif type(rec.sheet) == \"table\" then Ally.with(rec, refitHp, rec.sheet, rec); applySheet(SHEET) end\r\nend\r\ntable.sort(mback)\r\nlocal mnote = #mback > 0 and (table.concat(mback, \", \") .. \" back\") or \"\"\r\nif not (type(sh) == \"table\" and type(sh.sdrain) == \"table\") then return mnote end\r\nlocal a = type(rec.ar) == \"table\" and rec.ar or {}\r\nlocal now = K.clockRef and tonumber(K.clockRef.min) or 0\r\nlocal back = {}\r\nfor ab, e in pairs(sh.sdrain) do\r\nlocal u = type(e) == \"table\" and e.untilK\r\nif u == \"rest\" or (kind == \"long\" and (u == \"longrest\" or (u == \"longrest_noclimax\" and not (tonumber(a.lastClimax) and a.lastClimax > now - 480)))) then\r\nsh.sdrain[ab] = nil; back[#back + 1] = ab\r\nend\r\nend\r\ntable.sort(back)\r\nif #back > 0 then K.drainRefit(rec, pc) end\r\nreturn K.joinNote(mnote, #back > 0 and (table.concat(back, \", \") .. \" back\") or \"\")\r\nend\r\nfunction K.drainText(rec, pc)\r\nlocal sh = (rec == pc and SHEET) or rec.sheet\r\nlocal o = {}\r\nfor _, ab in ipairs({ \"Strength\", \"Dexterity\", \"Constitution\", \"Intelligence\", \"Wisdom\", \"Charisma\" }) do\r\nlocal e = sh and K.drainOf(sh, ab)\r\nif e then\r\no[#o + 1] = string.format(\"%s %d (lowered from %d%s)\", ab, K.score(sh, ab), tonumber((type(sh.mscores) == \"table\" and sh.mscores[ab]) or sh.scores[ab]) or 10,\r\ne.untilK and (\", \" .. K.SCORE_UNTIL[e.untilK]) or tonumber(e.ends) and (\", until \" .. clockEn(e.ends)) or \"\")\r\nend\r\nend\r\nreturn #o > 0 and (\", lowered scores: \" .. table.concat(o, \"; \")) or \"\"\r\nend\r\nK.BADEND_KINDS = { captive = \"포로\", addiction = \"중독\", curse = \"저주\", background = \"타락한 배경\" }\r\nfunction K.AR.badTag(f, c, pc, clock)\r\nlocal head = \"[BADEND|\" .. table.concat(f, \"|\", 1, math.min(#f, 3))\r\nlocal function no(why) return head .. \"|bad:\" .. why .. \"|-]\", false end\r\nif not K.AR.on() then return no(\"arousal is not in this game (no module brings it)\") end\r\nif K.D2.perm ~= \"on\" then return no(\"permanent results are off: a Bad End is a defeat told by the story, nothing kept\") end\r\nlocal t = Ally.rec(pc, f[1] or \"\")\r\nif not t then return no(\"Player or a companion\") end\r\nlocal k = trim(f[2] or \"\")\r\nt.badRes = type(t.badRes) == \"table\" and t.badRes or {}\r\nif k == \"end\" then\r\nlocal kk = trim(f[3] or \"\")\r\nif not t.badRes[kk] then return no((f[1] or \"\") .. \" has no \" .. kk .. \" result\") end\r\nt.badRes[kk] = nil\r\nreturn head .. \"|ok|\" .. kk .. \" ends]\", true\r\nend\r\nif not K.BADEND_KINDS[k] then return no(\"kind: captive, addiction, curse or background\") end\r\nlocal text = trim(f[3] or \"\")\r\nif text == \"\" then return no(\"a short line of what it is\") end\r\nt.badRes[k] = { text = text, at = tonumber(clock and clock.min) or 0 }\r\nif type(t.badEnd) == \"table\" then t.badEnd.rec = true end\r\nreturn head .. \"|ok|kept: \" .. k .. \"]\", true\r\nend\r\n\r\n\r\n\r\n\r\nK.PG = {}\r\nfunction K.PG.on()\r\nif not K.AR.on() then return false end\r\nif K.PACK.preg then return true end\r\nfor _, sp in pairs(SPELLS) do if type(sp.m) == \"table\" and sp.m.preg then return true end end\r\nreturn false\r\nend\r\nfunction K.PG.sheet(r, pc) return (r == pc and SHEET) or (type(r) == \"table\" and r.sheet) or nil end\r\nfunction K.PG.party(r, pc) return r == pc or (type(r) == \"table\" and r.name and Ally.find(pc, r.name) ~= nil) end\r\nfunction K.PG.want(r, pc)\r\nlocal sh = K.PG.sheet(r, pc)\r\nreturn sh and type(sh.picks) == \"table\" and sh.picks.pregwant == \"yes\" or false\r\nend\r\nfunction K.PG.has(r, pc, t)\r\nlocal sh = K.PG.sheet(r, pc)\r\nreturn sh and Feat.fxOf and #Feat.fxOf(sh, t) > 0 or false\r\nend\r\nfunction K.PG.types(r, pc)\r\nlocal sh = K.PG.sheet(r, pc)\r\nif sh then\r\nlocal sp = SPECIES[sh.species or \"\"]\r\nreturn (sp and type(sp.types) == \"table\" and #sp.types > 0) and sp.types or { \"Pure Humanoid\" }\r\nend\r\nlocal m = MONSTERS[type(r) == \"table\" and r.kind or \"\"] or {}\r\nreturn type(m.ctypes) == \"table\" and m.ctypes or { \"Pure Humanoid\" }\r\nend\r\n\r\nfunction K.PG.compat(a, b, pc)\r\nlocal tbl = K.PACK.pregCompat\r\nif type(tbl) ~= \"table\" then return \"traditional\" end\r\nlocal rank, best = { none = 0, nontraditional = 1, traditional = 2 }, \"none\"\r\nfor _, x in ipairs(K.PG.types(a, pc)) do\r\nfor _, y in ipairs(K.PG.types(b, pc)) do\r\nlocal v = tbl[x .. \"|\" .. y] or \"none\"\r\nif rank[v] > rank[best] then best = v end\r\nend\r\nend\r\nreturn best\r\nend\r\n\r\nfunction K.PG.marks(r, pc)\r\nlocal o = {}\r\nfor n, row in pairs(K.AR.condsOf(r)) do\r\nif row.preg == \"adv\" then o.adv = n end\r\nif row.preg == \"block\" then o.block = n end\r\nif row.preg == \"auto\" then o.auto = n end\r\nif row.preg_ward then o.ward = n end\r\nif row.preg_any then o.any = n end\r\nif tonumber(row.preg_dc) then o.dc = tonumber(row.preg_dc); o.dcBy = n end\r\nend\r\n\r\nlocal sh = K.PG.sheet(r, pc)\r\nfor _, e in ipairs(sh and Feat.fxOf(sh, \"infertile\") or {}) do o.block = o.block or e.src or \"infertile\" end\r\nfor _, e in ipairs(sh and Feat.fxOf(sh, \"preg_ward\") or {}) do o.ward = o.ward or e.src or \"preg_ward\" end\r\nfor _, e in ipairs(sh and Feat.fxOf(sh, \"preg_any\") or {}) do o.any = o.any or e.src or \"preg_any\" end\r\n\r\n\r\nfor _, e in ipairs(sh and Feat.fxOf(sh, \"preg_auto\") or {}) do o.auto = o.auto or e.src or \"preg_auto\" end\r\nlocal now = K.clockRef and tonumber(K.clockRef.min)\r\nfor bn, b in pairs(type(r) == \"table\" and type(r.buff) == \"table\" and r.buff or {}) do\r\nif type(b) == \"table\" and b.pregAuto and not (tonumber(b.ends) and now and now >= b.ends) then o.auto = o.auto or bn end\r\nend\r\nreturn o\r\nend\r\nfunction K.PG.pb(r, pc)\r\nlocal sh = K.PG.sheet(r, pc)\r\nif sh then return 2 + math.floor((K.charLevel(sh) - 1) / 4) end\r\nreturn tonumber((MONSTERS[r.kind or \"\"] or {}).pb) or 2\r\nend\r\n\r\n\r\nfunction K.PG.absent(s)\r\nlocal nm, inner = trim(s or \"\"):match(\"^(.-)%s*%(([^()]+)%)$\")\r\nif not nm or trim(nm) == \"\" then return nil end\r\nlocal n = tonumber((trim(inner):gsub(\"^[Cc]on%a*%s*\", \"\"):gsub(\"^%+\", \"\")))\r\nif n then return { name = trim(nm), conm = n, absent = true } end\r\nlocal kind = K.monKind(Canon.name(trim(inner)))\r\nif kind then return { name = trim(nm), kind = kind, absent = true } end\r\nreturn nil\r\nend\r\nfunction K.PG.conMod(r, pc)\r\nif type(r) == \"table\" and r.absent and tonumber(r.conm) then return tonumber(r.conm) end\r\nlocal sh = K.PG.sheet(r, pc)\r\nif sh then return abilityMod(K.score(sh, \"Constitution\")) end\r\nlocal m = MONSTERS[r.kind or \"\"] or {}\r\nreturn tonumber(m.conm) or tonumber((m.saves or {}).Constitution) or 0\r\nend\r\nfunction K.PG.conCheck(r, pc)\r\nif K.PG.party(r, pc) then return Ally.run(pc, r ~= pc and r or nil, function() return bonusFor(\"Constitution\") end) end\r\nreturn K.PG.conMod(r, pc)\r\nend\r\nfunction K.PG.name(r, pc) return r == pc and \"Player\" or (type(r) == \"table\" and r.name) or \"?\" end\r\n\r\n\r\nfunction K.PG.multi(r, pc) return K.PG.party(r, pc) and K.PG.has(r, pc, \"preg_multi\") end\r\n\r\n\r\n\r\nfunction K.PG.canAdd(r, pc, by)\r\nif type(r) ~= \"table\" or type(r.preg) ~= \"table\" then return nil end\r\nlocal sh = K.PG.sheet(r, pc)\r\nlocal es = K.PG.party(r, pc) and sh and Feat.fxOf(sh, \"preg_multi\") or {}\r\nif #es == 0 then return \"pregnant already\" end\r\nlocal cap, distinct = 0, true\r\nfor _, e in ipairs(es) do\r\nlocal m = e.max ~= nil and (tonumber(K.fxNum(e.max, sh, e.srcLv)) or 1) or math.huge\r\nif m > cap then cap = m end\r\nif not e.distinct then distinct = false end\r\nend\r\nlocal all = K.PG.all(r)\r\nif #all >= cap then return string.format(\"pregnant already (%d at once at most)\", cap) end\r\nif distinct and by and by ~= \"\" then\r\nfor _, p in ipairs(all) do if p.by == by then return \"pregnant by \" .. by .. \" already (each one from a different giver)\" end end\r\nend\r\nreturn nil\r\nend\r\nfunction K.PG.all(r)\r\nlocal o = {}\r\nif type(r) == \"table\" and type(r.preg) == \"table\" then o[1] = r.preg end\r\nfor _, p in ipairs(type(r) == \"table\" and type(r.pregMore) == \"table\" and r.pregMore or {}) do if type(p) == \"table\" then o[#o + 1] = p end end\r\nreturn o\r\nend\r\nfunction K.PG.showing(r)\r\nfor _, p in ipairs(K.PG.all(r)) do if p.shows then return p end end\r\nreturn nil\r\nend\r\nfunction K.PG.sync(r, pc)\r\nif type(r) ~= \"table\" then return end\r\nlocal all = K.PG.all(r)\r\nr.preg = all[1]\r\nlocal more = {}\r\nfor i = 2, #all do more[#more + 1] = all[i] end\r\nr.pregMore = #more > 0 and more or nil\r\nlocal sh = K.PG.sheet(r, pc)\r\nsh = type(sh) == \"table\" and (sh.base or sh) or nil\r\nlocal pen = #more > 0 and #more or nil\r\nif sh and sh.pregPen ~= pen then\r\nsh.pregPen = pen\r\nK.afflictRefit(r, pc)\r\nend\r\nend\r\n\r\nfunction K.PG.add(r, pc, p)\r\nif type(r.preg) ~= \"table\" then r.preg = p; K.PG.sync(r, pc); return \"\" end\r\nr.pregMore = type(r.pregMore) == \"table\" and r.pregMore or {}\r\nr.pregMore[#r.pregMore + 1] = p\r\nK.PG.sync(r, pc)\r\nlocal n = #K.PG.all(r)\r\nreturn string.format(\" (pregnancy %d at once: Strength and Dexterity -%d)\", n, n - 1)\r\nend\r\n\r\nfunction K.PG.pick(r, line)\r\nlocal all = K.PG.all(r)\r\nlocal l = tostring(line or \"\"):lower()\r\nlocal hit\r\nfor i, p in ipairs(all) do\r\nfor _, w in ipairs({ p.by, p.from }) do\r\nif type(w) == \"string\" and w ~= \"\" and w ~= \"traditional\" and l:find(w:lower(), 1, true) then hit = hit and (hit ~= i and -1 or hit) or i end\r\nend\r\nend\r\nif hit and hit > 0 then return hit end\r\nlocal now = K.clockRef and tonumber(K.clockRef.min)\r\nfor i, p in ipairs(all) do if tonumber(p.ends) and now and now >= p.ends then return i end end\r\nreturn 1\r\nend\r\n\r\n\r\nfunction K.PG.markBrand(r, pc)\r\nlocal sh = K.PG.sheet(r, pc)\r\nfor _, x in ipairs(type(sh) == \"table\" and K.afflictOn(sh) or {}) do\r\nif type(x.rec) == \"table\" and x.rec.kind == \"brand\" then\r\nfor _, y in ipairs(x.fx or {}) do if type(y) == \"table\" and y.t == \"preg_multi\" then return x.e, x.rec end end\r\nend\r\nend\r\nreturn nil\r\nend\r\n\r\n\r\nfunction K.PG.birthUp(r, pc)\r\nlocal e, rec = K.PG.markBrand(r, pc)\r\nif not e then return \"\" end\r\nFeat.cur.brandUp = type(Feat.cur.brandUp) == \"table\" and Feat.cur.brandUp or {}\r\nlocal v = tonumber(Feat.cur.brandUp[e]) or 0\r\nFeat.cur.brandUp[e] = v + 1\r\nif v < 0 then return string.format(\", %s raised already in this reply\", e.name) end\r\nlocal was = tonumber(e.level) or tonumber(rec.level) or 1\r\ne.level = math.max(1, math.min(5, was + 1))\r\nif e.level == was then return string.format(\", %s stays at stage %d (the highest)\", e.name, was) end\r\nreturn string.format(\", %s stage %d->%d (Lua's)\", e.name, was, e.level)\r\nend\r\n\r\nfunction K.PG.impreg(f, pools, cur, c, pc, clock)\r\nlocal head = \"[IMPREG|\" .. table.concat(f, \"|\", 1, math.min(#f, 7))\r\nlocal function no(why)\r\nK.spendRefused(pools, cur, f[3])\r\nreturn head .. \"|bad:\" .. why .. \"|-]\", false\r\nend\r\nif not K.PG.on() then return no(\"pregnancy is not in this game (no module brings it)\") end\r\nlocal a, t = K.AR.target(f[1], c, pc), K.AR.target(f[2], c, pc)\r\nif not a then a = K.PG.absent(f[1]) end\r\nif not (a and t) then return no(\"Impregnator and Target: Player, a companion or a creature in the fight or the scene (one not here: Name (stat block) or Name (+its Constitution modifier))\") end\r\nlocal will = trim(f[7] or \"\"):lower()\r\nif will ~= \"willing\" and will ~= \"unwilling\" then return no(\"write willing or unwilling as the last field\") end\r\nif K.D2.mode ~= \"hard\" then\r\nif will ~= \"willing\" then return no(\"mild mode: only with a willing partner\") end\r\nif K.PG.party(t, pc) and not K.PG.want(t, pc) then return no(f[2] .. \" does not want a pregnancy (the character tab's pick)\") end\r\nend\r\nif K.PG.party(t, pc) and K.PG.has(t, pc, \"preg_guard\") and not K.PG.want(t, pc) then return no(f[2] .. \" cannot become pregnant against its wish (its feature)\") end\r\nlocal whyNot = K.PG.canAdd(t, pc, K.PG.party(a, pc) and K.PG.name(a, pc) or (a.absent and a.name) or trim(f[1] or \"\"))\r\nif whyNot then return no(f[2] .. \" is \" .. whyNot) end\r\nlocal ma, mt = K.PG.marks(a, pc), K.PG.marks(t, pc)\r\n\r\nif not (ma.any or mt.any) and K.PG.compat(a, t, pc) ~= \"traditional\" then\r\nreturn no(\"no traditional pregnancy between them (the breeding table): only a spell's or feature's PREG\")\r\nend\r\nlocal bad = {}\r\nlocal block = ma.block or mt.block\r\n\r\nfor _, e in ipairs(K.PG.sheet(a, pc) and Feat.fxOf(K.PG.sheet(a, pc), \"preg_unblock\") or {}) do\r\nlocal keep = false\r\nfor _, x in ipairs(e.except or {}) do for _, ty in ipairs(K.PG.types(t, pc)) do if ty == x then keep = true end end end\r\nif mt.block and not ma.block and not keep then block = nil end\r\nend\r\nif ma.ward or mt.ward then block = ma.ward or mt.ward end\r\nlocal dc = 10 + K.PG.conMod(t, pc) + K.PG.pb(t, pc)\r\nif ma.dc then dc = ma.dc end\r\nlocal adv = ma.adv or mt.adv\r\nlocal mode = tostring(f[3] or \"\"):lower():match(\"^%s*(%a+)\") or \"\"\r\n\r\nlocal pick = K.PG.has(a, pc, \"preg_roll\") or K.PG.has(t, pc, \"preg_roll\")\r\nif adv and not pick and mode == \"dis\" then return no(adv .. \": Advantage, write the d20 as adv A,B\") end\r\nif mode == \"dis\" and not pick then return no(\"no Disadvantage here (write one d20)\") end\r\nlocal aRec = K.PG.party(a, pc) and a or nil\r\nlocal roll, _, nat = takeD20(cur, pools, f[3] or \"\", bad, aRec, aRec and \"check\" or nil)\r\n\r\n\r\nlocal advNote = \"\"\r\nif adv and not pick and mode ~= \"adv\" and tonumber(roll) then\r\nlocal second = K.d(20)\r\nlocal n0 = tonumber(nat) or roll\r\nif second > n0 then roll = roll - n0 + second end\r\nadvNote = string.format(\" (%s: Advantage, Lua's second d20 %d)\", adv, second)\r\nend\r\nlocal bonus = K.PG.conCheck(a, pc)\r\nlocal auto = mt.auto\r\nif not auto and tonumber(((f[4] or \"\"):gsub(\"^%s*%+\", \"\"))) ~= bonus then bad[#bad + 1] = \"bonus \" .. tostring(f[4]) .. \"->\" .. string.format(\"%+d\", bonus) end\r\nif not auto and tonumber(f[5]) ~= dc then bad[#bad + 1] = \"DC \" .. tostring(f[5]) .. \"->\" .. dc end\r\nlocal ok = not block and (auto or (tonumber(roll) or 0) + bonus >= dc)\r\nlocal res = ok and \"success\" or \"failure\"\r\nif (f[6] or \"\"):lower() ~= res then bad[#bad + 1] = \"result \" .. tostring(f[6]) .. \"->\" .. res end\r\nlocal note = res .. advNote\r\nif block then note = note .. \" (\" .. block .. \")\" elseif auto then note = note .. \" (\" .. auto .. \": it succeeds by itself)\" end\r\nif ok then\r\nif K.PG.party(t, pc) then\r\nlocal now = tonumber(clock and clock.min) or 0\r\nlocal p = { kind = \"traditional\", by = K.PG.party(a, pc) and K.PG.name(a, pc) or (a.absent and a.name) or trim(f[1] or \"\"), from = \"traditional\", at = now }\r\n\r\nlocal fast = K.PG.sheet(a, pc) and Feat.fxOf(K.PG.sheet(a, pc), \"preg_fast\")[1]\r\nlocal tn, tu = tostring(fast and fast.term or \"\"):match(\"^%+?(%d+)([mhd])$\")\r\nif fast then\r\np.shows = now\r\np.ends = tn and (now + tonumber(tn) * K.TIME_UNIT[tu]) or nil\r\nnote = note .. \": pregnant (\" .. (fast.src or \"fast\") .. \": it shows now\" .. (p.ends and (\", the birth at \" .. clockEn(p.ends)) or \"\") .. \")\"\r\nelse\r\nnote = note .. \": pregnant (traditional; the story sets when it shows and the birth)\"\r\nend\r\nnote = note .. K.PG.add(t, pc, p)\r\nelse\r\nnote = note .. \": pregnant (the story's)\"\r\nend\r\nend\r\nreturn head .. \"|\" .. verdictOf(bad) .. \"|\" .. note .. \"]\", #bad == 0\r\nend\r\n\r\nfunction K.PG.tag(f, c, pc, clock)\r\nlocal head = \"[PREG|\" .. table.concat(f, \"|\", 1, math.min(#f, 5))\r\nif trim(f[2] or \"\"):lower() == \"move\" then f[3] = Canon.actor(f[3]) end\r\nlocal function no(why) return head .. \"|bad:\" .. why .. \"|-]\", false end\r\nif not K.PG.on() then return no(\"pregnancy is not in this game (no module brings it)\") end\r\nlocal t = Ally.rec(pc, f[1] or \"\")\r\nif not t then return no(\"Player or a companion (a creature's pregnancy is the story's)\") end\r\nlocal op = trim(f[2] or \"\"):lower()\r\nlocal now = tonumber(clock and clock.min) or 0\r\nif op == \"shows\" then\r\nif type(t.preg) ~= \"table\" then return no((f[1] or \"\") .. \" is not pregnant\") end\r\n\r\nfor _, p in ipairs(K.PG.all(t)) do if not p.shows then p.shows = now; break end end\r\nreturn head .. \"|ok|Pregnant shows]\", true\r\nelseif op == \"-\" then\r\nif type(t.preg) ~= \"table\" then return no((f[1] or \"\") .. \" is not pregnant\") end\r\nlocal how = trim(f[3] or \"\"):lower()\r\nif how ~= \"birth\" and how ~= \"end\" then return no(\"write birth or end\") end\r\n\r\nlocal all = K.PG.all(t)\r\nlocal i = K.PG.pick(t, f[4])\r\nlocal p = all[i]\r\ntable.remove(all, i)\r\nt.preg, t.pregMore = nil, all\r\nK.PG.sync(t, pc)\r\nlocal which = #all > 0 and (\" (the one \" .. ((p.by and p.by ~= \"\") and (\"by \" .. p.by) or (\"of \" .. tostring(p.from))) .. \"; \" .. #all .. \" more)\") or \"\"\r\nlocal up = how == \"birth\" and K.PG.birthUp(t, pc) or \"\"\r\nreturn head .. \"|ok|\" .. (how == \"birth\" and \"given birth\" or \"ended\") .. which .. up .. \"]\", true\r\nelseif op == \"term\" then\r\nif type(t.preg) ~= \"table\" then return no((f[1] or \"\") .. \" is not pregnant\") end\r\nlocal tn, tu = trim(f[3] or \"\"):match(\"^%+?(%d+)([mhd])$\")\r\nif not tn then return no(\"write the term: +8h, +3d\") end\r\nt.preg.kind, t.preg.shows, t.preg.ends = \"nontraditional\", t.preg.shows or now, now + tonumber(tn) * K.TIME_UNIT[tu]\r\nreturn head .. \"|ok|nontraditional now, the birth at \" .. clockEn(t.preg.ends) .. \"]\", true\r\nelseif op == \"move\" then\r\nif type(t.preg) ~= \"table\" then return no((f[1] or \"\") .. \" is not pregnant\") end\r\nlocal to = Ally.rec(pc, f[3] or \"\")\r\nif not to or to == t then return no(\"the receiver: Player or a companion, another one\") end\r\nlocal whyNot = K.PG.canAdd(to, pc, t.preg.by)\r\nif whyNot then return no((f[3] or \"\") .. \" is \" .. whyNot) end\r\nlocal mw = K.PG.marks(to, pc)\r\nif mw.ward then return no((f[3] or \"\") .. \" is \" .. mw.ward .. \" (no pregnancy)\") end\r\nlocal p = t.preg\r\nt.preg = nil\r\nK.PG.sync(t, pc)\r\nlocal more = K.PG.add(to, pc, p)\r\nreturn head .. \"|ok|now \" .. (f[3] or \"\") .. \"'s\" .. more .. \"]\", true\r\nelseif op ~= \"+\" then\r\nreturn no(\"write +, shows, term, move or -\")\r\nend\r\nlocal whyNot = K.PG.canAdd(t, pc, trim(f[3] or \"\"))\r\nif whyNot then return no((f[1] or \"\") .. \" is \" .. whyNot) end\r\nlocal src = Canon.name(f[3] or \"\")\r\nlocal sp = SPELLS[src]\r\nlocal mark = sp and type(sp.m) == \"table\" and sp.m.preg\r\nif mark then\r\nlocal cast = false\r\nfor _, x in ipairs(Feat.cur.casts or {}) do if x.name == src then cast = true end end\r\nif not cast and not K.AR.spellUp(src, pc) then return no(\"write [CAST|\" .. src .. \"|level] first, then its save, then the PREG\") end\r\nend\r\nif not mark then\r\nfor _, r in ipairs({ pc, table.unpack(Ally.list(pc)) }) do\r\nlocal sh = K.PG.sheet(r, pc)\r\nfor _, e in ipairs(sh and Feat.fxOf(sh, \"preg\") or {}) do if (e.name or e.src) == src then mark = e end end\r\nend\r\nend\r\n\r\nif not mark and K.D2.mode == \"hard\" and (K.PACK.impl[src] or (type(c) == \"table\" and c.active and type(c.units) == \"table\" and c.units[trim(f[3] or \"\")])\r\nor K.sceneUnit(pc, trim(f[3] or \"\"))) then mark = {} end\r\nif not mark then return no(\"a spell or feature with a pregnancy mark (m.preg), or in hardcore a creature or its implement\") end\r\nif K.D2.mode ~= \"hard\" and not K.PG.want(t, pc) then return no((f[1] or \"\") .. \" does not want a pregnancy (the character tab's pick)\") end\r\nif K.PG.has(t, pc, \"preg_guard\") and not K.PG.want(t, pc) then return no((f[1] or \"\") .. \" cannot become pregnant against its wish (its feature)\") end\r\nlocal mt = K.PG.marks(t, pc)\r\nif mt.ward then return no((f[1] or \"\") .. \" is \" .. mt.ward .. \" (no pregnancy)\") end\r\n\r\nif type(mark) == \"table\" and mark[\"if\"] == \"arousal_over_half\" then\r\nlocal a0 = type(t.ar) == \"table\" and t.ar or {}\r\nif (tonumber(a0.cur) or 0) * 2 <= K.AR.max(t, pc) then return no((f[1] or \"\") .. \"'s arousal is not over half its maximum\") end\r\nend\r\nlocal term = trim(f[5] or \"\")\r\nif term == \"\" and type(mark) == \"table\" and mark.term then term = tostring(mark.term) end\r\nlocal tn, tu = term:match(\"^%+?(%d+)([mhd])$\")\r\nlocal ends = tn and (now + tonumber(tn) * K.TIME_UNIT[tu]) or nil\r\nlocal more = K.PG.add(t, pc, { kind = \"nontraditional\", from = src, by = trim(f[3] or \"\"), at = now, shows = now, ends = ends,\r\noffspring = type(mark) == \"table\" and mark.offspring or nil })\r\nreturn head .. \"|ok|pregnant (nontraditional, \" .. src .. \")\" .. (ends and (\", birth at \" .. clockEn(ends)) or \", the term the story's\") .. more .. \"]\", true\r\nend\r\n\r\nfunction K.PG.text(r, pc)\r\nlocal p = type(r) == \"table\" and type(r.preg) == \"table\" and r.preg\r\n\r\nlocal wb = K.PG.on() and K.PG.sheet(r, pc) and Feat.fxOf(K.PG.sheet(r, pc), \"womb\")[1]\r\nlocal wt = wb and (\", womb-bearing whatever its body (\" .. (wb.src or \"womb\") .. \")\") or \"\"\r\nif not p then return wt end\r\n\r\nlocal all = K.PG.all(r)\r\nlocal function one(q) return (q.kind or \"?\") .. (q.by and (\", by \" .. q.by) or \"\") end\r\nlocal o\r\nif #all > 1 then\r\nlocal each = {}\r\nfor _, q in ipairs(all) do each[#each + 1] = one(q) end\r\no = \", \" .. #all .. \" pregnancies at once (\" .. table.concat(each, \"; \") .. \"; Strength and Dexterity -\" .. (#all - 1) .. \", Lua's)\"\r\nelse\r\no = \", pregnant (\" .. one(p) .. \")\"\r\nend\r\nif K.PG.showing(r) then o = o .. \": Pregnant (Disadvantage on Strength and Dexterity saves; attacks against it crit on 18-20)\"\r\nelse o = o .. \": not showing yet ([PREG|\" .. K.PG.name(r, pc) .. \"|shows] when the story shows it)\" end\r\nlocal now = K.clockRef and tonumber(K.clockRef.min)\r\nfor _, q in ipairs(all) do\r\nif tonumber(q.ends) and now and now >= q.ends then\r\no = o .. (#all > 1 and \"; a birth is due: write [PREG|\" or \"; its birth is due: write [PREG|\") .. K.PG.name(r, pc) .. \"|-|birth|a short line\" .. (#all > 1 and \" naming its giver\" or \"\") .. \"]\"\r\nbreak\r\nend\r\nend\r\nlocal mb = K.PG.markBrand(r, pc)\r\nif mb then o = o .. \" (a birth raises \" .. tostring(mb.name) .. \" a stage: Lua's, no BRAND tag)\" end\r\nreturn wt .. o\r\nend\r\n\r\nfunction K.PG.rest(rec, pc)\r\nif not K.PG.showing(rec) then return \"\" end\r\nlocal tot, d, bn = K.AR.saveRoll(rec, pc, \"Constitution\")\r\nif tot >= 15 then return string.format(\"Pregnant: Constitution save d20 %d%+d vs DC 15, fine\", d, bn) end\r\nlocal h = K.d(4)\r\nCond.load(rec)\r\nlocal sh = K.PG.sheet(rec, pc)\r\nif sh and Feat.immune(rec, sh, \"Poisoned\") then\r\nreturn string.format(\"Pregnant: Constitution save d20 %d%+d vs DC 15, failed, but immune to Poisoned\", d, bn)\r\nend\r\nlocal untilT = (K.clockRef and tonumber(K.clockRef.min) or 0) + h * 60\r\nlocal was = tonumber(rec.cond.Poisoned)\r\nif not (was and (was < 0 or was >= untilT)) then rec.cond.Poisoned = untilT end\r\nreturn string.format(\"Pregnant: Constitution save d20 %d%+d vs DC 15, Poisoned for %d hour%s\", d, bn, h, h > 1 and \"s\" or \"\")\r\nend\r\nfunction K.PG.rules(pc, c)\r\nif not K.PG.on() then return nil end\r\n\r\nlocal any = false\r\nfor _, r in ipairs(type(pc) == \"table\" and { pc, table.unpack(Ally.list(pc)) } or {}) do if type(r.preg) == \"table\" then any = true end end\r\nif not any and not (type(pc) == \"table\" and K.AR.scan(pc, c).warm) then return nil end\r\n\r\nreturn \"Pregnancy (the module's): only after sex that can make one (a cock or an ovipositor finishing in a womb-bearing partner's pussy, or a feature or spell\"\r\n.. \" that says so; never oral, anal or hands): [IMPREG|Impregnator|Target|d20|+its Constitution check|DC|success/failure|willing/unwilling]\"\r\n.. \" (an Impregnator not here, by the seed it left: Name (stat block))\"\r\n.. \" (Lua sets the DC; \" .. (K.D2.mode == \"hard\" and \"any partner\" or \"mild mode: a willing partner, one of Player's side only if it wants it\") .. \");\"\r\n.. \" a spell's or feature's after its failed Constitution save: [PREG|Target|+|Source|nontraditional|term] (term +3d, +8h; empty: the cause's or the story's);\"\r\n.. \" [PREG|Target|shows] when a traditional one shows, [PREG|Target|-|birth|a short line] or [PREG|Target|-|end|why]; [PREG|Target|term|+8h] makes it\"\r\n.. \" nontraditional with that term, [PREG|Holder|move|Receiver] moves it. The child is the story's NPC.\"\r\nend\r\n\r\n\r\nfunction K.afflictSheet(f1, c, pc)\r\nlocal t = K.AR.target(f1, c, pc)\r\nif not t then return nil, nil, \"target must be Player or a companion\" end\r\nlocal sh = (t == pc and SHEET) or t.sheet\r\nif not sh then return nil, nil, (f1 or \"?\") .. \" is a creature: its curse is the story's\" end\r\nreturn t, sh.base or sh, nil\r\nend\r\n\r\nfunction K.afflictRefit(t, pc)\r\nif t == pc then refitHp(SHEET, pc)\r\nelseif t.sheet then Ally.with(t, function() refitHp(t.sheet, t) end) end\r\nend\r\n\r\nfunction K.castNow(name, minLv)\r\nfor _, x in ipairs(Feat.cur.casts or {}) do if x.name == name and (tonumber(x.level) or 0) >= (tonumber(minLv) or 0) then return x end end\r\nreturn nil\r\nend\r\n\r\n\r\nfunction K.afflictTag(tag, f, c, pc, clock)\r\nlocal head = \"[\" .. tag .. \"|\" .. table.concat(f, \"|\", 1, math.min(#f, 5))\r\nlocal function no(why) return head .. \"|bad:\" .. why .. \"|-]\", false end\r\nif not (K.AR and K.AR.on() and K.PACK.afflict) then return no(\"no module brings afflictions in this game\") end\r\nlocal t, sh, why = K.afflictSheet(f[1], c, pc)\r\nif not t then return no(why) end\r\nlocal kind = ({ CURSE = \"curse\", BRAND = \"brand\", FETISH = \"fetish\" })[tag]\r\nlocal raw = trim(f[2] or \"\")\r\nlocal sign, nm = raw:match(\"^([+-])%s*(.+)$\")\r\nnm = trim(nm or raw)\r\nlocal name = Canon.name(nm)\r\nif not K.PACK.afflict[name] then for n in pairs(K.PACK.afflict) do if NAMES_KO[n] == nm or n:lower() == nm:lower() then name = n end end end\r\nlocal rec = K.PACK.afflict[name]\r\n\r\n\r\nif not rec then\r\nlocal names = {}\r\nfor n, r in pairs(K.PACK.afflict) do\r\nif type(r) == \"table\" and r.kind == kind and not K.d2need(r) then names[#names + 1] = NAMES_KO[n] or r.ko or n end\r\nend\r\ntable.sort(names)\r\nreturn no(nm .. \" is not one of the module's \" .. kind .. \"s\" .. (#names > 0 and (\": \" .. table.concat(names, \", \")) or \"\"))\r\nend\r\nif rec.kind ~= kind and not (tag == \"CURSE\" and rec.kind == \"brand\") then return no(name .. \" is a \" .. tostring(rec.kind) .. \", not a \" .. kind) end\r\nsh.afflict = type(sh.afflict) == \"table\" and sh.afflict or {}\r\nlocal kept = {}\r\nfor _, e in ipairs(sh.afflict) do if not (type(e) == \"table\" and e.over) then kept[#kept + 1] = e end end\r\nsh.afflict = kept\r\nlocal idx\r\nfor i, e in ipairs(sh.afflict) do if type(e) == \"table\" and e.name == name then idx = i end end\r\nlocal now = clock and tonumber(clock.min) or 0\r\n\r\nif not sign and tag == \"BRAND\" then\r\nlocal up = tonumber((trim(f[3] or \"\"):gsub(\"^%+\", \"\")))\r\nif not (idx and up) then return no(idx and \"write +1\" or ((f[1] or \"\") .. \" has no \" .. name)) end\r\nlocal e = sh.afflict[idx]\r\n\r\nlocal multi = false\r\nfor _, x in ipairs(rec.fx or {}) do if type(x) == \"table\" and x.t == \"preg_multi\" then multi = true end end\r\nFeat.cur.brandUp = type(Feat.cur.brandUp) == \"table\" and Feat.cur.brandUp or {}\r\nlocal v = tonumber(Feat.cur.brandUp[e]) or 0\r\nif multi then Feat.cur.brandUp[e] = v - 1 end\r\nif multi and v > 0 then\r\nreturn head .. string.format(\"|ok|%s stage %d already (Lua raised it at the birth)]\", name, tonumber(e.level) or 1), true\r\nend\r\nlocal was = tonumber(e.level) or tonumber(rec.level) or 1\r\ne.level = math.max(1, math.min(5, was + up))\r\nreturn head .. string.format(\"|ok|%s stage %d->%d (inhibition -%d)]\", name, was, e.level, e.level), true\r\nend\r\nif sign == \"+\" then\r\nlocal off = K.d2need(rec)\r\nif off then return no(name .. \" is \" .. K.D2_WHY[off]) end\r\nlocal e = { name = name, kind = rec.kind, at = now }\r\nif tag == \"CURSE\" then\r\ne.src = trim(f[3] or \"\") ~= \"\" and trim(f[3]) or nil\r\ne.level = tonumber(rec.level) or tonumber(f[4])\r\n\r\nif e.src and Canon.name(e.src) == \"Bestow Curse\" and not K.castNow(\"Bestow Curse\", rec.level) then\r\nreturn no(\"Bestow Curse cast at level \" .. tostring(rec.level or 3) .. \" or higher in this reply puts it on\")\r\nend\r\nelseif tag == \"BRAND\" then\r\ne.level = math.max(1, math.min(5, tonumber(f[3]) or tonumber(rec.level) or 1))\r\ne.src = trim(f[4] or \"\") ~= \"\" and trim(f[4]) or nil\r\nlocal bsp = e.src and SPELLS[Canon.name(e.src)]\r\nif bsp and type(bsp.m) == \"table\" and bsp.m.concentration then\r\nlocal cx\r\nfor _, x in ipairs(Feat.cur.casts or {}) do if x.name == Canon.name(e.src) then cx = x end end\r\n\r\nif not cx then\r\nfor _, r in ipairs(K.concRecs(pc)) do\r\nif type(r.conc) == \"table\" and r.conc.name == Canon.name(e.src) and not r.conc.lost then\r\ncx = { name = r.conc.name, by = (r == pc and \"Player\") or r.name, level = r.conc.level }\r\nend\r\nend\r\nend\r\nif cx and not (tonumber(bsp.m.dur_at) and (tonumber(cx.level) or 0) >= tonumber(bsp.m.dur_at)) then\r\ne.conc = { spell = cx.name, by = cx.by or \"Player\" }\r\nend\r\nend\r\nsh.brandRegrow = nil\r\n\r\nfor vn, vr in pairs(K.PACK.afflict) do\r\nif vr.kind == \"vice\" and type(vr.vice) == \"table\" and vr.vice.locked_by == name then\r\nlocal have\r\nfor _, x in ipairs(sh.afflict) do if type(x) == \"table\" and x.name == vn then have = x end end\r\nif not have then have = { name = vn, kind = \"vice\", times = {} }; sh.afflict[#sh.afflict + 1] = have end\r\nhave.addicted, have.dc, have.last = true, tonumber(vr.vice.dc) or 10, now\r\nend\r\nend\r\nelse\r\nlocal dn, du = trim(f[3] or \"\"):gsub(\"%s\", \"\"):match(\"^%+?(%d+)([mhd])$\")\r\nif dn then e.ends = now + tonumber(dn) * K.TIME_UNIT[du] end\r\ne.src = trim(f[4] or \"\") ~= \"\" and trim(f[4]) or nil\r\nend\r\nif idx then sh.afflict[idx] = e else sh.afflict[#sh.afflict + 1] = e end\r\nK.afflictRefit(t, pc)\r\nreturn head .. \"|ok|\" .. name .. (e.level and (\" (\" .. rec.kind .. \" \" .. e.level .. \")\") or \"\") .. (e.ends and (\", until \" .. clockEn(e.ends)) or \"\") .. \"]\", true\r\nend\r\nif sign ~= \"-\" then return no(\"write +Name or -Name\") end\r\nif not idx then return no((f[1] or \"\") .. \" has no \" .. name) end\r\nlocal e = sh.afflict[idx]\r\nlocal how = trim(f[3] or \"\")\r\nlocal lhow = how:lower()\r\nif rec.kind == \"curse\" or rec.kind == \"brand\" then\r\nlocal lv = tonumber(e.level) or tonumber(rec.level) or (rec.kind == \"brand\" and 1 or 3)\r\nlocal fixed = e.src and ({ species = 1, background = 1, choice = 1 })[tostring(e.src):lower()]\r\nif rec[\"end\"] == \"never\" or (rec.kind == \"brand\" and tostring(e.src or \"\"):lower() == \"species\") then return no(name .. \" can't be removed\") end\r\nlocal rcN = tonumber(how:match(\"^[Rr]emove [Cc]urse%s*(%d*)$\") or \"\") or (how:match(\"^[Rr]emove [Cc]urse\") and 3) or nil\r\nlocal okWay\r\n\r\nlocal wishOnly = rec.kind == \"curse\" and rec[\"end\"] == \"wish\"\r\nif wishOnly and lhow ~= \"wish\" then return no(name .. \": only Wish removes it ([CURSE|\" .. tostring(f[1] or \"\") .. \"|-\" .. name .. \"|Wish] after a CAST of Wish)\") end\r\nif lhow == \"wish\" then\r\nokWay = K.castNow(\"Wish\", 9) and true or false\r\nif not okWay then return no(\"Wish cast in this reply removes it\") end\r\nelseif rcN then\r\n\r\nlocal wishSrc = e.src and SPELLS[Canon.name(e.src)] and type(SPELLS[Canon.name(e.src)].m) == \"table\" and SPELLS[Canon.name(e.src)].m.wish_only\r\nlocal rcOk = (rec.kind == \"curse\" and rec[\"end\"] ~= \"wish\" and not fixed and not wishSrc) or (rec.kind == \"brand\" and K.D2.perm ~= \"on\" and not fixed and not wishSrc)\r\nif not rcOk then return no(name .. \": only Wish removes it\") end\r\nif rcN < lv then return no(string.format(\"Remove Curse at level %d or higher removes it (level %d)\", lv, rcN)) end\r\nif not K.castNow(\"Remove Curse\", lv) then return no(\"Remove Curse cast at level \" .. lv .. \" or higher in this reply removes it\") end\r\nokWay = true\r\nelseif lhow == \"divine intervention\" then\r\nokWay = true\r\nelseif lhow == \"story\" or lhow == \"이야기\" then\r\nokWay = true\r\nelse\r\nreturn no(\"how: Remove Curse N (cast in this reply), Wish (cast), Divine Intervention or story\")\r\nend\r\nend\r\ntable.remove(sh.afflict, idx)\r\n\r\nif rec.kind == \"brand\" and Feat.fxOf and #Feat.fxOf(sh, \"brand_regrow\") > 0 then sh.brandRegrow = true end\r\nK.afflictRefit(t, pc)\r\nreturn head .. \"|ok|\" .. name .. \" removed]\", true\r\nend\r\n\r\n\r\n\r\nfunction K.viceTag(f, pools, cur, c, pc, clock)\r\nlocal head = \"[VICE|\" .. table.concat(f, \"|\", 1, math.min(#f, 7))\r\nlocal function no(why) return head .. \"|bad:\" .. why .. \"|-]\", false end\r\nif not (K.AR and K.AR.on() and K.PACK.afflict) then return no(\"no module brings vices in this game\") end\r\nlocal t, sh, why = K.afflictSheet(f[1], c, pc)\r\nif not t then return no(why) end\r\nlocal nm = trim(f[2] or \"\")\r\nlocal name = Canon.name(nm)\r\nif not K.PACK.afflict[name] then for n in pairs(K.PACK.afflict) do if NAMES_KO[n] == nm or n:lower() == nm:lower() then name = n end end end\r\nlocal rec = K.PACK.afflict[name]\r\nif not (rec and rec.kind == \"vice\" and type(rec.vice) == \"table\") then return no(nm .. \" is not one of the module's vices\") end\r\nif (trim(f[3] or \"\")):lower() ~= \"partake\" then return no(\"write partake\") end\r\nlocal off = K.d2need(rec)\r\nif off then return no(name .. \" is \" .. K.D2_WHY[off]) end\r\nsh.afflict = type(sh.afflict) == \"table\" and sh.afflict or {}\r\nlocal e\r\nfor _, x in ipairs(sh.afflict) do if type(x) == \"table\" and x.name == name then e = x end end\r\nif not e then e = { name = name, kind = \"vice\", times = {} }; sh.afflict[#sh.afflict + 1] = e end\r\nlocal now = clock and tonumber(clock.min) or 0\r\nlocal times = {}\r\nfor _, m in ipairs(type(e.times) == \"table\" and e.times or {}) do if tonumber(m) and m > now - 7 * 1440 then times[#times + 1] = m end end\r\nlocal dc = (tonumber(rec.vice.dc) or 10) + #times + ((e.cured and tonumber(rec.vice.relapse)) or 0)\r\nlocal ab = rec.vice.save or \"Constitution\"\r\nlocal r = Ally.rec(pc, f[1] or \"\")\r\nlocal line = Ally.run(pc, r ~= pc and r or nil, function() return verifyCheck({ ab .. \" save\", f[4], f[5], tostring(dc), f[7] }, pools, cur, nil) end)\r\nlocal p = {}\r\nfor x in (line:sub(2, -2) .. \"|\"):gmatch(\"([^|]*)|\") do p[#p + 1] = x end\r\nlocal total = tonumber(p[#p]) or 0\r\nlocal bad = {}\r\nlocal v = p[#p - 1] or \"\"\r\nif v:match(\"^bad:\") then bad[#bad + 1] = v:sub(5) end\r\nif tonumber(f[6]) ~= dc then bad[#bad + 1] = string.format(\"DC %s->%d\", tostring(f[6]), dc) end\r\ntimes[#times + 1] = now\r\ne.times, e.last = times, now\r\nlocal note\r\nif total < dc then\r\nif not e.addicted then e.dc = dc end\r\ne.addicted = true\r\ne.dc = math.max(tonumber(e.dc) or dc, dc)\r\nnote = \"addicted (withdrawal DC \" .. e.dc .. \")\"\r\nelse\r\nnote = e.addicted and \"still addicted\" or \"not addicted\"\r\nend\r\nlocal ok = #bad == 0\r\nreturn string.format(\"[VICE|%s|%s|partake|%s|%s|%d|%s|%s|%d, %s]\", f[1], name, tostring(p[3]), tostring(p[4]), dc, tostring(f[7]),\r\nok and \"ok\" or (\"bad:\" .. table.concat(bad, \", \")), total, note), ok\r\nend\r\n\r\n\r\nfunction K.viceRest(rec, pc)\r\nlocal sh = (rec == pc and SHEET) or rec.sheet\r\nsh = sh and (sh.base or sh)\r\nif not (sh and type(sh.afflict) == \"table\" and K.PACK.afflict) then return \"\" end\r\nlocal now = K.clockRef and tonumber(K.clockRef.min) or 0\r\nlocal notes = {}\r\nfor _, e in ipairs(sh.afflict) do\r\nlocal r = type(e) == \"table\" and e.addicted and K.PACK.afflict[e.name or \"\"]\r\nif r and type(r.vice) == \"table\" and now - (tonumber(e.last) or now) >= 1440 then\r\nlocal ab = r.vice.save or \"Constitution\"\r\nlocal tot, d, b = K.AR.saveRoll(rec, pc, ab)\r\nlocal tot2, d2 = K.AR.saveRoll(rec, pc, ab)\r\nif tot2 < tot then tot, d = tot2, d2 end\r\nlocal base, dc = tonumber(r.vice.dc) or 10, tonumber(e.dc) or tonumber(r.vice.dc) or 10\r\nlocal w = string.format(\"%s withdrawal: %s save d20 %d%+d vs DC %d\", e.name, ab, d, b, dc)\r\nlocal lock = r.vice.locked_by and K.afflictHas(sh, r.vice.locked_by)\r\nif tot >= dc then\r\nif lock then w = w .. \", but \" .. r.vice.locked_by .. \" keeps it\"\r\nelseif dc <= base then e.addicted, e.dc, e.cured = nil, nil, true; w = w .. \", free of it\"\r\nelse e.dc = dc - 1; w = w .. \", DC \" .. e.dc end\r\nelseif r.vice.withdrawal == \"overstim\" then\r\nw = w .. \", overstimulation\" .. K.AR.overAdd(rec, pc, K.curC, 1, e.name)\r\nelse\r\nlocal n = d == 1 and 2 or 1\r\nrec.exh = math.min(6, (tonumber(rec.exh) or 0) + n)\r\nif rec.exh >= 6 then rec.dead = true end\r\nw = w .. \", Exhaustion +\" .. n\r\nend\r\nnotes[#notes + 1] = w\r\nend\r\nend\r\nreturn table.concat(notes, \"; \")\r\nend\r\n\r\nfunction K.afflictHas(sh, name)\r\nfor _, x in ipairs(K.afflictOn(sh)) do if x.e.name == name then return x end end\r\nreturn nil\r\nend\r\n\r\nfunction K.afflictText(rec, pc)\r\nlocal sh = K.AR.sheetOf(rec, pc)\r\nlocal on = K.afflictOn(sh)\r\nif #on == 0 and not (sh and sh.brandRegrow) then return \"\" end\r\nlocal o = {}\r\nfor _, x in ipairs(on) do\r\nlocal r, e = x.rec, x.e\r\nif r.kind == \"vice\" and not e.addicted then goto nextAff end\r\nlocal lv = tonumber(e.level) or tonumber(r.level)\r\nlocal d = r.kind .. (lv and (\" \" .. lv) or \"\") .. (r.kind == \"brand\" and lv and (\", inhibition -\" .. lv) or \"\")\r\nlocal who = (rec == pc and \"Player\") or rec.name or \"?\"\r\nlocal function fill(txt)\r\nreturn Ally.run(pc, rec ~= pc and rec or nil, function() return Feat.fill(txt, sh, who, x.e.name) end) or txt\r\nend\r\nif r.text ~= \"\" then d = d .. \"; \" .. fill(r.text) end\r\nif r.kind == \"fetish\" then\r\nif e.on == false then d = d .. \" (off: its good side is not on)\" end\r\nif type(r.neg_text) == \"string\" and r.neg_text ~= \"\" then d = d .. \"; drawback: \" .. fill(r.neg_text) end\r\nend\r\nif tonumber(e.ends) then d = d .. \"; until \" .. clockEn(e.ends) end\r\nif r.kind == \"vice\" then\r\nlocal due = (tonumber(e.last) or 0) + 1440\r\nd = string.format(\"vice, addicted: Disadvantage on its %s saves and related checks; must partake by %s ([VICE|...|partake], DC %d); not fed: withdrawal at a Long Rest\",\r\ntostring(type(r.vice) == \"table\" and r.vice.save or \"Constitution\"), clockEn(due), tonumber(e.dc) or 10) .. (r.text ~= \"\" and (\"; \" .. fill(r.text)) or \"\")\r\nend\r\no[#o + 1] = x.e.name .. \" (\" .. d .. \")\"\r\n::nextAff::\r\nend\r\nlocal s = #o > 0 and (\", afflictions: \" .. table.concat(o, \"; \")) or \"\"\r\nif sh and sh.brandRegrow then s = s .. \", its removed brand comes back at its next climax: write [BRAND|\" .. ((rec == pc and \"Player\") or rec.name or \"?\") .. \"|+Name|stage|regrown] then (usually a higher stage)\" end\r\nreturn s\r\nend\r\n\r\nfunction K.AR.overTag(f, c, pc)\r\nlocal head = \"[OVERSTIM|\" .. table.concat(f, \"|\", 1, math.min(#f, 3))\r\nlocal function no(why) return head .. \"|bad:\" .. why .. \"|-]\", false end\r\nif not K.AR.on() then return no(\"arousal is not in this game (no module brings it)\") end\r\nlocal t = Ally.rec(pc, f[1] or \"\") or K.AR.target(f[1], c, pc)\r\nif not t then return no(\"Player, a companion or a creature in the fight\") end\r\nlocal n = tonumber(((f[2] or \"\"):gsub(\"%s\", \"\")))\r\nif not n or n == 0 then return no(\"write +N or -N\") end\r\nlocal was = tonumber(type(t.ar) == \"table\" and t.ar.overstim) or 0\r\nlocal note = K.AR.overAdd(t, pc, c, n, trim(f[3] or \"\") ~= \"\" and trim(f[3]) or nil)\r\nlocal bad = note:match(\"%)(,.*)$\") or \"\"\r\nif note:find(\"immune\", 1, true) then return head .. \"|ok|immune to overstimulation]\", true end\r\nlocal lo = K.AR.overLow(t)\r\nreturn head .. string.format(\"|ok|overstimulation %d->%d\", was, tonumber(t.ar.overstim) or 0)\r\n.. (lo > 0 and string.format(\", counted as %d\", math.max(0, (tonumber(t.ar.overstim) or 0) - lo)) or \"\") .. bad .. \"]\", true\r\nend\r\n\r\nfunction K.AR.fightStart(c, pc)\r\nlocal recs = { pc, table.unpack(Ally.list(pc)) }\r\nfor _, u in pairs(c.units or {}) do if type(u) == \"table\" and u.side == \"enemy\" then recs[#recs + 1] = u end end\r\nlocal now = K.clockRef and tonumber(K.clockRef.min) or 0\r\nfor _, r in ipairs(recs) do\r\nlocal a = type(r) == \"table\" and type(r.ar) == \"table\" and r.ar\r\nif a and not r.dead and type(a.edge) ~= \"table\" and (tonumber(a.cur) or 0) > 0 and (tonumber(a.cur) or 0) >= K.AR.max(r, pc) then\r\na.edge, a.edgeSince, a.edgeHours, a.edgeGrace = { s = 0, f = 0 }, now, 0, math.max(0, K.AR.inhib(r, pc))\r\nend\r\nend\r\nend\r\n\r\nfunction K.AR.edgeTick(r, pc, clock)\r\nif not K.fightNow then return end\r\nlocal a = type(r) == \"table\" and type(r.ar) == \"table\" and r.ar\r\nif not (a and type(a.edge) == \"table\" and tonumber(a.edgeSince) and type(clock) == \"table\" and tonumber(clock.min)) then return end\r\nif not (r == pc or r.sheet) then return end\r\nif not tonumber(a.edgeGrace) then a.edgeGrace = math.max(0, K.AR.inhib(r, pc)) end\r\nlocal grace = a.edgeGrace * 60\r\nlocal over = math.floor((clock.min - a.edgeSince - grace) / 60)\r\nlocal done = tonumber(a.edgeHours) or 0\r\nif over > done then\r\nK.AR.overAdd(r, pc, K.curC, over - done, nil)\r\na.edgeHours = over\r\nend\r\nend\r\n\r\nfunction K.AR.condOn(f, c, pc, clock)\r\nlocal rec = Ally.rec(pc, f[1] or \"\")\r\nif rec then\r\n\r\nlocal sgnF, rwF = (f[2] or \"\"):match(\"^%s*([+-])%s*(.-)%s*$\")\r\nlocal spF = rwF and Canon.name(rwF)\r\nif spF == \"Reduce\" then spF = \"Enlarge/Reduce\" end\r\nif spF and K.foeFxOf(spF) then return K.recFxTag(f, rec, spF, sgnF, c, clock) end\r\nlocal line, good = Cond.verify({ f[2], f[3], f[4] }, rec, clock)\r\nreturn (line:gsub(\"^%[COND|\", \"[COND|\" .. f[1] .. \"|\", 1)), good\r\nend\r\nlocal head = \"[COND|\" .. table.concat(f, \"|\")\r\nlocal u = (c.active and type(c.units) == \"table\" and c.units[f[1] or \"\"]) or K.sceneUnit(pc, f[1]) or (type(c.units) == \"table\" and c.units[f[1] or \"\"])\r\nif not u then return head .. \"|bad:target must be Player, a companion, a creature in the fight or in the scene|-]\", false end\r\nlocal sign, raw = (f[2] or \"\"):match(\"^%s*([+-])%s*(.-)%s*$\")\r\nlocal name = Canon.name(raw or \"\")\r\nif not CONDS[name] then for n in pairs(CONDS) do if NAMES_KO[n] == raw then name = n end end end\r\n\r\n\r\n\r\nif CONDS[name] and not CONDS[name].pack and sign then\r\nu.cond = type(u.cond) == \"table\" and u.cond or {}\r\nif sign == \"-\" then\r\nif not u.cond[name] then return head .. \"|bad:\" .. f[1] .. \" is not \" .. name .. \"|-]\", false end\r\nu.cond[name] = nil\r\nelse\r\nlocal src = trim(f[4] or \"\")\r\nlocal spell, caster, featWho\r\nlocal sn = Canon.name(src)\r\nif SPELLS[sn] then spell, caster = sn, K.buffBy(sn, pc)\r\nelse\r\nlocal r = Ally.rec(pc, src ~= \"\" and src or \"Player\")\r\nif r and type(r.conc) == \"table\" and r.conc.name and not r.conc.lost then spell, caster = r.conc.name, (r == pc and \"Player\") or r.name end\r\nend\r\nif not (spell and caster and SPELLS[spell] and SPELLS[spell].m and SPELLS[spell].m.concentration) then\r\n\r\n\r\n\r\nlocal m2 = SPELLS[sn] and SPELLS[sn].m\r\nlocal fits, castBy = false, nil\r\nfor _, x in ipairs(type(m2) == \"table\" and type(m2.puts) == \"table\" and m2.puts or {}) do if x == name then fits = true end end\r\nfor _, x in ipairs(Feat.cur.casts or {}) do if x.name == sn then castBy = x.by or \"Player\" end end\r\nif not (fits and castBy) then\r\n\r\n\r\n\r\nfeatWho = K.featActor(pc, c, src)\r\nif not featWho then\r\nreturn head .. \"|bad:\" .. name .. \" on a creature comes with a spell in effect: name its caster (concentrating on it) or the spell as the source\"\r\n.. \" (one without Concentration: right after its CAST, a condition it puts on; a feature's: the feature or who uses it)|-]\", false\r\nend\r\nelse\r\nif tonumber(m2.puts_hp) and (tonumber(u.hp) or 0) > tonumber(m2.puts_hp) then\r\nreturn head .. \"|bad:\" .. f[1] .. \" has more than \" .. m2.puts_hp .. \" HP: no \" .. name .. \" from \" .. sn .. \"|-]\", false\r\nend\r\nspell, caster = sn, castBy\r\nend\r\nend\r\nif featWho then\r\nlocal put = K.featCondPut(u, { name }, src, featWho, f[3], c, clock)\r\nif #put == 0 then return head .. \"|ok|immune: \" .. name .. \"]\", true end\r\nu.cond[name].tag = true\r\nelse\r\nlocal e = { by = spell, caster = caster }\r\nlocal rn = trim(f[3] or \"\"):match(\"^%+?(%d+)r$\")\r\nif rn and c.active then e.untilR, e.fid = (tonumber(c.round) or 1) + tonumber(rn), c.fid end\r\n\r\nfor _, x in ipairs(type(SPELLS[spell].m.keeps) == \"table\" and SPELLS[spell].m.keeps or {}) do if x == name then e.keep = true end end\r\nif c.active then\r\nlocal r0\r\nfor _, x in pairs(u.cond) do if type(x) == \"table\" and x.by == spell and tonumber(x.r0) and x.r0f == c.fid then r0 = math.min(r0 or x.r0, x.r0) end end\r\ne.r0, e.r0f = r0 or (tonumber(c.round) or 1), c.fid\r\nend\r\nu.cond[name] = e\r\nend\r\nend\r\nlocal now = {}\r\nfor n in pairs(u.cond) do now[#now + 1] = n end\r\ntable.sort(now)\r\nreturn head .. \"|ok|\" .. (#now > 0 and table.concat(now, \", \") or \"none\") .. \"]\", true\r\nend\r\nif not (CONDS[name] and CONDS[name].pack) then return head .. \"|bad:\" .. tostring(raw) .. \" is not a condition a module brings (an SRD one comes with its spell)|-]\", false end\r\nif sign == \"+\" and not K.AR.on() then return head .. \"|bad:\" .. name .. \": no module brings it in this game|-]\", false end\r\nlocal off = sign == \"+\" and K.d2need(CONDS[name].pack)\r\nif off then return head .. \"|bad:\" .. name .. \" is \" .. K.D2_WHY[off] .. \"|-]\", false end\r\nu.cond = type(u.cond) == \"table\" and u.cond or {}\r\nif sign == \"-\" then\r\nif not u.cond[name] then return head .. \"|bad:\" .. f[1] .. \" is not \" .. name .. \"|-]\", false end\r\nu.cond[name] = nil\r\nelse\r\n\r\nlocal e = { pack = true, src = (f[4] and trim(f[4]) ~= \"\") and trim(f[4]) or nil }\r\nfor part in (trim(f[3] or \"\"):gsub(\"%s\", \"\") .. \",\"):gmatch(\"([^,]*),\") do\r\nlocal dn, du = part:match(\"^%+?(%d+)([mhd])$\")\r\nlocal rn = part:match(\"^%+?(%d+)r$\")\r\nif part == \"dmg\" then e.dmg = true\r\nelseif part == \"conc\" then e.conc = K.AR.concOf(f[4], pc)\r\nelseif dn then e.ends = (tonumber(clock and clock.min) or 0) + tonumber(dn) * K.TIME_UNIT[du]\r\nelseif rn and u.side == \"scene\" then e.ends = (tonumber(clock and clock.min) or 0) + math.max(1, math.ceil(tonumber(rn) / 10))\r\nelseif rn then e.untilR, e.fid = (tonumber(c.round) or 1) + tonumber(rn), c.fid end\r\nend\r\nu.cond[name] = e\r\nend\r\nlocal now = {}\r\nfor n in pairs(u.cond) do now[#now + 1] = n end\r\ntable.sort(now)\r\nreturn head .. \"|ok|\" .. (#now > 0 and table.concat(now, \", \") or \"none\") .. \"]\", true\r\nend\r\n\r\nfunction K.AR.concOf(src, pc)\r\nif not pc then return nil end\r\nlocal r = Ally.rec(pc, trim(src or \"\") ~= \"\" and trim(src) or \"Player\")\r\nif r and type(r.conc) == \"table\" and r.conc.name and not r.conc.lost then return { spell = r.conc.name, by = (r == pc and \"Player\") or r.name } end\r\nfor i = #(Feat.cur.casts or {}), 1, -1 do\r\nlocal x = Feat.cur.casts[i]\r\nlocal sp = SPELLS[x.name]\r\nif sp and sp.m and sp.m.concentration then return { spell = x.name, by = x.by or \"Player\" } end\r\nend\r\nreturn nil\r\nend\r\nfunction K.AR.concOver(cs, pc)\r\nreturn type(cs) == \"table\" and cs.spell and not K.AR.spellUp(cs.spell, pc, cs.by)\r\nend\r\n\r\nfunction K.AR.condsOf(t)\r\nlocal o = {}\r\nlocal function add(n, depth)\r\nlocal cd = CONDS[n]\r\nif not (cd and cd.pack) or o[n] or depth > 3 then return end\r\no[n] = cd.pack\r\nfor _, x in ipairs(cd.pack.has or {}) do add(x, depth + 1) end\r\nend\r\nlocal now = K.clockRef and tonumber(K.clockRef.min)\r\nlocal cc = K.curC\r\n\r\nlocal ov = type(t) == \"table\" and type(t.ar) == \"table\" and K.AR.overHard(t.ar, t) or 0\r\nif ov >= 1 then add(\"Intoxicated\", 0) end\r\nif ov >= 2 then add(\"Hyperaroused\", 0) end\r\nif ov >= 4 then add(\"Infatuated\", 0) end\r\nfor _, n in ipairs(K.afflictConds(t, K.curPc)) do add(n, 0) end\r\nfor n, v in pairs(type(t) == \"table\" and type(t.cond) == \"table\" and t.cond or {}) do\r\n\r\nlocal over = false\r\nif type(v) == \"number\" and v >= 0 and now and v <= now then over = true end\r\nif type(v) == \"table\" then\r\nif tonumber(v.ends) and now and now >= v.ends then over = true end\r\nif v.untilR and not (cc and cc.active and cc.fid == v.fid and (tonumber(cc.round) or 1) < v.untilR) then over = true end\r\nend\r\nif type(v) == \"table\" and K.AR.concOver(v.conc, K.curPc) then over = true end\r\nif type(t.condSpell) == \"table\" and K.AR.concOver(t.condSpell[n], K.curPc) then over = true end\r\nlocal r = type(t.condR) == \"table\" and t.condR[n]\r\nif type(r) == \"table\" and cc and not (cc.active and cc.fid == r.fid and (tonumber(cc.round) or 1) < (tonumber(r.to) or 0)) then over = true end\r\nif v and not over then add(n, 0) end\r\nend\r\nreturn o\r\nend\r\n\r\nfunction K.AR.willingFor(t, who)\r\nfor n, row in pairs(K.AR.condsOf(t)) do\r\nif row.willing == \"all\" then return n end\r\nif row.willing == \"source\" then\r\nlocal src = (type(t.condSrc) == \"table\" and t.condSrc[n]) or (type(t.cond) == \"table\" and type(t.cond[n]) == \"table\" and t.cond[n].src)\r\nor (type(t.ar) == \"table\" and K.AR.overHard(t.ar, t) >= 4 and t.ar.overSrc)\r\nif src and who and src == who then return n end\r\nend\r\nend\r\nreturn nil\r\nend\r\nfunction K.AR.blocked(t)\r\nfor n, row in pairs(K.AR.condsOf(t)) do if row.climax == \"block\" then return n end end\r\nreturn nil\r\nend\r\n\r\nfunction K.AR.condText(t)\r\nlocal o = {}\r\nfor n, row in pairs(K.AR.condsOf(t)) do\r\nlocal d = K.condDesc(row)\r\nlocal b = K.bindOf(t, n)\r\nif b then\r\nd = d .. (d ~= \"\" and \"; \" or \"\") .. string.format(\"bound%s%s: escape DC %d, break DC %d%s\", (b.by and b.by ~= \"\") and (\" by \" .. b.by) or \"\", b.src and (\" with \" .. b.src) or \"\", tonumber(b.esc) or 20, tonumber(b.brk) or 20,\r\nb.dis and (\", escape at Disadvantage (\" .. b.dis .. \")\") or \"\")\r\nend\r\no[#o + 1] = n .. (d ~= \"\" and (\" (\" .. d .. \")\") or \"\")\r\nend\r\ntable.sort(o)\r\nreturn #o > 0 and (\", conditions: \" .. table.concat(o, \"; \")) or \"\"\r\nend\r\n\r\nfunction K.AR.condDamaged(t)\r\nif type(t) ~= \"table\" or type(t.cond) ~= \"table\" then return \"\" end\r\nlocal gone = {}\r\nfor n, v in pairs(t.cond) do\r\nif v == -2 or (type(v) == \"table\" and v.dmg) or (type(t.condDmg) == \"table\" and t.condDmg[n]) then\r\nt.cond[n] = nil; gone[#gone + 1] = n\r\nif type(t.condDmg) == \"table\" then t.condDmg[n] = nil end\r\nend\r\nend\r\ntable.sort(gone)\r\nreturn #gone > 0 and (\" (\" .. table.concat(gone, \", \") .. \" ends)\") or \"\"\r\nend\r\n\r\nfunction K.AR.selfUse(r, pc, use)\r\nlocal sh = K.AR.sheetOf(r, pc)\r\nfor _, e in ipairs(sh and Feat.fxOf and Feat.fxOf(sh, \"advance_skill\") or {}) do if e.after_use == use then return e.src or use end end\r\nfor _, e in ipairs(sh and Feat.fxOf and Feat.fxOf(sh, \"self_spend\") or {}) do if e.use == use then return e.src or use end end\r\nreturn nil\r\nend\r\n\r\nfunction K.AR.hdHealTag(f, c, pc)\r\nlocal head = \"[HDHEAL|\" .. table.concat(f, \"|\", 1, math.min(#f, 5))\r\nlocal function no(why) return head .. \"|bad:\" .. why .. \"|-]\", false end\r\nlocal hr, tr = Ally.rec(pc, f[1] or \"\"), Ally.rec(pc, f[2] or \"\")\r\nif not hr or not tr then return no(\"the healer and the target: Player or a companion\") end\r\nif tr.dead then return no((f[2] or \"\") .. \" is dead\") end\r\nlocal hsh, tsh = K.AR.sheetOf(hr, pc), K.AR.sheetOf(tr, pc)\r\nlocal e\r\nfor _, x in ipairs(hsh and Feat.fxOf(hsh, \"hd_heal\") or {}) do if x.src == trim(f[3] or \"\") or x.use == trim(f[3] or \"\") then e = x end end\r\nif not e or not tsh then return no((f[1] or \"\") .. \" has no feature \" .. tostring(f[3]) .. \" that heals with Hit Point Dice\") end\r\nlocal most = math.max(1, K.fxNum(e.n or \"PB\", hsh, e.srcLv))\r\nlocal n = tonumber(f[4]) or most\r\nlocal bad = {}\r\nif n > most then bad[#bad + 1] = \"dice \" .. n .. \"->\" .. most; n = most end\r\nif (tonumber(tr.hd) or 0) < n then bad[#bad + 1] = \"dice \" .. n .. \"->\" .. (tonumber(tr.hd) or 0) .. \" (its Hit Point Dice left)\"; n = tonumber(tr.hd) or 0 end\r\nif n <= 0 then return no((f[2] or \"\") .. \" has no Hit Point Dice left\") end\r\n\r\nif (tonumber(tr.hp) or 0) >= (tonumber(tr.max) or 0) then return no((f[2] or \"\") .. \" is at full HP: no Hit Point Dice spent\") end\r\nlocal free = e.free_ok and trim(f[5] or \"\"):lower() == \"free\"\r\nif e.res and not free then\r\nif not (type(hr.res) == \"table\" and (tonumber(hr.res[e.res]) or 0) >= (tonumber(e.cost) or 1)) then return no(\"no \" .. e.res .. \" left\") end\r\nhr.res[e.res] = hr.res[e.res] - (tonumber(e.cost) or 1)\r\nend\r\n\r\nif e.kit then\r\nif K.kitLeft(pc) < 1 then return no(\"no Healer's Kit in the pack\") end\r\nK.kitSpend(pc)\r\nend\r\nlocal con = abilityMod(K.score(tsh, \"Constitution\"))\r\nlocal add = e.add and K.fxNum(e.add, hsh, e.srcLv) or 0\r\nlocal sum, rolls = 0, {}\r\nlocal room = (tonumber(tr.max) or 0) - math.max(0, tonumber(tr.hp) or 0)\r\nlocal halfBy = K.healHalf(tr, pc)\r\nfor _ = 1, n do\r\nif sum >= room then break end\r\nlocal die = K.hdNext(tsh, tr.hd)\r\nlocal r = K.d(die)\r\nrolls[#rolls + 1] = r\r\nlocal g = math.max(0, r + con + add)\r\nif halfBy then g = math.floor(g / 2) end\r\nsum = sum + g\r\ntr.hd = tr.hd - 1\r\nend\r\nif #rolls < n then bad[#bad + 1] = \"dice \" .. n .. \"->\" .. #rolls .. \" (full HP)\"; n = #rolls end\r\nlocal was = tr.hp\r\nif was <= 0 and sum > 0 then tr.ds, tr.stable, tr.wake = { s = 0, f = 0 }, false, nil end\r\ntr.hp = math.min(tr.max, math.max(0, tr.hp) + sum)\r\nreturn head .. \"|\" .. verdictOf(bad) .. \"|\" .. string.format(\"%d Hit Point Dice (%s), +%d HP, %d/%d\", n, table.concat(rolls, \",\"), tr.hp - was, tr.hp, tr.max)\r\n.. (halfBy and (\" (\" .. halfBy .. \": half)\") or \"\")\r\n.. ((e.res and not free) and string.format(\" (%s %d left)\", e.res, hr.res[e.res]) or (free and \" (free)\" or \"\"))\r\n.. (e.kit and (\" (kit uses \" .. K.kitLeft(pc) .. \")\") or \"\") .. \"]\", #bad == 0\r\nend\r\n\r\nfunction K.AR.ignores(rec, pc)\r\nlocal sh = K.AR.sheetOf(rec, pc)\r\nfor _, e in ipairs(sh and Feat.fxOf and Feat.fxOf(sh, \"inhib_ignore\") or {}) do\r\nif K.usedNow(rec, e.use) then return true end\r\nend\r\nreturn false\r\nend\r\n\r\nfunction K.usedNow(rec, use)\r\nif not use then return true end\r\nreturn Feat.cur.used and Feat.cur.used[rec] and Feat.cur.used[rec][use] and true or false\r\nend\r\nfunction K.AR.pb(rec, pc)\r\nlocal sh = K.AR.sheetOf(rec, pc)\r\nif sh then return 2 + math.floor((K.charLevel(sh) - 1) / 4) end\r\nlocal cr = tostring((MONSTERS[rec.kind or \"\"] or {}).cr or \"0\")\r\nlocal n = cr:find(\"/\") and 0 or (tonumber(cr) or 0)\r\nreturn 2 + math.floor((math.max(1, n) - 1) / 4)\r\nend\r\n\r\n\r\n\r\nfunction K.AR.turnNow(c)\r\nif c.rt and c.rt ~= \"\" then return c.rt end\r\nreturn (type(c.order) == \"table\" and c.order[1]) or nil\r\nend\r\nfunction K.AR.turnAt(c, actor)\r\nlocal r = tonumber(c.round) or 1\r\nlocal ia, ib\r\nfor i, n in ipairs(type(c.order) == \"table\" and c.order or {}) do\r\nif n == actor then ia = i end\r\nif n == c.rt then ib = i end\r\nend\r\nia = ia or ib or 0\r\nif ib and ia < ib then r = r + 1 end\r\nreturn r, ia\r\nend\r\n\r\n\r\nfunction K.AR.inFight(t, c)\r\nreturn type(c) == \"table\" and c.active and not (type(t) == \"table\" and t.side == \"scene\") and true or false\r\nend\r\n\r\n\r\nfunction K.AR.storyClimax(f, c, pc)\r\nlocal head = \"[CLIMAX|\" .. table.concat(f, \"|\", 1, 2)\r\nlocal function no(why) return head .. \"|bad:\" .. why .. \"|-]\", false end\r\nif not K.AR.on() then return no(\"arousal is not in this game (no module brings it)\") end\r\nlocal t = K.AR.target(f[1], c, pc)\r\nif not t then return no(\"target must be Player, a companion or a creature in the scene ([SCENE|Name (stat block)] first)\") end\r\nif t.dead or ((tonumber(t.hp) or 1) <= 0 and not t.zeroAct) then return no((f[1] or \"\") .. \" is down\") end\r\nif K.AR.inFight(t, c) then\r\nreturn no(\"in a fight a climax comes from Edging (its climax saves, stimulation at the maximum) or a spell or feature: [CLIMAX|\" .. (f[1] or \"Name\") .. \"|now|Spell or feature]\")\r\nend\r\nlocal denied = K.AR.blocked(t)\r\nif denied then return head .. \"|ok|no climax: \" .. denied .. \"]\", true end\r\nlocal a, mx = K.AR.st(t), K.AR.max(t, pc)\r\na.cur = math.max(tonumber(a.cur) or 0, mx)\r\nlocal note, extra = K.AR.climax(t, pc, c, f[1], (t == pc and \"Player\") or t.name or f[1])\r\nreturn head .. \"|ok|\" .. note .. \"]\" .. (extra or \"\"), true\r\nend\r\n\r\n\r\nfunction K.AR.incapIn(a, c)\r\nif not (type(a) == \"table\" and type(c) == \"table\" and c.active and tonumber(a.incapTo)) then return false end\r\nif a.incapFight ~= c.fid then return false end\r\nlocal r, i = K.AR.turnAt(c, a.incapWho)\r\nlocal to, at = tonumber(a.incapTo), tonumber(a.incapAt) or 0\r\nfor k, n in ipairs(type(c.order) == \"table\" and c.order or {}) do if n == a.incapAtN then at = k end end\r\nreturn r < to or (r == to and i < at)\r\nend\r\n\r\nfunction K.AR.incapLive(a)\r\nreturn type(a) == \"table\" and tonumber(a.incapUntil) and K.clockRef and tonumber(K.clockRef.min) and K.clockRef.min < a.incapUntil and true or false\r\nend\r\n\r\nfunction K.AR.incapNow(rec)\r\nlocal a = type(rec) == \"table\" and rec.ar\r\n\r\n\r\nif K.AR.incapLive(a) then return true end\r\nif type(a) == \"table\" and rec.side == \"scene\" and tonumber(a.incapUntil) then return false end\r\nif not (type(a) == \"table\" and K.fightNow and tonumber(a.incapTo)) then return false end\r\nif type(K.curC) ~= \"table\" then return false end\r\nreturn K.AR.incapIn(a, K.curC)\r\nend\r\n\r\n\r\n\r\n\r\nfunction K.AR.climax(t, pc, c, who, actor, causer)\r\nlocal a = K.AR.st(t)\r\na.vulnIncap = nil\r\ncauser = causer or actor\r\nwho = (t == pc and \"Player\") or t.name or who\r\nlocal sh = K.AR.sheetOf(t, pc)\r\nlocal left = K.AR.dice(t, pc)\r\nlocal before = tonumber(a.cur) or 0\r\n\r\nlocal csh = K.AR.sheetOf(t, pc)\r\nfor _, x in ipairs(csh and type((csh.base or csh).afflict) == \"table\" and (csh.base or csh).afflict or {}) do\r\nif type(x) == \"table\" and type(x.conc) == \"table\" and not K.AR.concOver(x.conc, pc) then x.conc = nil end\r\nend\r\n\r\nif t.zeroAct then t.zeroAct = nil; Feat.cur.zeroFell = true end\r\n\r\nlocal inFight = K.AR.inFight(t, c)\r\nFeat.cur.climaxed = type(Feat.cur.climaxed) == \"table\" and Feat.cur.climaxed or {}\r\nlocal chained = (inFight and K.AR.incapIn(a, c)) or (not inFight and Feat.cur.climaxed[t])\r\nFeat.cur.climaxed[t] = true\r\na.lastClimax = K.clockRef and tonumber(K.clockRef.min) or 0\r\na.chain = chained and ((tonumber(a.chain) or 1) + 1) or 1\r\nlocal keepEdge = inFight and K.AR.overHard(a, t) >= 5\r\na.edge = keepEdge and { s = 0, f = 0 } or nil\r\nif not keepEdge then a.edgeSince = nil end\r\na.climaxes = type(a.climaxes) == \"table\" and a.climaxes or {}\r\nlocal now = K.clockRef and tonumber(K.clockRef.min) or 0\r\nlocal recent = 0\r\nfor _, m in ipairs(a.climaxes) do if now - (tonumber(m) or -999) <= 1 then recent = recent + 1 end end\r\na.climaxes[#a.climaxes + 1] = now\r\nwhile #a.climaxes > 10 do table.remove(a.climaxes, 1) end\r\nif left <= 0 and not sh and t.side == \"enemy\" then\r\nlocal swapNote, swapExtra = K.AR.swapGift(t, a, pc, c, causer)\r\nt.hp, t.climaxOut = 0, true\r\nlocal by0 = causer and Ally.rec(pc, causer) or nil\r\nreturn \"CLIMAX with no recovery dice left: out of the fight, as one defeated\" .. ((by0 and by0 ~= t) and K.AR.climaxGives(by0, pc, K.AR.onClimax(by0, pc, \"other\"), t) or \"\") .. swapNote, swapExtra\r\nend\r\nif left <= 0 and sh then\r\nreturn \"CLIMAX with no recovery dice left\" .. K.AR.badEnd(t, pc, c, \"a climax with no recovery dice\"), \"\"\r\nend\r\nlocal n, pb, die = 0, K.AR.pb(t, pc), K.AR.dieOf(t, pc)\r\n\r\nlocal con = sh and abilityMod(K.score(sh, \"Constitution\")) or tonumber(((MONSTERS[t.kind or \"\"] or {}).saves or {}).Constitution) or 0\r\nwhile n < pb and left > 0 and a.cur > 0 do\r\na.cur = math.max(0, a.cur - math.max(1, K.dieFor(t, die) + con + K.recoverBonus(t, pc)))\r\nn, left = n + 1, left - 1\r\nend\r\na.used = (tonumber(a.used) or 0) + n\r\nlocal rounds = math.max(1, n)\r\n\r\nlocal mine = K.AR.onClimax(t, pc, \"self\")\r\nlocal half, condAdv = false, false\r\nfor _, e in ipairs(mine) do\r\nif e.half_incap then half = true end\r\nif e.conc_adv then condAdv = true end\r\nend\r\nif half then rounds = math.floor(rounds / 2) end\r\nfor _, e in ipairs(mine) do if e.no_incap then rounds = 0 end end\r\n\r\nlocal chainNote = \"\"\r\nif a.chain > 1 and rounds > 0 then\r\nrounds = rounds + (a.chain - 1)\r\nchainNote = not inFight and string.format(\", climax %d in a row\", a.chain)\r\nor a.chain == 2 and \", a second climax in a row: Stunned while it lasts\" or a.chain == 3 and \", a third in a row: Paralyzed while it lasts\"\r\nor string.format(\", climax %d in a row\", a.chain)\r\nif a.chain >= 4 and sh then chainNote = chainNote .. K.AR.overAdd(t, pc, c, 1, nil) end\r\nend\r\nlocal note = string.format(\"CLIMAX: arousal %d->%d (recovery dice %d)\", before, a.cur, n) .. chainNote .. (keepEdge and \", still Edging (overstimulation 5)\" or \"\")\r\nif rounds <= 0 then\r\na.incapTo, a.incapAt, a.incapUntil = nil, nil, nil\r\nnote = note .. \", not Incapacitated (halved)\"\r\nelseif not inFight then\r\n\r\n\r\na.incapTo, a.incapAt, a.incapUntil = nil, nil, nil\r\nnote = note .. \", Incapacitated for a moment (the story's)\"\r\nelseif type(c) == \"table\" and c.active then\r\n\r\nlocal r0, i0 = K.AR.turnAt(c, actor)\r\nlocal at = type(c.order) == \"table\" and c.order[i0]\r\na.incapTo, a.incapAt, a.incapAtN, a.incapWho, a.incapFight = r0 + rounds, i0, at or nil, who, c.fid\r\na.incapUntil = nil\r\nnote = note .. string.format(\", Incapacitated until round %d\", a.incapTo) .. (at and string.format(\" (%s's turn)\", at) or \"\")\r\n\r\nlocal cn = a.chain == 2 and \"Stunned\" or a.chain >= 3 and \"Paralyzed\"\r\nif cn and sh then\r\nt.cond = type(t.cond) == \"table\" and t.cond or {}\r\nt.condR = type(t.condR) == \"table\" and t.condR or {}\r\nt.cond[cn], t.condR[cn] = -3, { to = a.incapTo, fid = c.fid }\r\nend\r\nend\r\nlocal extra = \"\"\r\nnote = note .. K.AR.poolFill(t, pc)\r\n\r\n\r\nif type(a.bond) == \"table\" then\r\nlocal bs = a.bond.spell\r\nif n > 0 then note = note .. K.AR.bondHit(t, pc, c, 0, n, true) else a.bond = nil; note = note .. \" (\" .. bs .. \": the bond ends)\" end\r\nif type(t.conc) == \"table\" and t.conc.name == bs then t.conc = nil end\r\nend\r\nif type(t.conc) == \"table\" and t.conc.name and not t.conc.lost and (t == pc or Ally.find(pc, t.name or \"\")) then\r\nlocal dc = 15 + recent\r\nlocal bonus = Ally.run(pc, t, function() return bonusFor(\"Constitution save\") - Cond.fx(t).pen end)\r\nlocal d = K.d(20)\r\nif condAdv then d = math.max(d, K.d(20)) end\r\nlocal kept = d + bonus >= dc\r\nif not kept then t.conc.lost = true end\r\nextra = string.format(\"\\n[CONCSAVE|%s|%s|%d|%+d|%d|%s]\", t.name or \"Player\", t.conc.name, d, bonus, dc, kept and \"kept\" or \"lost\")\r\nend\r\n\r\nlocal sn, sx = K.AR.swapGift(t, a, pc, c, causer)\r\nnote, extra = note .. sn, extra .. sx\r\n\r\nnote = note .. K.AR.climaxGives(t, pc, mine, t)\r\nlocal by = causer and Ally.rec(pc, causer) or nil\r\nif by and by ~= t then note = note .. K.AR.climaxGives(by, pc, K.AR.onClimax(by, pc, \"other\"), t) end\r\nif t == pc or t.sheet then note = note .. K.MI.climaxCharge(t) end\r\nreturn note, extra\r\nend\r\n\r\nfunction K.AR.onClimax(rec, pc, when)\r\nlocal o = {}\r\nlocal sh = K.AR.sheetOf(rec, pc)\r\nif not sh or not Feat.fxOf then return o end\r\nlocal mode = type(rec.mode) == \"table\" and rec.mode.name\r\nfor _, e in ipairs(Feat.fxOf(sh, \"on_climax\")) do\r\nif (e.when or \"self\") == when and (not e.mode or e.mode == mode) and K.usedNow(rec, e.use) then o[#o + 1] = e end\r\nend\r\nreturn o\r\nend\r\n\r\nfunction K.AR.climaxGives(rec, pc, list, who)\r\nlocal note = \"\"\r\nlocal sh = K.AR.sheetOf(rec, pc)\r\nfor _, e in ipairs(list) do\r\nlocal src = e.src or \"on_climax\"\r\nif type(e.regain) == \"table\" then note = note .. K.regain(rec, pc, e.regain, src) end\r\n\r\n\r\nif type(e.mark_cond) == \"table\" and e.mark_cond.mark and K.curC and K.curC.active then\r\nlocal got = {}\r\nlocal puts = type(e.mark_cond.put) == \"table\" and e.mark_cond.put or { e.mark_cond.put or \"Stunned\" }\r\nfor nm, u in pairs(K.curC.units or {}) do\r\nif u.side == \"enemy\" and type(u.cond) == \"table\" and u.cond[e.mark_cond.mark] and (tonumber(u.hp) or 0) > 0 then\r\nlocal now = K.featCondPut(u, puts, src, rec == pc and \"Player\" or (rec.name or \"Player\"), nil, K.curC, nil, { rounds = e.mark_cond.rounds or 1 })\r\nif #now > 0 then got[#got + 1] = nm end\r\nend\r\nend\r\ntable.sort(got)\r\nif #got > 0 then note = note .. \" (\" .. src .. \": \" .. table.concat(got, \", \") .. \" now \" .. table.concat(puts, \", \") .. \")\" end\r\nend\r\nif e.cast_up then\r\nFeat.cur.climaxCast = Feat.cur.climaxCast or {}\r\nFeat.cur.climaxCast[rec] = { src = src }\r\nnote = note .. \" (\" .. src .. \": one CAST now, a level higher)\"\r\nend\r\n\r\nif e.use and Feat.cur.used and Feat.cur.used[rec] then Feat.cur.used[rec][e.use] = nil end\r\nif e.thp ~= nil then\r\nlocal n = math.max(1, K.fxNum(e.thp, sh, e.srcLv))\r\nrec.thp = math.max(tonumber(rec.thp) or 0, n)\r\nnote = note .. string.format(\" (%s: %d temporary HP)\", src, n)\r\nend\r\nif e.heal ~= nil and not rec.dead then\r\nlocal n\r\nif e.heal == \"target\" then\r\nlocal wsh = K.AR.sheetOf(who, pc)\r\nlocal cr = tostring((MONSTERS[who.kind or \"\"] or {}).cr or \"1\")\r\nn = wsh and K.charLevel(wsh) or math.max(1, cr:find(\"/\") and 1 or math.floor(tonumber(cr) or 1))\r\nelse\r\nn = K.fxNum(e.heal, sh, e.srcLv)\r\nend\r\nif n > 0 and tonumber(rec.hp) and tonumber(rec.max) then\r\nlocal was = rec.hp\r\nif was <= 0 then rec.ds, rec.stable, rec.wake = { s = 0, f = 0 }, false, nil end\r\nrec.hp = math.min(rec.max, math.max(0, rec.hp) + n)\r\nnote = note .. string.format(\" (%s: %s regains %d HP, %d/%d)\", src, rec == pc and \"Player\" or (rec.name or \"?\"), rec.hp - was, rec.hp, rec.max)\r\nend\r\nend\r\nif e.res then\r\nlocal n\r\nif type(e.n) == \"string\" and e.n:match(\"^%d*d%d+$\") then\r\nn = 0\r\nfor _, d in ipairs(parseFormula(e.n).dice) do for _ = 1, d.n do n = n + K.d(d.s) end end\r\nelse\r\nn = K.fxNum(e.n or 1, sh, e.srcLv)\r\nend\r\nlocal top = Ally.run(pc, rec ~= pc and rec or nil, function() return PC.res[e.res] and PC.res[e.res].max end)\r\nrec.res = type(rec.res) == \"table\" and rec.res or {}\r\nif top then\r\nlocal was = rec.res[e.res] or 0\r\nrec.res[e.res] = math.min(top, was + n)\r\nnote = note .. string.format(\" (%s: %s %d/%d)\", src, e.res, rec.res[e.res], top)\r\nend\r\nend\r\nif e.note then note = note .. \" (\" .. src .. \": \" .. e.note .. \")\" end\r\nend\r\nreturn note\r\nend\r\n\r\n\r\n\r\nfunction K.AR.climaxAdvSrc(t, pc)\r\nlocal sh = K.AR.sheetOf(t, pc)\r\nif not sh then return nil end\r\nfor _, e in ipairs(Feat.fxOf(sh, \"climax_save\") or {}) do if e.auto == \"adv\" then return e.src or \"climax_save\" end end\r\nfor _, x in ipairs(K.afflictOn(sh)) do\r\nif x.e.on ~= false and type(x.rec.text) == \"string\" and x.rec.text:lower():find(\"%f[%a]advantage on climax saves\") then return x.e.name end\r\nend\r\nreturn nil\r\nend\r\n\r\n\r\nfunction K.AR.climaxSave(f, pools, cur, c, pc)\r\nlocal head = \"[CLIMAX|\" .. table.concat(f, \"|\", 1, 5)\r\nlocal function no(why)\r\nK.spendRefused(pools, cur, f[2])\r\nreturn head .. \"|bad:\" .. why .. \"|-]\", false\r\nend\r\nif not K.AR.on() then return no(\"arousal is not in this game (no module brings it)\") end\r\nlocal t = K.AR.target(f[1], c, pc)\r\nif not t then return no(\"target must be Player, a companion or a creature in the fight\") end\r\nif t.dead or ((tonumber(t.hp) or 1) <= 0 and not t.zeroAct) then return no((f[1] or \"\") .. \" is down\") end\r\nlocal a, mx = K.AR.st(t), K.AR.max(t, pc)\r\nlocal legacyRoll = false\r\nlocal prefixed = trim(f[2] or \"\"):lower() == \"d20\"\r\nlocal givenRoll = trim(f[3] or \"\")\r\nif prefixed and (givenRoll:match(\"^%d+$\") or givenRoll:match(\"^adv %d+,%s*%d+$\") or givenRoll:match(\"^dis %d+,%s*%d+$\")) then\r\n\r\n\r\ntable.remove(f, 2)\r\nif trim(f[5] or \"\") == \"\" then f[5] = \"\"; legacyRoll = true end\r\nhead = \"[CLIMAX|\" .. table.concat(f, \"|\", 1, 5)\r\nend\r\n\r\nlocal advFix\r\nlocal a1 = trim(f[2] or \"\"):match(\"^[Aa][Dd][Vv]%s+(%d+)%s*,%s*%d+$\")\r\nif a1 and not K.AR.climaxAdvSrc(t, pc) then\r\nadvFix = \"no Advantage source: adv->\" .. a1\r\nf[2] = a1\r\nhead = \"[CLIMAX|\" .. table.concat(f, \"|\", 1, 5)\r\nend\r\n\r\nlocal cs = {}\r\nlocal csh = K.AR.sheetOf(t, pc)\r\nfor _, e in ipairs(csh and Feat.fxOf(csh, \"climax_save\") or {}) do\r\nif e.auto == \"fail\" then cs.fail = e.src or \"climax_save\" end\r\nif e.on_fail == \"climax\" then cs.climax = e.src or \"climax_save\" end\r\nend\r\n\r\nif trim(f[6] or \"\"):lower() == \"extra\" then\r\nhead = \"[CLIMAX|\" .. table.concat(f, \"|\", 1, math.min(#f, 7))\r\nlocal bad = { advFix }\r\nlocal rec = (t == pc or Ally.find(pc, t.name or \"\")) and t or nil\r\nlocal roll, _, nat = takeD20(cur, pools, f[2] or \"\", bad, rec, rec and \"save\" or nil)\r\nlocal bonus = K.AR.inhib(t, pc)\r\nif tonumber(((f[3] or \"\"):gsub(\"^%s*%+\", \"\"))) ~= bonus then bad[#bad + 1] = \"bonus \" .. tostring(f[3]) .. \"->\" .. string.format(\"%+d\", bonus) end\r\nif tonumber(f[4]) ~= K.AR.DC then bad[#bad + 1] = \"DC \" .. tostring(f[4]) .. \"->\" .. K.AR.DC end\r\nlocal should = (K.AR.blocked(t) or (not cs.fail and (nat == 20 or (nat ~= 1 and (tonumber(roll) or 0) + bonus >= K.AR.DC)))) and \"success\" or \"failure\"\r\nif legacyRoll then\r\nf[5] = should\r\nhead = \"[CLIMAX|\" .. table.concat(f, \"|\", 1, math.min(#f, 7))\r\nelseif (f[5] or \"\"):lower() ~= should then bad[#bad + 1] = \"result \" .. tostring(f[5]) .. \"->\" .. should end\r\nlocal note = should == \"success\" and \"no more overstimulation\" or (\"overstimulation\" .. K.AR.overAdd(t, pc, c, 1, trim(f[7] or \"\") ~= \"\" and trim(f[7]) or nil))\r\nif should == \"failure\" and cs.fail then note = note .. \" (\" .. cs.fail .. \": a failure by itself)\" end\r\nlocal cxtra = \"\"\r\nif should == \"failure\" and cs.climax then\r\nlocal cn, cx = K.AR.climax(t, pc, c, f[1], (t == pc and \"Player\") or t.name or f[1])\r\nnote, cxtra = note .. \", \" .. tostring(cn), cx or \"\"\r\nend\r\n\r\nlocal owner = should == \"failure\" and Ally.rec(pc, trim(f[7] or \"\"))\r\nlocal osh = owner and K.AR.sheetOf(owner, pc)\r\nfor _, e in ipairs(osh and Feat.fxOf(osh, \"climax_extra\") or {}) do note = note .. K.regain(owner, pc, e.regain, e.src) end\r\nreturn head .. \"|\" .. verdictOf(bad) .. \"|\" .. note .. \"]\" .. cxtra, #bad == 0\r\nend\r\n\r\nif not K.AR.inFight(t, c) then\r\nreturn no(\"out of a fight there are no climax saves (no Edging there): when the story reaches a climax, [CLIMAX|\" .. (f[1] or \"Name\") .. \"|now]\")\r\nend\r\n\r\n\r\nif type(a.edge) ~= \"table\" and type(Feat.cur.edgeWas) == \"table\" and Feat.cur.edgeWas[t] then\r\nK.spendRefused(pools, cur, f[2])\r\nreturn head .. \"|ok|no longer Edging (it ended earlier in this reply): nothing more]\", true\r\nend\r\nif type(a.edge) ~= \"table\" then return no((f[1] or \"\") .. \" is not Edging (its arousal is below the maximum)\") end\r\nFeat.cur.edgeWas = type(Feat.cur.edgeWas) == \"table\" and Feat.cur.edgeWas or {}\r\nFeat.cur.edgeWas[t] = true\r\nlocal bad = { advFix }\r\nlocal rec = (t == pc or Ally.find(pc, t.name or \"\")) and t or nil\r\nlocal roll, _, nat = takeD20(cur, pools, f[2] or \"\", bad, rec, rec and \"save\" or nil)\r\nlocal bonus = K.AR.inhib(t, pc)\r\nlocal wb = (f[3] or \"\"):gsub(\"^%s*%+\", \"\")\r\nlocal old = Feat.cur.inhib0 and Feat.cur.inhib0[t]\r\nif old and tonumber(wb) == old and old ~= bonus then\r\nf[3] = string.format(\"%+d\", bonus)\r\nhead = \"[CLIMAX|\" .. table.concat(f, \"|\", 1, 5)\r\nelseif tonumber(wb) ~= bonus then bad[#bad + 1] = \"bonus \" .. tostring(f[3]) .. \"->\" .. string.format(\"%+d\", bonus) end\r\nif tonumber(f[4]) ~= K.AR.DC then bad[#bad + 1] = \"DC \" .. tostring(f[4]) .. \"->\" .. K.AR.DC end\r\nlocal should, note, extra\r\nlocal denied = K.AR.blocked(t)\r\nif denied then\r\nshould = \"success\"\r\na.edge.s = (tonumber(a.edge.s) or 0) + 1\r\nnote = string.format(\"%s: a success by itself; Edging: %d successes, %d failures\", denied, a.edge.s, a.edge.f or 0)\r\nelseif cs.fail then\r\nshould = \"failure\"\r\na.edge.f = (tonumber(a.edge.f) or 0) + 1\r\nnote = nil\r\nelseif nat == 20 then\r\nshould = \"success\"\r\na.cur, a.edge = mx - 1, nil\r\nnote = \"a natural 20: no longer Edging, arousal \" .. a.cur .. \"/\" .. mx\r\nelseif nat == 1 then\r\nshould = \"failure\"\r\na.edge.f = (tonumber(a.edge.f) or 0) + 2\r\nelseif (tonumber(roll) or 0) + bonus >= K.AR.DC then\r\nshould = \"success\"\r\na.edge.s = (tonumber(a.edge.s) or 0) + 1\r\nelse\r\nshould = \"failure\"\r\na.edge.f = (tonumber(a.edge.f) or 0) + 1\r\nend\r\nif legacyRoll then\r\nf[5] = should\r\nhead = \"[CLIMAX|\" .. table.concat(f, \"|\", 1, 5)\r\nelseif (f[5] or \"\"):lower() ~= should then bad[#bad + 1] = \"result \" .. tostring(f[5]) .. \"->\" .. should end\r\nlocal failNote = should == \"failure\" and K.AR.climaxGives(t, pc, K.AR.onClimax(t, pc, \"fail\"), t) or \"\"\r\nif should == \"failure\" and c.active then\r\nfor _, r in ipairs(K.concRecs(pc)) do\r\nif r ~= t then failNote = failNote .. K.AR.climaxGives(r, pc, K.AR.onClimax(r, pc, \"other_fail\"), t) end\r\nend\r\nend\r\nlocal me = (t == pc and \"Player\") or t.name or f[1]\r\nif c.active then c.last = me end\r\nif should == \"failure\" and cs.climax and type(a.edge) == \"table\" then a.edge.f = math.max(3, tonumber(a.edge.f) or 0) end\r\nif cs.fail and should == \"failure\" then failNote = \" (\" .. cs.fail .. \": a failure by itself)\" .. failNote end\r\nif type(a.edge) == \"table\" and a.edge.f >= 3 then\r\nnote, extra = K.AR.climax(t, pc, c, f[1], me)\r\nelseif type(a.edge) == \"table\" and a.edge.s >= 3 then\r\na.cur, a.edge = mx - 1, nil\r\nnote = \"three successes: no longer Edging, arousal \" .. a.cur .. \"/\" .. mx\r\nend\r\nnote = (note or string.format(\"Edging: %d successes, %d failures\", a.edge.s, a.edge.f)) .. failNote\r\nreturn head .. \"|\" .. verdictOf(bad) .. \"|\" .. note .. \"]\" .. (extra or \"\"), #bad == 0\r\nend\r\n\r\n\r\n\r\n\r\nfunction K.AR.climaxBy(f, c, pc)\r\nlocal head = \"[CLIMAX|\" .. table.concat(f, \"|\", 1, 3)\r\nlocal function no(why) return head .. \"|bad:\" .. why .. \"|-]\", false end\r\nif not K.AR.on() then return no(\"arousal is not in this game (no module brings it)\") end\r\nlocal t = K.AR.target(f[1], c, pc)\r\nif not t then return no(\"target must be Player, a companion or a creature in the fight\") end\r\nif t.dead or ((tonumber(t.hp) or 1) <= 0 and not t.zeroAct) then return no((f[1] or \"\") .. \" is down\") end\r\nlocal mode = (f[2] or \"\"):lower()\r\nlocal n = Canon.name(f[3] or \"\")\r\nlocal cast\r\nfor _, x in ipairs(Feat.cur.casts or {}) do if x.name == n then cast = x end end\r\nlocal m = SPELLS[n] and SPELLS[n].m or {}\r\nif mode == \"vuln\" then\r\nif not m.climax_vuln then return no((f[3] or \"?\") .. \" is no spell that does that (vulnerable after a climax)\") end\r\nif not cast then return no(\"write [CAST|\" .. n .. \"|level] first, in this reply\") end\r\nlocal a0 = K.AR.st(t)\r\nif not (K.AR.incapIn(a0, c) or K.AR.incapLive(a0)) then return no((f[1] or \"\") .. \" is not Incapacitated by a climax now\") end\r\na0.vulnIncap = true\r\nreturn head .. \"|ok|vulnerable to stimulation while that climax's Incapacitated lasts]\", true\r\nend\r\n\r\n\r\nif mode == \"now\" and not SPELLS[n] then\r\nlocal tsh = K.AR.sheetOf(t, pc)\r\nlocal fits, byAff = false, false\r\nfor _, e in ipairs(tsh and Feat.fxOf(tsh, \"on_climax\") or {}) do if e.use and Canon.name(e.use) == n then fits = true end end\r\n\r\nlocal ax = tsh and K.afflictHas(tsh, n)\r\nif ax then for _, e in ipairs(ax.fx) do if e.t == \"climax_now\" then fits, byAff = true, true end end end\r\nif fits then\r\nif not byAff and not K.usedNow(t, n) then return no(\"write [USE|\" .. n .. \"] first, in this reply\") end\r\nlocal denied = K.AR.blocked(t)\r\nif denied then return head .. \"|ok|no climax: \" .. denied .. \"]\", true end\r\nlocal note, extra = K.AR.climax(t, pc, c, f[1], (t == pc and \"Player\") or t.name or f[1])\r\nreturn head .. \"|ok|\" .. note .. \"]\" .. (extra or \"\"), true\r\nend\r\nend\r\nlocal want = mode == \"now\" and m.climax_now or m.climax_end\r\nif type(want) ~= \"table\" then return no((f[3] or \"?\") .. \" is no spell that does that (\" .. (mode == \"now\" and \"a climax at once\" or \"ends a climax's Incapacitated\") .. \")\") end\r\nif not cast then return no(\"write [CAST|\" .. n .. \"|level] first, in this reply\") end\r\nlocal by = cast.by and Ally.find(pc, cast.by) or pc\r\nlocal a, mx = K.AR.st(t), K.AR.max(t, pc)\r\nlocal me = by == pc and \"Player\" or (by.name or \"?\")\r\nif mode == \"now\" then\r\nlocal gap = mx - (tonumber(a.cur) or 0)\r\nlocal under = tonumber(want.under) or 0\r\nlocal denied = K.AR.blocked(t)\r\nif denied then return head .. \"|ok|no climax: \" .. denied .. \"]\", true end\r\nif gap >= under then return head .. \"|ok|\" .. string.format(\"no climax: %d to its maximum, not under %d\", gap, under) .. \"]\", true end\r\nlocal note, extra = K.AR.climax(t, pc, c, f[1], me)\r\nif want.vuln then a.vulnIncap = true end\r\nreturn head .. \"|ok|\" .. note .. \"]\" .. (extra or \"\"), true\r\nend\r\nif not (K.AR.incapIn(a, c) or K.AR.incapLive(a)) then return no((f[1] or \"\") .. \" is not Incapacitated by a climax now\") end\r\na.incapTo, a.incapAt, a.incapAtN, a.incapWho, a.incapFight, a.vulnIncap, a.incapUntil = nil, nil, nil, nil, nil, nil, nil\r\nlocal numb = 0\r\nif want.numb == \"ATK\" then\r\nnumb = Ally.run(pc, by ~= pc and by or nil, function() local st = Spell.stats(n); return st and st.atk or 0 end)\r\nelseif want.numb ~= nil then\r\nnumb = tonumber(K.spellTerms(tostring(want.numb), n, by, pc)) or 0\r\nend\r\nif numb > 0 then a.numb = math.max(tonumber(a.numb) or 0, numb) end\r\nreturn head .. \"|ok|\" .. \"no longer Incapacitated\" .. (numb > 0 and string.format(\", numbness %d\", a.numb) or \"\") .. \"]\", true\r\nend\r\nfunction K.AR.text(rec, pc, c)\r\nlocal a, mx = K.AR.st(rec), K.AR.max(rec, pc)\r\nlocal left, all = K.AR.dice(rec, pc)\r\nlocal sh = K.AR.sheetOf(rec, pc)\r\n\r\n\r\n\r\nlocal inFight = K.AR.inFight(rec, c)\r\nlocal edge = inFight and type(a.edge) == \"table\" and string.format(\", EDGING: climax saves %d successes, %d failures ([CLIMAX|...|15|%+d|15|success] at the start of its turns)\",\r\ntonumber(a.edge.s) or 0, tonumber(a.edge.f) or 0, K.AR.inhib(rec, pc)) or \"\"\r\n\r\n\r\nif inFight and edge == \"\" and not K.AR.incapIn(a, c) and (tonumber(a.cur) or 0) < mx and (tonumber(a.cur) or 0) >= mx * 0.8 then\r\nedge = string.format(\", not Edging yet: no climax save until stimulation brings it to %d (then Edging)\", mx)\r\nend\r\nif not inFight and (tonumber(a.cur) or 0) >= mx then edge = \", at its maximum\" end\r\nlocal at = a.incapAtN\r\nlocal incap = K.AR.incapIn(a, c)\r\nand string.format(\", CLIMAXED: Incapacitated until round %d%s (no actions, no reactions)\", a.incapTo, at and string.format(\", %s's turn\", at) or \"\") or \"\"\r\nreturn string.format(\"Arousal %d/%d%s%s%s%s%s\", tonumber(a.cur) or 0, mx, sh and string.format(\", recovery dice %d/%d (d%d)\", left, all, K.AR.die(sh)) or \"\",\r\n(tonumber(a.numb) or 0) > 0 and (\", numbness \" .. a.numb) or \"\", edge, incap, K.AR.condText(rec)\r\n.. ((tonumber(a.overstim) or 0) > 0 and (\", overstimulation \" .. a.overstim .. (a.overSrc and (\" (from \" .. a.overSrc .. \")\") or \"\")\r\n.. (function() local lo, ls = K.AR.overLow(rec); return lo > 0 and string.format(\" (counted as %d: %s)\", math.max(0, a.overstim - lo), ls or \"overstim_lower\") or \"\" end)()) or \"\")\r\n.. (type(rec.badEnd) == \"table\" and (\", BAD END (\" .. rec.badEnd.why .. \")\" .. ((K.D2.perm == \"on\" and not rec.badEnd.rec)\r\nand string.format(\": write one [BADEND|%s|kind|a short line] (kind captive, addiction, curse or background)\", rec == pc and \"Player\" or (rec.name or \"?\")) or \"\")) or \"\")\r\n.. K.AR.badResText(rec) .. ((rec == pc or rec.sheet) and K.drainText(rec, pc) or \"\") .. K.PG.text(rec, pc) .. K.afflictText(rec, pc)\r\n.. ((K.AR.posOf(rec, pc) == \"top\" and \", a top: penetrates, is never penetrated\") or (K.AR.posOf(rec, pc) == \"bottom\" and \", a bottom: is penetrated, never penetrates\") or \"\"))\r\nend\r\n\r\nK.AR.STORY = \"Out of a fight arousal is the story's: no Edging and no climax saves. At its maximum it stays there until the story reaches a climax;\"\r\n.. \" then write one [CLIMAX|Name|now] (Lua spends the recovery dice, counts the climax and plays what follows it).\"\r\n.. \" ADVANCE and STIM out of a fight only when a spell or feature asks for one, or when the user wants the numbers.\"\r\n\r\n\r\nK.AR.WORDS = \"In Korean (the story, a status line): Arousal = 흥분도, inhibition = 억제, recovery dice = 회복 주사위, stimulation = 자극, numbness = 둔감, Edging = 임계, climax = 절정.\"\r\nfunction K.AR.badResText(rec)\r\nlocal o = {}\r\nfor k, v in pairs(type(rec.badRes) == \"table\" and rec.badRes or {}) do o[#o + 1] = k .. \" (\" .. tostring(type(v) == \"table\" and v.text or v) .. \")\" end\r\ntable.sort(o)\r\nreturn #o > 0 and (\", bad end aftermath: \" .. table.concat(o, \"; \")) or \"\"\r\nend\r\n\r\nK.AR_SHAPE = {\r\nBIND = \"[BIND|Binder|Target|Condition|Restraint or Spell|willing/unwilling] or [BIND|-|Target|Condition or all]\",\r\nESCAPE = \"[ESCAPE|Target|Condition|Skill|d20|+bonus|DC|success/failure]\",\r\nSTRIP = \"[STRIP|Target|d20|+Sleight of Hand bonus|its AC now|success/failure] (a companion's: Name/Target)\",\r\nPREG = \"[PREG|Target|+|Source|nontraditional|term], [PREG|Target|shows], [PREG|Target|term|+8h], [PREG|Holder|move|Receiver] or [PREG|Target|-|birth or end|a short line]\",\r\nIMPREG = \"[IMPREG|Impregnator|Target|d20|+its Constitution check|DC|success/failure|willing/unwilling]\",\r\nCURSE = \"[CURSE|Target|+Name|source|level] or [CURSE|Target|-Name|Remove Curse N]\",\r\nBRAND = \"[BRAND|Target|+Name|stage|source] or [BRAND|Target|Name|+1]\",\r\nFETISH = \"[FETISH|Target|+Name|1h|source] or [FETISH|Target|-Name]\",\r\nVICE = \"[VICE|Target|Name|partake|d20|+save|DC|success/failure]\",\r\nSWAP = \"[SWAP|A|B|Spell]\",\r\nOVERSTIM = \"[OVERSTIM|Target|+N|source] or [OVERSTIM|Target|-N]\",\r\nSCORE = \"[SCORE|Target|Ability|-N|min M|until] or [SCORE|Target|Ability|end]\",\r\nBADEND = \"[BADEND|Name|kind|a short line]\",\r\nMAXDOWN = \"[MAXDOWN|Target|hp or arousal|N|until] or [MAXDOWN|Target|hp|end]\",\r\nHDHEAL = \"[HDHEAL|Healer|Target|Feature|N]\",\r\nBOND = \"[BOND|Caster|Target|Spell]\",\r\nREACT = \"[REACT|Who|Feature] or [REACT|Who|Feature|Ally or all]\",\r\n}\r\n\r\nK.AR_TAGS = { STIM = true, SOOTHE = true, NUMB = true, CLIMAX = true, ADVANCE = true, INHIB = true, SWAP = true, REACT = true, BOND = true,\r\nHDHEAL = true, OVERSTIM = true, BADEND = true }\r\n\r\n\r\n\r\nfunction K.AR.hot(r, c)\r\nif type(r) ~= \"table\" then return false end\r\nlocal a = type(r.ar) == \"table\" and r.ar or {}\r\nreturn (tonumber(a.cur) or 0) > 0 or (tonumber(a.numb) or 0) > 0 or type(a.edge) == \"table\" or (a.incapTo and K.AR.incapIn(a, c)) or (tonumber(a.overstim) or 0) > 0\r\nor type(r.badEnd) == \"table\" or (type(r.badRes) == \"table\" and next(r.badRes) ~= nil) or next(K.AR.condsOf(r)) ~= nil\r\nor (type(r.maxDown) == \"table\" and r.maxDown.arousal ~= nil)\r\nend\r\nfunction K.AR.scan(pc, c)\r\nlocal o = { warm = type(pc) == \"table\" and pc.arWarm or false }\r\nlocal recs = type(pc) == \"table\" and { pc, table.unpack(Ally.list(pc)) } or {}\r\nif type(c) == \"table\" and c.active then for _, u in pairs(c.units or {}) do if u.side == \"enemy\" then recs[#recs + 1] = u end end end\r\n\r\n\r\nif type(pc) == \"table\" and type(pc.scene) == \"table\" then for _, u in pairs(pc.scene.units or {}) do if type(u) == \"table\" then recs[#recs + 1] = u end end end\r\nfor _, r in ipairs(recs) do\r\nlocal a = type(r.ar) == \"table\" and r.ar or {}\r\nif K.AR.hot(r, c) then o.warm = true end\r\nif (type(a.edge) == \"table\" and K.AR.inFight(r, c)) or (a.incapTo and K.AR.incapIn(a, c)) then o.edge = true end\r\nif (tonumber(a.overstim) or 0) > 0 or type(r.badEnd) == \"table\" or (type(r.badRes) == \"table\" and next(r.badRes) ~= nil) then o.over = true end\r\nif next(K.AR.condsOf(r)) ~= nil then o.cond = true end\r\nlocal ash = K.AR.sheetOf(r, pc)\r\nif ash and type((ash.base or ash).afflict) == \"table\" and next((ash.base or ash).afflict) then o.afflict, o.warm = true, true end\r\nif (type(r.sdrain) == \"table\" and next(r.sdrain)) or (type(r.sheet) == \"table\" and type(r.sheet.sdrain) == \"table\" and next(r.sheet.sdrain))\r\nor (type(r.maxDown) == \"table\" and next(r.maxDown)) then o.score = true end\r\nend\r\nif SHEET and type(SHEET.sdrain) == \"table\" and next(SHEET.sdrain) then o.score = true end\r\n\r\nfor n, sp in pairs(SPELLS) do\r\nlocal m = type(sp.m) == \"table\" and sp.m\r\nif m and (m.climax_now or m.climax_end or m.climax_vuln or m.inhib or m.inhib_vs or m.swap or m.bond or m.climax_pool) and Spell.known(n) then o.spells = true end\r\nend\r\nfor _, r in ipairs({ pc, table.unpack(Ally.list(pc)) }) do\r\nlocal sh = K.AR.sheetOf(r, pc)\r\nfor _, k in ipairs({ \"dmg_to_stim\", \"hd_heal\", \"inhib_src\" }) do if sh and #Feat.fxOf(sh, k) > 0 then o.feats = true end end\r\nend\r\nreturn o\r\nend\r\n\r\nfunction K.AR.apSaveText()\r\nreturn (K.D2.mode == \"hard\"\r\nand (\"A save against an approach spell takes the target's inhibition on its save bonus unless the SAVE ends |willing (Lua adds it:\"\r\n.. \" write the bonus as listed); Player's or a companion's save against a creature's approach ends |unwilling or |willing\")\r\nor (\"A save against an approach spell takes a negative inhibition on its save bonus (Lua adds it); Player's or a companion's save\"\r\n.. \" against a creature's approach ends |willing\"))\r\n.. \" (a SAVE after its damage, a CHECK after its result).\"\r\nend\r\nfunction K.AR.rules(pc, c)\r\nif not K.AR.on() then return nil end\r\nlocal sc = K.AR.scan(pc, c)\r\nlocal adv = next(K.PACK.impl) and \" a direct approach [ADVANCE|Attacker|Target|Implement|willing/unwilling|d20|+bonus|AC|hit/miss/crit|formula|dice|stim]\" or \"\"\r\n\r\nlocal story = not (type(c) == \"table\" and c.active) and (\" \" .. K.AR.STORY) or \"\"\r\nif not sc.warm then\r\n\r\nreturn K.AR.WORDS .. story .. \" Arousal (Lua keeps it, beside HP; all quiet now): stimulation [STIM|Target|Source|Type|formula|dice|amount] (Type a damage type), soothing\"\r\n.. \" [SOOTHE|Target|Source|formula|dice|amount],\" .. adv .. (K.PACK.bind and \", binding [BIND|Binder|Target|Condition|Restraint or Spell|willing/unwilling]\" or \"\")\r\n.. \", a creature out of a fight as a target: [SCENE|Name (stat block)] first\"\r\n.. (K.PACK.afflict and \", a curse [CURSE|Target|+Name|source|level], a brand [BRAND|Target|+Name|stage|source], a fetish for a while [FETISH|Target|+Name|1h|source], a vice [VICE|Target|Name|partake|d20|+save|DC|success/failure]\" or \"\")\r\n.. \". \" .. K.AR.apSaveText()\r\n.. \" The rest of the rules come in the request once arousal is in play; a spell or feature line that names a tag gives its shape.\"\r\n.. (K.PACK.ar.text and (\" \" .. K.PACK.ar.text) or \"\")\r\nend\r\nlocal o = { K.AR.WORDS .. \" Arousal (Lua keeps it, beside HP): stimulation [STIM|Target|Source|Type|formula|dice|amount] (Type one of the damage types,\"\r\n.. \" its dice from the pool as damage; numbness takes it first; a save that halves it: |half after the amount, the amount halved;\"\r\n.. \" MOD and PB in a formula are its caster's), soothing [SOOTHE|Target|Source|formula|dice|amount],\"\r\n.. \" numbness [NUMB|Target|N] (the higher stays; [NUMB|Target|N|Spell] when a spell gives it).\"\r\n.. (story ~= \"\" and story or (\" In a fight, at its maximum a creature is Edging (not a climax: a climax is told only after a CLIMAX result);\"\r\n.. \" more stimulation at the maximum is a failure of its climax saves, as much as the maximum at once a climax.\"))\r\n.. \" Lua spends the recovery dice of a climax and of rests.\" }\r\nif sc.edge then\r\no[#o + 1] = \"Edging (in a fight): at the start of each of its turns a climax save [CLIMAX|Target|15|+bonus|15|success/failure]\"\r\n.. \" (replace the third field with the rolled d20 value, e.g. 15; adv N,M only when its own listed feature or affliction gives Advantage on climax saves, dis N,M when one gives Disadvantage (443). Never write the literal word d20; the bonus is Lua's: three successes bring it\"\r\n.. \" to the maximum - 1, three failures are a climax, a natural 1 is two failures, a natural 20 ends it).\"\r\n.. \" One more climax save a feature asks for, Edging or not: [CLIMAX|Target|15|+bonus|15|success/failure|extra|source] (a failure: one level of overstimulation).\"\r\nend\r\nif sc.spells then\r\n\r\no[#o + 1] = \"A spell that makes a creature climax at once, after its CAST: [CLIMAX|Target|now|Spell]; one that ends a climax's Incapacitated: [CLIMAX|Target|end|Spell];\"\r\n.. \" one that leaves a climaxed creature vulnerable: [CLIMAX|Target|vuln|Spell].\"\r\n.. \" A spell that changes a creature's inhibition: [INHIB|Target|Spell|-1d4|dice] (or a number; Lua keeps it while the spell lasts); one that weighs it: [INHIB|Target|Spell|vs].\"\r\n.. \" A spell that binds two creatures' sensations, after its CAST: [SWAP|A|B|Spell] (Lua moves what either takes to the other).\"\r\n.. \" One that bonds its target to its caster: [BOND|Caster|Target|Spell] (Lua rolls the target's saves).\"\r\nend\r\nif sc.feats then\r\n\r\no[#o + 1] = \"A reaction that turns damage into stimulation, before that damage: [REACT|Who|Feature] ([REACT|Who|Feature|Ally or all] for one that takes an ally's).\"\r\n.. \" A feature that heals with the target's Hit Point Dice: [HDHEAL|Healer|Target|Feature|N] (Lua rolls them; only for one below its HP maximum).\"\r\nend\r\nif sc.cond or sc.edge then\r\n\r\no[#o + 1] = \"A module's condition on a creature: [COND|Target|+Name|duration|source] (duration +1m, Nr, dmg = until it takes damage; source: whose it is), [COND|Target|-Name] when it ends;\"\r\n.. \" a direct approach that hits one Edging gives its dice' maximum.\"\r\nelse\r\no[#o + 1] = \"A module's condition on a creature: [COND|Target|+Name|duration|source].\"\r\nend\r\n\r\no[#o + 1] = \"A creature out of a fight (an NPC in a scene) is a target once it is in a scene: [SCENE|Name (stat block)|Name (stat block)] (Julian (Noble)), [SCENE|end] when it is over.\"\r\nif K.PACK.afflict then\r\n\r\no[#o + 1] = \"Curses and brands (the module's): [CURSE|Target|+Name|source|level] (Bestow Curse: after its CAST at that level or higher), [CURSE|Target|-Name|Remove Curse N]\"\r\n.. \" (after its CAST at the curse's level or higher), [CURSE|Target|-Name|Wish] or [CURSE|Target|-Name|story]; [BRAND|Target|+Name|stage|source], [BRAND|Target|Name|+1],\"\r\n.. \" [BRAND|Target|-Name|Wish\" .. (K.D2.perm == \"on\" and \"\" or \" or Remove Curse N (N at least the stage)\") .. \"]; a fetish for a while: [FETISH|Target|+Name|1h|source].\"\r\n.. \" Lua keeps their effects (a brand's stage off the inhibition); a creature's are the story's.\"\r\n.. \" A vice taken: [VICE|Target|Name|partake|d20|+save|DC|success/failure] (Lua sets the DC; a failure is addiction).\"\r\nend\r\nif K.PACK.bind then\r\n\r\no[#o + 1] = \"Binding: [BIND|Binder|Target|Condition|Restraint or Spell|willing/unwilling] (Lua sets its escape and break DCs). An unwilling creature only once it is\"\r\n.. \" Restrained, Grappled, Incapacitated or unconscious, after the book's contest as CHECK tags (the binder's Athletics or Sleight of Hand against its Athletics\"\r\n.. \" or Acrobatics; against an unconscious one's Perception, which wakes it on a loss). [ESCAPE|Target|Condition|Skill|d20|+bonus|DC|success/failure]\"\r\n.. \" (an action: Dexterity, Acrobatics or Sleight of Hand slips out, Strength or Athletics breaks it); [BIND|-|Target|Condition or all] when it is taken off.\"\r\nend\r\nif sc.over then\r\n\r\no[#o + 1] = \"Overstimulation a spell or a feature gives or takes: [OVERSTIM|Target|+N|source] / [OVERSTIM|Target|-N]; Lua adds its own (climaxes in a row, long Edging).\"\r\n.. \" A BAD END (Lua's result) is a defeat: tell it as a defeat event (the enemies act as the story would, captivity among the outcomes)\"\r\n.. (K.D2.perm == \"on\" and \"; permanent results are on: \" .. (K.D2.lvdown == \"on\" and \"Lua takes a level, and \" or \"\") .. \"you pick one lasting story result, written as [BADEND|Name|kind|a short line] (kind captive, addiction, curse or background; [BADEND|Name|end|kind] when the story ends it).\" or \", no lasting change to the numbers.\")\r\nelse\r\no[#o + 1] = \"Overstimulation: [OVERSTIM|Target|+N|source].\"\r\nend\r\nif sc.score then\r\no[#o + 1] = \"A score lowered or set by a spell or a feature: [SCORE|Target|Ability|-N|min M|until] or [SCORE|Target|Ability|=N||until] (until longrest, rest, longrest_noclimax, restore, +30d; empty: until [SCORE|Target|Ability|end]; =PB: its Proficiency Bonus; a sixth field keep_spell: its spell attack and DC stay).\"\r\n.. \" An HP or arousal maximum lowered (a bite): [MAXDOWN|Target|hp or arousal|N|until] (until as SCORE's; empty: a Long Rest; [MAXDOWN|Target|hp|end] when it is restored).\"\r\nend\r\n\r\nif adv ~= \"\" then\r\no[#o + 1] = \"A direct approach is [ADVANCE|Attacker|Target|Implement|willing/unwilling|d20|+bonus|AC|hit/miss/crit|formula|dice|stim]\"\r\n.. \" (Implement: one of the module's, or a spell in effect that makes one, by the spell's name)\"\r\n.. \" (the target's inhibition goes on its AC when it is unwilling\" .. (K.D2.mode == \"hard\" and \"\" or \"; an unwilling target only in hardcore mode\")\r\n.. \"; a willing one gives Advantage: adv A,B, unless the attacker has Disadvantage\"\r\n.. \"; a critical one doubles the dice and at the maximum is two failures).\"\r\nend\r\no[#o + 1] = K.AR.apSaveText()\r\nif K.PACK.ar.text then o[#o + 1] = K.PACK.ar.text end\r\nreturn table.concat(o, \" \")\r\nend\r\n\r\nfunction K.AR.target(name, c, pc)\r\nlocal r = Ally.rec(pc, name)\r\nif r then return r end\r\nlocal cu = type(c) == \"table\" and type(c.units) == \"table\" and c.units[name or \"\"] or nil\r\nif cu and c.active then return cu end\r\nreturn K.sceneUnit(pc, name) or cu or nil\r\nend\r\n\r\n\r\n\r\nfunction K.sceneUnit(pc, name)\r\nlocal sc = type(pc) == \"table\" and type(pc.scene) == \"table\" and type(pc.scene.units) == \"table\" and pc.scene.units\r\nlocal u = sc and sc[trim(name or \"\")]\r\nlocal now = K.clockRef and tonumber(K.clockRef.min)\r\nif u and now and now - (tonumber(pc.scene.last) or now) > 60 then pc.scene = nil; return nil end\r\nif u and now then pc.scene.last = now end\r\nreturn u or nil\r\nend\r\n\r\n\r\n\r\nfunction K.planTag(f, pc, clock)\r\nlocal head = \"[PLAN|\" .. table.concat(f, \"|\")\r\nif trim(f[1] or \"\") == \"-\" then pc.plan = nil; return head .. \"|ok|cleared]\", true end\r\nlocal names, bad = {}, {}\r\nfor _, raw in ipairs(f) do\r\nlocal n = K.monCanon(trim(raw or \"\"))\r\nlocal kind = n:match(\"^(.-) %d+$\")\r\nif kind and not MONSTERS[kind] then kind = K.monCanon(kind) end\r\nif MONSTERS[n] then names[#names + 1] = n\r\nelseif kind and MONSTERS[kind] then names[#names + 1] = kind\r\nelseif trim(raw or \"\") ~= \"\" then bad[#bad + 1] = raw end\r\nend\r\nif #bad > 0 then return head .. \"|bad:no such stat block in this game: \" .. table.concat(bad, \", \") .. \" (write the nearest one it has)|-]\", false end\r\nif #names == 0 then return head .. \"|bad:write the creatures' stat blocks|-]\", false end\r\npc.plan = { names = names, at = tonumber(type(clock) == \"table\" and clock.min) or 0 }\r\nlocal o = {}\r\nfor _, n in ipairs(names) do o[#o + 1] = n .. (MONSTERS[n].pp and (\" passive Perception \" .. MONSTERS[n].pp) or \"\") end\r\nreturn head .. \"|ok|\" .. table.concat(o, \"; \") .. \"]\", true\r\nend\r\n\r\nfunction K.planScan(tags)\r\nlocal names\r\nfor _, t in ipairs(type(tags) == \"table\" and tags or {}) do\r\nif t[1] == \"PLAN\" then\r\n\r\n\r\nlocal fl, got, bad = {}, {}, false\r\nfor v in ((t[2] or \"\") .. \"|\"):gmatch(\"([^|]*)|\") do\r\nv = trim(v)\r\nif v == \"ok\" or v:match(\"^bad:\") then break end\r\nfl[#fl + 1] = v\r\nend\r\nif fl[1] == \"-\" then\r\nnames = nil\r\nelse\r\nfor _, v in ipairs(fl) do\r\nif v ~= \"\" then\r\nlocal n = Canon.name(v)\r\nlocal kind = n:match(\"^(.-) %d+$\")\r\nif MONSTERS[n] then got[#got + 1] = n elseif kind and MONSTERS[kind] then got[#got + 1] = kind else bad = true end\r\nend\r\nend\r\nif not bad and #got > 0 then names = got end\r\nend\r\nend\r\nend\r\nreturn names\r\nend\r\n\r\nfunction K.planLive(pc, clock)\r\nlocal pl = type(pc) == \"table\" and not pc.dead and type(pc.plan) == \"table\" and pc.plan\r\nif not pl or (tonumber(clock and clock.min) or 0) - (tonumber(pl.at) or 0) > 1440 then return nil end\r\nreturn pl.names or {}\r\nend\r\nfunction K.planText(pc, clock, fight)\r\nlocal rule = \"A creature the story sets up ahead of a fight (an ambush, a lair, a patrol on the way): write [PLAN|stat block|...] at the\"\r\n.. \" end of that reply; the requests after it give its numbers and stat block. [PLAN|-] once it is gone.\"\r\nif fight then return nil end\r\nlocal names = K.planLive(pc, clock)\r\nif not names then return rule end\r\nlocal o, seen = {}, {}\r\nfor _, n in ipairs(names) do\r\nlocal m = MONSTERS[n]\r\nif type(m) == \"table\" and not seen[n] then\r\nseen[n] = true\r\n\r\no[#o + 1] = string.format(\"%s: passive Perception %s, passive Insight %s, Stealth %+d, AC %d, HP %d, Speed %d ft%s\", n, tostring(m.pp or \"?\"),\r\ntostring(m.pi or \"?\"), tonumber(m.stealth) or 0, tonumber(m.ac) or 10, tonumber(m.hp) or 1, tonumber(m.speed) or 30, m.fly and \" (flies)\" or \"\")\r\nend\r\nend\r\nif #o == 0 then return rule end\r\nreturn rule .. \"\\n[PLANNED] Set up ahead, not fighting yet: \" .. table.concat(o, \"; \")\r\n.. \". A Stealth or Sleight of Hand check against one of them uses its passive Perception as the DC, a Deception check its passive Insight.\"\r\nend\r\nfunction K.sceneTag(f, pc, clock)\r\nlocal head = \"[SCENE|\" .. table.concat(f, \"|\")\r\nlocal function no(why) return head .. \"|bad:\" .. why .. \"|-]\", false end\r\nif (trim(f[1] or \"\")):lower() == \"end\" then\r\nif type(pc.scene) ~= \"table\" then return no(\"no scene open\") end\r\npc.scene = nil\r\nreturn head .. \"|ok|scene over]\", true\r\nend\r\npc.scene = type(pc.scene) == \"table\" and pc.scene or { units = {} }\r\nlocal now = clock and tonumber(clock.min) or 0\r\npc.scene.last = now\r\nlocal made, bad = {}, {}\r\nfor _, field in ipairs(f) do\r\nlocal raw = trim(field or \"\")\r\nif raw ~= \"\" then\r\nlocal disp, inner = raw:match(\"^(.-)%s*%(([^()]+)%)$\")\r\nlocal kind = disp and K.monCanon(trim(inner)) or K.monCanon(raw)\r\nlocal name = (disp and disp ~= \"\") and disp or kind\r\n\r\nif not MONSTERS[kind] then bad[#bad + 1] = raw .. \" (write it with a stat block this game has in brackets, as Julian (Noble))\"\r\nelse\r\nlocal base, n = name, 1\r\nwhile (pc.scene.units[name] and pc.scene.units[name].kind ~= kind) or Ally.rec(pc, name) do n = n + 1; name = base .. \" \" .. n end\r\nif n > 1 and pc.scene.units[base] == nil and Ally.rec(pc, base) then bad[#bad + 1] = base .. \" is Player or a companion\"; goto nextScene end\r\nif not pc.scene.units[name] then\r\nlocal st = MONSTERS[kind]\r\npc.scene.units[name] = { side = \"scene\", kind = kind, hp = st.hp, max = st.hp, name = name }\r\nend\r\nmade[#made + 1] = name .. \" (\" .. kind .. \")\"\r\nend\r\nend\r\n::nextScene::\r\nend\r\nif #made == 0 then\r\nif next(pc.scene.units) == nil then pc.scene = nil end\r\nreturn no(#bad > 0 and table.concat(bad, \"; \") or \"name the creatures, as [SCENE|Julian (Noble)]\")\r\nend\r\nreturn head .. \"|\" .. (#bad > 0 and (\"bad:\" .. table.concat(bad, \"; \")) or \"ok\") .. \"|scene: \" .. table.concat(made, \", \") .. \"]\", #bad == 0\r\nend\r\n\r\nfunction K.sceneText(pc, c)\r\nlocal sc = type(pc) == \"table\" and type(pc.scene) == \"table\" and type(pc.scene.units) == \"table\" and pc.scene.units\r\nif not sc or next(sc) == nil then return nil end\r\nlocal o, names = {}, {}\r\nfor n in pairs(sc) do names[#names + 1] = n end\r\ntable.sort(names)\r\nfor _, n in ipairs(names) do\r\nlocal u = sc[n]\r\nlocal st = MONSTERS[u.kind] or {}\r\nlocal best = 0\r\nfor _, x in ipairs(st.attacks or {}) do if (tonumber(x.hit) or 0) > best then best = tonumber(x.hit) end end\r\no[#o + 1] = string.format(\"%s (%s's stat block): AC %d, approach %+d with an implement's own dice and no modifier, %s\", n, u.kind, tonumber(st.ac) or 10, best, K.AR and K.AR.on()\r\nand (K.AR.text(u, pc, c) .. string.format(\", inhibition %+d\", K.AR.inhib(u, pc))) or (\"HP \" .. u.hp .. \"/\" .. u.max))\r\nend\r\nreturn \"SCENE (out of a fight; the module's tags take these as targets by name, no turns or rounds: a climax's rounds are \\\"for a while\\\"): \"\r\n.. table.concat(o, \"; \") .. \". [SCENE|end] when it is over; a COMBAT or more than an hour passing ends it too.\"\r\nend\r\nfunction K.AR.check(head, f, c, pc, pools, cur, fi, di)\r\nlocal function no(why)\r\nif fi then K.spendRefused(pools, cur, nil, f[fi], f[di]) end\r\nreturn head .. \"|bad:\" .. why .. \"|-]\", false\r\nend\r\nif not K.AR.on() then return nil, no(\"arousal is not in this game (no module brings it)\") end\r\nlocal t = K.AR.target(f[1], c, pc)\r\nif not t then return nil, no(\"target must be Player, a companion or a creature in the fight\") end\r\nif t.dead or (tonumber(t.hp) or 1) <= 0 then return nil, no((f[1] or \"\") .. \" is down\") end\r\nreturn t\r\nend\r\nfunction K.AR.stim(f, pools, cur, c, pc)\r\n\r\n\r\nlocal half = (f[7] or \"\"):lower() == \"half\"\r\nlocal head = \"[STIM|\" .. table.concat(f, \"|\", 1, 6) .. (half and \"|half\" or \"\")\r\nlocal by, sname = K.castBy(f[2], pc)\r\nf = { f[1], f[2], f[3], K.spellTerms(f[4], sname, by, pc), f[5], f[6] }\r\nlocal t, line, good = K.AR.check(head, f, c, pc, pools, cur, 4, 5)\r\nif not t then return line, good end\r\nfor en, ko in pairs(K.DMG_KO) do if trim(f[3] or \"\") == ko then f[3] = en end end\r\nlocal ty = (f[3] or \"\"):lower()\r\nif not K.DTYPES[ty] then\r\nK.spendRefused(pools, cur, nil, f[4], f[5])\r\nreturn head .. \"|bad:type: one of the damage types (Fire, Psychic...)|-]\", false\r\nend\r\nlocal p = parseFormula(f[4] or \"\")\r\nif not p then return head .. \"|bad:write the formula: [STIM|Target|Source|Type|2d6|dice|amount]|-]\", false end\r\nlocal bad = {}\r\nlocal amount = spendDice(p, f[5], pools, cur, bad, K.wroteF(f[4], f[5]))\r\namount = math.max(0, tonumber(amount) or 0)\r\nif half then amount = math.floor(amount / 2) end\r\nif tonumber(f[6]) ~= amount then bad[#bad + 1] = \"amount \" .. tostring(f[6]) .. \"->\" .. amount end\r\n\r\nlocal impl = not sname and K.AR.impl(f[2])\r\nlocal magical\r\nif sname then magical = true elseif impl then magical = impl.magical == true end\r\nlocal src = { type = ((f[3] or \"\"):lower():gsub(\"^%l\", string.upper)), magical = magical }\r\n\r\n\r\nsrc.by = sname and by and ((by == pc and \"Player\") or by.name) or nil\r\nlocal text, extra = K.AR.give(t, amount, pc, c, false, f[1], nil, src)\r\nreturn head .. \"|\" .. verdictOf(bad) .. \"|\" .. text .. \"]\" .. extra, #bad == 0\r\nend\r\n\r\n\r\nfunction K.AR.give(t, amount, pc, c, crit, who, actor, src)\r\nlocal a, mx = K.AR.st(t), K.AR.max(t, pc)\r\n\r\nlocal partner, pname = K.AR.swapOf(t, pc, c)\r\nif partner and not (type(src) == \"table\" and src.swapped) then\r\nlocal s2 = {}\r\nfor k, v in pairs(type(src) == \"table\" and src or {}) do s2[k] = v end\r\ns2.swapped = true\r\nlocal text, extra = K.AR.give(partner, amount, pc, c, crit, pname, actor, s2)\r\nreturn \"swapped to \" .. pname .. \": \" .. text, extra\r\nend\r\n\r\n\r\nlocal modNote = \"\"\r\nif type(src) == \"table\" and type(src.parts) == \"table\" and not src.raw then\r\n\r\namount = 0\r\nfor _, pt in ipairs(src.parts) do\r\nlocal r1, v1, w1 = K.AR.stimMods(t, pc, c, { type = pt.type, magical = src.magical, pierce = src.pierce })\r\nlocal x = tonumber(pt.n) or 0\r\nif r1 == \"immune\" then x = 0; modNote = modNote .. \" (\" .. pt.type .. \" immune: \" .. w1 .. \")\"\r\nelseif r1 and not v1 then x = math.floor(x / 2); modNote = modNote .. \" (\" .. pt.type .. \" resisted: \" .. w1 .. \")\"\r\nelseif v1 and not r1 then x = x * 2; modNote = modNote .. \" (\" .. pt.type .. \" vulnerable: \" .. w1 .. \")\" end\r\namount = amount + x\r\nend\r\nelse\r\nlocal res, vul, why = K.AR.stimMods(t, pc, c, src)\r\nif type(src) == \"table\" and src.raw then res, vul = nil, nil end\r\nif res == \"immune\" then amount = 0; modNote = \" (immune: \" .. why .. \")\"\r\nelseif res and not vul then amount = math.floor(amount / 2); modNote = \" (resisted: \" .. why .. \")\"\r\nelseif vul and not res then amount = amount * 2; modNote = \" (vulnerable: \" .. why .. \")\" end\r\nend\r\n\r\nif amount > 0 then a.lastStim = K.clockRef and tonumber(K.clockRef.min) or 0 end\r\nlocal tsh = K.AR.sheetOf(t, pc)\r\nfor _, e in ipairs(tsh and Feat.fxOf(tsh, \"stim_thp\") or {}) do\r\nif amount > 0 and (not e.cond or K.AR.condsOf(t)[e.cond]) then\r\nt.thp = math.max(tonumber(t.thp) or 0, amount)\r\nmodNote = modNote .. string.format(\" (%s: %d temporary HP)\", e.src or \"stim_thp\", t.thp)\r\nend\r\nend\r\n\r\nmodNote = modNote .. K.AR.stimHeal(t, amount, src)\r\nif amount > 0 then modNote = modNote .. K.AR.bondHit(t, pc, c, amount, nil) end\r\nlocal soak = (type(src) == \"table\" and src.raw) and 0 or math.min(tonumber(a.numb) or 0, amount)\r\na.numb = (tonumber(a.numb) or 0) - soak\r\nif a.numb <= 0 then a.numbRes = nil end\r\nlocal got = amount - soak\r\nlocal inFight = K.AR.inFight(t, c)\r\nlocal atMax = inFight and (tonumber(a.cur) or 0) >= mx and type(a.edge) == \"table\"\r\na.cur = math.min(mx, (tonumber(a.cur) or 0) + got)\r\n\r\nlocal note, extra = \"\", \"\"\r\nif a.cur >= mx and not inFight then\r\n\r\na.edge, a.edgeSince, a.edgeHours, a.edgeGrace = nil, nil, nil, nil\r\nnote = \"at its maximum (out of a fight: no Edging)\"\r\nelseif a.cur >= mx then\r\nlocal denied = K.AR.blocked(t)\r\nif denied and atMax and got > 0 then\r\nnote = \"Edging (\" .. denied .. \": no climax)\"\r\nelseif atMax and got > 0 then\r\nif got >= mx then\r\nnote, extra = K.AR.climax(t, pc, c, who, actor, src and src.by)\r\nelse\r\na.edge.f = (tonumber(a.edge.f) or 0) + (crit and 2 or 1)\r\nif a.edge.f >= 3 then note, extra = K.AR.climax(t, pc, c, who, actor, src and src.by)\r\nelse note = string.format(\"Edging: %d successes, %d failures (no climax yet)\", a.edge.s or 0, a.edge.f) end\r\nend\r\nelseif type(a.edge) ~= \"table\" then\r\na.edge = { s = 0, f = 0 }\r\na.edgeSince, a.edgeHours = K.clockRef and tonumber(K.clockRef.min) or 0, 0\r\na.edgeGrace = math.max(0, K.AR.inhib(t, pc))\r\nnote = \"Edging (not a climax yet)\"\r\nend\r\nend\r\nreturn a.cur .. \"/\" .. mx .. modNote .. (soak > 0 and string.format(\" (numbness -%d)\", soak) or \"\") .. (note ~= \"\" and (\", \" .. note) or \"\"), extra\r\nend\r\n\r\n\r\n\r\n\r\nfunction K.AR.stimMods(t, pc, c, src)\r\nlocal a = K.AR.st(t)\r\nsrc = type(src) == \"table\" and src or {}\r\nlocal function fits(e)\r\nif e.nonmagical and src.magical ~= false then return false end\r\nif type(e.types) == \"table\" then\r\nfor _, ty in ipairs(e.types) do if ty == src.type then return true end end\r\nreturn false\r\nend\r\nreturn true\r\nend\r\nlocal res, vul, why\r\nlocal sh = K.AR.sheetOf(t, pc)\r\nif sh and Feat.fxOf then\r\nfor _, e in ipairs(Feat.fxOf(sh, \"stim_resist\")) do if fits(e) and not (type(src.pierce) == \"table\" and src.pierce[src.type]) then res, why = true, e.src or \"stim_resist\" end end\r\nfor _, e in ipairs(Feat.fxOf(sh, \"stim_vuln\")) do if fits(e) then vul, why = true, e.src or \"stim_vuln\" end end\r\nfor _, e in ipairs(Feat.fxOf(sh, \"stim_immune\")) do if fits(e) then return \"immune\", nil, e.src or \"stim_immune\" end end\r\nend\r\nif type(a.numbRes) == \"table\" and (tonumber(a.numb) or 0) > 0 and fits(a.numbRes) and not (type(src.pierce) == \"table\" and src.pierce[src.type]) then res, why = true, a.numbRes.by or \"numbness\" end\r\nif a.vulnIncap then\r\nif K.AR.incapIn(a, c) then vul, why = true, \"Incapacitated by a climax\"\r\nelse a.vulnIncap = nil end\r\nend\r\nreturn res, vul, why\r\nend\r\n\r\n\r\n\r\nfunction K.AR.sizeOf(t, pc)\r\nif type(t) ~= \"table\" then return 3 end\r\nlocal isRec = t == pc or (t.name and Ally.find(pc, t.name) == t) or false\r\nlocal n = K.SIZE_RANK[isRec and K.recSize(t) or K.unitSize(t)] or 3\r\nfor _, row in pairs(K.AR.condsOf(t)) do n = n + (tonumber(row.size_step) or 0) end\r\nreturn math.max(1, math.min(6, n))\r\nend\r\n\r\nfunction K.AR.sizesText(pc, c)\r\nif not K.AR.on() then return nil end\r\nlocal o, odd = {}, false\r\nlocal function add(nm, t)\r\nlocal n = K.AR.sizeOf(t, pc)\r\nif n ~= 3 then odd = true; o[#o + 1] = nm .. \" \" .. K.sizeName(n) end\r\nend\r\nadd(\"Player\", pc)\r\nfor _, a in ipairs(Ally.list(pc)) do if not a.dead then add(a.name, a) end end\r\nlocal names = {}\r\nif type(c) == \"table\" and c.active then for nm, u in pairs(c.units or {}) do if u.side ~= \"friend\" and (tonumber(u.hp) or 1) > 0 then names[#names + 1] = { nm, u } end end end\r\nif type(pc.scene) == \"table\" then for nm, u in pairs(pc.scene.units or {}) do names[#names + 1] = { nm, u } end end\r\ntable.sort(names, function(x, y) return x[1] < y[1] end)\r\nfor _, x in ipairs(names) do add(x[1], x[2]) end\r\nreturn odd and (\"Sizes (the rest Medium): \" .. table.concat(o, \", \") .. \".\") or nil\r\nend\r\nfunction K.sizeName(n)\r\nfor k, v in pairs(K.SIZE_RANK) do if v == n then return k end end\r\nreturn n > 6 and \"Gargantuan\" or \"Tiny\"\r\nend\r\nfunction K.AR.implSize(atk, impl, iname, pc)\r\nlocal n = (impl.kind == \"body\" or impl.kind == \"natural\") and K.AR.sizeOf(atk, pc) or (K.SIZE_RANK[impl.size or \"Medium\"] or 3)\r\nlocal ash = K.AR.sheetOf(atk, pc)\r\nfor _, e in ipairs(ash and Feat.fxOf(ash, \"impl_size\") or {}) do if K.fxImpl(ash, e, impl, iname) then n = n + (tonumber(e.n) or 0) end end\r\nfor _, row in pairs(K.AR.condsOf(atk)) do\r\nlocal is = row.impl_size\r\nif type(is) == \"table\" then\r\nlocal hit = is.names == nil and is.kinds == nil\r\nfor _, x in ipairs(is.names or {}) do if x == iname then hit = true end end\r\nfor _, x in ipairs(is.kinds or {}) do if x == impl.kind then hit = true end end\r\nif hit then n = n + (tonumber(is.n) or 0) end\r\nend\r\nend\r\nreturn n\r\nend\r\n\r\n\r\nfunction K.AR.sizeRule(atk, t, impl, iname, pc)\r\nlocal o = { d = 0, dice = 0 }\r\nlocal is, ts = K.AR.implSize(atk, impl, iname, pc), K.AR.sizeOf(t, pc)\r\no.d, o.is, o.ts = is - ts, is, ts\r\nlocal as = impl.size_as\r\nif as == \"phallic\" then o.dice = o.d elseif as == \"yonic\" then o.dice = -o.d end\r\nif impl.phallic and K.D2.hitomi ~= \"on\" then\r\nlocal okn = 0\r\nfor _, row in pairs(K.AR.condsOf(t)) do okn = okn + (tonumber(row.size_ok) or 0) end\r\nif o.d >= 2 + okn then\r\nif K.D2.mode == \"hard\" then o.big = true\r\nelse o.refuse = string.format(\"too large to penetrate (%d sizes bigger): another implement or approach\", o.d) end\r\nelseif o.d <= -3 then o.dis = true end\r\nend\r\nreturn o\r\nend\r\n\r\nfunction K.AR.impl(name, atk, pc, withTool)\r\n\r\nlocal sn, tn = trim(name or \"\"):match(\"^(.-)%s*%((.-)%)$\")\r\nif sn then\r\nlocal sp0 = SPELLS[Canon.name(sn)]\r\nif sp0 and type(sp0.m) == \"table\" and type(sp0.m.advance) == \"table\" and sp0.m.advance.animate then\r\nlocal tool, tname = K.AR.impl(tn)\r\nlocal base, bn = K.AR.impl(sn, atk, pc, true)\r\nif base and tool and tool.kind == \"tool\" then\r\nbase.dice, base.type, base.tool = tool.dice, tool.type, tname\r\nreturn base, bn .. \" (\" .. tname .. \")\"\r\nend\r\nreturn nil\r\nend\r\nend\r\nlocal n = Canon.name(name or \"\")\r\nif K.PACK.impl[n] then return K.PACK.impl[n], n end\r\nfor en, r in pairs(K.PACK.impl) do if NAMES_KO[en] == trim(name or \"\") or en:lower() == trim(name or \"\"):lower() then return r, en end end\r\n\r\n\r\nif type(atk) == \"table\" and (atk == pc or atk.sheet) then\r\nlocal raw = trim(name or \"\")\r\nlocal outer, inner = raw:match(\"^(.-)%s*%(([^()]+)%)$\")\r\nfor _, x in ipairs(LOOT.inUse(atk)) do\r\nlocal m = x[2].srd and K.MAGIC and K.MAGIC[x[2].srd]\r\nlocal im = m and m.implement\r\nif type(im) == \"table\" then\r\nlocal names = { x[1], K.MI.ko(x[1]) or NAMES_KO[x[2].srd or \"\"] }\r\nlocal hit, asName = false, im.as\r\nfor _, nm in ipairs(names) do\r\nif nm == raw or (nm or \"\"):lower() == raw:lower() then hit = true end\r\nif im.as == \"any\" and outer and (nm == outer or (nm or \"\"):lower() == outer:lower()) then hit, asName = true, inner end\r\nend\r\nif hit then\r\nlocal base, bn = K.AR.impl(asName)\r\nif not base or asName == \"any\" then return nil end\r\nlocal plus = im.plus == \"var\" and tonumber((type(m.var) == \"table\" and type(m.var[x[2].var or \"\"]) == \"table\" and m.var[x[2].var].n) or 0) or tonumber(im.plus) or 0\r\nreturn setmetatable({ dice = im.dice or base.dice, type = im.type or base.type, magical = true, itemPlus = plus, item = x[1] }, { __index = base }), bn\r\nend\r\nend\r\nend\r\nend\r\n\r\nlocal sp = SPELLS[n]\r\nif not sp then\r\nfor en, row in pairs(SPELLS) do if NAMES_KO[en] == trim(name or \"\") and type(row.m) == \"table\" and row.m.advance then n, sp = en, row break end end\r\nend\r\nif sp and type(sp.m) == \"table\" and type(sp.m.advance) == \"table\" and type(atk) == \"table\" and (atk == pc or atk.sheet) then\r\nfor _, a in ipairs(Spell.active(atk)) do\r\nif a.name == n and not a.lost then\r\nlocal ad = sp.m.advance\r\nif ad.animate and not withTool then return nil end\r\nreturn { kind = \"spell\", spell = n, level = tonumber(a.level) or sp.level, dice = ad.dice or \"1d6\", type = ad.type or \"Force\",\r\nmod = ad.mod, hit = ad.hit }, n\r\nend\r\nend\r\nend\r\nreturn nil\r\nend\r\n\r\n\r\nfunction K.AR.implBuffs(atk, impl, pc, name)\r\nlocal o = {}\r\nif type(atk) ~= \"table\" or not (atk == pc or atk.sheet) then return o end\r\n\r\nlocal ash = K.AR.sheetOf(atk, pc)\r\nif ash and type(atk.mode) == \"table\" and atk.mode.name == \"Rage\" then\r\nfor _, e in ipairs(Feat.fxOf(ash, \"rage_spell\")) do\r\nlocal b = SPELLS[e.spell or \"\"] and SPELLS[e.spell].m and SPELLS[e.spell].m.impl_buff\r\nif type(b) == \"table\" then\r\nlocal hit = b.kinds == nil\r\nfor _, k in ipairs(b.kinds or {}) do if k == impl.kind then hit = true end end\r\nif hit then o[#o + 1] = { spell = e.spell, b = b, ab = e.ability } end\r\nend\r\nend\r\nend\r\nfor _, a in ipairs(Spell.active(atk)) do\r\nlocal b = not a.lost and SPELLS[a.name] and SPELLS[a.name].m and SPELLS[a.name].m.impl_buff\r\nif type(b) == \"table\" then\r\nlocal hit = b.kinds == nil\r\nfor _, k in ipairs(b.kinds or {}) do if k == impl.kind then hit = true end end\r\n\r\nlocal bound = b.one and type(atk.implBind) == \"table\" and atk.implBind[a.name]\r\nif hit and bound and name and bound ~= name then hit = false end\r\nif hit then o[#o + 1] = { spell = a.name, b = b } end\r\nend\r\nend\r\nreturn o\r\nend\r\n\r\n\r\n\r\nfunction K.AR.tabHtml(pc, sh, tipSpan)\r\nlocal a, mx = K.AR.st(pc), K.AR.max(pc, pc)\r\nlocal left, all = K.AR.dice(pc, pc)\r\nlocal p = type(sh.picks) == \"table\" and sh.picks or {}\r\nlocal ab = K.AR.MENTAL[p.inhib or \"\"] and p.inhib or K.AR.bestMental(sh)\r\nlocal o = {}\r\nlocal state = \"\"\r\nif type(a.edge) == \"table\" then state = string.format(\" · 임계: 성공 %d · 실패 %d\", tonumber(a.edge.s) or 0, tonumber(a.edge.f) or 0) end\r\nif K.AR.incapIn(a, K.curC) then state = state .. string.format(\" · 절정으로 %d라운드까지 행동불능\", a.incapTo) end\r\no[#o + 1] = string.format(\"흥분도 %d/%d · 회복 주사위 %d/%d (d%d) · 억제 %+d (%s)%s%s\", tonumber(a.cur) or 0, mx, left, all, K.AR.die(sh),\r\nK.AR.inhib(pc, pc), (NAMES_KO[ab] or ab), (tonumber(a.numb) or 0) > 0 and (\" · 둔감 \" .. a.numb) or \"\", state)\r\nlocal im = {}\r\nlocal names = {}\r\nfor n in pairs(K.PACK.impl) do names[#names + 1] = n end\r\ntable.sort(names)\r\nfor _, n in ipairs(names) do\r\nlocal impl = K.PACK.impl[n]\r\nif K.d2ok(impl) and K.AR.implHas(sh, impl, n) then\r\nlocal b, dice = K.AR.implNums(pc, impl, n, pc)\r\nlocal prof = K.AR.implProf(sh, impl, n)\r\nlocal label = string.format(\"%s %+d %s\", NAMES_KO[n] or n, b, dice)\r\nlocal tip = (NAMES_KO[n] or n) .. \" · \" .. (impl.kind == \"tool\" and \"도구\" or \"몸\") .. \" · \" .. K.stimKo(impl.type) .. \" 자극\"\r\n.. (prof and \" · 숙련\" or \" · 숙련 아님\") .. (impl.tip and (\"\\n\" .. impl.tip) or \"\")\r\nim[#im + 1] = tipSpan(label, tip)\r\nend\r\nend\r\nfor _, x in ipairs(Spell.active(pc)) do\r\nlocal impl = K.AR.impl(x.name, pc, pc)\r\nif impl and impl.kind == \"spell\" then\r\nlocal b, dice = K.AR.implNums(pc, impl, x.name, pc)\r\nim[#im + 1] = tipSpan(string.format(\"%s %+d %s\", (NAMES_KO[x.name] or x.name), b, dice), (NAMES_KO[x.name] or x.name) .. \" · 주문이 만든 도구 · \" .. K.stimKo(impl.type) .. \" 자극\")\r\nend\r\nend\r\nif #im > 0 then o[#o + 1] = \"성적 도구: \" .. table.concat(im, \", \") end\r\n\r\nlocal bt = K.btnFn\r\nif K.PG.on() and bt then\r\n\r\nif type(pc.preg) == \"table\" then\r\nlocal n = #K.PG.all(pc)\r\nlocal by = pc.preg.by\r\nby = by and (by == \"Player\" and \"당신\" or NAMES_KO[by] or (K.toKo and K.toKo(by)) or by)\r\no[#o + 1] = \"임신 중 (\" .. (pc.preg.kind == \"traditional\" and \"전통\" or \"비전통\") .. (by and (\", \" .. by) or \"\") .. \")\"\r\n.. (n > 1 and (string.format(\" 외 %d건 · 근력·민첩 -%d\", n - 1, n - 1)) or \"\")\r\n.. (K.PG.showing(pc) and \" · 근력·민첩 내성 불리, 나를 향한 공격 18~20 치명타\" or \" · 아직 드러나지 않음\")\r\nend\r\nend\r\n\r\nlocal KIND_KO = { curse = \"저주\", brand = \"낙인\", vice = \"중독\", fetish = \"페티시\" }\r\nlocal af = {}\r\nfor _, x in ipairs(K.afflictOn and K.afflictOn(sh) or {}) do\r\nlocal r, e = x.rec, x.e\r\nif not (r.kind == \"fetish\" and e.src == \"history\") and not (r.kind == \"vice\" and not e.addicted) then\r\nlocal lv = tonumber(e.level) or tonumber(r.level)\r\nlocal label = (NAMES_KO[e.name] or e.name) .. ((r.kind == \"brand\" and lv) and (\" \" .. lv .. \"단계\") or (r.kind == \"curse\" and lv) and (\" \" .. lv .. \"레벨\") or \"\")\r\nlocal tip = KIND_KO[r.kind] .. (r.kind == \"brand\" and lv and (\" · 억제 -\" .. lv) or \"\")\r\n.. (r.kind == \"vice\" and (\" · 내성 DC \" .. (tonumber(e.dc) or 10) .. \" · \" .. clockKo(((tonumber(e.last) or 0) + 1440)) .. \"까지 다시 해야 함\") or \"\")\r\n.. (tonumber(e.ends) and (\" · \" .. clockKo(e.ends) .. \"까지\") or \"\")\r\n.. ((r.tip and r.tip ~= \"\") and (\"\\n\" .. r.tip) or \"\")\r\naf[#af + 1] = { k = r.kind, s = tipSpan(label, tip) }\r\nend\r\nend\r\nfor _, k in ipairs({ \"curse\", \"brand\", \"vice\", \"fetish\" }) do\r\nlocal l = {}\r\nfor _, x in ipairs(af) do if x.k == k then l[#l + 1] = x.s end end\r\nif #l > 0 then o[#o + 1] = KIND_KO[k] .. \": \" .. table.concat(l, \", \") end\r\nend\r\n\r\nif (tonumber(a.overstim) or 0) > 0 then o[#o + 1] = \"과자극 \" .. a.overstim .. \"/6\" .. (a.overSrc and (\" (\" .. (NAMES_KO[a.overSrc] or a.overSrc) .. \")\") or \"\") end\r\nlocal bd = pc.badDown\r\nif type(bd) == \"table\" then o[#o + 1] = string.format(\"배드 엔드: %s %d → %d레벨\", NAMES_KO[bd.cls] or bd.cls or \"?\", tonumber(bd.from) or 0, tonumber(bd.to) or 0) end\r\nfor k, v in pairs(type(pc.badRes) == \"table\" and pc.badRes or {}) do\r\no[#o + 1] = \"배드 엔드 결과: \" .. (K.BADEND_KINDS[k] or k) .. \" (\" .. tostring(type(v) == \"table\" and v.text or v) .. \")\"\r\nend\r\nreturn table.concat(o, \"<br>\")\r\nend\r\n\r\n\r\nK.POS_KO = { top = \"삽입\", bottom = \"수용\", any = \"상관없음\" }\r\nK.POS_TO = { top = \"삽입으로\", bottom = \"수용으로\", any = \"상관없음으로\" }\r\nK.POS_TIP = { top = \"넣기만 하고 받지 않습니다.\", bottom = \"받기만 하고 넣지 않습니다.\", any = \"정하지 않습니다(이야기 흐름대로).\" }\r\nfunction K.AR.posOf(rec, pc)\r\nlocal sh = type(rec) == \"table\" and ((rec == pc and SHEET) or rec.sheet) or nil\r\nlocal v = sh and type(sh.picks) == \"table\" and sh.picks.position\r\nreturn (v == \"top\" or v == \"bottom\") and v or nil\r\nend\r\n\r\nfunction K.AR.implHas(sh, impl, name)\r\nif impl.kind ~= \"natural\" then return true end\r\nif not (sh and Feat.fxOf) then return false end\r\nfor _, e in ipairs(Feat.fxOf(sh, \"implement_prof\")) do\r\nfor _, k in ipairs(e.kinds or {}) do if k == \"natural\" then return true end end\r\nfor _, k in ipairs(e.names or {}) do if k == name or (impl.item and k == impl.item) then return true end end\r\nend\r\nreturn false\r\nend\r\nfunction K.AR.implProf(sh, impl, name)\r\nif type(sh) == \"table\" and #Feat.fxOf(sh, \"no_advance_prof\") > 0 then return false end\r\n\r\nlocal p = type(sh) == \"table\" and type(sh.picks) == \"table\" and sh.picks or {}\r\nlocal hist = K.PACK.ar and K.PACK.ar.hist[p.sexhist or \"\"]\r\n\r\nif hist and type(hist.body_prof) == \"table\" and (impl.kind == \"body\" or impl.kind == \"natural\") then\r\nfor _, x in ipairs(hist.body_prof) do if x == name then return impl.kind == \"body\" or K.AR.implHas(sh, impl, name) end end\r\nreturn false\r\nend\r\nif impl.kind == \"body\" then return not (hist and hist.no_body_prof) end\r\nif impl.kind == \"tool\" and type(p.imptools) == \"table\" then\r\n\r\nfor i, x in ipairs(p.imptools) do if i <= (tonumber(hist and hist.tools) or 0) and x == name then return true end end\r\nend\r\nfor _, e in ipairs(Feat.fxOf(sh, \"implement_prof\")) do\r\nfor _, k in ipairs(e.kinds or {}) do if k == impl.kind then return true end end\r\n\r\nfor _, k in ipairs(e.names or {}) do if k == name or (impl.item and k == impl.item) then return true end end\r\nif e.pick and K.pickHas(p[e.pick], name) then return true end\r\nend\r\nreturn false\r\nend\r\n\r\nfunction K.AR.implNums(atk, impl, name, pc, c)\r\nlocal sh = K.AR.sheetOf(atk, pc)\r\n\r\n\r\nif impl.kind == \"spell\" then\r\nreturn Ally.run(pc, atk ~= pc and atk or nil, function()\r\nlocal st = Spell.stats(impl.spell) or { atk = 0, mod = 0 }\r\nlocal bonus = st.atk\r\nif impl.hit ~= nil then\r\nlocal h = K.spellTerms(tostring(impl.hit), impl.spell)\r\nlocal q = parseFormula(h)\r\nbonus = tonumber(h) or (q and #q.dice == 0 and q.mod) or st.atk\r\nend\r\nlocal dice = Spell.formula(impl.spell, K.spellTerms(impl.dice, impl.spell) .. (impl.mod and \"+MOD\" or \"\"), impl.level, \"advance\") or impl.dice\r\nreturn bonus, dice, st.mod or 0\r\nend)\r\nend\r\nif not sh then\r\nlocal st = statsOf(atk, pc)\r\nlocal best = 0\r\nfor _, x in ipairs(st.attacks or {}) do if (tonumber(x.hit) or 0) > best then best = tonumber(x.hit) end end\r\nreturn best, impl.dice, 0\r\nend\r\nlocal function m(ab) return abilityMod(K.score(sh, ab)) end\r\nlocal mod = impl.ability == \"finesse\" and math.max(m(\"Strength\"), m(\"Dexterity\")) or m(impl.ability)\r\nfor _, e in ipairs(Feat.fxOf and Feat.fxOf(sh, \"weapon_ability\") or {}) do\r\nfor _, x in ipairs(e.implements or {}) do if x == name and e.ability and m(e.ability) > mod then mod = m(e.ability) end end\r\nend\r\nlocal pb = 2 + math.floor((K.charLevel(sh) - 1) / 4)\r\n\r\n\r\nlocal add = \"\"\r\nfor _, x in ipairs(K.AR.implBuffs(atk, impl, pc, name)) do\r\nif x.ab then\r\nlocal v = m(ABBR[x.ab] or x.ab)\r\nif v > mod then mod = v end\r\nelseif x.b.spell_ability then\r\nlocal st = Ally.run(pc, atk ~= pc and atk or nil, function() return Spell.stats(x.spell) end)\r\nif st and (st.mod or 0) > mod then mod = st.mod end\r\nend\r\nif type(x.b.dice) == \"string\" and x.b.dice:match(\"^%d*d%d+$\") then add = add .. \"+\" .. x.b.dice end\r\nend\r\n\r\nfor _, e in ipairs(Feat.fxOf(sh, \"monk_implements\")) do\r\nlocal fits = false\r\nfor _, k in ipairs(e.kinds or {}) do if k == impl.kind then fits = true end end\r\nfor _, k in ipairs(e.names or {}) do if k == name then fits = true end end\r\nif fits then\r\nif m(\"Dexterity\") > mod then mod = m(\"Dexterity\") end\r\nlocal ma = K.rowOf(sh, \"Monk\").martial_arts\r\nlocal function size(d) local n, x = tostring(d):match(\"^(%d*)d(%d+)$\"); return (tonumber(n) or 1) * (tonumber(x) or 0) end\r\nif ma and size(ma) > size(impl.dice) then impl = setmetatable({ dice = ma }, { __index = impl }) end\r\nend\r\nend\r\n\r\nfor _, e in ipairs(Feat.fxOf(sh, \"impl_dice\")) do\r\nif type(e.dice) == \"string\" and K.fxImpl(sh, e, impl, name) then impl = setmetatable({ dice = e.dice }, { __index = impl }) end\r\nend\r\nlocal bonus = mod + (K.AR.implProf(sh, impl, name) and pb or 0)\r\nfor _, e in ipairs(Feat.fxOf(sh, \"impl_bonus\")) do\r\nif K.fxImpl(sh, e, impl, name) then bonus = bonus + K.fxNum(e.add or 0, sh, K.charLevel(sh)) end\r\nend\r\n\r\nlocal amode = type(atk.mode) == \"table\" and atk.mode.name\r\nfor _, e in ipairs(Feat.fxOf(sh, \"advance_bonus\")) do if not e.mode or e.mode == amode then bonus = bonus + K.fxNum(e.add, sh, e.srcLv) end end\r\nfor _, e in ipairs(Feat.fxOf(sh, \"impl_step\")) do\r\nlocal hit = (not e.mode or e.mode == amode)\r\nif hit and type(e.kinds) == \"table\" then hit = false; for _, k in ipairs(e.kinds) do if k == impl.kind then hit = true end end end\r\nif hit then\r\nlocal steps = { [4] = 6, [6] = 8, [8] = 10, [10] = 12, [12] = 12 }\r\nimpl = setmetatable({ dice = (impl.dice:gsub(\"d(%d+)\", function(x) local n = tonumber(x); for _ = 1, tonumber(e.step) or 1 do n = steps[n] or n end; return \"d\" .. n end)) }, { __index = impl })\r\nend\r\nend\r\n\r\nif K.AR.advancing and Feat.fxOf then\r\nlocal used = Feat.cur.used and Feat.cur.used[atk]\r\nfor _, e in ipairs(Feat.fxOf(sh, \"advance_skill\")) do\r\nlocal key = (e.src or \"\") .. \"|\" .. tostring(atk)\r\nif used and used[e.after_use or \"\"] and not (Feat.cur.advSkill and Feat.cur.advSkill[key]) then\r\nlocal sk = Ally.run(pc, atk ~= pc and atk or nil, function() return bonusFor(e.skill or \"Performance\") end)\r\nif sk then\r\nbonus = mod + sk\r\nFeat.cur.advSkill = Feat.cur.advSkill or {}\r\nFeat.cur.advSkill[key] = true\r\nK.AR.advSkillNote = string.format(\" (%s: %s %+d)\", e.src or \"advance_skill\", e.skill or \"Performance\", sk)\r\nend\r\nend\r\nend\r\nend\r\nlocal formula = impl.dice .. add .. (mod ~= 0 and string.format(\"%+d\", mod) or \"\")\r\nlocal p = parseFormula(formula)\r\nreturn bonus, p and canon(p, false) or formula, mod\r\nend\r\n\r\n\r\nfunction K.AR.apAC(ac, inh)\r\nac, inh = tonumber(ac) or 10, tonumber(inh) or 0\r\nif K.D2 and K.D2.mode == \"hard\" then\r\nreturn string.format(\"approached at AC %d when willing, %d when unwilling (its inhibition added)\", ac + math.min(0, inh), ac + inh)\r\nend\r\nreturn string.format(\"approached at AC %d\", ac + math.min(0, inh))\r\nend\r\nfunction K.AR.acOf(t, pc)\r\nif K.AR.sheetOf(t, pc) then return Ally.run(pc, t, function() return pcStats(t).ac end) end\r\nreturn statsOf(t, pc).ac\r\nend\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\nK.INSP_TAGS = { ATTACK = { keys = { 1, 2 }, d20 = 3, res = 6, low = \"miss\" }, SAVE = { keys = { 1, 2 }, d20 = 3, res = 6, low = \"failure\" },\r\nCHECK = { keys = { 1 }, d20 = 2, res = 5, low = \"failure\" } }\r\n\r\n\r\n\r\n\r\nfunction K.histTags(v)\r\nv = v:gsub(\"\\n?%[[%u_]+|[^%]]*|auto|[^%]]*%]\", \"\")\r\nreturn (v:gsub(\"%[([%u_]+)|([^%]]*)%]\", function(tag, rest)\r\nlocal f = split(rest)\r\nlocal vi\r\nfor i, x in ipairs(f) do if x == \"ok\" or x:sub(1, 4) == \"bad:\" then vi = i; break end end\r\nif not vi then return nil end\r\nlocal head = \"[\" .. tag .. (vi > 1 and (\"|\" .. table.concat(f, \"|\", 1, vi - 1)) or \"\") .. \"]\"\r\nif f[vi] == \"ok\" then return head end\r\nlocal parts = {}\r\nfor p in (f[vi]:sub(5) .. \";\"):gmatch(\"([^;]*);\") do\r\nlocal q = trim(p)\r\nif q ~= \"\" and not q:match(\"^Lua d20\") and not q:match(\"^Lua dice\") then parts[#parts + 1] = q end\r\nend\r\nlocal why = table.concat(parts, \"; \")\r\nreturn head .. \" (Lua \" .. (K.isFixed(tag, rest) and \"fixed\" or \"refused\") .. (why ~= \"\" and (\": \" .. why) or \"\") .. \")\"\r\nend))\r\nend\r\n\r\n\r\n\r\nfunction K.safeBad(line)\r\nlocal b = line:find(\"|bad:\", 1, true)\r\nif not b then return line end\r\nlocal nl = line:find(\"\\n\", b, true)\r\nlocal head, body, tail = line:sub(1, b + 4), line:sub(b + 5, nl and nl - 1 or #line), nl and line:sub(nl) or \"\"\r\nif not body:find(\"[\", 1, true) then return line end\r\nbody = body:gsub(\"%[([^%[%]\\n]*)%]\", function(x) return \"«\" .. x:gsub(\"|\", \"¦\") .. \"»\" end)\r\nreturn head .. body .. tail\r\nend\r\nfunction K.inspMerge(text)\r\nlocal tags = {}\r\nlocal at = 1\r\nwhile true do\r\nlocal s0, e0, tag, rest = text:find(\"%[(%u+)|([^%]]*)%]\", at)\r\nif not s0 then break end\r\nif K.INSP_TAGS[tag] then\r\nif not rest:find(\"|bad:\", 1, true) then rest = rest:gsub(\"|%s*ok%s*$\", \"\") end\r\nlocal f = split(rest)\r\nlocal judged = false\r\nfor _, v in ipairs(f) do if v == \"ok\" or v:match(\"^bad:\") then judged = true end end\r\ntags[#tags + 1] = { s = s0, e = e0, tag = tag, f = f, judged = judged }\r\nend\r\nat = e0 + 1\r\nend\r\nlocal drop, set = {}, {}\r\nlocal function same(a, b)\r\nif a.tag ~= b.tag then return false end\r\nfor _, k in ipairs(K.INSP_TAGS[a.tag].keys) do if trim(a.f[k] or \"\"):lower() ~= trim(b.f[k] or \"\"):lower() then return false end end\r\nreturn true\r\nend\r\nfor j = 2, #tags do\r\nlocal tj = tags[j]\r\nlocal sp = K.INSP_TAGS[tj.tag]\r\nif not tj.judged then\r\nlocal d = trim(tj.f[sp.d20] or \"\")\r\nlocal ia = d:match(\"^[Ii][Nn][Ss][Pp]%s+(%d+)%s*,%s*%d+$\")\r\nfor i = j - 1, 1, -1 do\r\nlocal ti = tags[i]\r\nif not ti.judged and not drop[i] and same(ti, tj) then\r\nlocal di = trim(ti.f[sp.d20] or \"\")\r\nif di:match(\"^%d+$\") and trim(ti.f[sp.res] or \"\"):lower() == sp.low then\r\nlocal between = text:sub(ti.e + 1, tj.s - 1):lower()\r\nif ia and ia == di then\r\ndrop[i] = true\r\nelseif not ia and d:match(\"^%d+$\") and (between:find(\"영감\", 1, true) or between:find(\"inspiration\", 1, true)) then\r\ndrop[i] = true\r\nset[j] = \"insp \" .. di .. \",\" .. d\r\nend\r\nend\r\nbreak\r\nend\r\nend\r\nend\r\nend\r\nif not next(drop) then return text end\r\nfor j = #tags, 1, -1 do\r\nlocal t = tags[j]\r\nif drop[j] then\r\nlocal e = t.e\r\nif text:sub(e + 1, e + 1) == \"\\r\" then e = e + 1 end\r\nif text:sub(e + 1, e + 1) == \"\\n\" then e = e + 1 end\r\ntext = text:sub(1, t.s - 1) .. text:sub(e + 1)\r\nelseif set[j] then\r\nlocal f = {}\r\nfor k, v in ipairs(t.f) do f[k] = v end\r\nf[K.INSP_TAGS[t.tag].d20] = set[j]\r\ntext = text:sub(1, t.s - 1) .. \"[\" .. t.tag .. \"|\" .. table.concat(f, \"|\") .. \"]\" .. text:sub(t.e + 1)\r\nend\r\nend\r\nreturn text\r\nend\r\n\r\n\r\n\r\n\r\nfunction K.AR.recip(atk, t, impl, iname, ash, dice, pc, c, atkName, me, sizeDice)\r\nlocal on = impl.reciprocal == true\r\nfor _, e in ipairs(ash and Feat.fxOf(ash, \"impl_recip\") or {}) do if K.fxImpl(ash, e, impl, iname) then on = true end end\r\nif not on or atk.dead or (tonumber(atk.hp) or 1) <= 0 then return \"\", \"\" end\r\nlocal tot, d, b = K.AR.saveRoll(atk, pc, \"Constitution\")\r\nlocal o = string.format(\"; reciprocal: %s Constitution save d20 %d%+d vs DC 15\", me, d, b)\r\nif tot >= 15 then return o .. \", fine\", \"\" end\r\nlocal p = parseFormula(dice or \"\") or { dice = {} }\r\nlocal n = 0\r\nfor _, dd in ipairs(p.dice) do for _ = 1, dd.n do n = n + K.d(dd.s) end end\r\nlocal why = \"\"\r\nif (tonumber(sizeDice) or 0) ~= 0 then\r\nlocal x = 0\r\nfor _ = 1, math.abs(sizeDice) do x = x + K.d(4) end\r\nn = sizeDice > 0 and (n + x) or math.max(0, n - x)\r\nwhy = why .. string.format(\" (size %s%dd4)\", sizeDice > 0 and \"+\" or \"-\", math.abs(sizeDice))\r\nend\r\nfor _, e in ipairs(ash and Feat.fxOf(ash, \"recip_resist\") or {}) do n = math.floor(n / 2); why = why .. \" (\" .. (e.src or \"recip_resist\") .. \": halved)\"; break end\r\nfor _, e in ipairs(ash and Feat.fxOf(ash, \"recip_vuln\") or {}) do\r\nif K.fxImpl(ash, e, impl, iname) then n = n * 2; why = why .. \" (\" .. (e.src or \"recip_vuln\") .. \": doubled)\"; break end\r\nend\r\nlocal tName = (t == pc and \"Player\") or t.name or \"?\"\r\nlocal text, extra = K.AR.give(atk, n, pc, c, false, atkName, tName, { type = impl.type, magical = impl.kind == \"spell\" or impl.magical or false })\r\nreturn o .. \", failed: \" .. n .. why .. \", \" .. text, extra or \"\"\r\nend\r\n\r\n\r\nfunction K.AR.ownDis(atk, atkRec, pc)\r\nif atkRec then local _, _, d = K.ownMode(atkRec, \"attack\"); if d then return true end end\r\nlocal names = atkRec and Cond.active(atkRec) or K.foeCondFx(atk, pc).list\r\nfor n in pairs(K.AR.condsOf(atk)) do names[#names + 1] = n end\r\nfor _, n in ipairs(names) do\r\nfor _, m in pairs(K.condEff(n)) do\r\nif m.own_attacks == \"disadvantage\" or (type(m.pack) == \"table\" and m.pack.own_dis) then return true end\r\nend\r\nend\r\nreturn false\r\nend\r\nfunction K.AR.advance(f, pools, cur, c, pc)\r\nlocal head = \"[ADVANCE|\" .. table.concat(f, \"|\", 1, 11)\r\nlocal function no(why)\r\nK.spendRefused(pools, cur, f[5], f[9], f[10])\r\nreturn head .. \"|bad:\" .. why .. \"|-]\", false\r\nend\r\nif not K.AR.on() then return no(\"arousal is not in this game (no module brings it)\") end\r\nlocal atk, t = K.AR.target(f[1], c, pc), K.AR.target(f[2], c, pc)\r\nif not atk then return no(\"attacker must be Player, a companion or a creature in the fight\") end\r\nif not t then return no(\"target must be Player, a companion or a creature in the fight\") end\r\nif atk.dead or ((tonumber(atk.hp) or 1) <= 0 and not atk.zeroAct) then return no((f[1] or \"\") .. \" is down\") end\r\nif t.dead or (tonumber(t.hp) or 1) <= 0 then return no((f[2] or \"\") .. \" is down\") end\r\nlocal atkRec = (atk == pc or Ally.find(pc, atk.name or \"\")) and atk or nil\r\nlocal cant = (K.AR.incapNow(atk) and \"Incapacitated (a climax)\") or (atkRec and Cond.fx(atkRec).incap) or (not atkRec and K.foeCondFx(atk, pc).incap)\r\nif cant then return no((f[1] or \"\") .. \" cannot act (\" .. cant .. \")\") end\r\nlocal will = (f[4] or \"\"):lower()\r\nif will ~= \"willing\" and will ~= \"unwilling\" then return no(\"write willing or unwilling as the fourth field\") end\r\n\r\n\r\nlocal wcond = K.AR.willingFor(t, (atk == pc and \"Player\") or atk.name or f[1])\r\nif not wcond and K.D2.mode == \"hard\" and type(t.ar) == \"table\" and type(t.ar.edge) == \"table\" and K.AR.inFight(t, c) then wcond = \"Edging\" end\r\nif wcond and will == \"unwilling\" then will = \"willing\"; f[4] = \"willing\"; head = \"[ADVANCE|\" .. table.concat(f, \"|\", 1, 11) end\r\nif will == \"unwilling\" and K.D2.mode ~= \"hard\" then return no(\"mild mode: an approach goes only to a willing creature\") end\r\nlocal impl, iname = K.AR.impl(f[3], atk, pc)\r\nif not impl then return no(\"no implement \" .. tostring(f[3]) .. \" (the module's list, or a spell in effect that makes one; one that animates a tool: Spell (Tool))\") end\r\n\r\nlocal ash = K.AR.sheetOf(atk, pc)\r\nif ash and not K.AR.implHas(ash, impl, iname) then return no((f[1] or \"\") .. \" has no \" .. iname .. \" (a body part of some species or features)\") end\r\n\r\nif impl.phallic then\r\nif K.AR.posOf(atk, pc) == \"bottom\" then return no((f[1] or \"\") .. \" is a bottom (the character tab): it is penetrated, never penetrates\") end\r\nif K.AR.posOf(t, pc) == \"top\" then return no((f[2] or \"\") .. \" is a top (the character tab): it penetrates, is never penetrated\") end\r\nend\r\nlocal off = K.d2need(impl)\r\nif off then return no(\"implement \" .. iname .. \" is \" .. K.D2_WHY[off]) end\r\nlocal sz = K.AR.sizeRule(atk, t, impl, iname, pc)\r\nif sz.refuse then return no(sz.refuse) end\r\nif sz.big and will == \"willing\" then will = \"unwilling\" end\r\nlocal bad = {}\r\nK.AR.advancing, K.AR.advSkillNote = true, nil\r\nlocal bonus, dice, mod = K.AR.implNums(atk, impl, iname, pc, c)\r\nif (tonumber(impl.itemPlus) or 0) ~= 0 then bonus = bonus + impl.itemPlus end\r\nK.AR.advancing = nil\r\nlocal inhib = K.AR.inhib(t, pc)\r\nif impl.kind == \"spell\" and K.AR.ignores(atk, pc) then inhib = math.min(0, inhib) end\r\nlocal ac = (tonumber(K.AR.acOf(t, pc)) or 10) + (will == \"unwilling\" and inhib or math.min(0, inhib))\r\nlocal roll, rmode, nat = takeD20(cur, pools, f[5] or \"\", bad, atkRec, atkRec and \"attack\" or nil)\r\nnat = nat or roll\r\n\r\n\r\nlocal willAdv, willAdvNote = will == \"willing\", \"\"\r\nlocal function firstD20()\r\nlocal g = K.d20Got or {}\r\nlocal a, b = tonumber(g[1]), tonumber(g[2])\r\nif not (a and b and tonumber(roll)) then return end\r\nroll = roll - (rmode == \"adv\" and math.max(a, b) or math.min(a, b)) + a\r\nnat, rmode = a, \"normal\"\r\nend\r\n\r\nif willAdv and (sz.dis or rmode == \"dis\" or K.AR.ownDis(atk, atkRec, pc)) then\r\nif rmode == \"adv\" or rmode == \"dis\" then firstD20() end\r\nwillAdvNote = \" (willing: Advantage, cancelled by Disadvantage)\"\r\nelseif willAdv and (rmode == \"normal\" or rmode == \"bi\" or rmode == \"luck\" or rmode == \"insp\") and tonumber(nat) then\r\n\r\n\r\nlocal second = K.d(20)\r\nif second > nat then roll, nat = roll - nat + second, second end\r\nrmode = \"adv\"\r\nwillAdvNote = string.format(\" (willing: Advantage, Lua's second d20 %d)\", second)\r\nelseif sz.dis and rmode == \"normal\" then\r\ncur.d20 = cur.d20 + 1\r\nlocal w = pools.d20[cur.d20]\r\nif w == nil then K.poolEmpty(bad, \"d20\"); w = K.pastDie(pools, \"d20\", cur.d20) end\r\nbad[#bad + 1] = string.format(\"d20 %s->dis %s,%d (%d sizes smaller: Disadvantage)\", tostring(roll), tostring(roll), w, -sz.d)\r\nroll = math.min(tonumber(roll) or 20, w)\r\nnat, rmode = roll, \"dis\"\r\nelseif sz.dis and rmode == \"adv\" then\r\nfirstD20()\r\nend\r\n\r\nif rmode == \"adv\" and impl.precise then\r\n\r\n\r\nK.AR.advancing = true\r\nlocal _, pd = K.AR.implNums(atk, setmetatable({ dice = impl.precise }, { __index = impl }), iname, pc, c)\r\nK.AR.advancing = nil\r\nif pd then dice = pd end\r\nend\r\nif (tonumber(impl.itemPlus) or 0) ~= 0 then dice = dice .. string.format(\"%+d\", impl.itemPlus) end\r\nlocal wb = (f[6] or \"\"):gsub(\"^%s*%+\", \"\")\r\nif tonumber(wb) ~= bonus then bad[#bad + 1] = \"bonus \" .. tostring(f[6]) .. \"->\" .. string.format(\"%+d\", bonus) end\r\nlocal old = Feat.cur.inhib0 and Feat.cur.inhib0[t]\r\nlocal acOld = old and (tonumber(K.AR.acOf(t, pc)) or 10) + (will == \"unwilling\" and old or math.min(0, old))\r\nif acOld and tonumber(f[7]) == acOld and acOld ~= ac then f[7] = tostring(ac); head = \"[ADVANCE|\" .. table.concat(f, \"|\", 1, 11)\r\nelseif tonumber(f[7]) ~= ac then bad[#bad + 1] = \"AC \" .. tostring(f[7]) .. \"->\" .. ac .. (will == \"unwilling\" and inhib > 0 and \" (with its inhibition)\" or \"\") end\r\n\r\nlocal critMin = 20\r\nfor _, e in ipairs(ash and Feat.fxOf(ash, \"impl_crit\") or {}) do\r\nif K.fxImpl(ash, e, impl, iname) then critMin = math.min(critMin, tonumber(e.min) or 20) end\r\nend\r\nlocal res = nat >= critMin and \"crit\" or nat == 1 and \"miss\" or ((tonumber(roll) or 0) + bonus >= ac and \"hit\" or \"miss\")\r\n\r\nlocal stimType\r\nfor cn, row in pairs(K.AR.condsOf(t)) do\r\nlocal ac0 = row.advance_crit\r\nlocal fitsI = ac0 == true\r\nif type(ac0) == \"table\" then\r\nfor _, x in ipairs(ac0.names or {}) do if x == iname then fitsI = true end end\r\nfor _, x in ipairs(ac0.kinds or {}) do if x == impl.kind then fitsI = true end end\r\nend\r\nif fitsI and res == \"hit\" then res = \"crit\"; K.AR.advCritBy = cn end\r\nif row.stim_type then stimType = row.stim_type end\r\nend\r\nif (f[8] or \"\"):lower() ~= res then bad[#bad + 1] = \"result \" .. tostring(f[8]) .. \"->\" .. res .. (K.AR.advCritBy and res == \"crit\" and (\" (\" .. K.AR.advCritBy .. \")\") or \"\") end\r\nK.AR.advCritBy = nil\r\nlocal me = (atk == pc and \"Player\") or atk.name or f[1]\r\nif c.active then c.last = me end\r\nfor _, x in ipairs(K.AR.implBuffs(atk, impl, pc, iname)) do\r\nif x.b.one then atk.implBind = type(atk.implBind) == \"table\" and atk.implBind or {}; atk.implBind[x.spell] = atk.implBind[x.spell] or iname end\r\nend\r\nif res == \"miss\" then\r\nK.spendRefused(pools, cur, nil, f[9], f[10])\r\nreturn head .. \"|\" .. verdictOf(bad) .. \"|miss\" .. willAdvNote .. \"]\", #bad == 0\r\nend\r\nif atkRec then\r\nFeat.cur.lastHit = Feat.cur.lastHit or {}\r\nFeat.cur.lastHit[(atkRec == pc and \"Player\") or atkRec.name or \"Player\"] = t\r\nend\r\nlocal want = parseFormula(dice)\r\nif res == \"crit\" then for _, dd in ipairs(want.dice) do dd.n = dd.n * 2 end end\r\nlocal amount, vals = spendDice(want, f[10], pools, cur, bad, K.wroteF(f[9], f[10]))\r\namount = math.max(0, tonumber(amount) or 0)\r\n\r\n\r\nlocal featNote = \"\"\r\nif ash and type(vals) == \"table\" then\r\nfor _, e in ipairs(Feat.fxOf(ash, \"stim_reroll\")) do\r\nif K.fxImpl(ash, e, impl, iname) then\r\nlocal upto = K.fxNum(e.upto or 1, ash, K.charLevel(ash))\r\nfor _, v in ipairs(vals) do\r\nif tonumber(v.v) and tonumber(v.s) and v.v <= upto then\r\nlocal nv = K.d(v.s)\r\namount = amount - v.v + nv; featNote = featNote .. string.format(\" (%s: %d->%d)\", e.src or \"stim_reroll\", v.v, nv); v.v = nv\r\nend\r\nend\r\nend\r\nend\r\nfor _, e in ipairs(Feat.fxOf(ash, \"stim_floor\")) do\r\nif K.fxImpl(ash, e, impl, iname) then\r\nlocal mn = tonumber(e.min) or 2\r\nfor _, v in ipairs(vals) do if tonumber(v.v) and v.v < mn then amount = amount + (mn - v.v); v.v = mn; featNote = featNote .. \" (\" .. (e.src or \"stim_floor\") .. \")\" end end\r\nend\r\nend\r\nend\r\n\r\nlocal parts, magicBuff\r\nfor _, x in ipairs(K.AR.implBuffs(atk, impl, pc, iname)) do\r\nif x.b.one then atk.implBind = type(atk.implBind) == \"table\" and atk.implBind or {}; atk.implBind[x.spell] = atk.implBind[x.spell] or iname end\r\nif x.b.magical then magicBuff = true end\r\nlocal bp = type(x.b.dice) == \"string\" and x.b.dice_type and parseFormula(x.b.dice)\r\nif bp and #bp.dice > 0 and type(vals) == \"table\" then\r\nlocal d = bp.dice[1]\r\nlocal k, part = d.n * (res == \"crit\" and 2 or 1), 0\r\nfor i = #vals, 1, -1 do\r\nif k <= 0 then break end\r\nif vals[i].s == d.s then part, k = part + vals[i].v, k - 1 end\r\nend\r\npart = math.min(part, amount)\r\nparts = parts or { { type = impl.type, n = amount } }\r\nparts[1].n = parts[1].n - part\r\nparts[#parts + 1] = { type = x.b.dice_type, n = part, max = d.n * (res == \"crit\" and 2 or 1) * d.s }\r\nend\r\nend\r\nif canon(parseFormula(f[9] or \"\") or { dice = {}, mod = 0 }, false) ~= canon(want, false) then bad[#bad + 1] = \"formula \" .. tostring(f[9]) .. \"->\" .. canon(want, false) end\r\n\r\nif type(t.ar) == \"table\" and type(t.ar.edge) == \"table\" then\r\nlocal mxv = want.mod\r\nfor _, dd in ipairs(want.dice) do mxv = mxv + dd.n * dd.s end\r\nif tonumber(f[11]) == amount or tonumber(f[11]) == mxv then f[11] = tostring(mxv); head = \"[ADVANCE|\" .. table.concat(f, \"|\", 1, 11) end\r\namount = mxv\r\nif parts then\r\nlocal rest = 0\r\nfor i = 2, #parts do parts[i].n = parts[i].max or parts[i].n; rest = rest + parts[i].n end\r\nparts[1].n = mxv - rest\r\nend\r\nend\r\nif tonumber(f[11]) ~= amount then bad[#bad + 1] = \"stim \" .. tostring(f[11]) .. \"->\" .. amount end\r\n\r\nK.AR.toyNote = nil\r\nfor cn, row in pairs(K.AR.condsOf(t)) do\r\nlocal as = row.advance_stim\r\nlocal q = type(as) == \"table\" and parseFormula(as.dice or \"\")\r\nif q then\r\nlocal x = 0\r\nfor _, dd in ipairs(q.dice) do for _ = 1, dd.n * (res == \"crit\" and 2 or 1) do x = x + K.d(dd.s) end end\r\nparts = parts or { { type = stimType or impl.type, n = amount } }\r\nparts[#parts + 1] = { type = as.type, n = x }\r\namount = amount + x\r\nK.AR.toyNote = (K.AR.toyNote or \"\") .. string.format(\" (%s: +%d %s)\", cn, x, as.type)\r\nend\r\nend\r\n\r\nlocal sizeNote = \"\"\r\nif sz.dice ~= 0 then\r\nlocal x = 0\r\nfor _ = 1, math.abs(sz.dice) do x = x + K.d(4) end\r\nlocal before = amount\r\namount = sz.dice > 0 and (amount + x) or math.max(0, amount - x)\r\nif parts then parts[1].n = math.max(0, parts[1].n + (amount - before)) end\r\nsizeNote = string.format(\" (size %s%dd4 = %s%d, %s vs %s)\", sz.dice > 0 and \"+\" or \"-\", math.abs(sz.dice), sz.dice > 0 and \"+\" or \"-\", math.abs(amount - before),\r\nK.sizeName(sz.is), K.sizeName(sz.ts))\r\nend\r\nif sz.big then\r\n\r\nlocal q = parseFormula(impl.dice or \"1d4\") or { dice = {}, mod = 0 }\r\nlocal hurt = 0\r\nfor _, dd in ipairs(q.dice) do for _ = 1, dd.n * (res == \"crit\" and 2 or 1) do hurt = hurt + K.d(dd.s) end end\r\nlocal tRec = (t == pc or Ally.find(pc, t.name or \"\")) and t or nil\r\nlocal hn\r\nif tRec then hn = hurtPC(tRec, hurt, false); hn = (tRec.hp or 0) .. \"/\" .. (tRec.max or 0) .. hn\r\nelse\r\nlocal raw = hurt\r\nhurt, hn = Feat.adjust(MONSTERS[t.kind or \"\"], hurt, impl.type)\r\nhn = hn .. K.hurtFoe(t, raw, hurt, impl.type, false)\r\nhn = (t.hp or 0) .. \"/\" .. (t.max or 0) .. hn\r\nend\r\nsizeNote = sizeNote .. string.format(\" (too large by %d sizes: %d %s damage, HP %s)\", sz.d, hurt, impl.type or \"Bludgeoning\", hn)\r\nend\r\nlocal sty = stimType or impl.type\r\nif stimType and parts then for _, x in ipairs(parts) do x.type = stimType end end\r\n\r\nlocal pierce\r\nfor _, e in ipairs(ash and Feat.fxOf(ash, \"stim_pierce\") or {}) do\r\nlocal p0 = type(ash.picks) == \"table\" and ash.picks or {}\r\npierce = pierce or {}\r\nfor _, x in ipairs(e.types or {}) do pierce[x] = true end\r\nif e.pick and type(p0[e.pick]) == \"string\" then pierce[p0[e.pick]] = true end\r\nend\r\nlocal text, extra = K.AR.give(t, amount, pc, c, res == \"crit\", f[2], me, { type = sty, magical = impl.kind == \"spell\" or impl.magical or magicBuff or false, parts = parts, pierce = pierce })\r\ntext = featNote .. text .. (K.AR.toyNote or \"\") .. sizeNote\r\nK.AR.toyNote = nil\r\nlocal rText, rExtra = K.AR.recip(atk, t, impl, iname, ash, impl.dice, pc, c, f[1], me, sz.dice)\r\n\r\n\r\nif type(impl.say) == \"string\" and impl.say ~= \"\" then rText = rText .. \"; \" .. iname .. \": \" .. impl.say:gsub(\"%[\", \"«\"):gsub(\"%]\", \"»\") end\r\nreturn head .. \"|\" .. verdictOf(bad) .. \"|\" .. sty .. \" \" .. text .. willAdvNote .. (K.AR.advSkillNote or \"\") .. rText .. \"]\" .. extra .. rExtra, #bad == 0\r\nend\r\n\r\nfunction K.AR.implText(pc)\r\nif not K.AR.on() then return nil end\r\nlocal o = {}\r\nlocal other = {}\r\nlocal grp = {}\r\nfor n, impl in pairs(K.PACK.impl) do\r\nif not K.d2need(impl) and K.AR.implHas(SHEET, impl, n) then\r\nlocal b, dice, mod0 = K.AR.implNums(pc, impl, n, pc)\r\nif impl.kind == \"tool\" and not K.AR.implProf(SHEET, impl, n) and b == mod0 then other[#other + 1] = b\r\nelse\r\n\r\nlocal k = string.format(\"%+d %s %s\", b, dice, impl.type)\r\ngrp[k] = grp[k] or {}\r\ngrp[k][#grp[k] + 1] = n\r\nend\r\nend\r\nend\r\nfor k, names in pairs(grp) do table.sort(names); o[#o + 1] = table.concat(names, \", \") .. \" \" .. k end\r\n\r\nfor _, a in ipairs(Spell.active(pc)) do\r\nlocal impl = K.AR.impl(a.name, pc, pc, true)\r\nlocal adv = SPELLS[a.name] and SPELLS[a.name].m and SPELLS[a.name].m.advance\r\nif impl and impl.kind == \"spell\" and type(adv) == \"table\" and adv.animate then\r\nlocal b = K.AR.implNums(pc, impl, a.name, pc)\r\no[#o + 1] = string.format(\"%s (spell; write it as %s (Tool), the tool's dice and type) %+d\", a.name, a.name, b)\r\nelseif impl and impl.kind == \"spell\" then\r\nlocal b, dice = K.AR.implNums(pc, impl, a.name, pc)\r\no[#o + 1] = string.format(\"%s (spell) %+d %s %s\", a.name, b, dice, impl.type)\r\nend\r\nend\r\nif #o == 0 and #other == 0 then return nil end\r\ntable.sort(o)\r\ntable.sort(other)\r\nif #other > 0 then\r\no[#o + 1] = string.format(\"other tool implements %s, their own dice (no proficiency)\",\r\nother[1] == other[#other] and string.format(\"%+d\", other[1]) or string.format(\"%+d to %+d\", other[1], other[#other]))\r\nend\r\nreturn \"Player's approaches (implements): \" .. table.concat(o, \"; \") .. \".\"\r\nend\r\nfunction K.AR.soothe(f, pools, cur, c, pc)\r\nlocal head = \"[SOOTHE|\" .. table.concat(f, \"|\", 1, 5)\r\nlocal by, sname = K.castBy(f[2], pc)\r\nf = { f[1], f[2], K.spellTerms(f[3], sname, by, pc), f[4], f[5] }\r\nlocal t, line, good = K.AR.check(head, f, c, pc, pools, cur, 3, 4)\r\nif not t then return line, good end\r\nlocal p = parseFormula(f[3] or \"\")\r\nif not p then return head .. \"|bad:write the formula: [SOOTHE|Target|Source|1d8|dice|amount]|-]\", false end\r\nlocal bad = {}\r\nlocal amount = spendDice(p, f[4], pools, cur, bad, K.wroteF(f[3], f[4]))\r\namount = math.max(0, tonumber(amount) or 0)\r\nif tonumber(f[5]) ~= amount then bad[#bad + 1] = \"amount \" .. tostring(f[5]) .. \"->\" .. amount end\r\nlocal a, mx = K.AR.st(t), K.AR.max(t, pc)\r\na.cur = math.max(0, (tonumber(a.cur) or 0) - amount)\r\nif a.cur < mx then a.edge = nil end\r\nreturn head .. \"|\" .. verdictOf(bad) .. \"|\" .. a.cur .. \"/\" .. mx .. \"]\", #bad == 0\r\nend\r\nfunction K.AR.numb(f, c, pc)\r\nlocal head = \"[NUMB|\" .. (f[1] or \"\") .. \"|\" .. (f[2] or \"\")\r\nlocal t, line, good = K.AR.check(head, f, c, pc)\r\nif not t then return line, good end\r\nlocal n = tonumber(f[2])\r\nif not n or n < 0 or n ~= math.floor(n) then return head .. \"|bad:write [NUMB|Target|N]|-]\", false end\r\nlocal a = K.AR.st(t)\r\na.numb = math.max(tonumber(a.numb) or 0, n)\r\n\r\nlocal sn = Canon.name(f[3] or \"\")\r\nlocal nr = SPELLS[sn] and SPELLS[sn].m and SPELLS[sn].m.numb_resist\r\nif type(nr) == \"table\" then\r\na.numbRes = { types = nr.types, nonmagical = nr.nonmagical, by = sn }\r\nreturn head .. \"|\" .. sn .. \"|ok|numbness \" .. a.numb .. \", resisting \" .. (nr.nonmagical and \"nonmagical implements\" or \"stimulation\") .. \" while it lasts]\", true\r\nend\r\na.numbRes = nil\r\nreturn head .. ((f[3] or \"\") ~= \"\" and (\"|\" .. f[3]) or \"\") .. \"|ok|numbness \" .. a.numb .. \"]\", true\r\nend\r\n\r\nfunction K.AR.short(rec, pc)\r\nif not K.AR.on() then return \"\" end\r\nlocal sh = K.AR.sheetOf(rec, pc)\r\nlocal a = K.AR.st(rec)\r\nif not sh or (tonumber(a.cur) or 0) <= 0 then return \"\" end\r\nlocal left = K.AR.dice(rec, pc)\r\nlocal pb = 2 + math.floor((K.charLevel(sh) - 1) / 4)\r\nlocal n, con, before, used = K.AR.die(sh), abilityMod(K.score(sh, \"Constitution\")), a.cur, 0\r\nwhile left > 0 and used < pb and a.cur > 0 do\r\na.cur = math.max(0, a.cur - math.max(1, K.dieFor(rec, n) + con + K.recoverBonus(rec, pc)))\r\nleft, used = left - 1, used + 1\r\nend\r\na.used = (tonumber(a.used) or 0) + used\r\nif a.cur < K.AR.max(rec, pc) then a.edge = nil end\r\nreturn used > 0 and string.format(\"arousal %d->%d (recovery dice %d)\", before, a.cur, used) or \"\"\r\nend\r\nfunction K.AR.long(rec, pc)\r\nif not K.AR.on() or type(rec.ar) ~= \"table\" then return \"\" end\r\nlocal a, mx = rec.ar, K.AR.max(rec, pc)\r\nlocal before = tonumber(a.cur) or 0\r\na.cur = math.max(0, before - math.floor(mx / 2))\r\na.used, a.numb = 0, 0\r\na.inhibAdj = nil\r\nrec.arPool = nil\r\nlocal restNote = \"\"\r\nif type(rec.badEnd) == \"table\" and (K.D2.perm ~= \"on\" or rec.badEnd.rec) then rec.badEnd = nil end\r\nif rec == pc then\r\nlocal any = false\r\nfor _, r in ipairs({ pc, table.unpack(Ally.list(pc)) }) do if K.AR.hot(r, nil) then any = true end end\r\nif not any then pc.arWarm = nil end\r\nend\r\nif (tonumber(a.overstim) or 0) > 0 then\r\nlocal now = K.clockRef and tonumber(K.clockRef.min) or 0\r\nif not tonumber(a.lastStim) or a.lastStim <= now - 480 then a.overstim = a.overstim - 1; restNote = \", overstimulation \" .. a.overstim end\r\nend\r\nif a.cur < mx then a.edge = nil end\r\na.incapTo = nil\r\nlocal out = (before > 0 and string.format(\"arousal %d->%d\", before, a.cur) or \"\") .. restNote\r\nreturn (out:gsub(\"^, \", \"\"))\r\nend\r\n\r\n\r\n\r\nfunction Ally.rest(pc, kind, clock)\r\nlocal notes = {}\r\nlocal all = { table.unpack(Ally.list(pc)) }\r\nfor _, g in ipairs(Ally.guests(pc)) do all[#all + 1] = g end\r\nfor _, a in ipairs(all) do\r\nif not a.dead then\r\nAlly.with(a, function()\r\nif kind == \"long\" then\r\nlocal keepHp = K.restNoHp(SHEET, \"long\") and a.hp or nil\r\na.hp, a.hd, a.wake, a.ds, a.thp, a.form, a.mode = a.max, a.level, nil, { s = 0, f = 0 }, nil, nil, nil\r\nif keepHp then a.hp = keepHp end\r\na.hi = nil\r\nfor k, r in pairs(PC.res) do a.res[k] = r.max end\r\nCond.load(a)\r\nif a.exh > 0 then a.exh = a.exh - 1 end\r\nif (tonumber(a.ordeal) or 0) > 0 then a.ordeal = a.ordeal - 1 end\r\na.taxed = nil\r\nLOOT.refill(a)\r\nlocal pt = K.portentRoll(a, SHEET)\r\nif pt ~= \"\" then notes[#notes + 1] = (a.name or \"?\") .. pt end\r\nlocal arL = K.joinNote(K.joinNote(K.AR.long(a, pc), K.drainRest(a, pc, \"long\")), K.viceRest(a, pc))\r\nif arL ~= \"\" then notes[#notes + 1] = (a.name or \"?\") .. \" \" .. arL end\r\nelseif a.hp > 0 then\r\nlocal b0, used = a.hp, 0\r\nlocal halfA = K.healHalf(a, pc)\r\nwhile not K.restNoHp(SHEET, \"short\") and a.hd > 0 and a.hp < a.max do\r\n\r\nlocal g = math.max(1, K.dieFor(a, K.hdNext(a.sheet, a.hd)) + MOD.Constitution)\r\nif halfA then g = math.floor(g / 2) end\r\na.hp = math.min(a.max, a.hp + g)\r\na.hd = a.hd - 1\r\nused = used + 1\r\nend\r\n\r\nif used > 0 then\r\nnotes[#notes + 1] = string.format(\"%s HP %d->%d, Hit Point Dice %d\", a.name or \"?\", b0, a.hp, used)\r\nK.hdGain(pc, a.name, a.hp - b0, clock)\r\nend\r\nlocal arN = K.joinNote(K.AR.short(a, pc), K.drainRest(a, pc, \"short\"))\r\nif arN ~= \"\" then notes[#notes + 1] = (a.name or \"?\") .. \" \" .. arN end\r\nfor k, r in pairs(PC.res) do a.res[k] = math.min(r.max + K.gainExtra(SHEET, k), (a.res[k] or 0) + r.short) end\r\nFeat.arcane(a)\r\nFeat.restoration(a)\r\nFeat.shortRest(a)\r\nend\r\nend)\r\nend\r\nend\r\nreturn table.concat(notes, \"; \")\r\nend\r\n\r\n\r\nfunction Ally.line(a, fight)\r\nlocal sh = a.sheet\r\nlocal st = pcStats(a)\r\n\r\nlocal down = \"\"\r\nif a.hp <= 0 then\r\nlocal p = (not fight and a.wake) and clockParts(a.wake)\r\ndown = p and string.format(\" DOWN until %02d:%02d on day %d\", p.h, p.m, p.day) or \" DOWN\"\r\nend\r\nlocal out = { string.format(\"- %s (%s %s; %s): HP %d/%d%s, AC %d, Speed %d ft\", a.name, sh.species, K.mcText(sh),\r\na.note ~= \"\" and a.note or \"-\", a.hp, a.max, down .. K.maxBonusText(a) .. ((tonumber(a.thp) or 0) > 0 and (\", \" .. a.thp .. \" temporary HP\") or \"\"),\r\nst.ac, st.speed) .. (st.fly and string.format(\" (fly %d ft, hover)\", st.fly) or \"\") }\r\nif not fight then\r\nlocal atk = {}\r\nfor _, x in ipairs(st.attacks) do\r\nif not x.spell then atk[#atk + 1] = string.format(\"%s +%d %s%s\", x.name, x.hit, x.dmg, Feat.exText(x)) end\r\nend\r\nout[#out + 1] = \"Attacks: \" .. table.concat(atk, \"; \")\r\nend\r\nlocal sk, sv = {}, {}\r\nfor _, k in ipairs(K.profSkills(sh)) do sk[#sk + 1] = string.format(\"%s %+d\", k, bonusFor(k)) end\r\nfor _, x in ipairs(K.otherSkills(sh)) do sk[#sk + 1] = x end\r\nfor _, ab in ipairs(ABILS) do sv[#sv + 1] = string.format(\"%s %+d\", ab:sub(1, 3):upper(), bonusFor(ab .. \" save\")) end\r\nif not fight then out[#out + 1] = \"Skills (others use the ability modifier): \" .. table.concat(sk, \", \") end\r\nlocal tt = not fight and K.toolText(sh, a.name, true)\r\nif tt then out[#out + 1] = tt end\r\nout[#out + 1] = \"Saves: \" .. table.concat(sv, \", \")\r\nlocal res = {}\r\nfor k, r in pairs(PC.res) do\r\nif K.MP.shown(k) and k ~= \"MP\" then res[#res + 1] = string.format(\"%s %d/%d\", k, a.res[k] or 0, r.max) end\r\nend\r\ntable.sort(res)\r\nif #res > 0 then out[#out + 1] = \"Uses: \" .. table.concat(res, \", \") end\r\nlocal sl = K.slotsLeft(a)\r\nif sl then out[#out + 1] = sl end\r\nif K.AR.on() then\r\nout[#out + 1] = K.AR.text(a) .. \", \" .. K.AR.apAC(st.ac, K.AR.inhib(a, a))\r\nlocal it = K.AR.implText(a)\r\nif it then out[#out + 1] = (it:gsub(\"^Player's approaches\", a.name .. \"'s approaches\")) end\r\nend\r\nlocal mp = K.MP.line(a, a.name)\r\nif mp then out[#out + 1] = mp end\r\nlocal bt = K.buffText(a, a.name)\r\nif bt then out[#out + 1] = bt end\r\n\r\nlocal views = K.casterViews(sh)\r\nif Spell.stats() and #views > 0 then\r\nlocal anyCost = false\r\n\r\nlocal always, seen = {}, {}\r\nfor _, v in ipairs(views) do\r\nfor _, n in ipairs(v.cantrips or {}) do seen[n] = true end\r\nfor _, n in ipairs(v.spells or {}) do seen[n] = true end\r\nend\r\nfor _, n in ipairs(Feat.always(sh)) do if not seen[n] and SPELLS[n] then seen[n] = true; always[#always + 1] = n end end\r\nfor vi, v in ipairs(views) do\r\nlocal sp = {}\r\nfor _, list in ipairs({ v.cantrips or {}, v.spells or {}, vi == 1 and always or {} }) do\r\nfor _, n in ipairs(list) do\r\nlocal row = SPELLS[n]\r\nlocal m = row and row.m or {}\r\nlocal lv = row and row.level or 0\r\nlocal what = \"\"\r\n\r\nlocal pact = K.pactLevel()\r\nlocal at = (pact and lv >= 1 and lv < pact) and pact or lv\r\nif m.kind == \"attack\" and m.damage and m.attack ~= \"weapon\" then\r\nwhat = \" attack \" .. Spell.formula(n, m.damage, at, m.type)\r\nelseif m.kind == \"attack\" and type(m.stim) == \"table\" and m.attack ~= \"weapon\" then\r\nwhat = \" attack \" .. (Spell.formula(n, K.spellTerms(m.stim.dice or \"1d6\", n), at, \"stim\") or \"?\") .. \" \" .. (m.stim.type or \"Force\") .. \" stimulation (arousal)\"\r\nelseif m.kind == \"save\" then\r\nwhat = \" \" .. (m.save or \"\"):sub(1, 3):upper() .. \" save\" .. (m.damage and (\" \" .. Spell.formula(n, m.damage, at, m.type) .. (m.on_save == \"half\" and \" half\" or \"\"))\r\nor (type(m.fail) == \"string\" and (\": \" .. K.spellTerms(K.failText(m), n)) or \"\"))\r\nelseif m.kind == \"auto\" and m.say then\r\nwhat = \" \" .. K.spellTerms(m.say, n)\r\nelseif m.kind == \"auto\" then\r\nwhat = string.format(\" %d darts %s\", (m.darts or 1) + ((m.upcast or {}).darts or 0) * (at - lv), m.damage)\r\nelseif m.hp_bonus or m.temp_hp or m.temp_share then\r\nwhat = \" \" .. K.hpBuffWhat(n, m, lv, a.name)\r\nelseif m.kind == \"buff\" and m.cast == \"reaction\" and m.ac_bonus then\r\nwhat = \" Reaction when hit: +\" .. m.ac_bonus .. \" AC to its next turn, that attack too (Lua counts it)\"\r\nelseif m.kind == \"buff\" and m.cast ~= \"reaction\" then\r\nwhat = type(m.party_skill) == \"table\" and \" Lua adds its bonus for the whole party, no BUFF tag\"\r\nor ((type(m.say) == \"string\" and m.say ~= \"\" and (\" \" .. K.spellTerms(m.say, n) .. \";\") or \" effect narrated;\") .. \" a BUFF tag per target after the CAST\")\r\nelseif m.kind == \"heal\" and (m.heal_all or m.heal_share) then\r\nwhat = m.heal_all and \" heals all HP\" or (\" heals \" .. m.heal_share .. \" divided\")\r\nelseif m.kind == \"heal\" then\r\nlocal hf = Spell.formula(n, m.heal, lv)\r\n\r\nif K.subHas(sh, \"Disciple of Life\") and lv >= 1 then hf = canon(parseFormula(hf .. \"+\" .. (2 + lv)), false) end\r\nwhat = \" heals \" .. hf\r\nelseif type(m.say) == \"string\" and m.say ~= \"\" then\r\nwhat = \" \" .. K.spellTerms(m.say, n)\r\nend\r\nif row and row.cost then what = what .. \"; needs \" .. row.cost; anyCost = true end\r\nsp[#sp + 1] = n .. \" (\" .. (lv == 0 and \"cantrip\" or (\"level \" .. lv)) .. (at ~= lv and (\", cast at \" .. at) or \"\") .. what\r\n.. (m.concentration and \", Concentration\" or \"\") .. K.AR.apNote(m) .. (type(m.warn) == \"string\" and (\"; \" .. K.spellTerms(m.warn, n)) or \"\") .. \")\"\r\nend\r\nend\r\nlocal s = Spell.stats(nil, v.class)\r\nout[#out + 1] = string.format(\"Spells%s (save DC %d, spell attack %+d): %s\", #views > 1 and (\" as a \" .. v.class) or \"\", s.dc, s.atk, table.concat(sp, \"; \"))\r\nend\r\nif anyCost then out[#out + 1] = K.COST_RULE end\r\n\r\nif type(a.conc) == \"table\" and a.conc.name then out[#out + 1] = \"Concentrating on \" .. a.conc.name .. \" ([CONC|end|\" .. a.name .. \"] to drop it)\" end\r\nlocal gone = K.concGoneText(a, a.name)\r\nif gone ~= \"\" then out[#out + 1] = trim(gone):gsub(\"%.$\", \"\") end\r\nend\r\nlocal ft = Feat.text(sh, a)\r\nif ft then out[#out + 1] = ft:gsub(\"%.$\", \"\") end\r\nout[#out + 1] = K.replacedText(sh)\r\nlocal now = Feat.now(a)\r\nif now then out[#out + 1] = now end\r\nlocal cs = Cond.active(a)\r\n\r\nif (a.exh or 0) > 0 then\r\ncs[#cs + 1] = string.format(\"Exhaustion %d (-%d on its checks and saves; the attack bonuses above already include it)\", a.exh, 2 * a.exh)\r\nend\r\n\r\nif (tonumber(a.ordeal) or 0) > 0 then\r\ncs[#cs + 1] = string.format(\"back from the dead (-%d on its checks and saves, one less per Long Rest; the attack bonuses above already include it)\", a.ordeal)\r\nend\r\nif a.taxed then cs[#cs + 1] = \"taxed by Resurrection (no spells, Disadvantage on D20 Tests until a Long Rest)\" end\r\nlocal wt = K.wearText(a)\r\nif wt then out[#out + 1] = \"Damaged gear: \" .. wt end\r\n\r\nlocal mi = {}\r\nfor n, l in pairs(type(a.loot) == \"table\" and a.loot or {}) do\r\nif type(l) == \"table\" and l.srd and (tonumber((a.items or {})[n]) or 0) > 0 then mi[#mi + 1] = K.MI.text(n, l, a.items[n]) end\r\nend\r\ntable.sort(mi)\r\nif #mi > 0 then out[#out + 1] = \"Magic items: \" .. table.concat(mi, \"; \") end\r\nif #cs > 0 then out[#out + 1] = \"Conditions: \" .. table.concat(cs, \", \") end\r\nreturn table.concat(out, \". \") .. \".\"\r\nend\r\n\r\n\r\n\r\n\r\n\r\nAlly.WORDS = { \"동료\", \"일행\", \"파티\", \"합류\", \"동행\", \"같이 가\", \"함께 가\", \"같이 갈\", \"함께 갈\", \"같이 다니\", \"함께 다니\", \"데려\",\r\n\r\n\"붙여\", \"고용\", \"용병\", \"데리고\", \"도와줄 사람\", \"도울 사람\", \"hire\",\r\n\"party\", \"companion\", \"join\", \"영입\" }\r\n\r\nAlly.PREV_WORDS = { \"동료\", \"합류\", \"동행\", \"영입\", \"같이 가\", \"함께 가\", \"같이 갈\", \"함께 갈\", \"데려\" }\r\n\r\n\r\nfunction Ally.text(pc, fight, want, userText, cue, prevText)\r\nlocal list, lines = Ally.list(pc), {}\r\nif #list > 0 then\r\n\r\nlines[1] = \"[PARTY] Player's companions, a closed list kept by Lua: nobody else travels or fights beside Player unless an ALLY tag adds them. You play them.\"\r\nlocal tools = false\r\nfor _, a in ipairs(list) do\r\nif a.dead then\r\nlines[#lines + 1] = \"- \" .. a.name .. \": DEAD. Write [ALLY|-\" .. a.name .. \"|reason] when the story leaves them behind.\"\r\nelse\r\nlines[#lines + 1] = Ally.with(a, Ally.line, a, fight)\r\nif not fight and next(K.toolProfs(a.sheet)) then tools = true end\r\nend\r\nend\r\n\r\nif tools then lines[#lines + 1] = \"Companions' tools: \" .. K.TOOL_RULE:gsub(\"%[CHECK|Tool\", \"[CHECK|Name/Tool\") .. \".\" end\r\nlines[#lines + 1] = \"Companions act on their own judgement, true to their note; they go along with the user's requests when it makes sense to them.\"\r\n\r\n.. \" A plan Player says aloud for the party (to rest, to move on, to make camp) goes ahead in this reply; a companion may answer in character,\"\r\n.. \" and comes along.\"\r\n.. \" In a fight, play each companion's turn in the initiative order. Their tags use the exact name: ATTACK as attacker or target, HEAL as target,\"\r\n.. \" [CAST|Spell|slot level|Name] for their spells (then SAVE, DAMAGE, ATTACK or HEAL as for Player; with no slot left at a spell's level, at the lowest\"\r\n.. \" higher level in their \\\"Spell slots left\\\"), and Name/ before the skill for their rolls:\"\r\n.. \" [CHECK|Name/Skill|d20|+bonus|DC|result], [PASSIVE|Name/Skill|DC|result], [USE|Name/Feature], a trap that catches them [TRAP|severity|Name/Ability save|...],\"\r\n.. \" a creature's effect on them [SAVE|Name|Ability|...] as in COMBAT STATUS.\"\r\n.. (K.DEATH == \"harsh\" and \" A companion at 0 HP dies at once (harsh rule).\"\r\n\r\nor (K.DEATH == \"gentle\" and \" A companion at 0 HP is down and safe (gentle rule): no turns, no death; it comes to with 1 HP in the reply after\"\r\n.. \" a fight someone in the party stood through, else an hour after the fight (Lua sets it at the TIME tag that reaches the hour on its line).\"\r\nor \" A companion at 0 HP is down: no turns and no death saving throws, but each hit while down counts as a failed one (a crit two, three is death),\"\r\n\r\n.. \" and massive damage kills it as it does Player, with its own HP maximum;\"\r\n.. \" Lua wakes them with 1 HP 1-4 hours after the fight, at the TIME tag that reaches the hour on its line.\")\r\n.. \" A HEAL tag (a potion, a spell) on a downed companion wakes it at once.\")\r\n.. \" A companion leaves for good with [ALLY|-Name|reason], never during a fight.\"\r\n\r\n.. \" When the story changes a companion for good (a scar, a new title, a vow, how they now feel about Player), rewrite\"\r\n.. \" their note with [ALLY|=Name|new short Korean note: the whole note, not only the change]; seldom, not every reply.\"\r\n\r\n.. \" Gear that changes hands between Player and a companion (given, lent, handed back, loot shared out) moves only with\"\r\n.. \" [GIVE|From|To|Item|count], From and To being Player or the exact name; one who gets a weapon or armor they can use puts it on (Lua).\"\r\nend\r\nlocal have = Ally.size(pc) - 1\r\n\r\nlocal capNow = math.max(0, math.min(Ally.MAX, tonumber(want) or Ally.MAX))\r\nif not fight then\r\nlines[#lines + 1] = capNow == 0 and \"Party setting: 혼자 (no companions).\"\r\nor string.format(\"Party setting: up to %d companion%s (%d now).\", capNow, capNow > 1 and \"s\" or \"\", have)\r\nend\r\n\r\n\r\n\r\nlocal talk = false\r\nfor _, w in ipairs(Ally.WORDS) do\r\nif (userText or \"\"):lower():find(w, 1, true) then talk = true end\r\nend\r\n\r\n\r\nfor _, w in ipairs(Ally.PREV_WORDS) do\r\nif (prevText or \"\"):lower():find(w, 1, true) then talk = true end\r\nend\r\n\r\n\r\n\r\nlocal cap = math.max(0, math.min(Ally.MAX, tonumber(want) or Ally.MAX))\r\n\r\n\r\nif not fight and talk and cap == 0 then\r\nlines[#lines + 1] = \"[SOLO] The settings keep Player without companions: nobody joins, so write no [ALLY|+...] tag; someone may help in the story\"\r\n.. \" for this scene, and in a fight only as a helper named with + in the COMBAT tag. If the user wants a companion, say so in one short table-talk line (formal ~습니다):\"\r\n.. \" \\\"지금은 동료 없이 하는 설정입니다. 동료를 들이려면 동료 탭에서 파티 최대 인원을 올려 주십시오.\\\"\"\r\nelseif not fight and have >= cap and talk then\r\nlines[#lines + 1] = string.format(\"[PARTY FULL] Player already has %d companions, the most the settings allow: nobody else joins, so write no\"\r\n.. \" [ALLY|+...] tag. If the user wants another, say so in one short table-talk line (formal ~습니다), e.g. \\\"파티가 가득 찼습니다(동료 %d명).\"\r\n.. \" 새 동료를 들이려면 동료 탭의 헤어지기로 한 명과 먼저 헤어지거나 파티 최대 인원을 올려야 합니다.\\\", and in the story the person may walk along for this scene only.\",\r\nhave, have)\r\nend\r\nlocal due = false\r\nif not fight and have < cap and talk then\r\n\r\n\r\nlines[#lines + 1] = \"When someone agrees to go along with Player and fight beside them (to travel together, or hired for this one job), write\"\r\n.. \" [ALLY|+Name|Species|Class|short Korean note: look with weapon and armor, personality, way of talking] in that reply, before any fight. Class: one of \" .. table.concat(K.classNames(), \", \") .. \";\"\r\n.. \" One tag for each person; when several agree, write all their tags in the same reply.\" .. K.ALLY_NAME\r\n\r\n.. \" A last field is their level against Player's when the story makes them seasoned or green: +1 to +3 or -1 to -3\"\r\n.. \" (e.g. [ALLY|+Name|Human|Fighter|note|+2]); leave it out for Player's level.\"\r\n.. \" Lua builds the sheet at Player's level. At most \" .. cap .. \" companions, never during a fight. A hired hand leaves with [ALLY|-Name|reason] when the job is done.\"\r\n.. \" Someone who only walks along for a scene and does not fight needs no tag.\"\r\n\r\n\r\n\r\nlines[#lines + 1] = string.format(\"[JOINING] The user's message asks someone to come along (room for %d more). In this reply, when they agree,\"\r\n.. \" write their ALLY tag right then, before any COMBAT tag. Without it (or a + helper in the COMBAT tag, for one fight) they are not in the fight: no turns, no HP, and the story\"\r\n.. \" must not show them fighting.\", cap - have)\r\nelseif not fight and have < cap then\r\n\r\n\r\nlines[#lines + 1] = \"Someone who agrees to travel and fight beside Player joins only with [ALLY|+Name|Species|class (the SRD's or a rule expansion's)|short Korean note]\"\r\n.. \" in that reply, one tag each (several may join at once); add |+N or |-N (at most 3) for one more or less seasoned than Player.\" .. K.ALLY_NAME\r\nend\r\n\r\nlocal gone = {}\r\nfor _, g in ipairs(Ally.guests(pc)) do if g.parted then gone[#gone + 1] = g.name end end\r\nif not fight and have < cap and #gone > 0 then\r\nlines[#lines + 1] = \"Companions who parted earlier, kept as they were: \" .. table.concat(gone, \", \")\r\n.. \". One who comes back rejoins with [ALLY|+Name] under that same name (Lua brings back its sheet, picks and gear).\"\r\nend\r\nif #lines == 0 then return nil end\r\nreturn table.concat(lines, \"\\n\")\r\nend\r\n\r\n\r\n\r\nfunction Feat.initRefill(r)\r\nif type(r) ~= \"table\" or r.dead then return end\r\nr.res = type(r.res) == \"table\" and r.res or {}\r\nfor _, e in ipairs(Feat.fxOf(SHEET, \"init_refill\")) do\r\nlocal top = PC.res[e.res] and PC.res[e.res].max\r\nlocal have = r.res[e.res] or 0\r\nif top and e.upto and have < e.upto then\r\nr.res[e.res] = math.min(top, e.upto)\r\nelseif top and e.use and have < top and (r.res[e.use] or 0) >= 1 then\r\nr.res[e.res], r.res[e.use] = top, r.res[e.use] - 1\r\nend\r\nend\r\nend\r\n\r\nlocal function startCombat(f, c, pc, surprise, deadly)\r\nif c.active then return \"[COMBAT|\" .. table.concat(f, \"|\") .. \"|bad:already in combat]\" end\r\npc.plan = nil\r\nFeat.initRefill(pc)\r\nfor _, a in ipairs(Ally.list(pc)) do if not a.dead then Ally.with(a, Feat.initRefill, a) end end\r\nlocal fresh = newCombat()\r\nfresh.fid = tostring(math.random(1, 1073741824))\r\nlocal count, unknown, made = {}, {}, {}\r\nfresh.units[\"Player\"] = { side = \"pc\", init = surprise == \"party\" and math.min(Feat.init(), Feat.init()) or Feat.init() }\r\n\r\nfor _, a in ipairs(Ally.list(pc)) do\r\nif not a.dead then\r\nlocal ai = Ally.with(a, Feat.init)\r\nif surprise == \"party\" then ai = math.min(ai, Ally.with(a, Feat.init)) end\r\nfresh.units[a.name] = { side = \"ally\", ally = a.name, init = ai }\r\nend\r\nend\r\nfresh.party = Ally.size(pc)\r\n\r\nlocal helpers, helpBudget, nFoes = {}, 0, 0\r\nfor _, field in ipairs(f) do\r\nlocal h = field:match(\"^%s*%+%s*(.-)%s*$\")\r\nif h and h ~= \"\" then\r\nlocal nm, spw, clw, lvw = h:match(\"^([^/]+)/([^/]+)/([^/]+)/?(.*)$\")\r\nlocal kind = not nm and Canon.name(h)\r\nif nm then\r\nnm = trim(nm)\r\nlocal g = Ally.isGuest(pc, nm)\r\nif not g and not Ally.find(pc, nm) and nm ~= \"Player\" and not MONSTERS[nm] then\r\nlocal sp, pk = K.species(trim(spw))\r\nlocal cl = Ally.classOf(trim(clw))\r\nif sp and cl then\r\ng = Ally.build(nm, sp, cl, \"\", 1, pk)\r\ng.guest = true\r\ng.lvOff = Ally.lvOffOf(lvw, pc)\r\nif g.lvOff then g.lvOff = math.max(-Ally.LV_SPREAD, math.min(Ally.LV_SPREAD, g.lvOff)) end\r\nAlly.setLevel(g, Ally.levelFor(pc, g))\r\npc.guests = type(pc.guests) == \"table\" and pc.guests or {}\r\npc.guests[#pc.guests + 1] = g\r\nwhile #pc.guests > 6 do table.remove(pc.guests, 1) end\r\nend\r\nend\r\nif g and not g.dead then\r\nif Ally.levelFor(pc, g) ~= K.charLevel(g.sheet) then Ally.setLevel(g, Ally.levelFor(pc, g)) end\r\nlocal gi = Ally.with(g, Feat.init)\r\nif surprise == \"party\" then gi = math.min(gi, Ally.with(g, Feat.init)) end\r\nfresh.units[g.name] = { side = \"ally\", ally = g.name, guest = true, init = gi }\r\nhelpBudget = helpBudget + (BUDGET[g.level] or BUDGET[#BUDGET])[3]\r\nhelpers[#helpers + 1] = g.name\r\nelse\r\nunknown[#unknown + 1] = field\r\nend\r\nelseif kind and MONSTERS[kind] then\r\nlocal st = MONSTERS[kind]\r\ncount[kind] = (count[kind] or 0) + 1\r\nlocal name = kind .. \" \" .. count[kind]\r\nlocal d = K.d(20)\r\nif surprise == \"party\" then d = math.min(d, K.d(20)) end\r\nfresh.units[name] = { side = \"friend\", kind = kind, hp = st.hp, max = st.hp, init = d + st.init }\r\nhelpBudget = helpBudget + st.xp\r\nhelpers[#helpers + 1] = name\r\nelse\r\nunknown[#unknown + 1] = field\r\nend\r\nend\r\nend\r\nfor _, field in ipairs(f) do\r\nif not field:match(\"^%s*%+\") then\r\nnFoes = nFoes + 1\r\n\r\n\r\nlocal base, hpo = field:match(\"^(.-)%s*%([Hh][Pp]%s*(%d+)%)%s*$\")\r\nlocal kind = trim(base or field)\r\n\r\nlocal shown = kind\r\nlocal disp, inner = kind:match(\"^(.-)%s*%(([^()]+)%)$\")\r\nif disp and disp ~= \"\" and MONSTERS[K.monCanon(trim(inner))] then\r\nkind = K.monCanon(trim(inner))\r\nshown = (MONSTERS[disp] or disp:find(\"[|%[%]/=;]\") or disp:match(\"%d$\")) and kind or disp\r\nif shown ~= kind then\r\npc.monAlias = type(pc.monAlias) == \"table\" and pc.monAlias or {}\r\npc.monAlias[shown] = kind\r\nK.MON_ALIAS[shown] = kind\r\nend\r\nelseif not MONSTERS[kind] and type(pc.monAlias) == \"table\" and MONSTERS[pc.monAlias[kind] or \"\"] then\r\nshown, kind = kind, pc.monAlias[kind]\r\nelseif not MONSTERS[kind] and MONSTERS[K.monCanon(kind)] then\r\nkind = K.monCanon(kind)\r\nshown = kind\r\nend\r\nlocal st = MONSTERS[kind]\r\nif st then\r\ncount[shown] = (count[shown] or 0) + 1\r\nwhile fresh.units[shown .. \" \" .. count[shown]] do count[shown] = count[shown] + 1 end\r\nlocal name = shown .. \" \" .. count[shown]\r\n\r\nlocal d = K.d(20)\r\nif surprise == \"enemies\" then d = math.min(d, K.d(20)) end\r\nlocal hp = hpo and math.max(1, math.min(st.hp, tonumber(hpo))) or st.hp\r\n\r\nfresh.units[name] = { side = \"enemy\", kind = kind, hp = hp, max = st.hp, init = d + st.init,\r\nxp = hp < st.hp and math.max(10, math.floor(st.xp * hp / st.hp)) or nil, lr = st.lr }\r\nmade[#made + 1] = name\r\nelse\r\nunknown[#unknown + 1] = field\r\nnFoes = nFoes - 1\r\nend\r\nend\r\nend\r\nif #unknown > 0 then\r\n\r\nunknown[#unknown] = unknown[#unknown] .. \" (no such stat block in this game: write it with the nearest one it has in brackets, as Death Knight (Knight))\"\r\nend\r\n\r\nlocal capB, capL = K.capBudget(pc)\r\nlocal high = capB + helpBudget\r\nlocal function sumXp()\r\nlocal s = 0\r\nfor _, u in pairs(fresh.units) do if u.side == \"enemy\" then s = s + (u.xp or MONSTERS[u.kind].xp) end end\r\nreturn s\r\nend\r\n\r\n\r\n\r\nlocal planned = false\r\nfor _, x in ipairs(Quest.load(pc).list) do\r\nlocal s = x.stages[x.at]\r\nfor _, k in ipairs(s and s.foes or {}) do if count[k] then planned = true end end\r\nend\r\nif planned then deadly = true end\r\nlocal xp0, left = sumXp(), {}\r\nif not deadly then\r\nwhile sumXp() > high and #made > 1 do\r\nlocal name = table.remove(made)\r\nfresh.units[name] = nil\r\ntable.insert(left, 1, name)\r\nend\r\nend\r\nfresh.deadly = deadly and xp0 > high or nil\r\n\r\n\r\nlocal lone = not deadly and sumXp() > high\r\nif lone then fresh.deadly = true end\r\nif Feat.cur and Feat.cur.flips then\r\nfor _, name in ipairs(left) do Feat.cur.flips[#Feat.cur.flips + 1] = \"absent|\" .. name end\r\nend\r\n\r\nif type(pc.scene) == \"table\" and type(pc.scene.units) == \"table\" then\r\nfor sn, su in pairs(pc.scene.units) do\r\nlocal fu = fresh.units[sn .. \" 1\"] or fresh.units[sn]\r\nif fu and fu.side ~= \"pc\" and fu.side ~= \"ally\" and fu.kind == su.kind then\r\nfor _, k in ipairs({ \"ar\", \"cond\", \"condBind\", \"preg\", \"sdrain\", \"maxDown\" }) do if su[k] ~= nil then fu[k] = su[k] end end\r\nend\r\nend\r\npc.scene = nil\r\nend\r\nfor name in pairs(fresh.units) do fresh.order[#fresh.order + 1] = name end\r\n\r\n\r\ntable.sort(fresh.order, function(a, b)\r\nlocal ua, ub = fresh.units[a], fresh.units[b]\r\nif ua.init ~= ub.init then return ua.init > ub.init end\r\nlocal pa, pb = ua.side ~= \"enemy\", ub.side ~= \"enemy\"\r\nif pa ~= pb then return pa end\r\nreturn a < b\r\nend)\r\n\r\nfor _, s in ipairs(type(pc.summons) == \"table\" and pc.summons or {}) do\r\nlocal caster = s.by == \"Player\" and \"Player\" or s.by\r\nif (tonumber(s.hp) or 0) > 0 and fresh.units[caster] then K.summonJoin(fresh, s) end\r\nend\r\nfresh.active = #fresh.order > 1\r\nif fresh.active then pc.prep, pc.prepx = nil, nil end\r\nif fresh.active then pc.making = nil end\r\nfor k in pairs(c) do c[k] = nil end\r\nfor k, v in pairs(fresh) do c[k] = v end\r\nK.foeTargets(c, pc, true)\r\nif c.active and K.AR and K.AR.on() then K.AR.fightStart(c, pc) end\r\nlocal bad = {}\r\nif #unknown > 0 then bad[#bad + 1] = \"unknown \" .. table.concat(unknown, \",\") end\r\n\r\nif #left > 0 then bad[#bad + 1] = string.format(\"over \" .. capL .. \" budget %d>%d XP: %s left out\", xp0, high, table.concat(left, \", \")) end\r\nlocal xp = sumXp()\r\nif lone then bad[#bad + 1] = string.format(\"over \" .. capL .. \" budget %d>%d XP: one enemy alone, fought as a deadly fight\", xp, high)\r\nelseif planned and xp > high then bad[#bad + 1] = string.format(\"over \" .. capL .. \" budget %d>%d XP: the job's planned enemy, fought as a deadly fight\", xp, high)\r\nelseif xp > high and not fresh.deadly then bad[#bad + 1] = string.format(\"over \" .. capL .. \" budget %d>%d XP\", xp, high) end\r\n\r\n\r\nif fresh.party == 1 and #helpers == 0 and nFoes > K.SOLO_FOES then bad[#bad + 1] = \"more than \" .. K.SOLO_FOES .. \" enemies for Player alone\" end\r\nif (fresh.party > 1 or #helpers > 0) and nFoes > K.PARTY_FOES then bad[#bad + 1] = \"more than \" .. K.PARTY_FOES .. \" enemies\" end\r\nlocal verdict = verdictOf(bad)\r\nreturn \"[COMBAT|\" .. table.concat(f, \"|\") .. \"|\" .. verdict .. (fresh.deadly and \"|deadly\" or \"\") .. \"]\"\r\nend\r\n\r\nlocal function pcHpText(pc)\r\nif pc.dead then return \"사망\" end\r\nif pc.hp > 0 then return pc.hp .. \"/\" .. pc.max end\r\nif pc.stable then return \"0/\" .. pc.max .. \" 안정\" end\r\nreturn string.format(\"0/%d 쓰러짐 (죽음 내성 성공 %d · 실패 %d)\", pc.max, pc.ds.s, pc.ds.f)\r\nend\r\n\r\nfunction Ally.hpText(a)\r\nif a.dead then return \"사망\" end\r\nif a.hp > 0 then return a.hp .. \"/\" .. a.max end\r\nreturn \"0/\" .. a.max .. \" 쓰러짐\" .. ((a.ds and a.ds.f > 0) and (\" (실패 \" .. a.ds.f .. \")\") or \"\")\r\nend\r\n\r\n\r\n\r\n\r\n\r\n\r\nK.Fix = {}\r\n\r\n\r\n\r\nfunction K.Fix.snap(c, pc)\r\nlocal function eff(r) return r.dead and 0 or ((tonumber(r.hp) or 0) + (tonumber(r.thp) or 0)) end\r\nlocal s = { Player = eff(pc) }\r\nfor _, a in ipairs(Ally.list(pc)) do s[a.name] = eff(a) end\r\nfor name, u in pairs(c.units or {}) do\r\nif u.side == \"enemy\" then s[name] = tonumber(u.hp) or 0 end\r\nend\r\nreturn s\r\nend\r\n\r\n\r\nK.Fix.CLAIM = { ATTACK = { 2, 9, -1 }, SAVE = { 1, 9, -1 }, DAMAGE = { 1, 4, -1 }, HAZARD = { 1, 10, -1 }, HEAL = { 1, 5, 1 } }\r\n\r\n\r\n\r\nfunction K.Fix.note(tag, f, who, before, after, line)\r\nlocal view = Feat.cur.view\r\nlocal cl = K.Fix.CLAIM[tag]\r\nif tag == \"SAVE\" and line:find(\"^%[CHECK|\") then cl = nil end\r\nlocal tgt, amt\r\nif cl then\r\ntgt, amt = f[cl[1]], (tonumber(f[cl[2]]) or 0) * cl[3]\r\nelseif tag == \"TRAP\" then\r\n\r\ntgt, amt = who and who.name or (who == false and \"\" or \"Player\"), -(tonumber(f[9]) or 0)\r\nend\r\n\r\n\r\nif tgt and line then\r\nfor _, n in ipairs(K.Fix.KEEP) do\r\nif line:find(\"(\" .. n, 1, true) then Feat.cur.kept = Feat.cur.kept or {}; Feat.cur.kept[tgt] = n end\r\nend\r\nend\r\nfor name, h in pairs(after) do\r\nlocal b = before[name]\r\nif view[name] == nil then Feat.cur.view0[name] = b or h end\r\nif b == nil then\r\nif view[name] == nil then view[name] = h end\r\nelseif name == tgt then\r\nview[name] = math.max(0, (view[name] or b) + amt)\r\nelseif h ~= b then\r\nview[name] = math.max(0, (view[name] or b) + h - b)\r\nend\r\nend\r\nlocal res = line:match(\"result%->(%a+)\")\r\n\r\n\r\nif tag == \"DEATH\" then\r\nlocal said20 = tonumber((f[1] or \"\"):match(\"%d+\")) == 20\r\nlocal real20 = line:find(\"|HP 1]\", 1, true) ~= nil\r\nif said20 and not real20 then\r\nFeat.cur.flips[#Feat.cur.flips + 1] = \"death|norise|\" .. (res or f[2] or \"\")\r\nelseif real20 and not said20 then\r\nFeat.cur.flips[#Feat.cur.flips + 1] = \"death|rose\"\r\nelseif res then\r\nFeat.cur.flips[#Feat.cur.flips + 1] = \"death|\" .. res\r\nend\r\nreturn\r\nend\r\nif not res then return end\r\nif tag == \"ATTACK\" and (f[1] == \"Player\" or f[2] == \"Player\") then\r\nif ((f[6] or \"\"):lower() == \"miss\") ~= (res == \"miss\") then\r\nFeat.cur.flips[#Feat.cur.flips + 1] = \"attack|\" .. f[1] .. \"|\" .. f[2] .. \"|\" .. (res == \"miss\" and \"miss\" or \"hit\")\r\nend\r\nelseif (tag == \"SAVE\" or tag == \"HAZARD\") and (res == \"success\" or res == \"failure\")\r\nand K.monKind(f[1]) then\r\n\r\n\r\n\r\nlocal lr = line:find(\"(Legendary Resistance, \", 1, true) and \"lr\" or line:find(K.NO_LR, 1, true) and \"nolr\"\r\nor (res == \"success\" and line:find(\"Magic Resistance\", 1, true)) and \"mr\" or \"\"\r\nlocal x = \"save|\" .. f[1] .. \"|\" .. res\r\nif tag == \"HAZARD\" then x = x .. \"|\" .. lr .. \"|\" .. trim(f[2] or \"\") elseif lr ~= \"\" then x = x .. \"|\" .. lr end\r\nFeat.cur.flips[#Feat.cur.flips + 1] = x\r\nelse\r\nlocal what = line:match(\"^%[CHECK|([^|/]*)|\")\r\nif what then Feat.cur.flips[#Feat.cur.flips + 1] = \"check|\" .. what .. \"|\" .. res end\r\nend\r\nend\r\n\r\n\r\n\r\n\r\n\r\nK.Fix.KEEP = { \"Death Ward\", \"Relentless Endurance\", \"Relentless Rage\", \"Undead Fortitude\" }\r\nfunction K.Fix.lines(c, pc, text)\r\nlocal o, now, names = {}, K.Fix.snap(c, pc), {}\r\nfor name in pairs(Feat.cur.view or {}) do names[#names + 1] = name end\r\ntable.sort(names)\r\nlocal prose = text and tostring(text):gsub(\"%b[]\", \"\") or \"\"\r\nfor _, name in ipairs(names) do\r\nlocal ai, h = Feat.cur.view[name], now[name]\r\nlocal kept = Feat.cur.kept and Feat.cur.kept[name]\r\nlocal told = kept and h and h > 0 and (prose:find(kept, 1, true) or (NAMES_KO[kept] and prose:find(NAMES_KO[kept], 1, true)))\r\nif h and (ai <= 0) ~= (h <= 0) and not told then\r\nlocal r = name == \"Player\" and pc or Ally.find(pc, name) or (c.units or {})[name] or {}\r\nlocal was = (Feat.cur.view0[name] or 1) > 0\r\nlocal kind = h <= 0 and (was and \"down\" or \"still\") or (was and \"up\" or \"rose\")\r\no[#o + 1] = string.format(\"[FIX|%s|%s|%d/%d]\", kind, name, tonumber(r.hp) or h, tonumber(r.max) or h)\r\nend\r\nend\r\nfor _, x in ipairs(Feat.cur.flips or {}) do o[#o + 1] = \"[FIX|\" .. x .. \"]\" end\r\n\r\n\r\n\r\n\r\nif pc.dead and Feat.cur.killed and (Feat.cur.view0 or {}).Player and Feat.cur.view0.Player > 0 then\r\ntable.insert(o, 1, \"[FIX|dead|Player|\" .. (K.DEATH == \"harsh\" and \"harsh\" or \"massive\") .. \"]\")\r\nend\r\nwhile #o > 4 do table.remove(o) end\r\nreturn o\r\nend\r\n\r\n\r\n\r\nfunction K.pcRefused(s)\r\nlocal why\r\ns = tostring(s or \"\")\r\nfor body in s:gmatch(\"%[PC|([^%]]*)%]\") do\r\nlocal r = body:match(\"|bad:([^|]*)|%-$\")\r\nif r then why = r end\r\nend\r\nfor r in s:gmatch(\"%[PC|[^%]]*%] %(Lua refused: ([^\\n]*)%)\") do why = r end\r\nif not why then return nil end\r\nreturn \"[CHARACTER NOT MADE] Lua refused your last reply's PC tag (\" .. why .. \"), so no character exists yet, whatever that reply told the user.\"\r\n.. \" Say so in one OOC sentence, then write the PC tag again with that fixed (a SPELLS tag after it only for a class with spells at that level), unless the user now asks for something else.\"\r\nend\r\n\r\nfunction K.Fix.request(s)\r\nlocal o = {}\r\nfor body in tostring(s or \"\"):gmatch(\"%[FIX|([^%]]*)%]\") do\r\nlocal f = split(body)\r\nif f[1] == \"up\" then\r\no[#o + 1] = (f[2] or \"?\") .. \" is still standing at \" .. (f[3] or \"?\") .. \" HP, not down\"\r\nelseif f[1] == \"down\" then\r\no[#o + 1] = (f[2] or \"?\") .. \" is down (\" .. (f[3] or \"0\") .. \" HP)\"\r\nelseif f[1] == \"still\" then\r\no[#o + 1] = (f[2] or \"?\") .. \" is still down (\" .. (f[3] or \"0\") .. \" HP): what was to bring them up did not take\"\r\nelseif f[1] == \"rose\" then\r\no[#o + 1] = (f[2] or \"?\") .. \" is back up at \" .. (f[3] or \"?\") .. \" HP\"\r\nelseif f[1] == \"attack\" then\r\no[#o + 1] = (f[2] or \"?\") .. \"'s attack on \" .. (f[3] or \"?\") .. (f[4] == \"miss\" and \" missed\" or \" hit\")\r\nelseif f[1] == \"check\" then\r\no[#o + 1] = \"Player's \" .. (f[2] or \"check\") .. \" was a \" .. (f[3] or \"?\")\r\nelseif f[1] == \"save\" then\r\nlocal what = (f[5] or \"\") ~= \"\" and f[5] or \"the spell\"\r\no[#o + 1] = (f[2] or \"?\") .. \"'s save against \" .. what .. \" was a \" .. (f[3] or \"?\")\r\n.. (f[4] == \"lr\" and \" (its Legendary Resistance turned the failure)\" or f[4] == \"nolr\" and \" (no Legendary Resistance against damage alone)\"\r\nor f[4] == \"mr\" and \" (its Magic Resistance)\" or \"\")\r\n.. \": \" .. what .. (f[3] == \"failure\" and \" did all it does on a failure\" or \" did only what it does on a success\")\r\nelseif f[1] == \"insp\" then\r\no[#o + 1] = \"Lua spent Player's Heroic Inspiration on the death saving throw that would have been the third failure: \"\r\n.. (f[2] or \"?\") .. \" rerolled to \" .. (f[3] or \"?\") .. \", \" .. (f[4] == \"rose\" and \"a 20, Player woke up with 1 HP\"\r\nor f[4] == \"success\" and \"a success, Player is still alive (dying)\" or f[4] == \"dead\" and \"still a failure, Player is dead\" or \"a failure\")\r\n.. \"; the story after it follows this\"\r\nelseif f[1] == \"absent\" then\r\no[#o + 1] = (f[2] or \"?\") .. \" is not in this fight: Lua left it out (over the High budget). It never joined; leave it out of the story from here\"\r\nelseif f[1] == \"dead\" then\r\no[#o + 1] = \"Player died in that reply (\" .. (f[3] == \"massive\" and \"massive damage: the damage beyond Player's HP was Player's HP maximum or more\" or \"0 HP under the harsh rule\")\r\n.. \"); what the story told after it (waking up, being robbed, going on) did not happen. Player is dead\"\r\nelseif f[1] == \"death\" and f[2] == \"norise\" then\r\no[#o + 1] = \"Player did not wake up: the death saving throw was not a 20 (a \" .. (f[3] or \"?\") .. \"), so Player is still down at 0 HP\"\r\nelseif f[1] == \"death\" and f[2] == \"rose\" then\r\no[#o + 1] = \"Player woke up with 1 HP: the death saving throw was a natural 20\"\r\nelseif f[1] == \"death\" then\r\no[#o + 1] = \"Player's death saving throw was a \" .. (f[2] or \"?\")\r\nend\r\nend\r\n\r\nfor who, spell in tostring(s or \"\"):gmatch(\"%[CONCSAVE|([^|%]]*)|([^|%]]*)|[^%]]*|lost%]\") do\r\no[#o + 1] = who .. \"'s Concentration on \" .. spell .. \" broke (a failed Constitution save after damage), so the spell has ended\"\r\n.. \" (what it did in that reply still counted)\"\r\nend\r\nif #o == 0 then return nil end\r\nreturn \"[LUA CORRECTION] Lua's dice and rules ended your last reply differently from its story: \" .. table.concat(o, \"; \")\r\n.. \". GAME STATE and COMBAT STATUS have the real numbers, and the user saw this note under your reply. Open this reply\"\r\n.. \" with a sentence or two that shows it in the story, answer the user's message even if it assumed otherwise, then go on.\"\r\nend\r\n\r\n\r\n\r\n\r\n\r\nfunction K.concSaves(pc, before, after, line)\r\nlocal recs = { { \"Player\", pc } }\r\nfor _, a in ipairs(Ally.list(pc)) do recs[#recs + 1] = { a.name, a } end\r\nfor _, x in ipairs(recs) do\r\nlocal name, r = x[1], x[2]\r\nlocal b, h = before[name], after[name]\r\n\r\nlocal keep = false\r\nif type(r.conc) == \"table\" then\r\nAlly.run(pc, r, function()\r\nfor _, e in ipairs(Feat.fxOf(SHEET, \"conc_keep\")) do\r\nfor _, n in ipairs(e.spells or {}) do if n == r.conc.name then keep = true end end\r\nend\r\nend)\r\nend\r\nif not keep and type(r.conc) == \"table\" and r.conc.name and not r.conc.lost and b and h and h < b and (tonumber(r.hp) or 0) > 0 and not r.dead then\r\nlocal dc = math.min(30, math.max(10, math.floor((b - h) / 2)))\r\nlocal bonus = Ally.run(pc, r, function() return bonusFor(\"Constitution save\") - Cond.fx(r).pen end)\r\nlocal d = K.d(20)\r\nlocal fl = Ally.run(pc, r, function() return K.d20Floor(SHEET, \"conc\", \"Constitution\") end)\r\nif fl and d < fl then d = fl end\r\nlocal kept = d + bonus >= dc\r\nline = line .. string.format(\"\\n[CONCSAVE|%s|%s|%d|%+d|%d|%s]\", name, r.conc.name, d, bonus, dc, kept and \"kept\" or \"lost\")\r\n\r\n\r\n\r\nif not kept then r.conc.lost = true end\r\nend\r\nend\r\nreturn line\r\nend\r\n\r\n\r\nfunction K.josa(word, final, open)\r\nlocal cp\r\nfor _, x in utf8.codes(tostring(word or \"\")) do cp = x end\r\nif not cp then return final end\r\nif cp >= 0xAC00 and cp <= 0xD7A3 then return (cp - 0xAC00) % 28 ~= 0 and final or open end\r\nif cp >= 48 and cp <= 57 then\r\nreturn ({ [0] = true, true, false, true, false, false, true, true, true, false })[cp - 48] and final or open\r\nend\r\nreturn final\r\nend\r\n\r\n\r\n\r\n\r\n\r\nlocal function hpLine(c, pc)\r\nlocal order, mine, foes, fallen = {}, {}, {}, {}\r\nfor _, name in ipairs(c.order) do\r\nlocal u = c.units[name]\r\n\r\nlocal deadFoe = u.side ~= \"pc\" and u.side ~= \"ally\" and u.hp <= 0 and not K.foeUp(u)\r\nif not deadFoe then order[#order + 1] = name .. \" (\" .. u.init .. \")\" end\r\nif u.side == \"friend\" then\r\nmine[#mine + 1] = name .. \" \" .. u.hp .. \"/\" .. u.max\r\nelseif u.side == \"pc\" then\r\ntable.insert(mine, 1, name .. \" \" .. pcHpText(pc))\r\nelseif u.side == \"ally\" then\r\nlocal a = Ally.find(pc, u.ally)\r\nmine[#mine + 1] = name .. \" \" .. (a and Ally.hpText(a) or \"-\")\r\nelseif deadFoe then\r\nfallen[#fallen + 1] = name\r\nelse\r\nfoes[#foes + 1] = name .. \" \" .. u.hp .. \"/\" .. u.max\r\nend\r\nend\r\nif #fallen > 0 then foes[#foes + 1] = \"✝ \" .. table.concat(fallen, \", \") end\r\nreturn \"[HP|\" .. table.concat(order, \" ▶ \") .. \"|\" .. table.concat(mine, \" · \") .. \" ‖ \" .. table.concat(foes, \" · \")\r\n.. (c.active and \"\" or \" · 전투 종료\") .. \"]\"\r\nend\r\n\r\nlocal function moneyKo(cp)\r\nreturn (moneyText(cp):gsub(\"(%d+) gp\", \"금화 %1\"):gsub(\"(%d+) sp\", \"· 은화 %1\"):gsub(\"(%d+) cp\", \"· 동화 %1\")\r\n:gsub(\"^· \", \"\"))\r\nend\r\n\r\nlocal function koName(n)\r\nif n == \"MP\" then return K.MP.name() end\r\nlocal slot = n:match(\"^Spell Slot (%d)$\")\r\nif slot then return slot .. \"레벨 슬롯\" end\r\nlocal ps = n:match(\"^Pact Slot (%d)$\")\r\nif ps then return \"계약 \" .. ps .. \"레벨 슬롯\" end\r\nlocal free = n:match(\"^(.-) %(free%)$\")\r\nif free then return (NAMES_KO[free] or free) .. \" (무료)\" end\r\nlocal arc, al = n:match(\"^(.-) %((%d)%)$\")\r\nif arc and NAMES_KO[arc] then return NAMES_KO[arc] .. \" (\" .. al .. \"레벨)\" end\r\nif NAMES_KO[n] then return NAMES_KO[n] end\r\nlocal base, part = n:match(\"^(.-) %((.-)%)$\")\r\nif base and NAMES_KO[base] and NAMES_KO[part] then return NAMES_KO[base] .. \" (\" .. NAMES_KO[part] .. \")\" end\r\nreturn K.MI.ko(n) or n\r\nend\r\n\r\nfunction K.clsKo(sh)\r\nif type(sh) ~= \"table\" then return \"\" end\r\nreturn #K.mcList(sh) > 0 and K.mcText(sh, koName) or koName(sh.class)\r\nend\r\nlocal function dots(n) return string.rep(\"●\", n) .. string.rep(\"○\", 3 - n) end\r\nlocal function pct(a, b) return (b and b > 0) and math.max(0, math.min(100, math.floor(a * 100 / b))) or 100 end\r\n\r\n\r\nlocal function gearText(pc, wrap)\r\nwrap = wrap or function(_, label) return label end\r\nlocal eq = pc.equip or {}\r\nlocal worn, hands = {}, {}\r\n\r\nlocal function lab(n)\r\nlocal l = type(pc.loot) == \"table\" and pc.loot[n]\r\nreturn koName(n) .. ((type(l) == \"table\" and l.attuned) and \" ✧\" or \"\")\r\nend\r\n\r\nlocal function hurt(n, armor)\r\nlocal x = type(pc.wear) == \"table\" and tonumber(pc.wear[n])\r\nreturn x and string.format(armor and \" (방어도 -%d)\" or \" (명중 -%d)\", x) or \"\"\r\nend\r\nif eq.armor then worn[#worn + 1] = wrap(eq.armor, lab(eq.armor), nil, pc) .. hurt(eq.armor, true) end\r\nif K.isShield(pc, eq.off) then worn[#worn + 1] = wrap(eq.off, lab(eq.off), nil, pc) .. hurt(eq.off, true) end\r\nlocal mw = eq.main and gearOf(pc, eq.main)\r\nif eq.main then\r\nhands[#hands + 1] = wrap(eq.main, lab(eq.main), nil, pc) .. ((mw and mw.two) and \" (양손)\" or (mw and mw.vers and not eq.off) and \" (한손/양손)\" or \"\")\r\n.. hurt(eq.main)\r\nend\r\nif eq.off and not K.isShield(pc, eq.off) then hands[#hands + 1] = wrap(eq.off, lab(eq.off), nil, pc) .. hurt(eq.off) end\r\n\r\nlocal hold\r\nlocal ow = eq.off and not K.isShield(pc, eq.off) and gearOf(pc, eq.off)\r\nif mw and ow then\r\n\r\n\r\nlocal nick = ow.mastery == \"Nick\" and type(SHEET.picks) == \"table\" and type(SHEET.picks.mastery) == \"table\"\r\nand table.concat(SHEET.picks.mastery, \",\"):find(eq.off, 1, true)\r\nhold = \"쌍수: 양손에 경량 무기를 하나씩 들었습니다. 공격 행동으로 주 무기를 휘두른 뒤 추가 행동으로 보조 손 무기로 한 번 더 공격합니다.\"\r\n.. ((type(SHEET.picks) == \"table\" and SHEET.picks.style == \"Two-Weapon Fighting\") and \" 쌍수 전투술 덕분에 보조 손 피해에도 능력치 수정치가 더해집니다.\"\r\nor \" 보조 손 공격은 피해에 능력치 수정치를 더하지 않습니다 (전투 유파 쌍수 전투술이면 더합니다).\")\r\n.. (nick and \" 잇기(Nick) 통달이 있어서 보조 손 공격을 추가 행동 없이 공격 행동 안에서 할 수 있습니다.\" or \"\")\r\nelseif mw and mw.two then\r\nhold = \"양손 무기: 두 손으로 쥐어야 합니다. 방패나 다른 무기는 못 듭니다.\"\r\nelseif mw and mw.vers and not eq.off then\r\nhold = \"다용도 무기: 한 손이 비어 있어서 두 손으로 쥐면 피해 주사위가 커집니다 (공격 목록의 \\\"양손\\\").\"\r\nelseif K.isShield(pc, eq.off) then\r\nlocal _, _, splus = gearOf(pc, eq.off)\r\nhold = \"방패: 한 손에 무기, 다른 손에 방패. 방어도 +\" .. (2 + (splus or 0)) .. \".\"\r\nelseif mw then\r\nhold = \"한 손 무기: 다른 손이 비어 있습니다.\"\r\nend\r\nlocal handLabel = hold and wrap and wrap(\"__hands\", \"손\", hold) or \"손\"\r\nlocal equip = (#worn > 0 and table.concat(worn, \", \") or \"갑옷 없음\") .. \" (방어도 \" .. pcStats(pc).ac .. \") · \" .. handLabel .. \": \"\r\n.. (#hands > 0 and table.concat(hands, \", \") or \"빈손\")\r\n.. ((pc.pactW and Feat.invoked(SHEET, \"Pact of the Blade\")) and (\" · 계약 무기: \" .. lab(pc.pactW)) or \"\")\r\nlocal rows = {}\r\nfor name, n in pairs(pc.items) do\r\nlocal left = n - equippedCount(eq, name)\r\nif left > 0 then rows[#rows + 1] = { lab(name), name, left } end\r\nend\r\ntable.sort(rows, function(a, b) return a[1] < b[1] end)\r\nlocal pack = {}\r\nfor _, r in ipairs(rows) do\r\npack[#pack + 1] = wrap(r[2], r[1], nil, pc) .. (r[3] > 1 and (\" ×\" .. r[3]) or \"\")\r\n.. (r[2] == K.KIT and (\" (남은 횟수 \" .. K.kitLeft(pc) .. \")\") or \"\")\r\nend\r\nreturn equip, #pack > 0 and table.concat(pack, \", \") or \"비어 있음\"\r\nend\r\n\r\n\r\n\r\nlocal function statusLine(pc, clock)\r\nlocal p = clockParts(clock.min)\r\nlocal alert, kind = \"\", \"\"\r\nif pc.dead then\r\nalert, kind = \"사망\", \"bad\"\r\nelseif pc.hp <= 0 then\r\nkind = \"bad\"\r\nalert = pc.stable and \"쓰러짐 · 안정\"\r\nor (\"쓰러짐 · 죽음 내성 성공 \" .. dots(pc.ds.s) .. \" · 실패 \" .. dots(math.min(3, pc.ds.f)))\r\nelseif xpNext(pc) and pc.xp >= xpNext(pc) then\r\nalert, kind = \"레벨 업 가능\", \"up\"\r\nend\r\n\r\nlocal cs = {}\r\nfor _, name in ipairs(Cond.active(pc)) do cs[#cs + 1] = koName(name) end\r\nif (pc.exh or 0) > 0 then cs[#cs + 1] = koName(\"Exhaustion\") .. \" \" .. pc.exh end\r\nif (tonumber(pc.ordeal) or 0) > 0 then cs[#cs + 1] = \"부활의 시련 -\" .. pc.ordeal end\r\nif pc.taxed then cs[#cs + 1] = \"부활의 대가 · 주문 불가\" end\r\nif #cs > 0 and not pc.dead then\r\nalert = (alert ~= \"\" and (alert .. \" · \") or \"\") .. table.concat(cs, \" · \")\r\nif kind == \"\" then kind = \"bad\" end\r\nend\r\nlocal equip, pack = gearText(pc)\r\nlocal res = { not K.LITE and string.format(\"생명력 주사위 %d/%d\", pc.hd, pc.level) or nil }\r\nlocal names = {}\r\nfor name in pairs(PC.res) do if K.MP.shown(name) then names[#names + 1] = name end end\r\ntable.sort(names)\r\nfor _, name in ipairs(names) do res[#res + 1] = string.format(\"%s %d/%d\", koName(name), pc.res[name] or 0, PC.res[name].max) end\r\nif K.AR.on() then\r\nlocal ov = K.AR.overHard(K.AR.st(pc), pc)\r\nres[#res + 1] = string.format(\"흥분도 %d/%d · 억제 %+d%s\", tonumber(K.AR.st(pc).cur) or 0, K.AR.max(pc, pc), K.AR.inhib(pc, pc), ov > 0 and (\" · 과자극 \" .. ov .. \"/6\") or \"\")\r\nend\r\nreturn string.format(\"[STATUS|모험 %d일째 · %s|%d월 %d일 · Lv %d %s|%s|%s|%d / %d%s|%d|%s|%d|%s|%s|%s|%s|%s]\",\r\np.day, p.ko, p.month, p.date, pc.level, K.clsKo(SHEET), alert, kind,\r\npc.hp, pc.max, (tonumber(pc.thp) or 0) > 0 and (\" (+\" .. pc.thp .. \")\") or \"\", pct(pc.hp, pc.max),\r\nxpNext(pc) and (pc.xp .. \" / \" .. xpNext(pc)) or tostring(pc.xp), pct(pc.xp, xpNext(pc)),\r\nequip, table.concat(res, \" · \"), moneyKo(pc.cp), pack, (tostring(pc.placeName or \"\"):gsub(\"[|%]]\", \"\")))\r\nend\r\n\r\n\r\n\r\nK.DELTA_MAX = 8\r\nK.BAD_LOG_MAX = 20\r\nlocal function turnDelta(p0, p)\r\nlocal d = {}\r\nlocal function add(kind, text) d[#d + 1] = { kind, text } end\r\nlocal names = {}\r\nfor n in pairs(p0.items or {}) do names[n] = true end\r\nfor n in pairs(p.items or {}) do names[n] = true end\r\nlocal sorted = {}\r\nfor n in pairs(names) do sorted[#sorted + 1] = n end\r\ntable.sort(sorted)\r\nfor _, n in ipairs(sorted) do\r\nlocal diff = (p.items[n] or 0) - ((p0.items or {})[n] or 0)\r\nif diff ~= 0 then\r\nadd(diff > 0 and \"up\" or \"down\", (diff > 0 and \"+\" or \"−\") .. koName(n) .. (math.abs(diff) > 1 and (\" ×\" .. math.abs(diff)) or \"\"))\r\nend\r\nend\r\nlocal dc = (p.cp or 0) - (p0.cp or 0)\r\nif dc ~= 0 then add(dc > 0 and \"up\" or \"down\", (dc > 0 and \"+\" or \"−\") .. moneyKo(math.abs(dc))) end\r\nlocal e0, e = p0.equip or {}, p.equip or {}\r\nfor _, slot in ipairs({ \"armor\", \"main\", \"off\" }) do\r\nif e[slot] ~= e0[slot] then\r\nif e0[slot] then add(\"\", \"해제 \" .. koName(e0[slot])) end\r\nif e[slot] then add(\"\", \"장착 \" .. koName(e[slot])) end\r\nend\r\nend\r\nif p.dead and not p0.dead then\r\nadd(\"down\", \"사망\")\r\nelseif p.hp <= 0 and p0.hp > 0 then\r\nadd(\"down\", \"쓰러짐\")\r\nelseif p.hp ~= p0.hp then\r\nadd(p.hp > p0.hp and \"up\" or \"down\", string.format(\"생명력 %+d\", p.hp - p0.hp))\r\nend\r\nif p.xp ~= p0.xp then add(\"up\", string.format(\"경험치 %+d\", p.xp - p0.xp)) end\r\n\r\nlocal was = {}\r\nfor _, a in ipairs(Ally.list(p0)) do was[a.name] = a end\r\nfor _, a in ipairs(Ally.list(p)) do\r\nlocal o = was[a.name]\r\nif not o then\r\nadd(\"up\", \"+동료 \" .. a.name)\r\nelseif a.dead and not o.dead then\r\nadd(\"down\", a.name .. \" 사망\")\r\nelseif a.hp <= 0 and o.hp > 0 then\r\nadd(\"down\", a.name .. \" 쓰러짐\")\r\nelseif a.hp ~= o.hp then\r\nadd(a.hp > o.hp and \"up\" or \"down\", string.format(\"%s %+d\", a.name, a.hp - o.hp))\r\nend\r\nwas[a.name] = nil\r\nend\r\nfor _, a in ipairs(Ally.list(p0)) do\r\nif was[a.name] then add(\"down\", \"−동료 \" .. a.name) end\r\nend\r\nlocal c0, c1 = type(p0.cond) == \"table\" and p0.cond or {}, type(p.cond) == \"table\" and p.cond or {}\r\nlocal cn = {}\r\nfor n in pairs(c0) do cn[n] = true end\r\nfor n in pairs(c1) do cn[n] = true end\r\nlocal cl = {}\r\nfor n in pairs(cn) do cl[#cl + 1] = n end\r\ntable.sort(cl)\r\nfor _, n in ipairs(cl) do\r\nif c1[n] and not c0[n] then add(\"down\", \"+\" .. koName(n)) elseif c0[n] and not c1[n] then add(\"up\", \"−\" .. koName(n)) end\r\nend\r\nif (p.exh or 0) ~= (p0.exh or 0) then\r\nadd((p.exh or 0) > (p0.exh or 0) and \"down\" or \"up\", string.format(\"%s %+d\", koName(\"Exhaustion\"), (p.exh or 0) - (p0.exh or 0)))\r\nend\r\nif p.hd ~= p0.hd and not K.LITE then add(p.hd > p0.hd and \"up\" or \"down\", string.format(\"생명력 주사위 %+d\", p.hd - p0.hd)) end\r\nlocal rn = {}\r\nfor n in pairs(p.res or {}) do rn[#rn + 1] = n end\r\ntable.sort(rn)\r\nfor _, n in ipairs(rn) do\r\nlocal diff = (p.res[n] or 0) - ((p0.res or {})[n] or 0)\r\nif diff ~= 0 then add(diff > 0 and \"up\" or \"down\", string.format(\"%s %+d\", koName(n), diff)) end\r\nend\r\nwhile #d > K.DELTA_MAX do table.remove(d) end\r\nreturn d\r\nend\r\n\r\nonOutput = async(function(id)\r\nlocal t0 = clockNow()\r\nK.EN = K.LITE and K.En.on(id) or nil\r\nlocal ok, err = pcall(function()\r\nlocal last = getChat(id, -1)\r\nif not last or last.role ~= \"char\" then return end\r\npcall(K.packs, id)\r\n\r\nlocal miss = K.missingFresh(id)\r\nK.LOCKED = miss and true or nil\r\nif miss then\r\nsetChatVar(id, \"dnd_lua_error\", K.lockMsg(miss, \"이번 답을 처리하지 않았습니다. 모듈을 다시 켜고 다시 생성해 주십시오.\"))\r\nreturn\r\nend\r\nK.CW = K.combatW(id)\r\nK.CHK_D, K.FIGHT_D = K.checkD(id), K.fightD(id)\r\nK.PCAP = math.max(0, math.min(Ally.MAX, tonumber(getChatVar(id, \"dnd_party_want\")) or Ally.MAX))\r\n\r\n\r\n\r\ndo\r\nlocal okt, sec = pcall(os.time)\r\nlocal h, s = 0, tostring(last.data or \"\")\r\nfor i = 1, #s, 97 do h = (h * 31 + s:byte(i)) % 2147483647 end\r\npcall(math.randomseed, ((okt and tonumber(sec)) or 0) + getChatLength(id) * 7919 + h)\r\nK.rseed(((okt and tonumber(sec)) or 0) * 31 + getChatLength(id) * 7919 + h)\r\nend\r\n\r\n\r\n\r\nlocal len = getChatLength(id)\r\nK.REPLY = len\r\nlocal prevKey = Seed.at(id, len - 2)\r\nlocal base = prevKey and Seed.read(id, prevKey)\r\nif base then\r\nbase.len = len\r\nelse\r\nbase = getState(id, \"dnd_base\")\r\nend\r\nif not Seed.ok(base) or base.len ~= len then\r\nlocal sh0 = loadSheet(id)\r\napplySheet(sh0)\r\nbase = { len = len, sheet = sh0, pc = loadPC(id), combat = loadCombat(id), clock = loadClock(id) }\r\nsetState(id, \"dnd_base\", base)\r\nend\r\n\r\nlocal missB = K.missingIn(base.sheet, base.pc)\r\nif missB then\r\nK.LOCKED = true\r\nsetChatVar(id, \"dnd_lua_error\", K.lockMsg(missB, \"이번 답을 처리하지 않았습니다. 모듈을 다시 켜고 다시 생성해 주십시오.\"))\r\nreturn\r\nend\r\nlocal sheet = (type(base.sheet) == \"table\" and type(base.sheet.scores) == \"table\") and base.sheet or loadSheet(id)\r\napplySheet(sheet)\r\nlocal pc = K.MP.wrapAll(base.pc)\r\n\r\n\r\nfor k, v in pairs(newPC()) do if pc[k] == nil then pc[k] = v end end\r\nFeat.fillRes(pc)\r\nK.DEATH = Feat.deathRule(id)\r\nFeat.gentleFix(pc)\r\nlocal pc0 = deepCopy(pc)\r\nCond.cur = pc\r\nK.partyFx(pc, sheet)\r\nFeat.cur = { savage = {}, dodge = {}, spent = {}, cleave = {}, wear = {}, view = {}, view0 = {}, flips = {}, blessed = {} }\r\nFeat.cur.snap = K.snapParty(pc)\r\nSpell.cur = nil\r\nlocal newChar = false\r\nlocal rolled = getState(id, \"dnd_rolled\")\r\nlocal c = base.combat\r\nc.order = c.order or {}\r\nc.units = c.units or {}\r\nK.regSummons(pc, c)\r\nFeat.cur.cover0 = {}\r\nfor name, u in pairs(c.units) do Feat.cur.cover0[name] = K.coverOf(u) end\r\nlocal wasActive = c.active\r\n\r\n\r\n\r\nif K.DEATH == \"gentle\" and not wasActive and K.partyStands(pc) then\r\nif not pc.dead and pc.hp <= 0 then pc.hp, pc.wake, pc.stable, pc.ds = 1, nil, false, { s = 0, f = 0 } end\r\nfor _, a in ipairs(Ally.list(pc)) do\r\nif not a.dead and (tonumber(a.hp) or 0) <= 0 then a.hp, a.wake, a.ds = 1, nil, { s = 0, f = 0 } end\r\nend\r\nend\r\nlocal clock = (type(base.clock) == \"table\" and base.clock.min) and base.clock or loadClock(id)\r\nK.replyClock = clock.min\r\nK.clockRef = clock\r\nlocal tctx = { added = {}, paid = false, clock = clock }\r\n\r\nlocal um = getChat(id, -2)\r\nif um and um.role == \"user\" then\r\nlocal st, _, nsh, npc = K.Form.apply(tostring(um.data or \"\"), getState(id, \"dnd_rolled\"), c.active)\r\nif st == \"ok\" then\r\nnpc.allies = pc.allies\r\nsheet = nsh\r\nfor k in pairs(pc) do pc[k] = nil end\r\nfor k, v in pairs(npc) do pc[k] = v end\r\napplySheet(sheet)\r\nnewChar = true\r\nend\r\n\r\nlocal stc, _, csh, cpc = K.CharCode.apply(tostring(um.data or \"\"), c.active, sheet, pc, clock.min)\r\nif stc == \"ok\" then\r\nsheet = csh\r\nfor k in pairs(pc) do pc[k] = nil end\r\nfor k, v in pairs(cpc) do pc[k] = v end\r\napplySheet(sheet)\r\nnewChar = true\r\nend\r\nend\r\n\r\n\r\nlocal prevReply = getChat(id, -3)\r\nif Shop.isLine(prevReply) then prevReply = getChat(id, -4) end\r\nlocal pick = um and um.role == \"user\" and prevReply and prevReply.role ~= \"user\" and K.optPick(um.data, prevReply.data)\r\nK.OPTLOCK = (pick and K.optLocks(pick)) and { kind = pick.kind, dc = pick.dc } or nil\r\n\r\nlocal pools = getState(id, \"dnd_pool\") or {}\r\npools.d20 = pools.d20 or {}\r\nlocal cur = { d20 = 0 }\r\nlocal okN, badN, n = 0, 0, 0\r\nlocal bads = {}\r\nlocal band = xpNext(pc) and (xpNext(pc) - XP_LEVEL[pc.level]) or 0\r\nlocal budget = { left = math.floor(band / 4) }\r\n\r\n\r\nlocal text = (last.data or \"\")\r\n:gsub(\"\\n?%[FIX|[^%]]*%]\", \"\")\r\n:gsub(\"\\n?%[CONCSAVE|[^%]]*%]\", \"\")\r\n:gsub(\"\\n?%[HP|[^%]]*%]\", \"\")\r\n:gsub(\"\\n?%[STATUS|[^%]]*%]\", \"\")\r\n:gsub(\"\\n?%[XP|[^%]|]*|[^%]|]*|auto|[^%]]*%]\", \"\")\r\n:gsub(\"\\n?<!%-%-dseed:%w+%-%->\", \"\")\r\n:gsub(\"\\n?%[ROUND|[^%]]*%]\", \"\")\r\n:gsub(\"\\n?%[CONC|end[^%]]*|auto|[^%]]*%]\", \"\")\r\n\r\n\r\nlocal held = {}\r\nfor _, t in ipairs({ \"Thoughts\", \"thoughts\", \"Thinking\", \"thinking\", \"think\", \"Think\" }) do\r\ntext = text:gsub(\"<\" .. t .. \">.-</\" .. t .. \">\", function(s)\r\nheld[#held + 1] = s\r\nreturn \"\\2\" .. #held .. \"\\2\"\r\nend)\r\nend\r\ntext = K.cutDraft(text)\r\ntext = K.cutTaken(text)\r\ntext = K.spellNames(text)\r\ntext = K.holdQuoted(text, held)\r\ntext = K.cutLeak(text)\r\ntext = K.gmFix(text)\r\n\r\n\r\nlocal paid = {}\r\nfor num, rest in text:gmatch(\"%[QUEST|done|(#?%d*)([^%]]*)%]\") do\r\nlocal x = Quest.find(Quest.load(pc), num)\r\n\r\nlocal ending = rest:match(\"^|%s*(%a+)\") or ((x and x.at > #x.stages) and \"success\" or \"\")\r\nif x and (ending == \"success\" or ending == \"partial\") then\r\npaid[Quest.payLeft(x, ending)] = true\r\nend\r\nend\r\n\r\nfor gp in text:gmatch(\"%[QUEST|advance|[^%]]-(%d+)%s*gp\") do paid[tonumber(gp)] = true end\r\nlocal ooc = getChatVar(id, \"dnd_ooc\") == \"1\"\r\nlocal ev = {}\r\nlocal deferred = {}\r\nlocal okp, persona = pcall(getPersonaName, id)\r\nif not okp or type(persona) ~= \"string\" then persona = nil end\r\n\r\n\r\nlocal seenRoll = {}\r\nK.partyPc = pc\r\nK.MI.syncAll(pc, sheet)\r\nK.UNDERWATER = c.active and c.underwater or nil\r\ntext = K.inspMerge(text)\r\n\r\n\r\nlocal tagList, tagAt = {}, 0\r\nfor tg, rs in text:gmatch(\"%[([%u_]+)|?([^%]]*)%]\") do tagList[#tagList + 1] = { tg, rs } end\r\nK.planNow = K.planScan(tagList)\r\nlocal preLine = {}\r\nlocal function handleTag(tag, rest)\r\nK.MAXDICE = nil\r\nK.diceLog, K.d20Log = {}, nil\r\nK.boomNow = nil\r\nif ooc then return nil end\r\n\r\n\r\nif not rest:find(\"|bad:\", 1, true) then rest = rest:gsub(\"|%s*ok%s*$\", \"\") end\r\nif K.ROLL_TAGS[tag] and not rest:find(\"|ok|\", 1, true) and not rest:find(\"|bad:\", 1, true) then\r\nif seenRoll[tag .. \"|\" .. rest] and not K.nextRoll(tag, rest, pools, cur) then\r\nn = n + 1\r\nbadN = badN + 1\r\nlocal line = \"[\" .. tag .. \"|\" .. rest .. \"|bad:the same tag twice, ignored|\" .. (tag == \"CHECK\" and \"0\" or \"-\") .. \"]\"\r\nif #bads < 8 then bads[#bads + 1] = line end\r\nreturn line\r\nend\r\nseenRoll[tag .. \"|\" .. rest] = true\r\nend\r\nif tag == \"PC\" and not rest:find(\"%a\") then return nil end\r\nK.roundNow, K.fightNow, K.curC = tonumber(c.round) or 1, c.active, c\r\nK.curPc = pc or K.curPc\r\nlocal before = K.Fix.snap(c, pc)\r\nlocal roundAct0, roundLast0 = c.active, c.last\r\nlocal f = split(rest)\r\nif tag == \"CHECK\" or tag == \"PASSIVE\" or tag == \"EQUIP\" or tag == \"UNEQUIP\" or tag == \"USE\" or tag == \"BUY\" or tag == \"SELL\" then\r\nf[1] = Canon.name(f[1])\r\nelseif tag == \"ATTACK\" then\r\n\r\n\r\nlocal judged = false\r\nfor _, v in ipairs(f) do if v == \"ok\" or v:match(\"^bad:\") then judged = true end end\r\n\r\nlocal function tgtOk(v)\r\nlocal n = Canon.actor(v or \"\", persona)\r\nreturn c.units[n] ~= nil or n == \"Player\" or Ally.find(pc, n) ~= nil\r\nor (type(pc.scene) == \"table\" and type(pc.scene.units) == \"table\" and pc.scene.units[n] ~= nil)\r\nend\r\nK.atkNamed = nil\r\nif judged then\r\n\r\nfor nm in tostring(f[#f] or \"\"):gmatch(\"%(([^()]+)%)\") do\r\nlocal cn = Canon.name(trim(nm))\r\nlocal m = SPELLS[cn] and SPELLS[cn].m\r\nif type(m) == \"table\" and m.kind == \"attack\" and not m.damage and m.foe_cond then K.atkNamed = cn end\r\nend\r\nend\r\nif not judged then\r\n\r\n\r\n\r\nif f[2] and SPELLS[Canon.name(f[2])] and not c.units[Canon.actor(f[2], persona)] and (f[3] or \"\"):find(\"%d\") and not tgtOk(f[3]) then\r\nlocal only\r\nfor name, u in pairs(c.units or {}) do\r\nif u.side == \"enemy\" and (u.hp or 0) > 0 then only = (only == nil) and name or false end\r\nend\r\nif only then\r\nf[2] = only\r\nif #f == 8 and (f[6] or \"\"):match(\"^%d+[dD]%d\") then table.insert(f, 6, \"?\") end\r\nend\r\nend\r\nif #f >= 9 and f[3] and not tgtOk(f[2]) and tgtOk(f[3]) then K.atkNamed = Canon.name(trim(f[2] or \"\")); table.remove(f, 2) end\r\nif #f == 8 and ({ hit = true, miss = true, crit = true })[f[5]] then table.insert(f, 5, \"?\") end\r\n\r\nif f[7] and f[7]:match(\"^%d+[dD]1$\") then f[7] = tostring(tonumber(f[7]:match(\"^(%d+)\"))) end\r\n\r\nif #f == 8 and f[6] == \"miss\" then\r\nif (f[8] or \"\"):match(\"^%d+$\") then table.insert(f, 8, \"-\") else f[9] = \"0\" end\r\nend\r\n\r\nif #f == 8 and (f[6] == \"hit\" or f[6] == \"crit\") and (f[7] or \"\"):find(\"%d[dD]%d\") then f[9] = \"?\" end\r\n\r\n\r\nif #f == 7 and (f[4] or \"\"):match(\"^[%+%-]%d+$\") and (f[5] or \"\"):match(\"^[%d%s,/]+$\") and (f[5] or \"\"):find(\"%d\")\r\nand (f[7] or \"\"):match(\"^%d+$\") then\r\nf = { f[1], f[2], f[3], f[4], \"?\", \"?\", \"?\", f[5], f[7] }\r\nend\r\n\r\n\r\nlocal rest3 = {}\r\nfor i = 4, #f do if trim(f[i]) ~= \"\" then rest3[#rest3 + 1] = f[i] end end\r\nif #f >= 3 and #f <= 5 and #rest3 == 0 and (f[3] or \"\"):find(\"%d\") then\r\nf = { f[1], f[2], f[3], \"?\", \"?\", \"?\", \"?\", \"?\", \"?\" }\r\nend                end\r\nf[1], f[2] = Canon.actor(f[1], persona), Canon.actor(f[2], persona)\r\nf[1], f[2] = K.unitFix(c, pc, f[1]), K.unitFix(c, pc, f[2])\r\nelseif tag == \"HEAL\" then\r\nf[1], f[2] = Canon.actor(f[1], persona), Canon.name(f[2])\r\nelseif tag == \"STIM\" or tag == \"SOOTHE\" or tag == \"NUMB\" or tag == \"CLIMAX\" or tag == \"INHIB\" then\r\nf[1] = Canon.actor(f[1], persona)\r\nelseif tag == \"HDHEAL\" then\r\nf[1], f[2] = Canon.actor(f[1], persona), Canon.actor(f[2], persona)\r\nelseif tag == \"IMPREG\" then\r\nf[1], f[2] = Canon.actor(f[1], persona), Canon.actor(f[2], persona)\r\nelseif tag == \"OVERSTIM\" or tag == \"SCORE\" or tag == \"BADEND\" or tag == \"MAXDOWN\" or tag == \"PREG\" then\r\nf[1] = Canon.actor(f[1], persona)\r\nelseif tag == \"SWAP\" or tag == \"BOND\" or tag == \"REACT\" then\r\nf[1] = Canon.actor(f[1], persona)\r\nif tag ~= \"REACT\" then f[2] = Canon.actor(f[2], persona) elseif f[3] and f[3]:lower() ~= \"all\" then f[3] = Canon.actor(f[3], persona) end\r\nelseif tag == \"ADVANCE\" then\r\n\r\nlocal function isWho(v)\r\nlocal n = Canon.actor(v or \"\", persona)\r\nreturn n == \"Player\" or (c.units and c.units[n] ~= nil) or Ally.find(pc, n) ~= nil\r\nor (type(pc.scene) == \"table\" and type(pc.scene.units) == \"table\" and pc.scene.units[n] ~= nil)\r\nend\r\nif #f >= 11 and not isWho(f[2]) and isWho(f[3]) then table.remove(f, 2) end\r\nf[1], f[2] = Canon.actor(f[1], persona), Canon.actor(f[2], persona)\r\nelseif tag == \"BIND\" then\r\nif trim(f[1] or \"\") ~= \"-\" then f[1] = Canon.actor(f[1], persona) end\r\nf[2] = Canon.actor(f[2], persona)\r\nelseif tag == \"ESCAPE\" or tag == \"CURSE\" or tag == \"BRAND\" or tag == \"FETISH\" or tag == \"VICE\" then\r\nf[1] = Canon.actor(f[1], persona)\r\nelseif tag == \"COND\" and f[1] and not f[1]:match(\"^%s*[%+%-]\") then\r\n\r\nf[1] = K.unitFix(c, pc, Canon.actor(f[1], persona))\r\nelseif tag == \"ITEM\" or tag == \"COND\" then\r\nf[1] = Canon.signed(f[1])\r\nelseif tag == \"LOOT\" and f[3] then\r\nf[3] = Canon.name(f[3])\r\nelseif tag == \"SPELLS\" and f[2] then\r\nf[1], f[2] = Canon.list(f[1]), Canon.list(f[2])\r\nelseif (tag == \"OPT\" or tag == \"TRAP\") and f[2] then\r\nf[2] = Canon.name(f[2])\r\nend\r\n\r\nif (tag == \"SAVE\" or tag == \"HAZARD\" or tag == \"DAMAGE\" or tag == \"KNOCKOUT\") and f[1] then f[1] = K.unitFix(c, pc, f[1]) end\r\n\r\nlocal who, whoName\r\n\r\nlocal abAt = (tag == \"SAVE\" and 2) or (tag == \"HAZARD\" and 3) or nil\r\nif abAt and f[abAt] and f[abAt] ~= \"-\" then\r\nlocal v = Canon.name(f[abAt])\r\nf[abAt] = abilityName(v) or (MOD[v] and v) or f[abAt]\r\nend\r\nif tag == \"CHECK\" or tag == \"PASSIVE\" or tag == \"USE\" or tag == \"TRAP\" or tag == \"WEAR\" or tag == \"ATTUNE\" then\r\nlocal k = tag == \"TRAP\" and 2 or 1\r\nif f[k] then\r\nlocal rest\r\nwho, rest, whoName = Ally.prefix(pc, f[k], persona)\r\nf[k] = Canon.name(rest)\r\nend\r\nend\r\n\r\n\r\nK.apWill = nil\r\nK.lastAdj = nil\r\nK.curAttacker = nil\r\n\r\n\r\nif tag == \"SAVE\" and (#f == 6 or (#f == 7 and ({ willing = 1, unwilling = 1 })[trim(f[7] or \"\"):lower()]))\r\nand ({ success = 1, failure = 1 })[trim(f[6] or \"\"):lower()] then\r\nlocal w = Canon.actor(f[1] or \"\", persona)\r\n\r\n\r\nif w == \"Player\" or Ally.find(pc, w) or K.saveNoDmg(pc, trim(f[2] or \"\")) then\r\nfor _ = 1, 3 do table.insert(f, 7, \"-\") end\r\nend\r\nend\r\n\r\n\r\nif tag == \"SAVE\" and #f == 10 and trim(f[2] or \"\") ~= \"-\" then\r\nlocal dashes = true\r\nfor i = 3, 7 do if trim(f[i] or \"\") ~= \"-\" then dashes = false end end\r\nif dashes then table.remove(f, 2) end\r\nend\r\nlocal wAt = (tag == \"SAVE\" and 10) or (tag == \"CHECK\" and 6) or nil\r\nif wAt and (#f == wAt or #f == wAt + 2) then\r\nlocal w = trim(f[wAt] or \"\"):lower()\r\nif w == \"willing\" or w == \"unwilling\" then K.apWill = w; table.remove(f, wAt) end\r\nend\r\n\r\nif tag == \"CHECK\" and #f == 4 and (f[4] or \"\"):match(\"^%d+$\") then f[5] = \"?\" end\r\nif tag == \"SAVE\" and #f == 8 and trim(f[7] or \"\") == \"-\" and trim(f[8] or \"\") == \"-\" then f[9] = \"0\" end\r\nlocal a = args(f)\r\nlocal line, good\r\nif tag == \"CHECK\" and (#f == 5 or #f == 7) then\r\nlocal lock = (who == nil) and K.OPTLOCK or nil\r\nline, good = Ally.run(pc, who or nil, function() return verifyCheck({ f[1], f[2], f[3], f[4], f[5] }, pools, cur, lock) end)\r\n\r\nlocal total = tonumber(line:match(\"|(%-?%d+)%]$\"))\r\nif f[1] == \"Medicine\" and tonumber(f[4]) == 10 and total and total >= 10 and K.stabilize(pc, who) then\r\nline = line:gsub(\"%]$\", \" (Player Stable)]\")\r\nend\r\nelseif tag == \"ATTACK\" and (#f == 9 or #f == 11) then\r\nline, good = verifyAttack({ f[1], f[2], f[3], f[4], f[5], f[6], f[7], f[8], f[9] }, pools, cur, c, pc)\r\nK.noteMelee(c, f[1], f[2], K.atkKindLast)\r\nelseif tag == \"HEAL\" and #a == 4 and K.isNpc(a[3]) and trim(a[4] or \"\"):lower() == \"free\" then\r\nline, good = K.npcHeal({ a[1], a[2], \"npc free\" }, c, pc)\r\nelseif tag == \"HEAL\" and #a == 3 and K.isNpc(a[3]) then\r\nline, good = K.npcHeal(a, c, pc)\r\nelseif tag == \"HEAL\" and (#a == 2 or #a == 5) and K.isAid(a[2]) then\r\nif #a == 5 then K.spendRefused(pools, cur, nil, a[3], a[4]) end\r\nline, good = K.firstAid(a, c, pc)\r\nelseif tag == \"HEAL\" and #a == 5 then\r\n\r\n\r\nlocal hs = Canon.name(a[2] or \"\")\r\nlocal hsp = SPELLS[hs]\r\nlocal castLine\r\nlocal castAlready = false\r\nfor _, x in ipairs(Feat.cur.casts or {}) do if x.name == hs then castAlready = true end end\r\nif hsp and hsp.m and (hsp.m.heal or hsp.m.heal_all or hsp.m.heal_share or hsp.m.hp_bonus or hsp.m.temp_hp or hsp.m.temp_share) and not HEAL_SRC[hs] and Spell.known(hs)\r\nand not (Spell.cur and Spell.cur.name == hs) and not ((hsp.m.hp_bonus or hsp.m.temp_hp or hsp.m.temp_share) and castAlready) then\r\nlocal cl, cok = Spell.cast({ hs, tostring(hsp.level) }, pc, c, tctx)\r\nif cok then castLine = cl end\r\nend\r\nline, good = verifyHeal(a, pools, cur, c, pc)\r\nif castLine then line = castLine .. \"\\n\" .. line end\r\nelseif tag == \"DEATH\" and #a >= 1 then\r\nline, good = verifyDeath(a, pools, cur, c, pc)\r\nelseif tag == \"TIME\" and #a >= 1 then\r\n\r\n\r\nif c.active and K.fightDone(c, pc) then c.active, c.endedAt = false, clock.min end\r\nline, good = verifyTime(a, clock)\r\nK.wakeDue(pc, c, clock)\r\nK.timedEnds(pc, clock)\r\nelseif tag == \"REST\" and #a >= 1 then\r\nline, good = verifyRest(a, c, pc, clock)\r\nif good then\r\nif (a[1] or \"\"):lower() == \"short\" then tctx.shortRest = true end\r\nSpell.restWindow(pc, sheet, a[1])\r\nif a[1] == \"short\" then for _, r in ipairs({ pc, table.unpack(Ally.list(pc)) }) do K.MI.shortRefill(r) end end\r\nlocal an = Ally.rest(pc, a[1], clock)\r\nif an ~= \"\" and line:sub(-1) == \"]\" then line = line:sub(1, -2) .. \"; \" .. an .. \"]\" end\r\nlocal rt = K.restThp(pc, a[1])\r\nif rt ~= \"\" and line:sub(-1) == \"]\" then line = line:sub(1, -2) .. \"; \" .. rt .. \"]\" end\r\nend\r\nelseif tag == \"STIM\" and #a >= 6 then\r\nline, good = K.AR.stim(a, pools, cur, c, pc)\r\nelseif tag == \"SOOTHE\" and #a >= 5 then\r\nline, good = K.AR.soothe(a, pools, cur, c, pc)\r\nelseif tag == \"NUMB\" and #a >= 2 then\r\nline, good = K.AR.numb(a, c, pc)\r\nelseif tag == \"SWAP\" and #a >= 3 then\r\nline, good = K.AR.swapTag(a, c, pc)\r\nelseif tag == \"OVERSTIM\" and #a >= 2 then\r\nline, good = K.AR.overTag(a, c, pc)\r\nelseif tag == \"SCORE\" and #a >= 3 then\r\nline, good = K.scoreTag(a, c, pc, clock)\r\nelseif tag == \"BADEND\" and #a >= 2 then\r\nline, good = K.AR.badTag(a, c, pc, clock)\r\nelseif tag == \"MAXDOWN\" and #a >= 3 then\r\nline, good = K.maxDownTag(a, c, pc, clock)\r\nelseif tag == \"BIND\" and #a >= 3 then\r\nline, good = K.bindTag(a, c, pc, clock)\r\nelseif tag == \"STRIP\" and #a >= 5 then\r\nline, good = K.stripTag(a, pools, cur, c, pc)\r\nelseif tag == \"ESCAPE\" and #a >= 7 then\r\nline, good = K.escapeTag(a, pools, cur, c, pc)\r\nelseif (tag == \"CURSE\" or tag == \"BRAND\" or tag == \"FETISH\") and #a >= 2 then\r\nline, good = K.afflictTag(tag, a, c, pc, clock)\r\nelseif tag == \"VICE\" and #a >= 7 then\r\nline, good = K.viceTag(a, pools, cur, c, pc, clock)\r\nelseif tag == \"PLAN\" and #a >= 1 then\r\nline, good = K.planTag(a, pc, clock)\r\nelseif tag == \"SCENE\" and #a >= 1 then\r\nline, good = K.sceneTag(a, pc, clock)\r\nelseif tag == \"KNOCKOUT\" and #a >= 1 then\r\nline, good = K.knockoutTag(a, c, pc)\r\nelseif tag == \"IMPREG\" and #a >= 7 then\r\nline, good = K.PG.impreg(a, pools, cur, c, pc, clock)\r\nelseif tag == \"PREG\" and #a >= 2 then\r\nline, good = K.PG.tag(a, c, pc, clock)\r\nelseif tag == \"HDHEAL\" and #a >= 3 then\r\nline, good = K.AR.hdHealTag(a, c, pc)\r\nelseif tag == \"BOND\" and #a >= 3 then\r\nline, good = K.AR.bondTag(a, c, pc)\r\nelseif tag == \"REACT\" and #a >= 2 then\r\nline, good = K.AR.reactTag(a, c, pc)\r\nelseif tag == \"INHIB\" and #a >= 3 then\r\nline, good = K.AR.inhibTag(a, pools, cur, c, pc)\r\nelseif tag == \"INHIB\" then\r\nline, good = \"[INHIB|\" .. table.concat(a, \"|\") .. \"|bad:write [INHIB|Target|Spell|-1d4|dice] or [INHIB|Target|Spell|vs]|-]\", false\r\nelseif tag == \"ADVANCE\" and #a >= 11 then\r\nline, good = K.AR.advance(a, pools, cur, c, pc)\r\nelseif tag == \"ADVANCE\" then\r\nK.spendRefused(pools, cur, a[5], a[9], a[10])\r\nline, good = \"[ADVANCE|\" .. table.concat(a, \"|\") .. \"|bad:write [ADVANCE|Attacker|Target|Implement|willing/unwilling|d20|+bonus|AC|hit/miss/crit|formula|dice|stim]|-]\", false\r\nelseif tag == \"CLIMAX\" and #a >= 5 then\r\nline, good = K.AR.climaxSave(a, pools, cur, c, pc)\r\nelseif tag == \"CLIMAX\" and (a[2] or \"\"):lower() == \"now\" and (#a == 2 or (#a == 3 and trim(a[3] or \"\") == \"\")) then\r\nline, good = K.AR.storyClimax({ a[1], a[2] }, c, pc)\r\nelseif tag == \"CLIMAX\" and #a == 3 and ((a[2] or \"\"):lower() == \"now\" or (a[2] or \"\"):lower() == \"end\" or (a[2] or \"\"):lower() == \"vuln\") then\r\nline, good = K.AR.climaxBy(a, c, pc)\r\nelseif tag == \"CLIMAX\" then\r\nK.spendRefused(pools, cur, a[2])\r\nline, good = \"[CLIMAX|\" .. table.concat(a, \"|\") .. \"|bad:write [CLIMAX|Target|15|+bonus|15|success/failure] (third field: a roll like 15 or adv 15,19; never literal d20)|-]\", false\r\nelseif tag == \"STIM\" or tag == \"SOOTHE\" or tag == \"NUMB\" then\r\n\r\nif tag == \"STIM\" then K.spendRefused(pools, cur, nil, a[4], a[5]) elseif tag == \"SOOTHE\" then K.spendRefused(pools, cur, nil, a[3], a[4]) end\r\nlocal shape = { STIM = \"[STIM|Target|Source|Type|formula|dice|amount]\", SOOTHE = \"[SOOTHE|Target|Source|formula|dice|amount]\", NUMB = \"[NUMB|Target|N]\" }\r\nline, good = \"[\" .. tag .. \"|\" .. table.concat(a, \"|\") .. \"|bad:write \" .. shape[tag] .. \"|-]\", false\r\nelseif K.AR_SHAPE[tag] then\r\n\r\nline, good = \"[\" .. tag .. \"|\" .. table.concat(a, \"|\") .. \"|bad:write \" .. K.AR_SHAPE[tag] .. \"|-]\", false\r\nelseif tag == \"XP\" and #a >= 1 then\r\nline, good = verifyXP(a, pc, budget)\r\nelseif tag == \"BUFF\" and (f[3] == \"auto\" or f[4] == \"auto\") then\r\nline, good = \"\", true\r\nelseif tag == \"REVIVE\" and #a >= 2 then\r\nline, good = K.raiseTag(a, c, pc, clock, persona)\r\nelseif tag == \"BUFF\" and #a >= 2 then\r\nline, good = K.buffTag(a, c, pc, clock)\r\nelseif tag == \"MP\" and #a >= 2 then\r\nline, good = K.MP.give(a, c, pc)\r\nelseif tag == \"ITEM\" and #a >= 1 and tctx.hazTook and tctx.hazTook[(K.itemName(Canon.name(((a[1] or \"\"):match(\"^%s*%-%s*(.-)%s*$\") or \"\"))))] then\r\n\r\nline, good = \"[ITEM|\" .. table.concat(a, \"|\") .. \"|bad:HAZARD already took it from the pack|-]\", false\r\nelseif tag == \"ITEM\" and #a >= 1 then\r\nline, good = verifyItem(a, pc)\r\nelseif (tag == \"EQUIP\" or tag == \"UNEQUIP\") and #a >= 1 then\r\nline, good = verifyEquip(a, c, pc, clock, tag == \"EQUIP\")\r\nelseif tag == \"ROLL_STATS\" then\r\nlocal nums = {}\r\nfor n in rest:gmatch(\"%d+\") do nums[#nums + 1] = tonumber(n) end\r\nrolled = (#nums == 6) and nums or rollStats()\r\nsetState(id, \"dnd_rolled\", rolled)\r\nline, good = \"[ROLL_STATS|ok|\" .. table.concat(rolled, \", \") .. \"]\", true\r\nelseif tag == \"PC\" and #a >= 1 then\r\nlocal nsh, npc\r\nline, good, nsh, npc = verifyPC(a, rolled)\r\nif good then\r\nnewChar = true\r\nsheet = nsh\r\n\r\nlocal party = pc.allies\r\nfor k in pairs(pc) do pc[k] = nil end\r\nfor k, v in pairs(npc) do pc[k] = v end\r\npc.allies = party\r\nK.partyFx(pc, sheet)\r\nFeat.cur.snap = nil\r\nend\r\napplySheet(sheet)\r\nelseif tag == \"THREAD\" or tag == \"NPC\" or tag == \"SECRET\" then\r\n\r\nline, good = \"\", true\r\nelseif tag == \"GOLD\" and #a >= 1 then\r\nlocal g = tonumber((a[1] or \"\"):match(\"^%s*%+%s*(%d+)%s*gp%s*$\") or \"\")\r\nif g and paid[g] then\r\npaid[g] = nil\r\nline, good = \"[GOLD|\" .. a[1] .. \"|bad:paid by the QUEST tag|-]\", false\r\nelse\r\nline, good = verifyGold(a, pc)\r\nend\r\nelseif (tag == \"BUY\" or tag == \"SELL\") and #a >= 3 then\r\nline, good = verifyTrade(a, pc, tag)\r\nelseif tag == \"CAST\" and #a >= 1 then\r\n\r\nif tctx.rolls then tctx.rolls[Canon.name(a[1] or \"\")] = nil end\r\n\r\nlocal by = a[3] and Canon.actor(a[3], persona) or \"Player\"\r\nlocal r = by ~= \"Player\" and Ally.find(pc, by)\r\nlocal downWhy = K.castAllDown(tagList, tagAt, by, a, c, pc, persona)\r\nif by ~= \"Player\" and not r then\r\nline, good = \"[CAST|\" .. table.concat(a, \"|\") .. \"|bad:unknown companion|-]\", false\r\nelseif downWhy then\r\nline, good = \"[CAST|\" .. table.concat(a, \"|\") .. \"|bad:\" .. downWhy .. \"|-]\", false\r\nelseif r then\r\nline, good = Ally.with(r, Spell.cast, a, r, c, tctx)\r\n\r\nif good and Canon.name(a[1] or \"\") == \"Spare the Dying\" and K.stabilize(pc, r) then\r\nline = line:gsub(\"%]$\", \" (Player Stable)]\")\r\nend\r\nelse\r\nline, good = Spell.cast(a, pc, c, tctx)\r\nend\r\nelseif tag == \"PLACE\" and #a >= 1 then\r\nlocal v = trim(a[1] or \"\"):lower()\r\nlocal where = (v == \"town\" or v == \"마을\" or v == \"village\" or v == \"city\") and \"town\"\r\nor (v == \"wild\" or v == \"야외\" or v == \"dungeon\" or v == \"ruins\") and \"wild\" or nil\r\n\r\nlocal nm = where and (a[2] or \"\") or a[1]\r\nnm = trim(tostring(nm):gsub(\"[|%]%[%^;]\", \"\"))\r\nlocal cut = utf8.offset(nm, 41)\r\nif cut then nm = nm:sub(1, cut - 1) end\r\nif not where and nm == \"\" then\r\nline, good = \"[PLACE|\" .. table.concat(a, \"|\") .. \"|bad:town or wild, and the place's name|-]\", false\r\nelse\r\nlocal was = pc.place == \"wild\" and \"wild\" or \"town\"\r\nlocal now = where or was\r\npc.place = now\r\nif nm ~= \"\" then pc.placeName = nm elseif now ~= was then pc.placeName = nil end\r\nlocal change = now == was and \"same\" or (now == \"town\" and \"enter\" or \"leave\")\r\nline, good = \"[PLACE|\" .. table.concat(a, \"|\") .. \"|ok|\" .. now .. \"|\" .. change .. \"|\" .. (pc.placeName or \"\") .. \"]\", true\r\nend\r\nelseif tag == \"ALLY\" and #a >= 1 then\r\nline, good = Ally.verify(a, pc, c, persona)\r\nelseif tag == \"GIVE\" and #a >= 3 then\r\nline, good = K.give(a, pc, c, persona)\r\nelseif tag == \"CRAFT\" and #a >= 1 then\r\nline, good = K.craft(a, pc, c, clock, persona)\r\nelseif tag == \"SUMMON\" and #a >= 1 then\r\nline, good = K.summonTag(a, c, pc, clock, persona)\r\nelseif tag == \"IMPLANT\" and #a >= 2 then\r\nline, good = K.implantTag(a, c, pc, clock, persona)\r\nelseif tag == \"TRIGGER\" and #a >= 2 then\r\nline, good = K.triggerTag(a, c, pc, tctx, persona)\r\nelseif tag == \"MOUNT\" and #a >= 1 then\r\nline, good = K.mountTag(a, c, pc)\r\nelseif tag == \"COVER\" and #a >= 2 then\r\nline, good = K.coverTag(a, c, persona)\r\nelseif tag == \"HAZARD\" and (#f == 10 or #f == 12) and K.hazSpell(f[2]) then\r\n\r\n\r\nline, good = Spell.save({ f[1], f[3], f[4], f[5], f[6], f[7], f[8], f[9], f[10] }, pools, cur, c, pc, tctx)\r\nelseif tag == \"HAZARD\" and (#f == 10 or #f == 12) then\r\nline, good = K.hazard({ f[1], f[2], f[3], f[4], f[5], f[6], f[7], f[8], f[9], f[10] }, pools, cur, c, pc, tctx)\r\nelseif tag == \"SAVE\" and (#f == 9 or #f == 11) and (Canon.actor(f[1] or \"\", persona) == \"Player\"\r\nor Ally.find(pc, Canon.actor(f[1] or \"\", persona))) then\r\n\r\n\r\nlocal w = Canon.actor(f[1] or \"\", persona)\r\nlocal r = w ~= \"Player\" and Ally.find(pc, w) or nil\r\nf[1] = w\r\nline, good = Ally.run(pc, r, function()\r\nreturn K.foeSave({ f[1], f[2], f[3], f[4], f[5], f[6], f[7], f[8], f[9] }, pools, cur, c, pc, tctx, r or pc)\r\nend)\r\nelseif tag == \"SAVE\" and (#f == 9 or #f == 11) then\r\nline, good = Spell.save({ f[1], f[2], f[3], f[4], f[5], f[6], f[7], f[8], f[9] }, pools, cur, c, pc, tctx)\r\nelseif tag == \"DAMAGE\" and #f == 5 and not (f[5] or \"\"):match(\"^ok\") and not (f[5] or \"\"):match(\"^bad:\") then\r\nline, good = K.selfDamage(f, pools, cur, c, pc)\r\nelseif tag == \"DAMAGE\" and (#f == 4 or #f == 6) then\r\nline, good = Spell.damage({ f[1], f[2], f[3], f[4] }, pools, cur, c, pc, tctx)\r\nelseif tag == \"CONC\" then\r\n\r\n\r\n\r\nlocal who = trim(a[2] or \"\")\r\nlocal unit\r\nif who ~= \"\" then\r\nlocal w = Canon.actor(who, persona)\r\nunit = (w == \"Player\") and pc or Ally.find(pc, w)\r\nelseif type(pc.conc) == \"table\" and pc.conc.name then\r\nunit = pc\r\nelse\r\nlocal seen = {}\r\nfor _, l in ipairs({ Ally.list(pc), Ally.guests(pc) }) do\r\nfor _, r in ipairs(l) do\r\nif type(r.conc) == \"table\" and r.conc.name and not r.dead then seen[#seen + 1] = r end\r\nend\r\nend\r\nif #seen == 1 then unit = seen[1] elseif #seen > 1 then unit = false end\r\nend\r\nlocal was = unit and type(unit.conc) == \"table\" and unit.conc.name\r\nif was then unit.conc = nil; unit.concEnd = { name = was, why = \"was dropped\" } end\r\nlocal named = who ~= \"\" and (\"|\" .. who) or \"\"\r\nif was then\r\nline, good = \"[CONC|end\" .. (unit == pc and \"\" or (\"|\" .. unit.name)) .. \"|ok|\" .. was .. \"]\", true\r\nelseif unit == false then\r\nline, good = \"[CONC|end|bad:more than one companion is concentrating, name the caster|-]\", false\r\nelseif who ~= \"\" and not unit then\r\nline, good = \"[CONC|end\" .. named .. \"|bad:unknown caster|-]\", false\r\nelse\r\nline, good = \"[CONC|end\" .. named .. \"|bad:not concentrating|-]\", false\r\nend\r\nelseif tag == \"COND\" and #a >= 2 and not (a[1] or \"\"):match(\"^%s*[+-]\") and (a[2] or \"\"):match(\"^%s*[+-]\") then\r\nline, good = K.AR.condOn(a, c, pc, clock)\r\nelseif tag == \"COND\" and #a >= 1 then\r\nline, good = Cond.verify(a, pc, clock)\r\nelseif tag == \"QUEST\" and #a >= 1 then\r\nline, good = Quest.verify(a, pc)\r\nelseif tag == \"STAGE\" and #a >= 1 then\r\nline, good = Quest.stage(a, pc, tctx)\r\nelseif (tag == \"WEAR\" or tag == \"USE\" or tag == \"ATTUNE\") and who == false then\r\n\r\nline, good = \"[\" .. tag .. \"|\" .. table.concat(a, \"|\") .. \"|bad:not applied|-]\", false\r\nelseif tag == \"WEAR\" and #a >= 1 then\r\nline, good = K.wear(a, who or pc)\r\nelseif tag == \"ATTUNE\" and #a >= 1 then\r\nline, good = Ally.run(pc, who or nil, function() return K.MI.attune(a, who or pc, c, clock, tctx) end)\r\nelseif tag == \"LOOT\" and #a >= 2 then\r\nline, good = verifyLoot(a, pc, tctx)\r\nelseif tag == \"TRAP\" and (#f == 9 or #f == 11) then\r\n\r\n\r\nlocal target = who or (who == false and deepCopy(pc)) or pc\r\nline, good = Ally.run(pc, who or nil, function()\r\nreturn verifyTrap({ f[1], f[2], f[3], f[4], f[5], f[6], f[7], f[8], f[9] }, pools, cur, target)\r\nend)\r\nif who == false then line = line:gsub(\"|[^|%]]*%]$\", \"|-]\") end\r\nelseif tag == \"BACKGROUND\" and #a >= 4 then\r\nline, good = K.verifyBackground(a, id)\r\nelseif tag == \"SPELLS\" and #a >= 1 then\r\n\r\ndeferred[#deferred + 1] = a\r\nreturn \"\\1SPELLS\" .. #deferred .. \"\\1\"\r\nelseif tag == \"SPELLBOOK\" and #a >= 1 then\r\na.book = true\r\ndeferred[#deferred + 1] = a\r\nreturn \"\\1SPELLS\" .. #deferred .. \"\\1\"\r\nelseif tag == \"INITIATE\" and #a >= 1 then\r\na.initiate = true\r\ndeferred[#deferred + 1] = a\r\nreturn \"\\1SPELLS\" .. #deferred .. \"\\1\"\r\nelseif tag == \"PASSIVE\" and #a >= 3 then\r\nline, good = Ally.run(pc, who or nil, function() return verifyPassive(a, who or pc) end)\r\nelseif tag == \"USE\" and a[1] == \"Healer's Kit\" then\r\nline, good = K.healerKit(a, pc, who or pc, persona)\r\nelseif tag == \"USE\" and a[1] == \"Bardic Inspiration\" and trim(a[2] or \"\") == \"\" and K.AR and K.AR.selfUse(who or pc, pc, \"Bardic Inspiration\") then\r\n\r\nlocal ur = who or pc\r\nif (type(ur.res) == \"table\" and tonumber(ur.res[\"Bardic Inspiration\"]) or 0) < 1 then\r\nline, good = \"[USE|Bardic Inspiration|bad:no uses left|-]\", false\r\nelse\r\nur.res[\"Bardic Inspiration\"] = ur.res[\"Bardic Inspiration\"] - 1\r\nFeat.cur.used = Feat.cur.used or {}\r\nFeat.cur.used[ur] = Feat.cur.used[ur] or {}\r\nFeat.cur.used[ur][\"Bardic Inspiration\"] = true\r\nline, good = \"[USE|Bardic Inspiration|ok|for \" .. K.AR.selfUse(ur, pc, \"Bardic Inspiration\") .. \", \" .. ur.res[\"Bardic Inspiration\"] .. \" left]\", true\r\nend\r\nelseif tag == \"USE\" and a[1] == \"Bardic Inspiration\" then\r\nline, good = Feat.inspire(a, who or pc, pc, c)\r\nif good then Feat.cur.used = Feat.cur.used or {}; Feat.cur.used[who or pc] = Feat.cur.used[who or pc] or {}; Feat.cur.used[who or pc][\"Bardic Inspiration\"] = true end\r\nelseif tag == \"USE\" and #a >= 1 then\r\nline, good = Ally.run(pc, who or nil, function()\r\nlocal l2, g2 = K.MI.use(a, who or pc, c, clock)\r\nif l2 and g2 then\r\nlocal p0 = K.MI.parse(a[1] or \"\")\r\nlocal af = p0 and type(p0.m) == \"table\" and p0.m.afflict\r\nif type(af) == \"table\" and af.when == \"use\" then K.MI.afflictNow(who or pc, K.MI.canon(p0), af) end\r\nend\r\nif l2 then return l2, g2 end\r\nif Canon.name(a[1] or \"\") == \"Basic Poison\" then return K.poisonUse(a, who or pc, c, clock) end\r\nreturn verifyUse(a, c, who or pc, pc, persona)\r\nend)\r\nif good then\r\nlocal ur = who or pc\r\nFeat.cur.used = Feat.cur.used or {}\r\nFeat.cur.used[ur] = Feat.cur.used[ur] or {}\r\nFeat.cur.used[ur][trim(a[1] or \"\")] = true\r\nend\r\nelseif tag == \"GM\" then\r\nreturn nil\r\nelseif tag == \"OPT\" and #a >= 1 and ((c.active and not wasActive) or WEAPONS[Canon.name(a[2] or \"\")]\r\nor (c.units and c.units[trim(a[3] or \"\")] and not K.HAZ[Canon.name(a[2] or \"\")] and not SPELLS[Canon.name(a[2] or \"\")])) then\r\n\r\n\r\nline, good = \"[OPT|\" .. table.concat(a, \"|\") .. \"|bad:OPT is a suggestion for the next input; an attack Player makes in this reply is \"\r\n.. \"[ATTACK|Player|target|d20|+hit|AC|hit/miss/crit|formula|dice|damage]|-]\", false\r\nelseif tag == \"OPT\" and #a >= 1 then\r\nreturn verifyOpt(a, pc, c)\r\nelseif tag == \"COMBAT\" then\r\nlocal kinds, surprise, deadly, uw = {}, nil, false, false\r\nfor _, k in ipairs(f) do\r\nlocal lk = k:lower()\r\nif lk == \"surprise\" or lk == \"surprised\" then\r\nsurprise = \"enemies\"\r\nelseif lk == \"ambush\" or lk == \"ambushed\" then\r\nsurprise = \"party\"\r\nelseif lk == \"deadly\" or lk == \"hopeless\" or k == \"절망\" then\r\ndeadly = true\r\nelseif lk == \"underwater\" or k == \"수중\" or k == \"물속\" then\r\nuw = true\r\nelseif k ~= \"\" and k ~= \"ok\" and not k:match(\"^bad:\") then\r\nkinds[#kinds + 1] = k\r\nend\r\nend\r\nev.threat = true\r\n\r\n\r\nlocal flip = surprise == \"party\" and not c.active and (text:match(\"%[COMBAT|.-%](.*)\") or \"\"):find(\"[ATTACK|Player|\", 1, true)\r\nif flip then surprise = \"enemies\" end\r\nlocal line = startCombat(kinds, c, pc, surprise, deadly)\r\nif flip then\r\nlocal note = \"ambush->surprise (Player struck first)\"\r\nif line:find(\"|bad:\", 1, true) then\r\nline = line:gsub(\"|(bad:[^|%]]*)\", \"|%1; \" .. note, 1)\r\nelse\r\nline = line:gsub(\"|ok([|%]])\", \"|bad:\" .. note .. \"%1\", 1)\r\nend\r\nend\r\nif c.active then Feat.heroic(pc, sheet) end\r\nif c.active and not wasActive then\r\n\r\nlocal said = trim((um and um.role == \"user\" and tostring(um.data or \"\") or \"\"):gsub(\"[%[%]]\", \"\"))\r\nif (utf8.len(said) or #said) > 200 then said = said:sub(1, (utf8.offset(said, 201) or (#said + 1)) - 1) end\r\nc.opening = said ~= \"\" and said or nil\r\nc.openingAt = getChatLength(id) - 1\r\nif surprise then line = line:gsub(\"%]$\", \"|\" .. (surprise == \"enemies\" and \"surprise\" or \"ambush\") .. \"]\") end\r\nif uw then c.underwater = true; line = line:gsub(\"%]$\", \"|underwater]\") end\r\nend\r\nK.UNDERWATER = c.active and c.underwater or nil\r\nreturn K.roundMark(c, tag, f, roundAct0, line, roundLast0)\r\nelseif tag == \"DAMAGE\" or tag == \"HEAL\" then\r\n\r\nline, good = \"[\" .. tag .. \"|\" .. table.concat(a, \"|\") .. \"|bad:fields \" .. #a .. \"|-]\", false\r\nelseif K.D20_FIELD[tag] then\r\n\r\n\r\nlocal field = f[K.D20_FIELD[tag]] or \"\"\r\nif field:find(\"%d\") then takeD20(cur, pools, field, {}) end\r\nline, good = \"[\" .. tag .. \"|\" .. table.concat(a, \"|\") .. \"|bad:fields \" .. #a .. \"|-]\", false\r\nelseif tag == \"COMBAT_END\" then\r\nif c.active then c.endedAt = clock.min end\r\nc.active = false\r\nreturn (rest ~= \"\") and (\"[COMBAT_END|\" .. rest .. \"]\") or \"[COMBAT_END]\"\r\nelse\r\nreturn nil\r\nend\r\n\r\nif line and Feat.cur.dtsLines then line = line .. Feat.cur.dtsLines; Feat.cur.dtsLines = nil end\r\n\r\n\r\nif K.apWill and wAt and line then\r\nlocal nb, pos = 0, nil\r\nfor i = 1, #line do\r\nif line:byte(i) == 124 then nb = nb + 1; if nb == wAt then pos = i; break end end\r\nend\r\nif pos then line = line:sub(1, pos) .. K.apWill .. \"|\" .. line:sub(pos + 1) end\r\nend\r\nline = K.diceNote(line)\r\nK.diceLog, K.d20Log = nil, nil\r\nif good and K.AR_TAGS[tag] then pc.arWarm = true end\r\n\r\nif Feat.cur.healStim then\r\n\r\n\r\nfor tr, x in pairs(Feat.cur.healStim) do\r\nif tag == \"HEAL\" and K.AR.on() and not line:match(\"|%-%]$\") then\r\nlocal txt, extra = K.AR.give(tr, x.n, pc, c, false, tr == pc and \"Player\" or tr.name, nil, { type = \"Radiant\", magical = true })\r\nline = line:gsub(\"%]$\", \" (\" .. tostring(x.src or \"heal_bonus\") .. \": \" .. x.n .. \" Radiant stimulation, \" .. tostring(txt) .. \")]\", 1) .. (extra or \"\")\r\nend\r\nend\r\nFeat.cur.healStim = nil\r\nend\r\n\r\nif who ~= nil and line then\r\nlocal nm = (who and who.name or whoName):gsub(\"%%\", \"%%%%\")\r\nline = line:gsub(\"^(%[%u+|\" .. (tag == \"TRAP\" and \"[^|]*|\" or \"\") .. \")\", \"%1\" .. nm .. \"/\", 1)\r\nif who == false then\r\ngood = false\r\nif line:find(\"|ok|\", 1, true) then\r\nline = line:gsub(\"|ok|\", \"|bad:unknown companion|\", 1)\r\nelse\r\nline = line:gsub(\"|bad:\", \"|bad:unknown companion;\", 1)\r\nend\r\nend\r\nend\r\n\r\nif tag == \"TRAP\" or tag == \"CHECK\" or tag == \"PASSIVE\" then\r\nev.gimmick = true\r\nelseif good and (tag == \"XP\" or tag == \"LOOT\" or (tag == \"QUEST\" and a[1] == \"done\" and a[3] ~= \"fail\") or (tag == \"ITEM\" or tag == \"GOLD\") and (a[1] or \"\"):match(\"^%s*%+\")) then\r\nev.reward = true\r\nend\r\nif line then line = K.safeBad(line) end\r\nn = n + 1\r\nif good then\r\nokN = okN + 1\r\nelse\r\nbadN = badN + 1\r\nif #bads < 8 then bads[#bads + 1] = line end\r\nend\r\nlocal after = K.Fix.snap(c, pc)\r\nK.Fix.note(tag, f, who, before, after, line or \"\")\r\nif line then line = K.concSaves(pc, before, after, line) end\r\nif line then line = K.roundMark(c, tag, f, roundAct0, line, roundLast0) end\r\nK.stampDeaths(pc, clock, c)\r\nK.MI.syncAll(pc, sheet)\r\nif K.boomNow and line then line = line .. \"\\3\" .. K.boomNow .. \"\\3\" end\r\nreturn line\r\nend\r\n\r\n\r\nlocal handleTag0 = handleTag\r\nlocal outerTag, outerRest\r\nhandleTag = function(tag, rest)\r\nlocal who, what\r\nif c.active then who, what = K.reactOf(tag, rest, persona, pc) end\r\nif not who then return handleTag0(tag, rest) end\r\nlocal rd = tonumber(c.round) or 1\r\n\r\nif outerTag and (tag ~= outerTag or rest ~= outerRest) then rd = K.roundAfter(c, outerTag, outerRest, persona) end\r\nc.reacted = type(c.reacted) == \"table\" and c.reacted or {}\r\nlocal used = c.reacted[who]\r\nif not rest:find(\"|ok|\", 1, true) and not rest:find(\"|bad:\", 1, true) and type(used) == \"table\" and used.r == rd then\r\nlocal line = \"[\" .. tag .. \"|\" .. rest .. \"|bad:\" .. who .. \"'s Reaction is used this round (\" .. tostring(used.what)\r\n.. \"); one Reaction a round, back at the start of its turn|-]\"\r\nn, badN = n + 1, badN + 1\r\nif #bads < 8 then bads[#bads + 1] = line end\r\nreturn line\r\nend\r\n\r\n\r\nlocal last = c.last\r\nK.inReact = true\r\nlocal okr, line = pcall(handleTag0, tag, rest)\r\nK.inReact = nil\r\nif not okr then error(line, 0) end\r\nif c.active then c.last = last end\r\nif line and line:find(\"|ok|\", 1, true) then c.reacted[who] = { r = rd, what = what } end\r\nreturn line\r\nend\r\nlocal out = text:gsub(\"%[([%u_]+)|?([^%]]*)%]\", function(tag, rest)\r\ntagAt = tagAt + 1\r\nif preLine[tagAt] ~= nil then return preLine[tagAt] or nil end\r\nouterTag, outerRest = tag, rest\r\n\r\nif tag == \"CLIMAX\" then\r\nlocal why = K.climaxReplaced(tagList, tagAt, rest, persona)\r\nif why then\r\nlocal cf = {}\r\nfor v in ((rest or \"\") .. \"|\"):gmatch(\"([^|]*)|\") do v = trim(v); if v == \"ok\" or v:match(\"^bad:\") then break end; cf[#cf + 1] = v end\r\nlocal d20f = cf[2]\r\nif trim(d20f or \"\"):lower() == \"d20\" and cf[3] then d20f = cf[3] end\r\nK.spendRefused(pools, cur, d20f, nil, nil)\r\nreturn \"[CLIMAX|\" .. table.concat(cf, \"|\") .. \"|bad:\" .. why .. \"|-]\"\r\nend\r\nend\r\n\r\nif tag == \"ADVANCE\" then\r\nlocal fa = K.tagFields(rest)\r\nlocal who = function(v) return Canon.actor(v or \"\", persona) end\r\nlocal Y, X = who(fa[1]), who(fa[2])\r\nlocal here = tagAt\r\nfor j = here + 1, #tagList do\r\nlocal tg = tagList[j][1]\r\nif tg == \"ADVANCE\" and who(K.tagFields(tagList[j][2])[1]) == Y then break end\r\nlocal kind, by = K.insteadOf(tg, tagList[j][2], persona)\r\nif kind == \"ADVANCE\" and by == X and preLine[j] == nil then\r\nfor k = j + 1, #tagList do\r\nif tagList[k][1] == \"CAST\" then break end\r\nif tagList[k][1] == \"SAVE\" and who(K.tagFields(tagList[k][2])[1]) == Y and preLine[k] == nil then\r\n\r\nlocal snap = {}\r\nfor kk, vv in pairs(cur) do snap[kk] = vv end\r\nK.spendRefused(pools, cur, fa[5], fa[9], fa[10])\r\ntagAt = j\r\nlocal l1 = handleTag(tg, tagList[j][2])\r\npreLine[j] = l1 == nil and false or l1\r\ntagAt = k\r\nlocal l2 = handleTag(\"SAVE\", tagList[k][2])\r\npreLine[k] = l2 == nil and false or l2\r\nK.noteGone(tagList[k][2], l2, persona)\r\ntagAt = here\r\nlocal gone0 = Feat.cur.advGone and Feat.cur.advGone[Y]\r\nif gone0 and gone0.by == X then\r\nreturn K.advGoneLine(c, Y, fa, \"[ADVANCE|\" .. table.concat(fa, \"|\") .. \"|bad:\" .. Y .. \" was teleported away by \" .. gone0.spell .. \" (its save failed)|-]\")\r\nend\r\n\r\n\r\nfor kk in pairs(cur) do cur[kk] = snap[kk] end\r\nlocal l0 = handleTag(tag, rest)\r\ntagAt = k\r\nseenRoll[\"SAVE|\" .. tagList[k][2]] = nil\r\nlocal l3 = handleTag(\"SAVE\", tagList[k][2])\r\npreLine[k] = l3 == nil and false or l3\r\ntagAt = here\r\nreturn l0\r\nend\r\nend\r\nbreak\r\nend\r\nend\r\nlocal gone = Feat.cur.advGone and Feat.cur.advGone[Y]\r\nif gone and gone.by == X then\r\nK.spendRefused(pools, cur, fa[5], fa[9], fa[10])\r\nreturn K.advGoneLine(c, Y, fa, \"[ADVANCE|\" .. table.concat(fa, \"|\") .. \"|bad:\" .. Y .. \" was teleported away by \" .. gone.spell .. \" (its save failed)|-]\")\r\nend\r\nend\r\n\r\n\r\nlocal shieldFor\r\ndo\r\nlocal T = K.dmgTargetOf(tag, rest, persona, pc, c)\r\nif T then\r\nlocal here = tagAt\r\nfor j = here + 1, #tagList do\r\nlocal tg = tagList[j][1]\r\nif K.dmgTargetOf(tg, tagList[j][2], persona, pc, c) == T then break end\r\nlocal kind, by = K.insteadOf(tg, tagList[j][2], persona)\r\nif kind == \"damage\" and by == T and preLine[j] == nil then\r\ntagAt = j\r\nlocal sc = Spell.cur\r\nlocal l1 = handleTag(tg, tagList[j][2])\r\nSpell.cur = sc\r\npreLine[j] = l1 == nil and false or l1\r\nK.noteShield(tagList[j][2], l1, persona)\r\nshieldFor = T\r\ntagAt = here\r\nbreak\r\nend\r\nend\r\nend\r\nend\r\n\r\n\r\n\r\nif tag == \"CAST\" and not rest:find(\"|ok|\", 1, true) and not rest:find(\"|bad:\", 1, true) and K.insteadOf(tag, rest, persona) == \"damage\" then\r\nlocal line = \"[CAST|\" .. rest .. \"|bad:write it right after the ATTACK, SAVE or DAMAGE it answers, that tag as rolled; Lua takes that damage away|-]\"\r\nn, badN = n + 1, badN + 1\r\nif #bads < 8 then bads[#bads + 1] = line end\r\nreturn line\r\nend\r\n\r\n\r\nif tag == \"ATTACK\" then\r\nlocal here = tagAt\r\nfor j = here + 1, #tagList do\r\nlocal tg, rs = tagList[j][1], tagList[j][2] or \"\"\r\nif tg == \"ATTACK\" then break end\r\nif preLine[j] == nil and K.answersAttack(tg, rs, rest, tagList[j + 1], persona, pc, c) then\r\ntagAt = j\r\nlocal l = handleTag(tg, rs)\r\ntagAt = here\r\npreLine[j] = l == nil and false or l\r\nend\r\nend\r\nend\r\nlocal line = handleTag(tag, rest)\r\n\r\n\r\nif shieldFor and Feat.cur and type(Feat.cur.dmgShield) == \"table\" then Feat.cur.dmgShield[shieldFor] = nil end\r\nif tag == \"SAVE\" then K.noteGone(rest, line, persona) elseif tag == \"CAST\" then K.noteShield(rest, line, persona) end\r\nreturn line\r\nend)\r\nouterTag, outerRest = nil, nil\r\nK.planNow = nil\r\n\r\nfor i, a in ipairs(deferred) do\r\nlocal line, good\r\n\r\nlocal na, why = a, nil\r\nif not a.initiate and not a.book then\r\nlocal cls, f1, f2, head, err = Spell.tagClass(sheet, a)\r\nna, why = { f1, f2, cls = cls, head = head }, err\r\nend\r\nlocal shut = not a.initiate and not a.book and not why and Spell.windowBad(pc, sheet, na, newChar)\r\nlocal first = not a.initiate and not a.book and #(select(2, K.lists(sheet, na.cls))) == 0\r\nif a.initiate then\r\nline, good = Feat.initiate(a, c, sheet)\r\n\r\n\r\nif good then applySheet(sheet); Feat.fillRes(pc) end\r\nelseif a.book then line, good = Spell.bookAdd(a, c, sheet, pc, clock)\r\nelseif why then line, good = na.head .. \"|bad:\" .. why .. \"|-]\", false\r\nelseif shut then line, good = na.head .. \"|bad:\" .. shut .. \"|-]\", false\r\nelse line, good = verifySpells(na, c, sheet) end\r\n\r\n\r\nif first and good and na.cls then\r\n\r\nSpell.setWin(pc, sheet, na.cls, { kind = \"all\", why = #K.mcList(sheet) > 0 and \"newcls\" or \"new\", orig = deepCopy((select(2, K.lists(sheet, na.cls)))) })\r\nend\r\nn = n + 1\r\nif good then okN = okN + 1 else badN = badN + 1; if #bads < 8 then bads[#bads + 1] = line end end\r\nout = out:gsub(\"\\1SPELLS\" .. i .. \"\\1\", function() return line end, 1)\r\nend\r\nout = K.goneOff(out, pc)\r\nK.stampDeaths(pc, clock, c)\r\n\r\nif newChar and (CLASSES[sheet.class] or {}).spell_ability then\r\npc.prep = { kind = \"all\", why = \"new\", orig = deepCopy(sheet.spells or {}) }\r\nend\r\n\r\n\r\n\r\nif c.active and c.opening and c.openingAt == getChatLength(id) - 1 and c.last == \"Player\" then c.opening = nil end\r\nout = out:gsub(\"\\2(%d+)\\2\", function(i) return held[tonumber(i)] end)\r\n\r\nif c.active and K.fightDone(c, pc) then c.active = false end\r\n\r\nlocal fixes = K.Fix.lines(c, pc, out)\r\nif #fixes > 0 then out = out .. \"\\n\" .. table.concat(fixes, \"\\n\") end\r\n\r\n\r\nif c.active then\r\nlocal bl = K.buffTurn(pc)\r\nif #bl > 0 then out = out .. \"\\n\" .. table.concat(bl, \"\\n\") end\r\nend\r\n\r\n\r\n\r\nif c.active and K.suggestOn(id) then\r\nout = out:gsub(\"\\n?%[OPT|[^%]]*%]\", \"\")\r\nlocal opts = K.fightOpts(c, pc)\r\nif #opts > 0 then out = out .. \"\\n\" .. table.concat(opts, \"\\n\") end\r\nend\r\nif c.active or wasActive then out = out .. \"\\n\" .. hpLine(c, pc) end\r\nif wasActive and not c.active then Ally.fightOver(pc) end\r\nif c.active then Feat.heroic(pc, sheet) end\r\nif c.active then K.foeTargets(c, pc, true) end\r\n\r\n\r\nif not c.active and #c.order > 0 and not c.xp_given then\r\nc.xp_given = true\r\nlocal sum, names = 0, {}\r\nfor _, name in ipairs(c.order) do\r\nlocal u = c.units[name]\r\nif u.side == \"enemy\" and u.hp <= 0 and MONSTERS[u.kind] then\r\nsum = sum + (u.xp or MONSTERS[u.kind].xp)\r\nnames[#names + 1] = name\r\nend\r\nend\r\nif sum > 0 and not pc.dead then\r\nev.reward = true\r\n\r\nif xpNext(pc) then\r\n\r\nlocal share = math.floor(sum / math.max(1, tonumber(c.party) or 1))\r\naddXP(pc, share)\r\nout = out .. \"\\n\" .. string.format(\"[XP|%d|combat: %s%s|auto|%s]\", share, table.concat(names, \", \"),\r\nshare < sum and string.format(\" (%d / %d)\", sum, c.party) or \"\", xpText(pc))\r\nend\r\nend\r\nend\r\nCond.expire(pc, clock)\r\n\r\n\r\nAlly.buffs(pc, clock)\r\nAlly.tick(pc, clock)\r\nK.buffConc(pc)\r\nif not c.active then K.concEndClear(pc) end\r\nK.summonsTick(pc, c, clock)\r\nK.heatTick(pc, sheet, clock)\r\nfor _, a in ipairs(Ally.list(pc)) do if not a.dead then K.heatTick(a, a.sheet, clock) end end\r\nK.MI.syncAll(pc, sheet)\r\nif pc.dead or pc.hp > 0 or not pc.stable then pc.wake = nil end\r\n\r\n\r\nif wasActive and not c.active and not c.endedAt then c.endedAt = clock.min end\r\nK.wakeDue(pc, c, clock)\r\nAlly.sync(pc)\r\npc.shop_log = nil\r\nlocal salt = tonumber(getChatVar(id, \"dnd_shop_salt\"))\r\nif not salt then\r\nsalt = math.random(1, 1000000)\r\nsetChatVar(id, \"dnd_shop_salt\", tostring(salt))\r\nend\r\nShop.refresh(pc, clock, salt)\r\nSpell.cur = nil\r\n\r\npc.pace = type(pc.pace) == \"table\" and pc.pace or {}\r\nfor k in pairs(ev) do pc.pace[k] = math.floor(len / 2) end\r\nout = out .. \"\\n\" .. statusLine(pc, clock)\r\nlocal key = Seed.newKey(id)\r\nout = out .. \"\\n<!--dseed:\" .. key .. \"-->\"\r\n\r\nif out ~= last.data then setChat(id, -1, out) end\r\n\r\n\r\n\r\n\r\nSeed.write(id, key, { sheet = sheet, pc = pc, combat = c, clock = clock, prev = prevKey })\r\n\r\nsetStateChanged(id, \"dnd_pc\", pc)\r\nsetStateChanged(id, \"dnd_turn_delta\", newChar and {} or turnDelta(pc0, pc))\r\nsetStateChanged(id, \"dnd_sheet\", sheet)\r\nsetStateChanged(id, \"dnd_combat\", c)\r\nsetStateChanged(id, \"dnd_clock\", clock)\r\nlocal als = K.aliasStr(pc.monAlias)\r\nlocal was = getChatVar(id, \"dnd_mon_alias\")\r\nif was == nil or was == \"null\" then was = \"\" end\r\nif als ~= was then setChatVar(id, \"dnd_mon_alias\", als) end\r\nK.aliasLoad(als)\r\nsetChatVar(id, \"dnd_seed_live\", key)\r\n\r\nlocal log = getState(id, \"dnd_bad_log\")\r\nif type(log) ~= \"table\" then log = {} end\r\nlocal turn = math.floor(len / 2)\r\nlocal kept = {}\r\nfor _, e in ipairs(log) do if type(e) == \"table\" and e[1] ~= turn then kept[#kept + 1] = e end end\r\nfor _, line in ipairs(bads) do kept[#kept + 1] = { turn, line } end\r\nwhile #kept > K.BAD_LOG_MAX do table.remove(kept, 1) end\r\nif #kept ~= #log or #bads > 0 then setStateChanged(id, \"dnd_bad_log\", kept) end\r\nsetChatVar(id, \"dnd_last_verify\", string.format(\"tags %d, ok %d, bad %d\", n, okN, badN)\r\n.. (getChatVar(id, \"dnd_debug_used\") == \"1\" and \" · 디버그 사용\" or \"\"))\r\nif getChatVar(id, \"dnd_opt_debug\") == \"1\" then\r\nsetState(id, \"dnd_last_bad\", bads)\r\nsetChatVar(id, \"dnd_perf_out\", string.format(\"%.0f\", (clockNow() - t0) * 1000))\r\nend\r\n\r\n\r\n\r\nend)\r\nif not ok then\r\nlocal prev = getChatVar(id, \"dnd_lua_error\")\r\nlocal had = prev and prev ~= \"\" and prev ~= \"null\"\r\nsetChatVar(id, \"dnd_lua_error\", (had and (prev .. \" / \") or \"\") .. tostring(err))\r\nend\r\nend)\r\n\r\n\r\n\r\nlocal WORD_KO = {\r\nPlayer = \"당신\",\r\nsuccess = \"성공\", failure = \"실패\", hit = \"명중\", miss = \"빗나감\", crit = \"치명타\",\r\nshort = \"짧은 휴식\", long = \"긴 휴식\", stable = \"안정\", dead = \"사망\",\r\nnuisance = \"방해형\", deadly = \"치명형\",\r\n}\r\n\r\n\r\n\r\nlocal function langKo()\r\nlocal ok, lang = pcall(cbs, \"{{metadata::lang}}\")\r\nlang = (ok and type(lang) == \"string\") and lang:lower() or \"\"\r\nreturn not lang:match(\"^%a%a\") or lang:sub(1, 2) == \"ko\"\r\nend\r\n\r\n\r\nlocal function monKo(v)\r\nif not K.MON_KO then return v end\r\nlocal m = MONSTERS[v]\r\nif m and m.ko then return m.ko end\r\nlocal kind, n = v:match(\"^(.-) (%d+)$\")\r\nm = kind and MONSTERS[kind]\r\nreturn (m and m.ko) and (m.ko .. \" \" .. n) or v\r\nend\r\n\r\n\r\n\r\nK.NOTE_NAMES = { \"Great Weapon Fighting\", \"Dark One's Blessing\", \"Relentless Endurance\", \"Sorcerous Restoration\", \"Lightning Absorption\",\r\n\"Three-Quarters Cover\", \"Arcane Recovery\", \"Natural Recovery\", \"Undead Fortitude\", \"Acid Absorption\", \"Savage Attacker\",\r\n\"Blessed Healer\", \"Potent Cantrip\", \"Uncanny Dodge\", \"Sorcery Points\", \"Half Cover\", \"Exhaustion\", \"Tireless\", \"Graze\" }\r\nfunction K.patEsc(s) return (s:gsub(\"[%^%$%(%)%%%.%[%]%*%+%-%?]\", \"%%%0\")) end\r\n\r\nlocal function toKo(v)\r\nif WORD_KO[v] then return WORD_KO[v] end\r\nif NAMES_KO[v] then return NAMES_KO[v] end\r\nlocal mk = monKo(v)\r\nif mk ~= v then return mk end\r\nlocal ab = v:match(\"^(%a+) save$\")\r\nif ab and NAMES_KO[ab] then return NAMES_KO[ab] .. \" 내성\" end\r\nlocal sign, name = v:match(\"^([+-])%s*(.+)$\")\r\nif sign and NAMES_KO[name] then return sign .. NAMES_KO[name] end\r\n\r\nlocal mi = (K.MI.maybe(v) and K.MI.ko(v)) or (sign and K.MI.maybe(name) and K.MI.ko(name) and (sign .. K.MI.ko(name)))\r\nif mi then return mi end\r\n\r\n\r\nif K.MON_KO then\r\nv = v:gsub(\"(%u[%a%-' ]-) (%d+)\", function(kind, n)\r\nlocal pre = \"\"\r\nwhile not MONSTERS[kind] do\r\nlocal a, b = kind:match(\"^(%S+ )(.+)$\")\r\nif not a then return nil end\r\npre, kind = pre .. a, b\r\nend\r\nreturn pre .. monKo(kind .. \" \" .. n)\r\nend)\r\nend\r\nlocal out = v:gsub(\"%f[%w]Player%f[%W]\", \"당신\"):gsub(\"Summoned \", \"소환된 \")\r\n:gsub(\"(%d+) successes, (%d+) failures\", \"성공 %1 · 실패 %2\")\r\n:gsub(\"Hit Point Dice\", \"생명력 주사위\"):gsub(\"^combat: \", \"전투: \"):gsub(\"%->\", \"→\")\r\n:gsub(\"%(resisted%)\", \"(저항: 절반)\"):gsub(\"%(immune%)\", \"(면역: 0)\"):gsub(\"%(vulnerable%)\", \"(취약: 두 배)\")\r\n\r\n:gsub(\"%(Pact of the Blade: ([^()]+)%)\", function(n) return \"(칼날의 계약: \" .. koName(trim(n)) .. \")\" end)\r\n:gsub(\"([%a' ]+) %(pact weapon%)\", function(n) return \"계약 무기: \" .. koName(trim(n)) end)\r\n:gsub(\"%(Eldritch Smite: (%a+) Slot (%d) (%d+) left%)\", function(k, l, n) return \"(\" .. (NAMES_KO[\"Eldritch Smite\"] or \"Eldritch Smite\") .. \": \" .. (k == \"Pact\" and \"계약 \" or \"\") .. l .. \"레벨 슬롯 \" .. n .. \"개 남음)\" end)\r\n\r\n:gsub(\"%(Prismatic Spray ([^()]-)%)\", function(b) return \"(\" .. koName(\"Prismatic Spray\") .. \" \" .. K.prismKo(b) .. \")\" end)\r\n:gsub(\"%((%a+) (%d+), (%a+) (%d+)%)\", function(a, x, b, y)\r\nlocal ka, kb = K.DMG_KO and K.DMG_KO[a], K.DMG_KO and K.DMG_KO[b]\r\nif ka and kb then return \"(\" .. ka .. \" \" .. x .. \", \" .. kb .. \" \" .. y .. \")\" end end)\r\n:gsub(\"%(Indigo: \", \"(남색 광선: \"):gsub(\"%(sent to another plane: out of this fight%)\", \"(다른 세계로 날아감: 이 싸움에서 빠짐)\")\r\n:gsub(\"%(%+(%d+): a priest's healing, ([^;%)]-); paid (%d+) gp, ([^%)]-) left%)\", \"(+%1: 사제의 치유, %2, 금화 %3 냄, %4 남음)\")\r\n:gsub(\"%(%+(%d+): a priest's healing, ([^;%)]-); free%)\", \"(+%1: 사제의 치유, %2, 대가 없음)\")\r\n:gsub(\"%(%+(%d+): a priest's healing, ([^;%)]-)%)\", \"(+%1: 사제의 치유, %2)\")\r\n:gsub(\"%(%+(%d+): first aid, ([^%)]-)%)\", \"(+%1: 응급 치료, %2)\")\r\n\r\n:gsub(\"%(resistance ignored: ([^%)]+)%)\", function(n) return \"(저항 무시: \" .. (NAMES_KO[n] or (n == \"Elemental Adept\" and \"원소 숙련자\") or n) .. \")\" end)\r\n:gsub(\"%(resisted: underwater%)\", \"(물속 저항: 절반)\")\r\n\r\n:gsub(\"immune %(([^%)]+)%)\", function(n) return \"면역 (\" .. (NAMES_KO[n] or n) .. \")\" end)\r\n:gsub(\"temporary HP (%d+)\", \"임시 생명력 %1\")\r\n\r\n:gsub(\"%(Legendary Resistance, (%d+) left%)\", \"(전설 저항, %1회 남음)\"):gsub(\"%(Evasion%)\", \"(회피기동)\")\r\n:gsub(\"%(no Legendary Resistance against damage alone%)\", \"(피해만 주는 효과라 전설 저항을 쓰지 않음)\")\r\n:gsub(\"%(Greater Magic Resistance%)\", \"(상급 마법 저항)\")\r\n:gsub(\"%(([%a ]+): Advantage, Lua's second d20 (%d+)%)\", function(n, d) return \"(\" .. (n == \"willing\" and \"동의\" or NAMES_KO[n] or n) .. \": 이점, Lua의 두 번째 d20 \" .. d .. \")\" end)\r\n\r\n:gsub(\"%(Shield: %+(%d+) AC until its turn%)\", \"(방패: 자기 차례까지 방어도 +%1)\")\r\n:gsub(\"%(([%a' ]+): %+(%d+) AC%)\", function(n, v) return \"(\" .. (NAMES_KO[n] or n) .. \": 방어도 +\" .. v .. \")\" end)\r\n\r\n:gsub(\"([^;%(]-)'s next attack roll hits\", \"%1의 다음 공격은 반드시 명중\")\r\n:gsub(\"([%+%-]%d+) to ([^;%(]-)'s next attack roll\", \"%2의 다음 명중 굴림 %1\")\r\n:gsub(\"([^;%(]-)'s next hit deals x(%S+) damage\", \"%1의 다음 명중 피해 ×%2\")\r\n:gsub(\"([%+%-]%d+) AC for ([^;,%(]-) until its next turn\", function(v, w)\r\nreturn trim(w) .. \"의 방어도 \" .. v .. \"(다음 턴까지)\" end)\r\n:gsub(\"([%+%-]%d+) AC against the next attack on ([^;%(]+)\", function(v, w)\r\nlocal tw = trim(w); return tw .. K.josa(tw, \"을\", \"를\") .. \" 노리는 다음 공격에 방어도 \" .. v .. (w:match(\"%s$\") and \" \" or \"\") end)\r\n:gsub(\"the next hit on ([^;]-) takes (%S+) less %(Lua rolls it and takes it off: write the damage before it%)\",\r\nfunction(w, d) return w .. K.josa(w, \"이\", \"가\") .. \" 받는 다음 명중 피해 \" .. d .. \"만큼 줄임(Lua가 굴려 뺌)\" end)\r\n:gsub(\"%(([^():]-): teleported out of the way, no damage%)\", function(n) return \"(\" .. koName(trim(n)) .. \": 피해 없이 피함)\" end)\r\n:gsub(\"the next attack on ([^;%(]-) misses %(a Critical Hit too%)\", function(w) local tw = trim(w); return tw .. K.josa(tw, \"을\", \"를\") .. \" 노리는 다음 공격은 빗나감(치명타도)\" end)\r\n:gsub(\"%((.-): misses%)\", function(n) return \"(\" .. (NAMES_KO[n] or n) .. \": 빗나감)\" end)\r\n:gsub(\"%s?%(Lua counts it%)\", \" (Lua가 셈)\")\r\n\r\n:gsub(\": failed%)\", \": 실패)\")\r\n:gsub(\"Resistance to (%a+) this turn\", function(t) return ((K.DMG_KO and K.DMG_KO[t]) or t) .. \" 저항(이번 턴)\" end)\r\n:gsub(\"%(([%a' ]+) took (%d+), (%d+) left%)\", function(n, a, b)\r\nlocal k = NAMES_KO[trim(n)] or trim(n); return \"(\" .. k .. K.josa(k, \"이\", \"가\") .. \" \" .. a .. \" 막음, \" .. b .. \" 남음)\" end)\r\n:gsub(\"; gone: \", \"; 사라짐: \")\r\n:gsub(\"Spell Slot (%d) (%d+/%d+)\", \"%1레벨 슬롯 %2\"):gsub(\"Pact Slot (%d) (%d+/%d+)\", \"계약 %1레벨 슬롯 %2\")\r\n:gsub(\"%(([%a' ]+): ([%+%-]%d+)%)\", function(n, v) return \"(\" .. (NAMES_KO[n] or n) .. \": \" .. v .. \")\" end)\r\n:gsub(\"%(([%a' ]+): x(%S+)%)\", function(n, v) return \"(\" .. (NAMES_KO[n] or n) .. \": ×\" .. v .. \")\" end)\r\n:gsub(\"%(([%a' ]+): ([%a' ]+) (%d+) left%)\", function(n, r, v) return \"(\" .. (NAMES_KO[n] or n) .. \": \" .. (NAMES_KO[r] or r) .. \" \" .. v .. \" 남음)\" end)\r\n:gsub(\"%(as (%a+)%)\", function(t) local k = K.DMG_KO and K.DMG_KO[t]; return \"(\" .. (k or t) .. \" 피해로)\" end)\r\n:gsub(\"%(([%a' ]+): no Advantage, the first d20%)\", function(n) return \"(\" .. (NAMES_KO[n] or n) .. \": 이점 없음, 첫 d20)\" end)\r\n:gsub(\"temporary HP (%S+ %d+)\", \"임시 생명력 %1\")\r\n:gsub(\"([%a'][%a' ]-) (%d+/%d+)\", function(n, v) local k = NAMES_KO[trim(n)]; if k then return k .. \" \" .. v end end)\r\n:gsub(\"%(Reflective Carapace%)\", \"(반사 갑각)\")\r\n:gsub(\"%(Split: (.-) appears; each has (%d+) HP%)\", \"(분열: %1 등장, 둘 다 생명력 %2)\")\r\n:gsub(\"%(Loathsome Limbs: (.-) falls off and fights on; the troll has Exhaustion (%d+)%)\", \"(끔찍한 사지: %1 떨어져 나와 싸움, 트롤은 탈진 %2)\")\r\n:gsub(\"%(its limbs grow back%)\", \"(사지가 다시 자람)\")\r\n:gsub(\"%(AC %+(%d+) until the end of its giver's next turn%)\", \"(건넨 쪽의 다음 차례 끝까지 방어도 +%1)\")\r\n:gsub(\"%(temporary HP %-(%d+)%)\", \"(임시 생명력 -%1)\")\r\n\r\n:gsub(\"%(its form next: a BUFF with the Beast%)\", \"(다음은 BUFF로 야수 모습)\")\r\n:gsub(\"%(([^:()]+) ends: its Temporary HP are gone%)\", function(n) return \"(\" .. koName(trim(n)) .. \" 끝남: 임시 생명력이 다 닳음)\" end)\r\n:gsub(\"%(([^:()]+) ends: back to ([^()]+)%)\", function(n, k) local kk = koName(trim(k)); return \"(\" .. koName(trim(n)) .. \" 끝남: \" .. kk .. K.josa(kk, \"으로\", \"로\") .. \" 돌아옴)\" end)\r\n:gsub(\"([^%[|]-) is a ([%a' %-]+) %(AC (%d+), (%d+) temporary HP%)\", function(w, b, ac, t)\r\nlocal k, kb = Ally.ko(trim(w)), koName(trim(b)); return k .. K.josa(k, \"이\", \"가\") .. \" \" .. kb .. K.josa(kb, \"으로\", \"로\") .. \" 변함 (방어도 \" .. ac .. \", 임시 생명력 \" .. t .. \")\" end)\r\n:gsub(\"%(Sundering Blow: %+5%)\", \"(가르는 일격: +5)\"):gsub(\"%(Cutting Words%)\", \"(\" .. (NAMES_KO[\"Cutting Words\"] or \"Cutting Words\") .. \")\")\r\n:gsub(\"%(([^:()]+): none on a success%)\", function(n) return \"(\" .. koName(trim(n)) .. \": 성공해서 피해 없음)\" end)\r\n:gsub(\"%((%d+) left to give%)\", \"(나눠 줄 %1 남음)\")\r\n\r\n:gsub(\"%(under ([^:()]+): ([^()]+)%)\", function(n, list) return \"(\" .. koName(trim(n)) .. \": \" .. K.foeFxKo(list) .. \")\" end)\r\n:gsub(\"%(no longer under ([^()]+)%)\", function(n) return \"(\" .. koName(trim(n)) .. \" 풀림)\" end)\r\n:gsub(\"%(pushed up to 15 ft away%)\", \"(15피트까지 밀려남)\")\r\n:gsub(\"%(([^:()]+): ([^():]-) now ([%a, ]+)%)\", function(sn, who, cs) return \"(\" .. koName(trim(sn)) .. \": \" .. who .. \" 이제 \" .. cs:gsub(\"%a+\", function(cn) return NAMES_KO[cn] or cn end):gsub(\", \", \"·\") .. \")\" end)\r\n:gsub(\"%(Dazed: on its next turn only one of move, action or Bonus Action%)\", \"(멍해짐: 다음 턴에 이동·행동·추가 행동 중 하나만)\")\r\n:gsub(\"%(([^:()]+): it picks another target or loses the attack%)\", function(n) return \"(\" .. koName(trim(n)) .. \": 다른 대상을 고르거나 공격을 잃음)\" end)\r\n:gsub(\"%(([^:()]+) ends: it attacked%)\", function(n) return \"(공격해서 \" .. koName(trim(n)) .. \" 끝남)\" end)\r\n\r\n:gsub(\"%(now ([%a, ]+)%)\", function(cs) return \"(이제 \" .. cs:gsub(\"%a+\", function(cn) return NAMES_KO[cn] or cn end):gsub(\", \", \"·\") .. \")\" end)\r\n\r\n:gsub(\"%(Mirror Image: d6 ([%d,]+), a duplicate is hit instead, (%d+) left%)\", function(d, n) return \"(\" .. (NAMES_KO[\"Mirror Image\"] or \"Mirror Image\") .. \": d6 \" .. d .. \", 분신이 대신 맞음, \" .. n .. \"개 남음)\" end)\r\n:gsub(\"%(Mirror Image: d6 ([%d,]+), no duplicate%)\", function(d) return \"(\" .. (NAMES_KO[\"Mirror Image\"] or \"Mirror Image\") .. \": d6 \" .. d .. \", 분신이 막지 못함)\" end)\r\n:gsub(\"%(no longer ([%a, ]+)%)\", function(cs) return \"(\" .. cs:gsub(\"%a+\", function(cn) return NAMES_KO[cn] or cn end) .. \" 풀림)\" end)\r\n:gsub(\"%((%u%a+): fails Strength and Dexterity saves%)\", function(cn) return \"(\" .. (NAMES_KO[cn] or cn) .. \": 근력·민첩 내성 자동 실패)\" end)\r\n:gsub(\"%((%u%a+): a hit within 5 ft is a Critical Hit%)\", function(cn) return \"(\" .. (NAMES_KO[cn] or cn) .. \": 5피트 안 명중은 치명타)\" end)\r\n:gsub(\"%(wakes up%)\", \"(깨어남)\")\r\n:gsub(\"%(not in COMBAT STATUS: taken as written%)\", \"(스탯 블록 밖 효과: 쓴 대로)\"):gsub(\"%(Poisoned: taken as written%)\", \"(중독: 쓴 대로)\")\r\n:gsub(\"(%d+) gp\", \"금화 %1\"):gsub(\"(%d+) sp\", \"은화 %1\"):gsub(\"(%d+) cp\", \"동화 %1\")\r\n\r\n:gsub(\"%(temporary HP%)\", \"(임시 생명력)\"):gsub(\"(%d+) temporary HP\", \"임시 생명력 %1\"):gsub(\": slots \", \": 슬롯 \")\r\n\r\n:gsub(\"HP maximum back\", \"생명력 최대치 회복\"):gsub(\"arousal maximum back\", \"흥분도 최대치 회복\")\r\n:gsub(\"%(([%a' ]+): the hit took (%d+)%)\", function(n, v) return \"(\" .. (NAMES_KO[n] or n) .. \": 맞은 피해 \" .. v .. \"까지만)\" end)\r\n:gsub(\"([%a][%a, ]*) back\", function(list)\r\nlocal AB = { Strength = \"근력\", Dexterity = \"민첩\", Constitution = \"건강\", Intelligence = \"지능\", Wisdom = \"지혜\", Charisma = \"매력\" }\r\nlocal o = {}\r\nfor w in list:gmatch(\"%a+\") do if not AB[w] then return nil end; o[#o + 1] = AB[w] end\r\nreturn table.concat(o, \"·\") .. \" 회복\"\r\nend)\r\n\r\n:gsub(\"%(massive damage%)\", \"(대량 피해)\"):gsub(\"^dead%f[%A]\", \"사망\"):gsub(\"%(당신 Stable%)\", \"(당신 안정)\")\r\n\r\n\r\n:gsub(\"%(turned: [^%)]*%)\", \"(퇴치됨: 1분 동안 달아남, 다른 피해를 받으면 풀림)\")\r\n:gsub(\"%(covered in oil%)\", \"(기름 범벅)\"):gsub(\"%(pushed 5 ft or Prone%)\", \"(5피트 밀림 또는 넘어진 상태)\")\r\n:gsub(\"%(burning: [^%)]*%)\", \"(불붙음: 턴 시작마다 화염 1d4)\"):gsub(\"%(lands Prone%)\", \"(넘어진 상태로 떨어짐)\")\r\n:gsub(\"%(not a Fiend or Undead%)\", \"(악마나 언데드가 아님)\")\r\n:gsub(\"%(Basic Poison spent%)\", \"(기본 독 씀)\")\r\n:gsub(\"%(it regurgitates what it swallowed%)\", \"(삼킨 것을 모두 토해 냄)\")\r\n:gsub(\"%(swallowed by (.-)%)\", \"(%1에게 삼켜짐)\")\r\n:gsub(\"%(Survivor: (%d+) counts as 20%)\", \"(생존의 대가: %1도 20으로)\")\r\n:gsub(\"%(Preserve Life: (%d+) left%)\", \"(생명 보존: %1 남음)\"):gsub(\"%(Death Ward: 1 HP%)\", \"(죽음 방비: 생명력 1)\")\r\n:gsub(\"%(Relentless Rage failed: \", \"(끈질긴 격노 실패: \"):gsub(\"%(Relentless Rage: \", \"(끈질긴 격노: \")\r\n:gsub(\"%(Heroic Inspiration \", \"(영웅적 영감 \"):gsub(\"vs DC (%d+)\", \"vs 난이도 %1\")\r\n\r\nif out:find(\"[%(:]\") or out:find(\"%a %d\") then\r\n\r\n\r\nif not K.noteNames or K.noteNames.gen ~= K.PACK.gen then\r\nlocal l = {}\r\nfor _, en in ipairs(K.NOTE_NAMES) do l[#l + 1] = en end\r\nfor _, en in ipairs(K.PACK.nn) do l[#l + 1] = en end\r\ntable.sort(l, function(x, y) if #x ~= #y then return #x > #y end return x < y end)\r\nK.noteNames = { gen = K.PACK.gen, list = l }\r\nend\r\n\r\n\r\nlocal held = {}\r\nfor _, en in ipairs(K.noteNames.list) do\r\nif out:find(en, 1, true) and NAMES_KO[en] then\r\nlocal pat = K.patEsc(en)\r\nif K.PACK.nnw and K.PACK.nnw[en] then\r\npat = (en:find(\"^%w\") and \"%f[%w]\" or \"\") .. pat .. (en:find(\"%w$\") and \"%f[%W]\" or \"\")\r\nend\r\nout = out:gsub(pat, function() held[#held + 1] = NAMES_KO[en]; return \"\\1\" .. #held .. \"\\2\" end)\r\nend\r\nend\r\nif #held > 0 then out = out:gsub(\"\\1(%d+)\\2\", function(i) return held[tonumber(i)] end) end\r\nend\r\nreturn (out:gsub(\"%f[%a]HP%f[%A]\", \"생명력\"))\r\nend\r\nK.toKo = toKo\r\n\r\n\r\nfunction K.useLeftKo(left)\r\nlocal v = tostring(left or \"\")\r\nif v == \"end\" then return \"끝냄\" end\r\n\r\nif v == \"no uses to spend\" then return \"쓸 횟수가 없는 기능입니다\" end\r\nif v == \"pact weapon gone\" then return \"계약 무기를 거두었습니다\" end\r\nif v == \"already spent by the hit\" then return \"명중 때 슬롯을 이미 썼습니다\" end\r\nv = v:gsub(\"^on ([^,]+),\", \"%1에게 걸림,\")\r\n\r\nv = v:gsub(\"^([^,;]-) on$\", \"%1 켜짐\"):gsub(\"^([^,;]-) on( %()\", \"%1 켜짐%2\"):gsub(\"^([^,;]-) on,\", \"%1 켜짐,\")\r\nv = v:gsub(\"^%+(%d+) to ([%a ]-) for (.-) until round (%d+)\", function(n, on, who, r)\r\nlocal what = on:gsub(\"attack\", \"명중\"):gsub(\"save\", \"내성\"):gsub(\" and \", \"·\")\r\nreturn who:gsub(\", \", \"·\") .. \": \" .. what .. \" +\" .. n .. \"(\" .. r .. \"라운드까지)\"\r\nend)\r\nv = v:gsub(\"(%d+)/(%d+) charges\", \"충전 %1/%2\")\r\nv = v:gsub(\"; ([^;]-) is ([%a ]+)$\", function(who, cs)\r\nreturn \"; \" .. who .. \": \" .. cs:gsub(\"%a+\", function(cn) return cn == \"and\" and \"·\" or (NAMES_KO[cn] or cn) end):gsub(\" · \", \"·\")\r\nend)\r\nreturn toKo(v)\r\nend\r\n\r\nlocal function esc(v)\r\nreturn (tostring(v):gsub(\"&\", \"&amp;\"):gsub(\"<\", \"&lt;\"):gsub(\">\", \"&gt;\"):gsub('\"', \"&quot;\"))\r\nend\r\n\r\n\r\n\r\nK.R_GOOD = \"color:#c9eaa9;background:rgba(120,180,80,.2)\"\r\nK.R_BAD = \"color:#ffb3aa;background:rgba(208,87,75,.22)\"\r\nfunction K.resChip(r, foe)\r\nr = r or \"\"\r\nlocal st = \"\"\r\nif foe and (r == \"실패\" or r == \"failure\") then st = ' style=\"' .. K.R_GOOD .. '\"'\r\nelseif foe and (r == \"성공\" or r == \"success\") then st = ' style=\"' .. K.R_BAD .. '\"' end\r\nreturn '<b class=\"dnd-r\" data-r=\"' .. esc(r) .. '\"' .. st .. '>' .. esc(r) .. '</b>'\r\nend\r\n\r\n\r\n\r\n\r\nK.D20_MODE = { adv = \"이점\", dis = \"불리점\", luck = \"행운아\", insp = \"영웅적 영감\", bi = \"바드 영감\" }\r\n\r\nfor mode, e in pairs(K.FX_MODE) do K.D20_MODE[mode] = K.D20_MODE[mode] or NAMES_KO[e.src] or e.src end\r\nK.D4_KO = { bless = \"축복\", guidance = \"안내\", [\"축복\"] = \"축복\", [\"안내\"] = \"안내\" }\r\n\r\n\r\nfunction K.d20Ko(field)\r\nlocal s0 = tostring(field or \"\")\r\nlocal m, rest = s0:match(\"^%s*(%a+)%s+(.+)$\")\r\nif m and K.D20_MODE[m:lower()] then s0 = K.D20_MODE[m:lower()] .. \" \" .. rest end\r\nreturn (s0:gsub(\"(%a+)\", function(w) return K.D4_KO[w:lower()] or w end))\r\nend\r\nfunction K.d20Html(field)\r\nfield = tostring(field or \"\")\r\nlocal function die(n, off)\r\nreturn '<span class=\"dnd-d20' .. (off and \" off\" or \"\") .. '\" data-n=\"' .. n .. '\">' .. n .. '</span>'\r\nend\r\nlocal tail = \"\"\r\nlocal pre, word, d4 = field:match(\"^(.-%d)%s*%+?%s*([^%d%s,%+]+)%s*(%d+)%s*$\")\r\nif word and K.D4_KO[word:lower()] then\r\nfield, tail = pre, \" + \" .. K.D4_KO[word:lower()] .. \" \" .. d4\r\nend\r\nlocal mode, a, b = field:match(\"^%s*(%a+)%s+(%d+)%s*,%s*(%d+)%s*$\")\r\nif mode and K.D20_MODE[mode] then\r\nif mode == \"bi\" or (K.FX_MODE[mode] and K.FX_MODE[mode].t == \"die_bonus\") then return die(a) .. \" + \" .. K.D20_MODE[mode] .. \" \" .. b .. tail end\r\nlocal x, y = tonumber(a), tonumber(b)\r\nlocal useFirst = (mode == \"adv\" and x >= y) or (mode == \"dis\" and x <= y)\r\nreturn K.D20_MODE[mode] .. \" \" .. die(a, not useFirst) .. die(b, useFirst) .. tail\r\nend\r\nlocal n = field:match(\"^%s*(%d+)%s*$\")\r\nif n then return die(n) .. tail end\r\nreturn esc(field) .. tail\r\nend\r\n\r\n\r\n\r\nfunction K.sfRow(parts, vd)\r\nlocal o = {}\r\nfor i = 1, 4 do\r\nlocal p = parts[i]\r\nif p and p[2] and p[2] ~= \"\" then\r\n\r\n\r\nlocal plain = (p[1] .. p[2]):gsub(\"<[^>]+>\", \"\")\r\nlocal long = (utf8.len(plain) or #plain) > 24\r\no[#o + 1] = '<span class=\"dnd-sf\"' .. (long and ' style=\"white-space:normal\"' or \"\") .. '><i>' .. p[1] .. '</i>' .. p[2] .. '</span>'\r\nend\r\nend\r\nreturn '<div class=\"dnd-sub dnd-sfs\">' .. table.concat(o) .. (vd or \"\") .. '</div>'\r\nend\r\n\r\n\r\nfunction K.sfDamage(formula, rolls, label)\r\nformula, rolls = trim(formula or \"\"), trim(rolls or \"\")\r\nif formula == \"\" or formula == \"-\" then return nil end\r\nreturn { label or \"피해\", esc(formula) .. ((rolls ~= \"\" and rolls ~= \"-\") and (\" (주사위 \" .. esc(rolls) .. \")\") or \"\") }\r\nend\r\n\r\n\r\n\r\nfunction K.chip(text, small)\r\nreturn '<span class=\"dnd-sp on\">' .. esc(text) .. (small and (\"<small>\" .. esc(small) .. \"</small>\") or \"\") .. \"</span>\"\r\nend\r\nfunction K.chipRow(label, chips)\r\nif #chips == 0 then return \"\" end\r\nreturn '<div class=\"dnd-cr\"><i>' .. esc(label) .. '</i><span class=\"dnd-crs\">' .. table.concat(chips) .. \"</span></div>\"\r\nend\r\n\r\n\r\nfunction K.isFixed(tag, rest)\r\nlocal f = split(rest)\r\nlocal vi\r\nfor i, v in ipairs(f) do if v == \"ok\" or v:sub(1, 4) == \"bad:\" then vi = i break end end\r\nif not vi or f[vi]:sub(1, 4) ~= \"bad:\" then return false end\r\nlocal why = f[vi]\r\nif tag == \"LOOT\" then\r\nreturn not (why == \"bad:name\" or why:find(\"an SRD item\", 1, true) or why:find(\"one LOOT of grade\", 1, true))\r\nend\r\nif why:find(\"ignored\", 1, true) or why:find(\"unknown\", 1, true) or why:find(\"no combat\", 1, true) then return false end\r\n\r\n\r\nif tag == \"EQUIP\" or tag == \"UNEQUIP\" or tag == \"ATTUNE\" or tag == \"CRAFT\" then return false end\r\nfor _, w in ipairs({ \"bad:write \", \"no uses left\", \"not in items\", \"not enough\", \"not a spellcaster\", \"not during a fight\", \"the spell fades\" }) do\r\nif why:find(w, 1, true) then return false end\r\nend\r\nif tag == \"COMBAT\" then return true end\r\nlocal res = trim(f[vi + 1] or \"\")\r\nreturn res ~= \"\" and res ~= \"-\"\r\nend\r\n\r\n\r\n\r\n\r\nK.FIX_AT = { ATTACK = { res = 6, dmg = 9, formula = 7, bonus = 4, ac = 5, d20 = 3, dice = 8 },\r\nSAVE = { res = 6, dmg = 9, formula = 7, bonus = 4, dc = 5, d20 = 3, dice = 8 },\r\nHAZARD = { res = 7, dmg = 10, formula = 8, bonus = 5, dc = 6, d20 = 4, dice = 9 },\r\nTRAP = { res = 6, dmg = 9, formula = 7, bonus = 4, dc = 5, d20 = 3, dice = 8 },\r\nDAMAGE = { dmg = 4, formula = 2, dice = 3 }, HEAL = { dmg = 5, formula = 3, dice = 4 },\r\nCHECK = { res = 5, bonus = 3, dc = 4, d20 = 2 }, DEATH = { res = 2, d20 = 1 } }\r\nfunction K.fixShown(tag, rest)\r\nlocal at = K.FIX_AT[tag]\r\nif not at then return rest end\r\nlocal f = split(rest)\r\nlocal vi\r\nfor i, v in ipairs(f) do if v:sub(1, 4) == \"bad:\" then vi = i break end end\r\nif not vi then return rest end\r\nlocal function set(k, v) if v and at[k] and at[k] < vi then f[at[k]] = v end end\r\nfor part in (f[vi]:sub(5) .. \";\"):gmatch(\"([^;]*);\") do\r\npart = trim(part)\r\nset(\"res\", part:match(\"^result%->(%a+)$\"))\r\nset(\"dmg\", part:match(\"^damage .-%->(%-?%d+)\") or part:match(\"^amount .-%->(%-?%d+)\"))\r\nset(\"formula\", part:match(\"^formula .-%->(.+)$\"))\r\nset(\"bonus\", part:match(\"^hit .-%->([%+%-]%d+)$\") or part:match(\"^bonus .-%->([%+%-]%d+)$\"))\r\nset(\"ac\", part:match(\"^AC .-%->(%d+)\"))\r\nset(\"dc\", part:match(\"^DC .-%->(%d+)\"))\r\nset(\"d20\", part:match(\"^Lua d20 (.+)$\"))\r\nlocal dice = part:match(\"^Lua dice (.+)$\")\r\nset(\"dice\", dice)\r\n\r\nlocal q = dice == \"-\" and at.formula and parseFormula(f[at.formula] or \"\")\r\nif q and #q.dice > 0 then set(\"formula\", \"-\") end\r\nend\r\nreturn table.concat(f, \"|\")\r\nend\r\n\r\nfunction K.vdHtml(verdict)\r\nreturn verdict == \"\" and \"검증 전\" or ('<span class=\"dnd-vd\">Lua ' .. esc(verdict) .. \"</span>\")\r\nend\r\n\r\n\r\nfunction K.acdc(s)\r\nreturn (s:gsub(\"%f[%a]AC%f[%A]\", \"방어도\"):gsub(\"%f[%a]DC%f[%A]\", \"난이도\"))\r\nend\r\n\r\n\r\nK.WHY_R = { hit = \"명중\", miss = \"빗나감\", crit = \"치명타\", success = \"성공\", failure = \"실패\" }\r\nK.AB3_KO = { STR = \"근력\", DEX = \"민첩\", CON = \"건강\", INT = \"지능\", WIS = \"지혜\", CHA = \"매력\" }\r\nfunction K.whyKo(s)\r\n\r\nfor am in pairs(K.AMMO) do\r\nlocal ko = NAMES_KO[am] or am\r\ns = s:gsub(\"%f[%a]no \" .. am .. \"%f[%A]\", ko .. K.josa(ko, \"이\", \"가\") .. \" 없습니다\")\r\nend\r\n\r\ns = s:gsub(\"bonus ([%u, ]-moved to %u+[^%(;]*) %(([^:;]-): ([%u, ]+)%)\", function(mv, bg, list)\r\nlocal m2 = mv:gsub(\"(%u%u%u) moved to (%u%u%u)\", function(a, b) return (K.AB3_KO[a] or a) .. \" → \" .. (K.AB3_KO[b] or b) end)\r\nlocal l2 = list:gsub(\"%u%u%u\", function(a) return K.AB3_KO[a] or a end):gsub(\", \", \"·\")\r\nreturn \"능력치 보너스 \" .. m2 .. \" (\" .. koName(trim(bg)) .. \" 배경은 \" .. l2 .. \"만)\"\r\nend)\r\n:gsub(\"scores before the bonus ([%d,]+)\", \"보너스 넣기 전 능력치 %1\")\r\n\r\ns = s:gsub(\"([^;]-): only while ([^;]-) is on\", function(n, m) return koName(trim(n)) .. \": \" .. koName(trim(m)) .. \" 켜져 있을 때만\" end)\r\n:gsub(\"([^;]-): only with ([^;]-) chosen\", function(n, m) return koName(trim(n)) .. \": \" .. koName(trim(m)) .. \" 골랐을 때만\" end)\r\n:gsub(\"([^;]-): from level (%d+)\", function(n, l) return koName(trim(n)) .. \": \" .. l .. \"레벨부터\" end)\r\n:gsub(\"([^;]-) was teleported away by ([^;]-) %(its save failed%)\", function(n, sp)\r\nlocal k = Ally.ko(trim(n)); return k .. K.josa(k, \"은\", \"는\") .. \" \" .. koName(trim(sp)) .. \"으로 사라짐(내성 실패)\" end)\r\n:gsub(\"([^;]-) is cast in place of this climax save %(its CAST later in this reply%)\", function(n)\r\nreturn koName(trim(n)) .. \"으로 절정 내성을 대신함(뒤의 CAST)\" end)\r\n:gsub(\"([^;]-): once for each healing spell cast with a slot in this reply, after its CAST\", function(n)\r\nreturn koName(trim(n)) .. \": 이번 답에서 슬롯으로 쓴 회복 주문마다 한 번(그 주문의 CAST 뒤)\" end)\r\n\r\ns = s:gsub(\";%s*Lua d20 [^;]*\", \"\"):gsub(\";%s*Lua dice [^;]*\", \"\"):gsub(\"^%s*Lua d20 [^;]*;?\", \"\"):gsub(\"^%s*Lua dice [^;]*;?\", \"\")\r\n\r\n\r\nlocal parts, n = {}, 0\r\ns = s:gsub(\"%-&gt;\", \"\u0001\"):gsub(\"&gt;\", \"\\5\"):gsub(\"&lt;\", \"\\6\")\r\nlocal function die(part) local z = part:match(\"^%s*d(%d+) [^;]-\u0001%-?%d+%s*$\"); return z and z ~= \"20\" end\r\nfor part in (s .. \";\"):gmatch(\"([^;]*);\") do\r\nparts[#parts + 1] = part\r\nif die(part) then n = n + 1 end\r\nend\r\nif n >= 3 then\r\nlocal o, put = {}, false\r\nfor _, part in ipairs(parts) do\r\nif die(part) then\r\nif not put then put = true; o[#o + 1] = \"dice to the pool \" .. n end\r\nelseif part ~= \"\" then\r\no[#o + 1] = part\r\nend\r\nend\r\ns = table.concat(o, \";\")\r\nend\r\ns = s:gsub(\"\u0001\", \"-&gt;\")\r\nreturn (s:gsub(\"%f[%a]result (%a+)%-&gt;(%a+)\", function(w, r) return \"결과 \" .. (K.WHY_R[w:lower()] or w) .. \" → \" .. (K.WHY_R[r] or r) end)\r\n:gsub(\"result%-&gt;(%a+)\", function(r) return \"결과 → \" .. (K.WHY_R[r] or r) end)\r\n:gsub(\"%f[%a]damage (.-)%-&gt;\", \"피해 %1 → \"):gsub(\"%f[%a]amount (%S+)%-&gt;\", \"회복량 %1 → \")\r\n:gsub(\"%f[%a]formula (%S*)%-&gt;\", \"공식 %1 → \"):gsub(\"%f[%a]bonus (%S+)%-&gt;\", \"보너스 %1 → \")\r\n:gsub(\"%f[%a]hit ([%+%-]%d+)%-&gt;\", \"명중 보너스 %1 → \")\r\n:gsub(\"%f[%w](d%d+) pool empty\", \"%1 주사위가 바닥나 Lua가 굴림\")\r\n:gsub(\"dice to the pool (%d+)\", \"주사위 %1개를 풀 순서대로\")\r\n:gsub(\"same roll for every target: \", \"모든 대상에 같은 굴림: \"):gsub(\"same roll for each one it catches: \", \"맞은 모두에게 같은 굴림: \")\r\n:gsub(\"attacker is down\", \"공격자가 쓰러져 있음\"):gsub(\"not an enemy in this fight\", \"이 싸움의 적이 아님\")\r\n\r\n:gsub(\"([^;]-) failed its save against the ward on ([^;:]-): another target, or the attack is lost\", function(w, t)\r\nlocal a, b = Ally.ko(trim(w)), Ally.ko(trim(t)); return a .. K.josa(a, \"은\", \"는\") .. \" \" .. b .. \"에게 걸린 보호에 대한 내성에 실패: 다른 대상을 고르거나 공격을 잃음\" end)\r\n:gsub(\"([^;]-) is ([%a' ]+) by ([^;:]-): it can't attack its charmer\", function(w, cn, t)\r\nlocal a, b = Ally.ko(trim(w)), Ally.ko(trim(t)); return a .. K.josa(a, \"은\", \"는\") .. \" \" .. b .. \"에게 \" .. (NAMES_KO[trim(cn)] or trim(cn)) .. \" 상태라 공격하지 못함\" end)\r\n:gsub(\"([^;]-) is ([^;:]-): no hostile action\", function(w, cn) local a = Ally.ko(trim(w)); return a .. K.josa(a, \"은\", \"는\") .. \" \" .. koName(trim(cn)) .. \" 상태라 적대 행동을 하지 못함\" end)\r\n:gsub(\"no ward that takes 1d4 off on ([^;]+)\", function(t) return Ally.ko(trim(t)) .. \"에게는 1d4를 빼는 보호가 없음\" end)\r\n:gsub(\"([^;]-) is a Beast %(Polymorph%): no spells\", function(w) return Ally.ko(trim(w)) .. \"은 변신으로 야수가 되어 주문을 못 씀\" end)\r\n:gsub(\"([^;]-) made no failed save against ([^;]-) in this reply %(its SAVE first%)\", function(w, n)\r\nlocal k = Ally.ko(trim(w)); return k .. K.josa(k, \"은\", \"는\") .. \" 이번 답에서 \" .. koName(trim(n)) .. \" 내성에 실패하지 않음(SAVE 먼저)\" end)\r\n:gsub(\"(%d+) Temporary HP in all: (%d+) left\", \"임시 생명력은 모두 %1: %2 남음\")\r\n:gsub(\"a hostile target: Disadvantage %(dis A,B%)\", \"적대하는 대상: 불리(dis A,B)\")\r\n:gsub(\"no Cutting Words %(a Lore Bard with a Bardic Inspiration left%)\", \"날카로운 말 없음(바드의 고양감이 남은 전승학파 바드가 없음)\")\r\n:gsub(\"Cutting Words takes off from a creature's attack roll only\", \"날카로운 말은 적의 명중 굴림에서만 뺌\")\r\n:gsub(\"no Bane on ([^;]+)\", function(t) return Ally.ko(trim(t)) .. \"에게는 \" .. koName(\"Bane\") .. \"이 걸려 있지 않음\" end)\r\n:gsub(\"([%a' ]+) takes off from ([^;]-) only\", function(n, w) return koName(trim(n)) .. \"은 \" .. (w == \"attack rolls against its target\" and \"그 대상을 노리는 명중 굴림\" or \"명중·내성 굴림\") .. \"에서만 뺌\" end)\r\n\r\n:gsub(\"([^;]+) is (%u%a+)\", function(w, cn) if CONDS[cn] then return Ally.ko(trim(w)) .. \" \" .. (NAMES_KO[cn] or cn) .. \" 상태라 행동 못 함\" end end)\r\n:gsub(\"^cap (%d+)$\", \"상한 %1\")\r\n\r\n:gsub(\"([^;]-) has ended %(([^;]-)'s Concentration ([^;)]-)%): cast it again %(a new CAST and slot%) to use it\", function(sp, who, why)\r\nlocal k = koName(trim(sp))\r\nlocal w = K.CONC_WHY_KO[why] or why\r\nreturn string.format(\"%s%s 이미 끝났습니다(%s의 집중이 %s). 다시 쓰려면 새로 시전해야 합니다\", k, K.josa(k, \"은\", \"는\"), who == \"Player\" and \"당신\" or Ally.ko(who), w)\r\nend)\r\n:gsub(\"no spell in effect with an? (%a+) save %(write CAST first[^)]*%)\", function(ab) return (NAMES_KO[ab] or ab) .. \" 내성을 받는 주문이 걸려 있지 않습니다(먼저 CAST)\" end)\r\n:gsub(\"no spell in effect that hits without a roll %(write CAST first%)\", \"굴림 없이 맞히는 주문이 걸려 있지 않습니다(먼저 CAST)\")\r\n\r\n:gsub(\"grade (%u)%-&gt;(%u): [^;]- is grade %u already\", \"등급 %1 → %2: 이미 %2등급인 물건\")\r\n:gsub(\"grade (%u)%-&gt;(%u): ([^;]-) is a level (%d) spell\", function(a, b, sp, lv)\r\nlocal k = koName(sp); return string.format(\"등급 %s → %s: %s%s %s레벨 주문\", a, b, k, K.josa(k, \"은\", \"는\"), lv) end)\r\n:gsub(\"power spell ([^:;]-): grade (%u) casts up to level (%d)\", function(sp, g, lv)\r\nreturn string.format(\"주문 능력 %s 뺌: %s등급은 %s레벨 주문까지(다음 답에서 그 안의 주문으로 다시 정함)\", koName(trim(sp)), g, lv) end)\r\n:gsub(\"grade (%u)%-&gt;(%u) at level (%d+)\", \"등급 %1 → %2: %3레벨의 상한\")\r\n:gsub(\"grade B%-&gt;A: crit is grade A's\", \"등급 B → A: 치명타 19~20은 A등급부터\"):gsub(\"power crit: grade A or S\", \"치명타 능력 뺌: A등급부터\")\r\n:gsub(\"power ([^:;]-): grade (%u) has (%d)\", function(w, g, n) return string.format(\"능력 %s 뺌: %s등급은 능력 %s개\", trim(w), g, n) end)\r\n\r\n:gsub(\"power ([^:;]-): resist and save on armor, a Shield or a trinket\", function(w) return \"능력 \" .. K.lootPwWord(w) .. \" 뺌: 저항·내성은 갑옷·방패·장신구에만\" end)\r\n:gsub(\"power ([^:;]-): dmg and crit on a weapon\", function(w) return \"능력 \" .. K.lootPwWord(w) .. \" 뺌: 피해·치명타는 무기에만\" end)\r\n:gsub(\"power ([^:;]-): dmg Type, crit, resist Type, save or spell Name\", function(w) return \"능력 \" .. K.lootPwWord(w) .. \" 뺌: 피해 종류·치명타·저항 종류·내성·주문 이름 중 하나로\" end)\r\n:gsub(\"power ([^:;]-): an [^;]- spell\", function(w) return \"능력 \" .. K.lootPwWord(w) .. \" 뺌: 이 게임에 없는 주문\" end)\r\n:gsub(\"grade C, B, A or S\", \"등급은 C·B·A·S 중 하나\")\r\n\r\n:gsub(\"more than one companion is concentrating, name the caster\", \"집중 중인 동료가 여럿이라 누구의 집중인지 이름이 필요함\")\r\n:gsub(\"not concentrating\", \"집중 중이 아님\"):gsub(\"unknown caster\", \"모르는 시전자\")\r\n:gsub(\"%(Savage Attacker%)\", \"(\" .. koName(\"Savage Attacker\") .. \")\"):gsub(\"%(Great Weapon Fighting \", \"(\" .. koName(\"Great Weapon Fighting\") .. \" \")\r\n\r\n\r\n:gsub(\"([^;]-) is not Bloodied %(more than half its HP%)\", function(w)\r\nreturn (w == \"Player\" and \"당신\" or Ally.ko(trim(w))) .. \"의 생명력이 절반보다 많음(생명 보존은 절반 이하인 대상에게만)\" end)\r\n:gsub(\"([^;]-) is not one of the module's vices\", function(w) return trim(w) .. \": 모듈에 있는 중독이 아님\" end)\r\n:gsub(\"([^;]-) is not one of the module's (%a+)s: ([^;]*)\", function(w, k, list)\r\nlocal kk = ({ curse = \"저주\", brand = \"낙인\", fetish = \"페티시\" })[k] or k\r\nreturn trim(w) .. \": 모듈에 없는 \" .. kk .. \"(있는 것: \" .. list .. \")\" end)\r\n:gsub(\"([^;]-) is not one of the module's (%a+)s\", function(w, k)\r\nlocal kk = ({ curse = \"저주\", brand = \"낙인\", fetish = \"페티시\" })[k] or k\r\nreturn trim(w) .. \": 모듈에 없는 \" .. kk end)\r\n:gsub(\"([^;]-) is not one of the module's\", function(w) return trim(w) .. \": 모듈에 없는 이름(모듈에 있는 것만 붙음)\" end)\r\n:gsub(\"write «CAST¦Spell¦free» for ([^;]+)\", function(w) return koName(trim(w)) .. \"은 «CAST¦주문¦free»로 씀\" end)\r\n\r\n:gsub(\" %(with its inhibition%)\", \" (억제 포함)\"):gsub(\"%f[%a]stim (%S+)%-&gt;\", \"자극 %1 → \")\r\n:gsub(\"no Cleric cantrip of ([^;]-)'s dealt damage in this reply %(its SAVE first%)\", function(w)\r\nreturn (w == \"Player\" and \"당신\" or Ally.ko(trim(w))) .. \"의 클레릭 소마법이 이번 답에서 피해를 주지 않음(강화된 주문시전은 소마법이 피해를 준 뒤에만)\" end)\r\n:gsub(\"base is an SRD weapon, armor or Shield %(kept as a trinket%)\", \"바탕은 SRD 무기·갑옷·방패만 됨(장신구로 둠)\")\r\n\r\n:gsub(\"([^;]-) is not Edging %(its arousal is below the maximum%)\", function(w) return (w == \"Player\" and \"당신\" or Ally.ko(trim(w))) .. \"은 임계가 아님(흥분도가 최대치 아래)\" end)\r\n:gsub(\"over (%a+) budget (%d+)\\5(%d+) XP: one enemy alone, fought as a deadly fight\", function(l, a, b) return K.BUDGET_KO[l] .. \" 예산 초과(\" .. a .. \">\" .. b .. \" XP): 적 하나뿐이라 치명적인 싸움으로\" end)\r\n:gsub(\"over (%a+) budget (%d+)\\5(%d+) XP: ([^;]-) left out\", function(l, a, b, w)\r\nlocal o = {}\r\nfor n in (w .. \",\"):gmatch(\"%s*([^,]-)%s*,\") do if n ~= \"\" then o[#o + 1] = Ally.ko(n) end end\r\nreturn K.BUDGET_KO[l] .. \" 예산 초과(\" .. a .. \">\" .. b .. \" XP): \" .. table.concat(o, \", \") .. \" 뺌\" end)\r\n:gsub(\"DC (%d+)%-&gt;(%d+) %(the user's check difficulty%)\", \"난이도 %1 → %2 (판정 난이도 설정)\")\r\n:gsub(\"no character yet: write the PC tag first\", \"아직 캐릭터 없음: PC 태그를 먼저\")\r\n:gsub(\"([^;]-) is at full HP: no Hit Point Dice spent\", function(w) return (w == \"Player\" and \"당신\" or Ally.ko(trim(w))) .. \"의 생명력이 가득 차 있어 생명력 주사위를 쓰지 않음\" end)\r\n:gsub(\"dice (%d+)%-&gt;(%d+) %(full HP%)\", \"주사위 %1 → %2개 (생명력이 가득 차서 멈춤)\")\r\n:gsub(\"([%a ]-) (%d+) has no spells yet %(they start at level (%d+)%): write no SPELLS tag\", function(cl, lv, from)\r\nreturn koName(trim(cl)) .. \" \" .. lv .. \"레벨은 아직 주문이 없음(\" .. from .. \"레벨부터)\" end)\r\n:gsub(\"([%a ]-) (%d+) has no spells yet: write no SPELLS tag\", function(cl, lv) return koName(trim(cl)) .. \" \" .. lv .. \"레벨은 아직 주문이 없음\" end)\r\n:gsub(\"write its spell power: spell Name, level (%d) or lower\", \"주문 능력을 적을 것: %1레벨 이하 주문\")\r\n:gsub(\"unknown item: not in ([^;]-)'s items %(a found one comes in by its LOOT first%)\", function(w)\r\nreturn (w == \"Player\" and \"당신\" or Ally.ko(trim(w))) .. \"의 물건에 없음(찾은 물건은 먼저 LOOT로 받아야 함)\" end)\r\n:gsub(\"OPT is a suggestion for the next input; an attack Player makes in this reply is \", \"선택지는 다음 입력용 제안: 이번 답에서 하는 공격은 \")\r\n:gsub(\"copying ([^;]-) costs (%d+) gp\", function(sp, n) return koName(trim(sp)) .. \" 베끼기 \" .. n .. \" gp\" end)\r\n:gsub(\"target must be Player, a companion, a creature in the fight or in the scene\", \"대상은 당신·동료·싸움이나 장면의 생물만\")\r\n:gsub(\"target must be Player, a companion or a creature in the fight\", \"대상은 당신·동료·싸움 중인 생물만\")\r\n:gsub(\"attacker must be Player, a companion or a creature in the fight\", \"공격자는 당신·동료·싸움 중인 생물만\")\r\n:gsub(\"target must be Player or a companion\", \"대상은 당신이나 동료만\")\r\n:gsub(\"([%a' ]-) spends ([%a' ]-): USE that by its name\", function(n, r) local k = koName(trim(r)); return koName(trim(n)) .. \": \" .. k .. K.josa(k, \"을\", \"를\") .. \" 쓰는 기능(USE는 그 이름으로)\" end)\r\n:gsub(\"not a feature with uses\", \"횟수를 쓰는 기능이 아님\")\r\n:gsub(\"unknown source\", \"회복 출처를 모름(물약·이번 답의 주문·기능·물건, 파티 밖 사제는 npc, 약초·붕대는 First Aid)\")\r\n:gsub(\"^unknown ([^;]+)$\", function(w) return \"모르는 이름: \" .. trim(w) end):gsub(\";%s*unknown ([^;]+)\", function(w) return \"; 모르는 이름: \" .. trim(w) end)\r\n:gsub(\"%-&gt;\", \" → \"):gsub(\";\", \", \"):gsub(\"\\5\", \"&gt;\"):gsub(\"\\6\", \"&lt;\"))\r\nend\r\n\r\n\r\nfunction K.lootPwWord(w)\r\nw = trim(w or \"\")\r\nlocal lw = w:lower()\r\nif lw == \"save\" then return \"내성\" elseif lw == \"crit\" then return \"치명타\" end\r\nlocal k, rest = lw:match(\"^(%a+)%s+(.+)$\")\r\nif k == \"dmg\" or k == \"resist\" then\r\nlocal ty = trim(w:match(\"^%a+%s+(.+)$\") or \"\")\r\nty = ty:sub(1, 1):upper() .. ty:sub(2):lower()\r\nreturn (k == \"dmg\" and \"피해 \" or \"저항 \") .. ((K.DMG_KO and K.DMG_KO[ty]) or ty)\r\nelseif k == \"spell\" then\r\nreturn \"주문 \" .. koName(Canon.name(trim(w:sub(7))))\r\nend\r\nreturn w\r\nend\r\nK.CONC_WHY_KO = { [\"ended by the Rage\"] = \"격노로 끝남\", [\"broke after damage\"] = \"피해로 깨짐\", [\"ended at 0 HP\"] = \"쓰러져 끝남\", [\"ended when Incapacitated\"] = \"행동불능으로 끝남\",\r\n[\"ran out\"] = \"시간이 다 됨\", [\"was dropped\"] = \"직접 끝냄\", [\"moved to another spell\"] = \"다른 주문으로 옮겨 감\" }\r\n\r\nfunction K.spellChipRows(names)\r\nlocal byLv, rows = {}, {}\r\nfor _, n in ipairs(names) do\r\nlocal lv = SPELLS[n] and SPELLS[n].level or 10\r\nbyLv[lv] = byLv[lv] or {}\r\nbyLv[lv][#byLv[lv] + 1] = K.chip(koName(n))\r\nend\r\nfor lv = 0, 10 do\r\nif byLv[lv] then rows[#rows + 1] = K.chipRow(lv == 0 and \"소마법\" or lv == 10 and \"그 밖\" or (lv .. \"레벨\"), byLv[lv]) end\r\nend\r\nreturn table.concat(rows)\r\nend\r\n\r\n\r\n\r\nK.END_KO = {\r\n[\"enemies fled\"] = \"적이 달아났습니다\", [\"enemy fled\"] = \"적이 달아났습니다\", [\"the enemies fled\"] = \"적이 달아났습니다\",\r\n[\"fled\"] = \"달아났습니다\", [\"hid\"] = \"숨어서 따돌렸습니다\", [\"hidden\"] = \"숨어서 따돌렸습니다\",\r\n[\"surrender\"] = \"적이 항복했습니다\", [\"surrendered\"] = \"적이 항복했습니다\", [\"enemies surrendered\"] = \"적이 항복했습니다\",\r\n[\"truce\"] = \"싸움을 멈추기로 했습니다\", [\"parley\"] = \"말로 싸움을 멈췄습니다\", [\"negotiation\"] = \"말로 싸움을 멈췄습니다\",\r\n[\"escape\"] = \"빠져나왔습니다\", [\"escaped\"] = \"빠져나왔습니다\", [\"outran\"] = \"따돌리고 빠져나왔습니다\", [\"party fled\"] = \"우리 편이 달아났습니다\",\r\n[\"victory\"] = \"적을 모두 물리쳤습니다\", [\"enemies defeated\"] = \"적을 모두 물리쳤습니다\", [\"all enemies defeated\"] = \"적을 모두 물리쳤습니다\",\r\n[\"party defeated\"] = \"우리 편이 모두 쓰러졌습니다\", [\"party down\"] = \"우리 편이 모두 쓰러졌습니다\", [\"defeat\"] = \"우리 편이 모두 쓰러졌습니다\",\r\n[\"party fell\"] = \"우리 편이 모두 쓰러졌습니다\", [\"all down\"] = \"우리 편이 모두 쓰러졌습니다\", [\"defeated\"] = \"우리 편이 모두 쓰러졌습니다\",\r\n\r\n[\"done\"] = \"싸움이 끝났습니다\", [\"over\"] = \"싸움이 끝났습니다\", [\"ended\"] = \"싸움이 끝났습니다\", [\"end\"] = \"싸움이 끝났습니다\",\r\n[\"won\"] = \"적을 모두 물리쳤습니다\", [\"win\"] = \"적을 모두 물리쳤습니다\", [\"enemies dead\"] = \"적을 모두 물리쳤습니다\", [\"all enemies dead\"] = \"적을 모두 물리쳤습니다\",\r\n}\r\n\r\n\r\n\r\n\r\nfunction K.toolKo(v)\r\nlocal tool, sk = K.toolOf(v)\r\nif not tool then return nil end\r\nreturn koName(tool) .. (sk and (\" (\" .. koName(sk) .. \")\") or \"\")\r\nend\r\nfunction Ally.ko(v)\r\nlocal n, rest = (v or \"\"):match(\"^%s*([^/]-)%s*/%s*(.-)%s*$\")\r\nif not n then return K.toolKo(v or \"\") or toKo(v or \"\") end\r\nreturn n .. \" · \" .. (K.toolKo(rest) or toKo(rest))\r\nend\r\n\r\n\r\nfunction K.downKo(why)\r\nif not why:find(\"down\", 1, true) then return why end\r\nlocal function names(s)\r\nlocal o = {}\r\nfor n in (s .. \",\"):gmatch(\"%s*([^,]-)%s*,\") do if n ~= \"\" then o[#o + 1] = Ally.ko(n) end end\r\nreturn table.concat(o, \", \")\r\nend\r\nreturn (why:gsub(\"target (.-)%-&gt;(.-) %((.-) was down%)\", function(a, b, d) return \"대상 \" .. Ally.ko(a) .. \" → \" .. Ally.ko(b) .. \" (\" .. Ally.ko(d) .. \" 쓰러짐)\" end)\r\n:gsub(\"^(.-) is down: attack a standing enemy %((.-)%)$\", function(a, s) return Ally.ko(a) .. \" 이미 쓰러짐 · 서 있는 적: \" .. names(s) end)\r\n:gsub(\"^(.-) is down: attack a standing enemy$\", function(a) return Ally.ko(a) .. \" 이미 쓰러짐\" end)\r\n\r\n:gsub(\"([^;]-) is down: no standing target for ([^;]-) %(nothing spent%)\", function(a, sp)\r\nlocal k = koName(trim(sp)); return Ally.ko(trim(a)) .. \" 이미 쓰러짐: \" .. k .. \"의 대상이 없어 쓰지 않음(소모 없음)\" end))\r\nend\r\n\r\n\r\nfunction K.raiseKo(why)\r\nif not (why:find(\"dead\", 1, true) or why:find(\"died\", 1, true) or why:find(\"priest\", 1, true) or why:find(\"service\", 1, true)\r\nor why:find(\"species\", 1, true) or why:find(\"with CAST first\", 1, true)) then return why end\r\nlocal function span(s)\r\nreturn (s:gsub(\"moments\", \"방금\"):gsub(\"(%d+) minutes?\", \"%1분\"):gsub(\"(%d+) hours?\", \"%1시간\"):gsub(\"(%d+) days?\", \"%1일\"):gsub(\"(%d+) years?\", \"%1년\"))\r\nend\r\nlocal function nm(s) local k = koName(s); return k .. K.josa(k, \"은\", \"는\") end\r\nlocal function who(w, a, b) local k = Ally.ko(w); return k .. K.josa(k, a, b) end\r\nreturn (why:gsub(\"^(.-) died (.-) ago: (.-) reaches (.+)$\", function(w, e, s, lim) return who(w, \"이\", \"가\") .. \" 죽은 지 \" .. span(e) .. \": \" .. nm(s) .. \" \" .. span(lim) .. \" 안에만 됩니다\" end)\r\n:gsub(\"^(.-) is not dead$\", function(w) return who(w, \"은\", \"는\") .. \" 죽지 않았습니다\" end)\r\n:gsub(\"^cast (.-) with CAST first.*$\", function(s) return \"먼저 \" .. koName(s) .. \" 시전(CAST)이 있어야 합니다\" end)\r\n:gsub(\"^the service costs (%d+) gp with its material, the party has (.+)$\", function(g, h) return \"사제 비용 금화 \" .. g .. \"(재료 포함), 가진 돈 \" .. toKo(h) end)\r\n:gsub(\"^a priest who casts it lives in a town or a city.*$\", \"사제는 마을이나 도시에 있습니다\")\r\n:gsub(\"^(.-) is not a playable species$\", function(s) return koName(s) .. \": 고를 수 있는 종족이 아닙니다\" end)\r\n:gsub(\"^a species only with Reincarnate$\", \"종족은 환생에서만 고릅니다\")\r\n:gsub(\"^a spell that brings back the dead: .*$\", \"죽은 이를 되살리는 주문이 아닙니다\")\r\n:gsub(\"^bring back the dead with .*$\", \"되살리기는 HEAL이 아니라 시전 뒤 REVIVE 태그로 합니다\"))\r\nend\r\n\r\n\r\n\r\nfunction K.miKo(why)\r\nlocal function nm(s) return koName(trim(s)) end\r\nlocal function jo(s, a, b) local k = nm(s); return k .. K.josa(k, a, b) end\r\nlocal function who(list)\r\nlocal o = {}\r\nfor w in (list:gsub(\" or \", \",\") .. \",\"):gmatch(\"%s*([^,]-)%s*,\") do\r\nif w ~= \"\" then\r\no[#o + 1] = (w == \"Spellcaster\" and \"주문을 쓰는 이\") or (w == \"Belt of Dwarvenkind\" and (nm(w) .. \"에 조율한 이\")) or nm(w)\r\nend\r\nend\r\nreturn table.concat(o, \", \")\r\nend\r\nlocal out = why\r\n:gsub(\"^not in the pack$\", \"가방에 없습니다\")\r\n:gsub(\"^write the item's name$\", \"물품 이름을 써야 합니다\")\r\n:gsub(\"^(.-) needs no attunement: it works as it is$\", function(n) return jo(n, \"은\", \"는\") .. \" 조율 없이 그냥 씁니다\" end)\r\n:gsub(\"^attuning takes a Short Rest: not in a fight$\", \"조율에는 짧은 휴식이 걸려서 전투 중에는 못 합니다\")\r\n:gsub(\"^not attuned to (.+)$\", function(n) return nm(n) .. \": 조율하지 않은 물품입니다\" end)\r\n:gsub(\"^already attuned$\", \"이미 조율했습니다\")\r\n:gsub(\"^3 items attuned already.*$\", \"이미 물품 3개에 조율했습니다. 하나를 먼저 풀어야 합니다\")\r\n:gsub(\"^(.-) attunes only to an? (.+)$\", function(n, w) return jo(n, \"은\", \"는\") .. \" \" .. who(w) .. \"만 조율할 수 있습니다\" end)\r\n:gsub(\"^(.-) needs attunement first.*$\", function(n) return nm(n) .. \": 먼저 조율해야 합니다\" end)\r\n:gsub(\"^(.-): (.-) again only after the next dawn %(a Long Rest%)$\", function(i, s) return nm(i) .. \": \" .. nm(s) .. K.josa(nm(s), \"은\", \"는\") .. \" 다음 새벽(긴 휴식) 뒤에 다시 씁니다\" end)\r\n:gsub(\"^(.-) again only after the next dawn.*$\", function(n) return nm(n) .. \": 다음 새벽(긴 휴식) 뒤에 다시 씁니다\" end)\r\n:gsub(\"^its study takes 48 hours: not in a fight$\", \"48시간 공부해야 해서 전투 중에는 못 합니다\")\r\n:gsub(\"^(%a+) is 30 already$\", function(a) return nm(a) .. \" 이미 30입니다\" end)\r\n:gsub(\"^no spent spell slot of level (%d)( or lower)$\", \"쓴 %1레벨 이하 주문 슬롯이 없습니다\")\r\n:gsub(\"^no spent spell slot of level (%d)$\", \"쓴 %1레벨 주문 슬롯이 없습니다\")\r\n:gsub(\"^its healing is a HEAL.*$\", \"회복은 HEAL 태그로 씁니다\")\r\n:gsub(\"^name a nonmagical Melee weapon or ammunition in the pack.*$\", \"가방에 있는 마법 아닌 근접 무기나 탄약을 적어야 합니다\")\r\n:gsub(\"^(.-): only a Melee weapon that deals Slashing or Piercing damage$\", function(w) return nm(w) .. \": 참격이나 관통 피해를 주는 근접 무기만 됩니다\" end)\r\n:gsub(\"^(.-) casts (.-) at level (%d) only$\", function(i, s, l) return nm(i) .. \": \" .. nm(s) .. K.josa(nm(s), \"은\", \"는\") .. \" \" .. l .. \"레벨로만 시전합니다\" end)\r\n:gsub(\"^(.-) spends at most (%d+) charges on (.+)$\", function(i, n, s) return nm(i) .. \": \" .. nm(s) .. \"에는 충전을 \" .. n .. \"개까지만 씁니다\" end)\r\n:gsub(\"^(.-) has (%d+) charges; (.-) at level (%d) takes (%d+)$\", function(i, h, s, l, n)\r\nreturn nm(i) .. \" 충전 \" .. h .. \"개: \" .. l .. \"레벨 \" .. nm(s) .. K.josa(nm(s), \"은\", \"는\") .. \" \" .. n .. \"개가 듭니다\" end)\r\n:gsub(\"^no Spell Scroll %((.-)%) in the pack$\", function(s) return nm(\"Spell Scroll (\" .. s .. \")\") .. K.josa(nm(\"Spell Scroll (\" .. s .. \")\"), \"이\", \"가\") .. \" 가방에 없습니다\" end)\r\n:gsub(\"^(.-) is not on (.-)'s spell list: the scroll cannot be read$\", function(s, w) return nm(s) .. K.josa(nm(s), \"은\", \"는\") .. \" \" .. Ally.ko(w) .. \"의 주문 목록에 없어 두루마리를 읽지 못합니다\" end)\r\n:gsub(\"^the scroll's check failed, the spell fades with no effect$\", \"두루마리 판정 실패: 주문이 효과 없이 사라졌습니다\")\r\n:gsub(\"^no magic item in use casts (.-) %((.-) needs attunement or is not held%)$\", function(s, i) return nm(i) .. \": 조율하지 않았거나 들고 있지 않습니다\" end)\r\n:gsub(\"^no magic item in use casts (.+)$\", function(s) return nm(s) .. K.josa(nm(s), \"을\", \"를\") .. \" 시전하는 마법 물품이 없습니다\" end)\r\n:gsub(\"^an Artifact is not for sale$\", \"아티팩트는 사고팔 수 없습니다\")\r\n:gsub(\"^(.-) deals (%a+): the poison needs Piercing or Slashing$\", function(w) return nm(w) .. \": 독은 관통·참격 무기에만 바릅니다\" end)\r\n:gsub(\"^no Basic Poison in the pack$\", \"가방에 기본 독이 없습니다\")\r\n\r\n:gsub(\"^a spell that makes a creature: .*$\", \"생물을 부르는 주문이 아닙니다\")\r\n:gsub(\"^(.-) made its creatures already in this casting$\", function(s) return nm(s) .. \": 이번 시전으로 이미 불렀습니다\" end)\r\n:gsub(\"^a familiar's form: .*$\", \"패밀리어 모습: 박쥐·고양이·개구리·매·도마뱀·문어·올빼미·쥐·까마귀·거미·족제비, 또는 도전 지수 0 야수\")\r\n:gsub(\"^the steed's type: Celestial, Fey or Fiend$\", \"군마의 종류: 천상체·요정·악마\")\r\n:gsub(\"^Skeleton %(bones%) or Zombie %(a corpse%)$\", \"스켈레톤(뼈)이나 좀비(시체)\")\r\n:gsub(\"^a level (%d) casting animates (%d+) at most$\", \"%1레벨 시전은 %2개까지 일으킵니다\")\r\n:gsub(\"^the breath's damage type: .*$\", \"숨결 피해 종류: 산성·냉기·화염·번개·독성\")\r\n:gsub(\"^not riding$\", \"타고 있지 않습니다\")\r\n:gsub(\"^a summoned creature to ride %(its name%)$\", \"탈 소환수 이름을 적어야 합니다\")\r\n:gsub(\"^(.-) is too small to ride$\", function(s) return toKo(s) .. \": 너무 작아서 못 탑니다\" end)\r\n:gsub(\"^a familiar cannot attack.*$\", \"패밀리어는 공격하지 못합니다 (돕기·회피·질주는 됩니다)\")\r\n:gsub(\"^(.-) is ridden by Player: a controlled mount takes only Dash, Disengage or Dodge$\", function(s) return toKo(s) .. \": 당신이 탄 탈것은 질주·이탈·회피만 합니다\" end)\r\n\r\n:gsub(\"^not during a fight$\", \"전투 중에는 못 합니다\")\r\n:gsub(\"^count 1%-100$\", \"개수는 1~100\")\r\n:gsub(\"^the helper is a companion's name$\", \"돕는 사람은 동료 이름으로\")\r\n:gsub(\"^(.-) is not among Player's prepared spells$\", function(s) return nm(s) .. K.josa(nm(s), \"은\", \"는\") .. \" 준비한 주문이 아닙니다\" end)\r\n:gsub(\"^scribing needs proficiency in Arcana or with Calligrapher's Supplies$\", \"두루마리를 쓰려면 비전학이나 서예가 도구 숙련이 있어야 합니다\")\r\n:gsub(\"^a Potion of Healing needs proficiency with the Herbalism Kit$\", \"치유의 물약은 약초학 키트 숙련이 있어야 만듭니다\")\r\n:gsub(\"^story gear: Lua does not count it, narrate the work %(no tag%)$\", \"Lua가 세지 않는 이야기 장비라 태그 없이 이야기로 만듭니다\")\r\n:gsub(\"^no tool makes (.-) %(the SRD's Craft lists%)$\", function(s) return nm(s) .. K.josa(nm(s), \"을\", \"를\") .. \" 만드는 도구가 없습니다\" end)\r\n:gsub(\"^(.-) needs proficiency with (.+)$\", function(s, tl)\r\nlocal o = {}\r\nfor x in (tl:gsub(\" or \", \",\") .. \",\"):gmatch(\"%s*([^,]-)%s*,\") do if x ~= \"\" then o[#o + 1] = nm(x) end end\r\nreturn nm(s) .. K.josa(nm(s), \"은\", \"는\") .. \" \" .. table.concat(o, \"·\") .. \" 숙련이 있어야 만듭니다\" end)\r\n:gsub(\"^(.-) is not proficient with (.+)$\", function(w, tl) return Ally.ko(w) .. \": \" .. nm(tl) .. \" 숙련이 없습니다\" end)\r\n:gsub(\"^the materials cost (.-), the party has (.+)$\", function(a, b) return \"재료비 \" .. toKo(a) .. \", 가진 돈 \" .. toKo(b) end)\r\n:gsub(\"^name the weapon or the ammunition: .*$\", \"바를 무기나 탄약을 적어야 합니다\")\r\n:gsub(\"copying (.-) from its scroll: Arcana d20 (%d+)([%+%-]%d+) vs DC (%d+) failed, the scroll is gone\", function(s, d, b, dc)\r\nreturn \"두루마리에서 \" .. nm(s) .. \" 베끼기 실패: 비전학 d20 \" .. d .. b .. \" vs 난이도 \" .. dc .. \", 두루마리는 사라졌습니다\" end)\r\n:gsub(\"^an? (%a+) item at level (%d+) %(only from level 11%)$\", function(r, l) return (r == \"Legendary\" and \"전설\" or \"아티팩트\") .. \" 물품은 11레벨부터 (지금 \" .. l .. \"레벨)\" end)\r\n:gsub(\"^name the spell: Spell Scroll %(Fireball%)$\", \"주문 이름을 적어야 합니다: Spell Scroll (Fireball)\")\r\n:gsub(\"^(.-) comes in kinds: name one, (.+)$\", function(n, ex) return nm(n) .. \": 종류를 적어야 합니다, \" .. ex end)\r\n:gsub(\"^name its base: (.+)$\", function(ex) return \"바탕 무기·갑옷을 적어야 합니다: \" .. ex end)\r\n:gsub(\"^(.-) cannot be (.+)$\", function(b, n) return nm(b) .. K.josa(nm(b), \"은\", \"는\") .. \" \" .. nm(n) .. K.josa(nm(n), \"이\", \"가\") .. \" 될 수 없습니다\" end)\r\nreturn out\r\nend\r\n\r\n\r\nfunction K.miUseKo(left)\r\nleft = left:gsub(\"→\", \"->\"):gsub(\"방어도\", \"AC\"):gsub(\"당신\", \"Player\"):gsub(\"생명력\", \"HP\")\r\nlocal o, story = {}, false\r\nlocal function list(s, sep)\r\nlocal t = {}\r\nfor x in (s:gsub(\" or \", \",\") .. \",\"):gmatch(\"%s*([^,]-)%s*,\") do if x ~= \"\" then t[#t + 1] = K.MI.DMG_KO[x] or koName(x) end end\r\nreturn table.concat(t, sep or \"·\")\r\nend\r\nlocal span = function(s) return (s:gsub(\"(%d+) minutes?\", \"%1분\"):gsub(\"(%d+) hours?\", \"%1시간\"):gsub(\"(%d+) days?\", \"%1일\")) end\r\nfor part in (left .. \";\"):gmatch(\"%s*([^;]-)%s*;\") do\r\nif part ~= \"\" then\r\nlocal k\r\nlocal n = part:match(\"^Temporary HP (%d+)$\")\r\nif n then k = \"임시 생명력 \" .. n end\r\nif not k and part:match(\"^Bless without Concentration\") then k = koName(\"Bless\") .. \" (집중 없이): 명중·내성 굴림 +1d4\" end\r\nif not k and part:match(\"^Haste without Concentration\") then k = koName(\"Haste\") .. \" (집중 없이): 민첩 내성 이점, 속도 2배, 행동 하나 더\" end\r\nif not k and part == \"Resistance to all damage\" then k = \"모든 피해에 저항\" end\r\nlocal rs = not k and part:match(\"^Resistance to (.+)$\")\r\nif rs then k = list(rs) .. \" 저항\" end\r\nlocal ac = not k and part:match(\"^%+(%d+) AC$\")\r\nif ac then k = \"방어도 +\" .. ac end\r\nlocal cb = not k and part:match(\"^cannot be (.+)$\")\r\nif cb then k = list(cb) .. \" 면역\" end\r\nif not k and part == \"Freedom of Movement\" then k = koName(\"Freedom of Movement\") end\r\nif not k and part == \"Exhaustion 0\" then k = \"탈진 해소\" end\r\nlocal en = not k and part:match(\"^(%a+) ended$\")\r\nif en then k = koName(en) .. \" 풀림\" end\r\nlocal ab, sc = nil, nil\r\nif not k then ab, sc = part:match(\"^(%a+) (%d+) %(unless higher%)$\") end\r\nif ab then k = koName(ab) .. \" \" .. sc end\r\nlocal pa, p0, p1 = nil, nil, nil\r\nif not k then pa, p0, p1 = part:match(\"^(%a+) (%d+) %-> (%d+) %(48 hours\") end\r\nif pa then k = koName(pa) .. \" \" .. p0 .. \" → \" .. p1 .. \" (6일 안에 48시간 공부)\" end\r\nlocal cnt, w, nw = nil, nil, nil\r\nif not k then cnt, w, nw = part:match(\"^(%d*)%s*(.-) %-> (.+)$\") end\r\nif w then k = (cnt ~= \"\" and (cnt .. \"개 \") or \"\") .. koName(w) .. \" → \" .. koName(nw) end\r\nlocal sl, sa = nil, nil\r\nif not k then sl, sa = part:match(\"^(.-) back: (%d+/%d+)$\") end\r\nif sl then k = koName(sl) .. \" 1개 회복 · \" .. sa end\r\nif not k and part:match(\"^1 minute\") then k = \"1분 (전투가 끝나면 끝)\" end\r\nif not k and part:match(\"^%d+ %a+$\") and span(part) ~= part then k = span(part) end\r\nlocal pd, pm = part:match(\"^(%d+)/(%d+) per dawn$\")\r\nif pd then k = pd .. \"/\" .. pm .. \" 남음 (새벽에 회복)\" end\r\nif not k and part == \"used up\" then k = \"다 씀\" end\r\nif not k and part:find(\"[\\234-\\237]\") then k = part end\r\nif k then o[#o + 1] = k else story = true end\r\nend\r\nend\r\nif story then table.insert(o, 1, \"효과는 이야기로\") end\r\nreturn table.concat(o, \" · \")\r\nend\r\n\r\n\r\nfunction Ally.html(f)\r\nlocal a = args(f)\r\nlocal verdict = f[#a + 1] or \"\"\r\nlocal sign, name = (a[1] or \"\"):match(\"^%s*([+=-])%s*(.-)%s*$\")\r\nlocal vd = verdict == \"\" and \"검증 전\" or ('<span class=\"dnd-vd\">Lua ' .. esc(verdict) .. \"</span>\")\r\nif sign == \"=\" then\r\n\r\nreturn string.format('<div class=\"dnd-tag%s\" data-v=\"%s\"><div class=\"dnd-h\"><span class=\"dnd-chip\">❖ 동료 소개</span><b>%s</b></div><div class=\"dnd-sub\">%s · %s</div></div>',\r\nverdict == \"\" and \" pend\" or \"\", esc(verdict), esc(name or \"\"), esc(a[2] or \"\"), vd)\r\nend\r\nif sign == \"-\" then\r\nreturn string.format('<div class=\"dnd-tag%s\" data-v=\"%s\"><div class=\"dnd-h\"><span class=\"dnd-chip\">❖ 동료 이탈</span><b>%s</b></div><div class=\"dnd-sub\">%s%s</div></div>',\r\nverdict == \"\" and \" pend\" or \"\", esc(verdict), esc(name or \"\"), (a[2] or \"\") ~= \"\" and (esc(a[2]) .. \" · \") or \"\", vd)\r\nend\r\nlocal who = f[#a + 2] or \"\"\r\nlocal sp, cl, lv = who:match(\"^(%S+) (%S+) (%d+)$\")\r\nlocal hp, ac = (f[#a + 3] or \"\"):match(\"^HP (%d+) AC (%d+)$\")\r\nlocal what = sp and string.format(\"%s %s · %s레벨\", koName(sp), koName(cl), lv)\r\nor (koName(Canon.name(a[2] or \"\")) .. \" \" .. koName(Canon.name(a[3] or \"\")))\r\nreturn string.format('<div class=\"dnd-tag chk%s\" data-v=\"%s\"><div class=\"dnd-h\"><span class=\"dnd-chip\">❖ 동료 합류</span><b>%s</b> · %s</div><div class=\"dnd-sub\">%s%s%s</div></div>',\r\nverdict == \"\" and \" pend\" or \"\", esc(verdict), esc(name or \"\"), esc(what),\r\n(a[4] or \"\") ~= \"\" and (esc(a[4]) .. \" · \") or \"\", hp and (\"생명력 \" .. hp .. \" · 방어도 \" .. ac .. \" · \") or \"\", vd)\r\nend\r\n\r\n\r\n\r\n\r\nlocal TERMS = {\r\n{ w = { \"죽음 내성 굴림\", \"죽음 내성\", \"사망 내성 굴림\", \"사망 내성\" }, tip = \"생명력 0일 때 턴마다 d20: 10 이상 성공. 성공 3번이면 안정, 실패 3번이면 사망. 20이면 생명력 1로 깨어납니다. 쓰러진 채 맞으면 실패 1번(치명타면 2번)입니다.\" },\r\n\r\n{ w = { \"대량 피해\", \"즉사\" }, tip = \"생명력이 0이 되고도 남은 피해가 최대 생명력 이상이거나, 쓰러진 채 최대 생명력 이상의 피해를 받으면 바로 사망합니다.\" },\r\n{ w = { \"내성 굴림\" }, tip = \"해로운 효과를 버티는 d20 굴림. 능력치 수정치를 더하고, 숙련된 내성이면 숙련 보너스도 더합니다.\" },\r\n{ w = { \"이점\", \"유리함\" }, tip = \"d20을 두 번 굴려 높은 쪽을 씁니다. 불리점과 겹치면 둘 다 없어집니다.\" },\r\n{ w = { \"불리점\", \"불리함\" }, tip = \"d20을 두 번 굴려 낮은 쪽을 씁니다. 이점과 겹치면 둘 다 없어집니다.\" },\r\n\r\n\r\n{ w = { \"기회공격\", \"기회 공격\" }, tip = \"적의 손이 닿는 거리를 이탈 행동 없이 벗어나면, 그 적이 반응행동으로 한 번 공격합니다.\" },\r\n{ w = { \"추가 행동\", \"보너스 행동\" }, tip = \"기능이나 주문이 허락할 때만 쓰는 짧은 행동. 턴마다 한 번.\" },\r\n{ w = { \"반응행동\", \"반응 행동\" }, tip = \"남의 턴에도 쓸 수 있는 즉시 행동 (기회공격 등). 쓰고 나면 내 다음 턴이 시작될 때까지 다시 못 씁니다.\" },\r\n{ w = { \"치명타\" }, tip = \"명중 굴림 d20이 20이면 치명타: 피해 주사위를 두 배로 굴립니다.\" },\r\n{ w = { \"방어도\", \"AC\" }, tip = \"명중 굴림이 이 값 이상이어야 맞습니다.\" },\r\n{ w = { \"명중 굴림\", \"공격 굴림\" }, tip = \"d20 + 공격 수정치. 상대 방어도 이상이면 맞습니다. 20은 치명타, 1은 빗나감.\" },\r\n{ w = { \"상시 판정\" }, tip = \"일부러 굴리지 않을 때의 판정. 10 + 기술 수정치로, 이 값 이상이면 알아챕니다.\" },\r\n{ w = { \"우선권\", \"선제권\" }, tip = \"전투 순서. 전투가 시작되면 d20 + 민첩 수정치로 정합니다 (Lua가 굴립니다).\" },\r\n{ w = { \"엄폐\" }, tip = \"사이에 가리는 것이 있으면 방어도와 민첩 내성에 절반 엄폐 +2, 3/4 엄폐 +5.\" },\r\n{ w = { \"숙련 보너스\" }, tip = \"숙련된 기술·무기·내성 굴림에 더하는 값. 1~4레벨 +2, 5~8레벨 +3, 9~12레벨 +4, 13~16레벨 +5, 17~20레벨 +6.\" },\r\n{ w = { \"생명력 주사위\" }, tip = \"짧은 휴식 때 굴려서 생명력을 회복합니다. 긴 휴식이면 모두 다시 찹니다.\" },\r\n{ w = { \"짧은 휴식\" }, tip = \"1시간 쉬기. 생명력 주사위로 회복하고, 일부 기능이 다시 찹니다.\" },\r\n{ w = { \"긴 휴식\" }, tip = \"8시간 쉬기. 생명력과 기능을 모두 회복합니다. 끝난 뒤 16시간은 다시 할 수 없습니다.\" },\r\n{ w = { \"주문 슬롯\" }, tip = \"레벨 1 이상 주문을 쓸 때마다 하나씩 씁니다. 긴 휴식으로 다시 찹니다.\" },\r\n{ w = { \"소마법\" }, tip = \"슬롯을 쓰지 않고 몇 번이든 쓸 수 있는 주문.\" },\r\n{ w = { \"암습 공격\", \"암습\", \"급소 공격\" }, tip = \"턴마다 한 번, 이점이 있거나 대상 옆에 아군이 있을 때 기교·원거리 무기 피해에 주사위를 더합니다 (1d6, 3레벨부터 홀수 레벨마다 1d6씩 늘어 19레벨 10d6).\" },\r\n{ w = { \"재기의 바람\" }, tip = \"추가 행동으로 1d10 + 파이터 레벨만큼 생명력 회복. 휴식으로 다시 찹니다.\" },\r\n{ w = { \"행동 연쇄\" }, tip = \"이번 턴에 행동을 한 번 더 합니다 (마법 행동 제외). 휴식으로 다시 찹니다.\" },\r\n{ w = { \"붙잡힘\" }, tip = \"속도 0. 붙잡은 상대가 아닌 대상에게는 공격이 불리점.\" },\r\n{ w = { \"넘어진 상태\", \"넘어짐\" }, tip = \"내 공격 불리점. 5피트 안의 공격은 이점, 멀리서는 불리점. 일어나려면 이동력 절반.\" },\r\n{ w = { \"포박\" }, tip = \"속도 0, 나를 치는 공격은 이점, 내 공격과 민첩 내성은 불리점.\" },\r\n{ w = { \"행동불능\" }, tip = \"행동·추가 행동·반응행동을 못 하고 말도 못 합니다. 집중이 깨집니다.\" },\r\n{ w = { \"마비\" }, tip = \"행동불능. 근력·민첩 내성 자동 실패, 나를 치는 공격은 이점, 5피트 안에서 맞으면 치명타.\" },\r\n{ w = { \"중독\" }, tip = \"명중 굴림과 능력 판정에 불리점.\" },\r\n{ w = { \"탈진\" }, tip = \"단계마다 d20 굴림 -2, 속도 -5피트. 6단계면 사망. 긴 휴식마다 1단계 회복.\" },\r\n{ w = { \"무의식\" }, tip = \"쓰러져 아무것도 못 합니다. 나를 치는 공격은 이점, 5피트 안에서 맞으면 치명타.\" },\r\n}\r\n\r\nif K.LITE then\r\nlocal keep = {}\r\nfor _, e in ipairs(TERMS) do\r\nlocal w = e.w[1]\r\nif w == \"주문 슬롯\" then\r\nkeep[#keep + 1] = { w = { \"마나\", \"기력\", \"신성력\" }, tip = \"주문과 클래스 기능에 함께 쓰는 힘. 긴 휴식에 다 차고, 전투 밖에서 쉬면 GM이 조금 돌려줍니다.\" }\r\nelseif w == \"긴 휴식\" then\r\nkeep[#keep + 1] = { w = e.w, tip = \"8시간 쉬기. 생명력과 MP를 모두 회복합니다. 끝난 뒤 16시간은 다시 할 수 없습니다.\" }\r\nelseif w ~= \"생명력 주사위\" and w ~= \"짧은 휴식\" then\r\nkeep[#keep + 1] = e\r\nend\r\nend\r\nTERMS = keep\r\nend\r\n\r\n\r\nlocal function midWord(text, s)\r\nif s <= 1 then return false end\r\nlocal b = text:byte(s - 1)\r\nif b < 128 then return text:sub(s - 1, s - 1):match(\"%w\") ~= nil end\r\nif s > 3 then\r\nlocal lead = text:byte(s - 3)\r\nreturn lead >= 0xEA and lead <= 0xED\r\nend\r\nreturn false\r\nend\r\n\r\nlocal function termify(text)\r\nlocal segs, pos, n = {}, 1, #text\r\nwhile pos <= n do\r\nlocal s = text:find(\"[%[<]\", pos)\r\nlocal stop = s and s - 1 or n\r\nif stop >= pos then segs[#segs + 1] = { pos, stop } end\r\nif not s then break end\r\nlocal close = text:find(text:sub(s, s) == \"[\" and \"]\" or \">\", s + 1, true)\r\npos = (close or n) + 1\r\nend\r\nlocal found = {}\r\nlocal function free(s, e)\r\nfor _, x in ipairs(found) do if s <= x.e and e >= x.s then return false end end\r\nreturn true\r\nend\r\nfor _, t in ipairs(TERMS) do\r\nlocal hit\r\nfor _, seg in ipairs(segs) do\r\nfor _, w in ipairs(t.w) do\r\nlocal from = seg[1]\r\nwhile true do\r\nlocal s, e = text:find(w, from, true)\r\nif not s or e > seg[2] then break end\r\nlocal ascii = w:byte(1) < 128\r\nlocal after = ascii and text:sub(e + 1, e + 1):match(\"%w\")\r\nif not midWord(text, s) and not after and free(s, e) then hit = { s = s, e = e, t = t }; break end\r\nfrom = s + 1\r\nend\r\nif hit then break end\r\nend\r\nif hit then break end\r\nend\r\nif hit then found[#found + 1] = hit end\r\nend\r\nif #found == 0 then return text end\r\ntable.sort(found, function(a, b) return a.s < b.s end)\r\nlocal out, last = {}, 1\r\nfor _, x in ipairs(found) do\r\nout[#out + 1] = text:sub(last, x.s - 1)\r\nout[#out + 1] = '<span class=\"dnd-term\" tabindex=\"0\">' .. text:sub(x.s, x.e) .. '<span class=\"dnd-tip\">' .. esc(x.t.tip) .. '</span></span>'\r\nlast = x.e + 1\r\nend\r\nout[#out + 1] = text:sub(last)\r\nreturn table.concat(out)\r\nend\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\nfunction K.baRider(pc, best, spellOk)\r\nif not (SHEET and type(best) == \"table\") or best.stim then return nil end\r\nlocal active = {}\r\nfor _, a in ipairs(Spell.active(pc)) do active[a.name] = true end\r\nlocal conc = type(pc.conc) == \"table\" and pc.conc.name or nil\r\nlocal pick, pickV\r\nfor _, n in ipairs(Spell.names()) do\r\nlocal sp = SPELLS[n]\r\nlocal m = sp and sp.m\r\nif m and m.cast == \"bonus\" and m.kind == \"buff\" and m.rider and m.rider_each and not active[n]\r\nand not (m.concentration and conc) and (not m.lasting or best.weapon) and K.canCast(pc, n) and spellOk(n) then\r\nlocal f, v = parseFormula(m.rider), 0\r\nfor _, d in ipairs(f and f.dice or {}) do v = v + d.n * (d.s + 1) / 2 end\r\nif not pickV or v > pickV then pick, pickV = n, v end\r\nend\r\nend\r\nif pick then\r\nlocal ko = koName(pick)\r\nreturn { pre = ko .. K.josa(ko, \"을\", \"를\") .. \" 걸고\" }\r\nend\r\nlocal sw = koName(\"Spiritual Weapon\")\r\nif active[\"Spiritual Weapon\"] then return { pre = sw .. K.josa(sw, \"과\", \"와\") .. \" 함께\" } end\r\nif not conc and K.canCast(pc, \"Spiritual Weapon\") and spellOk(\"Spiritual Weapon\") then return { pre = sw .. K.josa(sw, \"을\", \"를\") .. \" 부르고\" } end\r\nlocal res = type(pc.res) == \"table\" and pc.res or {}\r\nlocal monkBA, off\r\nfor _, x in ipairs(pcStats(pc).attacks) do\r\nif x.name == \"Unarmed Strike (Bonus Action)\" then monkBA = true end\r\nif x.offhand and x.mastery ~= \"Nick\" then off = x end\r\nend\r\nif monkBA and K.cl(SHEET, \"Monk\") > 0 and best.weapon and best.melee then\r\nif K.cl(SHEET, \"Monk\") >= 2 and (tonumber(res[\"Focus Points\"]) or 0) > 0 then return { post = \", 이어서 \" .. koName(\"Flurry of Blows\") } end\r\nreturn { post = \", 이어서 맨손 타격 한 번 더\" }\r\nend\r\nif K.cl(SHEET, \"Rogue\") >= 3 and best.weapon then return { pre = koName(\"Steady Aim\") .. \" 후\", adv = true } end\r\nif off and best.item and type(pc.equip) == \"table\" and best.item == pc.equip.main then return { post = \", 이어서 반대 손 공격\" } end\r\nreturn nil\r\nend\r\nfunction K.fightOpts(c, pc)\r\nlocal foes = {}\r\nfor _, name in ipairs(c.order or {}) do\r\nlocal u = c.units[name]\r\n\r\nlocal ko = type(u) == \"table\" and type(u.cond) == \"table\" and type(u.cond.Unconscious) == \"table\" and u.cond.Unconscious.ko\r\nif u and u.side == \"enemy\" and u.hp > 0 and MONSTERS[u.kind] and not ko then foes[#foes + 1] = { name = name, u = u, m = MONSTERS[u.kind] } end\r\nend\r\nif #foes == 0 or pc.dead or (tonumber(pc.hp) or 0) <= 0 then return {} end\r\nif Cond.fx(pc).incap then return {} end\r\ntable.sort(foes, function(x, y)\r\nif x.u.hp ~= y.u.hp then return x.u.hp < y.u.hp end\r\nreturn x.name < y.name\r\nend)\r\nlocal t = foes[1]\r\nlocal ac, tko = t.m.ac or 10, toKo(t.name)\r\n\r\nlocal function ro(w)\r\nlocal cp\r\nfor _, x in utf8.codes(w) do cp = x end\r\nlocal fin = cp and cp >= 0xAC00 and cp <= 0xD7A3 and (cp - 0xAC00) % 28 or 0\r\nreturn w .. ((fin ~= 0 and fin ~= 8) and \"으로\" or \"로\")\r\nend\r\nlocal function jo(w, a, b) return w .. K.josa(w, a, b) end\r\n\r\nlocal function chance(hit, adv, spell)\r\nif spell and t.m.mres == 2 then return 0 end\r\nlocal n = 0\r\nlocal fl = SHEET and K.d20Floor(SHEET, \"attack\", nil) or 0\r\nfor r = 1, 20 do\r\nlocal rr = math.max(r, fl)\r\nif rr == 20 or (rr ~= 1 and rr + hit >= ac) then n = n + 1 end\r\nend\r\nlocal p = n / 20\r\n\r\n\r\nlocal md, a0, d0 = K.ownMode(pc, \"attack\", nil, spell)\r\nif adv then md = d0 and nil or \"adv\" end\r\nif md == \"adv\" then p = 1 - (1 - p) ^ 2 elseif md == \"dis\" then p = p * p end\r\nreturn math.floor(p * 100 + 0.5)\r\nend\r\n\r\n\r\n\r\nlocal function fails(m, ab, dc)\r\nlocal b = (m.saves or {})[ab] or 0\r\nlocal n = 0\r\nfor r = 1, 20 do if r + b < dc then n = n + 1 end end\r\nif m.mres == 2 then return 0 end\r\nreturn m.mres == 1 and (n / 20) ^ 2 or n / 20\r\nend\r\nlocal function avg(formula)\r\nlocal p = parseFormula(formula or \"\")\r\nif not p then return 0 end\r\nlocal s = p.mod\r\nfor _, d in ipairs(p.dice) do s = s + d.n * (d.s + 1) / 2 end\r\nreturn s\r\nend\r\nlocal function pct(p) return math.floor(p * 100 + 0.5) end\r\nlocal o = {}\r\nlocal function add(label, kind, dc, p) o[#o + 1] = string.format(\"[OPT|%s|%s|%s|ok|%s]\", label, kind, dc, p) end\r\nlocal res = type(pc.res) == \"table\" and pc.res or {}\r\nlocal items = type(pc.items) == \"table\" and pc.items or {}\r\n\r\n\r\nlocal function spellOk(n)\r\nif pc.form and not K.formCast(SHEET, n) then return false end\r\nif type(pc.mode) == \"table\" and pc.mode.name == \"Rage\" then return false end\r\nfor _, e in ipairs(K.modeFx(pc, SHEET)) do if e.no_spells then return false end end\r\nreturn true\r\nend\r\n\r\nlocal best, bestV, cant\r\nfor _, x in ipairs(pcStats(pc).attacks) do\r\nif not x.name:find(\"Bonus Action\", 1, true) and not x.name:find(\"^Unarmed\") and not (x.spell and not spellOk(x.spell))\r\nand not (x.ammo and (tonumber(items[x.ammo]) or 0) < 1) then\r\nlocal v = chance(x.hit, nil, x.spell) / 100 * avg(x.dmg)\r\nif not bestV or v > bestV then best, bestV = x, v end\r\nend\r\nend\r\nfor _, n in ipairs(Spell.names()) do\r\nlocal sp = SPELLS[n]\r\nlocal m = sp and sp.m\r\nlocal st = m and sp.level == 0 and m.kind == \"save\" and m.damage and m.save and spellOk(n) and Spell.stats(n)\r\nif st then\r\nlocal f = fails(t.m, m.save, st.dc)\r\nlocal v = (f + (m.on_save == \"half\" and (1 - f) / 2 or 0)) * avg(Spell.formula(n, m.damage, 0, m.type))\r\nif not bestV or v > bestV then best, bestV, cant = n, v, f end\r\nend\r\nend\r\n\r\nlocal civ = tostring(t.m.cr or \"\") == \"0\"\r\nif civ then\r\nlocal mb, mv\r\nfor _, x in ipairs(pcStats(pc).attacks) do\r\nif x.melee and x.weapon and not x.name:find(\"Bonus Action\", 1, true) and not x.stim then\r\nlocal v = chance(x.hit) / 100 * avg(x.dmg)\r\nif not mv or v > mv then mb, mv = x, v end\r\nend\r\nend\r\nif mb then best, cant = mb, nil end\r\nend\r\nif cant then\r\nadd(jo(koName(best), \"을\", \"를\") .. \" \" .. tko .. \"에게 쓴다\", best, t.name, pct(cant))\r\nelseif best then\r\nlocal wko = ro(koName((best.name:gsub(\" %(spell%)$\", \"\"):gsub(\" %(two hands%)$\", \"\"):gsub(\" %(thrown%)$\", \"\"))))\r\nadd(wko .. \" \" .. tko .. \" 공격\" .. ((civ and best.melee) and \" (쓰러뜨리면 기절)\" or \"\"), \"Attack\", ac, chance(best.hit, nil, best.spell))\r\nif SHEET and K.cl(SHEET, \"Barbarian\") > 0 and best.weapon then\r\n\r\nlocal _, worn = gearOf(pc, pc.equip and pc.equip.armor)\r\nif not (type(pc.mode) == \"table\" and pc.mode.name == \"Rage\") and (res.Rage or 0) > 0 and not (worn and worn.cat == \"heavy\") then\r\nadd(\"격노를 켜고 \" .. wko .. \" 공격\", \"Attack\", ac, chance(best.hit, nil, best.spell))\r\nelseif K.cl(SHEET, \"Barbarian\") >= 2 and best.str then\r\nadd(\"무모한 공격으로 \" .. tko .. \" 공격 (나도 이점을 줌)\", \"Attack\", ac, chance(best.hit, true, best.spell))\r\nend\r\nend\r\n\r\nlocal rider = not (SHEET and K.cl(SHEET, \"Barbarian\") > 0) and K.baRider(pc, best, spellOk) or nil\r\nif rider then\r\nadd((rider.pre and (rider.pre .. \" \") or \"\") .. wko .. \" \" .. tko .. \" 공격\" .. (rider.post or \"\"), \"Attack\", ac, chance(best.hit, rider.adv, best.spell))\r\nend\r\nend\r\n\r\nif SHEET and K.cl(SHEET, \"Cleric\") >= 2 and (res[\"Channel Divinity\"] or 0) > 0 then\r\nlocal und\r\nfor _, x in ipairs(foes) do if x.m.undead and not und then und = x end end\r\nif c.turned then und = nil end\r\nfor _, e in ipairs(K.cdFoeSaves(SHEET)) do\r\nif und and e.name == \"Turn Undead\" then\r\nadd(jo(koName(\"Turn Undead\"), \"을\", \"를\") .. \" 쓴다\", \"Turn Undead\", und.name, pct(fails(und.m, e.save, K.fxDC(e))))\r\nelseif not und and e.name == \"Divine Spark\" then\r\nadd(jo(koName(\"Divine Spark\"), \"을\", \"를\") .. \" \" .. tko .. \"에게 쓴다\", \"Divine Spark\", t.name, pct(fails(t.m, e.save, K.fxDC(e))))\r\nend\r\nend\r\nend\r\n\r\nlocal bs, bsV, bsP\r\nlocal spread = math.min(#foes, 3)\r\nfor _, n in ipairs(Spell.names()) do\r\nlocal sp = SPELLS[n]\r\nlocal m = sp and sp.m\r\nif sp and sp.level >= 1 and m and m.damage and (m.kind == \"save\" or m.kind == \"attack\" or m.kind == \"auto\") and m.cast ~= \"reaction\"\r\nand m.attack ~= \"weapon\" and not K.SUMMON[n] and not (type(pc.conc) == \"table\" and pc.conc.name == n) and K.canCast(pc, n) and spellOk(n) then\r\nlocal st = Spell.stats(n)\r\nif st then\r\nlocal dmg = avg(Spell.formula(n, m.damage, sp.level, m.type))\r\nlocal v, p\r\nif m.kind == \"save\" then\r\np = fails(t.m, m.save, st.dc)\r\nv = (p + (m.on_save == \"half\" and (1 - p) / 2 or 0)) * dmg\r\nelseif m.kind == \"attack\" then\r\np = chance(st.atk, nil, true) / 100\r\nv = p * dmg * (tonumber(m.rays) or tonumber(m.beams) or 1)\r\nelse\r\nv = dmg * (tonumber(m.darts) or 1)\r\nend\r\nif m.area then v = v * spread end\r\nif not bsV or v > bsV then bs, bsV, bsP = n, v, p end\r\nend\r\nend\r\nend\r\nif bs and not civ then\r\nlocal m = SPELLS[bs].m\r\nlocal nko = jo(koName(bs), \"을\", \"를\")\r\nlocal label = m.area and (nko .. \" 시전한다\") or (nko .. \" \" .. tko .. \"에게 시전한다\")\r\nif m.kind == \"save\" then add(label, bs, t.name, pct(bsP))\r\nelseif m.kind == \"attack\" then add(label, \"Attack\", ac, pct(bsP))\r\nelse add(label, \"-\", \"\", \"-\") end\r\nend\r\n\r\nlocal hurt, healLine\r\nfor _, r in ipairs({ pc, table.unpack(Ally.list(pc)) }) do\r\nif not r.dead and (tonumber(r.max) or 0) > 0 and (tonumber(r.hp) or 0) * 2 <= r.max\r\nand (not hurt or (tonumber(r.hp) or 0) / r.max < (tonumber(hurt.hp) or 0) / hurt.max) then hurt = r end\r\nend\r\nif hurt then\r\nlocal who = hurt == pc and \"내 상처를\" or jo(hurt.name, \"을\", \"를\")\r\nlocal hs, hsV\r\nfor _, n in ipairs(Spell.names()) do\r\nlocal sp = SPELLS[n]\r\nlocal m = sp and sp.m\r\nif sp and m and m.kind == \"heal\" and (m.heal or m.heal_all) and not m.raise and K.canCast(pc, n) and spellOk(n) then\r\nlocal v = m.heal_all and (hurt.max - math.max(0, hurt.hp)) or avg(Spell.formula(n, m.heal, sp.level))\r\nif m.cast == \"bonus\" then v = v + 1 end\r\nif not hsV or v > hsV then hs, hsV = n, v end\r\nend\r\nend\r\nlocal n0 = #o\r\nif hs then\r\nadd(ro(koName(hs)) .. \" \" .. who .. \" 치료한다\", \"-\", \"\", \"-\")\r\nelseif SHEET and K.cl(SHEET, \"Paladin\") > 0 and (res[\"Lay On Hands\"] or 0) > 0 then\r\nadd(ro(koName(\"Lay On Hands\")) .. \" \" .. who .. \" 치료한다\", \"-\", \"\", \"-\")\r\nelseif hurt == pc and SHEET and K.cl(SHEET, \"Fighter\") > 0 and (res[\"Second Wind\"] or 0) > 0 then\r\nadd(ro(koName(\"Second Wind\")) .. \" 숨을 돌린다\", \"-\", \"\", \"-\")\r\nelseif hurt == pc and (items[\"Potion of Healing\"] or 0) > 0 then\r\nadd(\"치유의 물약을 마신다\", \"-\", \"\", \"-\")\r\nend\r\nif #o > n0 then healLine = o[#o] end\r\nend\r\nif (res[\"Breath Weapon\"] or 0) > 0 then add(\"브레스 무기\", \"-\", \"\", \"-\") end\r\n\r\nlocal holy = (t.m.what or \"\"):find(\"Fiend\") or (t.m.what or \"\"):find(\"Undead\")\r\nfor _, k in ipairs({ \"Alchemist's Fire\", \"Acid\", \"Holy Water\", \"Oil\" }) do\r\nif (items[k] or 0) > 0 and (k ~= \"Holy Water\" or holy) then\r\nlocal kko = koName(k)\r\no[#o + 1] = verifyOpt({ kko .. K.josa(kko, \"을\", \"를\") .. \" 던진다\", k, t.name }, pc, c)\r\nbreak\r\nend\r\nend\r\nif K.canShove(pc, c.units[t.name]) then\r\no[#o + 1] = verifyOpt({ tko .. K.josa(tko, \"을\", \"를\") .. \" 밀쳐 넘어뜨린다\", \"Shove\", t.name }, pc, c)\r\nend\r\n\r\nlocal keep = {}\r\nfor _, line in ipairs(o) do\r\nif line:find(\"|ok|\", 1, true) and #keep < 4 then keep[#keep + 1] = line end\r\nend\r\n\r\nif healLine and #keep == 4 then\r\nlocal kept = false\r\nfor _, line in ipairs(keep) do if line == healLine then kept = true end end\r\nif not kept then keep[4] = healLine end\r\nend\r\nreturn keep\r\nend\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\nfunction K.optList(text)\r\nlocal out = {}\r\nfor rest in tostring(text or \"\"):gmatch(\"%[OPT|([^%]]*)%]\") do\r\nlocal f = split(rest)\r\nlocal a = args(f)\r\nif f[#a + 1] == \"ok\" then out[#out + 1] = { label = a[1] or \"\", kind = a[2] or \"-\", dc = tonumber(a[3] or \"\") } end\r\nend\r\nreturn out\r\nend\r\n\r\n\r\n\r\nfunction K.optPick(userText, replyText)\r\nlocal function norm(s) return (tostring(s or \"\"):gsub(\"<!%-%-.-%-%->\", \"\"):gsub(\"[%s%p]\", \"\"):lower()) end\r\nlocal u = norm(userText)\r\nif u == \"\" then return nil end\r\nfor _, o in ipairs(K.optList(replyText)) do\r\n\r\nlocal keep = K.MON_KO\r\nK.MON_KO = true\r\nlocal ko = norm(toKo(o.label))\r\nK.MON_KO = keep\r\nfor _, l in ipairs({ norm(o.label), ko }) do\r\nif l ~= \"\" and (u == l or (#l >= 9 and u:find(l, 1, true))) then return o end\r\nend\r\nend\r\nreturn nil\r\nend\r\n\r\n\r\n\r\nfunction K.optLocks(o)\r\nreturn type(o) == \"table\" and o.dc ~= nil and o.kind ~= \"Attack\" and not K.HAZ[o.kind] and bonusFor(o.kind) ~= nil\r\nend\r\n\r\nlocal function optHtml(f, n)\r\nlocal a = args(f)\r\nlocal verdict, pct = f[#a + 1] or \"\", f[#a + 2] or \"\"\r\nlocal kind, dc = a[2] or \"-\", a[3] or \"\"\r\nlocal what\r\nif kind == \"-\" or kind == \"\" then\r\nwhat = \"판정 없음\"\r\nelseif kind == \"Attack\" then\r\nwhat = \"공격 · 방어도 \" .. dc\r\nelseif K.HAZ[kind] then\r\nwhat = (kind == \"Shove\" and \"밀치기\" or koName(kind)) .. \" · \" .. toKo(dc) .. \"의 내성\"\r\nelseif kind == \"Turn Undead\" or kind == \"Divine Spark\" then\r\nwhat = koName(\"Channel Divinity\") .. \" · \" .. toKo(dc) .. \"의 내성\"\r\nelseif SPELLS[kind] then\r\nwhat = (SPELLS[kind].level == 0 and \"소마법\" or \"주문\") .. \" · \" .. toKo(dc) .. \"의 내성\"\r\nelse\r\nwhat = Ally.ko(kind) .. \" · 난이도 \" .. dc\r\nend\r\nlocal chance\r\nif verdict == \"\" then chance = \"…\"\r\nelseif verdict:match(\"^bad\") then chance = \"?\"\r\nelseif pct == \"-\" or pct == \"\" then chance = \"·\"\r\nelse chance = pct .. \"%\" end\r\n\r\n\r\nlocal pick = n and ('<span class=\"dnd-opt-btn\" style=\"flex:0 0 auto;margin-left:6px\"><button risu-btn=\"dnd_opt_' .. n\r\n.. '\" style=\"padding:4px 10px\">고르기</button></span>') or \"\"\r\nreturn string.format('<div class=\"dnd-optline\"><span class=\"dnd-pct\">%s</span><b>%s</b> <span class=\"dnd-m\">%s</span>%s</div>',\r\n\r\n\r\nesc(chance), esc(toKo(a[1] or \"\")), esc(what), pick)\r\nend\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\nlocal BUTTON_FN = {\r\ndnd_pace_on = \"dndPaceOn\", dnd_pace_off = \"dndPaceOff\",\r\ndnd_suggest_on = \"dndSuggestOn\", dnd_suggest_off = \"dndSuggestOff\",\r\ndnd_lvl_1 = \"dndLvl1\", dnd_lvl_2 = \"dndLvl2\", dnd_lvl_3 = \"dndLvl3\",\r\ndnd_lang_ko = \"dndLangKo\", dnd_lang_en = \"dndLangEn\",\r\ndnd_levelup = \"dndLevelUp\",\r\ndnd_levelup_Strength = \"dndAsiStr\", dnd_levelup_Dexterity = \"dndAsiDex\", dnd_levelup_Constitution = \"dndAsiCon\",\r\ndnd_levelup_GrapplerStr = \"dndAsiGrapStr\", dnd_levelup_GrapplerDex = \"dndAsiGrapDex\",\r\ndnd_levelup_Intelligence = \"dndAsiInt\", dnd_levelup_Wisdom = \"dndAsiWis\", dnd_levelup_Charisma = \"dndAsiCha\",\r\ndnd_hpmode_avg = \"dndHpAvg\", dnd_hpmode_roll = \"dndHpRoll\",\r\ndnd_dbg_on = \"dndDbgOn\", dnd_dbg_off = \"dndDbgOff\",\r\ndnd_dbg_hp_full = \"dndDbgHpFull\", dnd_dbg_hp_half = \"dndDbgHpHalf\", dnd_dbg_hp_zero = \"dndDbgHpZero\",\r\ndnd_dbg_xp = \"dndDbgXp\", dnd_dbg_t1h = \"dndDbgT1h\", dnd_dbg_t8h = \"dndDbgT8h\", dnd_dbg_t1d = \"dndDbgT1d\",\r\ndnd_dbg_fight = \"dndDbgFight\", dnd_dbg_end = \"dndDbgEnd\",\r\ndnd_dbg_d20_20 = \"dndDbgD20High\", dnd_dbg_d20_1 = \"dndDbgD20Low\",\r\ndnd_dbg_req_on = \"dndDbgReqOn\", dnd_dbg_req_off = \"dndDbgReqOff\",\r\n}\r\n\r\nBUTTON_FN.dnd_party_0, BUTTON_FN.dnd_party_1, BUTTON_FN.dnd_party_2, BUTTON_FN.dnd_party_3 = \"dndParty0\", \"dndParty1\", \"dndParty2\", \"dndParty3\"\r\nBUTTON_FN.dnd_dbg_ally, BUTTON_FN.dnd_dbg_ally_clear = \"dndDbgAlly\", \"dndDbgAllyClear\"\r\nBUTTON_FN.dnd_pick_mastery_RESET = \"dndPickMasteryReset\"\r\nBUTTON_FN.dnd_mastery_more = \"dndMasteryMore\"\r\nBUTTON_FN.dnd_death_srd, BUTTON_FN.dnd_death_gentle, BUTTON_FN.dnd_death_harsh = \"dndDeathSrd\", \"dndDeathGentle\", \"dndDeathHarsh\"\r\nBUTTON_FN.dnd_d2_mild, BUTTON_FN.dnd_d2_hard, BUTTON_FN.dnd_d2perm_off, BUTTON_FN.dnd_d2perm_on = \"dndD2Mild\", \"dndD2Hard\", \"dndD2PermOff\", \"dndD2PermOn\"\r\nBUTTON_FN.dnd_d2_off = \"dndD2Off\"\r\nBUTTON_FN.dnd_pack_reload = \"dndPackReload\"\r\nBUTTON_FN.dnd_d2furry_off, BUTTON_FN.dnd_d2furry_on, BUTTON_FN.dnd_d2xeno_off, BUTTON_FN.dnd_d2xeno_on = \"dndD2FurryOff\", \"dndD2FurryOn\", \"dndD2XenoOff\", \"dndD2XenoOn\"\r\nBUTTON_FN.dnd_d2lvdown_off, BUTTON_FN.dnd_d2lvdown_on = \"dndD2LvdownOff\", \"dndD2LvdownOn\"\r\nBUTTON_FN.dnd_d2hitomi_off, BUTTON_FN.dnd_d2hitomi_on = \"dndD2HitomiOff\", \"dndD2HitomiOn\"\r\nBUTTON_FN.dnd_d2omega_off, BUTTON_FN.dnd_d2omega_on = \"dndD2OmegaOff\", \"dndD2OmegaOn\"\r\nBUTTON_FN.dnd_combat_low, BUTTON_FN.dnd_combat_mid, BUTTON_FN.dnd_combat_high = \"dndCombatLow\", \"dndCombatMid\", \"dndCombatHigh\"\r\nBUTTON_FN.dnd_checkw_low, BUTTON_FN.dnd_checkw_mid, BUTTON_FN.dnd_checkw_high = \"dndCheckLow\", \"dndCheckMid\", \"dndCheckHigh\"\r\nBUTTON_FN.dnd_checkd_easy, BUTTON_FN.dnd_checkd_mid, BUTTON_FN.dnd_checkd_hard = \"dndCheckDEasy\", \"dndCheckDMid\", \"dndCheckDHard\"\r\nBUTTON_FN.dnd_fightd_easy, BUTTON_FN.dnd_fightd_mid, BUTTON_FN.dnd_fightd_hard = \"dndFightDEasy\", \"dndFightDMid\", \"dndFightDHard\"\r\nBUTTON_FN.dnd_drawer_toggle = \"dndDrawerToggle\"\r\nBUTTON_FN.dnd_drawer_close = \"dndDrawerClose\"\r\n\r\n\r\n\r\nlocal function setDrawerOpen(id, on)\r\nsetChatVar(id, \"dnd_drawer_open\", on and \"1\" or \"0\")\r\nend\r\nlocal function drawerIsOpen(id)\r\nreturn getChatVar(id, \"dnd_drawer_open\") == \"1\"\r\nend\r\n\r\n\r\nlocal BTN_FIRST = false\r\nlocal function rawBtn(label, payload)\r\n\r\n\r\nif BTN_FIRST and not BUTTON_FN[payload] and payload:sub(1, 7) == \"dnd_cg_\" and not payload:find(\"[^%w_]\") then\r\nreturn \"{{button::\" .. label .. \"::dndCg_\" .. payload:sub(8) .. \"}}\"\r\nend\r\nif BTN_FIRST and not BUTTON_FN[payload] and payload:sub(1, 9) == \"dnd_pick_\" and not payload:find(\"[^%w_]\") then\r\nreturn \"{{button::\" .. label .. \"::dndP_\" .. payload:sub(5) .. \"}}\"\r\nend\r\nif BTN_FIRST and BUTTON_FN[payload] then return \"{{button::\" .. label .. \"::\" .. BUTTON_FN[payload] .. \"}}\" end\r\nreturn '<button risu-btn=\"' .. payload .. '\">' .. label .. '</button>'\r\nend\r\nlocal function btn(label, payload, on)\r\nreturn '<span class=\"dnd-opt-btn' .. (on and \" is-on\" or \"\") .. '\">' .. rawBtn(label, payload) .. '</span>'\r\nend\r\nK.btnFn = btn\r\n\r\n\r\n\r\nK.ATK_KO = { Bite = \"물기\", Bites = \"물기\", Claw = \"발톱\", Claws = \"발톱\", [\"Rotting Claw\"] = \"썩은 발톱\", Rend = \"할퀴기\", Slam = \"후려치기\",\r\n[\"Psychic Slam\"] = \"정신 강타\", [\"Otherworldly Slam\"] = \"이계의 후려치기\", Scratch = \"긁기\", Talons = \"갈고리발톱\", Beak = \"부리\",\r\nTentacle = \"촉수\", Tentacles = \"촉수\", Sting = \"독침\", Hooves = \"발굽\", Ram = \"들이받기\", Gore = \"뿔 찌르기\", Tail = \"꼬리\",\r\nFist = \"주먹\", [\"Rotting Fist\"] = \"썩은 주먹\", Pincer = \"집게\", Pseudopod = \"위족\", [\"Life Drain\"] = \"생명 흡수\",\r\n[\"Needle Sword\"] = \"바늘 검\", [\"Enchanting Bow\"] = \"매혹의 활\", [\"Necrotic Sword\"] = \"사령 검\", [\"Necrotic Bow\"] = \"사령 활\" }\r\nfunction K.atkKo(n) return NAMES_KO[n] or K.ATK_KO[n] or koName(n) end\r\n\r\n\r\nlocal FIRST_MARK = \"※※\"\r\n\r\nlocal FIRST_INTRO = '<div class=\"dnd-intro\"><div class=\"dnd-intro-t\">❖ 새 모험</div>'\r\n.. '<div>이대로 시작하면 기본 캐릭터 <b>인간 파이터 · 군인</b>으로 진행합니다. 시트는 오른쪽 위 <b>❖ 설정 → 캐릭터</b> 탭에 있습니다.</div>'\r\n.. '<div>내 캐릭터로 하려면 첫 입력에 <b>GM: 캐릭터 만들자</b>처럼 GM에게 말을 걸면 됩니다 (원하는 것을 같이 적어도, 알아서 해 달라고 해도 됩니다). AI와 상의해서 종족·클래스·배경·능력치를 정하고, 규칙은 Lua가 검사합니다.'\r\n.. ' 이미 정해 두었다면 <b>❖ 설정 → 캐릭터</b> 탭의 양식을 채워 보내도 바로 만들어집니다.'\r\n.. ' <span class=\"dnd-m\">(종족 9 · 클래스 12 · 배경 4·직접 짓기 · 1~' .. K.maxLevelAll() .. '레벨)</span></div></div>'\r\n\r\nlocal CREATE_INTRO = '<div class=\"dnd-intro\"><div class=\"dnd-intro-t\">❖ 새 모험 · 캐릭터 만들기</div>'\r\n.. '<div>만드는 길은 셋입니다. <b>① 눌러서 만들기</b>(위)가 제일 쉽습니다.</div>'\r\n.. '<div><b>② 양식 직접 작성</b> — 복사해서 고쳐 보내면 Lua가 바로 만듭니다. 빈 칸은 클래스에 맞게 알아서 채웁니다.'\r\n.. ' 능력치는 숫자 6개(근력 민첩 건강 지능 지혜 매력 순), <b>표준 배열</b>, <b>굴림</b> 중 하나.'\r\n.. '<details style=\"margin:4px 0 6px\"><summary style=\"cursor:pointer;font-size:12px;color:#a8977a\">양식 보기</summary>'\r\n.. '<div style=\"white-space:pre-wrap;user-select:all;-webkit-user-select:all;font-size:12px;line-height:1.5;padding:6px 9px;margin-top:5px;border:1px dashed rgba(212,175,90,.45);border-radius:4px\">' .. K.Form.TEMPLATE_BR .. '</div>' .. '</details></div>'\r\n.. '<div><b>③ AI와 상의</b> — 하고 싶은 캐릭터를 대강 적어 보십시오 (예: <b>GM: 엘프 로그로 캐릭터 만들자, 능력치는 굴려서</b>). '\r\n.. 'AI가 종족·클래스·배경·능력치·기술·장비를 차례로 물어보고, 규칙은 Lua가 검사합니다.</div>'\r\n.. '<div>@START@ 만들기 전까지는 기본 캐릭터(인간 파이터)로 계산됩니다.'\r\n.. ' <span class=\"dnd-m\">(종족 9 · 클래스 12 · 배경 4·직접 짓기 · 1~' .. K.maxLevelAll() .. '레벨)</span></div></div>'\r\n\r\n\r\nK.START_LINE = {\r\nporter = \"다 만들어지면 짐꾼의 물음에 답하며 모험을 시작하면 됩니다.\",\r\ntable = \"다 만들어지면 아래 이야기처럼 첫 장면을 정해 보내면 모험이 시작됩니다.\",\r\n}\r\nK.START_DONE = {\r\nporter = \"이제 짐꾼의 물음에 답하며 시작하면 됩니다.\",\r\ntable = \"이제 첫 장면을 정해 보내면 시작됩니다.\",\r\n}\r\n\r\nlocal function optRow(title, desc, on, payloadOn, payloadOff)\r\nreturn '<div class=\"dnd-opt\"><div class=\"dnd-opt-t\">' .. title .. '</div><div class=\"dnd-opt-d\">' .. desc .. '</div><div class=\"dnd-opt-btns\">'\r\n.. btn(\"켜기\", payloadOn, on) .. btn(\"끄기\", payloadOff, not on) .. '</div></div>'\r\nend\r\n\r\n\r\nfunction K.En.row(id)\r\nlocal en = K.En.on(id)\r\nreturn '<div class=\"dnd-opt\"><div class=\"dnd-opt-t\">❖ 이야기 언어</div><div class=\"dnd-opt-d\">'\r\n.. 'English를 고르면 AI가 이야기와 선택지, GM의 말을 영어로 씁니다. 첫 메시지도 영어판으로 보내고, 한글 용어 대조표는 넣지 않습니다.'\r\n.. ' 화면의 상자와 상태창은 한국어 그대로입니다. 이미 한국어로 진행한 채팅에서 바꾸면 앞의 답들이 한국어로 남습니다.</div>'\r\n.. '<div class=\"dnd-opt-btns\">' .. btn(\"한국어\", \"dnd_lang_ko\", not en) .. btn(\"English\", \"dnd_lang_en\", en) .. '</div></div>'\r\nend\r\n\r\nlocal function levelRow(lv)\r\nlocal names = { \"처음\", \"조금\", \"잘 앎\" }\r\nlocal btns = {}\r\nfor i, nm in ipairs(names) do\r\nbtns[#btns + 1] = btn(nm, \"dnd_lvl_\" .. i, lv == tostring(i))\r\nend\r\nreturn '<div class=\"dnd-opt\"><div class=\"dnd-opt-t\">❖ TRPG 익숙함</div><div class=\"dnd-opt-d\">'\r\n.. '처음: 규칙이 처음 나올 때 서술 속에서 풀어 줍니다.<br>'\r\n.. '조금: 규칙 용어에 점선이 생기고, 누르면 한 줄 설명이 뜹니다.<br>잘 앎: 설명 없이 진행합니다.</div>'\r\n.. '<div class=\"dnd-opt-btns\">' .. table.concat(btns) .. '</div></div>'\r\nend\r\n\r\n\r\nlocal FEATURE_KO = {\r\n[\"Fighting Style\"] = { \"전투 유파\", \"전투 유파 재주 하나를 고릅니다 (궁술·방어술·대형 무기 전투술·쌍수 전투술 등).\" },\r\n[\"Second Wind\"] = { \"재기의 바람\", \"추가 행동으로 1d10 + 파이터 레벨만큼 회복. 짧은 휴식에 1회, 긴 휴식에 전부 다시 찹니다.\" },\r\n[\"Weapon Mastery\"] = { \"무기 통달\", \"고른 무기의 통달 속성(가르기·스치기·밀치기 등)을 쓸 수 있습니다.\" },\r\n[\"Action Surge\"] = { \"행동 연쇄\", \"내 턴에 행동을 한 번 더 합니다 (마법 행동 제외). 짧은 휴식이나 긴 휴식으로 다시 찹니다. 17레벨부터는 휴식 사이 두 번(한 턴에 한 번).\" },\r\n[\"Tactical Mind\"] = { \"전술적 사고\", \"능력 판정에 실패하면 재기의 바람 1회를 써서 1d10을 더합니다. 그래도 실패하면 소모되지 않습니다.\" },\r\n[\"Ability Score Improvement\"] = { \"능력치 점수 상승\", \"능력치 하나에 +2, 또는 둘에 +1씩 (최대 20). 대신 일반 재주 하나를 골라도 됩니다(SRD의 잡기 전문가, 모듈이 더한 일반 재주). 레벨 업 화면에서 고릅니다.\" },\r\n[\"Extra Attack\"] = { \"추가 공격\", \"공격 행동을 할 때 두 번 공격합니다.\" },\r\n[\"Tactical Shift\"] = { \"전술적 이동\", \"재기의 바람을 쓸 때 기회공격을 받지 않고 속도 절반만큼 움직입니다.\" },\r\n[\"Expertise\"] = { \"숙달\", \"고른 기술 두 개에 숙련 보너스를 두 배로 더합니다 (기술 옆 ★).\" },\r\n[\"Sneak Attack\"] = { \"암습 공격\", \"턴마다 한 번, 이점이 있거나 대상 옆에 아군이 있을 때 기교·원거리 무기 피해에 주사위를 더합니다 (1d6, 3레벨부터 홀수 레벨마다 1d6씩 늘어 19레벨 10d6).\" },\r\n[\"Thieves' Cant\"] = { \"도둑의 속어\", \"도둑들끼리 쓰는 속어와 표식을 압니다. 언어도 하나 더 압니다.\" },\r\n[\"Cunning Action\"] = { \"교활한 행동\", \"추가 행동으로 질주·이탈·숨기를 할 수 있습니다.\" },\r\n[\"Steady Aim\"] = { \"차분한 조준\", \"이번 턴에 움직이지 않았다면 추가 행동으로 다음 공격에 이점 (그 뒤 속도 0).\" },\r\n[\"Cunning Strike\"] = { \"교활한 일격\", \"암습 공격 주사위를 줄여서 중독·넘어뜨리기·물러나기 같은 효과를 줍니다.\" },\r\n[\"Uncanny Dodge\"] = { \"놀라운 회피\", \"보이는 적의 공격에 맞으면 반응행동으로 피해를 절반으로 줄입니다.\" },\r\n[\"Spellcasting\"] = { \"주문시전\", \"준비한 주문을 주문 슬롯을 써서 시전합니다. 명중·내성·피해·회복은 Lua가 확인합니다.\" },\r\n[\"Divine Order\"] = { \"신성한 소임\", \"수호자(군용 무기·중갑 숙련) 또는 기적술사(소마법 하나 더, 비전학·종교학 판정 보너스) 중 하나.\" },\r\n\r\n[\"Channel Divinity\"] = { \"신성 변환\", \"1회로 신성한 불꽃(치유나 피해), 언데드 퇴치(5레벨부터 언데드 태우기 피해), 권역이 더하는 것(생명 권역의 생명 보존 등) 가운데 하나를 일으킵니다.\"\r\n.. \" 무엇을 하는지는 아래 ▼ 기능의 '할 수 있는 것'에 하나씩 있습니다. 짧은 휴식에 1회, 긴 휴식에 전부 다시 찹니다.\" },\r\n[\"Sear Undead\"] = { \"언데드 태우기\", \"언데드 퇴치를 쓸 때 지혜 수정치만큼 d8 광휘 피해도 줍니다.\" },\r\n[\"Ritual Adept\"] = { \"의식 시전\", \"주문책의 의식 주문을 슬롯 없이 의식으로 시전합니다 (10분 더 걸림).\" },\r\n[\"Arcane Recovery\"] = { \"비전 회복\", \"짧은 휴식을 하면 Lua가 알아서 써서 주문 슬롯 일부를 되찾습니다 (레벨 합 = 위저드 레벨 절반, 올림). 긴 휴식마다 한 번.\" },\r\n[\"Scholar\"] = { \"학자\", \"비전학·역사학·수사·의학·자연학·종교학 중 숙련된 하나에 숙달을 얻습니다.\" },\r\n[\"Memorize Spell\"] = { \"주문 암기\", \"짧은 휴식 때 준비한 주문 하나를 주문책의 다른 주문으로 바꿉니다.\" },\r\n}\r\nlocal SUBCLASS_TIP = {\r\nChampion = \"19~20에도 치명타가 나고(향상된 치명타, 15레벨부터 18~20), 우선권과 운동 판정에 이점(뛰어난 운동능력).\",\r\nThief = \"추가 행동으로 손속임·도구·물건 사용(빠른 손놀림), 빨리 오르고 멀리 뜁니다(오르내리기).\",\r\n[\"Life Domain\"] = \"치유 주문이 더 회복하고(생명의 사도), 신성 변환으로 여럿을 치유합니다(생명 보존).\",\r\nEvoker = \"방출학파 주문을 싸게 옮겨 적고(방출계 전공), 소마법이 빗나가도 피해 절반(강화된 소마법).\",\r\n}\r\n\r\nfor k, tip in pairs({\r\nRage = \"추가 행동으로 들어갑니다 (중갑 X). 근력 공격 피해 +2(9레벨 +3, 16레벨 +4), 타격·관통·참격 피해 저항, 근력 판정·내성 이점, 주문 불가. 전투가 끝나면 Lua가 끕니다. 짧은 휴식에 1회, 긴 휴식에 전부 다시 찹니다.\",\r\n[\"Barbarian|Unarmored Defense\"] = \"갑옷을 입지 않으면 방어도 = 10 + 민첩 + 건강 (방패는 들어도 됩니다).\",\r\n[\"Danger Sense\"] = \"민첩 내성 굴림에 이점 (행동불능이 아닐 때).\",\r\n[\"Reckless Attack\"] = \"턴의 첫 공격 때 고르면, 이번 턴 근력 공격에 이점. 대신 다음 내 턴까지 나를 노리는 공격도 이점.\",\r\n[\"Primal Knowledge\"] = \"바바리안 기술 하나 더 숙련. 격노 중엔 곡예·위협·감지·은신·생존 판정을 근력으로 할 수 있습니다.\",\r\n[\"Fast Movement\"] = \"중갑을 입지 않으면 속도 +10피트.\",\r\n[\"Bardic Inspiration\"] = \"추가 행동으로 60피트 안의 다른 사람에게 고양감 주사위(d6, 5레벨 d8, 10레벨 d10, 15레벨 d12)를 줍니다. 받은 사람은 1시간 안에 d20을 실패하면 그 주사위를 더합니다. 매력 수정치만큼, 긴 휴식에 다시 찹니다.\",\r\n[\"Jack of All Trades\"] = \"숙련이 없는 기술 판정에 숙련 보너스 절반(내림)을 더합니다.\",\r\n[\"Font of Inspiration\"] = \"바드의 고양감이 짧은 휴식에도 모두 다시 차고, 주문 슬롯을 써서 1회 되찾을 수도 있습니다.\",\r\nDruidic = \"드루이드의 비밀 언어를 알고, 동물과 대화 주문을 늘 준비해 둡니다.\",\r\n[\"Primal Order\"] = \"주술사(소마법 하나 더, 비전학·자연학 판정에 지혜 수정치) 또는 수호자(군용 무기·평갑 숙련) 중 하나.\",\r\n[\"Wild Shape\"] = \"추가 행동으로 본 적 있는 짐승으로 변합니다 (2레벨: 도전 지수 1/4 이하, 비행 속도 없는 것 · 4레벨: 1/2 이하 · 8레벨: 1 이하, 비행 속도도). 짐승의 방어도·속도·공격을 쓰고, 생명력은 그대로에 임시 생명력 = 드루이드 레벨. 변신 중엔 주문 불가. 짧은 휴식에 1회, 긴 휴식에 전부.\",\r\n[\"Wild Companion\"] = \"주문 슬롯이나 야생 변신 1회로 패밀리어 찾기를 시전합니다 (요정 형태).\",\r\n[\"Wild Resurgence\"] = \"야생 변신이 남지 않았으면 주문 슬롯으로 1회 되찾고, 긴 휴식마다 한 번 야생 변신으로 1레벨 슬롯을 되찾습니다.\",\r\n[\"Martial Arts\"] = \"갑옷·방패 없이 맨손이나 몽크 무기(단순 근접 무기, 경량 군용 근접 무기)를 쓰면 민첩을 쓸 수 있고 피해는 무술 주사위(1d6, 5레벨 1d8, 11레벨 1d10, 17레벨 1d12). 추가 행동으로 맨손 공격 하나.\",\r\n[\"Monk|Unarmored Defense\"] = \"갑옷과 방패 없이 방어도 = 10 + 민첩 + 지혜.\",\r\n[\"Monk's Focus\"] = \"기 점수 = 몽크 레벨. 1점씩: 연타(추가 행동 맨손 두 번), 인내의 방어(추가 행동 이탈 + 회피), 바람 걸음(추가 행동 이탈 + 질주). 짧은 휴식에 다 찹니다.\",\r\n[\"Unarmored Movement\"] = \"갑옷과 방패 없이 속도 +10피트 (6레벨 +15, 10레벨 +20, 14레벨 +25, 18레벨 +30).\",\r\n[\"Uncanny Metabolism\"] = \"우선권을 굴릴 때 긴 휴식마다 한 번, 기 점수를 다 채우고 무술 주사위 + 몽크 레벨만큼 회복합니다.\",\r\n[\"Deflect Attacks\"] = \"타격·관통·참격 공격에 맞으면 반응행동으로 피해를 1d10 + 민첩 + 몽크 레벨만큼 줄입니다.\",\r\n[\"Slow Fall\"] = \"떨어질 때 반응행동으로 낙하 피해를 몽크 레벨 × 5만큼 줄입니다.\",\r\n[\"Stunning Strike\"] = \"턴에 한 번, 몽크 무기나 맨손으로 맞히면 기 1점: 대상이 건강 내성에 실패하면 다음 내 턴까지 충격 상태.\",\r\n[\"Lay On Hands\"] = \"치유의 손길 점수 = 팔라딘 레벨 × 5. 추가 행동으로 닿은 사람을 원하는 점수만큼 회복 (5점으로 중독 해제). 긴 휴식에 다 찹니다.\",\r\n[\"Paladin's Smite\"] = \"신성한 강타를 늘 준비해 두고, 긴 휴식마다 한 번은 슬롯 없이 시전합니다.\",\r\n[\"Paladin|Channel Divinity\"] = \"1회로 신성 감지, 적 물리치기(9레벨), 맹세가 더하는 것(헌신의 맹세의 무기 축성 등) 가운데 하나를 일으킵니다. 무엇을 하는지는 아래 ▼ 기능의\"\r\n.. \" '할 수 있는 것'에 하나씩 있습니다. 짧은 휴식에 1회, 긴 휴식에 전부 다시 찹니다.\",\r\n[\"Faithful Steed\"] = \"탈것 부르기를 늘 준비해 두고, 긴 휴식마다 한 번은 슬롯 없이 시전합니다.\",\r\n[\"Favored Enemy\"] = \"사냥꾼의 표식을 늘 준비해 두고, 긴 휴식마다 두 번(5레벨 3번, 9레벨 4번, 13레벨 5번, 17레벨 6번)은 슬롯 없이 시전합니다.\",\r\n[\"Deft Explorer\"] = \"숙련된 기술 하나에 숙달, 언어 둘을 더 압니다.\",\r\n[\"Innate Sorcery\"] = \"추가 행동으로 1분 동안 소서러 주문 내성 난이도 +1, 소서러 주문 명중에 이점. 긴 휴식마다 2회. 여기서는 전투가 끝나면 Lua가 끕니다.\",\r\n[\"Font of Magic\"] = \"술법 점수 = 소서러 레벨, 긴 휴식에 다 찹니다. 주문 슬롯을 술법 점수로, 술법 점수를 슬롯으로 바꿀 수 있습니다.\",\r\nMetamagic = \"마법변형 둘(10레벨 넷, 17레벨 여섯)을 골라 술법 점수로 주문을 고쳐 씁니다 (캐릭터 탭 설명).\",\r\n[\"Sorcerous Restoration\"] = \"짧은 휴식 때 술법 점수를 레벨 절반(내림)만큼 되찾습니다. 긴 휴식마다 1회.\",\r\n[\"Eldritch Invocations\"] = \"섬뜩한 영창을 골라 늘 쓰는 능력을 얻습니다 (1레벨 1개, 2레벨 3개, 5레벨 5개, 7레벨 6개, 9레벨 7개, 12레벨 8개, 15레벨 9개, 18레벨 10개). 캐릭터 탭 설명.\",\r\n[\"Pact Magic\"] = \"주문 슬롯이 모두 가장 높은 레벨이고, 짧은 휴식에도 다 찹니다.\",\r\n[\"Magical Cunning\"] = \"1분 의식으로 쓴 계약 마법 슬롯의 절반(올림)을 되찾습니다. 긴 휴식마다 1회.\",\r\n[\"Focus Points\"] = \"기를 쓰는 기능(연타·인내의 방어·바람 걸음·충격의 일격)에 쓰는 점수. 짧은 휴식에 다 찹니다.\",\r\n[\"Sorcery Points\"] = \"마법변형에 쓰고, 주문 슬롯과 서로 바꿀 수 있는 점수. 긴 휴식에 다 찹니다.\",\r\n}) do\r\nlocal cl, key = k:match(\"^(%a+)|(.+)$\")\r\nFEATURE_KO[k] = { NAMES_KO[key or k] or (key or k), tip }\r\nend\r\nSUBCLASS_TIP[\"Path of the Berserker\"] = \"광분: 격노 중에 무모한 공격을 하면 턴마다 첫 명중에 격노 피해 보너스만큼 d6을 더합니다.\"\r\nSUBCLASS_TIP[\"College of Lore\"] = \"기술 숙련 셋을 더 얻고, 날카로운 말: 반응행동으로 고양감 주사위를 굴려 적의 피해·능력 판정·명중 굴림에서 뺍니다.\"\r\nSUBCLASS_TIP[\"Circle of the Land\"] = \"고른 땅(건조 지대·극지·온대·열대)의 주문을 늘 준비합니다. 대지의 도움: 야생 변신 1회로 10피트 구역에 2d6 사령 피해(건강 내성, 성공 시 절반)와 한 명 2d6 회복 (10레벨 3d6, 14레벨 4d6).\"\r\nSUBCLASS_TIP[\"Warrior of the Open Hand\"] = \"열린 손의 기법: 연타로 맞힐 때마다 기회공격 막기·15피트 밀기(근력 내성)·넘어뜨리기(민첩 내성) 중 하나.\"\r\nSUBCLASS_TIP[\"Oath of Devotion\"] = \"무기 축성: 신성 변환으로 10분 동안 근접 무기 명중에 매력 수정치(최소 +1)를 더합니다. 맹세 주문(악과 선으로부터의 보호·신앙의 방패, 5레벨 원호·진실의 공간 등)을 늘 준비.\"\r\nSUBCLASS_TIP.Hunter = \"사냥꾼의 사냥감 하나: 거체 학살자(다친 적에게 턴마다 한 번 무기 명중에 1d8) 또는 무리 파쇄자(턴마다 한 번, 처음 대상 5피트 안의 다른 적에게 한 번 더 공격).\"\r\nSUBCLASS_TIP[\"Draconic Sorcery\"] = \"용의 회복력: 생명력이 레벨마다 1 더, 갑옷 없이 방어도 = 10 + 민첩 + 매력. 용 주문(자기 변형·오색의 보주·명령·용의 숨결)을 늘 준비.\"\r\nSUBCLASS_TIP[\"Fiend Patron\"] = \"어두운 이의 축복: 적을 생명력 0으로 만들면 임시 생명력 = 매력 수정치 + 워락 레벨. 악마 주문(타오르는 손길·명령·타오르는 광선·암시)을 늘 준비.\"\r\n\r\n\r\nFeat.TIP = {\r\nstyle = { Archery = \"원거리 무기 명중 굴림 +2.\", Defense = \"갑옷을 입고 있으면 방어도 +1.\",\r\n[\"Great Weapon Fighting\"] = \"양손 근접 무기 피해 주사위의 1·2를 3으로 칩니다.\", [\"Two-Weapon Fighting\"] = \"보조 손 공격에도 능력치 수정치를 더합니다.\" },\r\nmastery = { Cleave = \"근접으로 맞히면 5피트 안 다른 적에게 한 번 더 (피해에 능력치 수정치는 안 붙고, 분노 같은 보너스는 붙습니다), 턴에 한 번.\", Graze = \"빗나가도 능력치 수정치만큼 피해.\",\r\nNick = \"경량 보조 무기 공격을 추가 행동 없이 공격 행동에 넣습니다.\", Push = \"맞히면 대형 이하를 10피트 밀어냅니다.\",\r\nSap = \"맞히면 대상의 다음 명중 굴림에 불리점.\", Slow = \"맞히면 대상 속도 -10피트 (다음 내 턴까지).\",\r\nTopple = \"맞히면 대상이 건강 내성에 실패할 때 넘어집니다.\", Vex = \"맞히면 그 대상을 향한 내 다음 명중 굴림에 이점.\" },\r\n\r\norder = {\r\nProtector = \"앞에 서서 싸우는 클레릭이 됩니다.\\n\"\r\n.. \"  군용 무기(롱소드·배틀액스·그레이트소드 같은 무기)를 쓸 수 있습니다.\\n\"\r\n.. \"  중갑(사슬 갑옷·판금 갑옷)을 입을 수 있어 방어도가 크게 오릅니다. 갑옷은 따로 구해야 하고, 근력이 모자라면 입었을 때 느려집니다.\\n\"\r\n.. \"몸으로 동료를 지키고 싶을 때 좋습니다.\",\r\nThaumaturge = \"주문 쪽에 힘을 싣는 클레릭이 됩니다.\\n\"\r\n.. \"  클레릭 소마법을 하나 더 배웁니다. 소마법은 주문 슬롯 없이 몇 번이든 씁니다.\\n\"\r\n.. \"  고른 뒤 GM에게 \\\"소마법 하나 더 고르자\\\"라고 말을 걸면 함께 고릅니다.\\n\"\r\n.. \"  비전학·종교학 판정(마법과 신에 대한 지식)에 지혜 수정치(최소 +1)를 더합니다.\\n\"\r\n.. \"뒤에서 주문으로 돕고, 아는 것으로 실마리를 푸는 클레릭에게 좋습니다.\",\r\n},\r\nlineage = { Drow = \"암시야가 120피트로 늘어납니다 (빛이 없어도 약 36m).\\n춤추는 빛 소마법.\\n3레벨 요정불, 5레벨 어둠 (하루 한 번 슬롯 없이).\",\r\n[\"High Elf\"] = \"요술 소마법 (긴 휴식 때 위저드 소마법으로 바꿀 수 있습니다).\\n3레벨 마법 탐지, 5레벨 안개 걸음 (하루 한 번 슬롯 없이).\",\r\n[\"Wood Elf\"] = \"이동 속도 35피트 (보통 30).\\n드루이드 소마법.\\n3레벨 활보, 5레벨 흔적 없는 이동 (하루 한 번 슬롯 없이).\" },\r\ngnome = { Forest = \"하급 환영 소마법.\\n동물과 대화를 숙련 보너스만큼 슬롯 없이 (긴 휴식에 다시 찹니다).\",\r\nRock = \"수리·요술 소마법.\\n작은 태엽 장치를 만듭니다 (불빛·소리·장난감 같은 것).\" },\r\ndragon = { Acid = \"산성 숨결, 산성 피해 저항 (검정·구리 용).\", Cold = \"냉기 숨결, 냉기 피해 저항 (은·백색 용).\",\r\nFire = \"화염 숨결, 화염 피해 저항 (금·놋쇠·적색 용).\", Lightning = \"번개 숨결, 번개 피해 저항 (청색·청동 용).\",\r\nPoison = \"독 숨결, 독성 피해 저항 (녹색 용).\" },\r\ngiant = { Cloud = \"추가 행동으로 30피트 순간이동.\", Fire = \"명중 시 1d10 화염 추가.\", Frost = \"명중 시 1d6 냉기 추가, 대상 속도 -10피트.\",\r\nHill = \"명중 시 대형 이하 대상을 넘어뜨립니다.\", Stone = \"반응행동으로 받은 피해를 1d12 + 건강만큼 줄입니다.\",\r\nStorm = \"반응행동으로 나를 친 상대에게 1d8 천둥 피해.\" },\r\nlegacy = { Abyssal = \"독성 피해 저항, 독 분사 소마법.\\n3레벨 통증 광선, 5레벨 인간형 포박.\", Chthonic = \"사령 피해 저항, 냉랭한 접촉 소마법.\\n3레벨 거짓 삶, 5레벨 무력화 광선.\",\r\nInfernal = \"화염 피해 저항, 화염 화살 소마법.\\n3레벨 지옥의 질책, 5레벨 어둠.\" },\r\nprimal = { Magician = \"소마법 하나 더, 비전학·자연학 판정에 지혜 수정치.\", Warden = \"군용 무기·평갑 숙련.\" },\r\nland = { Arid = \"흐려짐·타오르는 손길·화염 화살, 5레벨 화염구, 7레벨 황폐화, 9레벨 바위 벽.\", Polar = \"안개 구름·인간형 포박·서리 광선, 5레벨 진눈깨비 폭풍, 7레벨 얼음 폭풍, 9레벨 냉기 원뿔.\",\r\nTemperate = \"안개 걸음·전격의 손아귀·수면, 5레벨 번개, 7레벨 이동의 자유, 9레벨 나무 걸음.\", Tropical = \"산성 거품·통증 광선·거미줄, 5레벨 악취 구름, 7레벨 변신, 9레벨 곤충 떼.\" },\r\nprey = { [\"Colossus Slayer\"] = \"다친 적에게 턴마다 한 번, 무기 명중에 1d8 더.\",\r\n[\"Horde Breaker\"] = \"턴마다 한 번, 처음 대상 5피트 안의 다른 적에게 같은 무기로 한 번 더 공격.\" },\r\nfeat = {\r\nAlert = \"전투가 시작될 때 남보다 먼저 움직이기 쉬워집니다.\\n\"\r\n.. \"  우선권(전투에서 누가 먼저 움직일지 정하는 굴림)에 숙련 보너스를 더합니다. 1~4레벨은 +2이고, 레벨이 오르면 커집니다.\\n\"\r\n.. \"  따로 할 일은 없습니다. Lua가 알아서 더합니다.\\n\"\r\n.. \"  규칙에는 우선권을 굴린 뒤 동료와 순서를 바꾸는 효과도 있지만, 이 봇에서는 아직 쓸 수 없습니다.\\n\"\r\n.. \"먼저 치고 들어가거나, 쓰러진 동료를 서둘러 살려야 하는 캐릭터에게 좋습니다.\",\r\n[\"Magic Initiate\"] = \"다른 클래스의 마법을 조금 배웁니다.\\n\"\r\n.. \"  클레릭·드루이드·위저드 중 한 목록을 고릅니다. 배경이 복사면 클레릭, 현자면 위저드 목록으로 정해져 있습니다.\\n\"\r\n.. \"  그 목록의 소마법 둘: 주문 슬롯 없이 몇 번이든 씁니다.\\n\"\r\n.. \"  그 목록의 1레벨 주문 하나: 긴 휴식마다 한 번은 슬롯 없이 쓰고, 주문 슬롯이 있으면 슬롯으로도 씁니다.\\n\"\r\n.. \"  주문에 쓰는 능력치는 클레릭·드루이드 목록이면 지혜, 위저드 목록이면 지능입니다.\\n\"\r\n.. \"  주문은 GM에게 \\\"마법 입문자 주문 정하자\\\"라고 말을 걸면 함께 고릅니다.\\n\"\r\n.. \"주문을 못 쓰는 클래스도 마법을 조금 쓸 수 있게 되고, 주문 시전자는 쓸 수 있는 주문이 늘어납니다.\",\r\n[\"Savage Attacker\"] = \"무기로 맞혔을 때 피해가 커집니다.\\n\"\r\n.. \"  한 턴에 한 번, 무기 피해 주사위를 두 번 굴려 높은 쪽을 씁니다. 1d8 무기에서 3과 7이 나오면 7입니다.\\n\"\r\n.. \"  주사위가 큰 무기(그레이트소드 2d6, 그레이트액스 1d12)일수록 효과가 큽니다.\\n\"\r\n.. \"  따로 할 일은 없습니다. AI가 주사위를 두 번 쓰고 Lua가 높은 쪽을 셉니다.\\n\"\r\n.. \"무기를 들고 앞에서 싸우는 캐릭터에게 좋습니다. 주문 공격에는 붙지 않습니다.\",\r\n\r\nGrappler = \"맨손으로 붙잡고 싸우는 데 능해집니다.\\n\"\r\n.. \"  근력이나 민첩 +1(재주를 고를 때 정했습니다).\\n\"\r\n.. \"  내 턴에 공격 행동으로 맨손 공격을 맞히면 피해와 붙잡기를 한 번에 함께 할 수 있습니다(턴마다 한 번).\\n\"\r\n.. \"  내가 붙잡고 있는 생물을 공격할 때 이점을 받습니다.\\n\"\r\n.. \"  나와 크기가 같거나 작은 생물은 붙잡은 채로 움직여도 이동력이 더 들지 않습니다.\\n\"\r\n.. \"적을 붙잡아 두고 치는 캐릭터에게 좋습니다.\",\r\nSkilled = \"기술 숙련을 셋 더 얻습니다.\\n\"\r\n.. \"  숙련된 기술로 판정하면 숙련 보너스(1~4레벨은 +2)가 붙어 성공하기 쉬워집니다.\\n\"\r\n.. \"  고르면 이 탭에서 기술 셋을 이어서 고릅니다. 규칙상 도구 숙련도 고를 수 있지만 이 봇은 기술만 다룹니다.\\n\"\r\n.. \"대화, 조사, 몰래 움직이기처럼 전투 밖에서 할 줄 아는 게 많은 캐릭터를 원할 때 좋습니다.\",\r\n},\r\nmetamagic = { [\"Careful Spell\"] = \"1점: 내성 굴림 주문에서 매력 수정치만큼의 대상은 자동 성공, 피해도 안 받습니다.\",\r\n[\"Distant Spell\"] = \"1점: 사거리 2배, 접촉 주문은 30피트.\", [\"Empowered Spell\"] = \"1점: 피해 주사위를 매력 수정치 개수만큼 다시 굴립니다.\",\r\n[\"Extended Spell\"] = \"1점: 지속시간 2배 (최대 24시간), 집중 유지 내성에 이점.\", [\"Heightened Spell\"] = \"2점: 한 대상이 첫 내성 굴림에 불리점.\",\r\n[\"Quickened Spell\"] = \"2점: 행동 대신 추가 행동으로 시전.\", [\"Seeking Spell\"] = \"1점: 주문 명중 굴림이 빗나가면 다시 굴립니다.\",\r\n[\"Subtle Spell\"] = \"1점: 말·손짓·재료 없이 몰래 시전.\", [\"Transmuted Spell\"] = \"1점: 피해 종류(산성·냉기·화염·번개·독성·천둥)를 다른 하나로.\",\r\n[\"Twinned Spell\"] = \"1점: 슬롯을 올리면 대상이 느는 주문을 한 레벨 높여 쓴 것처럼 한 명 더.\" },\r\ninvocations = { [\"Agonizing Blast\"] = \"섬뜩한 마탄 피해에 매력 수정치를 더합니다 (2레벨~).\", [\"Armor of Shadows\"] = \"마법 갑주를 자신에게 슬롯 없이 마음대로.\",\r\n[\"Devil's Sight\"] = \"마법적 어둠 속에서도 120피트까지 보통처럼 봅니다 (2레벨~).\", [\"Eldritch Mind\"] = \"집중 유지 건강 내성에 이점.\",\r\n[\"Fiendish Vigor\"] = \"거짓 삶을 자신에게 슬롯 없이 마음대로, 주사위는 최댓값 (2레벨~).\", [\"Mask of Many Faces\"] = \"자기 위장을 슬롯 없이 마음대로 (2레벨~).\",\r\n[\"Misty Visions\"] = \"조용한 영상을 슬롯 없이 마음대로 (2레벨~).\",\r\n[\"Pact of the Blade\"] = \"추가 행동으로 계약 무기를 부르거나 무기와 결속. 그 무기는 매력으로 치고 숙련으로 칩니다. 피해는 무기 종류나 사령·정신·광휘 중 대상에게 잘 먹히는 쪽으로 들어갑니다.\",\r\n[\"Pact of the Chain\"] = \"패밀리어 찾기를 알고 특별한 형태(임프·슈도드래곤 등)를 고를 수 있습니다.\",\r\n[\"Pact of the Tome\"] = \"그림자의 책: 소마법 셋과 의식 주문 둘이 든 책.\", [\"Repelling Blast\"] = \"명중 굴림 소마법(섬뜩한 마탄 등)으로 맞히면 10피트 밀어냅니다 (2레벨~).\",\r\n[\"Thirsting Blade\"] = \"칼날의 계약 무기로 공격 행동을 하면 두 번 공격 (5레벨~).\", [\"One with Shadows\"] = \"어둑하거나 어두운 곳에서 마법 행동으로 투명 (5레벨~).\",\r\n[\"Master of Myriad Forms\"] = \"자기 변형을 슬롯 없이 마음대로 (5레벨~).\", [\"Ascendant Step\"] = \"자신에게 부양을 슬롯 없이 마음대로 (5레벨~).\",\r\n[\"Gift of the Depths\"] = \"물속에서 숨 쉬고 헤엄 속도, 수중 호흡 하루 한 번 슬롯 없이 (5레벨~).\",\r\n[\"Eldritch Spear\"] = \"피해를 주는 워락 소마법의 사거리가 레벨×30피트 늡니다 (2레벨~).\",\r\n[\"Otherworldly Leap\"] = \"자신에게 도약을 슬롯 없이 마음대로 (2레벨~).\",\r\n[\"Gaze of Two Minds\"] = \"추가 행동으로 동의한 생물 하나를 만져, 다음 내 턴이 끝날 때까지 그 생물의 감각으로 보고 듣습니다 (5레벨~).\",\r\n[\"Eldritch Smite\"] = \"턴마다 한 번 계약 무기가 맞으면 계약 슬롯 하나로 1d8 + 슬롯 레벨마다 1d8 역장 피해, 거대형 이하면 넘어뜨림 (5레벨~).\",\r\n[\"Investment of the Chain Master\"] = \"패밀리어가 비행·수영 속도, 마법 공격, 추가 행동 명령, 내성은 내 주문 난이도 (5레벨~).\",\r\n[\"Whispers of the Grave\"] = \"죽은 자와의 대화를 슬롯 없이 마음대로 (7레벨~).\",\r\n[\"Lifedrinker\"] = \"턴마다 한 번 계약 무기가 맞으면 1d6 사령·정신·광휘 피해, 생명력 주사위 하나로 회복 가능 (9레벨~).\",\r\n[\"Visions of Distant Realms\"] = \"비전의 눈을 슬롯 없이 마음대로 (9레벨~).\",\r\n[\"Gift of the Protectors\"] = \"그림자의 책에 이름을 적은 이가 0이 되면 1이 됩니다, 긴 휴식마다 한 번 (9레벨~).\",\r\n[\"Devouring Blade\"] = \"목마른 칼날의 공격이 세 번이 됩니다 (12레벨~).\",\r\n[\"Witch Sight\"] = \"30피트 안에서 진시야 (15레벨~).\" },\r\n}\r\nlocal SKILL_TIP = {\r\nAthletics = \"근력: 오르기·헤엄·뛰기·붙잡기·밀치기\", Acrobatics = \"민첩: 균형 잡기·구르기·붙잡기에서 빠져나가기\",\r\n[\"Sleight of Hand\"] = \"민첩: 소매치기·물건 몰래 숨기기\", Stealth = \"민첩: 들키지 않고 숨고 움직이기\",\r\nArcana = \"지능: 주문·마법 물건·다른 세계에 대한 지식\", History = \"지능: 옛 사건·왕국·전쟁에 대한 지식\",\r\nInvestigation = \"지능: 단서를 찾고 추리하기\", Nature = \"지능: 지형·동식물·날씨에 대한 지식\", Religion = \"지능: 신·의식·교단에 대한 지식\",\r\n[\"Animal Handling\"] = \"지혜: 동물을 달래고 다루기\", Insight = \"지혜: 상대의 속마음과 거짓말 알아채기\",\r\nMedicine = \"지혜: 쓰러진 사람 안정시키기·병 알아보기\", Perception = \"지혜: 보고 듣고 알아채기\",\r\nSurvival = \"지혜: 흔적 쫓기·길 찾기·사냥하기\", Deception = \"매력: 속이기\", Intimidation = \"매력: 겁주기\",\r\nPerformance = \"매력: 노래·연기·연주\", Persuasion = \"매력: 설득하기\",\r\n}\r\n\r\nlocal DAMAGE_KO = { Acid = \"산성\", Bludgeoning = \"타격\", Cold = \"냉기\", Fire = \"화염\", Force = \"역장\", Lightning = \"번개\",\r\nNecrotic = \"사령\", Piercing = \"관통\", Poison = \"독성\", Psychic = \"정신\", Radiant = \"광휘\", Slashing = \"참격\", Thunder = \"천둥\" }\r\nK.DMG_KO = DAMAGE_KO\r\n\r\n\r\n\r\nlocal function spellTip(n)\r\nlocal sp = SPELLS[n]\r\nif not sp then return n end\r\nlocal head = { n, sp.level == 0 and \"소마법\" or (sp.level .. \"레벨\") }\r\nif sp.school and sp.school ~= \"\" then head[#head + 1] = sp.school end\r\nlocal lines = { table.concat(head, \" · \") }\r\nlocal meta = {}\r\nfor _, v in ipairs({ sp.time, sp.range, sp.dur }) do\r\nif v and v ~= \"\" then meta[#meta + 1] = v end\r\nend\r\nif #meta > 0 then lines[#lines + 1] = table.concat(meta, \" · \") end\r\n\r\nif sp.cost_ko then lines[#lines + 1] = \"재료: \" .. sp.cost_ko end\r\nif sp.ko then\r\nlines[#lines + 1] = sp.ko\r\n\r\nif sp.ko:find(\"높은 레벨로 시전하면\", 1, true) and (sp.level or 0) >= 1 then\r\nlines[#lines + 1] = string.format(\"높은 레벨로 시전: %d레벨 주문을 %d레벨 슬롯으로 쓰면 한 단계 높인 것입니다. 쓸 때 \\\"%d레벨 슬롯으로\\\"처럼 말하면 됩니다.\",\r\nsp.level, sp.level + 1, sp.level + 1)\r\nend\r\nelse\r\nlocal t = {}\r\nif sp.attack then t[#t + 1] = \"명중 굴림\" end\r\nif sp.save then t[#t + 1] = koName(sp.save) .. \" 내성\" .. (sp.half_on_save and \"(성공 시 절반)\" or \"\") end\r\nif sp.damage then t[#t + 1] = sp.damage .. \" \" .. (DAMAGE_KO[sp.damage_type] or sp.damage_type or \"\") .. \" 피해\" end\r\nif sp.heal then t[#t + 1] = sp.heal .. \" 회복\" end\r\nif #t > 0 then lines[#lines + 1] = table.concat(t, \" · \") end\r\nend\r\nreturn table.concat(lines, \"\\n\")\r\nend\r\n\r\n\r\nfunction K.freeTip(n)\r\nif SPELLS[n] then return spellTip(n) .. \"\\n슬롯 없이 쓰는 횟수입니다. 긴 휴식에 다시 찹니다.\" end\r\nreturn koName(n) .. \"\\n준비한 대지 주문 하나(1레벨 이상)를 긴 휴식마다 한 번 슬롯 없이 시전합니다(자연적 회복력).\"\r\nend\r\n\r\n\r\nlocal function tipSpan(word, tip)\r\nreturn '<span class=\"dnd-term\" tabindex=\"0\">' .. esc(word) .. '<span class=\"dnd-tip\">'\r\n.. (esc(tip):gsub(\"\\n\", \"<br>\")) .. '</span></span>'\r\nend\r\n\r\n\r\nfunction K.condTip(shown)\r\nlocal nm = trim(tostring(shown or \"\"))\r\nnm = trim(nm:match(\"^(.-)%s*%b()$\") or nm)\r\nnm = nm:match(\"^(.-) %d+$\") or nm\r\nif nm == \"\" then return nil end\r\nfor n, row in pairs(CONDS) do\r\nif koName(n) == nm or n == nm then\r\nlocal tip = type(row) == \"table\" and type(row.pack) == \"table\" and row.pack.tip or nil\r\nreturn tip or K.dictDesc(koName(n)) or K.dictDesc(nm)\r\nend\r\nend\r\nreturn K.dictDesc(nm)\r\nend\r\n\r\nfunction K.condTipHtml(text)\r\nlocal o = {}\r\nfor part in (tostring(text or \"\") .. \" · \"):gmatch(\"(.-) · \") do\r\nlocal tip = part ~= \"\" and K.condTip(part) or nil\r\no[#o + 1] = tip and tipSpan(part, tip) or esc(part)\r\nend\r\nreturn table.concat(o, \" · \")\r\nend\r\n\r\n\r\n\r\n\r\nfunction K.featDef(name, cls)\r\nlocal fk = (cls and FEATURE_KO[cls .. \"|\" .. name]) or FEATURE_KO[name]\r\nlocal rec = type(K.FX[name]) == \"table\" and K.FX[name] or nil\r\nlocal tip = fk and fk[2]\r\nif not tip and rec then tip = (K.LITE and rec.lite) or rec.tip end\r\nreturn { ko = NAMES_KO[name] or (fk and fk[1]) or nil, tip = tip, can = K.featCan(name), text = rec and rec.text or nil }\r\nend\r\n\r\nfunction K.fillTip(t, sh, name)\r\nif type(t) ~= \"string\" or not sh or not t:find(\"{\", 1, true) then return t end\r\nreturn Feat.fill(t, sh, \"나\", name, true)\r\nend\r\nfunction K.featTip(name, cls, sh)\r\nreturn K.fillTip(K.featDef(name, cls).tip, sh, name)\r\nend\r\n\r\nK.CANFX = setmetatable({}, { __mode = \"k\" })\r\nfunction K.featCan(name)\r\nif K.CAN[name] then return K.CAN[name] end\r\nlocal rec = K.FX[name]\r\nif type(rec) ~= \"table\" or type(rec.can) ~= \"table\" then return nil end\r\nlocal hit = K.CANFX[rec]\r\nif hit and hit.gen == K.PACK.gen then return hit.list end\r\nlocal c = {}\r\nfor _, e in ipairs(rec.can) do\r\nlocal o = {}\r\nfor k, x in pairs(e) do o[k] = x end\r\no.ko = e.ko or NAMES_KO[name] or name\r\nif e.lite ~= \"skip\" then o.lite = nil end\r\nlocal t = (K.LITE and e.lite and e.lite ~= \"skip\") and e.lite or e.tip\r\no.tip = t and function(sh) return K.fillTip(t, sh, name) end or nil\r\nc[#c + 1] = o\r\nend\r\nK.CANFX[rec] = { gen = K.PACK.gen, list = c }\r\nreturn c\r\nend\r\n\r\nfunction K.featSheet(sh, name)\r\nif type(sh) ~= \"table\" or not sh.class then return sh end\r\nfor _, x in ipairs(Feat.levelFeaturesBy(sh, true)) do\r\nif x.name == name then return K.view(sh, x.class, x.level) end\r\nend\r\nreturn sh\r\nend\r\n\r\n\r\nlocal function featureSpans(sh)\r\nlocal cl = CLASSES[sh.class]\r\nlocal feats = {}\r\nfor _, x in ipairs(Feat.levelFeatures(sh)) do\r\nlocal key = x:gsub(\" %(.-%)$\", \"\")\r\nif key:match(\" Subclass$\") then\r\nlocal cn = key:match(\"^(.-) Subclass$\")\r\nlocal sub = K.subOf(sh, CLASSES[cn] and cn or sh.class) or cn\r\nfeats[#feats + 1] = tipSpan(\"하위 클래스: \" .. koName(sub), (SUBCLASS_TIP[sub] or (K.subRec(cn, sub) or {}).tip or sub) .. K.subOnlyTip(CLASSES[cn] and cn or sh.class))\r\nelse\r\nlocal f = K.featDef(key, sh.class)\r\nfeats[#feats + 1] = f.tip and tipSpan(f.ko or key, K.fillTip(f.tip, sh, key)) or esc(koName(key))\r\nend\r\nend\r\nreturn table.concat(feats, \" · \")\r\nend\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\nK.CAN_WHEN = { act = \"행동\", bonus = \"추가 행동\", react = \"반응행동\", hit = \"공격할 때\", other = \"그 밖에\" }\r\nK.CAN_ORDER = { \"act\", \"bonus\", \"react\", \"hit\", \"other\" }\r\nfunction K.canCost(res, n, unit)\r\nif K.LITE then\r\nlocal c = K.MP.price(res, n)\r\nif c then return K.MP.name() .. \" \" .. c end\r\nend\r\nreturn koName(res) .. \" \" .. (n or 1) .. (unit or \"회\")\r\nend\r\nfunction K.canDC(ab) return 8 + PROF + (MOD[ab] or 0) end\r\nfunction K.canSpellDC(sh)\r\nlocal ab = (CLASSES[sh.class] or {}).spell_ability\r\nreturn 8 + PROF + (ab and MOD[ab] or 0)\r\nend\r\nfunction K.canSg(n) return string.format(\"%+d\", n) end\r\nK.REST_SHORT1 = \" 짧은 휴식에 1회, 긴 휴식에 전부 다시 찹니다.\"\r\nK.CAN = {\r\n\r\n[\"Second Wind\"] = { { ko = \"재기의 바람\", when = \"bonus\", res = \"Second Wind\", litetip = true, tip = function(sh)\r\nreturn string.format(\"1d10 + %d만큼 생명력을 되찾습니다.\", sh.level)\r\n.. (sh.level >= 5 and \" 그때 기회공격을 받지 않고 속도의 절반까지 움직일 수 있습니다(전술적 이동).\" or \"\") .. K.REST_SHORT1 end } },\r\n[\"Action Surge\"] = { { ko = \"행동 연쇄\", when = \"other\", res = \"Action Surge\", litetip = true, tip = function(sh)\r\nreturn \"내 턴에 행동을 한 번 더 합니다(마법 행동은 안 됩니다).\" .. (sh.level >= 17 and \" 휴식 사이 두 번까지 쓰지만 한 턴에는 한 번입니다.\" or \"\")\r\n.. \" 짧은 휴식이나 긴 휴식에 다시 찹니다.\" end } },\r\n[\"Tactical Mind\"] = { { ko = \"전술적 사고\", when = \"other\", res = \"Second Wind\",\r\ntip = \"능력 판정에 실패했을 때 재기의 바람 1회를 써서 1d10을 더합니다. 그래도 실패하면 그 1회는 쓰지 않은 것이 됩니다.\" } },\r\n[\"Indomitable\"] = { { ko = \"불요불굴\", when = \"other\", res = \"Indomitable\", tip = function(sh)\r\nreturn string.format(\"내성 굴림에 실패하면 파이터 레벨(%d)을 더해 다시 굴리고, 새 값을 씁니다. 긴 휴식마다 %d회.\", sh.level,\r\nsh.level >= 17 and 3 or sh.level >= 13 and 2 or 1) end } },\r\n[\"Tactical Master\"] = { { ko = \"전술의 달인\", when = \"hit\",\r\ntip = \"통달 속성을 쓸 수 있는 무기로 공격할 때, 이번 공격만 그 속성 대신 밀치기·약화·둔화 가운데 하나를 씁니다.\" } },\r\n\r\n[\"Sneak Attack\"] = { { ko = \"암습 공격\", when = \"hit\", tip = function(sh, row)\r\nreturn string.format(\"턴마다 한 번, 기교 무기나 원거리 무기로 맞힌 공격에 피해를 %s 더합니다. 그 공격에 이점이 있거나, 대상 5피트 안에\"\r\n.. \" 행동불능이 아닌 내 편이 있고 불리점이 없어야 합니다.\", row.sneak_attack or \"1d6\") end } },\r\n[\"Cunning Action\"] = { { ko = \"교활한 행동\", when = \"bonus\", tip = \"질주·이탈·숨기 가운데 하나를 추가 행동으로 합니다.\" } },\r\n[\"Steady Aim\"] = { { ko = \"차분한 조준\", when = \"bonus\",\r\ntip = \"이번 턴에 움직이지 않았다면, 이번 턴 다음 명중 굴림에 이점을 받습니다. 그 뒤 이번 턴 속도는 0입니다.\" } },\r\n[\"Cunning Strike\"] = {\r\n{ ko = \"교활한 일격: 중독\", when = \"hit\", cost = \"암습 1d6\", tip = function() return string.format(\"대상이 건강 내성 굴림(난이도 %d)에 실패하면 1분 동안\"\r\n.. \" 중독 상태가 되고, 자기 턴이 끝날 때마다 다시 굴려 성공하면 풀립니다. 독살자 도구를 지니고 있어야 합니다.\", K.canDC(\"Dexterity\")) end },\r\n{ ko = \"교활한 일격: 넘어뜨리기\", when = \"hit\", cost = \"암습 1d6\", tip = function() return string.format(\"대형 이하 대상이 민첩 내성 굴림(난이도 %d)에\"\r\n.. \" 실패하면 넘어진 상태가 됩니다.\", K.canDC(\"Dexterity\")) end },\r\n{ ko = \"교활한 일격: 물러나기\", when = \"hit\", cost = \"암습 1d6\", tip = \"공격 직후 기회공격을 받지 않고 속도의 절반까지 움직입니다.\" },\r\n},\r\n[\"Devious Strikes\"] = {\r\n{ ko = \"교활한 일격: 멍하게\", when = \"hit\", cost = \"암습 2d6\", tip = function() return string.format(\"대상이 건강 내성 굴림(난이도 %d)에 실패하면\"\r\n.. \" 다음 자기 턴에 이동·행동·추가 행동 가운데 하나만 합니다.\", K.canDC(\"Dexterity\")) end },\r\n{ ko = \"교활한 일격: 기절시키기\", when = \"hit\", cost = \"암습 6d6\", tip = function() return string.format(\"대상이 건강 내성 굴림(난이도 %d)에 실패하면\"\r\n.. \" 1분 동안, 또는 피해를 받을 때까지 무의식 상태가 됩니다. 자기 턴이 끝날 때마다 다시 굴려 성공하면 깹니다.\", K.canDC(\"Dexterity\")) end },\r\n{ ko = \"교활한 일격: 시야 가리기\", when = \"hit\", cost = \"암습 3d6\", tip = function() return string.format(\"대상이 민첩 내성 굴림(난이도 %d)에 실패하면\"\r\n.. \" 다음 자기 턴이 끝날 때까지 장님 상태가 됩니다.\", K.canDC(\"Dexterity\")) end },\r\n},\r\n[\"Uncanny Dodge\"] = { { ko = \"놀라운 회피\", when = \"react\", tip = \"보이는 공격자의 명중 굴림에 맞으면, 그 공격의 피해를 절반(내림)으로 줄입니다.\" } },\r\n[\"Stroke of Luck\"] = { { ko = \"행운의 한 방\", when = \"other\", res = \"Stroke of Luck\", tip = \"d20 판정에 실패하면 그 굴림을 20으로 바꿉니다. 짧은 휴식이나 긴 휴식마다 1회.\" } },\r\n[\"Supreme Sneak\"] = { { ko = \"교활한 일격: 은신 공격\", when = \"hit\", cost = \"암습 1d6\",\r\ntip = \"숨기로 얻은 투명 상태에서 공격해도, 3/4 엄폐나 완전 엄폐 뒤에서 턴을 끝내면 투명이 풀리지 않습니다.\" } },\r\n\r\n[\"Divine Intervention\"] = { { ko = \"신의 간섭\", when = \"act\", res = \"Divine Intervention\", tip = function(sh)\r\nreturn \"마법 행동으로, 반응행동이 필요 없는 5레벨 이하 클레릭 주문 하나를 슬롯과 재료 없이 시전합니다(준비하지 않은 것도 됩니다). 긴 휴식마다 1회.\"\r\n.. (sh.level >= 20 and \" 상위 신의 간섭: 소원도 고를 수 있지만, 그러면 긴 휴식을 2d4번 마칠 때까지 다시 쓰지 못합니다.\" or \"\") end } },\r\n[\"Blessed Strikes\"] = {\r\n{ ko = \"신성한 일격\", when = \"hit\", pick = { \"blessed\", \"Divine Strike\" }, tip = function(sh)\r\nreturn string.format(\"턴마다 한 번, 무기로 명중 굴림을 맞히면 사령이나 광휘 피해를 %s 더합니다(Lua가 공식에 넣습니다).\", sh.level >= 14 and \"2d8\" or \"1d8\") end },\r\n},\r\n[\"Improved Blessed Strikes\"] = {\r\n{ ko = \"강화된 주문시전: 활력\", when = \"other\", pick = { \"blessed\", \"Potent Spellcasting\" }, tip = function()\r\nreturn string.format(\"클레릭 소마법으로 피해를 준 뒤, 60피트 안의 한 명(나 포함)에게 지혜 수정치의 두 배(%d)만큼 임시 생명력을 줍니다. 시전마다 한 번(Lua가 더합니다).\",\r\n2 * math.max(0, MOD.Wisdom)) end },\r\n},\r\n\r\n[\"Arcane Recovery\"] = { { ko = \"비전 회복\", when = \"other\", lite = \"skip\" } },\r\n[\"Memorize Spell\"] = { { ko = \"주문 암기\", when = \"other\", lite = \"skip\" } },\r\n[\"Overchannel\"] = { { ko = \"과전환\", when = \"other\" } },\r\n\r\n[\"Rage\"] = { { ko = \"격노\", when = \"bonus\", res = \"Rage\", litetip = true, tip = function(sh, row)\r\nreturn string.format(\"중갑을 입지 않았을 때 들어갑니다. 그동안 타격·관통·참격 피해에 저항하고, 근력으로 하는 공격의 피해에 %s, 근력 판정과 근력 내성 굴림에\"\r\n.. \" 이점을 받습니다. 주문을 쓰거나 집중할 수 없습니다. 여기서는 전투가 끝나면 Lua가 끕니다.\", K.canSg(row.rage or 2))\r\n.. (sh.level >= 7 and \" 들어가면서 속도의 절반까지 움직일 수 있습니다(본능적 도약).\" or \"\") .. K.REST_SHORT1 end } },\r\n[\"Reckless Attack\"] = { { ko = \"무모한 공격\", when = \"hit\",\r\ntip = \"내 턴 첫 명중 굴림 때 고르면, 다음 내 턴이 시작될 때까지 근력으로 하는 명중 굴림에 이점을 받고, 나를 노리는 명중 굴림도 이점을 받습니다.\" } },\r\n[\"Brutal Strike\"] = {\r\n{ ko = \"잔혹한 일격: 강력한 일격\", when = \"hit\", tip = function(sh) return K.brutalHead(sh) .. \" 대상을 나에게서 똑바로 15피트 밀어내고, 나는 기회공격을 받지 않고\"\r\n.. \" 대상 쪽으로 속도의 절반까지 곧장 움직일 수 있습니다.\" end },\r\n{ ko = \"잔혹한 일격: 오금 베기\", when = \"hit\", tip = function(sh) return K.brutalHead(sh) .. \" 다음 내 턴이 시작될 때까지 대상의 속도가 15피트 줄어듭니다\"\r\n.. \"(가장 최근 하나만).\" end },\r\n{ ko = \"잔혹한 일격: 비틀거리는 일격\", when = \"hit\", from = 13, tip = function(sh) return K.brutalHead(sh) .. \" 대상은 다음 내성 굴림에 불리점을 받고,\"\r\n.. \" 다음 내 턴이 시작될 때까지 기회공격을 못 합니다.\" end },\r\n{ ko = \"잔혹한 일격: 가르는 일격\", when = \"hit\", from = 13, tip = function(sh) return K.brutalHead(sh) .. \" 다음 내 턴이 시작되기 전, 다른 생물이 대상에게\"\r\n.. \" 하는 다음 명중 굴림에 +5가 붙습니다.\" end },\r\n},\r\n[\"Relentless Rage\"] = { { ko = \"끈질긴 격노\", when = \"other\" } },\r\n[\"Retaliation\"] = { { ko = \"앙갚음\", when = \"react\" } },\r\n[\"Intimidating Presence\"] = { { ko = \"위협적 존재감\", when = \"bonus\", res = \"Intimidating Presence\", tip = function()\r\nreturn string.format(\"30피트 안에서 고른 생물이 지혜 내성 굴림(난이도 %d)을 하고, 실패하면 1분 동안 공포 상태가 됩니다(자기 턴이 끝날 때마다 다시 굴려\"\r\n.. \" 성공하면 풀림). 긴 휴식마다 1회, 격노 1회를 써서 다시 쓸 수 있습니다.\", K.canDC(\"Strength\")) end } },\r\n\r\n[\"Bardic Inspiration\"] = { { ko = \"바드의 고양감\", when = \"bonus\", res = \"Bardic Inspiration\", litetip = true, tip = function(sh, row)\r\nreturn string.format(\"60피트 안에서 나를 보거나 듣는 다른 생물 하나에게 고양감 주사위(%s)를 줍니다. 그 생물은 1시간 안에 d20 판정에 실패하면 주사위를\"\r\n.. \" 굴려 더해 성공으로 바꿀 수 있습니다(한 번에 하나만 지님). 매력 수정치만큼, 긴 휴식에 다시 찹니다.\", row.bi or \"1d6\")\r\n.. (sh.level >= 5 and \" 짧은 휴식에도 모두 다시 찹니다.\" or \"\") end } },\r\n[\"Font of Inspiration\"] = { { ko = \"고양감의 샘\", when = \"other\", lite = \"skip\",\r\ntip = \"주문 슬롯 하나를 써서(행동 없이) 바드의 고양감 1회를 되찾습니다. 고양감은 짧은 휴식에도 모두 다시 찹니다.\" } },\r\n[\"Countercharm\"] = { { ko = \"매혹반사\", when = \"react\",\r\ntip = \"나나 30피트 안의 생물이 매혹이나 공포를 거는 효과의 내성 굴림에 실패하면, 이점을 받고 다시 굴리게 합니다.\" } },\r\n[\"Peerless Skill\"] = { { ko = \"독보적인 기술\", when = \"other\", res = \"Bardic Inspiration\",\r\ntip = \"능력 판정이나 명중 굴림에 실패하면 고양감 주사위를 굴려 d20에 더합니다. 그래도 실패하면 그 1회는 쓰지 않은 것이 됩니다.\" } },\r\n\r\n[\"Wild Shape\"] = { { ko = \"야생 변신\", when = \"bonus\", res = \"Wild Shape\", litetip = true, tip = function(sh, row)\r\nreturn string.format(\"아는 야수 형태(도전 지수 %s 이하%s)로 변해 %d시간 동안 지냅니다. 야수의 능력치를 쓰되 생명력·지능·지혜·매력·클래스 기능은 그대로이고,\"\r\n.. \" 드루이드 레벨만큼(%d) 임시 생명력을 얻습니다. %s 추가 행동으로 돌아옵니다.\", row.forms or \"1/4\", sh.level >= 8 and \"\" or \", 비행 속도 없는 것\",\r\nmath.max(1, math.floor(sh.level / 2)), sh.level, sh.level >= 18 and \"변한 동안에도 주문을 씁니다(값이 정해진 재료를 쓰는 주문은 빼고).\"\r\nor \"변한 동안 주문은 못 쓰지만, 이미 하던 집중은 이어집니다.\") .. K.REST_SHORT1 end } },\r\n[\"Wild Companion\"] = { { ko = \"야생의 동료\", when = \"act\", litetip = true,\r\ntip = \"마법 행동으로 야생 변신 1회나 주문 슬롯 하나를 써서 재료 없이 패밀리어 찾기를 시전합니다. 그 패밀리어는 요정이고 긴 휴식을 마치면 사라집니다.\" } },\r\n[\"Wild Resurgence\"] = { { ko = \"야생의 재기\", when = \"other\", lite = \"skip\",\r\ntip = \"내 턴마다 한 번, 야생 변신이 남지 않았으면 주문 슬롯 하나를 써서(행동 없이) 1회를 되찾습니다. 또 긴 휴식마다 한 번, 야생 변신 1회를 써서 1레벨 슬롯 하나를 얻습니다.\" } },\r\n[\"Natural Recovery\"] = { { ko = \"자연적 회복력\", when = \"other\" } },\r\n[\"Nature's Sanctuary\"] = { { ko = \"자연의 성역\", when = \"act\", res = \"Wild Shape\" } },\r\n\r\n[\"Martial Arts\"] = { { ko = \"무술: 맨손 공격\", when = \"bonus\", tip = function(sh, row)\r\nreturn string.format(\"추가 행동으로 맨손 공격을 한 번 합니다. 갑옷과 방패 없이 맨손이나 몽크 무기로 칠 때 민첩을 쓸 수 있고, 피해는 무술 주사위 %s입니다.\",\r\nrow.martial_arts or \"1d6\") end } },\r\n[\"Monk's Focus\"] = {\r\n{ ko = \"연타\", when = \"bonus\", res = \"Focus Points\", unit = \"점\", tip = function(sh)\r\nreturn string.format(\"추가 행동으로 맨손 공격을 %s 합니다.\", sh.level >= 10 and \"세 번\" or \"두 번\") end },\r\n{ ko = \"인내의 방어\", when = \"bonus\", tip = function(sh)\r\nreturn \"추가 행동으로 이탈합니다. 기 1점을 쓰면 이탈과 회피를 함께 합니다\" .. (sh.level >= 10 and \". 그때 무술 주사위 두 개를 굴린 만큼 임시 생명력도 얻습니다.\" or \".\") end },\r\n{ ko = \"바람 걸음\", when = \"bonus\", tip = function(sh)\r\nreturn \"추가 행동으로 질주합니다. 기 1점을 쓰면 이탈과 질주를 함께 하고 이번 턴 도약 거리가 두 배가 됩니다\"\r\n.. (sh.level >= 10 and \". 그때 5피트 안의 대형 이하 아군 하나를 턴이 끝날 때까지 함께 데려갑니다(그 아군은 기회공격을 받지 않음).\" or \".\") end },\r\n},\r\n[\"Uncanny Metabolism\"] = { { ko = \"놀라운 신진대사\", when = \"other\", res = \"Uncanny Metabolism\", lite = \"skip\", tip = function(sh, row)\r\nreturn string.format(\"우선권을 굴릴 때 기 점수를 모두 되찾고, 무술 주사위(%s) + %d만큼 생명력을 되찾습니다. 긴 휴식마다 1회.\", row.martial_arts or \"1d6\", sh.level) end } },\r\n[\"Deflect Attacks\"] = { { ko = \"공격 쳐내기\", when = \"react\", tip = function(sh, row)\r\nreturn string.format(\"%s 피해가 든 명중 굴림에 맞으면, 그 공격의 피해를 1d10 + %d만큼 줄입니다. 0으로 줄였다면 기 1점으로 되돌려, 5피트 안(원거리 공격이면\"\r\n.. \" 60피트 안)의 생물이 민첩 내성 굴림(난이도 %d)에 실패하면 무술 주사위(%s)를 두 번 굴린 값 %s만큼 피해를 줍니다.\",\r\nsh.level >= 13 and \"어떤 종류든\" or \"타격·관통·참격\", MOD.Dexterity + sh.level, K.canDC(\"Wisdom\"), row.martial_arts or \"1d6\", K.canSg(MOD.Dexterity)) end } },\r\n[\"Slow Fall\"] = { { ko = \"저속 낙하\", when = \"react\", tip = function(sh) return string.format(\"떨어질 때 낙하 피해를 %d만큼 줄입니다.\", 5 * sh.level) end } },\r\n[\"Stunning Strike\"] = { { ko = \"충격의 일격\", when = \"hit\", res = \"Focus Points\", unit = \"점\", tip = function()\r\nreturn string.format(\"턴마다 한 번, 몽크 무기나 맨손 공격으로 맞히면 대상이 건강 내성 굴림(난이도 %d)을 합니다. 실패하면 다음 내 턴이 시작될 때까지 충격 상태가\"\r\n.. \" 되고, 성공해도 그때까지 속도가 절반이 되며 다음에 받는 명중 굴림에 이점이 붙습니다.\", K.canDC(\"Wisdom\")) end } },\r\n[\"Disciplined Survivor\"] = { { ko = \"단련된 생존자\", when = \"other\", res = \"Focus Points\", unit = \"점\",\r\ntip = \"모든 내성 굴림에 숙련입니다. 내성 굴림에 실패하면 기 1점을 써서 다시 굴리고 새 값을 씁니다.\" } },\r\n[\"Superior Defense\"] = { { ko = \"우월한 방어\", when = \"other\", res = \"Focus Points\", n = 3, unit = \"점\",\r\ntip = \"내 턴이 시작될 때 쓰면, 1분 동안(행동불능이 되면 끝) 역장을 뺀 모든 피해에 저항합니다.\" } },\r\n[\"Wholeness of Body\"] = { { ko = \"신체의 완전화\", when = \"bonus\", res = \"Wholeness of Body\", tip = function(sh, row)\r\nreturn string.format(\"무술 주사위(%s) %s만큼(최소 1) 생명력을 되찾습니다. 지혜 수정치만큼, 긴 휴식에 다시 찹니다.\", row.martial_arts or \"1d6\", K.canSg(MOD.Wisdom)) end } },\r\n[\"Quivering Palm\"] = { { ko = \"진동장\", when = \"hit\", res = \"Focus Points\", n = 4, unit = \"점\", tip = function(sh)\r\nreturn string.format(\"맨손 공격으로 맞히면 몸속에 진동을 심습니다(%d일 동안, 한 번에 한 생물). 행동으로, 또는 공격 행동의 공격 하나를 포기해 터뜨리면 대상이\"\r\n.. \" 건강 내성 굴림(난이도 %d)을 해서 실패하면 역장 피해 10d12, 성공하면 그 절반을 받습니다.\", sh.level, K.canDC(\"Wisdom\")) end } },\r\n\r\n[\"Lay On Hands\"] = { { ko = \"치유의 손길\", when = \"bonus\", litetip = true, tip = function(sh)\r\nreturn string.format(\"닿은 생물(나 포함)에게 치유의 손길 점수에서 원하는 만큼 생명력을 줍니다(점수 %d, 긴 휴식에 다 참). 5점으로 중독 상태를 풉니다.\", 5 * sh.level)\r\n.. (sh.level >= 14 and \" 5점마다 장님·매혹·귀머거리·공포·마비·충격 가운데 하나도 풉니다(회복의 손길).\" or \"\") end } },\r\n[\"Paladin's Smite\"] = { { ko = \"신성한 강타\", when = \"hit\", litetip = true, tip = function(sh)\r\nreturn \"근접 무기나 맨손 공격으로 맞힌 직후 추가 행동으로 씁니다. 그 공격에 광휘 피해 2d8을 더하고, 높은 레벨로 쓰면 한 단계마다 1d8, 대상이 악마나 언데드면\"\r\n.. \" 1d8이 더 붙습니다. 긴 휴식마다 한 번은 슬롯 없이 씁니다.\"\r\n.. ((sh.level >= 15 and sh.class == \"Paladin\") and \" 쓸 때 나와 보호의 오오라 안의 동료가 다음 내 턴이 시작될 때까지 절반 엄폐를 받습니다(보호의 강타).\" or \"\") end } },\r\n[\"Abjure Foes\"] = { { ko = \"적 물리치기\", when = \"act\", res = \"Channel Divinity\", tip = function(sh)\r\nlocal n = math.max(1, MOD.Charisma)\r\nreturn string.format(\"마법 행동으로, 60피트 안에 보이는 생물을 %s 골라 지혜 내성 굴림(난이도 %d)을 시킵니다. 실패하면 1분 동안, 또는 피해를 받을 때까지\"\r\n.. \" 공포 상태가 되고, 그동안 자기 턴에 이동·행동·추가 행동 가운데 하나만 합니다.\", n == 1 and \"하나\" or (n .. \"까지\"), K.canSpellDC(sh)) end } },\r\n[\"Holy Nimbus\"] = { { ko = \"신성한 후광\", when = \"bonus\", res = \"Holy Nimbus\" } },\r\n\r\n[\"Tireless\"] = { { ko = \"지치지 않음\", when = \"act\", res = \"Tireless\", litetip = true, tip = function()\r\nreturn string.format(\"마법 행동으로 1d8 %s(최소 1)만큼 임시 생명력을 얻습니다. 지혜 수정치만큼, 긴 휴식에 다시 찹니다. 짧은 휴식을 마칠 때마다 탈진도\"\r\n.. \" 1단계 줄어듭니다.\", K.canSg(MOD.Wisdom)) end } },\r\n[\"Nature's Veil\"] = { { ko = \"자연의 장막\", when = \"bonus\", res = \"Nature's Veil\", litetip = true,\r\ntip = \"다음 내 턴이 끝날 때까지 투명 상태가 됩니다. 지혜 수정치만큼, 긴 휴식에 다시 찹니다.\" } },\r\n[\"Superior Hunter's Prey\"] = { { ko = \"우월한 사냥꾼의 사냥감\", when = \"hit\", tip = function(sh)\r\nreturn string.format(\"턴마다 한 번, 사냥꾼의 표식을 건 생물에게 피해를 줄 때 그 추가 피해(%s 역장)를 30피트 안에 보이는 다른 생물에게도 줍니다.\",\r\nsh.level >= 20 and \"1d10\" or \"1d6\") end } },\r\n[\"Superior Hunter's Defense\"] = { { ko = \"우월한 사냥꾼의 방어\", when = \"react\" } },\r\n\r\n[\"Innate Sorcery\"] = { { ko = \"타고난 술법\", when = \"bonus\", res = \"Innate Sorcery\", litetip = true, tip = function(sh)\r\nreturn \"1분 동안 소서러 주문의 내성 난이도가 1 오르고, 소서러 주문 명중 굴림에 이점을 받습니다(여기서는 전투가 끝나면 Lua가 끕니다). 긴 휴식마다 2회.\"\r\n.. (sh.level >= 7 and \" 남은 횟수가 없으면 술법 점수 2점으로 켤 수 있고, 켜진 동안 주문 하나에 마법변형을 둘까지 씁니다.\" or \"\")\r\n.. (sh.level >= 20 and \" 켜진 동안 내 턴마다 마법변형 하나를 술법 점수 없이 씁니다.\" or \"\") end } },\r\n[\"Font of Magic\"] = {\r\n{ ko = \"슬롯을 술법 점수로\", when = \"other\", lite = \"skip\", tip = \"행동 없이 주문 슬롯 하나를 써서, 그 레벨만큼 술법 점수를 얻습니다.\" },\r\n{ ko = \"술법 점수로 슬롯 만들기\", when = \"bonus\", lite = \"skip\", tip = \"술법 점수로 5레벨 이하 주문 슬롯 하나를 만듭니다. 1레벨 2점, 2레벨 3점(소서러 3레벨부터),\"\r\n.. \" 3레벨 5점(5레벨부터), 4레벨 6점(7레벨부터), 5레벨 7점(9레벨부터). 만든 슬롯은 긴 휴식을 마치면 사라집니다.\" },\r\n},\r\n[\"Sorcerous Restoration\"] = { { ko = \"술법 회복\", when = \"other\", lite = \"skip\" } },\r\n[\"Dragon Wings\"] = { { ko = \"용의 날개\", when = \"bonus\" } },\r\n\r\n[\"Magical Cunning\"] = { { ko = \"마법적 교활함\", when = \"other\", lite = \"skip\" } },\r\n[\"Contact Patron\"] = { { ko = \"후원자 접촉\", when = \"act\", res = \"Contact Patron\" } },\r\n[\"Dark One's Own Luck\"] = { { ko = \"어두운 이의 명운\", when = \"other\", res = \"Dark One's Own Luck\" } },\r\n[\"Hurl Through Hell\"] = { { ko = \"지옥너머로 던지기\", when = \"hit\", res = \"Hurl Through Hell\", litetip = true, tip = function(sh)\r\nreturn string.format(\"턴마다 한 번 명중 굴림으로 맞히면, 대상이 매력 내성 굴림(난이도 %d)에 실패할 때 하계로 내던집니다. 악마가 아니면 정신 피해 8d10을 받고,\"\r\n.. \" 다음 내 턴이 끝날 때까지 행동불능 상태였다가 돌아옵니다. 긴 휴식마다 1회(계약 마법 슬롯 하나로 다시).\", K.canSpellDC(sh)) end } },\r\n}\r\n\r\nfunction K.brutalHead(sh)\r\nreturn string.format(\"무모한 공격을 한 턴에 근력 공격 하나의 이점을 포기하면(불리점은 없어야 함), 맞혔을 때 피해를 %s 더하고 효과를 %s 고릅니다.\",\r\nsh.level >= 17 and \"2d10\" or \"1d10\", sh.level >= 17 and \"서로 다른 둘까지\" or \"하나\")\r\nend\r\n\r\nK.CAN_SUB3 = {\r\nChampion = {\r\n{ ko = \"향상된 치명타\", tip = \"무기와 맨손 공격이 d20 19~20에서도 치명타가 됩니다.\" },\r\n{ ko = \"뛰어난 운동능력\", tip = \"우선권과 근력(운동) 판정에 이점. 치명타를 내면 기회공격을 받지 않고 속도의 절반까지 움직일 수 있습니다.\" },\r\n},\r\nThief = {\r\n{ ko = \"빠른 손놀림\", when = \"bonus\", tip = \"추가 행동으로 다음 가운데 하나를 합니다. 손재주 판정(도둑 도구로 자물쇠 따기·함정 해제, 소매치기), 사용 행동,\"\r\n.. \" 또는 마법 행동이 필요한 마법 물건 쓰기.\" },\r\n{ ko = \"오르내리기\", tip = \"오르기 속도가 속도와 같고, 도약 거리를 근력 대신 민첩으로 정합니다.\" },\r\n},\r\n[\"Life Domain\"] = {\r\n{ ko = \"생명 보존\", when = \"act\", res = \"Channel Divinity\", tip = function(sh)\r\nreturn string.format(\"마법 행동으로, 30피트 안에서 생명력이 절반 이하인 생물들(나 포함)에게 모두 합쳐 %d까지 생명력을 나눠 줍니다. 한 생물은 최대 생명력의 절반까지만\"\r\n.. \" 채울 수 있습니다.\", 5 * sh.level) end },\r\n{ ko = \"생명의 사도\", tip = \"슬롯을 쓴 주문으로 생명력을 되찾게 하면, 그 턴에 2 + 슬롯 레벨만큼 더 되찾습니다(Lua가 공식에 넣습니다).\" },\r\n},\r\nEvoker = {\r\n{ ko = \"방출계 전공\", tip = \"방출계 주문을 주문책에 옮겨 적는 시간과 비용이 절반이고, 레벨이 오를 때마다 방출계 주문 하나를 공짜로 더 적습니다.\" },\r\n{ ko = \"강력한 소마법\", tip = \"피해를 주는 소마법이 빗나가거나 대상이 내성에 성공해도 피해의 절반을 줍니다(다른 효과는 없음).\" },\r\n},\r\n[\"Path of the Berserker\"] = {\r\n{ ko = \"광분\", when = \"hit\", tip = function(sh, row)\r\nreturn string.format(\"격노 중에 무모한 공격을 한 턴, 근력 공격으로 처음 맞힌 대상에게 피해를 %dd6 더합니다(Lua가 공식에 넣습니다).\", row.rage or 2) end },\r\n},\r\n[\"College of Lore\"] = {\r\n{ ko = \"날카로운 말\", when = \"react\", res = \"Bardic Inspiration\", tip = function(sh, row)\r\nreturn string.format(\"60피트 안에 보이는 생물이 피해를 굴리거나 능력 판정·명중 굴림에 성공하면, 고양감 주사위(%s)를 굴려 그 값을 빼서 피해를 줄이거나\"\r\n.. \" 실패로 돌립니다.\", row.bi or \"1d6\") end },\r\n{ ko = \"추가 숙련\", tip = \"아무 기술 셋에 숙련을 얻습니다.\" },\r\n},\r\n[\"Circle of the Land\"] = {\r\n{ ko = \"대지의 도움\", when = \"act\", res = \"Wild Shape\", tip = function(sh)\r\nlocal n = 2 + (sh.level >= 10 and 1 or 0) + (sh.level >= 14 and 1 or 0)\r\nreturn string.format(\"마법 행동으로 60피트 안 한 지점 둘레 반경 10피트 구체에 꽃과 가시를 피웁니다. 그 안에서 고른 생물은 건강 내성 굴림(난이도 %d)을 해서\"\r\n.. \" 실패하면 사령 피해 %dd6, 성공하면 그 절반을 받고, 그 안의 한 명은 생명력 %dd6을 되찾습니다(10레벨 3d6, 14레벨 4d6).\", K.canSpellDC(sh), n, n) end },\r\n{ ko = \"대지의 주문\", tip = \"고른 땅의 주문이 늘 준비되어 있습니다(캐릭터 탭의 대지 선택).\" },\r\n},\r\n[\"Warrior of the Open Hand\"] = {\r\n{ ko = \"열린 손의 기법\", when = \"hit\", tip = function()\r\nreturn string.format(\"연타로 맞힐 때마다 하나를 고릅니다. 어지럽히기: 다음 자기 턴이 시작될 때까지 기회공격을 못 함. 밀어내기: 근력 내성 굴림(난이도 %d)에\"\r\n.. \" 실패하면 15피트 밀려남. 넘어뜨리기: 민첩 내성 굴림(난이도 %d)에 실패하면 넘어진 상태.\", K.canDC(\"Wisdom\"), K.canDC(\"Wisdom\")) end },\r\n},\r\n[\"Oath of Devotion\"] = {\r\n{ ko = \"무기 축성\", when = \"hit\", res = \"Channel Divinity\", tip = function()\r\nreturn string.format(\"공격 행동을 할 때 든 근접 무기 하나에 힘을 깃들입니다. 10분 동안 그 무기의 명중 굴림에 %s(Lua가 더합니다), 맞힐 때 원래 피해 종류나\"\r\n.. \" 광휘 피해를 고르고, 반경 20피트를 밝게 비춥니다.\", K.canSg(math.max(1, MOD.Charisma))) end },\r\n{ ko = \"헌신의 맹세 주문\", tip = \"악과 선으로부터의 보호·신앙의 방패(5레벨부터 원호·진실의 공간, 9레벨부터 희망의 봉화·마법 무효화, 13레벨부터\"\r\n.. \" 이동의 자유·신앙의 수호자, 17레벨부터 교감·화염 강타)가 늘 준비되어 있습니다.\" },\r\n},\r\nHunter = {\r\n{ ko = \"거체 학살자\", when = \"hit\", pick = { \"prey\", \"Colossus Slayer\" },\r\ntip = \"턴마다 한 번, 무기로 맞힌 대상의 생명력이 깎여 있으면 피해 1d8을 더합니다(Lua가 공식에 넣습니다). 휴식을 마치면 무리 파쇄자로 바꿀 수 있습니다.\" },\r\n{ ko = \"무리 파쇄자\", when = \"hit\", pick = { \"prey\", \"Horde Breaker\" },\r\ntip = \"턴마다 한 번, 무기로 공격할 때 처음 대상 5피트 안에 있고 이번 턴에 공격하지 않은 다른 생물에게 같은 무기로 한 번 더 공격합니다. 휴식을 마치면 거체\"\r\n.. \" 학살자로 바꿀 수 있습니다.\" },\r\n{ ko = \"사냥꾼의 지식\", tip = \"사냥꾼의 표식을 건 생물에게 어떤 면역·저항·취약이 있는지 압니다.\" },\r\n},\r\n[\"Draconic Sorcery\"] = {\r\n{ ko = \"용의 회복력\", tip = \"최대 생명력이 소서러 레벨마다 1 더 오르고, 갑옷을 입지 않으면 방어도 = 10 + 민첩 + 매력입니다.\" },\r\n{ ko = \"용 주문\", tip = \"자기 변형·오색의 보주·명령·용의 숨결(5레벨부터 공포·비행, 7레벨부터 비전의 눈·괴물 매혹, 9레벨부터 전설 지식·용 소환)이 늘 준비되어 있습니다.\" },\r\n},\r\n[\"Fiend Patron\"] = {\r\n{ ko = \"어두운 이의 축복\", tip = \"적을 생명력 0으로 만들면(10피트 안에서 누가 그렇게 해도) 매력 수정치 + 워락 레벨(최소 1)만큼 임시 생명력을 얻습니다(Lua가 줍니다).\" },\r\n},\r\n}\r\n\r\nK.CAN_CD = {\r\nCleric = {\r\n{ ko = \"신성한 불꽃\", when = \"act\", res = \"Channel Divinity\", tip = function(sh)\r\nlocal d = string.format(\"%dd8%s\", K.sparkDice(sh.level), K.canSg(MOD.Wisdom))\r\nreturn string.format(\"마법 행동으로, 30피트 안에 보이는 다른 생물 하나(나는 안 됨)에게 신의 힘을 모읍니다. 생명력을 %s만큼 되찾게 하거나, 건강 내성 굴림\"\r\n.. \"(난이도 %d)을 시켜 실패하면 광휘나 사령 피해 %s, 성공하면 그 절반을 줍니다. 7·13·18레벨에 주사위가 하나씩 늘어납니다.\", d, K.canSpellDC(sh), d) end },\r\n{ ko = \"언데드 퇴치\", name = \"Turn Undead\", when = \"act\", res = \"Channel Divinity\", tip = function(sh)\r\nreturn string.format(\"마법 행동으로, 30피트 안에서 고른 언데드가 모두 지혜 내성 굴림(난이도 %d)을 합니다. 실패하면 1분 동안 공포·행동불능 상태가 되어 턴마다\"\r\n.. \" 나에게서 최대한 멀어지려 하고, 피해를 받거나 내가 행동불능이 되거나 죽으면 풀립니다.\", K.canSpellDC(sh))\r\n.. (sh.level >= 5 and string.format(\" 언데드 태우기: 실패한 언데드마다 광휘 피해 %dd8(한 번 굴려 모두 같은 값)을 주고, 이 피해로는 퇴치가 풀리지 않습니다.\",\r\nmath.max(1, MOD.Wisdom)) or \"\") end },\r\n},\r\nPaladin = {\r\n{ ko = \"신성 감지\", when = \"bonus\", res = \"Channel Divinity\",\r\ntip = \"10분 동안(행동불능이 되면 끝) 60피트 안의 천상체·악마·언데드가 어디 있는지 알고, 축성되거나 더럽혀진 곳이나 물건도 알아챕니다.\" },\r\n},\r\n}\r\n\r\nK.CAN_INV = { [\"Pact of the Blade\"] = \"bonus\", [\"Gaze of Two Minds\"] = \"bonus\", [\"One with Shadows\"] = \"act\", [\"Eldritch Smite\"] = \"hit\",\r\n[\"Repelling Blast\"] = \"hit\", [\"Lifedrinker\"] = \"hit\" }\r\nK.CAN_BOON = { [\"Boon of Combat Prowess\"] = \"hit\", [\"Boon of Dimensional Travel\"] = \"other\", [\"Boon of Fate\"] = \"other\",\r\n[\"Boon of Spell Recall\"] = \"other\", [\"Boon of the Night Spirit\"] = \"bonus\" }\r\n\r\nK.CAN_SPECIES = {\r\nDragonborn = {\r\n{ k = \"Breath Weapon\", ko = \"브레스 무기\", when = \"hit\", res = \"Breath Weapon\", tip = function(sh)\r\nlocal p = type(sh.picks) == \"table\" and sh.picks or {}\r\nreturn string.format(\"공격 행동의 공격 하나 대신 15피트 원뿔이나 30피트(폭 5피트) 선으로 숨을 내뿜습니다. 그 안의 생물이 민첩 내성 굴림(난이도 %d)에\"\r\n.. \" 실패하면 %s 피해 %dd10, 성공하면 그 절반을 받습니다. 숙련 보너스만큼, 긴 휴식에 다시 찹니다.\", K.canDC(\"Constitution\"),\r\nK.DMG_KO[p.dragon or \"\"] or \"혈통의\", K.cantripTier(K.charLevel(sh))) end },\r\n{ ko = \"용의 비행\", when = \"bonus\", from = 5, tip = \"10분 동안(행동불능이 되면 끝) 속도만큼의 비행 속도를 얻습니다. 긴 휴식마다 1회.\" },\r\n},\r\nDwarf = {\r\n{ ko = \"돌의 꾀\", when = \"bonus\", tip = \"돌 위에 있거나 돌에 닿아 있을 때, 10분 동안 진동 감지 60피트를 얻습니다. 숙련 보너스만큼, 긴 휴식에 다시 찹니다.\" },\r\n},\r\nGoliath = {\r\n{ ko = \"구름의 도약\", when = \"bonus\", res = \"Giant Ancestry\", pick = { \"giant\", \"Cloud\" }, tip = \"보이는 빈 곳으로 30피트까지 순간이동합니다. 숙련 보너스만큼, 긴 휴식에 다시 찹니다.\" },\r\n{ ko = \"화염의 불길\", when = \"hit\", res = \"Giant Ancestry\", pick = { \"giant\", \"Fire\" }, tip = \"명중 굴림으로 맞혀 피해를 주면 화염 피해 1d10을 더합니다(Lua가 공식에 넣습니다). 숙련 보너스만큼, 긴 휴식에 다시 찹니다.\" },\r\n{ ko = \"서리의 냉기\", when = \"hit\", res = \"Giant Ancestry\", pick = { \"giant\", \"Frost\" }, tip = \"명중 굴림으로 맞혀 피해를 주면 냉기 피해 1d6을 더하고, 다음 내 턴이 시작될 때까지 대상 속도가 10피트 줄어듭니다. 숙련 보너스만큼, 긴 휴식에 다시 찹니다.\" },\r\n{ ko = \"언덕의 넘어뜨리기\", when = \"hit\", res = \"Giant Ancestry\", pick = { \"giant\", \"Hill\" }, tip = \"명중 굴림으로 대형 이하 생물을 맞혀 피해를 주면 넘어진 상태로 만듭니다. 숙련 보너스만큼, 긴 휴식에 다시 찹니다.\" },\r\n{ ko = \"바위의 인내\", when = \"react\", res = \"Giant Ancestry\", pick = { \"giant\", \"Stone\" }, tip = function()\r\nreturn string.format(\"피해를 받으면 1d12 %s만큼 줄입니다. 숙련 보너스만큼, 긴 휴식에 다시 찹니다.\", K.canSg(MOD.Constitution)) end },\r\n{ ko = \"폭풍의 천둥\", when = \"react\", res = \"Giant Ancestry\", pick = { \"giant\", \"Storm\" }, tip = \"60피트 안의 생물에게 피해를 받으면 그 생물에게 천둥 피해 1d8을 줍니다. 숙련 보너스만큼, 긴 휴식에 다시 찹니다.\" },\r\n{ ko = \"대형 형태\", when = \"bonus\", from = 5, tip = \"자리가 넉넉하면 10분 동안 대형이 되어, 근력 판정에 이점을 받고 속도가 10피트 늘어납니다. 긴 휴식마다 1회.\" },\r\n},\r\nOrc = {\r\n{ ko = \"아드레날린 쇄도\", when = \"bonus\", res = \"Adrenaline Rush\", tip = function()\r\nreturn string.format(\"추가 행동으로 질주하고, 숙련 보너스(%d)만큼 임시 생명력을 얻습니다. 숙련 보너스만큼, 짧은 휴식이나 긴 휴식에 다시 찹니다.\", PROF) end },\r\n{ ko = \"불굴의 인내력\", when = \"other\", res = \"Relentless Endurance\", tip = \"생명력이 0이 되었지만 즉사하지 않으면 대신 1이 됩니다. 긴 휴식마다 1회.\" },\r\n},\r\n}\r\n\r\n\r\n\r\nK.CAN_BASIC = {\r\n{ row = \"기본 행동\", head = \"행동\", terms = { \"공격\", \"맨손 공격\", \"질주\", \"이탈\", \"회피\", \"돕기\", \"숨기\", \"마법\", \"대기\", \"물건 사용\", \"교섭\", \"수색\", \"탐구\" } },\r\n{ row = \"기본 반응\", head = \"반응행동\", terms = { \"기회공격\" } },\r\n\r\n{ row = \"이동\", head = \"행동과 따로, 내 턴마다 속도만큼\", terms = { \"이동\" } },\r\n{ row = \"행동 없이\", head = \"행동 없이\", terms = { \"물건 하나\", \"짧은 말\", \"엎드리기\" } },\r\n}\r\nK.CAN_BASIC_HEAD = { [\"맨손 공격\"] = \"공격 행동의 공격 하나로\" }\r\nfunction K.dictDesc(term)\r\nfor _, g in ipairs(type(K.DICT) == \"table\" and K.DICT.groups or {}) do\r\nfor _, e in ipairs(g[2] or {}) do if e[1] == term then return e[3] end end\r\nend\r\nreturn nil\r\nend\r\n\r\n\r\n\r\nfunction K.canDo(sh, fight, speed)\r\nif not CLASSES[sh.class or \"\"] then return \"\" end\r\nlocal p = type(sh.picks) == \"table\" and sh.picks or {}\r\nlocal groups, passive, seen = {}, {}, {}\r\nfor _, w in ipairs(K.CAN_ORDER) do groups[w] = {} end\r\n\r\n\r\nlocal v, row, lvNow = sh, {}, 1\r\nlocal function tipOf(e) return type(e.tip) == \"function\" and e.tip(v, row) or e.tip end\r\nlocal function fits(e)\r\nreturn not ((e.from and lvNow < e.from) or (e.pick and not K.pickHas(p[e.pick[1]], e.pick[2])) or (K.LITE and e.lite == \"skip\"))\r\nend\r\n\r\nlocal function add(e, fallback)\r\nlocal tip = (K.LITE and e.litetip and fallback) or tipOf(e) or fallback or \"\"\r\nif not e.when then\r\npassive[#passive + 1] = tipSpan(e.ko, tip)\r\nreturn\r\nend\r\nlocal cost = e.cost or (e.res and K.canCost(e.res, e.n, e.unit))\r\nlocal head = K.CAN_WHEN[e.when] .. (cost and (\" · \" .. cost) or \"\")\r\ngroups[e.when][#groups[e.when] + 1] = tipSpan(e.ko, head .. \"\\n\" .. tip)\r\n.. (cost and ('<small style=\"opacity:.65\"> ' .. esc(cost) .. '</small>') or \"\")\r\nend\r\nlocal function own(key) return K.featTip(key, v.class, v) end\r\nfor _, c in ipairs(K.classes(sh)) do\r\nv, row, lvNow = K.view(sh, c.name, c.level), c.row, c.level\r\nlocal cl = CLASSES[c.name]\r\nfor _, x in ipairs(Feat.levelFeatures(v)) do\r\nlocal key = x:gsub(\" %(.-%)$\", \"\")\r\n\r\nif not seen[key] then\r\nseen[key] = true\r\nif key:match(\" Subclass$\") then\r\nlocal sub = K.subOf(sh, c.name) or c.name\r\nlocal srec = K.subRec(c.name, sub) or {}\r\npassive[#passive + 1] = tipSpan(\"하위 클래스: \" .. koName(sub), (SUBCLASS_TIP[sub] or (srec.tip and tostring(srec.tip)) or sub) .. K.subOnlyTip(c.name))\r\nif K.CAN_SUB3[sub] then\r\nfor _, e in ipairs(K.CAN_SUB3[sub]) do if fits(e) then add(e) end end\r\nelse\r\n\r\nfor _, n in ipairs((type(srec.levels) == \"table\" and srec.levels or {})[tostring(K.subLevel(c.name))] or {}) do\r\nif not seen[n] then\r\nseen[n] = true\r\nlocal any = false\r\nfor _, e in ipairs(K.featCan(n) or {}) do if fits(e) then add(e, own(n)); any = true end end\r\nif not any then passive[#passive + 1] = tipSpan(NAMES_KO[n] or koName(n), own(n) or \"\") end\r\nend\r\nend\r\nend\r\nelseif key == \"Channel Divinity\" then\r\nfor _, e in ipairs(K.CAN_CD[v.class] or {}) do if fits(e) and not (e.name and K.replaced(v, e.name)) then add(e) end end\r\n\r\nlocal cr = K.FX[key]\r\nfor _, e in ipairs(type(cr) == \"table\" and type(cr.fx) == \"table\" and cr.fx or {}) do\r\nlocal o = e.t == \"choice\" and p[e.key]\r\nfor _, ov in ipairs(type(o) == \"table\" and o or { o }) do\r\nif type(ov) == \"string\" then for _, ce in ipairs(K.featCan(ov) or {}) do if fits(ce) then add(ce, own(ov)) end end end\r\nend\r\nend\r\nelseif key == \"Metamagic\" then\r\nfor _, n in ipairs(type(p.metamagic) == \"table\" and p.metamagic or {}) do\r\nadd({ ko = \"마법변형: \" .. (NAMES_KO[n] or n), when = \"other\", tip = \"주문을 쓸 때 술법 점수를 써서 고칩니다(주문 하나에 하나). \" .. (Feat.TIP.metamagic[n] or \"\") })\r\nend\r\nif type(p.metamagic) ~= \"table\" or #p.metamagic == 0 then passive[#passive + 1] = tipSpan(koName(key), own(key) or \"\") end\r\nelseif key == \"Eldritch Invocations\" then\r\nfor _, n in ipairs(type(p.invocations) == \"table\" and p.invocations or {}) do\r\nlocal fc = K.PACK.feat[n] == \"invocation\" and K.featCan(n)\r\nif fc then\r\nfor _, e in ipairs(fc) do if fits(e) then add(e, own(n)) end end\r\nelse\r\nadd({ ko = NAMES_KO[n] or n, when = K.CAN_INV[n], tip = Feat.TIP.invocations[n] or \"\" })\r\nend\r\nend\r\nif type(p.invocations) ~= \"table\" or #p.invocations == 0 then passive[#passive + 1] = tipSpan(koName(key), own(key) or \"\") end\r\nelseif key == \"Epic Boon\" and type(p.boon) == \"string\" and p.boon ~= \"\" then\r\nadd({ ko = NAMES_KO[p.boon] or p.boon, when = K.CAN_BOON[p.boon], tip = K.FX[p.boon] and K.FX[p.boon].tip or \"\" })\r\nelseif K.featCan(key) then\r\nlocal any = false\r\nfor _, e in ipairs(K.featCan(key)) do if fits(e) then add(e, own(key)); any = true end end\r\nif not any then passive[#passive + 1] = tipSpan(NAMES_KO[key] or koName(key), own(key) or \"\") end\r\nelseif own(key) then\r\npassive[#passive + 1] = tipSpan(NAMES_KO[key] or (FEATURE_KO[key] and FEATURE_KO[key][1]) or koName(key), own(key))\r\nelse\r\npassive[#passive + 1] = esc(koName(key))\r\nend\r\nend\r\nend\r\nend\r\n\r\nv, row, lvNow = sh, {}, K.charLevel(sh)\r\nfor _, e in ipairs(K.CAN_SPECIES[sh.species or \"\"] or {}) do\r\nif fits(e) and not (e.res and not PC.res[e.res]) then add(e) end\r\nend\r\n\r\nlocal bgFx = {}\r\nfor _, row in ipairs({ SPECIES[sh.species or \"\"], BACKGROUNDS[sh.background or \"\"] }) do\r\nfor _, n in ipairs(type(row) == \"table\" and type(row.fx) == \"table\" and row.fx or {}) do bgFx[#bgFx + 1] = n end\r\nend\r\nfor _, n in ipairs(bgFx) do\r\nif type(n) == \"string\" and K.FX[n] and not seen[n] then\r\nseen[n] = true\r\nlocal any = false\r\nfor _, e in ipairs(K.featCan(n) or {}) do if fits(e) then add(e, own(n)); any = true end end\r\nif not any then passive[#passive + 1] = tipSpan(NAMES_KO[n] or koName(n), own(n) or \"\") end\r\nend\r\nend\r\n\r\n\r\nfor _, x in ipairs(Feat.fxList(sh)) do\r\nlocal cat = K.PACK.feat[x.name]\r\nif cat and cat ~= \"invocation\" and cat ~= \"metamagic\" and not seen[x.name] then\r\nseen[x.name] = true\r\nfor _, e in ipairs(K.featCan(x.name) or {}) do if fits(e) then add(e, own(x.name)) end end\r\nend\r\nend\r\nif PC.res[\"Heroic Inspiration\"] then\r\nadd({ ko = koName(\"Heroic Inspiration\"), when = \"other\", res = \"Heroic Inspiration\", tip = \"d20을 굴린 직후 다시 굴리고, 새 값을 씁니다.\"\r\n.. (sh.species == \"Human\" and \" 긴 휴식을 마칠 때마다 생깁니다(휴먼의 지략).\" or \"\")\r\n.. (#Feat.fxOf(sh, \"insp_each_turn\") > 0 and \" 싸우는 동안 내 턴이 시작될 때 없으면 다시 생깁니다(영웅적 전사).\" or \"\") })\r\nend\r\nlocal out = { '<div class=\"dnd-feat-t\">할 수 있는 것</div>' }\r\nif fight then\r\nfor _, b in ipairs(K.CAN_BASIC) do\r\nlocal o = {}\r\nfor _, term in ipairs(b.terms) do\r\nlocal desc = K.dictDesc(term)\r\nlocal label = (term == \"이동\" and speed) and (\"속도 \" .. speed .. \"피트\") or term\r\nif desc then o[#o + 1] = tipSpan(label, (K.CAN_BASIC_HEAD[term] or b.head) .. \"\\n\" .. desc) end\r\nend\r\nif #o > 0 then out[#out + 1] = '<div class=\"dnd-kr\"><span class=\"dnd-kk\">' .. b.row .. '</span><span class=\"dnd-kv\">' .. table.concat(o, \" · \") .. '</span></div>' end\r\nend\r\nend\r\nlocal any = false\r\nfor _, w in ipairs(K.CAN_ORDER) do\r\nif #groups[w] > 0 then\r\nany = true\r\nout[#out + 1] = '<div class=\"dnd-kr\"><span class=\"dnd-kk\">' .. K.CAN_WHEN[w] .. '</span><span class=\"dnd-kv\">' .. table.concat(groups[w], \" · \") .. '</span></div>'\r\nend\r\nend\r\nif not any then out[#out + 1] = '<div class=\"dnd-dim\">아직 따로 쓰는 기능이 없습니다. 공격과 주문, 그리고 질주·이탈·회피·돕기 같은 기본 행동을 씁니다.</div>' end\r\nout[#out + 1] = '<div class=\"dnd-feat-t\">늘 적용되는 것</div><div>' .. table.concat(passive, \" · \") .. '</div>'\r\nreturn table.concat(out)\r\nend\r\n\r\n\r\n\r\nfunction K.itemWrap(name, label, extra, rec)\r\nif extra then return tipSpan(label, extra) end\r\nlocal l = type(rec) == \"table\" and type(rec.loot) == \"table\" and rec.loot[name]\r\nif type(l) == \"table\" then return tipSpan(label, l.srd and K.MI.tipKo(name, l) or K.lootTipKo(name, l)) end\r\nlocal tip = ITEM_TIP[name]\r\nreturn tip and tipSpan(label, label .. \"\\n\" .. tip) or esc(label)\r\nend\r\n\r\n\r\n\r\nfunction K.lootPwKo(pwEn)\r\nreturn (pwEn:gsub(\"(%a+) %+(%d+d%d+) damage\", function(ty, d) return (DAMAGE_KO[ty] or ty) .. \" 피해 +\" .. d end)\r\n:gsub(\"Critical Hit on 19%-20\", \"치명타 19~20\"):gsub(\"Resistance to (%a+)\", function(ty) return (DAMAGE_KO[ty] or ty) .. \" 저항\" end)\r\n:gsub(\"%+1 to every saving throw\", \"모든 내성 +1\"):gsub(\" %(its spell power set%)\", \" (주문 능력 정함)\")\r\n:gsub(\"([%a' /]+) (%d+)/Long Rest\", function(sp, n)\r\nsp = trim(sp)\r\nreturn (NAMES_KO[sp] or sp) .. \" 긴 휴식마다 \" .. n .. \"회\"\r\nend):gsub(\", \", \" · \"))\r\nend\r\n\r\n\r\nfunction K.spellTipKo(n)\r\nlocal t = spellTip(n)\r\nif not SPELLS[n] then return nil end\r\nif t:sub(1, #n) == n then t = koName(n) .. t:sub(#n + 1) end\r\nreturn t\r\nend\r\n\r\n\r\nfunction K.lootKindKo(grade, hasPw)\r\nif hasPw then return \"장신구\" end\r\nreturn (grade or \"C\") == \"C\" and \"기타\" or \"장신구\"\r\nend\r\nfunction K.lootTipKo(name, l)\r\nlocal o = { name }\r\nlocal plus = tonumber(l.plus) or 0\r\nif l.base then\r\nlocal isW = WEAPONS[l.base] ~= nil\r\no[#o + 1] = (l.grade or \"C\") .. \"등급 · \" .. koName(l.base) .. \" 바탕\" .. (plus > 0 and (isW and (\" · 명중·피해 +\" .. plus) or (\" · 방어도 +\" .. plus)) or \"\")\r\nelse\r\no[#o + 1] = (l.grade or \"C\") .. \"등급 · \" .. K.lootKindKo(l.grade, type(l.pw) == \"table\" and #l.pw > 0)\r\nif type(l.pw) == \"table\" and #l.pw > 0 then o[#o + 1] = \"장착하지 않아도 가방에 있으면 효과가 납니다.\" end\r\nend\r\nlocal pw = K.lootPwKo(LOOT.pwText(l.pw))\r\nif pw ~= \"\" then\r\nfor _, w in ipairs(type(l.pw) == \"table\" and l.pw or {}) do\r\nif w.k == \"spell\" and type(l.left) == \"table\" and l.left[w.spell] then pw = pw .. \" (\" .. l.left[w.spell] .. \"회 남음)\" end\r\nend\r\no[#o + 1] = pw\r\nfor _, w in ipairs(type(l.pw) == \"table\" and l.pw or {}) do\r\nlocal st = w.k == \"spell\" and K.spellTipKo(w.spell)\r\nif st then o[#o + 1] = \"\\n\" .. st end\r\nend\r\nend\r\nif (l.fx or \"\") ~= \"\" and l.fx ~= \"-\" then o[#o + 1] = l.fx end\r\nreturn table.concat(o, \"\\n\")\r\nend\r\n\r\n\r\nK.MI.RAR_KO = { C = \"흔함\", B = \"흔하지 않음\", A = \"희귀\", S = \"매우 희귀\", L = \"전설\", X = \"아티팩트\" }\r\nfunction K.MI.tipKo(name, l)\r\nlocal o = { koName(name) }\r\nlocal pm = l.srd and K.MAGIC[l.srd]\r\nif pm and pm.pack and type(pm.tip) == \"string\" and pm.tip ~= \"\" then o[#o + 1] = pm.tip end\r\no[#o + 1] = (K.MI.RAR_KO[l.grade] or \"\") .. (l.att and (l.attuned and \" · 조율함\" or \" · 조율해야 효과가 납니다\") or \"\")\r\nlocal function dk(t) return DAMAGE_KO[t] or koName(t) end\r\nlocal pw, tell = {}, false\r\nfor _, w in ipairs(type(l.pw) == \"table\" and l.pw or {}) do\r\nlocal k = w.k\r\nif k == \"ac\" then pw[#pw + 1] = \"방어도 +\" .. tostring(w.n) .. (w[\"if\"] and \" (갑옷·방패 없을 때)\" or \"\")\r\nelseif k == \"acbase\" then pw[#pw + 1] = \"갑옷 없을 때 방어도 \" .. tostring(w.n) .. \" + 민첩\"\r\nelseif k == \"save\" then pw[#pw + 1] = \"모든 내성 +\" .. tostring(w.n or 1)\r\nelseif k == \"check\" then pw[#pw + 1] = \"능력 판정 +\" .. tostring(w.n)\r\nelseif k == \"set\" then pw[#pw + 1] = koName(w.ab) .. \" \" .. tostring(w.n) .. \" (더 높으면 그대로)\"\r\nelseif k == \"add\" and (tonumber(w.n) or 0) < 0 then pw[#pw + 1] = koName(w.ab) .. \" \" .. tostring(w.n) .. \" (최소 \" .. tostring(w.min or 1) .. \")\"\r\nelseif k == \"add\" then pw[#pw + 1] = koName(w.ab) .. \" +\" .. tostring(w.n) .. \" (최대 \" .. tostring(w.max or 20) .. \")\"\r\nelseif k == \"pb\" then pw[#pw + 1] = \"숙련 보너스 +\" .. tostring(w.n)\r\nelseif k == \"spellatk\" then pw[#pw + 1] = \"주문 명중 +\" .. tostring(w.n)\r\nelseif k == \"spelldc\" then pw[#pw + 1] = \"주문 내성 난이도 +\" .. tostring(w.n)\r\nelseif k == \"resist\" then pw[#pw + 1] = dk(w.type) .. \" 저항\"\r\nelseif k == \"imm\" then pw[#pw + 1] = dk(w.type) .. \" 피해 면역\"\r\nelseif k == \"vuln\" then pw[#pw + 1] = dk(w.type) .. \" 취약\"\r\nelseif k == \"cimm\" then pw[#pw + 1] = koName(w.cond) .. \" 면역\"\r\nelseif k == \"dmg\" then\r\nlocal vs = {}\r\nfor _, v in ipairs(w.vs or {}) do vs[#vs + 1] = K.MI.VAR_KO[v] or koName(v) end\r\npw[#pw + 1] = (w.type == \"weapon\" and \"피해\" or (dk(w.type) .. \" 피해\")) .. \" +\" .. w.dice\r\n.. (#vs > 0 and (\" (\" .. table.concat(vs, \"·\") .. \"에게)\") or \"\") .. (w.nat20 and \" (d20이 20일 때)\" or \"\")\r\n.. (w.thrown and \" (던질 때)\" or \"\") .. (w.may and not w.vs and \" (켰을 때)\" or \"\")\r\nelseif k == \"dtype\" then pw[#pw + 1] = dk(w.type) .. \" 피해를 줍니다\"\r\nelseif k == \"nocrit\" then pw[#pw + 1] = \"치명타를 맞아도 일반 명중\"\r\nelseif k == \"mithral\" then pw[#pw + 1] = \"근력 조건·은신 불리점 없음\"\r\nelseif k == \"prof\" then pw[#pw + 1] = \"숙련 없이 입어도 됩니다\"\r\nelseif k == \"maxhp\" then pw[#pw + 1] = \"레벨마다 최대 생명력 +1\"\r\nelseif k == \"speedmin\" then pw[#pw + 1] = \"속도 최소 \" .. tostring(w.n) .. \"피트\"\r\nelseif k == \"dmgbonus\" then pw[#pw + 1] = \"무기 피해 +\" .. tostring(w.n)\r\nelseif k == \"bonusattack\" then pw[#pw + 1] = \"추가 행동으로 이 무기 공격 한 번\"\r\nelseif k == \"unarmed\" then pw[#pw + 1] = \"맨손 공격 \" .. w.dice .. \" \" .. dk(w.type) .. \", 명중·피해 +\" .. tostring(w.plus)\r\nelseif k == \"deathsave\" then pw[#pw + 1] = \"죽음 내성 9 이하는 10으로\"\r\nelseif k == \"noammo\" then pw[#pw + 1] = \"탄약 없이 쏩니다\"\r\nelseif k == \"tell\" then tell = true end\r\nend\r\nif #pw > 0 then o[#o + 1] = table.concat(pw, \" · \") end\r\nif l.chmax then o[#o + 1] = \"충전 \" .. tostring(l.ch or 0) .. \"/\" .. l.chmax .. \" (새벽마다 일부 회복)\" end\r\nlocal m = K.MAGIC[l.srd] or {}\r\nlocal sps = {}\r\nfor _, s in ipairs(m.sp or {}) do\r\nif SPELLS[s.s] then sps[#sps + 1] = koName(s.s) .. (s.day and (\" 새벽마다 \" .. s.day .. \"회\") or ((s.c or 0) == 0 and \" 무제한\" or (\" 충전 \" .. s.c .. \"개\"))) end\r\nend\r\nif #sps > 0 then o[#o + 1] = \"주문: \" .. table.concat(sps, \", \") end\r\nif l.srd == \"Spell Scroll\" then o[#o + 1] = \"읽으면 \" .. koName(l.var or \"\") .. \" 시전 (그 주문이 내 클래스 목록에 있어야 합니다)\" end\r\n\r\nlocal tipOf = {}\r\nif l.srd == \"Spell Scroll\" and l.var then tipOf[1] = l.var\r\nelseif #(m.sp or {}) <= 2 then for _, x in ipairs(m.sp or {}) do tipOf[#tipOf + 1] = x.s end end\r\nfor _, n in ipairs(tipOf) do\r\nlocal st = K.spellTipKo(n)\r\nif st then o[#o + 1] = \"\\n\" .. st end\r\nend\r\nlocal u = type(m.use) == \"table\" and m.use\r\nif u then o[#o + 1] = u.day and \"새벽마다 한 번 씁니다\" or \"쓰면 사라집니다\" end\r\nif tell then o[#o + 1] = \"그 밖의 효과는 이야기에서\" end\r\nreturn table.concat(o, \"\\n\")\r\nend\r\n\r\n\r\n\r\nfunction K.otherGearHtml(sh)\r\nlocal order, n = {}, {}\r\nfor _, x in ipairs(type(sh.gear) == \"table\" and sh.gear or {}) do\r\nlocal k = koName(x)\r\nif not n[k] then order[#order + 1] = k; n[k] = 0 end\r\nn[k] = n[k] + 1\r\nend\r\nif #order == 0 then return \"\" end\r\nfor i, k in ipairs(order) do order[i] = k .. (n[k] > 1 and (\" ×\" .. n[k]) or \"\") end\r\nreturn '<div style=\"margin-top:4px\"><span class=\"dnd-dim\">그 밖의 짐</span> · ' .. esc(table.concat(order, \", \")) .. '</div>'\r\nend\r\n\r\nlocal function spellSpans(names)\r\nlocal o = {}\r\nfor _, n in ipairs(names or {}) do o[#o + 1] = tipSpan(koName(n), spellTip(n)) end\r\nreturn #o > 0 and table.concat(o, \" · \") or \"-\"\r\nend\r\n\r\n\r\n\r\n\r\nfunction K.pactText(sh, pc)\r\nif K.LITE and PC.res.MP then return string.format(\" · %s %d/%d\", K.MP.name(sh), tonumber(rawget(pc.res or {}, \"MP\")) or 0, PC.res.MP.max) end\r\nif not (CLASSES[K.castCl(sh) or \"\"] or {}).pact then return \"\" end\r\nlocal nm = K.pactApart(sh) and \"Pact Slot \" or \"Spell Slot \"\r\nfor l = 9, 1, -1 do\r\nlocal r = PC.res[nm .. l]\r\nif r then return string.format(\" · 계약 슬롯 %d레벨 %d/%d\", l, tonumber((pc.res or {})[nm .. l]) or 0, r.max) end\r\nend\r\nreturn \"\"\r\nend\r\nfunction K.spellRows(sh, pc, noSlots)\r\nlocal rows = {}\r\nif #(sh.cantrips or {}) > 0 then rows[#rows + 1] = \"소마법: \" .. spellSpans(sh.cantrips) end\r\nlocal byLv, seen, other, top = {}, {}, {}, 0\r\nlocal function add(n, always)\r\nif seen[n] then return end\r\nseen[n] = true\r\nlocal tip = spellTip(n) .. (always and \"\\n늘 준비된 주문입니다 (준비 개수와 따로).\" or \"\")\r\nlocal lv = SPELLS[n] and SPELLS[n].level\r\nif not lv or lv < 1 then other[#other + 1] = tipSpan(koName(n), tip); return end\r\nbyLv[lv] = byLv[lv] or {}\r\nbyLv[lv][#byLv[lv] + 1] = tipSpan(koName(n), tip)\r\nif lv > top then top = lv end\r\nend\r\nfor _, n in ipairs(sh.spells or {}) do add(n) end\r\nfor _, n in ipairs(Feat.always(sh)) do add(n, true) end\r\nlocal pact = (CLASSES[K.castCl(sh) or \"\"] or {}).pact\r\nif not noSlots then for l = 1, 9 do if PC.res[\"Spell Slot \" .. l] and l > top then top = l end end end\r\nfor l = 1, top do\r\nlocal slot = not pact and not noSlots and PC.res[\"Spell Slot \" .. l]\r\nif K.LITE and slot and PC.res.MP then\r\nlocal done = l >= 6 and type(pc.hi) == \"table\" and pc.hi[tostring(l)]\r\nrows[#rows + 1] = l .. \"레벨 (\" .. (done and \"오늘 씀\" or (K.MP.name(sh) .. \" \" .. K.MP.SPELL[l] .. (l >= 6 and \", 하루 1번\" or \"\"))) .. \")\"\r\n.. \": \" .. (byLv[l] and table.concat(byLv[l], \" · \") or \"-\")\r\nelseif byLv[l] or slot then\r\nrows[#rows + 1] = l .. \"레벨\" .. (slot and string.format(\" (슬롯 %d/%d)\", tonumber((pc.res or {})[\"Spell Slot \" .. l]) or 0, slot.max) or \"\")\r\n.. \": \" .. (byLv[l] and table.concat(byLv[l], \" · \") or \"-\")\r\nend\r\nend\r\nif #other > 0 then rows[#rows + 1] = \"그 밖: \" .. table.concat(other, \" · \") end\r\nreturn rows\r\nend\r\n\r\n\r\nfunction K.Form.refHtml()\r\nlocal function names(set)\r\nlocal o = {}\r\nfor en in pairs(set) do if type(en) == \"string\" then o[#o + 1] = koName(en) end end\r\ntable.sort(o)\r\nreturn table.concat(o, \" · \")\r\nend\r\nlocal function gear(e)\r\nlocal o = {}\r\nfor k, n in pairs(e.items or {}) do o[#o + 1] = (n > 1 and (n .. \" \") or \"\") .. koName(k) end\r\ntable.sort(o)\r\nfor _, g in ipairs(e.other or {}) do o[#o + 1] = koName(g) end\r\nif (e.gp or 0) > 0 then o[#o + 1] = \"금화 \" .. e.gp end\r\nreturn table.concat(o, \", \")\r\nend\r\nlocal b = { '<details style=\"margin:4px 0 6px\"><summary style=\"cursor:pointer;font-size:12px;color:#a8977a\">양식 직접 작성 · 고를 수 있는 것</summary>',\r\n'<div style=\"white-space:pre-wrap;user-select:all;-webkit-user-select:all;font-size:12px;line-height:1.5;padding:6px 9px;margin-top:5px;border:1px dashed rgba(212,175,90,.45);border-radius:4px\">' .. K.Form.TEMPLATE_BR .. '</div>',\r\n'<div class=\"dnd-opt-d\">빈 칸은 Lua가 채웁니다: 능력치는 클래스에 맞게 표준 배열, 보너스는 배경이 올려 주는 능력치에 +2/+1, 기술은 클래스가 흔히 고르는 것, 장비는 A(민첩 파이터는 B).</div>',\r\n'<div class=\"dnd-opt-t\">종족</div><div class=\"dnd-opt-d\">' .. esc(names(K.spOn())) .. '</div>',\r\n'<div class=\"dnd-opt-t\">배경 (보너스 줄 수 있는 능력치 · 주는 기술)</div>' }\r\nlocal bgs = {}\r\nfor en in pairs(K.bgsOn()) do bgs[#bgs + 1] = en end\r\ntable.sort(bgs)\r\nfor _, en in ipairs(bgs) do\r\nlocal r = BACKGROUNDS[en]\r\nlocal ab, sk = {}, {}\r\nfor _, a in ipairs(r.abilities) do ab[#ab + 1] = koName(a) end\r\nfor _, k in ipairs(r.skills) do sk[#sk + 1] = koName(k) end\r\nb[#b + 1] = '<div class=\"dnd-opt-d\"><b>' .. esc(koName(en)) .. '</b> · ' .. esc(table.concat(ab, \"·\")) .. ' · ' .. esc(table.concat(sk, \", \")) .. '</div>'\r\nend\r\nb[#b + 1] = '<div class=\"dnd-opt-t\">클래스 (기술 개수와 목록 · 장비 A / B)</div>'\r\nlocal cls = {}\r\nfor en in pairs(CLASSES) do cls[#cls + 1] = en end\r\ntable.sort(cls, function(x, y) return koName(x) < koName(y) end)\r\nfor _, en in ipairs(cls) do\r\nlocal r = CLASSES[en]\r\nlocal sk = {}\r\nfor _, k in ipairs(r.skills.from) do sk[#sk + 1] = koName(k) end\r\nb[#b + 1] = '<div class=\"dnd-opt-d\"><b>' .. esc(koName(en)) .. '</b> · 기술 ' .. r.skills.choose .. '개: ' .. esc(table.concat(sk, \", \"))\r\n.. '<br>A: ' .. esc(gear(r.equipment.A)) .. ' / B: ' .. esc(gear(r.equipment.B)) .. '</div>'\r\nend\r\nb[#b + 1] = '</details>'\r\nreturn table.concat(b)\r\nend\r\n\r\n\r\nFeat.WHAT = {\r\nstyle = \"전투 방식 하나. 늘 켜져 있습니다.\", order = \"클레릭의 신성한 소임 하나.\", primal = \"드루이드의 원시의 소임 하나.\",\r\nland = \"어느 땅의 주문을 늘 준비해 둘지 고릅니다.\", prey = \"공격에 붙는 사냥꾼의 기술 하나.\",\r\ndragon = \"브레스 무기와 피해 저항의 피해 종류를 정합니다.\",\r\nlineage = \"엘프 혈통 하나를 고릅니다. 소마법 하나와 3·5레벨에 주문 하나씩이 정해집니다 (설명을 펼쳐 보십시오).\",\r\ngnome = \"노움 혈통 하나를 고릅니다 (설명을 펼쳐 보십시오).\",\r\ngiant = \"거인의 힘 하나를 숙련 보너스만큼 쓸 수 있습니다 (긴 휴식에 다시 찹니다).\", legacy = \"저항하는 피해 종류와 혈통 주문이 정해집니다.\",\r\nkeen = \"엘프의 예리한 감각: 통찰·감지·생존 중 하나에 숙련을 얻습니다.\", feat = \"인간의 다재다능: 출신 재주 하나를 더 얻습니다.\",\r\nskillful = \"인간의 숙련: 아무 기술 하나에 숙련을 얻습니다 (환생으로 인간이 된 몸).\",\r\nmilist = \"마법 입문자: 어느 클래스의 주문 목록에서 배울지.\", skilled = \"숙련자: 아무 기술 셋에 숙련.\",\r\nmastery = \"고른 무기 종류로 공격하면 그 무기의 통달 속성(괴롭히기·스치기 등)이 붙습니다. 긴 휴식 뒤에 하나씩 바꿀 수 있습니다.\",\r\nspellab = \"종족 주문을 시전할 때 쓰는 능력치.\", xskill = \"기술 숙련 하나 더.\", metamagic = \"술법 점수로 주문을 고쳐 쓰는 방법.\",\r\nmcskill = \"나중에 얻은 클래스가 주는 기술 숙련 하나입니다. 바드는 아무 기술, 레인저와 로그는 그 클래스의 기술 목록에서 고릅니다.\",\r\ninvocations = \"늘 쓰는 섬뜩한 영창 능력.\",\r\nblessed = \"고른 쪽 하나가 늘 켜져 있습니다.\", fury = \"고른 쪽 하나가 늘 켜져 있습니다.\",\r\naffinity = \"그 피해에 저항하고, 그 피해를 주는 주문의 피해 굴림 하나에 매력 수정치를 더합니다.\", resilience = \"고른 피해 종류에 저항합니다.\",\r\nxstyle = \"전투 방식 하나 더. 늘 켜져 있습니다.\",\r\nboonab = \"고른 능력치가 1 오릅니다(최대 30).\",\r\nbeast = { Dog = \"생존 숙련, 냄새로 쫓는 판정에 이점, 5피트 안에 아군이 있으면 공포 내성에 이점.\",\r\nCat = \"오르기 속도가 이동 속도와 같고, 떨어질 때 피해가 레벨 × 5만큼 줄어듭니다.\",\r\nFox = \"하급 환영 소마법을 늘 알고, 기만에 숙련.\", Bear = \"운반량이 두 배, 붙잡기에서 벗어나는 판정에 이점, 레벨마다 생명력 +1.\" },\r\nmastone = \"준비해 둔 이 주문을 슬롯 없이 마음대로 시전합니다(가장 낮은 레벨로).\", masttwo = \"준비해 둔 이 주문을 슬롯 없이 마음대로 시전합니다(가장 낮은 레벨로).\",\r\nsig = \"늘 준비되어 있고, 짧은 휴식이나 긴 휴식마다 슬롯 없이 한 번씩 시전합니다.\",\r\n}\r\n\r\nFeat.TIP.xstyle = Feat.TIP.style\r\n\r\nFeat.TIP.lustbrand = setmetatable({}, { __index = function(_, v)\r\nlocal r = K.PACK.afflict and K.PACK.afflict[v]\r\nreturn type(r) == \"table\" and (r.tip or r.text) or nil\r\nend })\r\n\r\nsetmetatable(Feat.TIP, { __index = function(_, k)\r\nlocal cl = K.subClassOf(k)\r\nif not cl then return nil end\r\nreturn setmetatable({}, { __index = function(_, v)\r\nlocal rec = K.subRec(cl, v)\r\nreturn SUBCLASS_TIP[v] or (rec and rec.tip and tostring(rec.tip)) or nil\r\nend })\r\nend })\r\nsetmetatable(Feat.WHAT, { __index = function(_, k)\r\nlocal cl = K.subClassOf(k)\r\nif not cl then return nil end\r\nlocal d = K.subDefault(cl)\r\nreturn \"고르기 전까지는 기본 하위 클래스(\" .. (NAMES_KO[d] or d) .. \")의 기능이 적용됩니다. 고른 하위 클래스의 기능은 그 레벨부터 얻습니다.\"\r\nend })\r\n\r\nif K.LITE then\r\nFeat.KO.lineage = { Drow = \"다크 엘프\", [\"High Elf\"] = \"하이 엘프\", [\"Wood Elf\"] = \"우드 엘프\" }\r\nFeat.KO.dragon = { Acid = \"산성\", Cold = \"냉기\", Fire = \"화염\", Lightning = \"번개\", Poison = \"독\" }\r\nFeat.KO.giant = { Cloud = \"바람\", Fire = \"불꽃\", Frost = \"서리\", Hill = \"대지\", Stone = \"바위\", Storm = \"폭풍\" }\r\nFeat.KO.legacy = { Abyssal = \"독의 혈통\", Chthonic = \"죽음의 혈통\", Infernal = \"불꽃의 혈통\" }\r\nFeat.KO.milist = { Cleric = \"사제\", Druid = \"자연술사\", Wizard = \"마법사\" }\r\nFeat.TITLE.dragon = \"용인 원소 · 숨결과 저항의 피해 종류\"\r\nFeat.TITLE.legacy = \"마족 혈통\"\r\nFeat.TITLE.lineage = \"엘프 혈통\"\r\nend\r\n\r\nfunction K.liteSwap(s)\r\nif not K.LITE or type(s) ~= \"string\" then return s end\r\nfor _, p in ipairs(K.LITE_SWAP or {}) do s = s:gsub(p[1], p[2]) end\r\nreturn s\r\nend\r\nfor _, rec in pairs(K.FX) do\r\nfor _, e in ipairs(rec.fx) do\r\nif e.t == \"choice\" then\r\nFeat.TIP[e.key] = Feat.TIP[e.key] or {}\r\nfor _, o in ipairs(e.options or {}) do Feat.TIP[e.key][o] = K.FX[o] and K.FX[o].tip or nil end\r\nend\r\nend\r\nend\r\n\r\n\r\n\r\nfunction K.halfPick(id, sh, a)\r\nif not sh.scores[a] then return nil end\r\nlocal first = getChatVar(id, \"dnd_asi_half\")\r\nif first == nil or first == \"\" or first == \"null\" or first == a or not sh.scores[first] then\r\nsetChatVar(id, \"dnd_asi_half\", first == a and \"\" or a)\r\nreturn nil\r\nend\r\nsetChatVar(id, \"dnd_asi_half\", \"\")\r\nreturn \"Half_\" .. first .. \"_\" .. a\r\nend\r\n\r\n\r\n\r\n\r\nfunction K.grappleOk(sh)\r\nlocal sc = type(sh) == \"table\" and type(sh.scores) == \"table\" and sh.scores or {}\r\nreturn (tonumber(sc.Strength) or 0) >= 13 or (tonumber(sc.Dexterity) or 0) >= 13\r\nend\r\n\r\n\r\nfunction K.asiFeatFold(sh, prefix, total)\r\nlocal rows = {}\r\nlocal function row(label, tip, btns)\r\nrows[#rows + 1] = '<div style=\"margin:4px 0\"><span class=\"dnd-opt-d\">' .. (tip and tipSpan(label, tip) or esc(label)) .. '</span> ' .. table.concat(btns, \" \") .. '</div>'\r\nend\r\nif sh.feat4 ~= \"Grappler\" and K.grappleOk(sh) then\r\nrow(koName(\"Grappler\"), Feat.TIP.feat and Feat.TIP.feat.Grappler,\r\n{ btn(koName(\"Strength\") .. \" +1\", prefix .. \"GrapplerStr\", false), btn(koName(\"Dexterity\") .. \" +1\", prefix .. \"GrapplerDex\", false) })\r\nend\r\nfor _, fname in ipairs(K.gfeatList(sh, total)) do\r\nlocal asi, b = K.gfeatAsi(sh, fname), {}\r\nif #asi == 0 then\r\nb[1] = btn(\"받기\", prefix .. K.gfeatPay(fname), false)\r\nelse\r\nfor _, a in ipairs(asi) do if SCORE[a] then b[#b + 1] = btn(koName(a) .. \" +1\", prefix .. K.gfeatPay(fname, a), false) end end\r\nend\r\nif #b > 0 then row(koName(fname), K.FX[fname] and K.FX[fname].tip or nil, b) end\r\nend\r\nif #rows == 0 then return \"\" end\r\nreturn '<details style=\"margin:6px 0\"><summary style=\"cursor:pointer;font-size:12px;color:#a8977a\">재주로 받기 (' .. #rows .. '개) ▾</summary>'\r\n.. table.concat(rows) .. '</details>'\r\nend\r\nfunction K.halfRow(id, prefix)\r\nlocal first = getChatVar(id, \"dnd_asi_half\")\r\nlocal picks = {}\r\nfor _, a in ipairs(ABILS) do\r\nif SCORE[a] < 20 then picks[#picks + 1] = btn(string.format(\"%s %d→%d\", koName(a), SCORE[a], SCORE[a] + 1), prefix .. a, first == a) end\r\nend\r\nlocal wait = SCORE[first or \"\"] and (\" · \" .. koName(first) .. \" 다음으로 하나 더 고르십시오\") or \"\"\r\nreturn '<div class=\"dnd-opt-d\">또는 둘에 +1씩' .. esc(wait) .. '</div>' .. K.btnRows(picks)\r\nend\r\n\r\n\r\n\r\nfunction K.lvClass(id, sh)\r\nlocal c = getChatVar(id, \"dnd_lv_cls\")\r\nif type(c) == \"string\" and CLASSES[c] and c ~= sh.class and K.mcCan(sh, c) then return c end\r\nreturn sh.class\r\nend\r\n\r\nfunction K.mcGainKo(name)\r\nlocal g, o = K.mcGains(name), { \"생명력 주사위 d\" .. CLASSES[name].hit_die }\r\nif g.martial then o[#o + 1] = \"군용 무기\" end\r\nlocal ar = {}\r\nfor _, k in ipairs({ \"light\", \"medium\" }) do if g[k] then ar[#ar + 1] = Shop.ARMOR_KO[k] end end\r\nif g.shield then ar[#ar + 1] = \"방패\" end\r\nif #ar > 0 then o[#o + 1] = table.concat(ar, \"·\") end\r\nif g.skill == \"any\" then o[#o + 1] = \"아무 기술 하나\" elseif g.skill then o[#o + 1] = koName(name) .. \" 기술 목록에서 하나\" end\r\nreturn table.concat(o, \", \")\r\nend\r\n\r\nfunction K.mcWhyKo(why, x)\r\nif why == \"prereq\" then\r\nlocal o = {}\r\nfor _, n in ipairs(x or {}) do\r\nlocal ab = {}\r\nfor _, a in ipairs(n.abilities) do ab[#ab + 1] = koName(a) end\r\no[#o + 1] = table.concat(ab, n.either and \"이나 \" or \"·\") .. \" 13\"\r\nend\r\nreturn table.concat(o, \", \") .. \" 필요\"\r\nend\r\nif why and why:match(\"^max level\") then return \"최고 레벨\" end\r\nif why == \"pact\" then return \"계약 마법은 한 클래스만\" end\r\nif why == \"book\" then return \"주문책은 한 클래스만\" end\r\nreturn \"안 됨\"\r\nend\r\n\r\n\r\n\r\n\r\nfunction K.resetOk(sh, pc)\r\nreturn type(sh) == \"table\" and not sh.default and type(pc) == \"table\" and (pc.making or pc.dead) and true or false\r\nend\r\nfunction K.sheetReset(sh, pc, why)\r\nfor k in pairs(sh) do sh[k] = nil end\r\nfor k, v in pairs(deepCopy(DEFAULT_SHEET)) do sh[k] = v end\r\nsh.reset = why\r\napplySheet(sh)\r\nlocal party = pc.allies\r\nfor k in pairs(pc) do pc[k] = nil end\r\nfor k, v in pairs(newPC()) do pc[k] = v end\r\npc.allies = party\r\nFeat.cur.snap = nil\r\nend\r\nfunction K.resetRow(id, sh, pc)\r\nif not K.resetOk(sh, pc) then return \"\" end\r\nif loadCombat(id).active then return \"\" end\r\n\r\nif getChatVar(id, \"dnd_reset_ask\") == \"1\" then\r\nreturn '<div style=\"margin-top:12px\"><div class=\"dnd-opt-t\">시트 초기화</div><div class=\"dnd-opt-d\">' .. (pc.dead and \"죽은 캐릭터를\" or \"지금 캐릭터를\")\r\n.. ' 지우고 처음 만들 때처럼 새로 만듭니다. 고른 것과 장비, 돈, 경험치가 모두 사라지고 동료는 남습니다.</div>'\r\n.. K.btnRows({ btn(\"초기화\", \"dnd_sheetreset_yes\", false), btn(\"그만두기\", \"dnd_sheetreset_no\", false) }) .. '</div>'\r\nend\r\nreturn '<div class=\"dnd-opt-btns\" style=\"margin-top:12px\">' .. btn(\"시트 초기화 · 새로 만들기\", \"dnd_sheetreset\", false) .. '</div>'\r\nend\r\n\r\n\r\nfunction K.lvHist(id, sh, pc)\r\nlocal cur = Feat.picks(sh).sexhist\r\nlocal h = getChatVar(id, \"dnd_lv_hist\")\r\nif type(cur) == \"string\" and type(h) == \"string\" and h ~= cur and K.AR.histOpen(h, pc) then return h end\r\nreturn cur\r\nend\r\nfunction K.lvHistRow(id, sh, pc)\r\nlocal cur = Feat.picks(sh).sexhist\r\nif type(cur) ~= \"string\" or not K.PACK.ar.hist[cur] then return \"\" end\r\nlocal want = K.lvHist(id, sh, pc)\r\nlocal names = {}\r\nfor _, n in ipairs(K.AR.names()) do if n == cur or K.AR.histOpen(n, pc) then names[#names + 1] = n end end\r\nif #names <= 1 then return \"\" end\r\ntable.sort(names, function(x, y)\r\nlocal a, b = tonumber(K.PACK.ar.hist[x].xp) or 0, tonumber(K.PACK.ar.hist[y].xp) or 0\r\nif a ~= b then return a < b end\r\nreturn x < y\r\nend)\r\nlocal o = {}\r\nfor _, n in ipairs(names) do\r\no[#o + 1] = btn((n == cur and \"그대로 · \" or \"\") .. Feat.label(\"sexhist\", n) .. \" d\" .. tonumber(K.PACK.ar.hist[n].die),\r\n\"dnd_lvhist_\" .. n:gsub(\"'\", \"_Q_\"):gsub(\" \", \"_\"), n == want)\r\nend\r\nreturn '<div class=\"dnd-opt-t\">성적 이력 · 이 레벨부터</div>' .. K.btnRows(o)\r\n.. '<div class=\"dnd-opt-d\">경험치가 연 이력으로 바꿀 수 있습니다. 회복 주사위가 다르면 이 레벨부터 오르는 흥분도 최대치만 새 주사위를 따르고, 앞 레벨의 몫은 그대로입니다.'\r\n.. ' 회복 주사위는 이제 새 주사위로 굴립니다. 성적 도구 숙련과 페티시는 새 이력의 수를 따릅니다(늘면 고를 것이, 줄면 뺄 것이 생깁니다).</div>'\r\nend\r\nfunction K.histSpans(sh)\r\nif type(sh.histlv) ~= \"table\" then return \"\" end\r\nlocal lvs = {}\r\nfor k in pairs(sh.histlv) do if tonumber(k) then lvs[#lvs + 1] = tonumber(k) end end\r\ntable.sort(lvs)\r\nlocal o = {}\r\nfor i, lv in ipairs(lvs) do\r\nlocal nx, name = lvs[i + 1], sh.histlv[tostring(lv)]\r\nlocal h = K.PACK.ar and K.PACK.ar.hist[name or \"\"]\r\nlocal span = not nx and string.format(\"%d레벨부터\", lv) or (nx - 1 > lv and string.format(\"%d~%d레벨\", lv, nx - 1) or string.format(\"%d레벨\", lv))\r\no[#o + 1] = span .. \" \" .. Feat.label(\"sexhist\", name) .. (h and (\" d\" .. tonumber(h.die)) or \"\")\r\nend\r\nreturn #o > 1 and (' <span class=\"dnd-m\">(' .. esc(table.concat(o, \", \")) .. ')</span>') or \"\"\r\nend\r\n\r\n\r\nfunction K.lvClassRow(id, sh, cls)\r\nlocal have = {}\r\nfor _, c in ipairs(K.classes(sh)) do\r\nif K.mcCan(sh, c.name) then\r\nhave[#have + 1] = btn(string.format(\"%s %d→%d\", koName(c.name), c.level, c.level + 1), \"dnd_lvcls_\" .. c.name, c.name == cls)\r\nelse\r\nhave[#have + 1] = '<span class=\"dnd-opt-btn off\">' .. esc(koName(c.name) .. \" \" .. c.level .. \" · 최고 레벨\") .. '</span>'\r\nend\r\nend\r\nif K.cl(sh, cls) == 0 then have[#have + 1] = btn(koName(cls) .. \" 0→1\", \"dnd_lvcls_\" .. cls, true) end\r\nlocal names, can, cannot = {}, {}, {}\r\nfor n in pairs(CLASSES) do if n:sub(1, 1) ~= \"_\" and K.cl(sh, n) == 0 then names[#names + 1] = n end end\r\ntable.sort(names, function(x, y) return koName(x) < koName(y) end)\r\nfor _, n in ipairs(names) do\r\nlocal ok, why, x = K.mcCan(sh, n)\r\nif ok then\r\nif n ~= cls then can[#can + 1] = btn(koName(n), \"dnd_lvcls_\" .. n, false) end\r\nelse\r\ncannot[#cannot + 1] = koName(n) .. \" (\" .. K.mcWhyKo(why, x) .. \")\"\r\nend\r\nend\r\nlocal o = { '<div class=\"dnd-opt-t\">레벨을 올릴 클래스</div>', K.btnRows(have) }\r\nif K.cl(sh, cls) == 0 then\r\no[#o + 1] = '<div class=\"dnd-opt-d\">' .. esc(koName(cls) .. \"에서 더 얻는 것: \" .. K.mcGainKo(cls)) .. '. 그 클래스의 1레벨 기능도 얻습니다.</div>'\r\nend\r\nlocal body = {}\r\nif #can > 0 then body[#body + 1] = K.btnRows(can) end\r\nif #cannot > 0 then body[#body + 1] = '<div class=\"dnd-opt-d\">고를 수 없음: ' .. esc(table.concat(cannot, \" · \")) .. '</div>' end\r\nbody[#body + 1] = '<div class=\"dnd-opt-d\">새 클래스는 1레벨부터 시작합니다. 숙련 보너스와 경험치, 소마법의 위력은 캐릭터 레벨(모든 클래스의 합)을 따르고,'\r\n.. ' 내성 굴림 숙련과 시작 장비는 처음 클래스의 것만 있습니다. 새 클래스에서는 숙련 일부만 더 얻습니다. 고르려면 지금 클래스와 새 클래스의 주요 능력치가 모두 13 이상이어야 합니다.'\r\n.. ' 주문을 쓰는 클래스가 둘 이상이면 준비 주문은 클래스마다 따로 고르고, 주문 슬롯은 함께 씁니다.</div>'\r\no[#o + 1] = '<details style=\"margin:4px 0 6px\"><summary style=\"cursor:pointer;font-size:12px;color:#a8977a\">다른 클래스 더하기 (멀티클래스)</summary>'\r\n.. table.concat(body) .. '</details>'\r\nreturn table.concat(o)\r\nend\r\n\r\n\r\n\r\nfunction K.pickRows(id, sh, pc)\r\nlocal b = {}\r\nlocal cl = CLASSES[sh.class]\r\nlocal fold = '<details style=\"margin:4px 0 6px\"><summary style=\"cursor:pointer;font-size:12px;color:#a8977a\">설명</summary><div class=\"dnd-opt-d\">'\r\n\r\nlocal expPicks, expLeft = expertiseChoices(sh)\r\nif expLeft > 0 then\r\nlocal title = (K.cl(sh, \"Wizard\") >= 2 and K.cl(sh, \"Rogue\") + K.cl(sh, \"Bard\") + K.cl(sh, \"Ranger\") == 0)\r\nand \"학자 · 비전학·역사학·수사·의학·자연학·종교학 중 숙련된 하나 (숙련 보너스 두 배)\"\r\nor \"숙달 · 숙련된 기술을 고릅니다 (숙련 보너스 두 배)\"\r\nb[#b + 1] = '<div class=\"dnd-opt-t\">' .. esc(title) .. string.format(\" · %d개 남음</div>\", expLeft)\r\nlocal picks = {}\r\nfor _, k in ipairs(expPicks) do\r\npicks[#picks + 1] = btn(string.format(\"%s %+d→%+d\", koName(k), bonusFor(k), bonusFor(k) + PROF), \"dnd_exp_\" .. k:gsub(\" \", \"_\"), false)\r\nend\r\n\r\nif K.cl(sh, \"Wizard\") >= 2 and K.cl(sh, \"Rogue\") + K.cl(sh, \"Bard\") + K.cl(sh, \"Ranger\") == 0 then\r\nlocal mine = {}\r\nfor _, k in ipairs(expPicks) do mine[k] = true end\r\nfor _, k in ipairs({ \"Arcana\", \"History\", \"Investigation\", \"Medicine\", \"Nature\", \"Religion\" }) do\r\nif not mine[k] and not (sh.expertise and table.concat(sh.expertise, \",\"):find(k, 1, true)) then\r\npicks[#picks + 1] = '<span class=\"dnd-opt-btn off\">' .. esc(koName(k)) .. ' · 숙련 아님</span>'\r\nend\r\nend\r\nend\r\nif #picks == 0 then picks[1] = '<span class=\"dnd-opt-d\">고를 수 있는 숙련 기술이 없습니다.</span>' end\r\nb[#b + 1] = K.btnRows(picks)\r\nend\r\n\r\nif K.PG and K.PG.on() and (type(sh.picks) ~= \"table\" or sh.picks.pregwant == nil) then\r\nb[#b + 1] = '<div class=\"dnd-opt-t\">임신 원함</div><div class=\"dnd-opt-d\">순한맛에서는 \\\"예\\\"일 때만 이 캐릭터가 임신 판정의 대상이 됩니다. 하드코어는 책대로 원함과 상관없이 판정합니다. 고르기 전에는 아니오입니다.</div>'\r\nb[#b + 1] = K.btnRows({ btn(\"예\", \"dnd_pregwant_yes\", false), btn(\"아니오\", \"dnd_pregwant_no\", false) })\r\nend\r\n\r\nif K.AR and K.AR.on() and (type(sh.picks) ~= \"table\" or sh.picks.position == nil) then\r\nb[#b + 1] = '<div class=\"dnd-opt-t\">포지션</div><div class=\"dnd-opt-d\">삽입: 넣기만 하고 받지 않습니다. 수용: 받기만 하고 넣지 않습니다. 고르기 전에는 상관없음입니다.</div>'\r\nb[#b + 1] = K.btnRows({ btn(\"삽입\", \"dnd_position_top\", false), btn(\"수용\", \"dnd_position_bottom\", false), btn(\"상관없음\", \"dnd_position_any\", false) })\r\nend\r\nfor _, row in ipairs(Feat.pending(sh, pc)) do\r\nb[#b + 1] = '<div class=\"dnd-opt-t\">' .. esc(Feat.TITLE[row.key] or row.key) .. (row.need > 1 and string.format(\" · %d개 남음\", row.need) or \"\") .. '</div>'\r\nif Feat.WHAT[row.key] then b[#b + 1] = '<div class=\"dnd-opt-d\">' .. esc(Feat.WHAT[row.key]) .. '</div>' end\r\nlocal picks = {}\r\nlocal more = row.key == \"mastery\" and getChatVar(id, \"dnd_mastery_more\") == \"1\"\r\nfor i, o in ipairs(row.opts) do\r\nlocal label = Feat.label(row.key, o)\r\nif row.key == \"mastery\" then label = koName(o) .. \" · \" .. (Feat.KO.mastery[WEAPONS[o].mastery] or WEAPONS[o].mastery) end\r\nif row.key == \"mastery\" and i == row.owned + 1 then\r\npicks[#picks + 1] = btn(more and \"다른 무기 접기 ▴\" or \"다른 무기 보기 ▾\", \"dnd_mastery_more\", more)\r\nend\r\nif row.key ~= \"mastery\" or i <= row.owned or more then\r\npicks[#picks + 1] = btn(label, \"dnd_pick_\" .. row.key .. \"_\" .. o:gsub(\"'\", \"_Q_\"):gsub(\" \", \"_\"), false)\r\nend\r\nend\r\nb[#b + 1] = K.btnRows(picks)\r\nlocal o = {}\r\nif row.key == \"keen\" or row.key == \"skilled\" or row.key == \"xskill\" or row.key == \"mcskill\" then\r\nfor _, v in ipairs(row.opts) do if SKILL_TIP[v] then o[#o + 1] = '<b>' .. esc(koName(v)) .. '</b> ' .. esc(SKILL_TIP[v]) end end\r\nelseif row.key == \"mastery\" then\r\n\r\nlocal seen = {}\r\nfor i, v in ipairs(row.opts) do\r\nlocal m = WEAPONS[v].mastery\r\nif (i <= row.owned or more) and not seen[m] then\r\nseen[m] = true\r\no[#o + 1] = '<b>' .. esc(Feat.KO.mastery[m] or m) .. '</b> ' .. esc(Feat.TIP.mastery[m] or m)\r\nend\r\nend\r\nelseif Feat.TIP[row.key] then\r\nfor _, v in ipairs(row.opts) do\r\nif Feat.TIP[row.key][v] then\r\no[#o + 1] = '<div style=\"margin:0 0 8px\"><b>' .. esc(Feat.label(row.key, v)) .. '</b><br>' .. K.Cg.lines(Feat.TIP[row.key][v]) .. '</div>'\r\nend\r\nend\r\nend\r\nif #o > 0 then b[#b + 1] = fold .. table.concat(o, o[1]:sub(1, 4) == \"<div\" and \"\" or \"<br>\") .. '</div></details>' end\r\nend\r\n\r\nfor _, row in ipairs(K.histOver(sh)) do\r\nb[#b + 1] = '<div class=\"dnd-opt-t\">' .. esc(Feat.TITLE[row.key] or row.key) .. string.format(\" · %d개 빼기</div>\", row.need)\r\nb[#b + 1] = '<div class=\"dnd-opt-d\">지금 성적 이력에 맞지 않습니다(이력이 주는 수가 줄었거나 이력이 고를 수 없는 것). 누르면 하나씩 빠집니다.</div>'\r\nlocal picks = {}\r\nfor _, o in ipairs(row.opts) do picks[#picks + 1] = btn(Feat.label(row.key, o) .. \" 빼기\", \"dnd_pick_\" .. row.key .. \"_DROP_\" .. o:gsub(\"'\", \"_Q_\"):gsub(\" \", \"_\"), false) end\r\nb[#b + 1] = K.btnRows(picks)\r\nend\r\nif sh.asi_pending then\r\nlocal left = tonumber(sh.asi_pending) or 1\r\nb[#b + 1] = '<div class=\"dnd-opt-t\">능력치 점수 상승' .. (left > 1 and (\" (\" .. left .. \"번 남음)\") or \"\")\r\n.. ' · 하나에 +2, 또는 둘에 +1씩 (최대 20)</div>'\r\nlocal picks = {}\r\nfor _, a in ipairs(ABILS) do\r\nif SCORE[a] < 20 then\r\npicks[#picks + 1] = btn(string.format(\"%s %d→%d\", koName(a), SCORE[a], math.min(20, SCORE[a] + 2)), \"dnd_asi_\" .. a, false)\r\nend\r\nend\r\n\r\nb[#b + 1] = K.btnRows(picks) .. K.halfRow(id, \"dnd_asi_h\") .. K.asiFeatFold(sh, \"dnd_asi_\")\r\nend\r\nif Feat.miOpen(sh) then\r\nb[#b + 1] = '<div class=\"dnd-opt-t\">마법 입문자 · ' .. esc(koName(Feat.miList(sh))) .. ' 목록의 소마법 둘과 1레벨 주문 하나</div>'\r\nb[#b + 1] = '<div class=\"dnd-opt-d\">GM에게 \"마법 입문자 주문 정하자\"라고 말을 걸면 함께 고릅니다. 고르기 전에는 이 주문들을 쓸 수 없습니다.</div>'\r\nend\r\nif sh.hp_pending then\r\nlocal avg = math.floor(cl.hit_die / 2) + 1\r\nif #K.mcList(sh) > 0 then\r\nb[#b + 1] = string.format('<div class=\"dnd-opt-t\">2~%d레벨 생명력 · 평균 또는 굴리기(레벨마다 그 레벨 클래스의 생명력 주사위)</div>', K.charLevel(sh))\r\nb[#b + 1] = '<div class=\"dnd-opt-btns\">' .. btn(\"평균으로 확정\", \"dnd_hpfix_avg\", false) .. btn(\"굴리기\", \"dnd_hpfix_roll\", false) .. '</div>'\r\nelse\r\nb[#b + 1] = string.format('<div class=\"dnd-opt-t\">2~%d레벨 생명력 · 평균(레벨마다 %d) 또는 굴리기(레벨마다 1d%d)</div>', sh.level, avg, cl.hit_die)\r\nb[#b + 1] = '<div class=\"dnd-opt-btns\">' .. btn(\"평균으로 확정\", \"dnd_hpfix_avg\", false) .. btn(string.format(\"1d%d 굴리기\", cl.hit_die), \"dnd_hpfix_roll\", false) .. '</div>'\r\nend\r\nb[#b + 1] = '<div class=\"dnd-opt-d\">고르기 전에는 평균값입니다. 굴리면 되돌릴 수 없습니다.</div>'\r\nend\r\nreturn table.concat(b)\r\nend\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\nlocal function sheetPane(id, sh)\r\nlocal pc = loadPC(id)\r\nlocal cl = CLASSES[sh.class]\r\nlocal scl = CLASSES[K.castCl(sh) or \"\"] or {}\r\nlocal b = {}\r\nlocal chips = { koName(sh.species) }\r\n\r\nlocal multi = #K.mcList(sh) > 0\r\nfor _, c in ipairs(K.classes(sh)) do\r\nlocal ccl = CLASSES[c.name]\r\nchips[#chips + 1] = koName(c.name) .. (multi and (\" \" .. c.level) or \"\")\r\nif ccl.subclass and c.level >= ccl.subclass.level then chips[#chips + 1] = koName(K.subOf(sh, c.name) or ccl.subclass.name) end\r\nend\r\nchips[#chips + 1] = koName(sh.background)\r\nfor i, c in ipairs(chips) do chips[i] = '<span class=\"dnd-cc\">' .. esc(c) .. '</span>' end\r\n\r\n\r\n\r\nb[#b + 1] = '<div class=\"dnd-hero\"><div class=\"dnd-face lg\">✦<span class=\"dnd-face-p\" style=\"background-image:url(\\'{{source::user}}\\')\"></span><b class=\"dnd-lvb\">'\r\n.. K.charLevel(sh) .. '</b></div>'\r\n.. '<div class=\"dnd-hero-t\"><div class=\"dnd-name\">{{user}}</div><div class=\"dnd-uc\">' .. table.concat(chips) .. '</div></div></div>'\r\n\r\nb[#b + 1] = string.format('<div class=\"dnd-vit\"><div><small>생명력</small><b>%d/%d</b></div><div><small>방어도</small><b>%d</b></div>'\r\n.. '<div><small>속도</small><b>%d</b></div><div><small>숙련</small><b>+%d</b></div></div>', pc.hp, pc.max, pcStats(pc).ac, pcStats(pc).speed or PC.speed, PROF)\r\nlocal cells = {}\r\nfor _, a in ipairs(ABILS) do\r\ncells[#cells + 1] = string.format('<div class=\"dnd-ab%s\"><span>%s</span><b>%d</b><i>%+d</i></div>',\r\nSAVE_PROF[a] and \" sv\" or \"\", esc(koName(a)), SCORE[a], MOD[a])\r\nend\r\nb[#b + 1] = '<div class=\"dnd-abil\">' .. table.concat(cells) .. '</div>'\r\n\r\nlocal subl = { string.format(\"<b>숙련 +%d</b> · 숙련된 기술·무기·내성 굴림에 이 값을 더합니다. 5레벨에 +3, 9레벨에 +4, 13레벨에 +5, 17레벨에 +6으로 오릅니다.\", PROF) }\r\n\r\nlocal keepCur = Cond.cur\r\nCond.cur = pc\r\nlocal sst = scl.spell_ability and Spell.stats(nil, K.castCl(sh))\r\nCond.cur = keepCur\r\nif sst then\r\nlocal dc, atk = sst.dc, sst.atk\r\nsubl[#subl + 1] = string.format(\"<b>주문 내성 난이도 %d</b> · 적이 내 주문을 버티려면 내성 굴림이 %d 이상 나와야 합니다.\", dc, dc)\r\nsubl[#subl + 1] = string.format(\"<b>주문 명중 %+d</b> · 명중 굴림을 하는 주문은 d20 %+d%s 상대 방어도 이상이면 맞습니다.\", atk, atk, K.josa(tostring(atk), \"이\", \"가\"))\r\nend\r\nsubl[#subl + 1] = string.format(\"<b>금테 칸</b> · 그 능력치로 하는 내성 굴림(해로운 효과를 버티는 d20 굴림)에 숙련 보너스 +%d%s 붙습니다.\",\r\nPROF, K.josa(tostring(PROF), \"이\", \"가\"))\r\nb[#b + 1] = '<div class=\"dnd-subl\">' .. table.concat(subl, \"<br>\") .. '</div>'\r\n\r\nlocal party = K.partyFx(pc, sh)\r\nif party.aura > 0 then\r\nb[#b + 1] = '<div class=\"dnd-subl\">' .. tipSpan(NAMES_KO[party.auraBy] or party.auraBy, K.FX[party.auraBy] and K.FX[party.auraBy].tip or \"\")\r\n.. string.format(\" · 모든 내성 굴림 +%d</div>\", party.aura)\r\nend\r\nlocal nextXP = K.xpNext(pc, sh.class)\r\nif nextXP then\r\nb[#b + 1] = string.format('<div class=\"dnd-xpl dnd-xp\"><div><span>경험치 <b>%d / %d</b></span><span>%s</span></div>'\r\n.. '<div class=\"dnd-bar\"><div class=\"dnd-fill\" style=\"width:%d%%\"></div></div></div>', pc.xp, nextXP,\r\npc.xp >= nextXP and \"레벨 업을 할 수 있습니다\" or string.format(\"다음 레벨까지 %d\", nextXP - pc.xp), pct(pc.xp, nextXP))\r\nelse\r\nb[#b + 1] = string.format('<div class=\"dnd-xpl\"><div><span>경험치 <b>%d</b></span><span>최고 레벨(%d)입니다</span></div></div>', pc.xp, K.charLevel(sh))\r\nend\r\nif sh.held then\r\nb[#b + 1] = string.format('<div class=\"dnd-opt-d\">%d레벨은 지금 꺼져 있는 데이터 팩(모듈)이 더한 레벨입니다. 그 모듈을 다시 켤 때까지 %d레벨 능력으로 진행합니다.</div>',\r\nsh.held, sh.level)\r\nend\r\nb[#b + 1] = K.resetRow(id, sh, pc)\r\nb[#b + 1] = K.CharCode.row(id, sh, pc)\r\nif sh.default then\r\nb[#b + 1] = '<div class=\"dnd-opt-d\">기본 테스트 캐릭터입니다. 입력창에 GM: 캐릭터 만들자 라고 GM에게 말을 걸면 함께 만들 수 있습니다.'\r\n.. ' 아래 양식을 채워 보내면 바로 만들어집니다.</div>' .. K.Form.refHtml()\r\nend\r\n\r\n\r\nlocal open = {}\r\nlocal _, expLeft = expertiseChoices(sh)\r\nlocal npick = (expLeft > 0 and 1 or 0) + #Feat.pending(sh, pc) + (sh.asi_pending and (tonumber(sh.asi_pending) or 1) or 0) + (sh.hp_pending and 1 or 0)\r\n+ (Feat.miOpen(sh) and 1 or 0) + #K.histOver(sh)\r\nopen[#open + 1] = K.pickRows(id, sh, pc)\r\nlocal pk = Feat.picks(sh)\r\nlocal rollHp = getChatVar(id, \"dnd_hp_roll\") == \"1\"\r\nif nextXP and pc.xp >= nextXP then\r\n\r\nlocal lcls = K.lvClass(id, sh)\r\nlocal die, nextLv, total = CLASSES[lcls].hit_die, K.cl(sh, lcls) + 1, K.charLevel(sh) + 1\r\nlocal multi = lcls ~= sh.class or #K.mcList(sh) > 0\r\nlocal where = multi and string.format(\"%s %d레벨, 캐릭터 %d레벨\", koName(lcls), nextLv, total) or nil\r\nlocal hpNote = rollHp and string.format(\"생명력은 1d%d를 굴려 오릅니다.\", die)\r\nor string.format(\"생명력은 평균값(%d)으로 오릅니다.\", math.floor(die / 2) + 1)\r\nif not K.LITE then open[#open + 1] = K.lvClassRow(id, sh, lcls) end\r\nif K.AR and K.AR.on() then open[#open + 1] = K.lvHistRow(id, sh, pc) end\r\nopen[#open + 1] = '<div class=\"dnd-opt-t\">레벨 업 생명력</div><div class=\"dnd-opt-btns\">'\r\n.. btn(string.format(\"평균 +%d\", math.floor(die / 2) + 1), \"dnd_hpmode_avg\", not rollHp)\r\n.. btn(string.format(\"굴리기 1d%d\", die), \"dnd_hpmode_roll\", rollHp) .. '</div>'\r\nif K.asiLevel(lcls, nextLv) then\r\n\r\nopen[#open + 1] = string.format('<div class=\"dnd-opt-t\">%s 능력치 점수 상승 · 하나에 +2, 또는 둘에 +1씩 (최대 20)</div>',\r\nmulti and (koName(lcls) .. \" \" .. nextLv .. \"레벨\") or (total .. \"레벨\"))\r\nlocal picks = {}\r\nfor _, a in ipairs(ABILS) do\r\nif SCORE[a] < 20 then\r\npicks[#picks + 1] = btn(string.format(\"%s %d→%d\", koName(a), SCORE[a], math.min(20, SCORE[a] + 2)), \"dnd_levelup_\" .. a, false)\r\nend\r\nend\r\n\r\n\r\nopen[#open + 1] = '<div class=\"dnd-opt-btns dnd-dbg-btns\">' .. table.concat(picks) .. '</div>' .. K.halfRow(id, \"dnd_levelup_h\")\r\n.. K.asiFeatFold(sh, \"dnd_levelup_\", total)\r\nopen[#open + 1] = '<div class=\"dnd-opt-d\">' .. (where and (\"고르면 바로 레벨이 오릅니다(\" .. where .. \"). \") or string.format(\"고르면 바로 %d레벨이 됩니다. \", total))\r\n.. hpNote .. ' 전투 중에는 할 수 없습니다.</div>'\r\nelse\r\nopen[#open + 1] = '<div class=\"dnd-opt-btns\">' .. btn(where and (\"레벨 업 (\" .. where .. \")\") or string.format(\"레벨 업 (%d레벨로)\", total), \"dnd_levelup\", true) .. '</div>'\r\nopen[#open + 1] = '<div class=\"dnd-opt-d\">' .. hpNote .. ' 전투 중에는 할 수 없습니다.</div>'\r\nend\r\nend\r\nlocal openHtml = table.concat(open)\r\nif npick > 0 then b[#b + 1] = string.format('<div class=\"dnd-todo\">고를 것이 %d개 남았습니다</div>', npick) end\r\nif openHtml ~= \"\" then b[#b + 1] = '<div class=\"dnd-open\">' .. openHtml .. '</div>' end\r\n\r\n\r\nlocal function fold(title, count, body)\r\nreturn '<details class=\"dnd-sect\"><summary>' .. title .. (count and ('<i>' .. count .. '</i>') or \"\") .. '</summary><div class=\"dnd-sect-b\">' .. body .. '</div></details>'\r\nend\r\nlocal sk = {}\r\nfor _, k in ipairs(K.profSkills(sh)) do\r\nlocal label = string.format(\"%s %+d%s\", koName(k), bonusFor(k), EXPERT[k] and \"★\" or \"\")\r\nsk[#sk + 1] = SKILL_TIP[k] and tipSpan(label, SKILL_TIP[k]) or esc(label)\r\nend\r\n\r\nlocal tl = {}\r\nfor n in pairs(K.toolProfs(sh)) do tl[#tl + 1] = n end\r\ntable.sort(tl)\r\nfor _, n in ipairs(tl) do\r\nlocal t = K.TOOLS[n]\r\nsk[#sk + 1] = tipSpan(string.format(\"%s %+d\", t.ko, bonusFor(n)),\r\nt.ko .. \" · 도구\\n\" .. koName(t.ab) .. \" 판정에 숙련 보너스를 더합니다. 함께 쓰는 기술에도 숙련이면 이점.\\n쓰기: \" .. (t.util_ko or \"\"))\r\nend\r\nb[#b + 1] = fold(#tl > 0 and \"기술·도구\" or \"기술\", #sk, table.concat(sk, \" · \"))\r\nb[#b + 1] = fold(\"클래스 기능\", #Feat.levelFeatures(sh), K.canDo(sh))\r\nlocal cviews = K.casterViews(sh)\r\nif #cviews > 1 then\r\n\r\nlocal sl = {}\r\nfor l = 1, 9 do\r\nlocal r = PC.res[\"Spell Slot \" .. l]\r\nif r then sl[#sl + 1] = string.format(\"%d레벨 %d/%d\", l, tonumber((pc.res or {})[\"Spell Slot \" .. l]) or 0, r.max) end\r\nend\r\nfor l = 1, 9 do\r\nlocal r = PC.res[\"Pact Slot \" .. l]\r\nif r then sl[#sl + 1] = string.format(\"계약 %d레벨 %d/%d\", l, tonumber((pc.res or {})[\"Pact Slot \" .. l]) or 0, r.max) end\r\nend\r\nlocal sp = { '<div>슬롯: ' .. esc(#sl > 0 and table.concat(sl, \" · \") or \"없음\") .. '</div>' }\r\nfor _, v in ipairs(cviews) do\r\nlocal ab = CLASSES[v.class].spell_ability\r\nsp[#sp + 1] = '<div><b>' .. esc(koName(v.class)) .. '</b> · ' .. esc(string.format(\"%s 기반 · 주문 내성 난이도 %d · 주문 명중 %+d\", koName(ab),\r\n8 + PROF + MOD[ab], PROF + MOD[ab])) .. '</div>'\r\nif #(v.cantrips or {}) > 0 or #(v.spells or {}) > 0 then\r\nfor _, r in ipairs(K.spellRows(v, pc, true)) do sp[#sp + 1] = '<div>' .. r .. '</div>' end\r\nif K.isBook(v.class) and type(v.book) == \"table\" and #v.book > 0 then\r\nlocal room = Spell.bookRoom(sh)\r\nsp[#sp + 1] = '<div>주문책: ' .. spellSpans(v.book) .. (room > 0 and string.format(' · 빈 자리 %d (GM에게 \"주문책에 더할 주문 정하자\")', room) or \"\") .. '</div>'\r\nend\r\nelse\r\nsp[#sp + 1] = '<div>아직 ' .. esc(koName(v.class)) .. ' 주문을 고르지 않았습니다. GM에게 \"주문 정하자\"라고 말을 걸면 함께 고릅니다.</div>'\r\nend\r\nend\r\nb[#b + 1] = fold(\"주문\", nil, table.concat(sp) .. K.extraSpellLines(sh))\r\nelseif scl.spell_ability then\r\nlocal sp = { '<div>' .. esc(string.format(\"%s 기반 · 주문 내성 난이도 %d · 주문 명중 %+d%s\", koName(scl.spell_ability), 8 + PROF + MOD[scl.spell_ability],\r\nPROF + MOD[scl.spell_ability], K.pactText(sh, pc))) .. '</div>' }\r\nif ((sh.cantrips and #sh.cantrips > 0) or (sh.spells and #sh.spells > 0)) then\r\nfor _, r in ipairs(K.spellRows(sh, pc)) do sp[#sp + 1] = '<div>' .. r .. '</div>' end\r\nif K.isBook(K.castCl(sh)) and type(sh.book) == \"table\" and #sh.book > 0 then\r\nlocal room = Spell.bookRoom(sh)\r\nsp[#sp + 1] = '<div>주문책: ' .. spellSpans(sh.book) .. (room > 0 and string.format(' · 빈 자리 %d (GM에게 \"주문책에 더할 주문 정하자\")', room) or \"\") .. '</div>'\r\nend\r\nelse\r\nsp[#sp + 1] = '<div>아직 주문을 고르지 않았습니다. GM에게 \"주문 정하자\"라고 말을 걸면 함께 고릅니다.</div>'\r\nend\r\nb[#b + 1] = fold(\"주문\", nil, table.concat(sp) .. K.extraSpellLines(sh))\r\nelseif K.Card.hasSpells(sh) then\r\nb[#b + 1] = fold(\"주문\", nil, K.extraSpellLines(sh))\r\nend\r\nlocal made = {}\r\n\r\nlocal function undoBtn(key)\r\nif not (pc.making and not (K.curC and K.curC.active) and K.undoKey(sh, key)) then return \"\" end\r\nreturn \" \" .. btn(\"다시 고르기\", \"dnd_pick_\" .. key .. \"_UNDO\", false)\r\nend\r\nfor _, key in ipairs({ \"style\", \"xstyle\", \"order\", \"primal\", \"land\", \"prey\", \"dragon\", \"lineage\", \"gnome\", \"giant\", \"legacy\", \"spellab\", \"keen\", \"feat\", \"milist\",\r\n\"blessed\", \"fury\", \"affinity\", \"resilience\", \"boon\", \"boonab\", \"sexhist\", \"inhib\" }) do\r\nif type(pk[key]) == \"string\" then\r\nlocal tip = (Feat.TIP[key] and Feat.TIP[key][pk[key]]) or (key == \"keen\" and SKILL_TIP[pk[key]])\r\nlocal label = Feat.label(key, pk[key])\r\nmade[#made + 1] = esc(Feat.TITLE[key]:gsub(\" · .*$\", \"\") .. \": \") .. (tip and tipSpan(label, tip) or esc(label)) .. undoBtn(key)\r\nif key == \"sexhist\" then made[#made] = made[#made] .. K.histSpans(sh) end\r\n\r\nif key == \"resilience\" then\r\nmade[#made] = made[#made] .. \" \" .. (Feat.resilienceFree(sh, pc) and btn(\"다시 고르기\", \"dnd_pick_resilience_RESET\", false)\r\nor '<span class=\"dnd-m\">(휴식 뒤에 다시 고를 수 있습니다)</span>')\r\nend\r\nend\r\nend\r\nfor _, key in ipairs({ \"xskill\", \"mcskill\", \"metamagic\", \"invocations\", \"mastone\", \"masttwo\", \"sig\", \"imptools\", \"fetish\", \"fetishon\" }) do\r\nif type(pk[key]) == \"table\" and #pk[key] > 0 and Feat.TITLE[key] then\r\nlocal o = {}\r\nfor _, k in ipairs(pk[key]) do\r\nlocal tip = (Feat.TIP[key] and type(Feat.TIP[key]) == \"table\" and Feat.TIP[key][k]) or ((key == \"xskill\" or key == \"mcskill\") and SKILL_TIP[k])\r\no[#o + 1] = tip and tipSpan(Feat.label(key, k), tip) or esc(Feat.label(key, k))\r\nend\r\nmade[#made + 1] = esc(Feat.TITLE[key] .. \": \") .. table.concat(o, \", \") .. undoBtn(key)\r\n\r\nif key == \"mastone\" or key == \"masttwo\" then\r\nmade[#made] = made[#made] .. \" \" .. (Feat.smFree(sh, pc) and btn(\"다시 고르기\", \"dnd_pick_\" .. key .. \"_RESET\", false)\r\nor '<span class=\"dnd-m\">(긴 휴식 뒤에 하나를 바꿀 수 있습니다)</span>')\r\nend\r\nif key == \"fetishon\" then\r\nmade[#made] = made[#made] .. \" \" .. (Feat.fetishFree(sh, pc) and btn(\"다시 고르기\", \"dnd_pick_fetishon_RESET\", false)\r\nor '<span class=\"dnd-m\">(긴 휴식 뒤에 다시 고를 수 있습니다)</span>')\r\nend\r\nend\r\nend\r\nif type(pk.skilled) == \"table\" and #pk.skilled > 0 then\r\nlocal o = {}\r\nfor _, k in ipairs(pk.skilled) do o[#o + 1] = SKILL_TIP[k] and tipSpan(koName(k), SKILL_TIP[k]) or esc(koName(k)) end\r\nmade[#made + 1] = esc(\"숙련자: \") .. table.concat(o, \", \") .. undoBtn(\"skilled\")\r\nend\r\nif type(pk.mastery) == \"table\" and #pk.mastery > 0 then\r\nlocal o = {}\r\nfor _, w in ipairs(pk.mastery) do\r\nlocal m = WEAPONS[w].mastery\r\no[#o + 1] = tipSpan(koName(w) .. \"(\" .. (Feat.KO.mastery[m] or m) .. \")\", Feat.TIP.mastery[m] or m)\r\nend\r\nmade[#made + 1] = esc(\"무기 통달: \") .. table.concat(o, \", \") .. \" \"\r\n.. (Feat.masteryFree(sh, pc) and btn(\"다시 고르기\", \"dnd_pick_mastery_RESET\", false)\r\nor '<span class=\"dnd-m\">(긴 휴식 뒤에 다시 고를 수 있습니다)</span>')\r\nend\r\nlocal feats = {}\r\nfor _, f in ipairs(Feat.list(sh)) do\r\n\r\n\r\nlocal fr = type(K.FX[f]) == \"table\" and K.FX[f] or nil\r\nlocal tip = Feat.TIP.feat[f] or (fr and K.fillTip((K.LITE and fr.lite) or fr.tip, sh, f))\r\nlocal fko = Feat.KO.feat[f] or NAMES_KO[f] or (fr and fr.ko) or f\r\nfeats[#feats + 1] = tip and tipSpan(fko, tip) or esc(fko)\r\nend\r\nif #feats > 0 then made[#made + 1] = esc(\"재주: \") .. table.concat(feats, \", \") end\r\n\r\n\r\nlocal shownKey = { style = 1, xstyle = 1, order = 1, primal = 1, land = 1, prey = 1, dragon = 1, lineage = 1, gnome = 1, giant = 1, legacy = 1, spellab = 1,\r\nkeen = 1, feat = 1, milist = 1, blessed = 1, fury = 1, affinity = 1, resilience = 1, boon = 1, boonab = 1, sexhist = 1, inhib = 1 }\r\nfor _, c in ipairs(K.classes(sh)) do\r\nlocal sk = K.subKey(c.name)\r\nif type(pk[sk]) == \"string\" then\r\nlocal srec = K.subRec(c.name, pk[sk]) or {}\r\nlocal label = NAMES_KO[pk[sk]] or srec.ko or pk[sk]\r\nmade[#made + 1] = esc(\"하위 클래스 · \" .. koName(c.name) .. \": \") .. (srec.tip and tipSpan(label, srec.tip) or esc(label))\r\nshownKey[sk] = 1\r\nend\r\nend\r\nlocal seenKey = {}\r\nfor _, e in ipairs(Feat.fxOf(sh, \"choice\")) do\r\nlocal v = e.key and pk[e.key]\r\nif type(v) == \"string\" and not shownKey[e.key] and not seenKey[e.key] then\r\nseenKey[e.key] = true\r\nlocal title = NAMES_KO[e.src or \"\"] or (K.FX[e.src or \"\"] and K.FX[e.src].ko) or e.src or e.key\r\nlocal label = Feat.label(e.key, v)\r\nlocal tip = (K.FX[v] and K.FX[v].tip) or (Feat.TIP[e.key] and type(Feat.TIP[e.key]) == \"table\" and Feat.TIP[e.key][v])\r\nmade[#made + 1] = esc(title .. \": \") .. (tip and tipSpan(label, tip) or esc(label)) .. undoBtn(e.key)\r\nend\r\nend\r\nif K.AR and K.AR.on() and K.POS_KO[pk.position or \"\"] then\r\nlocal o = {}\r\nfor _, v in ipairs({ \"top\", \"bottom\", \"any\" }) do if v ~= pk.position then o[#o + 1] = btn(K.POS_TO[v], \"dnd_position_\" .. v, false) end end\r\nmade[#made + 1] = esc(\"포지션: \") .. tipSpan(K.POS_KO[pk.position], K.POS_TIP[pk.position]) .. \" \" .. table.concat(o, \" \")\r\nend\r\nif K.PG and K.PG.on() and type(pk.pregwant) == \"string\" then\r\nlocal w = pk.pregwant == \"yes\"\r\nmade[#made + 1] = esc(\"임신 원함: \") .. tipSpan(w and \"예\" or \"아니오\", \"순한맛에서는 \\\"예\\\"일 때만 이 캐릭터가 임신 판정의 대상이 됩니다. 하드코어는 책대로 원함과 상관없이 판정합니다.\") .. \" \"\r\n.. btn(w and \"아니오로\" or \"예로\", w and \"dnd_pregwant_no\" or \"dnd_pregwant_yes\", false)\r\nend\r\nif #made > 0 then b[#b + 1] = fold(\"고른 것\", nil, table.concat(made, \"<br>\")) end\r\n\r\nlocal arHtml = K.AR and K.AR.on() and K.AR.tabHtml and K.AR.tabHtml(pc, sh, tipSpan)\r\nif arHtml then b[#b + 1] = fold(\"흥분도\", nil, arHtml) end\r\n\r\nlocal _, packH = gearText(pc, K.itemWrap)\r\nb[#b + 1] = fold(\"배낭\", nil, '<div>' .. packH .. '</div>' .. K.otherGearHtml(sh))\r\nb[#b + 1] = '<div class=\"dnd-opt-d\" style=\"margin-top:8px\">점선 글자를 누르면 설명이 뜹니다.</div>'\r\nreturn table.concat(b)\r\nend\r\n\r\n\r\n\r\n\r\n\r\nlocal DEBUG_OPS = {\r\ndnd_dbg_hp_full = function(st) st.pc.hp = st.pc.max; st.pc.dead = false; st.pc.stable = false; st.pc.ds = { s = 0, f = 0 } end,\r\ndnd_dbg_hp_half = function(st) st.pc.hp = math.max(1, math.floor(st.pc.max / 2)); st.pc.dead = false end,\r\ndnd_dbg_hp_zero = function(st) st.pc.hp = 0; st.pc.dead = false; st.pc.stable = K.DEATH == \"gentle\"; st.pc.ds = { s = 0, f = 0 } end,\r\ndnd_dbg_hd_full = function(st) st.pc.hd = tonumber(st.pc.level) or st.pc.hd end,\r\ndnd_dbg_xp = function(st)\r\nlocal nx = K.xpNext(st.pc)\r\nif nx and st.pc.xp < nx then st.pc.xp = nx end\r\nend,\r\ndnd_dbg_t1h = function(st) st.clock.min = st.clock.min + 60 end,\r\ndnd_dbg_t8h = function(st) st.clock.min = st.clock.min + 480 end,\r\ndnd_dbg_t1d = function(st) st.clock.min = st.clock.min + 1440 end,\r\ndnd_dbg_end = function(st) st.combat.active = false end,\r\n\r\ndnd_dbg_ally = function(st)\r\nif st.combat.active or Ally.size(st.pc) - 1 >= Ally.MAX then return false end\r\nst.pc.allies = Ally.list(st.pc)\r\nfor _, x in ipairs({ { \"브란\", \"Fighter\" }, { \"세라\", \"Cleric\" }, { \"오윈\", \"Wizard\" } }) do\r\nif not Ally.find(st.pc, x[1]) then\r\nst.pc.allies[#st.pc.allies + 1] = Ally.build(x[1], \"Human\", x[2], \"디버그로 넣은 동료\", st.pc.level)\r\nreturn\r\nend\r\nend\r\nend,\r\ndnd_dbg_ally_clear = function(st)\r\nif st.combat.active then return false end\r\nst.pc.allies = {}\r\nend,\r\n}\r\n\r\n\r\nlocal function redrawStatus(id, pc, clock)\r\nlocal li = K.replyIdx(id)\r\nif li < 0 then return end\r\nlocal last = getChat(id, li)\r\nif last and last.role == \"char\" and last.data then\r\nlocal line = statusLine(pc, clock)\r\nlocal out = last.data:gsub(\"%[STATUS|[^%]]*%]\", function() return line end)\r\nif out ~= last.data then setChat(id, li, out) end\r\nend\r\nend\r\n\r\nlocal function debugAction(id, data)\r\nsetChatVar(id, \"dnd_debug_used\", \"1\")\r\nK.DEATH = Feat.deathRule(id)\r\nif data == \"dnd_dbg_d20_20\" or data == \"dnd_dbg_d20_1\" then\r\nsetChatVar(id, \"dnd_dbg_d20\", data == \"dnd_dbg_d20_20\" and \"20\" or \"1\")\r\nreturn\r\nend\r\nlocal sh = loadSheet(id)\r\napplySheet(sh)\r\nlocal live = liveSnap(id, sh)\r\nlocal op\r\nlocal ai, dir = data:match(\"^dnd_dbg_alv_(%d+)_(%a+)$\")\r\nlocal abw = data:match(\"^dnd_dbg_abw_(%d+)$\")\r\nlocal abI, abN, abD = data:match(\"^dnd_dbg_ab_(%d+)_(%a+)_([mp]%d)$\")\r\nif abw then\r\nsetChatVar(id, \"dnd_dbg_abwho\", abw)\r\nreturn\r\nelseif abI then\r\n\r\nif not SCORE[abN] then return end\r\nlocal d = (abD:sub(1, 1) == \"p\" and 1 or -1) * tonumber(abD:sub(2))\r\nabI = tonumber(abI)\r\nif abI == 0 then\r\nlocal cls = sh.class\r\nop = function(st)\r\nif type(st.sheet) ~= \"table\" or st.sheet.class ~= cls then return false end\r\nst.sheet.scores[abN] = math.max(1, math.min(30, (tonumber(st.sheet.scores[abN]) or 10) + d))\r\nrefitHp(st.sheet, st.pc)\r\napplySheet(st.sheet); Feat.fillRes(st.pc)\r\nend\r\nop(live)\r\nsetState(id, \"dnd_sheet\", live.sheet)\r\napplySheet(sh)\r\nelse\r\nop = function(st)\r\nlocal a = Ally.list(st.pc)[abI]\r\nif not a or a.dead then return end\r\nAlly.dbgScore(a, abN, d)\r\nend\r\nop(live)\r\nend\r\nelseif ai then\r\n\r\nif live.combat.active then return end\r\nai = tonumber(ai)\r\nop = function(st)\r\nlocal a = Ally.list(st.pc)[ai]\r\nif not a or a.dead then return end\r\nlocal off = math.floor(tonumber(a.lvOff) or 0) + (dir == \"up\" and 1 or -1)\r\na.lvOff = math.max(-Ally.LV_SPREAD, math.min(Ally.LV_SPREAD, off))\r\nlocal lv = Ally.levelFor(st.pc, a)\r\n\r\na.lvOff = lv - (tonumber(st.pc.level) or 1)\r\nif K.charLevel(a.sheet) ~= lv then Ally.setLevel(a, lv) end\r\nend\r\nop(live)\r\nelseif data == \"dnd_dbg_fight\" then\r\nif live.combat.active then return end\r\nstartCombat({ \"Goblin Warrior\", \"Goblin Warrior\" }, live.combat, live.pc)\r\nlocal fight = deepCopy(live.combat)\r\nop = function(s) s.combat = deepCopy(fight) end\r\nelseif DEBUG_OPS[data] then\r\nop = DEBUG_OPS[data]\r\nop(live)\r\nelse\r\nreturn\r\nend\r\nsetState(id, \"dnd_pc\", live.pc)\r\nsetState(id, \"dnd_clock\", live.clock)\r\nsetState(id, \"dnd_combat\", live.combat)\r\nsyncBases(id, op)\r\nredrawStatus(id, live.pc, live.clock)\r\nend\r\n\r\nlocal function debugPane(id)\r\nlocal pc, clock, c = loadPC(id), loadClock(id), loadCombat(id)\r\nlocal b = {}\r\nlocal function group(title, btns)\r\nb[#b + 1] = '<div class=\"dnd-opt-t\">' .. title .. '</div><div class=\"dnd-opt-btns dnd-dbg-btns\">' .. table.concat(btns) .. '</div>'\r\nend\r\nlocal function block(title, lines, cls)\r\nb[#b + 1] = '<div class=\"dnd-opt-t\">' .. title .. '</div><div class=\"' .. (cls or \"dnd-opt-d\") .. '\">'\r\n\r\n.. (esc(table.concat(lines, \"\\n\")):gsub(\"{\", \"&#123;\"):gsub(\"%[\", \"&#91;\"):gsub(\"\\n\", \"<br>\")) .. '</div>'\r\nend\r\nb[#b + 1] = '<div class=\"dnd-opt-d\">테스트용입니다. 바꾼 값은 다음 답변부터 반영되고, 마지막 답변을 리롤해도 유지됩니다.</div>'\r\ngroup(\"생명력\", { btn(\"가득\", \"dnd_dbg_hp_full\"), btn(\"절반\", \"dnd_dbg_hp_half\"), btn(\"0\", \"dnd_dbg_hp_zero\"), btn(\"생명력 주사위 채우기\", \"dnd_dbg_hd_full\") })\r\nlocal nx = K.xpNext(pc)\r\nif nx then group(\"경험치\", { btn(string.format(\"%d로 (레벨 업 버튼)\", nx), \"dnd_dbg_xp\") }) end\r\ngroup(\"시간\", { btn(\"+1시간\", \"dnd_dbg_t1h\"), btn(\"+8시간\", \"dnd_dbg_t8h\"), btn(\"+1일\", \"dnd_dbg_t1d\") })\r\ngroup(\"전투\", { btn(\"고블린 전사 둘\", \"dnd_dbg_fight\", c.active), btn(\"전투 끝\", \"dnd_dbg_end\") })\r\ngroup(\"동료 (\" .. (Ally.size(pc) - 1) .. \"/\" .. Ally.MAX .. \")\", { btn(\"한 명 넣기\", \"dnd_dbg_ally\"), btn(\"모두 내보내기\", \"dnd_dbg_ally_clear\") })\r\n\r\nfor i, a in ipairs(Ally.list(pc)) do\r\nif not a.dead then\r\nlocal off = math.floor(tonumber(a.lvOff) or 0)\r\ngroup(string.format(\"%s 레벨 %d (%s)\", esc(a.name), a.level or pc.level,\r\noff == 0 and \"당신과 같음\" or string.format(\"당신 %+d\", off)),\r\n{ btn(\"−1\", \"dnd_dbg_alv_\" .. i .. \"_dn\"), btn(\"+1\", \"dnd_dbg_alv_\" .. i .. \"_up\") })\r\nend\r\nend\r\n\r\n\r\nlocal whoI = math.floor(tonumber(getChatVar(id, \"dnd_dbg_abwho\")) or 0)\r\nlocal live = Ally.list(pc)\r\nif whoI > 0 and not (live[whoI] and not live[whoI].dead) then whoI = 0 end\r\nlocal wb = { btn(\"당신\", \"dnd_dbg_abw_0\", whoI == 0) }\r\nfor i, a in ipairs(live) do if not a.dead then wb[#wb + 1] = btn(esc(a.name), \"dnd_dbg_abw_\" .. i, whoI == i) end end\r\ngroup(\"능력치 고치기\", wb)\r\nlocal base = whoI == 0 and loadSheet(id).scores or live[whoI].sheet.scores\r\nfor _, ab in ipairs(ABILS) do\r\nlocal v = tonumber(base[ab]) or 10\r\nlocal key = \"dnd_dbg_ab_\" .. whoI .. \"_\" .. ab .. \"_\"\r\ngroup(string.format(\"%s %d (%+d)\", koName(ab), v, abilityMod(v)),\r\n{ btn(\"−5\", key .. \"m5\"), btn(\"−1\", key .. \"m1\"), btn(\"+1\", key .. \"p1\"), btn(\"+5\", key .. \"p5\") })\r\nend\r\nb[#b + 1] = '<div class=\"dnd-opt-d\">1부터 30까지, 만들 때와 능력치 상승의 상한(20)과 상관없이 바꿉니다. 바탕 점수이고, 재주·물건이 더하는 것은 그 위에 붙습니다.'\r\n.. ' 건강을 바꾸면 최대 생명력도 같이 바뀝니다. 동료는 레벨이 내려가 다시 만들어져도 바꾼 만큼이 남습니다.</div>'\r\nlocal forced = getChatVar(id, \"dnd_dbg_d20\")\r\ngroup(\"다음 답변의 첫 d20\", { btn(\"20\", \"dnd_dbg_d20_20\", forced == \"20\"), btn(\"1\", \"dnd_dbg_d20_1\", forced == \"1\") })\r\n\r\nlocal state = {\r\n\"생명력 \" .. pcHpText(pc) .. \" · \" .. pc.level .. \"레벨 · 경험치 \" .. pc.xp,\r\nclockKo(clock.min) .. \" (\" .. clockEn(clock.min) .. \")\",\r\ngetChatVar(id, \"dnd_debug_used\") == \"1\" and \"이 채팅은 디버그를 썼습니다\" or \"디버그 안 씀\",\r\n}\r\nstate[#state + 1] = string.format(\"Lua 처리 시간: 요청 %sms · 답변 검증 %sms (os.clock, 0이면 측정 불가)\",\r\ngetChatVar(id, \"dnd_perf_req\"), getChatVar(id, \"dnd_perf_out\"))\r\n\r\nstate[#state + 1] = string.format(\"버튼: %s · 화면 엔진 팩 읽기 %sms(%s), 마지막 합치기 %sms\", tostring(getChatVar(id, \"dnd_perf_btn\") or \"-\"),\r\ntostring(K.PACK.readMs or \"-\"), K.PACK.fromCache and \"캐시\" or \"로어북\", tostring(K.PACK.mergeMs or \"-\"))\r\n\r\nlocal packs = {}\r\nfor _, x in ipairs(K.PACK.list or {}) do\r\npacks[#packs + 1] = x.name .. (x.ok and \"\" or (\" (읽기 실패: \" .. tostring(x.err) .. \")\"))\r\n.. ((x.notes and #x.notes > 0) and (\" (\" .. table.concat(x.notes, \"; \") .. \")\") or \"\")\r\nend\r\nstate[#state + 1] = \"데이터 팩(모듈): \" .. (#packs > 0 and table.concat(packs, \", \") or \"없음\")\r\n\r\nlocal jms, jkb, jn = tostring(getChatVar(id, \"dnd_perf_json\") or \"\"):match(\"^(%d+)|(%d+)|(%d+)$\")\r\nif jms then\r\nstate[#state + 1] = string.format(\"요청 JSON 왕복(추정): %sms · 크기 %sKB · 메시지 %s개 (보낼 때마다 RisuAI가 요청 전체를 Lua에 넘기고 돌려받는 시간, 위 '요청'에 안 들어감)\",\r\njms, jkb, jn)\r\nend\r\nif K.PERF then\r\nstate[#state + 1] = string.format(\"최신 메시지 화면 그리기: 지난번 %.0fms · 가장 길었던 %.0fms\", K.PERF.last or 0, K.PERF.max or 0)\r\nlocal bm = K.PERF.bmax\r\nif bm then\r\nstate[#state + 1] = string.format(\"한 번에 다시 그린 메시지(같은 1초 안): 가장 컸던 묶음 %d개 · Lua 합계 %.0fms (보내면 마지막 5개를 다시 그림)\", bm.n, bm.ms)\r\nend\r\nend\r\nblock(\"지금 상태\", state)\r\nif #c.order > 0 then\r\nlocal u = { (c.active and \"전투 중\" or \"끝난 전투\") .. \" · 마지막 행동: \" .. ((c.last or \"\") ~= \"\" and c.last or \"-\") }\r\nfor _, name in ipairs(c.order) do\r\nlocal x = c.units[name] or {}\r\nlocal al = x.side == \"ally\" and Ally.find(pc, x.ally)\r\nu[#u + 1] = string.format(\"%s (우선권 %s) %s\", name, tostring(x.init or \"?\"),\r\nx.side == \"pc\" and pcHpText(pc) or al and Ally.hpText(al) or (tostring(x.hp) .. \"/\" .. tostring(x.max)))\r\nend\r\nblock(\"전투\", u)\r\nend\r\nlocal pools = getState(id, \"dnd_pool\")\r\nif type(pools) == \"table\" then\r\nlocal pl = {}\r\nfor _, k in ipairs(K.POOL_ORDER) do\r\nif type(pools[k]) == \"table\" then pl[#pl + 1] = k .. \": \" .. table.concat(pools[k], \", \") end\r\nend\r\nblock(\"지난 답변의 주사위 풀\", pl)\r\nend\r\nlocal verify = getChatVar(id, \"dnd_last_verify\")\r\nlocal v = { \"Lua 검증: \" .. ((verify == \"null\" or not verify) and \"-\" or verify) }\r\nlocal bads = getState(id, \"dnd_last_bad\")\r\nif type(bads) == \"table\" then\r\nfor _, line in ipairs(bads) do v[#v + 1] = \"✕ \" .. line end\r\nend\r\nlocal err = getChatVar(id, \"dnd_lua_error\")\r\nif err and err ~= \"\" and err ~= \"null\" then v[#v + 1] = \"Lua 오류: \" .. err end\r\nblock(\"마지막 검증\", v)\r\nlocal log = getState(id, \"dnd_bad_log\")\r\nif type(log) == \"table\" and #log > 0 then\r\nlocal l = {}\r\nfor i = #log, 1, -1 do\r\nlocal e = log[i]\r\nif type(e) == \"table\" then l[#l + 1] = string.format(\"%s턴 · %s\", tostring(e[1]), tostring(e[2])) end\r\nend\r\nblock(\"최근 거절된 태그 (최근 \" .. K.BAD_LOG_MAX .. \"건, 새것부터)\", l)\r\nend\r\n\r\nlocal formOn = getChatVar(id, \"dnd_form_ui\") == \"on\"\r\ngroup(\"주문 칸 폼 화면 (시험, 리스 2026.10.210 이상)\", { btn(\"켜기\", \"dnd_dbg_form_on\", formOn), btn(\"끄기\", \"dnd_dbg_form_off\", not formOn) })\r\n\r\n\r\nlocal req = getState(id, \"dnd_last_req\")\r\nif type(req) == \"string\" then\r\nif getChatVar(id, \"dnd_dbg_req\") == \"1\" then\r\ngroup(\"지난 요청에 Lua가 넣은 내용\", { btn(\"접기\", \"dnd_dbg_req_off\") })\r\nblock(\"\", { req }, \"dnd-pre\")\r\nelse\r\ngroup(\"지난 요청에 Lua가 넣은 내용 (\" .. (utf8.len(req) or #req) .. \"자)\", { btn(\"펼치기\", \"dnd_dbg_req_on\") })\r\nend\r\nend\r\nreturn table.concat(b)\r\nend\r\n\r\n\r\n\r\nif K.LITE then\r\nlocal function tip(k, s) if FEATURE_KO[k] then FEATURE_KO[k][2] = s end end\r\ntip(\"Spellcasting\", \"준비한 주문을 ⟨MP으로⟩ 시전합니다 (아래 레벨마다 비용, 6레벨 이상은 레벨마다 하루 한 번). 명중·내성·피해·회복은 Lua가 확인합니다.\")\r\ntip(\"Second Wind\", \"추가 행동으로 1d10 + 파이터 레벨만큼 회복합니다. 기력 2.\")\r\ntip(\"Action Surge\", \"내 턴에 행동을 한 번 더 합니다 (마법 행동 제외). 기력 5.\")\r\ntip(\"Rage\", \"추가 행동으로 들어갑니다 (중갑 X). 근력 공격 피해 +2(9레벨 +3, 16레벨 +4), 타격·관통·참격 피해 저항, 근력 판정·내성 이점, 주문 불가. 전투가 끝나면 Lua가 끕니다. 기력 3.\")\r\ntip(\"Monk's Focus\", \"기 점수 1점에 기력 1. 연타(추가 행동 맨손 두 번), 인내의 방어(추가 행동 이탈 + 회피), 바람 걸음(추가 행동 이탈 + 질주).\")\r\ntip(\"Focus Points\", \"기를 쓰는 기능(연타·인내의 방어·바람 걸음·충격의 일격)에 1점씩, 1점에 기력 1.\")\r\ntip(\"Channel Divinity\", \"신성력 3으로 신성한 불꽃(치유나 피해), 언데드 퇴치(5레벨부터 언데드 태우기 피해), 생명 보존(생명 권역) 가운데 하나를 일으킵니다.\"\r\n.. \" 무엇을 하는지는 아래 ▼ 기능의 '할 수 있는 것'에 하나씩 있습니다.\")\r\ntip(\"Bardic Inspiration\", \"추가 행동으로 60피트 안의 다른 사람에게 고양감 주사위(d6, 5레벨 d8, 10레벨 d10, 15레벨 d12)를 줍니다. 받은 사람은 1시간 안에 d20을 실패하면 그 주사위를 더합니다. 마나 2.\")\r\ntip(\"Font of Inspiration\", \"고양감은 마나로 씁니다. 이 기능의 몫은 마나 총량에 들어 있습니다.\")\r\ntip(\"Wild Shape\", \"추가 행동으로 본 적 있는 짐승으로 변합니다 (2레벨: 도전 지수 1/4 이하, 비행 속도 없는 것 · 4레벨: 1/2 이하 · 8레벨: 1 이하, 비행 속도도). 짐승의 방어도·속도·공격을 쓰고, 생명력은 그대로에 임시 생명력 = 드루이드 레벨. 변신 중엔 주문 불가. 마나 3.\")\r\ntip(\"Wild Companion\", \"마나나 야생 변신 1회로 패밀리어 찾기를 시전합니다 (요정 형태).\")\r\ntip(\"Innate Sorcery\", \"추가 행동으로 1분 동안 소서러 주문 내성 난이도 +1, 소서러 주문 명중에 이점. 마나 3. 여기서는 전투가 끝나면 Lua가 끕니다.\")\r\ntip(\"Font of Magic\", \"술법 점수는 마나로 씁니다 (1점에 마나 1).\")\r\ntip(\"Sorcery Points\", \"마법변형에 쓰는 점수. 1점에 마나 1.\")\r\ntip(\"Lay On Hands\", \"추가 행동으로 닿은 사람을 원하는 만큼 회복합니다. 5점마다 신성력 1 (5점으로 중독 해제).\")\r\ntip(\"Pact Magic\", \"주문을 마나로 시전합니다. 가진 가장 높은 레벨까지 원하는 레벨로 씁니다.\")\r\ntip(\"Favored Enemy\", \"사냥꾼의 표식을 늘 준비해 둡니다 (1레벨 비용, 기력 2).\")\r\ntip(\"Paladin's Smite\", \"신성한 강타를 늘 준비해 둡니다 (1레벨 비용, 신성력 2).\")\r\nfor _, k in ipairs({ \"Arcane Recovery\", \"Magical Cunning\", \"Sorcerous Restoration\", \"Uncanny Metabolism\" }) do\r\ntip(k, \"이 판에는 짧은 휴식이 없어서, 이 기능의 몫은 ⟨MP⟩ 총량에 들어 있습니다.\")\r\nend\r\ntip(\"Wild Resurgence\", \"야생 변신과 주문이 같은 마나를 써서, 이 판에서는 따로 하는 일이 없습니다.\")\r\ntip(\"Memorize Spell\", \"이 판에는 짧은 휴식이 없어서, 준비한 주문은 긴 휴식 뒤에만 바꿉니다.\")\r\ntip(\"Paladin|Channel Divinity\", \"신성력 3으로 신성 감지, 무기 축성(헌신의 맹세), 적 물리치기(9레벨) 가운데 하나를 일으킵니다. 무엇을 하는지는 아래 ▼ 기능의\"\r\n.. \" '할 수 있는 것'에 하나씩 있습니다.\")\r\n\r\nlocal function fx(k, s) if K.FX[k] then K.FX[k].tip = s end end\r\nfx(\"Archdruid\", \"10년에 1살씩만 늙습니다. 야생 변신이 마나를 써서, 이 판에서는 되찾기와 바꾸기가 없습니다.\")\r\nfx(\"Eldritch Master\", \"이 판에는 마법적 교활함이 없어서 따로 하는 일이 없습니다.\")\r\nfx(\"Natural Recovery\", \"준비한 대지 주문 하나는 긴 휴식마다 한 번 마나 없이.\")\r\nfx(\"Persistent Rage\", \"격노가 10분 동안 그대로 이어집니다.\")\r\nfx(\"Superior Inspiration\", \"고양감이 마나를 써서, 이 판에서는 따로 하는 일이 없습니다.\")\r\nfx(\"Perfect Focus\", \"기가 기력을 써서, 이 판에서는 따로 하는 일이 없습니다.\")\r\nfx(\"Tireless\", \"마법 행동으로 1d8 + 지혜 수정치만큼 임시 생명력. 기력 2.\")\r\nend\r\nlocal RES_TIP = { [\"생명력 주사위\"] = \"짧은 휴식 때 굴려서 생명력을 회복합니다. 긴 휴식이면 모두 다시 찹니다.\" }\r\nfor k, v in pairs(FEATURE_KO) do if not k:find(\"|\", 1, true) then RES_TIP[v[1]] = v[2] end end\r\n\r\nK.RES_TIP_CLASS = {}\r\nfor k, v in pairs(FEATURE_KO) do\r\nlocal cl = k:match(\"^(%a+)|\")\r\nif cl then K.RES_TIP_CLASS[cl .. \"|\" .. v[1]] = v[2] end\r\nend\r\nif K.LITE then\r\nfor _, w in ipairs({ \"마나\", \"기력\", \"신성력\" }) do\r\nRES_TIP[w] = \"주문과 클래스 기능에 함께 쓰는 힘. 긴 휴식에 다 차고, 전투 밖에서 쉬면 GM이 조금 돌려줍니다. 주문은 레벨 1~9에 2·3·5·6·7·9·10·11·13, 6레벨 이상은 레벨마다 하루 한 번.\"\r\nend\r\nend\r\n\r\nRES_TIP[NAMES_KO[\"Heroic Inspiration\"] or \"영웅적 영감\"] = \"d20을 굴린 직후 다시 굴리고, 새 값을 씁니다. 긴 휴식에 다시 찹니다.\"\r\n\r\n\r\nfor k, rec in pairs(K.FX) do\r\nlocal label = NAMES_KO[k] or k\r\nif type(rec.tip) == \"string\" and rec.tip ~= \"\" and not RES_TIP[label] then RES_TIP[label] = rec.tip end\r\nend\r\n\r\nfor k, tip in pairs({\r\n[\"Breath Weapon\"] = \"공격 행동의 공격 하나 대신 15피트 원뿔이나 30피트 선에 숨결: 민첩 내성(난이도 8 + 건강 + 숙련 보너스), 1d10 (5레벨 2d10, 11레벨 3d10, 17레벨 4d10) 피해, 성공 시 절반. 숙련 보너스만큼, 긴 휴식에 다시 찹니다.\",\r\n[\"Giant Ancestry\"] = \"골리앗 거인 혈통의 힘을 쓰는 횟수 (언덕: 넘어뜨리기, 바위: 피해 줄이기, 서리·화염·폭풍·구름: 피해나 이동). 긴 휴식에 다시 찹니다.\",\r\n[\"Adrenaline Rush\"] = \"추가 행동으로 질주하고 숙련 보너스만큼 임시 생명력. 짧은 휴식이나 긴 휴식에 다시 찹니다.\",\r\n[\"Relentless Endurance\"] = \"생명력이 0이 될 때 한 번 1로 버팁니다. 긴 휴식에 다시 찹니다.\",\r\n[\"Magic Initiate\"] = \"마법 입문자로 배운 1레벨 주문을 슬롯 없이 한 번. 긴 휴식에 다시 찹니다.\",\r\n}) do RES_TIP[NAMES_KO[k] or k] = tip end\r\n\r\nlocal function resSpans(res)\r\nlocal out = {}\r\nfor seg in ((res or \"\") .. \" · \"):gmatch(\"(.-) · \") do\r\nlocal name, cnt = seg:match(\"^(.-)%s+(%d+/%d+)$\")\r\nlocal ctip\r\nfor _, c in ipairs((name and SHEET) and K.classes(SHEET) or {}) do ctip = ctip or K.RES_TIP_CLASS[c.name .. \"|\" .. name] end\r\nlocal tip = name and (ctip or RES_TIP[name] or RES_TIP[(name:gsub(\" %(%d레벨%)$\", \"\"))])\r\nif name and not tip and name:match(\" %(무료%)$\") then\r\ntip = \"이 주문을 슬롯 없이 시전하는 횟수입니다. 긴 휴식에 다시 찹니다.\"\r\nend\r\nif name and name:match(\"^%d레벨 슬롯$\") then\r\ntip = \"그 레벨의 주문을 쓸 때 하나씩 씁니다 (더 높은 슬롯으로 올려 쓸 수도 있습니다). 긴 휴식으로 다시 찹니다.\"\r\nend\r\n\r\nlocal mi = SHEET and type(SHEET.mi) == \"table\" and SHEET.mi.spell\r\nif name and mi and name == koName(\"Magic Initiate\") then\r\ntip = \"마법 입문자 주문(\" .. koName(mi) .. \")을 쓰면 슬롯 대신 이 1회가 먼저 쓰입니다. 따로 말할 필요는 없습니다. 긴 휴식에 다시 찹니다.\"\r\n.. ((SPELLS[mi] and SPELLS[mi].ritual) and \" 의식 주문이라 전투 밖에서 의식으로 쓰면(10분 더 걸림) 이 1회도 아낍니다.\" or \"\")\r\nend\r\nout[#out + 1] = tip and (tipSpan(name, tip) .. \" \" .. esc(cnt)) or esc(seg)\r\nend\r\nreturn table.concat(out, \" · \")\r\nend\r\n\r\n\r\n\r\n\r\n\r\nfunction Ally.unloaded(a)\r\nlocal sh = type(a) == \"table\" and type(a.sheet) == \"table\" and a.sheet or {}\r\nreturn not CLASSES[sh.class or \"\"] or (sh.species ~= nil and sh.species ~= \"\" and not SPECIES[sh.species])\r\nend\r\n\r\nfunction Ally.statusRow(pc)\r\nlocal list = Ally.list(pc)\r\nif #list == 0 then return \"\" end\r\nlocal out = {}\r\nfor _, a in ipairs(list) do\r\nlocal tip = Ally.with(a, function()\r\nlocal res = {}\r\nfor k, r in pairs(PC.res) do\r\nif K.MP.shown(k) then res[#res + 1] = string.format(\"%s %d/%d\", koName(k), a.res[k] or 0, r.max) end\r\nend\r\ntable.sort(res)\r\nreturn string.format(\"%s %s · 방어도 %d%s%s\", koName(a.sheet.species), #K.mcList(a.sheet) > 0 and K.mcText(a.sheet, koName)\r\nor (koName(a.sheet.class) .. \" \" .. a.level .. \"레벨\"), pcStats(a).ac,\r\n#res > 0 and (\"\\n\" .. table.concat(res, \" · \")) or \"\", (a.note or \"\") ~= \"\" and (\"\\n\" .. a.note) or \"\")\r\nend)\r\nout[#out + 1] = tipSpan(a.name, tip) .. \" \" .. esc(Ally.hpText(a))\r\nend\r\nreturn '<div class=\"dnd-sec\"><span class=\"dnd-l\">동료</span>' .. table.concat(out, \" · \") .. '</div>'\r\nend\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\nK.Card = {}\r\n\r\nfunction K.Card.pips(cur, max)\r\ncur, max = math.max(0, tonumber(cur) or 0), tonumber(max) or 0\r\nif max <= 0 then return \"\" end\r\nif max > 8 then return ' <span class=\"dnd-pipn\">' .. cur .. \"/\" .. max .. '</span>' end\r\nlocal o = {}\r\nfor i = 1, max do o[#o + 1] = i <= cur and '<i class=\"dnd-pip\"></i>' or '<i class=\"dnd-pip used\"></i>' end\r\nreturn '<span class=\"dnd-pips\">' .. table.concat(o) .. '</span>'\r\nend\r\n\r\nfunction K.Card.bar(cur, max, foe, thp)\r\nlocal p = pct(math.max(0, tonumber(cur) or 0), tonumber(max) or 0)\r\nlocal sh = K.Card.shield(cur, max, thp, \"span\")\r\nreturn '<span class=\"dnd-hb' .. (foe and \" foe\" or (p <= 40 and \" low\" or \"\")) .. '\"' .. (sh ~= \"\" and ' style=\"position:relative\"' or \"\")\r\n.. '><span style=\"width:' .. p .. '%\"></span>' .. sh .. '</span>'\r\nend\r\n\r\n\r\nfunction K.Card.shield(cur, max, thp, tag)\r\nthp, max = tonumber(thp) or 0, tonumber(max) or 0\r\nif thp <= 0 or max <= 0 then return \"\" end\r\nlocal p = pct(math.max(0, tonumber(cur) or 0), max)\r\nlocal s = math.max(3, pct(math.min(thp, max), max))\r\nlocal left = (p + s <= 100) and p or math.max(0, 100 - s)\r\nreturn '<' .. tag .. ' style=\"position:absolute;top:0;bottom:0;height:100%;left:' .. left .. '%;width:' .. s .. '%;border-radius:999px;'\r\n.. 'background:linear-gradient(90deg,#d9a93a,#f6dc8a);box-shadow:inset 0 0 0 1px rgba(255,255,255,.35)\"></' .. tag .. '>'\r\nend\r\n\r\nfunction K.Card.chip(text, kind, tip)\r\nreturn '<span class=\"dnd-cc' .. (kind and (\" \" .. kind) or \"\") .. '\">' .. (tip and tipSpan(text, tip) or esc(text)) .. '</span>'\r\nend\r\n\r\n\r\nfunction K.Card.initial(name)\r\nreturn tostring(name or \"?\"):match(\"^[%z\\1-\\127\\194-\\244][\\128-\\191]*\") or \"?\"\r\nend\r\n\r\n\r\n\r\n\r\nfunction K.Card.arRow(r, pc, onlyIfAny)\r\nif not (K.AR and K.AR.on() and type(r) == \"table\") then return \"\" end\r\nlocal st, mx = K.AR.st(r), K.AR.max(r, pc)\r\nlocal cur = tonumber(st.cur) or 0\r\nif onlyIfAny and cur <= 0 then return \"\" end\r\nlocal edge = type(st.edge) == \"table\" and \" · 임계\" or \"\"\r\nreturn '<small style=\"text-align:right;opacity:.75;font-size:11px\">흥분도' .. edge .. '</small><span class=\"dnd-hb\"><span style=\"width:' .. pct(cur, mx) .. '%;' .. K.AR_FILL .. '\"></span></span>'\r\n.. '<span class=\"dnd-num\">' .. cur .. \"/\" .. mx .. '</span>'\r\nend\r\nfunction K.Card.unit(o)\r\nlocal d = tonumber(o.delta)\r\nlocal dl = (d and d ~= 0) and string.format('<span class=\"dnd-dl%s\">%+d</span>', d > 0 and \" up\" or \"\", d) or \"\"\r\nreturn '<div class=\"dnd-unit' .. (o.dim and \" dim\" or \"\") .. '\"><div class=\"dnd-who\"><b>' .. esc(o.name) .. '</b>'\r\n.. ((o.sub or \"\") ~= \"\" and ('<small>' .. esc(o.sub) .. '</small>') or \"\") .. '</div>'\r\n.. K.Card.bar(o.hp, o.max, o.foe, o.thp) .. '<span class=\"dnd-num\">' .. dl .. esc(o.hpText or ((o.hp or 0) .. \"/\" .. (o.max or 0))) .. '</span>'\r\n.. (o.ar or \"\")\r\n.. (o.kit or \"\") .. ((o.chips or \"\") ~= \"\" and ('<div class=\"dnd-uc\">' .. o.chips .. '</div>') or \"\") .. '</div>'\r\nend\r\n\r\n\r\n\r\nfunction K.Card.buffChips(r)\r\nlocal names = {}\r\nfor name, b in pairs(type(r.buff) == \"table\" and r.buff or {}) do\r\nif type(b) == \"table\" and b.by then names[#names + 1] = name end\r\nend\r\ntable.sort(names)\r\nlocal o = {}\r\nfor _, name in ipairs(names) do\r\nlocal b = r.buff[name]\r\no[#o + 1] = K.Card.chip(koName(name) .. (b.wplus and (\" +\" .. b.wplus) or \"\") .. (b.choice and (\" · \" .. koName(b.choice)) or \"\"), \"conc\")\r\nend\r\nreturn table.concat(o)\r\nend\r\nfunction K.Card.hpChips(r)\r\nlocal o = {}\r\nfor name, b in pairs(type(r.buff) == \"table\" and r.buff or {}) do\r\nif type(b) == \"table\" and tonumber(b.maxhp) then o[#o + 1] = K.Card.chip(koName(name) .. \" 최대 +\" .. b.maxhp) end\r\nend\r\ntable.sort(o)\r\nlocal bc = K.Card.buffChips(r)\r\nif bc ~= \"\" then o[#o + 1] = bc end\r\nif (tonumber(r.thp) or 0) > 0 then o[#o + 1] = K.Card.chip(\"임시 생명력 \" .. r.thp) end\r\nreturn #o > 0 and ('<div style=\"margin-top:3px\">' .. table.concat(o) .. '</div>') or \"\"\r\nend\r\n\r\n\r\n\r\n\r\n\r\nfunction K.castEffectKo(name, lv)\r\nlocal sp = SPELLS[name]\r\nif not sp then return \"\" end\r\nlocal m = sp.m or {}\r\nlocal v = m.hp_bonus or m.temp_hp\r\nif type(v) == \"number\" or (v and m.temp_hp) then\r\nlv = math.max(sp.level, tonumber(lv) or sp.level)\r\nlocal up = type(m.upcast) == \"table\" and (m.upcast.hp_bonus or m.upcast.temp_hp) or 0\r\nlocal extra = up * (lv - sp.level)\r\nlocal amt = type(v) == \"number\" and tostring(v + extra) or (tostring(v) .. (extra > 0 and (\"+\" .. extra) or \"\"))\r\nif m.temp_hp then return \"임시 생명력 \" .. amt end\r\nlocal mins = m.dur_mins or 480\r\nreturn \"최대 생명력과 생명력 +\" .. amt .. \" · \" .. (m.targets or 1) .. \"명까지 · \"\r\n.. (mins >= 1440 and (math.floor(mins / 1440) .. \"일\") or (math.floor(mins / 60) .. \"시간\"))\r\nend\r\nreturn sp.ko or \"\"\r\nend\r\n\r\nfunction K.Card.recChips(r)\r\nlocal o = {}\r\nif r.dead then\r\no[#o + 1] = K.Card.chip(\"사망\", \"bad\")\r\nelseif (tonumber(r.hp) or 0) <= 0 then\r\nlocal ds = type(r.ds) == \"table\" and r.ds or {}\r\no[#o + 1] = K.Card.chip(r.stable and \"쓰러짐 · 안정\" or string.format(\"쓰러짐 · 성공 %d · 실패 %d\", ds.s or 0, ds.f or 0), \"bad\")\r\nend\r\nfor _, n in ipairs(Cond.active(r)) do o[#o + 1] = K.Card.chip(koName(n), \"bad\", K.condTip(koName(n))) end\r\nif (tonumber(r.exh) or 0) > 0 then o[#o + 1] = K.Card.chip(koName(\"Exhaustion\") .. \" \" .. r.exh, \"bad\", K.condTip(koName(\"Exhaustion\"))) end\r\nif (tonumber(r.ordeal) or 0) > 0 then o[#o + 1] = K.Card.chip(\"부활의 시련 -\" .. r.ordeal, \"bad\") end\r\nif r.taxed then o[#o + 1] = K.Card.chip(\"부활의 대가 · 주문 불가\", \"bad\") end\r\nif type(r.conc) == \"table\" and r.conc.name then o[#o + 1] = K.Card.chip(\"집중 · \" .. koName(r.conc.name), \"conc\") end\r\n\r\nlocal bn = {}\r\nfor name, b in pairs(type(r.buff) == \"table\" and r.buff or {}) do\r\nif type(b) == \"table\" and tonumber(b.maxhp) then bn[#bn + 1] = name end\r\nend\r\ntable.sort(bn)\r\nfor _, name in ipairs(bn) do o[#o + 1] = K.Card.chip(koName(name) .. \" 최대 +\" .. r.buff[name].maxhp) end\r\no[#o + 1] = K.Card.buffChips(r)\r\nif (tonumber(r.thp) or 0) > 0 then o[#o + 1] = K.Card.chip(\"임시 생명력 \" .. r.thp) end\r\nreturn table.concat(o)\r\nend\r\n\r\n\r\n\r\n\r\nfunction K.Card.sceneSec(pc)\r\nlocal sc = type(pc) == \"table\" and type(pc.scene) == \"table\" and type(pc.scene.units) == \"table\" and pc.scene.units\r\nif not sc or next(sc) == nil then return \"\" end\r\nlocal names, o = {}, {}\r\nfor n in pairs(sc) do names[#names + 1] = n end\r\ntable.sort(names)\r\nfor _, n in ipairs(names) do\r\nlocal u = sc[n]\r\nlocal ch = K.Card.chip(\"장면\")\r\no[#o + 1] = K.Card.unit({ name = (NAMES_KO[n] or n), hp = u.hp, max = u.max, chips = ch, ar = K.Card.arRow(u, pc) })\r\nend\r\nreturn '<div class=\"dnd-sec\"><span class=\"dnd-l\">장면</span><div class=\"dnd-units\">' .. table.concat(o) .. '</div></div>'\r\nend\r\n\r\n\r\nK.AR_FILL = \"background:linear-gradient(90deg,#8c3a66,#e07aa8)\"\r\nfunction K.Card.arExtra(r, pc)\r\nlocal a = K.AR.st(r)\r\nlocal ov = K.AR.overHard(a, r)\r\nreturn string.format(\"억제 %+d\", K.AR.inhib(r, pc)) .. ((tonumber(a.numb) or 0) > 0 and (\" · 둔감 \" .. a.numb) or \"\") .. (ov > 0 and (\" · 과자극 \" .. ov .. \"/6\") or \"\")\r\nend\r\nfunction K.Card.arLine(pc)\r\nif not (K.AR and K.AR.on() and type(pc) == \"table\") then return \"\" end\r\nlocal a, mx = K.AR.st(pc), K.AR.max(pc, pc)\r\nlocal cur = tonumber(a.cur) or 0\r\nreturn '<div style=\"grid-column:1/-1\"><span class=\"dnd-l\">흥분도</span><span class=\"dnd-v\">' .. cur .. \" / \" .. mx\r\n.. ' <small style=\"opacity:.75\">' .. esc(K.Card.arExtra(pc, pc)) .. '</small></span>'\r\n.. '<div class=\"dnd-bar\"><div class=\"dnd-fill\" style=\"width:' .. pct(cur, mx) .. '%;' .. K.AR_FILL .. '\"></div></div></div>'\r\nend\r\n\r\nfunction K.Card.arAlly(a, pc)\r\nif not (K.AR and K.AR.on() and type(a) == \"table\") then return \"\" end\r\nlocal st, mx = K.AR.st(a), K.AR.max(a, pc)\r\nlocal cur = tonumber(st.cur) or 0\r\nreturn '<div class=\"dnd-hpl\"><span>흥분도 · ' .. esc(K.Card.arExtra(a, pc)) .. '</span><b>' .. cur .. \" / \" .. mx .. '</b></div>'\r\n.. '<span class=\"dnd-hb\"><span style=\"width:' .. pct(cur, mx) .. '%;' .. K.AR_FILL .. '\"></span></span>'\r\nend\r\nfunction K.Card.uses(cur, hd, hdMax)\r\nlocal names = {}\r\nlocal caster = SHEET and K.castCl(SHEET)\r\nfor name in pairs(PC.res) do\r\n\r\nif not name:match(\"^Spell Slot\") and not name:match(\"^Pact Slot\") and not (caster and name:match(\" %(free%)$\")) and K.MP.shown(name) then names[#names + 1] = name end\r\nend\r\ntable.sort(names, function(x, y) return koName(x) < koName(y) end)\r\nlocal o = {}\r\nif hd then\r\n\r\nlocal tip = RES_TIP[\"생명력 주사위\"]\r\nif SHEET and #K.mcList(SHEET) > 0 then\r\nlocal left = {}\r\nfor _, x in ipairs(K.hdLeft(SHEET, hd)) do left[#left + 1] = \"d\" .. x[1] .. \" \" .. x[2] .. \"개\" end\r\ntip = tip .. \"\\n남은 주사위: \" .. (#left > 0 and table.concat(left, \", \") or \"없음\") .. \". 큰 주사위부터 씁니다.\"\r\nend\r\no[#o + 1] = '<span class=\"dnd-use\">' .. tipSpan(\"생명력 주사위\", tip) .. K.Card.pips(hd, hdMax) .. '</span>'\r\nend\r\nfor _, name in ipairs(names) do\r\nlocal label = koName(name)\r\nlocal own\r\nfor _, c in ipairs(SHEET and K.classes(SHEET) or {}) do own = own or FEATURE_KO[c.name .. \"|\" .. name] end\r\nlocal tip = (own and own[2]) or RES_TIP[label] or RES_TIP[koName((name:gsub(\" %(%d%)$\", \"\")))]\r\nor (SHEET and K.featTip(name, nil, K.featSheet(SHEET, name)))\r\nif not tip and name:match(\" %(free%)$\") then tip = \"이 주문을 슬롯 없이 시전하는 횟수입니다. 긴 휴식에 다시 찹니다.\" end\r\n\r\nlocal mi = SHEET and type(SHEET.mi) == \"table\" and SHEET.mi.spell\r\nif name == \"Magic Initiate\" and mi then\r\ntip = \"마법 입문자 주문(\" .. koName(mi) .. \")을 쓰면 슬롯 대신 이 1회가 먼저 쓰입니다. 따로 말할 필요는 없습니다. 긴 휴식에 다시 찹니다.\"\r\n.. ((SPELLS[mi] and SPELLS[mi].ritual) and \" 의식 주문이라 전투 밖에서 의식으로 쓰면(10분 더 걸림) 이 1회도 아낍니다.\" or \"\")\r\nend\r\no[#o + 1] = '<span class=\"dnd-use\">' .. (tip and tipSpan(label, tip) or esc(label)) .. K.Card.pips((cur or {})[name], PC.res[name].max) .. '</span>'\r\nend\r\nreturn table.concat(o)\r\nend\r\n\r\n\r\n\r\nfunction K.Card.longRest(pc, clock)\r\nif not pc.long_end then return \"\" end\r\nlocal wait = K.LONG_WAIT - ((tonumber(clock.min) or 0) - pc.long_end)\r\nlocal tip = \"긴 휴식을 마치고 16시간이 지나야 다음 긴 휴식을 할 수 있습니다.\" .. (K.LITE and \" 그 사이에는 전투 밖에서 쉬면 GM이 생명력과 MP를 조금 돌려줍니다.\" or \" 짧은 휴식은 언제든 됩니다.\")\r\nreturn '<span class=\"dnd-use\">' .. tipSpan(\"긴 휴식\", tip) .. ' ' .. esc(wait > 0 and (math.ceil(wait / 60) .. \"시간 뒤\") or \"가능\") .. '</span>'\r\nend\r\n\r\n\r\n\r\nfunction K.Card.swings(sh)\r\nlocal n = 1\r\nfor _, x in ipairs(Feat.levelFeatures(sh)) do\r\nif x == \"Extra Attack\" then n = math.max(n, 2) elseif x == \"Two Extra Attacks\" then n = math.max(n, 3)\r\nelseif x == \"Three Extra Attacks\" then n = math.max(n, 4) end\r\nend\r\n\r\nfor _, c in ipairs(K.classes(sh)) do n = math.max(n, tonumber(c.row.attacks) or 1) end\r\nreturn n\r\nend\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\nfunction K.Card.extraSpells(sh)\r\nlocal out = {}\r\nfor n, x in pairs(Feat.extras(sh)) do\r\nif SPELLS[n] and not x.only and x.src then out[#out + 1] = { n = n, x = x } end\r\nend\r\ntable.sort(out, function(a, b)\r\nlocal la, lb = SPELLS[a.n].level or 0, SPELLS[b.n].level or 0\r\nif la ~= lb then return la < lb end\r\nreturn a.n < b.n\r\nend)\r\nreturn out\r\nend\r\n\r\n\r\nfunction K.exKey(x)\r\nreturn x.src .. (x.list or x.item or \"\") .. (x.src == \"feature\" and (\"|\" .. tostring(K.exFrom(x) or \"\") .. \"|\" .. tostring(x.ab or \"\")) or \"\")\r\nend\r\nfunction K.exFrom(x) return (type(x.fx) == \"table\" and x.fx.src) or x.free end\r\n\r\nfunction K.extraSpellLines(sh)\r\nlocal groups, gorder = {}, {}\r\nlocal own = {}\r\nfor _, v in ipairs(K.casterViews(sh)) do\r\nfor _, l in ipairs({ v.cantrips or {}, v.spells or {} }) do for _, n in ipairs(l) do own[n] = true end end\r\nend\r\nfor _, e in ipairs(K.Card.extraSpells(sh)) do\r\nif not own[e.n] then\r\nlocal key = K.exKey(e.x)\r\nif not groups[key] then groups[key] = {}; gorder[#gorder + 1] = key end\r\ntable.insert(groups[key], e.n)\r\nend\r\nend\r\nlocal pb = 2 + math.floor((K.charLevel(sh) - 1) / 4)\r\nlocal out = {}\r\nfor _, key in ipairs(gorder) do\r\nlocal x\r\nfor _, e in ipairs(K.Card.extraSpells(sh)) do if K.exKey(e.x) == key then x = e.x break end end\r\nlocal label = x.src == \"mi\" and (\"마법 입문자 · \" .. koName(x.list)) or x.src == \"invocation\" and \"섬뜩한 영창\"\r\nor x.src == \"item\" and (\"전리품 · \" .. koName(x.item)) or (x.src == \"feature\" and K.exFrom(x) and koName(K.exFrom(x)))\r\nor (\"종족 · \" .. koName(sh.species))\r\nlocal mod = abilityMod(tonumber((sh.scores or {})[x.ab]) or 10)\r\nout[#out + 1] = '<div>' .. esc(label) .. ': ' .. spellSpans(groups[key]) .. ' <span class=\"dnd-m\">('\r\n.. esc(string.format(\"%s · 내성 난이도 %d · 명중 %+d\", koName(x.ab), 8 + pb + mod, pb + mod)) .. ')</span></div>'\r\nend\r\nreturn table.concat(out)\r\nend\r\n\r\nfunction K.Card.prepOpt(id, sh, pc, idx)\r\nif not K.castCl(sh) then return {} end\r\nlocal o = { prep = Spell.cardState(id, sh, pc, idx), cant = Spell.cantState(id, sh, pc, idx) }\r\no.form = getChatVar(id, \"dnd_form_ui\") == \"on\"\r\nlocal cs = K.casters(sh)\r\nif #cs > 1 then\r\no.preps, o.cants = {}, {}\r\nfor _, c in ipairs(cs) do o.preps[c] = Spell.cardState(id, sh, pc, idx, c); o.cants[c] = Spell.cantState(id, sh, pc, idx, c) end\r\nend\r\nreturn o\r\nend\r\nfunction K.Card.hasSpells(sh)\r\nreturn K.castCl(sh) ~= nil or #K.Card.extraSpells(sh) > 0\r\nend\r\n\r\nfunction K.Card.spells(sh, rec, opt)\r\nopt = opt or {}\r\nlocal base = sh\r\nsh = K.casterView(sh) or sh\r\nlocal cl = CLASSES[sh.class]\r\nlocal caster = cl and cl.spell_ability\r\nlocal extra = K.Card.extraSpells(sh)\r\nif not caster and #extra == 0 then return \"\" end\r\n\r\n\r\nlocal views = caster and K.casterViews(base) or {}\r\nlocal multi = #views > 1\r\nlocal st = caster and Spell.stats() or nil\r\nlocal seen, ritual, bookOnly = {}, false, false\r\n\r\nlocal function collect(v, tg, always)\r\nlocal byLv, top, mine = {}, 0, {}\r\nlocal function add(n, on, alw)\r\nif mine[n] or not SPELLS[n] then return end\r\nmine[n] = true\r\nseen[n] = true\r\nlocal lv = SPELLS[n].level or 0\r\nbyLv[lv] = byLv[lv] or {}\r\nbyLv[lv][#byLv[lv] + 1] = { n = n, on = on, always = alw }\r\nif lv > top then top = lv end\r\nend\r\nfor _, n in ipairs(v.cantrips or {}) do add(n, true) end\r\nfor _, n in ipairs(v.spells or {}) do add(n, true) end\r\nfor _, n in ipairs(always) do add(n, true, true) end\r\nif not opt.ally and K.isBook(v.class) and type(v.book) == \"table\" then\r\nfor _, n in ipairs(v.book) do add(n, false) end\r\nend\r\n\r\n\r\n\r\nif tg and not K.isBook(v.class) then\r\nfor _, n in ipairs(Spell.prepChoices(v)) do add(n, false) end\r\nend\r\nreturn byLv, top\r\nend\r\n\r\nlocal pact = cl.pact and not K.pactApart(base)\r\nlocal slot, summ, slotTop = {}, {}, 0\r\nfor l = 1, 9 do\r\nlocal r = PC.res[\"Spell Slot \" .. l]\r\nif r then\r\nslot[l] = { cur = tonumber((rec.res or {})[\"Spell Slot \" .. l]) or 0, max = r.max }\r\nif l > slotTop then slotTop = l end\r\nsumm[#summ + 1] = '<span class=\"dnd-sl\">' .. (pact and (\"계약 \" .. l .. \"레벨\") or tostring(l)) .. K.Card.pips(slot[l].cur, r.max) .. '</span>'\r\nend\r\nend\r\nfor l = 1, 9 do\r\nlocal r = PC.res[\"Pact Slot \" .. l]\r\nif r then summ[#summ + 1] = '<span class=\"dnd-sl\">계약 ' .. l .. '레벨' .. K.Card.pips(tonumber((rec.res or {})[\"Pact Slot \" .. l]) or 0, r.max) .. '</span>' end\r\nend\r\n\r\nif K.LITE and PC.res.MP then\r\nsumm = { '<span class=\"dnd-sl\">' .. K.MP.name(sh) .. K.Card.pips(rawget(rec.res or {}, \"MP\"), PC.res.MP.max) .. '</span>' }\r\npact = false\r\nend\r\nlocal free, ownFree = {}, {}\r\nfor _, e in ipairs(extra) do if e.x.free then ownFree[e.x.free] = true end end\r\nfor name, r in pairs(PC.res) do\r\nlocal sp = name:match(\"^(.-) %(free%)$\")\r\nif sp and not ownFree[name] then free[#free + 1] = { sp = sp, cur = (rec.res or {})[name], max = r.max } end\r\nend\r\ntable.sort(free, function(x, y) return x.sp < y.sp end)\r\n\r\nlocal function names(list, tg, cls)\r\nlocal o = {}\r\nfor _, e in ipairs(list) do\r\nlocal rit = SPELLS[e.n].ritual and \"<sup>의식</sup>\" or \"\"\r\nif SPELLS[e.n].ritual then ritual = true end\r\nif not e.on then bookOnly = true end\r\nif tg and (SPELLS[e.n].level or 0) >= 1 and not e.always and opt.form then\r\n\r\no[#o + 1] = '<span style=\"white-space:nowrap\"><label class=\"dnd-sp dnd-fsp\"><input type=\"checkbox\" name=\"f_sp\" value=\"' .. Spell.key(e.n) .. '\"'\r\n.. (e.on and \" checked\" or \"\") .. '>' .. esc(koName(e.n)) .. rit .. '</label>' .. tipSpan(\"ⓘ\", spellTip(e.n)) .. '</span>'\r\nelseif tg and (SPELLS[e.n].level or 0) >= 1 and not e.always then\r\n\r\n\r\no[#o + 1] = '<span style=\"white-space:nowrap\"><span class=\"dnd-sp dnd-tg' .. (e.on and \" on\" or \"\") .. '\">' .. esc(koName(e.n)) .. rit\r\n.. '<span class=\"dnd-hit\">' .. rawBtn(\" \", (cls and (\"dnd_prepc_\" .. cls .. \"_\") or \"dnd_prep_\") .. Spell.key(e.n)) .. '</span></span>'\r\n.. tipSpan(\"ⓘ\", spellTip(e.n)) .. '</span>'\r\nelse\r\nlocal tip = spellTip(e.n) .. (e.always and \"\\n늘 준비된 주문입니다(준비 개수와 따로).\" or \"\")\r\no[#o + 1] = opt.ally and (tipSpan(koName(e.n), tip) .. rit)\r\nor ('<span class=\"dnd-sp' .. (e.on and \" on\" or \"\") .. '\">' .. tipSpan(koName(e.n), tip) .. rit .. '</span>')\r\nend\r\nend\r\nreturn table.concat(o, opt.ally and \" · \" or \"\")\r\nend\r\nlocal cur\r\nlocal function row(k, v) cur[#cur + 1] = '<div class=\"dnd-kr\"><span class=\"dnd-kk\">' .. k .. '</span><span class=\"dnd-kv\">' .. v .. '</span></div>' end\r\n\r\nlocal function levelRows(byLv, top, tg, cls, pips, learn)\r\nlocal pre = (cls and (\"dnd_cantc_\" .. cls .. \"_\")) or \"dnd_cant_\"\r\n\r\nif byLv[0] and learn and learn.undo then\r\nlocal o = {}\r\nlocal mineC = {}\r\nfor _, n in ipairs((K.casterView(base, cls) or {}).cantrips or {}) do mineC[n] = true end\r\nfor _, e in ipairs(byLv[0]) do\r\nif mineC[e.n] and opt.form then\r\no[#o + 1] = '<span style=\"white-space:nowrap\"><label class=\"dnd-sp dnd-fsp\"><input type=\"checkbox\" name=\"f_ct\" value=\"' .. Spell.key(e.n) .. '\" checked>'\r\n.. esc(koName(e.n)) .. '</label>' .. tipSpan(\"ⓘ\", spellTip(e.n)) .. '</span>'\r\nelseif mineC[e.n] then\r\no[#o + 1] = '<span style=\"white-space:nowrap\"><span class=\"dnd-sp dnd-tg on\">' .. esc(koName(e.n))\r\n.. '<span class=\"dnd-hit\">' .. rawBtn(\" \", pre .. Spell.key(e.n)) .. '</span></span>' .. tipSpan(\"ⓘ\", spellTip(e.n)) .. '</span>'\r\nelse\r\no[#o + 1] = '<span class=\"dnd-sp on\">' .. tipSpan(koName(e.n), spellTip(e.n)) .. '</span>'\r\nend\r\nend\r\nrow(\"소마법\", table.concat(o))\r\nelseif byLv[0] then row(\"소마법\", names(byLv[0], tg, cls)) end\r\n\r\nif learn and learn.open > 0 and #learn.list > 0 then\r\nlocal o = {}\r\nfor _, n in ipairs(learn.list) do\r\nif opt.form then\r\no[#o + 1] = '<span style=\"white-space:nowrap\"><label class=\"dnd-sp dnd-fsp\"><input type=\"checkbox\" name=\"f_ct\" value=\"' .. Spell.key(n) .. '\">'\r\n.. esc(koName(n)) .. '</label>' .. tipSpan(\"ⓘ\", spellTip(n)) .. '</span>'\r\nelse\r\no[#o + 1] = '<span style=\"white-space:nowrap\"><span class=\"dnd-sp dnd-tg\">' .. esc(koName(n))\r\n.. '<span class=\"dnd-hit\">' .. rawBtn(\" \", pre .. Spell.key(n)) .. '</span></span>' .. tipSpan(\"ⓘ\", spellTip(n)) .. '</span>'\r\nend\r\nend\r\nrow('소마법 고르기 <span class=\"dnd-pipn\">' .. learn.open .. '칸</span>', table.concat(o))\r\nend\r\nfor l = 1, top do\r\nlocal s = pips and slot[l] or nil\r\nif K.LITE and s and PC.res.MP then\r\nlocal done = l >= 6 and type(rec.hi) == \"table\" and rec.hi[tostring(l)]\r\nrow(l .. \"레벨\" .. ' <span class=\"dnd-pipn\">' .. (done and \"오늘 씀\" or (K.MP.SPELL[l] .. (l >= 6 and \" · 하루 1번\" or \"\"))) .. '</span>',\r\nbyLv[l] and names(byLv[l], tg, cls) or \"-\")\r\nelseif byLv[l] or (s and not pact) then\r\nrow(l .. \"레벨\" .. ((s and not pact) and K.Card.pips(s.cur, s.max) or \"\"), byLv[l] and names(byLv[l], tg, cls) or \"-\")\r\nend\r\nend\r\nend\r\n\r\nlocal function otherRows()\r\nif #free > 0 then\r\nlocal o = {}\r\nfor _, e in ipairs(free) do\r\no[#o + 1] = '<span class=\"dnd-sp on\">' .. tipSpan(koName(e.sp), K.freeTip(e.sp)) .. K.Card.pips(e.cur, e.max) .. '</span>'\r\nend\r\nrow(\"무료\", table.concat(o))\r\nend\r\n\r\nlocal groups, gorder = {}, {}\r\nfor _, e in ipairs(extra) do\r\nif not seen[e.n] then\r\nlocal key = K.exKey(e.x)\r\nif not groups[key] then groups[key] = {}; gorder[#gorder + 1] = key end\r\ntable.insert(groups[key], e)\r\nend\r\nend\r\nlocal pb = 2 + math.floor((K.charLevel(sh) - 1) / 4)\r\nfor _, key in ipairs(gorder) do\r\nlocal g = groups[key]\r\nlocal x = g[1].x\r\n\r\nlocal top, sub = (x.src == \"mi\" and \"마법 입문자\") or (x.src == \"invocation\" and \"섬뜩한 영창\") or (x.src == \"item\" and \"전리품\")\r\nor (x.src == \"feature\" and K.exFrom(x) and koName(K.exFrom(x))) or \"종족\",\r\n(x.src == \"mi\" and koName(x.list)) or (x.src == \"species\" and koName(sh.species)) or (x.src == \"item\" and koName(x.item)) or nil\r\nlocal label = '<span style=\"white-space:normal;display:inline-block;line-height:1.25\">' .. esc(top)\r\n.. (sub and ('<br><small style=\"font-weight:400\">' .. esc(sub) .. '</small>') or \"\") .. '</span>'\r\nlocal o = {}\r\nfor _, e in ipairs(g) do\r\nlocal r = e.x.free and PC.res[e.x.free]\r\nlocal note = e.x.atwill and \"\\n슬롯 없이 늘 쓸 수 있습니다.\"\r\nor e.x.free and (\"\\n슬롯 없이 한 번 쓸 수 있습니다. 긴 휴식에 다시 찹니다.\" .. (caster and \" 가진 슬롯으로도 쓸 수 있습니다.\" or \"\"))\r\nor \"\"\r\nif SPELLS[e.n].ritual then ritual = true end\r\no[#o + 1] = '<span class=\"dnd-sp on\">' .. tipSpan(koName(e.n), spellTip(e.n) .. note) .. (SPELLS[e.n].ritual and \"<sup>의식</sup>\" or \"\")\r\n.. (r and K.Card.pips(tonumber((rec.res or {})[e.x.free]) or 0, r.max) or \"\") .. '</span>'\r\nend\r\nlocal mod = abilityMod(tonumber((sh.scores or {})[x.ab]) or 10)\r\nrow(label, table.concat(o) .. '<div class=\"dnd-dim\" style=\"font-size:11px\">' .. esc(string.format(\"%s · 내성 난이도 %d · 명중 %+d\", koName(x.ab), 8 + pb + mod, pb + mod)) .. '</div>')\r\nend\r\nend\r\n\r\nlocal function formWrap(html, tg, learn, cls)\r\nif not (opt.form and (tg or learn)) then return html end\r\nreturn '<style>.dnd-fsp{cursor:pointer}.dnd-fsp input{margin:0 4px 0 0;accent-color:#d4af5a}'\r\n.. '.dnd-fsp:has(input:checked){border-style:solid;border-color:#8a6d38;color:#f6e7c6;background:rgba(212,175,90,.1)}</style>'\r\n.. '<form risu-form=\"dnd_spells' .. (cls and (\"_\" .. cls) or \"\") .. '\">'\r\n.. (tg and '<input type=\"hidden\" name=\"f_hsp\" value=\"1\">' or \"\") .. (learn and '<input type=\"hidden\" name=\"f_hct\" value=\"1\">' or \"\")\r\n.. html .. '<div style=\"margin-top:6px;text-align:right\"><button type=\"submit\" name=\"f_go\" value=\"save\" class=\"dnd-sp on\" style=\"min-height:26px;padding:0 14px;cursor:pointer\">저장</button></div></form>'\r\nend\r\nlocal function legend(isWiz)\r\nreturn '<span><i class=\"dnd-dot on\"></i>준비함 <i class=\"dnd-dot\"></i>' .. (isWiz and \"책에만\" or \"준비 안 함\") .. '</span>'\r\nend\r\nlocal function window(tg, cls)\r\nreturn '<div class=\"dnd-prep\">' .. esc(Spell.windowKo(tg)) .. '</div>'\r\n.. ((tg.msg ~= \"\" and (not tg.msgCls or tg.msgCls == cls)) and ('<div class=\"dnd-prep bad\">' .. esc(tg.msg) .. '</div>') or \"\")\r\nend\r\nlocal body = {}\r\nlocal anyTg, anyOpen, chosen = false, false, false\r\nlocal anyLearn = false\r\nif multi then\r\nlocal anyWiz = false\r\nfor _, v in ipairs(views) do\r\nlocal tg = not opt.fight and (opt.preps or {})[v.class] or nil\r\nlocal learn = not opt.fight and not opt.ally and (opt.cants or {})[v.class] or nil\r\nbookOnly = false\r\nlocal byLv, top = collect(v, tg, Feat.always(v))\r\nlocal rows = {}\r\ncur = rows\r\nlevelRows(byLv, top, tg, v.class, false, learn)\r\nlocal ab = CLASSES[v.class].spell_ability\r\nlocal innate = Cond.cur and type(Cond.cur.mode) == \"table\" and Cond.cur.mode.name == \"Innate Sorcery\" and v.class == \"Sorcerer\" and 1 or 0\r\nlocal mine = #(v.cantrips or {}) > 0 or #(v.spells or {}) > 0\r\nbody[#body + 1] = '<div class=\"dnd-book-hd\"><b>' .. esc(string.format(\"%s · %s · 내성 난이도 %d · 명중 %+d\", koName(v.class), koName(ab),\r\n8 + PROF + (MOD[ab] or 0) + innate, PROF + (MOD[ab] or 0))) .. '</b>' .. (bookOnly and legend(K.isBook(v.class)) or \"\") .. '</div>'\r\nif tg then body[#body + 1] = window(tg, v.class) end\r\nif learn and not tg and learn.msg ~= \"\" and (not learn.msgCls or learn.msgCls == v.class) then body[#body + 1] = '<div class=\"dnd-prep bad\">' .. esc(learn.msg) .. '</div>' end\r\nif not mine and not opt.ally and not K.noSpellsYet(v, v.class, v.level) then body[#body + 1] = '<div class=\"dnd-dim\">아직 ' .. esc(koName(v.class)) .. ' 주문을 안 골랐습니다. GM에게 \"주문 정하자\"라고 말을 걸면 함께 고릅니다.</div>' end\r\nbody[#body + 1] = table.concat(rows)\r\nif not opt.fight and not opt.ally and mine and not tg then body[#body + 1] = '<div class=\"dnd-book-ft\">' .. esc(Spell.changeRuleKo(v)) .. '</div>' end\r\nif opt.form and (tg or learn) then body[#body - (not opt.fight and not opt.ally and mine and not tg and 1 or 0)] = formWrap(table.concat(rows), tg, learn, v.class) end\r\nchosen = chosen or mine\r\nanyTg = anyTg or tg ~= nil\r\nanyOpen = anyOpen or (tg and tg.open) or (learn and learn.shown) or false\r\nanyLearn = anyLearn or (learn ~= nil and learn.open > 0)\r\nanyWiz = anyWiz or K.isBook(v.class)\r\nend\r\nlocal rows = {}\r\ncur = rows\r\notherRows()\r\nbody[#body + 1] = table.concat(rows)\r\nif ritual then\r\nbody[#body + 1] = '<div class=\"dnd-book-note\"><sup>의식</sup> 표시 주문은 ' .. (anyWiz and \"위저드 주문이면 준비하지 않아도 \" or \"\")\r\n.. '슬롯 없이 의식으로 쓸 수 있습니다(10분 더 걸림, 전투 밖에서).</div>'\r\nend\r\nelse\r\nlocal tg = not opt.ally and not opt.fight and opt.prep or nil\r\nlocal learn = not opt.ally and not opt.fight and opt.cant or nil\r\nlocal byLv, top = collect(sh, tg, Feat.always(base))\r\ntop = math.max(top, slotTop)\r\nlocal rows = {}\r\ncur = rows\r\nlevelRows(byLv, top, tg, nil, true, learn)\r\notherRows()\r\nlocal head = st and string.format(\"내성 난이도 %d · 명중 %+d%s\", st.dc, st.atk, K.pactText(sh, rec)) or \"\"\r\nchosen = not caster or #(sh.cantrips or {}) > 0 or #(sh.spells or {}) > 0 or K.noSpellsYet(sh, sh.class, sh.level)\r\nif opt.ally then\r\nbody[#body + 1] = '<div class=\"dnd-kr\"><span class=\"dnd-kk\"></span><span class=\"dnd-kv dnd-dim\">' .. esc(head) .. '</span></div>'\r\nelseif caster then\r\nbody[#body + 1] = '<div class=\"dnd-book-hd\"><b>' .. esc(head) .. '</b>' .. (bookOnly and legend(K.isBook(sh.class)) or \"\") .. '</div>'\r\nend\r\nif tg then body[#body + 1] = window(tg, sh.class) end\r\nif learn and not tg and learn.msg ~= \"\" then body[#body + 1] = '<div class=\"dnd-prep bad\">' .. esc(learn.msg) .. '</div>' end\r\nif not chosen then body[#body + 1] = '<div class=\"dnd-dim\">아직 주문을 안 골랐습니다. GM에게 \"주문 정하자\"라고 말을 걸면 함께 고릅니다.</div>' end\r\nbody[#body + 1] = formWrap(table.concat(rows), tg, learn, nil)\r\nif ritual then\r\nbody[#body + 1] = '<div class=\"dnd-book-note\"><sup>의식</sup> 표시 주문은 ' .. (K.isBook(sh.class) and \"준비하지 않아도 \" or \"\")\r\n.. '슬롯 없이 의식으로 쓸 수 있습니다(10분 더 걸림, 전투 밖에서).</div>'\r\nend\r\nif caster and not opt.ally and not opt.fight and chosen and not tg then\r\nbody[#body + 1] = '<div class=\"dnd-book-ft\">' .. esc(Spell.changeRuleKo(sh)) .. '</div>'\r\nend\r\nanyTg, anyOpen = tg ~= nil, (tg and tg.open) or (learn and learn.shown) or false\r\nanyLearn = learn ~= nil and learn.open > 0\r\nend\r\nreturn '<details class=\"' .. (opt.ally and \"dnd-ksp\" or \"dnd-sbook\") .. '\"' .. (anyOpen and \" open\" or \"\") .. '><summary><span class=\"dnd-kk\">' .. esc(opt.label or \"주문\")\r\n.. '</span><span class=\"dnd-kv\"><span class=\"dnd-slots\">' .. (#summ > 0 and table.concat(summ) or (chosen and \"\" or \"아직 안 고름\")) .. '</span>'\r\n.. '<span class=\"dnd-more\"><span class=\"mc\">' .. (opt.ally and \"펼치기\" or (anyTg and \"준비 바꾸기\" or (anyLearn and \"소마법 고르기\") or \"주문 보기\")) .. ' ▸</span><span class=\"mo\">접기 ▾</span></span></span></summary>'\r\n.. '<div class=\"dnd-book\">' .. table.concat(body) .. '</div></details>'\r\nend\r\n\r\n\r\nfunction K.Card.allyKit(a)\r\nlocal st = pcStats(a)\r\nlocal lines, byKey, sneak, unarmed = {}, {}, nil, nil\r\nfor _, x in ipairs(st.attacks) do\r\nlocal nm = tostring(x.name or \"\")\r\nif nm:match(\"^Unarmed Strike\") then\r\nunarmed = unarmed or x\r\nelseif not x.spell then\r\nlocal item = x.item or nm\r\nif nm:match(\"%(two hands%)$\") then\r\nif byKey[item] then byKey[item].two = x.dmg end\r\nelseif not byKey[item .. (x.offhand and \"#off\" or \"\")] and not (not x.offhand and byKey[item .. \"#off\"]) then\r\n\r\nlocal _, _, lplus = gearOf(a, item)\r\nlocal lname = (x.base and item ~= x.base) and (item .. ((lplus or 0) > 0 and (\" +\" .. lplus) or \"\")) or koName(x.base or item)\r\nlocal e = { item = item, label = lname .. (x.offhand and \" (보조)\" or \"\"), hit = x.hit, dmg = x.dmg }\r\nbyKey[item .. (x.offhand and \"#off\" or \"\")] = e\r\nlines[#lines + 1] = e\r\nend\r\nif x.sneak then sneak = x.sneak end\r\nend\r\nend\r\nif #lines == 0 and unarmed then lines[1] = { item = \"Unarmed Strike\", label = koName(\"Unarmed Strike\"), hit = unarmed.hit, dmg = unarmed.dmg } end\r\nlocal rows = {}\r\nlocal function row(k, v) rows[#rows + 1] = '<div class=\"dnd-kr\"><span class=\"dnd-kk\">' .. k .. '</span><span class=\"dnd-kv\">' .. v .. '</span></div>' end\r\nlocal swings = K.Card.swings(a.sheet)\r\nfor i, e in ipairs(lines) do\r\nif i > 2 then break end\r\nlocal tip = ITEM_TIP[e.item]\r\nlocal fl = type(a.loot) == \"table\" and a.loot[e.item]\r\nrow(i == 1 and \"무기\" or \"\", (type(fl) == \"table\" and tipSpan(e.label, K.lootTipKo(e.item, fl))\r\nor tip and tipSpan(e.label, e.label .. \"\\n\" .. tip) or esc(e.label))\r\n.. string.format(\" · 명중 <b>%+d</b> · 피해 <b>%s</b>\", e.hit, esc(e.dmg))\r\n.. (e.two and (\" · 양손 <b>\" .. esc(e.two) .. \"</b>\") or \"\")\r\n.. ((i == 1 and swings > 1) and ('<span class=\"dnd-dim\"> · 공격 ' .. (({ \"한\", \"두\", \"세\", \"네\" })[swings] or \"두\") .. ' 번</span>') or \"\"))\r\nend\r\nif sneak then row(esc(koName(\"Sneak Attack\")), \"피해 <b>+\" .. esc(sneak) .. '</b><span class=\"dnd-dim\"> · 한 턴에 한 번</span>') end\r\n\r\n\r\nlocal eq, worn = a.equip or {}, {}\r\nlocal function wear(n)\r\nif not n then return end\r\nlocal _, _, plus = gearOf(a, n)\r\nworn[#worn + 1] = K.itemWrap(n, koName(n), nil, a) .. ((plus or 0) > 0 and (\" +\" .. plus) or \"\")\r\nend\r\nwear(eq.armor)\r\nif K.isShield(a, eq.off) then wear(eq.off) end\r\nif #worn > 0 then row(\"방어구\", table.concat(worn, \" · \") .. ' · 방어도 <b>' .. st.ac .. '</b>') end\r\nlocal spells = K.Card.spells(a.sheet, a, { ally = true })\r\n\r\nlocal uses = K.Card.uses(a.res, not K.LITE and (tonumber(a.hd) or tonumber(a.level)) or nil, tonumber(a.level))\r\nreturn '<div class=\"dnd-kit\">' .. table.concat(rows) .. spells .. (uses ~= \"\" and ('<div class=\"dnd-kr\"><span class=\"dnd-kk\">자원</span><span class=\"dnd-kv\">' .. uses .. '</span></div>') or \"\") .. '</div>'\r\nend\r\n\r\n\r\nfunction K.Card.tab(id, idx)\r\nlocal t, at = tostring(getChatVar(id, \"dnd_card_tab\") or \"\"):match(\"^(%a+)@(%d+)$\")\r\nif t and tonumber(at) == idx then return t end\r\nreturn \"st\"\r\nend\r\n\r\nfunction K.Card.tabBtn(label, payload, on)\r\nreturn '<span class=\"dnd-ctab' .. (on and \" on\" or \"\") .. '\">' .. label .. '<span class=\"dnd-hit\">' .. rawBtn(\" \", payload) .. '</span></span>'\r\nend\r\n\r\n\r\n\r\nfunction K.Card.before(id)\r\nlocal ri = K.replyIdx(id)\r\nlocal key = Seed.at(id, ri - 1)\r\nlocal base = key and Seed.read(id, key)\r\nif not base then\r\nbase = stateOf(id, \"dnd_base\")\r\nif type(base) ~= \"table\" or base.len ~= ri + 1 then base = nil end\r\nend\r\nlocal out = {}\r\nif not base then return out end\r\nif type(base.pc) == \"table\" then\r\nout[\"@pc\"] = tonumber(base.pc.hp)\r\nfor _, a in ipairs(Ally.list(base.pc)) do out[\"@\" .. a.name] = tonumber(a.hp) end\r\nend\r\nif type(base.combat) == \"table\" and type(base.combat.units) == \"table\" then\r\nfor name, u in pairs(base.combat.units) do out[name] = tonumber(u.hp) end\r\nend\r\nreturn out\r\nend\r\n\r\n\r\n\r\nfunction K.Card.fight(id, pc, c, sh)\r\nlocal before = K.Card.before(id)\r\nlocal function change(now, was) return was and (tonumber(now) or 0) - was or nil end\r\nlocal nextUp = not pc.dead and (tonumber(pc.hp) or 0) > 0\r\nlocal order = {}\r\nfor _, name in ipairs(c.order) do\r\nlocal u = c.units[name]\r\nlocal foe = u.side == \"enemy\"\r\nlocal a = u.side == \"ally\" and Ally.find(pc, u.ally)\r\nlocal gone = (foe and u.hp <= 0 and not K.foeUp(u)) or (u.side == \"ally\" and (not a or a.dead)) or (u.side == \"friend\" and u.hp <= 0)\r\nif not gone then\r\nlocal me = u.side == \"pc\"\r\norder[#order + 1] = '<span class=\"dnd-oc' .. (foe and \" foe\" or \"\") .. ((me and nextUp) and \" next\" or (nextUp and \" done\" or \"\")) .. '\">'\r\n.. esc(me and \"당신\" or toKo(name)) .. ' <small>' .. esc(tostring(u.init or \"\")) .. '</small>' .. ((me and nextUp) and \" · 다음\" or \"\") .. '</span>'\r\nend\r\nend\r\n\r\nlocal function covChip(u)\r\nlocal cov = K.coverOf(u)\r\nreturn cov > 0 and K.Card.chip(NAMES_KO[K.COVER_EN[cov]] .. \" +\" .. cov) or \"\"\r\nend\r\nlocal mine = { K.Card.unit({ name = \"당신\", sub = (#K.mcList(sh) > 0 and K.mcText(sh, koName) or (koName(sh.class) .. \" \" .. sh.level)) .. \" · 방어도 \" .. pcStats(pc).ac,\r\nhp = pc.hp, max = pc.max, thp = pc.thp, hpText = pc.dead and \"사망\" or (pc.hp .. \"/\" .. pc.max), delta = change(pc.hp, before[\"@pc\"]),\r\nar = (not pc.dead) and K.Card.arRow(pc, pc) or nil, chips = K.Card.recChips(pc) .. covChip(c.units.Player) }) }\r\nfor _, a in ipairs(Ally.list(pc)) do\r\nmine[#mine + 1] = Ally.unloaded(a) and K.Card.unit({ name = a.name, sub = \"모듈 없음\", hp = a.hp, max = a.max }) or Ally.with(a, function()\r\nreturn K.Card.unit({ name = a.name, sub = Ally.clsKo(a) .. \" · 방어도 \" .. pcStats(a).ac, hp = a.hp, max = a.max, thp = a.thp,\r\nhpText = a.dead and \"사망\" or (a.hp .. \"/\" .. a.max), delta = change(a.hp, before[\"@\" .. a.name]), dim = a.dead,\r\nkit = (not a.dead) and K.Card.allyKit(a) or nil, ar = (not a.dead) and K.Card.arRow(a, pc) or nil, chips = K.Card.recChips(a) .. covChip(c.units[a.name]) })\r\nend)\r\nend\r\n\r\nfor _, name in ipairs(c.order) do\r\nlocal u = c.units[name]\r\nlocal g = u.side == \"ally\" and u.guest and Ally.isGuest(pc, u.ally)\r\nif g then\r\nmine[#mine + 1] = Ally.unloaded(g) and K.Card.unit({ name = g.name, sub = \"도움 · 클래스 모듈 없음\", hp = g.hp, max = g.max }) or Ally.with(g, function()\r\nreturn K.Card.unit({ name = g.name, sub = \"도움 · \" .. koName(g.sheet.class) .. \" \" .. g.level .. \" · 방어도 \" .. pcStats(g).ac, hp = g.hp, max = g.max,\r\nhpText = g.dead and \"사망\" or (g.hp .. \"/\" .. g.max), delta = change(g.hp, before[\"@\" .. g.name]), dim = g.dead,\r\nchips = K.Card.recChips(g) .. covChip(u) })\r\nend)\r\nelseif u.side == \"friend\" then\r\nmine[#mine + 1] = K.Card.unit({ name = toKo(name), sub = \"도움\", hp = u.hp, max = u.max, dim = u.hp <= 0,\r\nhpText = u.hp <= 0 and \"쓰러짐\" or (u.hp .. \"/\" .. u.max), delta = change(u.hp, before[name]), chips = covChip(u) })\r\nend\r\nend\r\nlocal foes, fallen = {}, {}\r\nfor _, name in ipairs(c.order) do\r\nlocal u = c.units[name]\r\nif u.side == \"enemy\" then\r\nif u.hp <= 0 and not K.foeUp(u) then\r\nfallen[#fallen + 1] = toKo(name)\r\nelse\r\nlocal ch = {}\r\nif u.hp <= 0 then ch[#ch + 1] = K.Card.chip(\"쓰러짐\", \"bad\") end\r\nif (tonumber(u.lr) or 0) > 0 then ch[#ch + 1] = K.Card.chip(\"전설 저항 \" .. u.lr) end\r\nif u.burned then ch[#ch + 1] = K.Card.chip(\"재생 멈춤\", \"bad\") end\r\nfor _, cn in ipairs(K.foeCondFx(u, pc).list) do ch[#ch + 1] = K.Card.chip(koName(cn)) end\r\nfor _, sn in ipairs(K.foeFx(u, pc).list) do ch[#ch + 1] = K.Card.chip(koName(sn)) end\r\nch[#ch + 1] = covChip(u)\r\nfoes[#foes + 1] = K.Card.unit({ name = toKo(name), hp = u.hp, max = u.max, foe = true, delta = change(u.hp, before[name]), chips = table.concat(ch),\r\nar = K.Card.arRow(u, pc, true) })\r\nend\r\nend\r\nend\r\nif #fallen > 0 then foes[#foes + 1] = '<div class=\"dnd-fallen\">✝ ' .. esc(table.concat(fallen, \", \")) .. '</div>' end\r\nlocal uses = K.Card.uses(pc.res)\r\nreturn '<div class=\"dnd-order\"><span class=\"dnd-l\">† 순서</span>' .. table.concat(order) .. '</div>'\r\n.. '<div class=\"dnd-fcols\"><div class=\"dnd-side ally\"><span class=\"dnd-l\">♥ 아군</span>' .. table.concat(mine) .. '</div>'\r\n.. '<div class=\"dnd-side foe\"><span class=\"dnd-l\">♥ 적</span>' .. table.concat(foes) .. '</div></div>'\r\n.. (K.Card.hasSpells(sh) and ('<div class=\"dnd-sec\">' .. K.Card.spells(sh, pc, { label = \"내 주문\", fight = true }) .. '</div>') or \"\")\r\n.. (uses ~= \"\" and ('<div class=\"dnd-sec\"><span class=\"dnd-l\">자원</span>' .. uses .. '</div>') or \"\")\r\nend\r\n\r\n\r\nfunction Ally.clsKo(a)\r\nreturn #K.mcList(a.sheet) > 0 and K.mcText(a.sheet, koName) or (koName(a.sheet.class) .. \" \" .. a.level)\r\nend\r\n\r\n\r\n\r\n\r\n\r\n\r\nfunction K.nameTag(name)\r\nlocal h = 2166136261\r\nfor c in tostring(name or \"\"):gmatch(\".\") do h = ((h ~ c:byte()) * 16777619) & 0xffffffff end\r\nreturn string.format(\"%06x\", h & 0xffffff)\r\nend\r\n\r\nfunction Ally.pregRow(i, a)\r\nif not (K.PG and K.PG.on()) then return \"\" end\r\nlocal w = type(a.sheet.picks) == \"table\" and a.sheet.picks.pregwant == \"yes\"\r\nlocal tag = \"dnd_apreg_\" .. i .. \"_\" .. K.nameTag(a.name) .. \"_\"\r\nreturn '<div class=\"dnd-opt-t\">임신 원함</div>' .. K.btnRows({ btn(\"예\", tag .. \"yes\", w), btn(\"아니오\", tag .. \"no\", not w) })\r\nend\r\n\r\nfunction Ally.pregNote(a)\r\nif not (K.PG and K.PG.on()) then return \"\" end\r\nreturn (type(a.preg) == \"table\" and ('<div class=\"dnd-opt-d\">' .. esc(\"임신 중 (\" .. (a.preg.kind == \"traditional\" and \"전통\" or \"비전통\")\r\n.. (a.preg.by and (\", \" .. (a.preg.by == \"Player\" and \"당신\" or NAMES_KO[a.preg.by] or (K.toKo and K.toKo(a.preg.by)) or a.preg.by)) or \"\") .. \")\"\r\n.. (#K.PG.all(a) > 1 and string.format(\" 외 %d건 · 근력·민첩 -%d\", #K.PG.all(a) - 1, #K.PG.all(a) - 1) or \"\")\r\n.. (K.PG.showing(a) and \" · 근력·민첩 내성 불리, 향한 공격 18~20 치명타\" or \" · 아직 드러나지 않음\")) .. '</div>') or \"\")\r\nend\r\n\r\nfunction Ally.posRow(i, a)\r\nif not (K.AR and K.AR.on()) then return \"\" end\r\nlocal v = type(a.sheet.picks) == \"table\" and a.sheet.picks.position or \"any\"\r\nlocal tag = \"dnd_apos_\" .. i .. \"_\" .. K.nameTag(a.name) .. \"_\"\r\nreturn '<div class=\"dnd-opt-t\">포지션</div>' .. K.btnRows({ btn(\"삽입\", tag .. \"top\", v == \"top\"), btn(\"수용\", tag .. \"bottom\", v == \"bottom\"), btn(\"상관없음\", tag .. \"any\", v ~= \"top\" and v ~= \"bottom\") })\r\nend\r\n\r\n\r\nfunction Ally.adultFold(i, a)\r\nlocal pos, preg = Ally.posRow(i, a), Ally.pregRow(i, a)\r\nif pos == \"\" and preg == \"\" then return \"\" end\r\nlocal pk = type(a.sheet.picks) == \"table\" and a.sheet.picks or {}\r\nlocal now = {}\r\nif pos ~= \"\" then now[#now + 1] = \"포지션 \" .. (({ top = \"삽입\", bottom = \"수용\" })[pk.position] or \"상관없음\") end\r\nif preg ~= \"\" then now[#now + 1] = \"임신 원함 \" .. (pk.pregwant == \"yes\" and \"예\" or \"아니오\") end\r\nreturn '<details class=\"dnd-give\"><summary>성인 설정 · ' .. esc(table.concat(now, \" · \")) .. '</summary>' .. pos .. preg .. '</details>'\r\nend\r\nfunction Ally.posClick(id, data)\r\nlocal i, tag, v = data:match(\"^dnd_apos_(%d+)_(%x+)_(%a+)$\")\r\nsetChatVar(id, \"dnd_card_tab\", \"pt@\" .. K.replyIdx(id))\r\ni = tonumber(i)\r\nif not i or not K.POS_KO[v or \"\"] then return end\r\nlocal pc = loadPC(id)\r\nlocal a = Ally.list(pc)[i]\r\nif not a or K.nameTag(a.name) ~= tag then return end\r\nlocal who = a.name\r\nlocal function op(s)\r\nlocal b = Ally.list(s.pc)[i]\r\nif not b or b.name ~= who then return false end\r\nb.sheet.picks = type(b.sheet.picks) == \"table\" and b.sheet.picks or {}\r\nb.sheet.picks.position = v\r\nreturn true\r\nend\r\nif not op({ pc = pc }) then return end\r\nsetState(id, \"dnd_pc\", pc)\r\nsyncBases(id, op)\r\nend\r\nfunction Ally.pregClick(id, data)\r\nlocal i, tag, v = data:match(\"^dnd_apreg_(%d+)_(%x+)_(%a+)$\")\r\nsetChatVar(id, \"dnd_card_tab\", \"pt@\" .. K.replyIdx(id))\r\ni = tonumber(i)\r\nif not i or (v ~= \"yes\" and v ~= \"no\") then return end\r\nlocal pc = loadPC(id)\r\nlocal a = Ally.list(pc)[i]\r\nif not a or K.nameTag(a.name) ~= tag then return end\r\nlocal who = a.name\r\nlocal function op(s)\r\nlocal b = Ally.list(s.pc)[i]\r\nif not b or b.name ~= who then return false end\r\nb.sheet.picks = type(b.sheet.picks) == \"table\" and b.sheet.picks or {}\r\nb.sheet.picks.pregwant = v\r\nreturn true\r\nend\r\nif not op({ pc = pc }) then return end\r\nsetState(id, \"dnd_pc\", pc)\r\nsyncBases(id, op)\r\nend\r\n\r\n\r\nfunction Ally.featSwap(sh, pick, atLv)\r\nlocal slot\r\nfor _, x in ipairs(type(sh.allyAsi) == \"table\" and sh.allyAsi or {}) do\r\nif not x.feat and (not atLv or x.lv == atLv) then slot = x end\r\nend\r\nif not slot then return false end\r\nlocal d = type(slot.d) == \"table\" and slot.d or {}\r\nfor k, v in pairs(d) do if sh.scores[k] then sh.scores[k] = sh.scores[k] - (tonumber(v) or 0) end end\r\nif applyASI(sh, pick) == \"?\" then\r\nfor k, v in pairs(d) do if sh.scores[k] then sh.scores[k] = sh.scores[k] + (tonumber(v) or 0) end end\r\nreturn false\r\nend\r\nslot.feat = pick\r\nreturn true\r\nend\r\nfunction Ally.featRow(i, a)\r\nif not (K.PACK.feat and next(K.PACK.feat)) then return \"\" end\r\nlocal sh = a.sheet\r\nlocal free = false\r\nfor _, x in ipairs(type(sh.allyAsi) == \"table\" and sh.allyAsi or {}) do if not x.feat then free = true end end\r\nif not free then return \"\" end\r\nlocal b, tips = {}, {}\r\nfor _, fname in ipairs(K.gfeatList(sh)) do\r\nlocal rec = K.FX[fname]\r\nlocal asi = K.gfeatAsi(sh, fname)\r\nlocal base = \"dnd_afeat_\" .. i .. \"_\" .. K.nameTag(a.name) .. \"_\"\r\nif #asi == 0 then b[#b + 1] = btn(koName(fname), base .. K.gfeatPay(fname), false)\r\nelse for _, ab in ipairs(asi) do b[#b + 1] = btn(koName(fname) .. \" · \" .. koName(ab) .. \" +1\", base .. K.gfeatPay(fname, ab), false) end end\r\nif rec.tip then tips[#tips + 1] = tipSpan(koName(fname), rec.tip) end\r\nend\r\nif #b == 0 then return \"\" end\r\nreturn '<div class=\"dnd-opt-t\">재주 (능력치 점수 상승 하나와 바꾸기)</div>' .. K.btnRows(b)\r\n.. '<div class=\"dnd-opt-d\">' .. esc(\"마지막으로 받은 능력치 점수 상승을 되돌리고 그 자리에 재주를 받습니다.\") .. (#tips > 0 and (\" 설명: \" .. table.concat(tips, \" · \")) or \"\") .. '</div>'\r\nend\r\nfunction Ally.featClick(id, data)\r\nlocal i, tag, pick = data:match(\"^dnd_afeat_(%d+)_(%x+)_(F_.+)$\")\r\nsetChatVar(id, \"dnd_card_tab\", \"pt@\" .. K.replyIdx(id))\r\ni = tonumber(i)\r\nif not (i and pick) then return end\r\nlocal fn = (pick:sub(3):match(\"^(.-)__%a+$\") or pick:sub(3)):gsub(\"_Q_\", \"'\"):gsub(\"_\", \" \")\r\nlocal sh0 = loadSheet(id)\r\napplySheet(sh0)\r\nlocal pc = loadPC(id)\r\nlocal a = Ally.list(pc)[i]\r\nif not a or a.dead or K.nameTag(a.name) ~= tag then return end\r\nif not K.gfeatOk(a.sheet, fn, K.FX[fn]) then return end\r\nlocal who = a.name\r\nlocal function op(s)\r\nlocal b = Ally.list(s.pc)[i]\r\nif not b or b.name ~= who then return false end\r\nif not Ally.featSwap(b.sheet, pick) then return false end\r\nAlly.autoPick(b)\r\nAlly.with(b, function() refitHp(b.sheet, b); Feat.fillRes(b) end)\r\nreturn true\r\nend\r\nif not op({ pc = pc }) then return end\r\nsetState(id, \"dnd_pc\", pc)\r\nsyncBases(id, op)\r\nend\r\nfunction Ally.subPickRow(i, a)\r\nlocal sh, out = a.sheet, {}\r\nlocal p = type(sh.picks) == \"table\" and sh.picks or {}\r\nfor _, c in ipairs(K.classes(sh)) do\r\nlocal key, opts = K.subKey(c.name), K.subOptions(c.name)\r\nif #opts > 1 and c.level >= K.subLevel(c.name) and p[key] == nil then\r\nlocal b, tips = {}, {}\r\nfor _, o in ipairs(opts) do\r\nb[#b + 1] = btn(koName(o), \"dnd_asub_\" .. i .. \"_\" .. K.nameTag(a.name) .. \"_\" .. key .. \"_\" .. o:gsub(\" \", \"_\"), false)\r\nlocal t = Feat.TIP[key][o]\r\nif t then tips[#tips + 1] = tipSpan(koName(o), t) end\r\nend\r\nlocal d = K.subDefault(c.name)\r\nout[#out + 1] = '<div class=\"dnd-opt-t\">' .. esc(Feat.TITLE[key]) .. '</div>' .. K.btnRows(b)\r\n.. '<div class=\"dnd-opt-d\">' .. esc(\"고르기 전까지는 기본 하위 클래스(\" .. koName(d) .. \")의 기능이 적용됩니다.\")\r\n.. (#tips > 0 and (\" 설명: \" .. table.concat(tips, \" · \")) or \"\") .. '</div>'\r\nend\r\nend\r\nreturn table.concat(out)\r\nend\r\nfunction Ally.subPickClick(id, data)\r\nlocal i, tag, key, v = data:match(\"^dnd_asub_(%d+)_(%x+)_(sub%a+)_(.+)$\")\r\nsetChatVar(id, \"dnd_card_tab\", \"pt@\" .. K.replyIdx(id))\r\ni = tonumber(i)\r\nlocal cl = K.subClassOf(key)\r\nif not (i and cl and v) or K.LITE then return end\r\nv = v:gsub(\"_\", \" \")\r\nlocal fits = false\r\nfor _, o in ipairs(K.subOptions(cl)) do if o == v then fits = true end end\r\nif not fits then return end\r\nlocal sh0 = loadSheet(id)\r\napplySheet(sh0)\r\nlocal pc = loadPC(id)\r\nlocal a = Ally.list(pc)[i]\r\nif not a or a.dead or K.nameTag(a.name) ~= tag then return end\r\nlocal who = a.name\r\nlocal function op(s)\r\nlocal b = Ally.list(s.pc)[i]\r\nif not b or b.name ~= who or b.dead then return false end\r\nlocal p = Feat.picks(b.sheet)\r\nif p[key] ~= nil or K.cl(b.sheet, cl) < K.subLevel(cl) then return false end\r\np[key] = v\r\n\r\nAlly.with(b, function() refitHp(b.sheet, b); Feat.fillRes(b) end)\r\nreturn true\r\nend\r\nif not op({ pc = pc }) then return end\r\nsetState(id, \"dnd_pc\", pc)\r\nsyncBases(id, op)\r\nend\r\n\r\n\r\n\r\nfunction Ally.everyKeys()\r\nlocal o = {}\r\nfor n, cat in pairs(K.PACK.feat or {}) do\r\nif cat == \"everyone\" and type(K.FX[n]) == \"table\" then\r\nfor _, e in ipairs(K.FX[n].fx or {}) do if e.t == \"choice\" and type(e.key) == \"string\" then o[e.key] = true end end\r\nend\r\nend\r\nreturn o\r\nend\r\nfunction Ally.everyRow(i, a)\r\nlocal keys = Ally.everyKeys()\r\nif not next(keys) or type(a.sheet) ~= \"table\" then return \"\" end\r\nlocal rows = Ally.with(a, function() return Feat.pending(a.sheet, a) end) or {}\r\nlocal out = {}\r\nfor _, row in ipairs(rows) do\r\nif keys[row.key] then\r\nlocal b = {}\r\nfor _, o in ipairs(row.opts) do\r\nb[#b + 1] = btn(Feat.label(row.key, o), \"dnd_aevery_\" .. i .. \"_\" .. K.nameTag(a.name) .. \"_\" .. row.key .. \"_\" .. o:gsub(\" \", \"_\"), false)\r\nend\r\nout[#out + 1] = '<div class=\"dnd-opt-t\">' .. esc(Feat.TITLE[row.key] or row.key) .. '</div>' .. K.btnRows(b)\r\nend\r\nend\r\nreturn table.concat(out)\r\nend\r\nfunction Ally.everyClick(id, data)\r\nlocal i, tag, key, v = data:match(\"^dnd_aevery_(%d+)_(%x+)_(%w+)_(.+)$\")\r\nsetChatVar(id, \"dnd_card_tab\", \"pt@\" .. K.replyIdx(id))\r\ni = tonumber(i)\r\nif not (i and key and v) or K.LITE or not Ally.everyKeys()[key] then return end\r\nv = v:gsub(\"_\", \" \")\r\nlocal sh0 = loadSheet(id)\r\napplySheet(sh0)\r\nlocal pc = loadPC(id)\r\nlocal a = Ally.list(pc)[i]\r\nif not a or a.dead or K.nameTag(a.name) ~= tag then return end\r\nlocal who = a.name\r\nlocal function op(s)\r\nlocal b = Ally.list(s.pc)[i]\r\nif not b or b.name ~= who or b.dead or type(b.sheet) ~= \"table\" then return false end\r\nlocal ok = Ally.with(b, function() return Feat.pick(b.sheet, key, v, b) end)\r\nif ok then Ally.with(b, function() refitHp(b.sheet, b); Feat.fillRes(b) end) end\r\nreturn ok\r\nend\r\nif not op({ pc = pc }) then return end\r\nsetState(id, \"dnd_pc\", pc)\r\nsyncBases(id, op)\r\nend\r\n\r\nfunction Ally.lvPickRow(i, a)\r\nlocal sh = a.sheet\r\nlocal cur = Ally.nextCls(a)\r\nif not cur then return \"\" end\r\nlocal have = {}\r\nfor _, c in ipairs(K.classes(sh)) do\r\nif K.mcCan(sh, c.name) then\r\nhave[#have + 1] = btn(string.format(\"%s %d→%d\", koName(c.name), c.level, c.level + 1), \"dnd_alvcls_\" .. i .. \"_\" .. K.nameTag(a.name) .. \"_\" .. c.name, c.name == cur)\r\nelse\r\nhave[#have + 1] = '<span class=\"dnd-opt-btn off\">' .. esc(koName(c.name) .. \" \" .. c.level .. \" · 최고 레벨\") .. '</span>'\r\nend\r\nend\r\nif K.cl(sh, cur) == 0 then have[#have + 1] = btn(koName(cur) .. \" 0→1\", \"dnd_alvcls_\" .. i .. \"_\" .. K.nameTag(a.name) .. \"_\" .. cur, true) end\r\nlocal names, can, cannot = {}, {}, {}\r\nfor n in pairs(CLASSES) do if n:sub(1, 1) ~= \"_\" and K.cl(sh, n) == 0 then names[#names + 1] = n end end\r\ntable.sort(names, function(x, y) return koName(x) < koName(y) end)\r\nfor _, n in ipairs(names) do\r\nlocal ok, why, x = K.mcCan(sh, n)\r\nif ok then\r\nif n ~= cur then can[#can + 1] = btn(koName(n), \"dnd_alvcls_\" .. i .. \"_\" .. K.nameTag(a.name) .. \"_\" .. n, false) end\r\nelse\r\ncannot[#cannot + 1] = koName(n) .. \" (\" .. K.mcWhyKo(why, x) .. \")\"\r\nend\r\nend\r\nlocal body = {}\r\nif #can > 0 then body[#body + 1] = K.btnRows(can) end\r\nif #cannot > 0 then body[#body + 1] = '<div class=\"dnd-opt-d\">고를 수 없음: ' .. esc(table.concat(cannot, \" · \")) .. '</div>' end\r\nbody[#body + 1] = '<div class=\"dnd-opt-d\">새 클래스는 1레벨부터 시작하고 그 클래스의 1레벨 기능을 얻습니다. 지금 클래스와 새 클래스의 주요 능력치가 모두 13 이상이어야 합니다.'\r\n.. ' 능력치 향상은 각 클래스의 레벨대로 오고, 처음 클래스의 주요 능력치가 오릅니다. 주문을 쓰는 클래스가 둘이면 준비 주문은 클래스마다, 주문 슬롯은 함께 씁니다.</div>'\r\nreturn '<details class=\"dnd-give\"><summary>다음 레벨 클래스 · ' .. esc(koName(cur)) .. '</summary>'\r\n.. '<div class=\"dnd-opt-d\">내 레벨이 오를 때 ' .. esc(a.name) .. '의 레벨이 이 클래스로 오릅니다. 다른 클래스를 고를 때까지 그대로이고, 고르지 않으면 처음 클래스로 오릅니다.</div>'\r\n.. K.btnRows(have)\r\n.. '<details style=\"margin:4px 0 6px\"><summary style=\"cursor:pointer;font-size:12px;color:#a8977a\">다른 클래스 더하기 (멀티클래스)</summary>'\r\n.. table.concat(body) .. '</details></details>'\r\nend\r\n\r\n\r\n\r\n\r\nfunction K.Card.allyStats(a)\r\nlocal sh = a.sheet\r\nlocal cells = {}\r\nfor _, ab in ipairs(ABILS) do\r\ncells[#cells + 1] = string.format('<div class=\"dnd-ab%s\"><span>%s</span><b>%d</b><i>%+d</i></div>',\r\nSAVE_PROF[ab] and \" sv\" or \"\", esc(koName(ab)), SCORE[ab], MOD[ab])\r\nend\r\nlocal line = { tipSpan(string.format(\"숙련 +%d\", PROF), \"숙련된 기술·무기·내성 굴림에 이 값을 더합니다.\\n금테 칸: 그 능력치의 내성 굴림에 숙련이 붙습니다.\") }\r\n\r\nlocal sst = Spell.stats(nil, K.castCl(sh))\r\nif sst then\r\nlocal dc, atk = sst.dc, sst.atk\r\nline[#line + 1] = tipSpan(\"주문 내성 난이도 \" .. dc, string.format(\"적이 이 동료의 주문을 버티려면 내성 굴림이 %d 이상 나와야 합니다.\", dc))\r\nline[#line + 1] = tipSpan(string.format(\"주문 명중 %+d\", atk), string.format(\"명중 굴림을 하는 주문은 d20 %+d%s 상대 방어도 이상이면 맞습니다.\", atk, K.josa(tostring(atk), \"이\", \"가\")))\r\nend\r\nlocal sk = {}\r\nfor _, k in ipairs(K.profSkills(sh)) do\r\nlocal label = string.format(\"%s %+d%s\", koName(k), bonusFor(k), EXPERT[k] and \"★\" or \"\")\r\nsk[#sk + 1] = SKILL_TIP[k] and tipSpan(label, SKILL_TIP[k]) or esc(label)\r\nend\r\nreturn '<div class=\"dnd-abil\" style=\"grid-template-columns:repeat(6,1fr)\">' .. table.concat(cells) .. '</div>'\r\n.. '<div class=\"dnd-subl\">' .. table.concat(line, \" · \") .. '</div>'\r\n.. (#sk > 0 and ('<div class=\"dnd-subl\">기술 · ' .. table.concat(sk, \" · \") .. '</div>') or \"\")\r\nend\r\n\r\n\r\nfunction K.Card.party(id, pc, fight)\r\nlocal list = Ally.list(pc)\r\nlocal leaving = {}\r\nfor _, nm in ipairs(Ally.leaving(id)) do leaving[nm] = true end\r\nlocal cards = {}\r\nfor i, a in ipairs(list) do\r\n\r\nif Ally.unloaded(a) then\r\nlocal ash = type(a.sheet) == \"table\" and a.sheet or {}\r\nlocal what = CLASSES[ash.class or \"\"] and (tostring(ash.species or \"?\") .. \" 종족\") or (tostring(ash.class or \"?\") .. \" 클래스\")\r\ncards[#cards + 1] = '<div class=\"dnd-comp\"><div class=\"dnd-opt-d\">' .. esc(a.name) .. ': '\r\n.. esc(what) .. K.josa(what, \"이\", \"가\") .. ' 들어 있는 모듈이 꺼져 있습니다. 모듈을 다시 켜 주십시오.</div></div>'\r\ngoto nextCard\r\nend\r\ncards[#cards + 1] = Ally.with(a, function()\r\nlocal st = pcStats(a)\r\nlocal sh = a.sheet\r\nlocal tags = { K.Card.chip(Ally.ko(sh.species)) }\r\nif #K.mcList(sh) > 0 then\r\nfor _, c in ipairs(K.classes(sh)) do tags[#tags + 1] = K.Card.chip(koName(c.name) .. \" \" .. c.level) end\r\nelse\r\ntags[#tags + 1] = K.Card.chip(koName(sh.class))\r\nend\r\nif sh.background then tags[#tags + 1] = K.Card.chip(koName(sh.background)) end\r\nlocal act\r\nif leaving[a.name] then\r\nact = '<span class=\"dnd-opt-btn off\">다음 답에서 헤어집니다</span>' .. btn(\"취소\", \"dnd_party_leave_cancel_\" .. i, false)\r\nelseif fight then\r\nact = '<span class=\"dnd-opt-btn off\">전투 중에는 헤어질 수 없습니다</span>'\r\nelse\r\nact = btn(\"헤어지기\", \"dnd_party_leave_\" .. i, false)\r\nend\r\nlocal chips = K.Card.recChips(a)\r\n\r\nlocal gear = \"\"\r\nif not a.dead and not fight then\r\nlocal give, take = {}, {}\r\nfor k, n in ipairs(Ally.gearList(pc)) do give[#give + 1] = btn(koName(n), \"dnd_give_\" .. i .. \"_\" .. k .. \"_\" .. K.nameTag(a.name) .. K.nameTag(n), false) end\r\nfor k, n in ipairs(Ally.gearList(a)) do\r\nlocal on = a.equip.armor == n or a.equip.main == n or a.equip.off == n\r\ntake[#take + 1] = btn(koName(n) .. (on and \" (착용)\" or \"\"), \"dnd_take_\" .. i .. \"_\" .. k .. \"_\" .. K.nameTag(a.name) .. K.nameTag(n), false)\r\nend\r\ngear = '<details class=\"dnd-give\"><summary>장비 주고받기</summary>'\r\n.. '<div class=\"dnd-opt-t\">내 가방에서 주기</div><div class=\"dnd-opt-btns dnd-dbg-btns\">'\r\n.. (#give > 0 and table.concat(give) or '<span class=\"dnd-opt-d\">줄 장비가 없습니다.</span>') .. '</div>'\r\n.. '<div class=\"dnd-opt-t\">돌려받기</div><div class=\"dnd-opt-btns dnd-dbg-btns\">'\r\n.. (#take > 0 and table.concat(take) or '<span class=\"dnd-opt-d\">없습니다.</span>') .. '</div>'\r\n.. '<div class=\"dnd-opt-d\">받은 무기·갑옷·방패를 쓸 수 있으면 바로 착용합니다(갑옷과 방패는 방어도가 나아질 때만, 방패는 두손 무기를 들고 있지 않을 때).'\r\n.. ' 장신구는 지니기만 하면 효과가 있고, 조율이 필요한 물건은 받은 쪽이 다시 조율해야 합니다.</div></details>'\r\nend\r\nreturn '<div class=\"dnd-comp\"><div class=\"dnd-hero\"><div class=\"dnd-face\">' .. esc(K.Card.initial(a.name)) .. '<b class=\"dnd-lvb\">' .. a.level .. '</b></div>'\r\n.. '<div class=\"dnd-hero-t\"><div class=\"dnd-name\">' .. esc(a.name) .. '</div><div class=\"dnd-uc\">' .. table.concat(tags) .. '</div>'\r\n.. (((a.note or \"\") ~= \"\" and a.note ~= \"-\") and ('<div class=\"dnd-memo\">' .. esc(a.note) .. '</div>') or \"\") .. '</div></div>'\r\n.. '<div class=\"dnd-hpl\"><span>생명력 · 방어도 ' .. st.ac .. ' · 속도 ' .. st.speed .. '</span><b>' .. esc(Ally.hpText(a)) .. '</b></div>'\r\n.. K.Card.bar(a.hp, a.max) .. K.Card.allyStats(a) .. (a.dead and \"\" or K.Card.arAlly(a, pc)) .. (a.dead and \"\" or K.Card.allyKit(a))\r\n.. (chips ~= \"\" and ('<div class=\"dnd-uc\">' .. chips .. '</div>') or \"\") .. (a.dead and \"\" or Ally.pregNote(a))\r\n.. gear .. ((a.dead or K.LITE) and \"\" or (Ally.subPickRow(i, a) .. Ally.lvPickRow(i, a) .. Ally.featRow(i, a) .. Ally.adultFold(i, a) .. Ally.everyRow(i, a))) .. '<div class=\"dnd-opt-btns\">' .. act .. '</div></div>'\r\nend)\r\n::nextCard::\r\nend\r\nif #list == 0 then cards[1] = '<div class=\"dnd-empty\">아직 함께하는 동료가 없습니다.</div>' end\r\n\r\nlocal sm = {}\r\nfor _, s in ipairs(type(pc.summons) == \"table\" and pc.summons or {}) do\r\nlocal st = s.st or MONSTERS[s.kind] or {}\r\nlocal p = s.ends and clockParts(s.ends)\r\nsm[#sm + 1] = '<div class=\"dnd-hpl\"><span>' .. esc(toKo(s.name)) .. ' · ' .. esc(koName(s.spell))\r\n.. (pc.mount == s.name and \" · 탄 상태\" or \"\") .. (s.noatk and \" · 공격 못 함\" or \"\")\r\n.. (p and string.format(\" · %d일째 %02d:%02d까지\", p.day, p.h, p.m) or \"\") .. '</span><b>' .. (s.hp or 0) .. \" / \" .. (s.max or 0) .. '</b></div>'\r\n.. K.Card.bar(s.hp, s.max)\r\n\r\nlocal at = {}\r\nfor _, x in ipairs(type(st.attacks) == \"table\" and st.attacks or {}) do\r\nat[#at + 1] = string.format(\"%s %+d, %s\", K.atkKo(x.name or \"?\"), tonumber(x.hit) or 0, tostring(x.dmg or \"\"))\r\nend\r\nif st.ac or #at > 0 then\r\nsm[#sm] = sm[#sm] .. '<div class=\"dnd-opt-d\">' .. esc((st.ac and (\"방어도 \" .. st.ac) or \"\") .. ((st.ac and #at > 0) and \" · \" or \"\") .. table.concat(at, \" · \")) .. '</div>'\r\nend\r\nend\r\nif #sm > 0 then cards[#cards + 1] = '<div class=\"dnd-comp\"><div class=\"dnd-opt-t\">소환수</div>' .. table.concat(sm) .. '</div>' end\r\n\r\nlocal want = tonumber(getChatVar(id, \"dnd_party_want\")) or Ally.MAX\r\nlocal wb = {}\r\nfor i = 0, Ally.MAX do wb[#wb + 1] = btn(i == 0 and \"혼자\" or (i .. \"명\"), \"dnd_party_\" .. i, want == i) end\r\n\r\nlocal style = getChatVar(id, \"dnd_ally_style\")\r\nstyle = (style == \"save\" or style == \"bold\") and style or \"normal\"\r\nlocal sb = { btn(\"아껴서\", \"dnd_allystyle_save\", style == \"save\"), btn(\"보통\", \"dnd_allystyle_normal\", style == \"normal\"),\r\nbtn(\"적극적으로\", \"dnd_allystyle_bold\", style == \"bold\") }\r\nlocal styleHtml = '<div class=\"dnd-opt-t\">동료 전투 성향</div><div class=\"dnd-opt-d\">동료가 싸움에서 주문 슬롯과 신성 변환을 얼마나 쓰는지 정합니다.'\r\n.. ' 아껴서: 무기와 소마법, 위험할 때 회복만. 보통: 언데드에게 언데드 퇴치, 적이 셋 이상이면 범위 주문. 적극적으로: 더 센 주문이 있으면 슬롯을 씁니다.'\r\n.. ' 그 차례에 할 일을 직접 말하면 그쪽이 먼저입니다.</div><div class=\"dnd-opt-btns\">' .. table.concat(sb) .. '</div>'\r\nreturn table.concat(cards) .. '<div class=\"dnd-pfoot\">' .. styleHtml .. '<div class=\"dnd-opt-t\">파티 최대 인원</div><div class=\"dnd-opt-d\">함께 다닐 수 있는 동료의 최대 수입니다.'\r\n.. ' 이야기에서 누군가에게 같이 가자고 하면 이 수까지 동료로 들어옵니다. \"혼자\"면 동료 없이 진행합니다.'\r\n.. ' 동료의 능력치는 Lua가 내 레벨에 맞춰 만들고, 이미 함께하는 동료는 그대로입니다.</div>'\r\n.. '<div class=\"dnd-opt-btns\">' .. table.concat(wb) .. '</div></div>'\r\nend\r\n\r\n\r\n\r\nK.PLACE_KO = { Forest = \"숲\", Ruins = \"폐허\", Urban = \"도시\", Grassland = \"초원\", Hill = \"구릉지\", Planar = \"다른 세계\", Underdark = \"언더다크\",\r\nMountain = \"산\", Swamp = \"늪\", Desert = \"사막\", Coastal = \"해안\", Underwater = \"물속\", Arctic = \"설원\" }\r\nK.SCALE_KO = { village = \"마을의 일\", city = \"도시의 일\", noble = \"귀족의 일\", kingdom = \"왕국의 일\" }\r\nfunction K.Card.jobs(pc)\r\nlocal q = Quest.load(pc)\r\nif #q.list == 0 then return '<div class=\"dnd-empty\">아직 받은 의뢰가 없습니다. 의뢰를 맡으면 여기에 적힙니다.</div>' end\r\nlocal out = {}\r\nfor _, x in ipairs(q.list) do\r\nlocal adv = tonumber(x.adv) or 0\r\n\r\nlocal pay = string.format(\"경험치 %d · 금화 %d\", x.xp, x.gp)\r\n.. (adv > 0 and string.format(\" (%d는 선수금으로 받음)\", adv) or \"\")\r\nlocal tags = { K.Card.chip(\"#\" .. x.id) }\r\nif (x.client or \"\") ~= \"\" then tags[#tags + 1] = K.Card.chip(x.client) end\r\ntags[#tags + 1] = K.Card.chip(K.SCALE_KO[x.scale] or x.scale or \"\")\r\ntags[#tags + 1] = K.Card.chip(K.PLACE_KO[x.place] or x.place or \"\")\r\nout[#out + 1] = '<div class=\"dnd-comp\"><div class=\"dnd-name\">' .. esc(x.title or \"\") .. '</div><div class=\"dnd-uc\">' .. table.concat(tags) .. '</div>'\r\n.. ((x.goal or \"\") ~= \"\" and ('<div class=\"dnd-memo\">' .. esc(x.goal) .. '</div>') or \"\")\r\n.. '<div class=\"dnd-hpl\"><span>성공하면</span><b>' .. esc(pay) .. '</b></div></div>'\r\nend\r\nreturn table.concat(out) .. '<div class=\"dnd-pfoot\"><div class=\"dnd-opt-d\">절반만 해내면 보수도 절반입니다. 의뢰는 한 번에 '\r\n.. Quest.MAX .. '개까지 맡을 수 있습니다.</div></div>'\r\nend\r\n\r\n\r\nlocal function statusHtml(id, f, idx)\r\nlocal sh = loadSheet(id)\r\napplySheet(sh)\r\nlocal pc = loadPC(id)\r\nlocal c = loadCombat(id)\r\nlocal fight = c.active and true or false\r\nlocal tab = K.Card.tab(id, idx)\r\nlocal g = function(i) return esc(f[i] or \"\") end\r\n\r\nlocal eqH, packH = gearText(pc, K.itemWrap)\r\nlocal delta = getState(id, \"dnd_turn_delta\")\r\nlocal chips = {}\r\nfor _, e in ipairs(type(delta) == \"table\" and delta or {}) do\r\nlocal t = tostring(e[2] or \"\")\r\n\r\nlocal hpChange = t:match(\"^생명력 [%+%-]%d+$\") or t == \"쓰러짐\"\r\nfor _, a in ipairs(Ally.list(pc)) do\r\nlocal rest = t:sub(1, #a.name + 1) == a.name .. \" \" and t:sub(#a.name + 2) or nil\r\nif rest and (rest:match(\"^[%+%-]%d+$\") or rest == \"쓰러짐\") then hpChange = true end\r\nend\r\nif not (fight and hpChange) then chips[#chips + 1] = '<span class=\"dnd-chip ' .. esc(e[1] or \"\") .. '\">' .. esc(t) .. '</span>' end\r\nend\r\nlocal n = #Ally.list(pc)\r\nlocal nj = #Quest.load(pc).list\r\nlocal head = '<div class=\"dnd-st\"><div class=\"dnd-hd\"><b>❖ ' .. g(1) .. '</b><span>' .. g(2) .. '</span></div>'\r\n.. ((f[13] or \"\") ~= \"\" and ('<div class=\"dnd-subl\" style=\"margin:2px 0 6px\">◇ ' .. g(13) .. '</div>') or \"\")\r\n.. '<div class=\"dnd-alert ' .. g(4) .. '\">' .. K.condTipHtml(f[3] or \"\") .. '</div>'\r\n.. '<div class=\"dnd-ctabs\">' .. K.Card.tabBtn(\"상태\", \"dnd_card_st\", tab ~= \"pt\" and tab ~= \"jb\")\r\n.. K.Card.tabBtn(\"동료\" .. (n > 0 and (\"<i>\" .. n .. \"</i>\") or \"\"), \"dnd_card_pt\", tab == \"pt\")\r\n\r\n.. K.Card.tabBtn(\"의뢰\" .. (nj > 0 and (\"<i>\" .. nj .. \"</i>\") or \"\"), \"dnd_card_jb\", tab == \"jb\") .. '</div><div class=\"dnd-cbody\">'\r\nif tab == \"pt\" then return head .. K.Card.party(id, pc, fight) .. '</div></div>' end\r\nif tab == \"jb\" then return head .. K.Card.jobs(pc) .. '</div></div>' end\r\nlocal more = K.canDo(sh, fight, fight and pcStats(pc).speed or nil)\r\n.. string.format('<div class=\"dnd-feat-t\">%s</div><div>감지 %d · 통찰 %d · 수사 %d</div>',\r\ntipSpan(\"상시 판정\", \"일부러 찾지 않을 때 알아채는 점수. 10 + 기술 수정치.\"),\r\n10 + bonusFor(\"Perception\"), 10 + bonusFor(\"Insight\"), 10 + bonusFor(\"Investigation\"))\r\nlocal folds = '<details class=\"dnd-fold\"><summary></summary><div class=\"dnd-items\">' .. packH .. K.otherGearHtml(sh) .. '</div></details>'\r\n.. '<details class=\"dnd-fold feat\"><summary></summary><div class=\"dnd-items\">' .. more .. '</div></details>'\r\nlocal deltaRow = #chips > 0 and ('<div class=\"dnd-delta\"><span class=\"dnd-l\">이번 턴</span>' .. table.concat(chips) .. '</div>') or \"\"\r\nif fight then return head .. deltaRow .. K.Card.fight(id, pc, c, sh) .. folds .. '</div></div>' end\r\nlocal party = {}\r\nfor _, a in ipairs(Ally.list(pc)) do\r\nparty[#party + 1] = K.Card.unit({ name = a.name, sub = Ally.clsKo(a) .. (Ally.unloaded(a) and \" · 클래스 모듈 없음\" or \"\"), hp = a.hp, max = a.max, thp = a.thp,\r\nhpText = a.dead and \"사망\" or (a.hp .. \"/\" .. a.max), dim = a.dead, chips = K.Card.recChips(a), ar = (not a.dead) and K.Card.arRow(a, pc) or nil })\r\nend\r\nlocal uses = K.Card.uses(pc.res, not K.LITE and pc.hd or nil, pc.level) .. K.Card.longRest(pc, loadClock(id))\r\nreturn head .. deltaRow\r\n.. '<div class=\"dnd-grid\"><div><span class=\"dnd-l\">생명력</span><span class=\"dnd-v\">' .. g(5) .. '</span>'\r\n.. '<div class=\"dnd-bar\"' .. ((tonumber(pc.thp) or 0) > 0 and ' style=\"position:relative\"' or \"\") .. '><div class=\"dnd-fill\" style=\"width:' .. g(6) .. '%\"></div>'\r\n.. K.Card.shield(pc.hp, pc.max, pc.thp, \"div\") .. '</div>'\r\n.. K.Card.hpChips(pc) .. '</div>'\r\n.. '<div class=\"dnd-xp\"><span class=\"dnd-l\">경험치</span><span class=\"dnd-v\">' .. g(7) .. '</span>'\r\n.. '<div class=\"dnd-bar\"><div class=\"dnd-fill\" style=\"width:' .. g(8) .. '%\"></div></div></div>' .. K.Card.arLine(pc) .. '</div>'\r\n.. (#party > 0 and ('<div class=\"dnd-sec\"><span class=\"dnd-l\">동료</span><div class=\"dnd-units\">' .. table.concat(party) .. '</div></div>') or \"\")\r\n.. K.Card.sceneSec(pc)\r\n.. '<div class=\"dnd-sec\"><span class=\"dnd-l\">장비</span>' .. eqH .. '</div>'\r\n.. (K.Card.hasSpells(sh) and ('<div class=\"dnd-sec\">' .. K.Card.spells(sh, pc, K.Card.prepOpt(id, sh, pc, idx)) .. '</div>') or \"\")\r\n.. '<div class=\"dnd-sec\"><span class=\"dnd-l\">자원</span>' .. uses .. '</div>'\r\n.. '<div class=\"dnd-sec\"><span class=\"dnd-l\">지갑</span>' .. g(11) .. '</div>'\r\n.. folds .. '</div></div>'\r\nend\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\nfunction Shop.rng(seed)\r\nlocal x = seed % 2147483648\r\nreturn function(n)\r\nx = (1103515245 * x + 12345) % 2147483648\r\nreturn x % n + 1\r\nend\r\nend\r\n\r\n\r\n\r\nfunction Shop.refresh(pc, clock, salt)\r\nlocal day = clockParts(clock.min).day\r\nif type(pc.shop) == \"table\" and pc.shop.day == day then Shop.modSlots(pc, day, salt); return end\r\nlocal pick = Shop.rng(day * 7919 + salt)\r\nlocal pool = {}\r\nfor _, g in ipairs(Shop.GOODS) do pool[#pool + 1] = g end\r\nlocal names = {}\r\nfor n in pairs(WEAPONS) do if not Shop.NO_SALE[n] then names[#names + 1] = n end end\r\nfor n in pairs(ARMOR) do names[#names + 1] = n end\r\ntable.sort(names)\r\nfor _, n in ipairs(names) do pool[#pool + 1] = { n, 1 } end\r\nlocal stock = {}\r\nfor _, g in ipairs(Shop.STAPLE) do stock[#stock + 1] = { name = g[1], n = g[2], staple = true } end\r\nfor _ = 1, Shop.DAILY do\r\nif #pool == 0 then break end\r\nlocal g = table.remove(pool, pick(#pool))\r\nstock[#stock + 1] = { name = g[1], n = g[2] }\r\nend\r\npc.shop = { day = day, stock = stock }\r\nShop.modSlots(pc, day, salt)\r\nend\r\n\r\n\r\n\r\nfunction Shop.modOk(name)\r\nlocal m = K.MAGIC and K.MAGIC[name]\r\nreturn type(m) == \"table\" and m.pack and not K.d2need(m) and not m.cursed and (m.mundane or m.r == \"C\") and type(m.var) ~= \"table\"\r\nand K.MI.parse(name) ~= nil or false\r\nend\r\nfunction Shop.modSlots(pc, day, salt)\r\nif type(pc.shop) ~= \"table\" or pc.shop.mod then return end\r\nlocal pool = {}\r\nfor n in pairs(K.MAGIC or {}) do if Shop.modOk(n) then pool[#pool + 1] = n end end\r\nif #pool == 0 then return end\r\ntable.sort(pool)\r\nlocal pick = Shop.rng(day * 7919 + salt + 104729)\r\nfor _ = 1, Shop.MOD_DAILY do\r\nif #pool == 0 then break end\r\npc.shop.stock[#pc.shop.stock + 1] = { name = table.remove(pool, pick(#pool)), n = 1, mod = true }\r\nend\r\npc.shop.mod = true\r\nend\r\n\r\nfunction Shop.modPrice(name)\r\nlocal m = K.MAGIC and K.MAGIC[name]\r\nif type(m) ~= \"table\" or not m.pack then return nil end\r\nif m.mundane then return coinsOf(m.cost) end\r\nlocal cons = m.cat == \"Potion\" or (type(m.use) == \"table\" and not m.use.day and not K.MI.keeps(m))\r\nreturn math.floor((K.MI.VALUE[m.r] or 0) * (cons and 0.5 or 1))\r\nend\r\n\r\nfunction Shop.price(name, n)\r\nreturn math.max(1, math.floor((PRICE[name] or Shop.modPrice(name) or 0) * n * Shop.MUL + 0.5))\r\nend\r\n\r\n\r\nfunction Shop.sellable(pc)\r\nlocal out = {}\r\nfor name, n in pairs(type(pc.items) == \"table\" and pc.items or {}) do\r\nlocal free = n - equippedCount(pc.equip or {}, name)\r\nif free > 0 and PRICE[name] and not isLoot(pc, name) and not K.AMMO[name] then\r\nout[#out + 1] = name\r\nend\r\nend\r\ntable.sort(out)\r\nreturn out\r\nend\r\n\r\n\r\nfunction Shop.apply(pc, act, key, name)\r\npc.shop_log = type(pc.shop_log) == \"table\" and pc.shop_log or {}\r\nif act == \"buy\" then\r\nlocal slot = type(pc.shop) == \"table\" and pc.shop.stock and pc.shop.stock[tonumber(key)]\r\nif not slot or slot.sold or (name and slot.name ~= name) then return false end\r\nlocal cost = Shop.price(slot.name, slot.n)\r\nif pc.cp < cost then return false end\r\n\r\nlocal got = slot.name\r\nif slot.mod then\r\nif not Shop.modOk(slot.name) then return false end\r\ngot = K.MI.ensure(pc, slot.name)\r\nif not got then return false end\r\nend\r\npc.cp = pc.cp - cost\r\npc.items[got] = (pc.items[got] or 0) + slot.n\r\nif not slot.staple then slot.sold = true end\r\npc.shop_log[#pc.shop_log + 1] = { \"bought\", slot.name, slot.n, cost }\r\nreturn true\r\nend\r\nlocal name = key\r\nlocal okName = false\r\nfor _, n in ipairs(Shop.sellable(pc)) do if n == name then okName = true end end\r\nif not okName then return false end\r\nlocal got = math.floor(Shop.price(name, 1) * Shop.SELL)\r\npc.items[name] = pc.items[name] - 1\r\nif pc.items[name] <= 0 then pc.items[name] = nil end\r\npc.cp = pc.cp + got\r\npc.shop_log[#pc.shop_log + 1] = { \"sold\", name, 1, got }\r\nreturn true\r\nend\r\n\r\n\r\nShop.ARMOR_KO = { light = \"경갑\", medium = \"평갑\", heavy = \"중갑\" }\r\n\r\n\r\nfunction Shop.note(pc, name, selling)\r\nlocal o = {}\r\nlocal w, a = WEAPONS[name], ARMOR[name]\r\nlocal function avg(d)\r\nlocal n, x = (d or \"\"):match(\"^(%d*)d(%d+)\")\r\nreturn n and (tonumber(n ~= \"\" and n or 1) or 1) * ((tonumber(x) or 0) + 1) / 2 or 0\r\nend\r\nif w then\r\no[#o + 1] = weaponProf(w) and \"숙련 있음\" or \"숙련 없음 (명중에 숙련 보너스를 더하지 못합니다)\"\r\nlocal best, bestName\r\nfor n2 in pairs(pc.items or {}) do\r\nlocal w2 = WEAPONS[n2]\r\nif n2 ~= name and w2 and (w2.ranged or false) == (w.ranged or false) and weaponProf(w2) and (not best or avg(w2.dmg) > best) then\r\nbest, bestName = avg(w2.dmg), n2\r\nend\r\nend\r\nif best then\r\nif selling and best > avg(w.dmg) then\r\no[#o + 1] = \"가진 \" .. koName(bestName) .. \" 쪽이 더 강합니다\"\r\nelseif not selling then\r\no[#o + 1] = avg(w.dmg) > best and (\"가진 \" .. koName(bestName) .. \"보다 피해 큼\")\r\nor avg(w.dmg) < best and (\"가진 \" .. koName(bestName) .. \"보다 피해 작음\") or (\"피해는 가진 \" .. koName(bestName) .. \" 정도\")\r\nend\r\nend\r\nelseif a and a.cat ~= \"shield\" then\r\no[#o + 1] = armorProf(a.cat) and \"숙련 있음\" or \"숙련 없음 (입으면 판정·공격에 불리점, 주문 못 씀)\"\r\nlocal function acOf(x) return x.base + (x.dex == \"full\" and MOD.Dexterity or x.dex == \"max2\" and math.min(K.dexCap(SHEET, x.cat), MOD.Dexterity) or 0) end\r\nlocal cur = pc.equip and pc.equip.armor and ARMOR[pc.equip.armor]\r\nlocal now = cur and acOf(cur) or (10 + MOD.Dexterity)\r\nlocal mine = acOf(a)\r\nif not selling then\r\no[#o + 1] = mine > now and string.format(\"지금보다 방어도 +%d\", mine - now) or mine < now and string.format(\"지금보다 방어도 %d\", mine - now) or \"지금과 방어도 같음\"\r\nend\r\nif a.str and SCORE.Strength < a.str then o[#o + 1] = \"근력 \" .. a.str .. \" 미만이라 속도 -10피트\" end\r\nend\r\nreturn table.concat(o, \" · \")\r\nend\r\n\r\nfunction Shop.kind(name)\r\nlocal a = ARMOR[name]\r\nif a then\r\nif a.cat == \"shield\" then return \"방패 · 방어도 +2\" end\r\nlocal ac = a.dex == \"full\" and (a.base .. \"+민첩\") or a.dex == \"max2\" and (a.base .. \"+민첩(최대 \" .. K.dexCap(SHEET, a.cat) .. \")\") or tostring(a.base)\r\nreturn (Shop.ARMOR_KO[a.cat] or \"갑옷\") .. \" · 방어도 \" .. ac\r\nend\r\nlocal w = WEAPONS[name]\r\nif w then\r\nreturn (w.martial and \"군용 \" or \"단순 \") .. (w.ranged and \"원거리\" or \"근접\") .. \" 무기 · \" .. w.dmg .. \" \" .. (DAMAGE_KO[w.type] or w.type or \"\")\r\nend\r\nlocal m = K.MAGIC and K.MAGIC[name]\r\nif type(m) == \"table\" and m.pack then return m.mundane and \"모듈 물건\" or (\"모듈 물건 · \" .. (K.MI.RAR_KO[m.r] or \"\") .. \" 마법 물건\") end\r\nreturn \"\"\r\nend\r\n\r\n\r\nfunction Shop.text(pc)\r\nlocal log = type(pc.shop_log) == \"table\" and pc.shop_log or {}\r\nif #log == 0 then return nil end\r\nlocal parts = {}\r\nfor _, e in ipairs(log) do\r\nparts[#parts + 1] = string.format(\"%s %s%s for %s\", e[1], (e[3] or 1) > 1 and (e[3] .. \" \") or \"\", e[2], moneyText(e[4] or 0))\r\nend\r\nreturn \"[SHOP] Since the last reply Player \" .. table.concat(parts, \", \") .. \" at a merchant (the drawer's shop).\"\r\n.. \" It is already paid and in the pack: if it fits the scene, narrate only the handover; never charge, pay or write BUY, SELL, ITEM or GOLD for it again.\"\r\nend\r\n\r\n\r\n\r\n\r\n\r\nShop.LINE = \"(상인에게 \"\r\nShop.LINE_EN = \"(To the merchant: \"\r\nfunction Shop.isLine(m)\r\nlocal d = type(m) == \"table\" and m.role == \"user\" and tostring(m.data or \"\")\r\nreturn d and (d:sub(1, #Shop.LINE) == Shop.LINE or d:sub(1, #Shop.LINE_EN) == Shop.LINE_EN) or false\r\nend\r\n\r\n\r\nfunction K.replyIdx(id)\r\nlocal n = getChatLength(id) - 1\r\nif n >= 1 and Shop.isLine(getChat(id, n)) then return n - 1 end\r\nreturn n\r\nend\r\n\r\n\r\nfunction K.isNewest(id, idx)\r\nif not idx or idx < 0 then return false end\r\nlocal n = getChatLength(id) - 1\r\nreturn idx == n or (idx == n - 1 and Shop.isLine(getChat(id, n)))\r\nend\r\n\r\n\r\nfunction Shop.say(e)\r\nlocal name = koName(e[2] or \"\")\r\nlocal what = e[1] == \"sold\" and (name .. \" 하나\") or ((e[3] or 1) > 1 and (name .. \" \" .. e[3] .. \"개\") or name)\r\nreturn what .. K.josa(what, \"을\", \"를\") .. \" \" .. moneyKo(e[4] or 0):gsub(\" · \", \" \") .. \"에 \" .. (e[1] == \"sold\" and \"판다\" or \"산다\")\r\nend\r\n\r\n\r\nfunction Shop.sayEn(e)\r\nlocal name = e[2] or \"\"\r\nlocal what = e[1] == \"sold\" and (\"one \" .. name) or ((e[3] or 1) > 1 and (e[3] .. \" \" .. name) or name)\r\nreturn (e[1] == \"sold\" and \"sell \" or \"buy \") .. what .. \" for \" .. moneyText(e[4] or 0)\r\nend\r\n\r\n\r\n\r\nfunction Shop.post(id, e)\r\nlocal n = getChatLength(id) - 1\r\nlocal last = n >= 0 and getChat(id, n)\r\nif not last or not e then return end\r\nlocal en = K.En.on(id)\r\nlocal part = en and Shop.sayEn(e) or Shop.say(e)\r\nlocal LINE = en and Shop.LINE_EN or Shop.LINE\r\nif Shop.isLine(last) then\r\nlocal t = tostring(last.data)\r\nlocal head, close = t:match(\"^(.-)(%)%s*)$\")\r\nsetChat(id, n, head and (head .. \", \" .. part .. close) or (t .. \"\\n\" .. LINE .. part .. \")\"))\r\npcall(reloadChat, id, n)\r\nelseif last.role ~= \"user\" then\r\naddChat(id, \"user\", LINE .. part .. \")\")\r\nend\r\nend\r\n\r\n\r\nfunction Shop.pane(id)\r\nlocal pc, c = loadPC(id), loadCombat(id)\r\nif c.active then return '<div class=\"dnd-empty\">전투 중에는 상점이 닫혀 있습니다.</div>' end\r\nif pc.place == \"wild\" then return '<div class=\"dnd-empty\">마을에 있을 때만 열립니다. 마을에 들어서면 다시 열립니다.</div>' end\r\nif type(pc.shop) ~= \"table\" or BTN_FIRST then return '<div class=\"dnd-empty\">첫 답이 오면 상점이 열립니다.</div>' end\r\nlocal b = {}\r\nlocal chosen = getChatVar(id, \"dnd_shop_pick\")\r\nb[#b + 1] = '<div class=\"dnd-opt-d\">근처 상인에게 사고팝니다. 사고팔면 그 내용이 내 메시지로 채팅에 들어가고, 보내기를 누르면 AI가 건네받는 장면을 씁니다.'\r\n.. ' 진열은 모험 날짜마다 바뀌고, 산 물건은 그날 다시 들어오지 않습니다 (기본 물건은 늘 있습니다).</div>'\r\n\r\nlocal n = getChatLength(id) - 1\r\nlocal said = n >= 0 and getChat(id, n)\r\nif Shop.isLine(said) then\r\nb[#b + 1] = '<div class=\"dnd-sent\"><span class=\"dnd-sent-l\">채팅에 들어간 내 메시지</span><div>' .. esc(said.data) .. '</div>'\r\n.. '<small>입력창을 비운 채 보내기를 누르면 이어집니다. 더 사고팔면 같은 메시지에 덧붙습니다.</small></div>'\r\nend\r\nb[#b + 1] = '<div class=\"dnd-shop-hd\"><span>지갑</span><b>' .. esc(moneyKo(pc.cp)) .. '</b></div>'\r\nlocal function tip(name, label)\r\nlocal pm = K.MAGIC and K.MAGIC[name]\r\nlocal t = ITEM_TIP[name] or (type(pm) == \"table\" and pm.pack and type(pm.tip) == \"string\" and pm.tip ~= \"\" and pm.tip) or nil\r\nreturn t and tipSpan(label, label .. \"\\n\" .. t) or esc(label)\r\nend\r\n\r\n\r\nlocal function item(name, meta, price, act)\r\nreturn '<div class=\"dnd-item\"><span class=\"dnd-item-n\">' .. name .. '</span>' .. (meta ~= \"\" and ('<span class=\"dnd-item-m\">' .. esc(meta) .. '</span>') or \"\")\r\n.. '<span class=\"dnd-item-p\">' .. esc(price) .. '</span><span class=\"dnd-item-b\">' .. act .. '</span></div>'\r\nend\r\nlocal staple, today = {}, {}\r\nfor i, slot in ipairs(pc.shop.stock) do\r\nlocal cost = Shop.price(slot.name, slot.n)\r\nlocal label = koName(slot.name) .. (slot.n > 1 and (\" ×\" .. slot.n) or \"\")\r\nlocal meta = {}\r\nfor _, x in ipairs({ Shop.kind(slot.name), Shop.note(pc, slot.name, false) }) do if x ~= \"\" then meta[#meta + 1] = x end end\r\nlocal act\r\nif slot.sold then\r\nact = '<span class=\"dnd-m\">품절</span>'\r\nelseif pc.cp < cost then\r\nact = '<span class=\"dnd-m\">돈 부족</span>'\r\nelseif chosen == \"b\" .. i then\r\nact = btn(\"사기 확인\", \"dnd_shop_buy_\" .. i, true) .. btn(\"취소\", \"dnd_shop_cancel\", false)\r\nelse\r\nact = btn(\"사기\", \"dnd_shop_pickb_\" .. i, false)\r\nend\r\nlocal row = item(tip(slot.name, label), table.concat(meta, \" · \"), moneyKo(cost), act)\r\nif slot.mod and not Shop.modOk(slot.name) then\r\nelseif slot.staple then staple[#staple + 1] = row else today[#today + 1] = row end\r\nend\r\nb[#b + 1] = '<div class=\"dnd-grp\">늘 있는 것</div>' .. table.concat(staple)\r\nb[#b + 1] = '<div class=\"dnd-grp\">오늘 들어온 것 · ' .. clockParts(loadClock(id).min).day .. '일째</div>'\r\n.. (#today > 0 and table.concat(today) or '<div class=\"dnd-opt-d\">오늘 들어온 물건이 없습니다.</div>')\r\nlocal sell = Shop.sellable(pc)\r\nb[#b + 1] = '<div class=\"dnd-grp\">팔기 · 값의 절반 (손에 든 것과 입은 것은 빼고)</div>'\r\nif #sell == 0 then b[#b + 1] = '<div class=\"dnd-opt-d\">팔 수 있는 물건이 없습니다.</div>' end\r\nfor _, name in ipairs(sell) do\r\nlocal got = math.floor(Shop.price(name, 1) * Shop.SELL)\r\nlocal key = name:gsub(\" \", \"_\"):gsub(\"'\", \"\")\r\nlocal act = chosen == \"s\" .. key and (btn(\"팔기 확인\", \"dnd_shop_sell_\" .. key, true) .. btn(\"취소\", \"dnd_shop_cancel\", false))\r\nor btn(\"팔기\", \"dnd_shop_picks_\" .. key, false)\r\nb[#b + 1] = item(tip(name, koName(name) .. \" ×\" .. pc.items[name]), Shop.note(pc, name, true), \"한 개 \" .. moneyKo(got), act)\r\nend\r\nreturn table.concat(b)\r\nend\r\n\r\n\r\n\r\n\r\n\r\nfunction Ally.giveClick(id, data)\r\nlocal act, i, k, tag = data:match(\"^dnd_(%a+)_(%d+)_(%d+)_(%x+)$\")\r\nif not act then act, i, k = data:match(\"^dnd_(%a+)_(%d+)_(%d+)$\") end\r\nsetChatVar(id, \"dnd_card_tab\", \"pt@\" .. K.replyIdx(id))\r\nif not act or loadCombat(id).active then return end\r\ni, k = tonumber(i), tonumber(k)\r\nlocal sh0 = loadSheet(id)\r\napplySheet(sh0)\r\nlocal pc = loadPC(id)\r\nlocal a = Ally.list(pc)[i]\r\nif not a or a.dead then return end\r\nlocal name = Ally.gearList(act == \"give\" and pc or a)[k]\r\nif not name then return end\r\nif tag and tag ~= K.nameTag(a.name) .. K.nameTag(name) then return end\r\nlocal who = a.name\r\nlocal function op(s)\r\nlocal p = s.pc\r\nlocal b = Ally.list(p)[i]\r\nif not b or b.name ~= who or b.dead then return false end\r\nlocal okm\r\nif act == \"give\" then okm = Ally.move(p, p, b, name, 1, false) else okm = Ally.move(p, b, p, name, 1, false) end\r\n\r\nif okm then K.MI.syncAll(p, s.sheet or sh0) end\r\nreturn okm\r\nend\r\nif not op({ pc = pc }) then return end\r\nsetState(id, \"dnd_pc\", pc)\r\nsetStateChanged(id, \"dnd_sheet\", sh0)\r\nsyncBases(id, op)\r\nredrawStatus(id, pc, loadClock(id))\r\nend\r\n\r\n\r\n\r\nfunction Ally.lvPickClick(id, data)\r\nlocal i, tag, cls = data:match(\"^dnd_alvcls_(%d+)_(%x+)_(%a+)$\")\r\nif not i then i, cls = data:match(\"^dnd_alvcls_(%d+)_(%a+)$\") end\r\nsetChatVar(id, \"dnd_card_tab\", \"pt@\" .. K.replyIdx(id))\r\ni = tonumber(i)\r\nif not (i and CLASSES[cls or \"\"]) or K.LITE then return end\r\nlocal sh0 = loadSheet(id)\r\napplySheet(sh0)\r\nlocal pc = loadPC(id)\r\nlocal a = Ally.list(pc)[i]\r\nif not a or a.dead or (tag and K.nameTag(a.name) ~= tag) then return end\r\nlocal who = a.name\r\nlocal function op(s)\r\nlocal b = Ally.list(s.pc)[i]\r\nif not b or b.name ~= who or b.dead then return false end\r\nif cls ~= b.sheet.class and not K.mcCan(b.sheet, cls) then return false end\r\nb.lvPick = cls ~= b.sheet.class and cls or nil\r\nreturn true\r\nend\r\nif not op({ pc = pc }) then return end\r\nsetState(id, \"dnd_pc\", pc)\r\nsyncBases(id, op)\r\nend\r\n\r\nfunction Shop.click(id, data)\r\nsetChatVar(id, \"dnd_drawer_open\", \"1\")\r\nsetChatVar(id, \"dnd_drawer_tab\", \"5\")\r\nif data == \"dnd_shop_cancel\" then setChatVar(id, \"dnd_shop_pick\", \"\"); return end\r\nlocal pb = data:match(\"^dnd_shop_pickb_(%d+)$\")\r\nlocal ps = data:match(\"^dnd_shop_picks_(.+)$\")\r\nif pb then setChatVar(id, \"dnd_shop_pick\", \"b\" .. pb); return end\r\nif ps then setChatVar(id, \"dnd_shop_pick\", \"s\" .. ps); return end\r\nsetChatVar(id, \"dnd_shop_pick\", \"\")\r\nif loadCombat(id).active then return end\r\nif loadPC(id).place == \"wild\" then return end\r\nlocal act, key = data:match(\"^dnd_shop_(%a+)_(.+)$\")\r\nif act ~= \"buy\" and act ~= \"sell\" then return end\r\nlocal sh = loadSheet(id)\r\napplySheet(sh)\r\nlocal pc = loadPC(id)\r\nif act == \"sell\" then\r\n\r\nfor _, n in ipairs(Shop.sellable(pc)) do\r\nif (n:gsub(\" \", \"_\"):gsub(\"'\", \"\")) == key then key = n end\r\nend\r\nend\r\nlocal slot = act == \"buy\" and type(pc.shop) == \"table\" and pc.shop.stock and pc.shop.stock[tonumber(key)]\r\nlocal name = slot and slot.name\r\nif not Shop.apply(pc, act, key, name) then return end\r\nsetState(id, \"dnd_pc\", pc)\r\nsyncBases(id, function(s) return Shop.apply(s.pc, act, key, name) end)\r\nredrawStatus(id, pc, loadClock(id))\r\npcall(Shop.post, id, pc.shop_log[#pc.shop_log])\r\nend\r\n\r\n\r\nfunction K.combatRow(id)\r\nlocal v = K.combatW(id)\r\nreturn '<div class=\"dnd-opt\"><div class=\"dnd-opt-t\">⚔ 전투 비중</div><div class=\"dnd-opt-d\">적게: 갈등을 대화·꾀·판정으로 먼저 풀고, 싸움은 원하거나 피할 수 없을 때만 납니다. 의뢰에 전투 단계가 없고, 우두머리도 말이나 꾀로 풀 수 있습니다.<br>'\r\n.. '보통: 지금까지와 같습니다.<br>많게: 위험이 자주 찾아오고 싸움으로 이어지는 장면이 늘어납니다. 의뢰에 전투 단계가 둘 들어갑니다.<br>어느 쪽이든 직접 싸움을 걸면 싸움이 납니다.</div>'\r\n.. '<div class=\"dnd-opt-btns\">' .. btn(\"적게\", \"dnd_combat_low\", v == \"low\") .. btn(\"보통\", \"dnd_combat_mid\", v == \"mid\")\r\n.. btn(\"많게\", \"dnd_combat_high\", v == \"high\") .. '</div></div>'\r\nend\r\n\r\n\r\n\r\n\r\n\r\n\r\nfunction K.srdX() return #K.expansionNames() > 0 and \"SRD or rule-expansion\" or \"SRD\" end\r\nfunction K.expansionNames()\r\nlocal o = {}\r\nfor _, x in ipairs(K.PACK.list or {}) do\r\nif x.ok and not (x.notes and x.notes[1] == \"off on the settings tab (adult module)\") then\r\nlocal nm = trim((tostring(x.name or \"\"):gsub(\"%s+v%d+%.%d+%s+%d+:%d+%s*$\", \"\")))\r\nif nm ~= \"\" and nm ~= \"?\" then o[#o + 1] = nm end\r\nend\r\nend\r\nreturn o\r\nend\r\nfunction K.expansionLine()\r\nlocal o = K.expansionNames()\r\nif #o == 0 then return nil end\r\nreturn \"Rule expansions in this game (data the user added beyond the SRD 5.2.1): \" .. table.concat(o, \"; \") .. \". Their classes,\"\r\n.. \" subclasses, species, backgrounds, feats, spells, items and creatures are this game's rules as much as the SRD's: in table talk\"\r\n.. \" (OOC) answer and offer from both, and where this request lists the options for a choice, that list is the whole set. Do not\"\r\n.. \" make up an expansion's content: what this request does not show, say you cannot see it from here.\"\r\n\r\n.. \" Where the GM rules say SRD (monsters and stat blocks, names in tags, conditions, items), an expansion's count the same.\"\r\nend\r\n\r\nfunction K.packTabOn()\r\nreturn (K.PACK.d2 or K.PACK.adultOn or K.PACK.adultOff or #(K.PACK.list or {}) > 0) and true or false\r\nend\r\n\r\nfunction K.packReadRow()\r\nlocal o = {}\r\nfor _, x in ipairs(K.PACK.list or {}) do\r\no[#o + 1] = esc(tostring(x.name)) .. ((x.notes and x.notes[1] == \"off on the settings tab (adult module)\") and \" (꺼 둠)\"\r\nor (not x.ok and \" (읽기 실패)\" or \"\"))\r\nend\r\nreturn '<div class=\"dnd-opt\"><div class=\"dnd-opt-t\">❖ 읽은 모듈</div><div class=\"dnd-opt-d\">' .. (#o > 0 and table.concat(o, \"<br>\") or \"없음\")\r\n.. '<br>새 판을 넣었는데 이름이 그대로면 위의 다시 읽기를 눌러 주십시오.</div></div>'\r\nend\r\nfunction K.packReloadRow()\r\nreturn '<div class=\"dnd-opt\"><div class=\"dnd-opt-t\">⟳ 모듈 다시 읽기</div><div class=\"dnd-opt-d\">큰 모듈(성인 DLC, PHB 같은 것)은 보낼 때마다 다시 읽지 않습니다(한 번에 1~2초).'\r\n.. ' 모듈을 켜거나 끄거나 새 판으로 바꿨으면 눌러 주십시오.</div><div class=\"dnd-opt-btns\">' .. btn(\"다시 읽기\", \"dnd_pack_reload\", false) .. '</div></div>'\r\nend\r\n\r\nfunction K.diffRows(id)\r\nlocal cd, fd = K.checkD(id), K.fightD(id)\r\n\r\nreturn '<div class=\"dnd-opt\"><div class=\"dnd-opt-t\">🎲 주사위 주작 방지</div><div class=\"dnd-opt-d\">켬: 난이도는 일 자체로 주사위를 보기 전에 정하고, 굴린 결과대로 갑니다.'\r\n.. ' 성공을 쉽게 만들려고 난이도·굴림·적의 행동·결과를 비틀지 않습니다.'\r\n.. ' 주사위를 써 버리려고 쓸데없는 판정이나 움직임을 넣지 않고, 누구든 실제로 할 법한 대로 움직입니다(원거리 적은 위험한 곳을 건너오지 않고 쏩니다).'\r\n.. ' 곤경은 이야기 속 사정에서만 생기고, 해결한 위협은 해결된 채로 둡니다. 이 지침은 주사위 풀 바로 아래에 들어갑니다.<br>'\r\n.. '끔: 이런 지침을 넣지 않습니다. AI가 알아서 합니다.<br>어느 쪽이든 난이도 숫자는 Lua가 고치지 않습니다.</div>'\r\n.. '<div class=\"dnd-opt-btns\">' .. btn(\"끔\", \"dnd_checkd_easy\", cd == \"easy\") .. btn(\"켬\", \"dnd_checkd_mid\", cd ~= \"easy\") .. '</div></div>'\r\n.. '<div class=\"dnd-opt\"><div class=\"dnd-opt-t\">⚔ 전투 난이도</div><div class=\"dnd-opt-d\">쉬움: 한 싸움의 적은 보통 예산까지, 준비된 싸움은 낮은 예산으로 짭니다.<br>'\r\n.. '보통: 지금까지와 같습니다(어려움 예산까지).<br>어려움: 어려움 예산의 1.5배까지, 준비된 싸움도 어려움 예산으로 짭니다.<br>예산을 넘는 적은 Lua가 뺍니다(이야기가 이미 보여 준 절망적인 싸움은 예외).</div>'\r\n.. '<div class=\"dnd-opt-btns\">' .. btn(\"쉬움\", \"dnd_fightd_easy\", fd == \"easy\") .. btn(\"보통\", \"dnd_fightd_mid\", fd == \"mid\") .. btn(\"어려움\", \"dnd_fightd_hard\", fd == \"hard\") .. '</div></div>'\r\nend\r\n\r\nfunction K.checkRow(id)\r\nlocal v = K.checkW(id)\r\nreturn '<div class=\"dnd-opt\"><div class=\"dnd-opt-t\">⚄ 판정 빈도</div><div class=\"dnd-opt-d\">적게: 위험이나 큰 갈림길에서만 굴리고, 나머지는 하는 대로 이뤄집니다.<br>'\r\n.. '보통: 지금까지와 같습니다. 결과가 불확실하고 실패에 대가가 있을 때 굴립니다.<br>'\r\n.. '많게: 찾기·오르기·숨기·속마음 읽기·까다로운 대화처럼 결과가 조금이라도 불확실하면 굴립니다. 걷기·사기 같은 평범한 행동과 이야기에 꼭 필요한 단서는 굴리지 않습니다.</div>'\r\n.. '<div class=\"dnd-opt-btns\">' .. btn(\"적게\", \"dnd_checkw_low\", v == \"low\") .. btn(\"보통\", \"dnd_checkw_mid\", v == \"mid\")\r\n.. btn(\"많게\", \"dnd_checkw_high\", v == \"high\") .. '</div></div>'\r\nend\r\n\r\n\r\nfunction Feat.d2Row(id)\r\n\r\nlocal modeBtns = function(cur)\r\nreturn '<div class=\"dnd-opt-btns\">' .. btn(\"끄기\", \"dnd_d2_off\", cur == \"off\") .. btn(\"순한맛\", \"dnd_d2_mild\", cur == \"mild\") .. btn(\"하드코어\", \"dnd_d2_hard\", cur == \"hard\") .. '</div>'\r\nend\r\nif K.PACK.adultOff and not K.PACK.d2 then\r\nreturn '<div class=\"dnd-opt\"><div class=\"dnd-opt-t\">🔞 성인 모듈</div><div class=\"dnd-opt-d\">끄기: 이 채팅에서는 모듈을 넣지 않은 것과 같습니다.'\r\n.. ' 그 모듈의 클래스·하위 클래스·종족 캐릭터는 다시 켤 때까지 잠기고, 쌓인 수치는 그대로 남아 켜면 이어집니다.</div>' .. modeBtns(\"off\") .. '</div>'\r\nend\r\nif not (K.PACK.d2 or K.PACK.adultOn) then return \"\" end\r\nlocal mode = getChatVar(id, \"dnd_dlc_mode\") == \"hard\" and \"hard\" or \"mild\"\r\nlocal perm = getChatVar(id, \"dnd_dlc_perm\") == \"on\" and \"on\" or \"off\"\r\nlocal furry, xeno = getChatVar(id, \"dnd_dlc_furry\"), getChatVar(id, \"dnd_dlc_xeno\")\r\nlocal lvdown = getChatVar(id, \"dnd_dlc_lvdown\")\r\nlocal hitomi = getChatVar(id, \"dnd_dlc_hitomi\")\r\nlocal omega = getChatVar(id, \"dnd_dlc_omega\")\r\n\r\nlocal function onOff(key, on)\r\nreturn '<div class=\"dnd-opt-btns\">' .. btn(\"끔\", \"dnd_d2\" .. key .. \"_off\", not on) .. btn(\"켬\", \"dnd_d2\" .. key .. \"_on\", on) .. '</div>'\r\nend\r\nlocal function block(title, desc, btns)\r\nreturn '<div class=\"dnd-opt\"><div class=\"dnd-opt-t\">' .. title .. '</div><div class=\"dnd-opt-d\">' .. desc .. '</div>' .. btns .. '</div>'\r\nend\r\nreturn block(\"🔞 성인 모듈\", '끄기: 이 채팅에서는 모듈을 넣지 않은 것과 같습니다.<br>순한맛: 하드코어 표시가 있는 하위 클래스·주문·배경 같은 것을'\r\n.. ' 새로 고를 수 없습니다. 이미 고른 것은 그대로 작동합니다.<br>하드코어: 모두 고를 수 있습니다.', modeBtns(mode))\r\n.. block(\"∞ 영구 결과\", '배드 엔드, 영구 능력치 감소, 영구 변형 표시가 있는 것을 새로 고를지 두 모드 어디서든 따로 정합니다.', onOff(\"perm\", perm == \"on\"))\r\n\r\n.. block(\"↓ 레벨 깎기\", '영구 결과가 켜져 있을 때, 배드 엔드가 클래스 레벨 하나도 가져갈지 정합니다. 끄면 이야기 결과만 남습니다.', onOff(\"lvdown\", lvdown == \"on\"))\r\n\r\n.. block(\"⇕ 히토미 물리학\", '켜면 크기 제한이 없습니다. 무엇이든 다 들어가고, 체격 차이의 자극 보정은 남습니다.', onOff(\"hitomi\", hitomi == \"on\"))\r\n\r\n.. block(\"✿ 퍼리\", '퍼리 표시가 있는 것을 새로 고를지 따로 정합니다(고양이 귀·꼬리 같은 것은 표시 없이 늘 들어갑니다).', onOff(\"furry\", furry == \"on\"))\r\n.. block(\"✧ 이종\", '이종 표시가 있는 것을 새로 고를지 따로 정합니다.', onOff(\"xeno\", xeno == \"on\"))\r\n\r\n.. block(\"⚥ 오메가버스 세계\", '켜면 모든 인간형에게 알파·베타·오메가 2차 성별이 있습니다. 캐릭터 탭과 동료 탭에서 고릅니다.', onOff(\"omega\", omega == \"on\"))\r\nend\r\n\r\n\r\nfunction Feat.deathRow(id)\r\nlocal v = Feat.deathRule(id)\r\nreturn '<div class=\"dnd-opt\"><div class=\"dnd-opt-t\">☠ 쓰러지면</div><div class=\"dnd-opt-d\">SRD: 죽음 내성을 굴립니다 (실패 셋이면 사망). 쓰러지고도 최대 생명력 이상의 피해가 남거나, 쓰러진 채 그만큼 맞으면 즉사합니다.<br>'\r\n.. '너그럽게: 기절만 하고 죽지 않습니다. 싸움이 끝나면 다음 답에서 생명력 1로 깨어납니다. 파티가 다 쓰러지면 싸움에 지고, 적은 그냥 떠나거나 가진 것을 털어 가거나 붙잡아 갑니다. 1시간 뒤 깨어납니다. 동료도 같습니다.<br>가혹하게: 0이 되면 바로 사망합니다.<br>SRD와 가혹하게에서는 누구를 살리려고 싸움·적의 행동·결과를 무르지 말라는 지침이 늘 함께 들어갑니다.</div>'\r\n.. '<div class=\"dnd-opt-btns\">' .. btn(\"SRD\", \"dnd_death_srd\", v == \"srd\") .. btn(\"너그럽게\", \"dnd_death_gentle\", v == \"gentle\")\r\n.. btn(\"가혹하게\", \"dnd_death_harsh\", v == \"harsh\") .. '</div></div>'\r\nend\r\n\r\n\r\n\r\n\r\nK.DICT_DEATH = {\r\nsrd = \"SRD 그대로입니다. 아래 죽음 내성대로 굴립니다. 설정 탭의 ☠ 쓰러지면에서 바꿀 수 있습니다.\",\r\ngentle = \"너그럽게로 정해져 있습니다. 쓰러져도 죽지 않고 기절만 합니다. 싸움이 끝나면 다음 답에서 생명력 1로 깨어납니다. 파티가 다 쓰러지면 싸움에 지고, 적은 그냥 떠나거나 가진 것을 털어 가거나 붙잡아 갑니다. 1시간 뒤 깨어납니다. 아래 죽음 내성은 굴리지 않습니다.\",\r\nharsh = \"가혹하게로 정해져 있습니다. 생명력이 0이 되면 바로 사망합니다. 아래 죽음 내성은 굴리지 않습니다.\",\r\n}\r\nfunction K.dictPane(id)\r\nif not K.DICT_HTML then\r\nlocal d = type(K.DICT) == \"table\" and K.DICT or { groups = {} }\r\nlocal out = { '<div class=\"dnd-dict\">' }\r\nif (d.intro or \"\") ~= \"\" then out[#out + 1] = '<div class=\"dnd-opt-d\">' .. esc(d.intro) .. '</div>' end\r\nfor _, g in ipairs(d.groups or {}) do\r\nout[#out + 1] = '<details class=\"dnd-dict-g\"><summary>' .. esc(g[1]) .. '</summary>'\r\nfor _, e in ipairs(g[2] or {}) do\r\nout[#out + 1] = '<div class=\"dnd-dict-e\"><b>' .. esc(e[1]) .. '</b>'\r\n.. ((e[2] or \"\") ~= \"\" and ('<span class=\"dnd-dict-en\">' .. esc(e[2]) .. '</span>') or \"\")\r\n.. '<div>' .. esc(e[3]) .. '</div></div>'\r\nend\r\nout[#out + 1] = '</details>'\r\nend\r\nout[#out + 1] = '</div>'\r\nK.DICT_HTML = table.concat(out)\r\nend\r\nlocal note = K.DICT_DEATH[Feat.deathRule(id)] or K.DICT_DEATH.srd\r\nreturn (K.DICT_HTML:gsub(\"@DEATH@\", function() return esc(note) end))\r\nend\r\n\r\n\r\n\r\n\r\nlocal function buildDrawer(id, first, sfx, lastId)\r\nBTN_FIRST = first and true or false\r\n\r\nlocal whenNewest = (lastId and lastId ~= sfx) and string.format(\"{{#when::{{lastmessageid}}::is::%d}}\\n\", lastId)\r\nor \"{{#when::{{chat_index}}::is::{{lastmessageid}}}}\\n\"\r\nsfx = \"-\" .. tostring(sfx or \"g\"):gsub(\"[^%w]\", \"m\")\r\nlocal sh = loadSheet(id)\r\napplySheet(sh)\r\nlocal verify = getChatVar(id, \"dnd_last_verify\")\r\nlocal err = getChatVar(id, \"dnd_lua_error\")\r\nlocal info = '<div class=\"dnd-opt-d\">Lua 검증: ' .. esc((verify == \"null\" or not verify) and \"-\" or verify) .. '</div>'\r\n\r\nlocal errTop = (err and err ~= \"\" and err ~= \"null\") and ('<div class=\"dnd-opt-d dnd-err\">Lua 오류: ' .. esc(err) .. '</div>') or \"\"\r\nlocal dbgOn = getChatVar(id, \"dnd_opt_debug\") == \"1\"\r\nlocal tab = getChatVar(id, \"dnd_drawer_tab\")\r\n\r\n\r\n\r\n\r\nlocal adultTab = K.packTabOn()\r\nif tab ~= \"3\" and tab ~= \"5\" and tab ~= \"6\" and not (tab == \"4\" and dbgOn) and not (tab == \"7\" and adultTab) then tab = \"1\" end\r\nlocal function radio(n)\r\nreturn '<input type=\"radio\" name=\"dnd-tab' .. sfx .. '\" id=\"dnd-tab-' .. n .. sfx .. '\" class=\"dnd-rad' .. n .. '\" style=\"display:none\"'\r\n.. (tab == n and \" checked>\" or \">\")\r\nend\r\n\r\n\r\n\r\nlocal open = drawerIsOpen(id) and \" is-open\" or \"\"\r\n\r\nlocal _, expLeft = expertiseChoices(sh)\r\nlocal pending = sh.asi_pending or sh.hp_pending or expLeft > 0 or #Feat.pending(sh, loadPC(id)) > 0 or Feat.miOpen(sh)\r\n\r\n\r\nlocal gear = '<div class=\"dnd-gear\">❖<span class=\"dnd-gear-t\"> 설정</span>' .. (pending and '<i class=\"dnd-gear-dot\"></i>' or \"\")\r\n.. '<span class=\"dnd-hit\">' .. rawBtn(\" \", \"dnd_drawer_toggle\") .. '</span></div>'\r\n\r\n\r\n\r\nif open == \"\" then\r\nlocal bar = '<div class=\"dnd-ui\"><div class=\"dnd-gear-bar\">' .. gear .. '</div></div>'\r\nif first then return bar end\r\nreturn whenNewest .. bar .. \"\\n{{/when}}\"\r\nend\r\n\r\n\r\n\r\n\r\n\r\n\r\nlocal only = not first\r\nlocal function tabLabel(n, text)\r\nif only then\r\nreturn '<span class=\"dnd-tab dnd-tab-' .. n .. '\" style=\"position:relative\">' .. text\r\n.. '<span class=\"dnd-hit\">' .. rawBtn(\" \", \"dnd_tab_\" .. n) .. '</span></span>'\r\nend\r\nreturn '<label class=\"dnd-tab dnd-tab-' .. n .. '\" for=\"dnd-tab-' .. n .. sfx .. '\">' .. text .. '</label>'\r\nend\r\nlocal function pane(n, build)\r\nif only and tab ~= n then return \"\" end\r\nreturn '<div class=\"dnd-pane-' .. n .. '\">' .. build() .. '</div>'\r\nend\r\nlocal function settings()\r\nreturn levelRow(familiarity(id))\r\n\r\n.. optRow(\"➤ 행동 추천\", \"답장 끝에 해 볼 만한 행동과 성공 확률을 보여 주고, 전투 중 내 차례에는 행동 버튼을 띄웁니다. 처음부터 켜져 있고, 끄면 그대로 갑니다.\",\r\nK.suggestOn(id), \"dnd_suggest_on\", \"dnd_suggest_off\")\r\n.. K.En.row(id)\r\n.. Feat.deathRow(id)\r\n.. K.combatRow(id)\r\n.. K.checkRow(id)\r\n.. K.diffRows(id)\r\n.. optRow(\"⚑ 페이스 신호\", \"위협·도전·보상이 한동안 없으면 장면이 받쳐 줄 때 슬쩍 꺼내 보라는 한 줄을 AI에게 넣습니다. 전투 중에는 쉽니다.\", optOn(id, \"dnd_opt_pace\"), \"dnd_pace_on\", \"dnd_pace_off\")\r\n.. optRow(\"⚒ 디버그 모드\", \"시험용 디버그 탭을 켭니다. 상태를 바로 바꾸고, Lua가 들고 있는 값과 요청에 넣은 내용을 볼 수 있습니다.\", dbgOn, \"dnd_dbg_on\", \"dnd_dbg_off\")\r\n\r\n.. (not adultTab and K.packReloadRow() or \"\")\r\n.. info\r\nend\r\nlocal ui = table.concat({\r\n'<div class=\"dnd-ui\">',\r\nradio(\"1\"), radio(\"5\"), radio(\"6\"), radio(\"3\"), adultTab and radio(\"7\") or \"\", dbgOn and radio(\"4\") or \"\",\r\n'<div class=\"dnd-gear-bar' .. open .. '\">' .. gear .. '</div>',\r\n'<div class=\"dnd-drawer' .. open .. '\"><div class=\"dnd-backdrop\"><span class=\"dnd-hit\">' .. rawBtn(\" \", \"dnd_drawer_close\") .. '</span></div><div class=\"dnd-panel\">'\r\n.. '<div class=\"dnd-panel-hd\"><b>❖ 모험 설정</b><span class=\"dnd-close\">✕<span class=\"dnd-hit\">' .. rawBtn(\" \", \"dnd_drawer_close\") .. '</span></span></div>'\r\n.. '<div class=\"dnd-tabs\">' .. tabLabel(\"1\", \"캐릭터\") .. tabLabel(\"5\", \"상점\") .. tabLabel(\"6\", \"규칙\") .. tabLabel(\"3\", \"설정\")\r\n.. (adultTab and tabLabel(\"7\", \"DLC\") or \"\") .. (dbgOn and tabLabel(\"4\", \"디버그\") or \"\") .. '</div>'\r\n.. '<div class=\"dnd-panel-body\">' .. errTop\r\n.. pane(\"1\", function() return sheetPane(id, sh) end)\r\n.. pane(\"5\", function() return Shop.pane(id) end)\r\n.. pane(\"6\", function() return K.dictPane(id) end)\r\n.. pane(\"3\", function() return '<div class=\"dnd-set\">' .. settings() .. '</div>' end)\r\n.. (adultTab and pane(\"7\", function() return '<div class=\"dnd-set\">' .. K.packReloadRow() .. K.packReadRow() .. Feat.d2Row(id) .. '</div>' end) or \"\")\r\n.. (dbgOn and pane(\"4\", function() return debugPane(id) end) or \"\")\r\n.. '</div></div></div>',\r\n'</div>',\r\n})\r\nif first then return ui end\r\nreturn whenNewest .. ui .. \"\\n{{/when}}\"\r\nend\r\n\r\n\r\n\r\nlocal function creationChoice(id, data)\r\nlocal sh = loadSheet(id)\r\napplySheet(sh)\r\nlocal pc = loadPC(id)\r\nlocal change\r\nlocal skill = data:match(\"^dnd_exp_(.+)$\")\r\nlocal abil = data:match(\"^dnd_asi_(%a+)$\") or data:match(\"^dnd_asi_(F_[%w_]+)$\")\r\nlocal half = data:match(\"^dnd_asi_h(%u%a+)$\")\r\nif half then\r\nif not sh.asi_pending then return end\r\nabil = K.halfPick(id, sh, half)\r\nif not abil then return end\r\nend\r\nif skill then\r\nskill = skill:gsub(\"_\", \" \")\r\nlocal picks = expertiseChoices(sh)\r\nlocal okPick = false\r\nfor _, k in ipairs(picks) do if k == skill then okPick = true end end\r\nif not okPick then return end\r\nchange = function(s)\r\ns.expertise = s.expertise or {}\r\nfor _, k in ipairs(s.expertise) do if k == skill then return end end\r\ns.expertise[#s.expertise + 1] = skill\r\nend\r\nelseif abil then\r\nif not sh.asi_pending or not (sh.scores[abil] or abil:match(\"^Grappler\") or abil:match(\"^Half_\") or abil:match(\"^F_\")) then return end\r\nif abil:match(\"^F_\") then\r\nlocal fname = (abil:match(\"^F_(.-)__%a+$\") or abil:match(\"^F_(.+)$\")):gsub(\"_Q_\", \"'\"):gsub(\"_\", \" \")\r\nif not K.gfeatOk(sh, fname, K.FX[fname]) then return end\r\n\r\nlocal fab, okAb = abil:match(\"__(%a+)$\"), nil\r\nokAb = not fab\r\nfor _, x in ipairs(K.gfeatAsi(sh, fname)) do if x == fab then okAb = true end end\r\nif not okAb or ((K.FX[fname] or {}).asi_save and not fab) then return end\r\nend\r\nif abil:match(\"^Grappler\") and (sh.feat4 == \"Grappler\" or not K.grappleOk(sh)) then return end\r\nchange = function(s)\r\nif not s.asi_pending then return end\r\nif applyASI(s, abil) == \"?\" then return end\r\nlocal left = (tonumber(s.asi_pending) or 1) - 1\r\ns.asi_pending = left > 0 and left or nil\r\nend\r\nelseif data:match(\"^dnd_pick_\") then\r\n\r\nlocal key, v = data:match(\"^dnd_pick_(%a%w*_%d+)_(.+)$\")\r\nif not key then key, v = data:match(\"^dnd_pick_(%a%w*)_(.+)$\") end\r\nif not key then return end\r\nv = v:gsub(\"_Q_\", \"'\"):gsub(\"_\", \" \")\r\nif v == \"RESET\" and loadCombat(id).active then return end\r\nif v == \"UNDO\" and (loadCombat(id).active or not pc.making) then return end\r\nif not Feat.pick(deepCopy(sh), key, v, pc) then return end\r\n\r\nif key == \"heatday\" and tonumber(v) then\r\nlocal clk = loadClock(id)\r\npc.heat = type(pc.heat) == \"table\" and pc.heat or {}\r\npc.heat.next, pc.heat.picked = (tonumber(clk.min) or 0) + tonumber(v) * 1440, tonumber(v)\r\nend\r\nchange = function(s, spc)\r\napplySheet(s)\r\nFeat.pick(s, key, v, spc or pc)\r\napplySheet(s)\r\nFeat.fillRes(spc or pc)\r\nend\r\nelseif data == \"dnd_hpfix_avg\" or data == \"dnd_hpfix_roll\" then\r\nif not sh.hp_pending then return end\r\nlocal rolls = {}\r\nfor lv = 2, K.charLevel(sh) do\r\nrolls[lv] = data == \"dnd_hpfix_roll\" and K.d(K.lvDie(sh, lv)) or 0\r\nend\r\nchange = function(s)\r\nif not s.hp_pending then return end\r\nfor lv = 2, K.charLevel(s) do setHpRoll(s, lv, rolls[lv] or 0) end\r\ns.hp_pending = nil\r\nend\r\nelse\r\nreturn\r\nend\r\nchange(sh, pc)\r\nrefitHp(sh, pc)\r\napplySheet(sh); Feat.fillRes(pc)\r\nsetState(id, \"dnd_sheet\", sh)\r\nsetState(id, \"dnd_pc\", pc)\r\nsyncBases(id, function(s)\r\nif s.sheet.class ~= sh.class then return false end\r\nchange(s.sheet, s.pc)\r\nrefitHp(s.sheet, s.pc)\r\napplySheet(s.sheet); Feat.fillRes(s.pc)\r\nend)\r\napplySheet(sh)\r\nredrawStatus(id, pc, loadClock(id))\r\nend\r\n\r\n\r\n\r\nfunction onButtonClick(id, data)\r\nlocal t0 = clockNow()\r\nlocal r = table.pack(pcall(onButtonClick0, id, data))\r\nlocal okd, dbg = pcall(getChatVar, id, \"dnd_opt_debug\")\r\nif okd and dbg == \"1\" then\r\npcall(setChatVar, id, \"dnd_perf_btn\", string.format(\"%s %dms (팩 읽기 %sms, 합치기 %sms)\", tostring(data), math.floor((clockNow() - t0) * 1000 + 0.5),\r\ntostring(K.PACK.readMs or \"-\"), tostring(K.PACK.mergeMs or \"-\")))\r\nend\r\nif not r[1] then error(r[2], 0) end\r\nreturn table.unpack(r, 2, r.n)\r\nend\r\n\r\n\r\n\r\nfunction onFormSubmit(id, key, metaJson)\r\nlocal okj, m = pcall(function() return json.decode(metaJson) end)\r\nK.formData = (okj and type(m) == \"table\" and type(m.data) == \"table\") and m.data or {}\r\nlocal r = table.pack(pcall(onButtonClick, id, \"dnd_form_\" .. tostring(key or \"\")))\r\nK.formData = nil\r\nif not r[1] then error(r[2], 0) end\r\nreturn table.unpack(r, 2, r.n)\r\nend\r\n\r\nfunction K.isPackBtn(data)\r\nreturn data == \"dnd_d2_mild\" or data == \"dnd_d2_hard\" or data == \"dnd_d2perm_off\" or data == \"dnd_d2perm_on\"\r\nor data == \"dnd_d2furry_off\" or data == \"dnd_d2furry_on\" or data == \"dnd_d2xeno_off\" or data == \"dnd_d2xeno_on\"\r\nor data == \"dnd_d2lvdown_off\" or data == \"dnd_d2lvdown_on\" or data == \"dnd_d2_off\" or data == \"dnd_pack_reload\"\r\nor data == \"dnd_d2hitomi_off\" or data == \"dnd_d2hitomi_on\"\r\nor data == \"dnd_d2omega_off\" or data == \"dnd_d2omega_on\"\r\nend\r\nfunction K.packBtn(id, data)\r\nif data == \"dnd_pack_reload\" then\r\npcall(K.packs, id, true)\r\npcall(K.packFpSave, id)\r\nelse\r\n\r\n\r\nif data == \"dnd_d2_off\" then setChatVar(id, \"dnd_dlc_adult\", \"off\")\r\nelseif data == \"dnd_d2_mild\" or data == \"dnd_d2_hard\" then setChatVar(id, \"dnd_dlc_mode\", data:sub(8)); setChatVar(id, \"dnd_dlc_adult\", \"on\")\r\nelse\r\nlocal which, v = data:match(\"^dnd_d2(%a+)_(%a+)$\")\r\nsetChatVar(id, \"dnd_dlc_\" .. which, v == \"on\" and \"on\" or \"off\")\r\nend\r\npcall(K.packs, id)\r\nend\r\nsetDrawerOpen(id, true)\r\nsetChatVar(id, \"dnd_drawer_tab\", K.packTabOn() and \"7\" or \"3\")\r\nend\r\nfunction onButtonClick0(id, data)\r\nK.seedNow(id, data)\r\npcall(K.packs, id)\r\npcall(K.packFpSave, id)\r\nlocal missNow = K.missingFresh(id)\r\nK.LOCKED = missNow and true or nil\r\npcall(Seed.restore, id)\r\n\r\nif data == \"dnd_drawer_toggle\" then\r\nsetDrawerOpen(id, not drawerIsOpen(id))\r\nreturn\r\nelseif data == \"dnd_drawer_close\" then\r\nsetChatVar(id, \"dnd_drawer_open\", \"0\")\r\nreturn\r\nend\r\n\r\n\r\n\r\nif K.LOCKED and K.isPackBtn(data) then\r\nK.packBtn(id, data)\r\nmissNow = K.missingFresh(id)\r\nK.LOCKED = missNow and true or nil\r\nsetChatVar(id, \"dnd_lua_error\", missNow and K.lockMsg(missNow, \"캐릭터를 그대로 두었습니다. 모듈을 다시 켜 주십시오.\") or \"\")\r\nreturn\r\nend\r\nif K.LOCKED then\r\nsetChatVar(id, \"dnd_lua_error\", K.lockMsg(missNow, \"캐릭터를 그대로 두었습니다. 모듈을 다시 켜 주십시오.\"))\r\nreturn\r\nend\r\n\r\n\r\nlocal optN = tonumber(data:match(\"^dnd_opt_(%d+)$\") or \"\")\r\nif optN then\r\nlocal last = getChat(id, -1)\r\nif Shop.isLine(last) then last = getChat(id, -2) end\r\nlocal o = last and last.role ~= \"user\" and K.optList(tostring(last.data or \"\"))[optN]\r\nif o then\r\nK.MON_KO = langKo()\r\naddChat(id, \"user\", K.En.on(id) and o.label or toKo(o.label))\r\nend\r\nreturn\r\nend\r\n\r\nsetChatVar(id, \"dnd_drawer_open\", \"0\")\r\nsetChatVar(id, \"dnd_drawer_tab\", \"1\")\r\nif data == \"dnd_suggest_on\" or data == \"dnd_suggest_off\" then\r\nsetChatVar(id, \"dnd_opt_suggest\", data == \"dnd_suggest_on\" and \"1\" or \"0\")\r\nsetDrawerOpen(id, true)\r\nsetChatVar(id, \"dnd_drawer_tab\", \"3\")\r\nelseif data == \"dnd_pace_on\" or data == \"dnd_pace_off\" then\r\nsetChatVar(id, \"dnd_opt_pace\", data == \"dnd_pace_on\" and \"1\" or \"0\")\r\nsetDrawerOpen(id, true)\r\nsetChatVar(id, \"dnd_drawer_tab\", \"3\")\r\nelseif data:sub(1, 9) == \"dnd_shop_\" then\r\nShop.click(id, data)\r\nelseif K.isPackBtn(data) then\r\nK.packBtn(id, data)\r\nlocal m = K.missingClass(id)\r\nif m then setChatVar(id, \"dnd_lua_error\", K.lockMsg(m, \"캐릭터를 그대로 두었습니다. 모듈을 다시 켜 주십시오.\")) end\r\nelseif data == \"dnd_death_srd\" or data == \"dnd_death_gentle\" or data == \"dnd_death_harsh\" then\r\nsetChatVar(id, \"dnd_death\", data:sub(11))\r\nsetDrawerOpen(id, true)\r\nsetChatVar(id, \"dnd_drawer_tab\", \"3\")\r\nelseif data == \"dnd_checkd_easy\" or data == \"dnd_checkd_mid\" or data == \"dnd_checkd_hard\" then\r\nsetChatVar(id, \"dnd_check_d\", data:sub(12))\r\nsetDrawerOpen(id, true)\r\nsetChatVar(id, \"dnd_drawer_tab\", \"3\")\r\nelseif data == \"dnd_fightd_easy\" or data == \"dnd_fightd_mid\" or data == \"dnd_fightd_hard\" then\r\nsetChatVar(id, \"dnd_fight_d\", data:sub(12))\r\nsetDrawerOpen(id, true)\r\nsetChatVar(id, \"dnd_drawer_tab\", \"3\")\r\nelseif data == \"dnd_checkw_low\" or data == \"dnd_checkw_mid\" or data == \"dnd_checkw_high\" then\r\nsetChatVar(id, \"dnd_check_w\", data:sub(12))\r\nsetDrawerOpen(id, true)\r\nsetChatVar(id, \"dnd_drawer_tab\", \"3\")\r\nelseif data == \"dnd_combat_low\" or data == \"dnd_combat_mid\" or data == \"dnd_combat_high\" then\r\nsetChatVar(id, \"dnd_combat_w\", data:sub(12))\r\nsetDrawerOpen(id, true)\r\nsetChatVar(id, \"dnd_drawer_tab\", \"3\")\r\nelseif data:sub(1, 19) == \"dnd_form_dnd_spells\" then\r\nlocal cls = data:match(\"^dnd_form_dnd_spells_(%a+)$\")\r\nSpell.formSave(id, cls and CLASSES[cls] and cls or nil, K.formData or {})\r\nelseif data:sub(1, 10) == \"dnd_cantc_\" then\r\nlocal cls, key = data:sub(11):match(\"^(%a+)_(.+)$\")\r\nif cls and CLASSES[cls] then Spell.cantTap(id, key, cls) end\r\nelseif data:sub(1, 9) == \"dnd_cant_\" then\r\nSpell.cantTap(id, data:sub(10))\r\nelseif data:sub(1, 9) == \"dnd_prep_\" then\r\nSpell.toggle(id, data:sub(10))\r\nelseif data:sub(1, 10) == \"dnd_prepc_\" then\r\n\r\nlocal cls, key = data:sub(11):match(\"^(%a+)_(.+)$\")\r\nif cls and CLASSES[cls] then Spell.toggle(id, key, cls) end\r\nelseif data == \"dnd_card_st\" or data == \"dnd_card_pt\" or data == \"dnd_card_jb\" then\r\n\r\nsetChatVar(id, \"dnd_card_tab\", data:sub(10) .. \"@\" .. K.replyIdx(id))\r\nelseif data == \"dnd_party_leave_cancel\" or data:match(\"^dnd_party_leave_%d$\") or data:match(\"^dnd_party_leave_cancel_%d$\") then\r\n\r\nlocal i = tonumber(data:match(\"(%d)$\") or \"\")\r\nlocal a = i and Ally.list(loadPC(id))[i]\r\nlocal list = {}\r\nif data ~= \"dnd_party_leave_cancel\" then\r\nfor _, nm in ipairs(Ally.leaving(id)) do if not (a and nm == a.name) then list[#list + 1] = nm end end\r\nif a and not data:find(\"cancel\", 1, true) and not loadCombat(id).active then list[#list + 1] = a.name end\r\nend\r\nsetChatVar(id, \"dnd_party_leave\", table.concat(list, \"|\"))\r\nsetChatVar(id, \"dnd_card_tab\", \"pt@\" .. K.replyIdx(id))\r\nelseif data:match(\"^dnd_give_%d+_%d+_?%x*$\") or data:match(\"^dnd_take_%d+_%d+_?%x*$\") then\r\nAlly.giveClick(id, data)\r\nelseif data:match(\"^dnd_alvcls_%d+_%a+$\") or data:match(\"^dnd_alvcls_%d+_%x+_%a+$\") then\r\nAlly.lvPickClick(id, data)\r\nelseif data:match(\"^dnd_asub_%d+_%x+_sub%a+_.+$\") then\r\nAlly.subPickClick(id, data)\r\nelseif data:match(\"^dnd_aevery_%d+_%x+_%w+_.+$\") then\r\nAlly.everyClick(id, data)\r\nelseif data:match(\"^dnd_apreg_%d+_%x+_%a+$\") then\r\nAlly.pregClick(id, data)\r\nelseif data:match(\"^dnd_afeat_%d+_%x+_F_.+$\") then\r\nAlly.featClick(id, data)\r\nelseif data == \"dnd_position_top\" or data == \"dnd_position_bottom\" or data == \"dnd_position_any\" then\r\n\r\nlocal v = data:sub(14)\r\nlocal sh = loadSheet(id)\r\nsh.picks = type(sh.picks) == \"table\" and sh.picks or {}\r\nsh.picks.position = v\r\nsetState(id, \"dnd_sheet\", sh)\r\nsyncBases(id, function(s) s.sheet.picks = type(s.sheet.picks) == \"table\" and s.sheet.picks or {}; s.sheet.picks.position = v; return true end)\r\nsetDrawerOpen(id, true)\r\nsetChatVar(id, \"dnd_drawer_tab\", \"1\")\r\nelseif data:match(\"^dnd_apos_%d+_%x+_%a+$\") then\r\nAlly.posClick(id, data)\r\nelseif data == \"dnd_pregwant_yes\" or data == \"dnd_pregwant_no\" then\r\n\r\nlocal v = data:sub(14)\r\nlocal sh = loadSheet(id)\r\nsh.picks = type(sh.picks) == \"table\" and sh.picks or {}\r\nsh.picks.pregwant = v\r\nsetState(id, \"dnd_sheet\", sh)\r\nsyncBases(id, function(s) s.sheet.picks = type(s.sheet.picks) == \"table\" and s.sheet.picks or {}; s.sheet.picks.pregwant = v; return true end)\r\nsetDrawerOpen(id, true)\r\nsetChatVar(id, \"dnd_drawer_tab\", \"1\")\r\nelseif data:match(\"^dnd_party_%d$\") then\r\nsetChatVar(id, \"dnd_party_want\", data:sub(-1))\r\nsetChatVar(id, \"dnd_card_tab\", \"pt@\" .. K.replyIdx(id))\r\nelseif data == \"dnd_allystyle_save\" or data == \"dnd_allystyle_normal\" or data == \"dnd_allystyle_bold\" then\r\nsetChatVar(id, \"dnd_ally_style\", data:sub(15))\r\nsetChatVar(id, \"dnd_card_tab\", \"pt@\" .. K.replyIdx(id))\r\nelseif data == \"dnd_lang_ko\" or data == \"dnd_lang_en\" then\r\nsetChatVar(id, \"dnd_lang\", data:sub(-2))\r\nsetDrawerOpen(id, true)\r\nsetChatVar(id, \"dnd_drawer_tab\", \"3\")\r\nelseif data == \"dnd_lvl_1\" or data == \"dnd_lvl_2\" or data == \"dnd_lvl_3\" then\r\nsetChatVar(id, \"dnd_opt_level\", data:sub(-1))\r\nsetDrawerOpen(id, true)\r\nsetChatVar(id, \"dnd_drawer_tab\", \"3\")\r\nelseif data == \"dnd_dbg_on\" or data == \"dnd_dbg_off\" then\r\nsetChatVar(id, \"dnd_opt_debug\", data == \"dnd_dbg_on\" and \"1\" or \"0\")\r\nsetDrawerOpen(id, true)\r\nsetChatVar(id, \"dnd_drawer_tab\", data == \"dnd_dbg_on\" and \"4\" or \"3\")\r\nelseif data == \"dnd_charexport\" or data == \"dnd_charexport_hide\" then\r\nlocal code = \"\"\r\nif data == \"dnd_charexport\" then\r\nlocal sh = loadSheet(id)\r\napplySheet(sh)\r\ncode = K.CharCode.make(sh, loadPC(id), loadClock(id).min) or \"\"\r\nend\r\nsetChatVar(id, \"dnd_export_code\", code)\r\nsetChatVar(id, \"dnd_export_show\", code ~= \"\" and \"1\" or \"0\")\r\nsetDrawerOpen(id, true)\r\nsetChatVar(id, \"dnd_drawer_tab\", \"1\")\r\nelseif data == \"dnd_dbg_form_on\" or data == \"dnd_dbg_form_off\" then\r\nsetChatVar(id, \"dnd_form_ui\", data == \"dnd_dbg_form_on\" and \"on\" or \"off\")\r\nsetDrawerOpen(id, true)\r\nsetChatVar(id, \"dnd_drawer_tab\", \"4\")\r\nelseif data == \"dnd_dbg_req_on\" or data == \"dnd_dbg_req_off\" then\r\nsetChatVar(id, \"dnd_dbg_req\", data == \"dnd_dbg_req_on\" and \"1\" or \"0\")\r\nsetDrawerOpen(id, true)\r\nsetChatVar(id, \"dnd_drawer_tab\", \"4\")\r\nelseif data:sub(1, 8) == \"dnd_dbg_\" then\r\nsetDrawerOpen(id, true)\r\nsetChatVar(id, \"dnd_drawer_tab\", \"4\")\r\ndebugAction(id, data)\r\nelseif data == \"dnd_levelup\" or data:sub(1, 12) == \"dnd_levelup_\" then\r\nsetDrawerOpen(id, true)\r\nsetChatVar(id, \"dnd_drawer_tab\", \"1\")\r\nlocal sh = loadSheet(id)\r\napplySheet(sh)\r\nlocal pc = loadPC(id)\r\nif loadCombat(id).active or not xpNext(pc) or pc.xp < xpNext(pc) then return end\r\n\r\nlocal cls = K.lvClass(id, sh)\r\nlocal nextLv = K.cl(sh, cls) + 1\r\n\r\nlocal pick = data:match(\"^dnd_levelup_(%a+)$\") or data:match(\"^dnd_levelup_(F_.+)$\")\r\nlocal half = data:match(\"^dnd_levelup_h(%u%a+)$\")\r\nif half then\r\nif not K.asiLevel(cls, nextLv) then return end\r\npick = K.halfPick(id, sh, half)\r\nif not pick then return end\r\nend\r\nlocal asiNext = K.asiLevel(cls, nextLv)\r\nif pick and pick:match(\"^F_\") then\r\nlocal fn = pick:sub(3):match(\"^(.-)__%a+$\") or pick:sub(3)\r\nfn = fn:gsub(\"_Q_\", \"'\"):gsub(\"_\", \" \")\r\nif not (asiNext and K.gfeatOk(sh, fn, K.FX[fn], K.charLevel(sh) + 1)) then return end\r\nend\r\nif asiNext and not (pick and (sh.scores[pick] or pick:match(\"^Grappler\") or pick:match(\"^Half_\") or pick:match(\"^F_\"))) then return end\r\nif asiNext and pick:match(\"^Grappler\") and (sh.feat4 == \"Grappler\" or not K.grappleOk(sh)) then return end\r\nlocal hpRoll = getChatVar(id, \"dnd_hp_roll\") == \"1\" and K.d(CLASSES[cls].hit_die) or nil\r\n\r\nlocal hist = K.AR and K.AR.on() and K.lvHist(id, sh, pc) or nil\r\nif hist == Feat.picks(sh).sexhist then hist = nil end\r\nlocal ok = levelUp(sh, pc, pick, hpRoll, cls, hist)\r\nif not ok then return end\r\nif K.AR and K.AR.on() then setChatVar(id, \"dnd_lv_hist\", \"\") end\r\n\r\nif Spell.SWAP_LEVEL[cls] then Spell.setWin(pc, sh, cls, { kind = \"one\", why = \"level\", orig = deepCopy((select(2, K.lists(sh, cls)))) }) end\r\nsetState(id, \"dnd_sheet\", sh)\r\nsetState(id, \"dnd_pc\", pc)\r\n\r\nsyncBases(id, function(s)\r\nif K.charLevel(s.sheet) ~= K.charLevel(sh) - 1 or s.sheet.class ~= sh.class then return false end\r\nlevelUp(s.sheet, s.pc, pick, hpRoll, cls, hist)\r\n\r\nif Spell.SWAP_LEVEL[cls] then Spell.setWin(s.pc, s.sheet, cls, { kind = \"one\", why = \"level\", orig = deepCopy((select(2, K.lists(s.sheet, cls)))) }) end\r\nend)\r\napplySheet(sh)\r\n\r\nredrawStatus(id, pc, loadClock(id))\r\nelseif data == \"dnd_hpmode_avg\" or data == \"dnd_hpmode_roll\" then\r\nsetChatVar(id, \"dnd_hp_roll\", data == \"dnd_hpmode_roll\" and \"1\" or \"0\")\r\nsetDrawerOpen(id, true)\r\nsetChatVar(id, \"dnd_drawer_tab\", \"1\")\r\nelseif data == \"dnd_sheetreset\" or data == \"dnd_sheetreset_no\" then\r\n\r\nsetChatVar(id, \"dnd_reset_ask\", data == \"dnd_sheetreset\" and \"1\" or \"0\")\r\nsetDrawerOpen(id, true)\r\nsetChatVar(id, \"dnd_drawer_tab\", \"1\")\r\nelseif data == \"dnd_sheetreset_yes\" then\r\nlocal sh, pc = loadSheet(id), loadPC(id)\r\nif getChatVar(id, \"dnd_reset_ask\") ~= \"1\" or not K.resetOk(sh, pc) or loadCombat(id).active then return end\r\nlocal why = pc.dead and \"dead\" or \"making\"\r\nK.sheetReset(sh, pc, why)\r\nsetState(id, \"dnd_sheet\", sh)\r\nsetState(id, \"dnd_pc\", pc)\r\n\r\nsyncBases(id, function(s)\r\nif not K.resetOk(s.sheet, s.pc) then return false end\r\nK.sheetReset(s.sheet, s.pc, why)\r\nend)\r\napplySheet(sh)\r\nsetChatVar(id, \"dnd_reset_ask\", \"0\")\r\nsetDrawerOpen(id, true)\r\nsetChatVar(id, \"dnd_drawer_tab\", \"1\")\r\nredrawStatus(id, pc, loadClock(id))\r\nelseif data:sub(1, 11) == \"dnd_lvhist_\" then\r\n\r\nlocal n = data:sub(12):gsub(\"_Q_\", \"'\"):gsub(\"_\", \" \")\r\nif not (K.AR and K.AR.on() and K.PACK.ar.hist[n]) then return end\r\nsetChatVar(id, \"dnd_lv_hist\", n)\r\nsetDrawerOpen(id, true)\r\nsetChatVar(id, \"dnd_drawer_tab\", \"1\")\r\nelseif data:sub(1, 10) == \"dnd_lvcls_\" then\r\n\r\nif not CLASSES[data:sub(11)] then return end\r\nsetChatVar(id, \"dnd_lv_cls\", data:sub(11))\r\nsetDrawerOpen(id, true)\r\nsetChatVar(id, \"dnd_drawer_tab\", \"1\")\r\nelseif data:match(\"^dnd_tab_%d$\") then\r\nsetDrawerOpen(id, true)\r\nsetChatVar(id, \"dnd_drawer_tab\", data:sub(-1))\r\nelseif data:sub(1, 7) == \"dnd_cg_\" then\r\nK.Cg.click(id, data)\r\nelseif data == \"dnd_mastery_more\" then\r\nsetChatVar(id, \"dnd_mastery_more\", getChatVar(id, \"dnd_mastery_more\") == \"1\" and \"0\" or \"1\")\r\nif getChatLength(id) > 0 then setDrawerOpen(id, true) end\r\nsetChatVar(id, \"dnd_drawer_tab\", \"1\")\r\nelseif data:sub(1, 8) == \"dnd_exp_\" or data:sub(1, 8) == \"dnd_asi_\" or data:sub(1, 10) == \"dnd_hpfix_\" or data:sub(1, 9) == \"dnd_pick_\" then\r\n\r\nif getChatLength(id) > 0 then setDrawerOpen(id, true) end\r\nsetChatVar(id, \"dnd_drawer_tab\", \"1\")\r\ncreationChoice(id, data)\r\nend\r\nend\r\n\r\n\r\n\r\nlocal function checkExplain(skill)\r\nlocal ab = skill:match(\"^(%a+) save$\")\r\nlocal what\r\nif SKILL_TIP[skill] then\r\nwhat = koName(skill) .. \" 판정 · \" .. SKILL_TIP[skill]\r\nelseif ab and NAMES_KO[ab] then\r\nwhat = NAMES_KO[ab] .. \" 내성 굴림 · 해로운 효과를 버티는 굴림\"\r\nelseif NAMES_KO[skill] then\r\nwhat = NAMES_KO[skill] .. \" 판정 · 기술 없이 능력치로\"\r\nelse\r\nwhat = \"판정\"\r\nend\r\nreturn '<div class=\"dnd-explain\">' .. esc(what) .. \". d20 + 수정치가 난이도 이상이면 성공.</div>\"\r\nend\r\nlocal ATTACK_EXPLAIN = '<div class=\"dnd-explain\">명중 굴림 · d20 + 공격 수정치가 상대 방어도 이상이면 명중. 20은 치명타(피해 주사위 두 배), 1은 빗나감.</div>'\r\n\r\n\r\n\r\n\r\n\r\nlocal function redrawDrawer(id)\r\nlocal len = getChatLength(id)\r\nif len > 0 and pcall(reloadChat, id, len - 1) then return end\r\npcall(reloadDisplay, id)\r\nend\r\nfunction dndDrawerToggle(id)\r\nsetDrawerOpen(id, not drawerIsOpen(id))\r\nredrawDrawer(id)\r\nend\r\nfunction dndDrawerClose(id)\r\nsetChatVar(id, \"dnd_drawer_open\", \"0\")\r\nredrawDrawer(id)\r\nend\r\nfunction dndPaceOn(id) onButtonClick(id, \"dnd_pace_on\") end\r\nfunction dndPaceOff(id) onButtonClick(id, \"dnd_pace_off\") end\r\nfunction dndSuggestOn(id) onButtonClick(id, \"dnd_suggest_on\") end\r\nfunction dndSuggestOff(id) onButtonClick(id, \"dnd_suggest_off\") end\r\nfunction dndLvl1(id) onButtonClick(id, \"dnd_lvl_1\") end\r\nfunction dndLvl2(id) onButtonClick(id, \"dnd_lvl_2\") end\r\nfunction dndLvl3(id) onButtonClick(id, \"dnd_lvl_3\") end\r\nfunction dndLangKo(id) onButtonClick(id, \"dnd_lang_ko\") end\r\nfunction dndLangEn(id) onButtonClick(id, \"dnd_lang_en\") end\r\nfunction dndLevelUp(id) onButtonClick(id, \"dnd_levelup\") end\r\nfunction dndAsiStr(id) onButtonClick(id, \"dnd_levelup_Strength\") end\r\nfunction dndAsiDex(id) onButtonClick(id, \"dnd_levelup_Dexterity\") end\r\nfunction dndAsiCon(id) onButtonClick(id, \"dnd_levelup_Constitution\") end\r\nfunction dndAsiInt(id) onButtonClick(id, \"dnd_levelup_Intelligence\") end\r\nfunction dndAsiWis(id) onButtonClick(id, \"dnd_levelup_Wisdom\") end\r\nfunction dndAsiCha(id) onButtonClick(id, \"dnd_levelup_Charisma\") end\r\nfunction dndHpAvg(id) onButtonClick(id, \"dnd_hpmode_avg\") end\r\nfunction dndHpRoll(id) onButtonClick(id, \"dnd_hpmode_roll\") end\r\nfunction dndDbgOn(id) onButtonClick(id, \"dnd_dbg_on\") end\r\nfunction dndDbgOff(id) onButtonClick(id, \"dnd_dbg_off\") end\r\nfunction dndDbgHpFull(id) onButtonClick(id, \"dnd_dbg_hp_full\") end\r\nfunction dndDbgHpHalf(id) onButtonClick(id, \"dnd_dbg_hp_half\") end\r\nfunction dndDbgHpZero(id) onButtonClick(id, \"dnd_dbg_hp_zero\") end\r\nfunction dndDbgXp(id) onButtonClick(id, \"dnd_dbg_xp\") end\r\nfunction dndDbgT1h(id) onButtonClick(id, \"dnd_dbg_t1h\") end\r\nfunction dndDbgT8h(id) onButtonClick(id, \"dnd_dbg_t8h\") end\r\nfunction dndDbgT1d(id) onButtonClick(id, \"dnd_dbg_t1d\") end\r\nfunction dndDbgFight(id) onButtonClick(id, \"dnd_dbg_fight\") end\r\nfunction dndDbgEnd(id) onButtonClick(id, \"dnd_dbg_end\") end\r\nfunction dndDbgD20High(id) onButtonClick(id, \"dnd_dbg_d20_20\") end\r\nfunction dndDbgD20Low(id) onButtonClick(id, \"dnd_dbg_d20_1\") end\r\nfunction dndDbgReqOn(id) onButtonClick(id, \"dnd_dbg_req_on\") end\r\nfunction dndDbgReqOff(id) onButtonClick(id, \"dnd_dbg_req_off\") end\r\nfunction dndDbgAlly(id) onButtonClick(id, \"dnd_dbg_ally\") end\r\nfunction dndAsiGrapStr(id) onButtonClick(id, \"dnd_levelup_GrapplerStr\") end\r\nfunction dndAsiGrapDex(id) onButtonClick(id, \"dnd_levelup_GrapplerDex\") end\r\nfunction dndPickMasteryReset(id) onButtonClick(id, \"dnd_pick_mastery_RESET\") end\r\nfunction dndMasteryMore(id) onButtonClick(id, \"dnd_mastery_more\") end\r\nfunction dndDeathSrd(id) onButtonClick(id, \"dnd_death_srd\") end\r\nfunction dndDeathGentle(id) onButtonClick(id, \"dnd_death_gentle\") end\r\nfunction dndDeathHarsh(id) onButtonClick(id, \"dnd_death_harsh\") end\r\nfunction dndD2Mild(id) onButtonClick(id, \"dnd_d2_mild\") end\r\nfunction dndD2Hard(id) onButtonClick(id, \"dnd_d2_hard\") end\r\nfunction dndD2Off(id) onButtonClick(id, \"dnd_d2_off\") end\r\nfunction dndPackReload(id) onButtonClick(id, \"dnd_pack_reload\") end\r\nfunction dndD2PermOff(id) onButtonClick(id, \"dnd_d2perm_off\") end\r\nfunction dndD2PermOn(id) onButtonClick(id, \"dnd_d2perm_on\") end\r\nfunction dndD2FurryOff(id) onButtonClick(id, \"dnd_d2furry_off\") end\r\nfunction dndD2FurryOn(id) onButtonClick(id, \"dnd_d2furry_on\") end\r\nfunction dndD2XenoOff(id) onButtonClick(id, \"dnd_d2xeno_off\") end\r\nfunction dndD2XenoOn(id) onButtonClick(id, \"dnd_d2xeno_on\") end\r\nfunction dndD2LvdownOff(id) onButtonClick(id, \"dnd_d2lvdown_off\") end\r\nfunction dndD2LvdownOn(id) onButtonClick(id, \"dnd_d2lvdown_on\") end\r\nfunction dndD2HitomiOff(id) onButtonClick(id, \"dnd_d2hitomi_off\") end\r\nfunction dndD2HitomiOn(id) onButtonClick(id, \"dnd_d2hitomi_on\") end\r\nfunction dndD2OmegaOff(id) onButtonClick(id, \"dnd_d2omega_off\") end\r\nfunction dndD2OmegaOn(id) onButtonClick(id, \"dnd_d2omega_on\") end\r\nfunction dndCombatLow(id) onButtonClick(id, \"dnd_combat_low\") end\r\nfunction dndCheckLow(id) onButtonClick(id, \"dnd_checkw_low\") end\r\nfunction dndCheckDEasy(id) onButtonClick(id, \"dnd_checkd_easy\") end\r\nfunction dndCheckDMid(id) onButtonClick(id, \"dnd_checkd_mid\") end\r\nfunction dndCheckDHard(id) onButtonClick(id, \"dnd_checkd_hard\") end\r\nfunction dndFightDEasy(id) onButtonClick(id, \"dnd_fightd_easy\") end\r\nfunction dndFightDMid(id) onButtonClick(id, \"dnd_fightd_mid\") end\r\nfunction dndFightDHard(id) onButtonClick(id, \"dnd_fightd_hard\") end\r\nfunction dndCheckMid(id) onButtonClick(id, \"dnd_checkw_mid\") end\r\nfunction dndCheckHigh(id) onButtonClick(id, \"dnd_checkw_high\") end\r\nfunction dndCombatMid(id) onButtonClick(id, \"dnd_combat_mid\") end\r\nfunction dndCombatHigh(id) onButtonClick(id, \"dnd_combat_high\") end\r\nfunction dndDbgAllyClear(id) onButtonClick(id, \"dnd_dbg_ally_clear\") end\r\nfunction dndParty0(id) onButtonClick(id, \"dnd_party_0\") end\r\nfunction dndParty1(id) onButtonClick(id, \"dnd_party_1\") end\r\nfunction dndParty2(id) onButtonClick(id, \"dnd_party_2\") end\r\nfunction dndParty3(id) onButtonClick(id, \"dnd_party_3\") end\r\n\r\n\r\n\r\n\r\n\r\nK.Cg = {}\r\nfunction K.Cg.load(id)\r\nlocal c = getState(id, \"dnd_cg\")\r\nif type(c) ~= \"table\" then c = {} end\r\nc.sk = type(c.sk) == \"table\" and c.sk or {}\r\nreturn c\r\nend\r\n\r\n\r\nfunction K.Cg.fields(c)\r\nreturn { species = c.sp or \"\", class = c.cl or \"\", background = c.bg or \"\", scores = c.ab == \"roll\" and \"굴림\" or \"표준 배열\",\r\nskills = table.concat(c.sk, \",\"), equipment = c.eq or \"\",\r\n\r\nlevel = (c.mc and (c.lv or 1) > 1) and \"1\" or tostring(c.lv or 1) }\r\nend\r\n\r\n\r\nfunction K.Cg.mcNote(c)\r\nif not c.mcTo then return \"\" end\r\nreturn '<div>' .. c.mcTo .. '레벨까지 <b>레벨 업 ' .. (c.mcTo - 1) .. '번</b>이 남았습니다. <b>❖ 설정 → 캐릭터</b> 탭에서 한 번씩 올리며, 레벨마다 클래스를 고르면 됩니다'\r\n.. ' (다른 클래스는 \"다른 클래스 더하기\"에서).</div>'\r\nend\r\nfunction K.Cg.want(c)\r\nif not (c.cl and (c.bg or c.bgx) and CLASSES[c.cl]) then return 0 end\r\nreturn CLASSES[c.cl].skills.choose + (c.sp == \"Human\" and 1 or 0)\r\nend\r\n\r\nfunction K.Cg.click(id, data)\r\nlocal c = K.Cg.load(id)\r\nif c.done then return end\r\nlocal kind, v = data:match(\"^dnd_cg_(%a+)_?(.*)$\")\r\nv = (v or \"\"):gsub(\"_\", \" \")\r\nc.err = nil\r\nif kind == \"sp\" and SPECIES[v] and not K.d2need(SPECIES[v]) then\r\nc.sp = v\r\nelseif kind == \"cl\" and CLASSES[v] then\r\nc.cl, c.sk, c.eq = v, {}, nil\r\nelseif kind == \"bg\" and BACKGROUNDS[v] and not K.d2need(BACKGROUNDS[v]) then\r\nc.bg, c.sk, c.bgx = v, {}, nil\r\nelseif kind == \"bgx\" then\r\n\r\nc.bg, c.sk, c.bgx = nil, {}, true\r\nelseif kind == \"ab\" and (v == \"standard\" or v == \"roll\") then\r\nc.ab = v\r\nif v == \"roll\" and type(getState(id, \"dnd_rolled\")) ~= \"table\" then setState(id, \"dnd_rolled\", rollStats()) end\r\nelseif kind == \"sk\" and SKILL[v] then\r\nlocal at\r\nfor i, k in ipairs(c.sk) do if k == v then at = i end end\r\nif at then table.remove(c.sk, at) elseif #c.sk < K.Cg.want(c) then c.sk[#c.sk + 1] = v end\r\nelseif kind == \"eq\" and (v == \"A\" or v == \"B\") then\r\nc.eq = v\r\nelseif kind == \"lv\" and tonumber(v) then\r\nc.lv = math.max(1, math.min(K.maxLevelAll(), tonumber(v)))\r\nelseif kind == \"mc\" and (v == \"on\" or v == \"off\") then\r\nc.mc = v == \"on\" or nil\r\nelseif kind == \"reset\" then\r\nc = { sk = {}, step = 1 }\r\nelseif kind == \"nav\" then\r\nc.step = math.max(1, math.min(#K.Cg.PAGES, (tonumber(c.step) or 1) + (v == \"next\" and 1 or -1)))\r\nelseif kind == \"go\" and not (c.sp and c.cl and c.bg) then\r\nc.err = \"종족·클래스·배경을 먼저 골라 주십시오\"\r\nelseif kind == \"go\" then\r\nlocal st, note, nsh, npc = K.Form.applyFields(K.Cg.fields(c), getState(id, \"dnd_rolled\"), false)\r\nif st == \"ok\" then\r\n\r\n\r\n\r\nc.mcTo = nil\r\nif c.mc and (c.lv or 1) > 1 then\r\nnpc.xp = XP_LEVEL[c.lv] or npc.xp\r\nc.mcTo = c.lv\r\nend\r\nsetState(id, \"dnd_sheet\", nsh)\r\nsetState(id, \"dnd_pc\", npc)\r\nc.done = note\r\nelse\r\nc.err = note or \"종족·클래스·배경을 먼저 골라 주십시오\"\r\nend\r\nend\r\nsetState(id, \"dnd_cg\", c)\r\nend\r\n\r\n\r\nK.Cg.PAYLOADS = { \"dnd_cg_ab_standard\", \"dnd_cg_ab_roll\", \"dnd_cg_eq_A\", \"dnd_cg_eq_B\", \"dnd_cg_go\", \"dnd_cg_reset\", \"dnd_cg_nav_next\", \"dnd_cg_nav_prev\", \"dnd_cg_bgx\",\r\n\"dnd_cg_mc_on\", \"dnd_cg_mc_off\" }\r\nfor _, t in ipairs({ { \"sp\", SPECIES }, { \"cl\", CLASSES }, { \"bg\", BACKGROUNDS }, { \"sk\", SKILL } }) do\r\nfor en in pairs(t[2]) do\r\nif type(en) == \"string\" then K.Cg.PAYLOADS[#K.Cg.PAYLOADS + 1] = \"dnd_cg_\" .. t[1] .. \"_\" .. en:gsub(\" \", \"_\") end\r\nend\r\nend\r\nfor lv = 1, K.maxLevelAll() do K.Cg.PAYLOADS[#K.Cg.PAYLOADS + 1] = \"dnd_cg_lv_\" .. lv end\r\n\r\nif getmetatable(_G) == nil then\r\nsetmetatable(_G, { __index = function(_, k)\r\nif type(k) == \"string\" and k:sub(1, 6) == \"dndCg_\" and not k:find(\"[^%w_]\") then\r\nlocal payload = \"dnd_cg_\" .. k:sub(7)\r\nreturn function(id) onButtonClick(id, payload) end\r\nend\r\nif type(k) == \"string\" and k:sub(1, 10) == \"dndP_pick_\" and not k:find(\"[^%w_]\") then\r\nlocal payload = \"dnd_\" .. k:sub(6)\r\nreturn function(id) onButtonClick(id, payload) end\r\nend\r\nreturn nil\r\nend })\r\nend\r\nfor _, payload in ipairs(K.Cg.PAYLOADS) do\r\nlocal fn = \"dndCg_\" .. payload:sub(8):gsub(\"[^%w]\", \"_\")\r\nBUTTON_FN[payload] = fn\r\n_G[fn] = function(id) onButtonClick(id, payload) end\r\nend\r\n\r\ndo\r\nlocal pay = { \"dnd_hpfix_avg\", \"dnd_hpfix_roll\", \"dnd_asi_GrapplerStr\", \"dnd_asi_GrapplerDex\" }\r\nfor _, a in ipairs(ABILS) do pay[#pay + 1] = \"dnd_asi_\" .. a; pay[#pay + 1] = \"dnd_asi_h\" .. a; pay[#pay + 1] = \"dnd_levelup_h\" .. a end\r\nfor n in pairs(CLASSES) do if n:sub(1, 1) ~= \"_\" then pay[#pay + 1] = \"dnd_lvcls_\" .. n end end\r\nlocal opts = { style = Feat.STYLES, order = { \"Protector\", \"Thaumaturge\" }, primal = { \"Magician\", \"Warden\" },\r\nland = { \"Arid\", \"Polar\", \"Temperate\", \"Tropical\" }, prey = { \"Colossus Slayer\", \"Horde Breaker\" }, dragon = Feat.DRAGON,\r\nlineage = { \"Drow\", \"High Elf\", \"Wood Elf\" }, gnome = { \"Forest\", \"Rock\" }, giant = Feat.GIANT,\r\nlegacy = { \"Abyssal\", \"Chthonic\", \"Infernal\" }, feat = Feat.ORIGIN, milist = Feat.MI_LISTS,\r\nspellab = { \"Intelligence\", \"Wisdom\", \"Charisma\" }, metamagic = Feat.METAMAGIC, mastery = {}, invocations = {},\r\nboonab = ABILS, beast = { \"Dog\", \"Cat\", \"Fox\", \"Bear\" } }\r\nfor _, x in ipairs(Feat.INVOCATIONS) do opts.invocations[#opts.invocations + 1] = x[1] end\r\nfor w in pairs(WEAPONS) do opts.mastery[#opts.mastery + 1] = w end\r\n\r\nopts.xstyle = Feat.STYLES\r\nfor _, rec in pairs(K.FX) do\r\nfor _, e in ipairs(rec.fx) do\r\nif e.t == \"choice\" then opts[e.key] = e.options elseif e.t == \"resist\" and e.pick then opts[e.pick] = e.opts end\r\nif e.t == \"spell_pick\" then opts[e.key] = Feat.spellPickOpts({}, e) end\r\nend\r\nend\r\nfor k in pairs(SKILL) do\r\npay[#pay + 1] = \"dnd_exp_\" .. k:gsub(\" \", \"_\")\r\nfor _, key in ipairs({ \"keen\", \"skilled\", \"xskill\", \"mcskill\" }) do pay[#pay + 1] = \"dnd_pick_\" .. key .. \"_\" .. k:gsub(\"'\", \"_Q_\"):gsub(\" \", \"_\") end\r\nend\r\nfor key, list in pairs(opts) do\r\nfor _, v in ipairs(list) do pay[#pay + 1] = \"dnd_pick_\" .. key .. \"_\" .. v:gsub(\"'\", \"_Q_\"):gsub(\" \", \"_\") end\r\nend\r\nfor _, payload in ipairs(pay) do\r\nif not BUTTON_FN[payload] then\r\nlocal fn = \"dndP_\" .. payload:sub(5):gsub(\"[^%w]\", \"_\")\r\nBUTTON_FN[payload] = fn\r\n_G[fn] = function(id) onButtonClick(id, payload) end\r\nend\r\nend\r\nend\r\n\r\n\r\n\r\nK.Cg.WHAT = {\r\nsp = \"어떤 몸으로 태어났는지를 정합니다. 능력치는 바꾸지 않고(능력치 보너스는 배경이 줍니다), 어둠 속에서도 보는 눈(암시야)이나 피해 저항 같은 타고난 특성을 줍니다. 거리는 피트로 적습니다 (5피트 ≈ 1.5m, 한 칸).\",\r\ncl = \"무엇을 하는 사람인지, 가장 중요한 선택입니다. 싸우는 방식, 생명력, 주문을 쓰는지, 레벨마다 얻는 기능이 정해집니다. 처음이면 파이터나 바바리안이 단순하고 튼튼합니다.\",\r\nbg = \"모험을 떠나기 전에 무엇을 하던 사람인지를 정합니다. 능력치 보너스를 받을 수 있는 능력치 셋, 기술 숙련 둘, 출신 재주 하나를 줍니다.\",\r\nab = \"근력·민첩·건강·지능·지혜·매력, 여섯 가지 타고난 능력입니다. 표준 배열은 15·14·13·12·10·8을 클래스에 맞게 놓는 공평한 방법, 굴림은 주사위(4d6 중 높은 셋)로 정하는 운의 방법입니다. 어느 쪽이든 배경 보너스 +2·+1이 더해집니다.\",\r\nsk = \"판정할 때 숙련 보너스(1~4레벨 +2)를 더해 주는 기술입니다. 클래스 목록에서 정해진 개수만큼 고릅니다. 배경이 주는 기술 둘은 이미 있습니다. 안 고르면 그 클래스가 흔히 고르는 것으로 채웁니다.\",\r\neq = \"처음 들고 가는 물건 묶음입니다. A는 그 클래스가 쓰는 장비, B는 대개 장비 대신 금화입니다(상점에서 직접 삽니다). 파이터만 B도 장비(민첩 캐릭터용)입니다.\",\r\nlv = \"처음이면 1레벨을 권합니다. 높게 시작하면 기능이 많아지는 대신 한꺼번에 익혀야 합니다. 생명력과 레벨별 기능은 Lua가 맞춰 줍니다.\",\r\n}\r\nK.Cg.BG_WHO = { Acolyte = \"신전에서 사제를 도우며 자란 사람\", Criminal = \"도둑·소매치기·밀수꾼 같은 뒷골목 출신\",\r\nSage = \"책과 연구로 세월을 보낸 학자\", Soldier = \"군대에서 복무하며 싸움을 배운 사람\" }\r\n\r\nK.Cg.PAGES = { \"종족\", \"클래스\", \"배경\", \"능력치\", \"기술\", \"장비·레벨\", \"확인\" }\r\nK.Cg.TIP = {\r\n\r\nsp = { Dragonborn = \"암시야 60피트: 어둠 속에서도 약 18m까지 봅니다.\\n용의 혈통: 고른 용의 피해 종류에 저항.\\n브레스 무기: 공격 행동의 공격 하나 대신 15피트 원뿔이나 30피트 선. 민첩 내성(난이도 8 + 건강 + 숙련 보너스)에 실패하면 1d10(5레벨 2d10), 성공하면 절반. 숙련 보너스만큼, 긴 휴식에 다시 찹니다.\\n용의 비행(5레벨): 추가 행동으로 10분 동안 날 수 있습니다. 긴 휴식마다 1회.\",\r\nDwarf = \"암시야 120피트: 빛이 없어도 약 36m까지 흑백으로 봅니다.\\n드워프의 탄성: 독 피해에 저항, 중독을 피하거나 끝내는 내성 굴림에 이점.\\n드워프의 끈기: 생명력 최대치가 레벨마다 1 더.\\n돌의 꾀: 돌 위에서 추가 행동으로 10분 동안 진동 감지 60피트. 숙련 보너스만큼, 긴 휴식에 다시 찹니다.\",\r\nElf = \"암시야 60피트: 어둠 속에서도 약 18m까지 봅니다.\\n요정 선조: 매혹을 피하거나 끝내는 내성 굴림에 이점.\\n예리한 감각: 통찰·감지·생존 중 하나에 숙련.\\n망아상태: 긴 휴식을 4시간 명상으로 마칩니다.\\n엘프 혈통: 드로우·하이 엘프·우드 엘프 중 하나. 소마법 하나, 3·5레벨에 주문 하나씩.\",\r\nGnome = \"작은 크기.\\n암시야 60피트: 어둠 속에서도 약 18m까지 봅니다.\\n노움의 교활함: 지능·지혜·매력 내성 굴림에 이점.\\n노움 혈통: 숲 노움(하급 환영 소마법, 동물과 대화를 숙련 보너스만큼) 또는 바위 노움(수리·요술 소마법, 작은 태엽 장치).\",\r\nGoliath = \"이동 속도 35피트: 보통은 30피트(약 9m).\\n거인 혈통: 아래 중 하나를 숙련 보너스만큼, 긴 휴식에 다시 찹니다.\\n  구름 — 추가 행동으로 30피트 순간이동\\n  화염 — 명중 시 1d10 화염 추가\\n  서리 — 명중 시 1d6 냉기, 대상 속도 -10피트\\n  언덕 — 명중 시 대형 이하를 넘어뜨림\\n  바위 — 반응행동으로 받은 피해를 1d12 + 건강만큼 줄임\\n  폭풍 — 반응행동으로 나를 친 상대에게 1d8 천둥\\n강인한 체격: 붙잡힘에서 벗어나는 판정에 이점.\\n대형 형태(5레벨): 추가 행동으로 10분 동안 커져서 근력 판정에 이점, 속도 +10피트. 긴 휴식마다 1회.\",\r\nHalfling = \"작은 크기.\\n용감함: 공포를 피하거나 끝내는 내성 굴림에 이점.\\n하플링의 기민함: 나보다 한 단계 큰 크리쳐가 있는 칸을 지나갈 수 있습니다(멈추지는 못합니다).\\n행운아: 명중 굴림·능력 판정·내성 굴림의 d20에서 1이 나오면 다시 굴려 새 값을 씁니다.\\n타고난 은신: 나보다 한 단계 이상 큰 크리쳐에 가려져 있으면 숨기를 할 수 있습니다.\",\r\nHuman = \"다재다능: 출신 재주 하나 더 (경계심·마법 입문자·야만적인 공격자·숙련자 중).\\n숙련: 아무 기술 하나에 숙련.\\n지략: 긴 휴식을 마칠 때마다 영웅적 영감(d20 하나를 다시 굴립니다).\",\r\nOrc = \"암시야 120피트: 빛이 없어도 약 36m까지 흑백으로 봅니다.\\n아드레날린 쇄도: 추가 행동으로 질주하면서 숙련 보너스만큼 임시 생명력. 숙련 보너스만큼, 짧은·긴 휴식에 다시 찹니다.\\n불굴의 인내력: 생명력이 0이 되었지만 즉사하지 않으면 대신 1로 버팁니다. 긴 휴식마다 1회.\",\r\nTiefling = \"암시야 60피트: 어둠 속에서도 약 18m까지 봅니다.\\n악마의 유산: 하나를 고릅니다. 3·5레벨에 주문 하나씩 더.\\n  심연 — 독 피해 저항, 독 분사 소마법\\n  저승 — 사령 피해 저항, 냉랭한 접촉 소마법\\n  지옥 — 화염 피해 저항, 화염 화살 소마법\\n다른 세계의 존재감: 단순마술 소마법.\" },\r\ncl = { Barbarian = \"격노로 버티며 큰 무기를 휘두르는 전사. 생명력이 가장 높고 단순합니다.\",\r\nBard = \"노래와 말로 동료를 돕는 주문시전자. 기술이 많고 바드의 고양감으로 아군 주사위를 올려 줍니다.\",\r\nCleric = \"신의 힘을 빌리는 주문시전자. 치유와 보호에 강하고 갑옷도 입습니다.\",\r\nDruid = \"자연의 주문을 쓰고 짐승으로 변신합니다 (야생 변신).\",\r\nFighter = \"무기와 갑옷의 달인. 가장 단순하고 튼튼해서 처음에 권합니다.\",\r\nMonk = \"맨손과 기로 빠르게 싸웁니다. 갑옷 없이 날렵하게.\",\r\nPaladin = \"맹세한 기사. 중갑과 근접전에 치유(치유의 손길)와 강타를 더합니다.\",\r\nRanger = \"활과 자연 주문의 사냥꾼. 사냥꾼의 표식으로 한 적을 몰아붙입니다.\",\r\nRogue = \"은신과 기술의 달인. 틈을 노린 한 방(암습 공격)이 큽니다.\",\r\nSorcerer = \"타고난 마법. 아는 주문은 적지만 마법변형으로 주문을 고쳐 씁니다.\",\r\nWarlock = \"계약으로 얻은 마법. 짧은 휴식마다 슬롯이 돌아오고, 섬뜩한 마탄이 주력입니다.\",\r\nWizard = \"주문책으로 가장 많은 주문을 쓰는 학자. 몸은 약합니다.\" },\r\n}\r\n\r\nif K.LITE then\r\nK.Cg.TIP.cl.Warlock = \"계약으로 얻은 마법. 섬뜩한 마탄이 주력이고, 마나로 가장 높은 레벨까지 원하는 레벨의 주문을 씁니다.\"\r\nlocal tp = K.Cg.TIP.sp\r\ntp.Elf = tp.Elf:gsub(\"요정 선조\", \"매혹 저항\"):gsub(\"\\n망아상태:[^\\n]*\", \"\")\r\ntp.Tiefling = tp.Tiefling:gsub(\"악마의 유산\", \"마족 혈통\"):gsub(\"  심연 —\", \"  독의 혈통 —\"):gsub(\"  저승 —\", \"  죽음의 혈통 —\")\r\n:gsub(\"  지옥 —\", \"  불꽃의 혈통 —\")\r\ntp.Dragonborn = tp.Dragonborn:gsub(\"용의 혈통: 고른 용의 피해 종류에 저항\", \"용인 원소: 산성·냉기·화염·번개·독 중 고른 원소의 피해에 저항\")\r\n:gsub(\"브레스 무기\", \"숨결\")\r\ntp.Goliath = tp.Goliath:gsub(\"  구름 —\", \"  바람 —\"):gsub(\"  화염 —\", \"  불꽃 —\"):gsub(\"  언덕 —\", \"  대지 —\")\r\ntp.Gnome = nil\r\ntp.Beastfolk = \"암시야 60피트: 어둠 속에서도 약 18m까지 봅니다.\\n예리한 감각: 감지 숙련.\\n발톱과 이빨: 맨손 공격이 1d6 + 근력 (베기·찌르기).\"\r\n.. \"\\n수인 혈통: 하나를 고릅니다.\\n  개 — 생존 숙련, 냄새로 쫓는 판정에 이점, 5피트 안에 아군이 있으면 공포 내성에 이점\"\r\n.. \"\\n  고양이 — 오르기 속도 = 이동 속도, 떨어질 때 피해 레벨 × 5 감소\\n  여우 — 하급 환영 소마법, 기만 숙련\"\r\n.. \"\\n  곰 — 운반량 두 배, 붙잡힘에서 벗어나는 판정에 이점, 레벨마다 생명력 +1\"\r\nend\r\n\r\n\r\nfunction K.btnRows(btns)\r\nlocal n = #btns\r\nlocal sizes = {}\r\nlocal left = n\r\nwhile left > 0 do\r\nlocal take = (left == 4) and 2 or math.min(3, left)\r\nsizes[#sizes + 1] = take\r\nleft = left - take\r\nend\r\nlocal out, i = {}, 1\r\nfor _, k in ipairs(sizes) do\r\nlocal row = {}\r\nfor j = i, i + k - 1 do row[#row + 1] = btns[j] end\r\nout[#out + 1] = '<div class=\"dnd-opt-btns\" style=\"margin:4px 0\">' .. table.concat(row) .. '</div>'\r\ni = i + k\r\nend\r\nreturn '<div style=\"margin:4px 0 10px\">' .. table.concat(out) .. '</div>'\r\nend\r\n\r\n\r\nfunction K.Cg.lines(t)\r\nlocal o = {}\r\nfor line in (t .. \"\\n\"):gmatch(\"([^\\n]*)\\n\") do\r\nif line:sub(1, 2) == \"  \" then\r\no[#o + 1] = '<span style=\"display:block;padding-left:12px\">· ' .. esc(trim(line)) .. '</span>'\r\nelseif line ~= \"\" then\r\no[#o + 1] = '<span style=\"display:block\">' .. esc(line) .. '</span>'\r\nend\r\nend\r\nreturn table.concat(o)\r\nend\r\n\r\nfunction K.Cg.html(id, start)\r\nlocal c = K.Cg.load(id)\r\nlocal keep = BTN_FIRST\r\nBTN_FIRST = true\r\nlocal b = { '<div class=\"dnd-intro\"><div class=\"dnd-intro-t\">❖ 눌러서 만들기</div>' }\r\nlocal fold = '<details style=\"margin:4px 0 6px\"><summary style=\"cursor:pointer;font-size:12px;color:#a8977a\">설명</summary><div class=\"dnd-opt-d\">'\r\nlocal function what(kind)\r\n\r\nreturn K.Cg.WHAT[kind] and ('<div class=\"dnd-opt-d\">' .. K.Cg.lines((K.Cg.WHAT[kind]:gsub(\"([요다]%.) \", \"%1\\n\"))) .. '</div>') or \"\"\r\nend\r\nlocal function row(title, kind, list, cur, note, tips)\r\nlocal btns, lines = {}, {}\r\nfor _, en in ipairs(list) do\r\nbtns[#btns + 1] = btn(koName(en), \"dnd_cg_\" .. kind .. \"_\" .. en:gsub(\" \", \"_\"), cur == en)\r\nlocal t = tips and tips[en]\r\nif t then lines[#lines + 1] = '<div style=\"margin:0 0 8px\"><b>' .. esc(koName(en)) .. '</b><br>' .. K.Cg.lines(t) .. '</div>' end\r\nend\r\nb[#b + 1] = '<div class=\"dnd-opt-t\">' .. title .. '</div>' .. what(kind) .. K.btnRows(btns)\r\nif #lines > 0 then b[#b + 1] = fold .. table.concat(lines) .. '</div></details>' end\r\nif note and note ~= \"\" then b[#b + 1] = '<div class=\"dnd-opt-d\">' .. note .. '</div>' end\r\nend\r\n\r\nlocal function bgLine(en)\r\nlocal r = BACKGROUNDS[en]\r\nlocal ab, sk = {}, {}\r\nfor _, a in ipairs(r.abilities) do ab[#ab + 1] = koName(a) end\r\nfor _, k in ipairs(r.skills) do sk[#sk + 1] = koName(k) end\r\nlocal feat, list = (r.feat or \"\"):match(\"^(.-) %((%a+)%)$\")\r\nfeat = feat or r.feat or \"\"\r\nlocal fk = (Feat.KO.feat[feat] or koName(feat)) .. (list and (\" (\" .. koName(list) .. \")\") or \"\")\r\n\r\nlocal who = K.Cg.BG_WHO[en] or (type(r.tip) == \"string\" and r.tip ~= \"\" and r.tip:gsub(\"%.$\", \"\")) or nil\r\nlocal own = {}\r\nfor _, x in ipairs(type(r.fx) == \"table\" and r.fx or {}) do own[#own + 1] = (K.FX[x] and K.FX[x].ko) or NAMES_KO[x] or x end\r\nreturn (who and (who .. \".\\n\") or \"\") .. \"능력치 보너스: \" .. table.concat(ab, \"·\") .. \" 중 하나에 +2, 다른 하나에 +1 (또는 셋 다 +1)\\n기술 숙련: \"\r\n.. table.concat(sk, \", \") .. \"\\n출신 재주: \" .. fk .. (#own > 0 and (\"\\n배경 특징: \" .. table.concat(own, \", \")) or \"\")\r\nend\r\nlocal function keys(t)\r\nlocal o = {}\r\nfor en in pairs(t) do if type(en) == \"string\" then o[#o + 1] = en end end\r\ntable.sort(o, function(x, y) return koName(x) < koName(y) end)\r\nreturn o\r\nend\r\nif c.done then\r\nlocal sh = loadSheet(id)\r\napplySheet(sh)\r\nlocal rows = K.pickRows(id, sh, loadPC(id))\r\nif rows ~= \"\" then\r\nb[#b + 1] = '<div>만들어졌습니다: <b>' .. esc(c.done) .. '</b>. 이어서 아래에서 고르면 됩니다 (나중에 <b>❖ 설정 → 캐릭터</b> 탭에서도 고를 수 있습니다).</div>'\r\n.. K.Cg.mcNote(c) .. rows\r\nelse\r\nb[#b + 1] = '<div>준비 끝: <b>' .. esc(c.done) .. '</b>. ' .. (K.START_DONE[start] or K.START_DONE.table) .. '</div>' .. K.Cg.mcNote(c)\r\nend\r\nb[#b + 1] = '</div>'\r\nBTN_FIRST = keep\r\nreturn table.concat(b)\r\nend\r\nlocal step = math.max(1, math.min(#K.Cg.PAGES, tonumber(c.step) or 1))\r\n\r\nlocal chosen = {}\r\nfor _, v in ipairs({ c.sp, c.cl, c.bg }) do chosen[#chosen + 1] = koName(v) end\r\nif c.bgx then chosen[#chosen + 1] = \"배경은 채팅으로\" end\r\nif c.lv and c.lv > 1 then chosen[#chosen + 1] = c.lv .. \"레벨\" end\r\nb[#b + 1] = '<div class=\"dnd-opt-d\"><b>' .. step .. '/' .. #K.Cg.PAGES .. ' · ' .. K.Cg.PAGES[step] .. '</b>'\r\n.. (#chosen > 0 and (' <span class=\"dnd-m\">— ' .. esc(table.concat(chosen, \" · \")) .. '</span>') or \"\") .. '</div>'\r\nlocal cl = c.cl and CLASSES[c.cl]\r\nlocal fields = c.sp and c.cl and c.bg and K.Form.build(K.Cg.fields(c), getState(id, \"dnd_rolled\"))\r\nlocal function gear(e)\r\nlocal o = {}\r\nfor k, n in pairs(e.items or {}) do o[#o + 1] = (n > 1 and (n .. \" \") or \"\") .. koName(k) end\r\ntable.sort(o)\r\nif (e.gp or 0) > 0 then o[#o + 1] = \"금화 \" .. e.gp end\r\nreturn table.concat(o, \", \")\r\nend\r\n\r\nlocal function scoreLine()\r\nif not fields then return nil end\r\nlocal sc = {}\r\nlocal i = 0\r\nfor n in fields[5]:gmatch(\"%d+\") do i = i + 1; sc[ABILS[i]] = tonumber(n) end\r\nfor n, a in fields[6]:gmatch(\"%+(%d) (%a+)\") do sc[a] = (sc[a] or 0) + tonumber(n) end\r\nlocal o = {}\r\nfor _, a in ipairs(ABILS) do o[#o + 1] = koName(a) .. \" \" .. (sc[a] or \"?\") end\r\nreturn table.concat(o, \" · \")\r\nend\r\nlocal need = '<div class=\"dnd-opt-d\">종족·클래스·배경을 먼저 골라 주십시오.</div>'\r\nif step == 1 then\r\nrow(\"종족\", \"sp\", keys(K.spOn()), c.sp, c.sp and \"혈통이 있는 종족은 만든 뒤 이어서 고릅니다.\" or nil, K.Cg.TIP.sp)\r\nelseif step == 2 then\r\nrow(\"클래스\", \"cl\", keys(K.clsOn()), c.cl, cl and esc(string.format((K.LITE and \"레벨당 생명력 d%d\" or \"생명력 주사위 d%d\") .. \" · 내성 %s · 주 능력치 %s\", cl.hit_die,\r\nkoName(cl.saves[1]) .. \"·\" .. koName(cl.saves[2]), koName(cl.primary[1]))) .. '<br>' .. featureSpans({ class = c.cl, level = c.lv or 1 }) or nil, K.Cg.TIP.cl)\r\nelseif step == 3 then\r\nlocal bgTips = {}\r\nfor en in pairs(BACKGROUNDS) do if type(en) == \"string\" then bgTips[en] = bgLine(en) end end\r\nlocal bgNote = c.bg and K.Cg.lines(bgLine(c.bg)) or nil\r\nif bgNote and fields then\r\nlocal o = {}\r\nfor n, a in fields[6]:gmatch(\"%+(%d) (%a+)\") do o[#o + 1] = koName(a) .. \" +\" .. n end\r\nbgNote = bgNote .. '<br>→ 지금은 <b>' .. esc(table.concat(o, \", \")) .. '</b> (클래스에 중요한 능력치부터 Lua가 붙입니다)'\r\nend\r\nrow(\"배경\", \"bg\", keys(K.bgsOn()), c.bg, bgNote, bgTips)\r\n\r\nb[#b + 1] = '<div class=\"dnd-opt-btns\" style=\"margin:4px 0\">' .. btn(\"직접 짓기 (채팅으로)\", \"dnd_cg_bgx\", c.bgx and true or false) .. '</div>'\r\n.. '<div class=\"dnd-opt-d\">' .. (c.bgx and \"배경은 채팅으로 정합니다. 나머지를 다 고른 뒤, 마지막 쪽 안내대로 어떤 사람이었는지 적어 보내면 AI가 같은 틀(능력치 셋, 기술 둘, 출신 재주 하나)로 배경을 짓고 캐릭터를 만듭니다. 시작 장비는 배경 몫 대신 금화 50입니다.\"\r\nor \"목록에 없는 배경을 원하면 직접 지을 수 있습니다.\") .. '</div>'\r\nelseif step == 4 then\r\nb[#b + 1] = '<div class=\"dnd-opt-t\">능력치</div>' .. what(\"ab\") .. K.btnRows({ btn(\"표준 배열\", \"dnd_cg_ab_standard\", c.ab ~= \"roll\"), btn(\"굴림 (4d6)\", \"dnd_cg_ab_roll\", c.ab == \"roll\") })\r\nlocal sl = scoreLine()\r\nlocal rolled = getState(id, \"dnd_rolled\")\r\nif c.bgx then\r\nb[#b + 1] = '<div class=\"dnd-opt-d\">' .. (c.ab == \"roll\" and type(rolled) == \"table\" and (\"굴린 값: \" .. esc(table.concat(rolled, \", \")) .. \". \") or \"\")\r\n.. \"클래스에 맞게 놓는 것과 배경 보너스 +2·+1은 배경이 정해진 뒤 AI가 붙입니다.</div>\"\r\nelse\r\nb[#b + 1] = sl and ('<div class=\"dnd-opt-d\">' .. esc(sl) .. ' <span class=\"dnd-m\">(클래스에 맞게 배치, 배경 보너스 +2/+1 포함)</span></div>') or need\r\nend\r\nelseif step == 5 then\r\nlocal want = K.Cg.want(c)\r\nif want > 0 then\r\nlocal skip, mine, btns, sl = {}, {}, {}, {}\r\nfor _, k in ipairs(c.bg and BACKGROUNDS[c.bg].skills or {}) do skip[k] = true end\r\nfor _, k in ipairs(c.sk) do mine[k] = true end\r\nfor _, k in ipairs(CLASSES[c.cl].skills.from) do\r\nif not skip[k] then\r\nbtns[#btns + 1] = btn(koName(k), \"dnd_cg_sk_\" .. k:gsub(\" \", \"_\"), mine[k])\r\nif SKILL_TIP[k] then sl[#sl + 1] = '<b>' .. esc(koName(k)) .. '</b> ' .. esc(SKILL_TIP[k]) end\r\nend\r\nend\r\nb[#b + 1] = '<div class=\"dnd-opt-t\">기술 · ' .. #c.sk .. '/' .. want .. '</div>' .. what(\"sk\") .. K.btnRows(btns)\r\n.. fold .. table.concat(sl, \"<br>\") .. '</div></details>'\r\n.. '<div class=\"dnd-opt-d\">' .. (c.bg and ('이미 있는 배경 기술: ' .. esc(koName(BACKGROUNDS[c.bg].skills[1]) .. \", \" .. koName(BACKGROUNDS[c.bg].skills[2])))\r\nor \"배경 기술 둘은 AI가 여기서 고르지 않은 것으로 정합니다.\") .. '</div>'\r\nelse\r\nb[#b + 1] = '<div class=\"dnd-opt-t\">기술</div>' .. need\r\nend\r\nelseif step == 6 then\r\nif cl then\r\nlocal auto = fields and fields[8]:sub(1, 1) or \"A\"\r\nlocal eq = c.eq or auto\r\nb[#b + 1] = '<div class=\"dnd-opt-t\">장비</div>' .. what(\"eq\") .. K.btnRows({ btn(\"A\", \"dnd_cg_eq_A\", eq == \"A\"), btn(\"B\", \"dnd_cg_eq_B\", eq == \"B\") })\r\n.. '<div class=\"dnd-opt-d\">' .. esc(gear(cl.equipment[eq])) .. '</div>'\r\nelse\r\nb[#b + 1] = '<div class=\"dnd-opt-t\">장비</div><div class=\"dnd-opt-d\">클래스를 먼저 골라 주십시오.</div>'\r\nend\r\nlocal lv = {}\r\nfor i = 1, K.maxLevelAll() do lv[#lv + 1] = btn(i .. \"레벨\", \"dnd_cg_lv_\" .. i, (c.lv or 1) == i) end\r\nb[#b + 1] = '<div class=\"dnd-opt-t\">레벨</div>' .. what(\"lv\") .. K.btnRows(lv)\r\nif (c.lv or 1) > 1 then\r\nb[#b + 1] = '<div class=\"dnd-opt-t\">레벨 올리는 방식</div><div class=\"dnd-opt-d\"><span style=\"display:block\">멀티클래스로 하면 1레벨로 만든 뒤,'\r\n.. ' 고른 레벨까지 레벨 업을 한 번씩 합니다. 레벨마다 클래스를 고를 수 있습니다.</span></div>'\r\n.. K.btnRows({ btn(\"한 클래스로 바로 \" .. c.lv .. \"레벨\", \"dnd_cg_mc_off\", not c.mc),\r\nbtn(\"멀티클래스로 (레벨 업 \" .. (c.lv - 1) .. \"번)\", \"dnd_cg_mc_on\", c.mc and true or false) })\r\nend\r\nelseif c.bgx then\r\n\r\nlocal o = { \"종족 \" .. (c.sp and koName(c.sp) or \"—\") .. \" · 클래스 \" .. (c.cl and koName(c.cl) or \"—\") .. \" · 배경 직접 짓기 · \" .. (c.lv or 1) .. \"레벨\",\r\n\"능력치 \" .. (c.ab == \"roll\" and \"굴림\" or \"표준 배열\") }\r\nlocal sk = {}\r\nfor _, k in ipairs(c.sk) do sk[#sk + 1] = koName(k) end\r\nif #sk > 0 then o[#o + 1] = \"기술 \" .. table.concat(sk, \", \") end\r\nif c.eq then o[#o + 1] = \"장비 \" .. c.eq end\r\nb[#b + 1] = '<div class=\"dnd-opt-t\">배경을 채팅으로 보내 주십시오</div><div class=\"dnd-opt-d\">' .. esc(table.concat(o, \"\\n\")):gsub(\"\\n\", \"<br>\") .. '</div>'\r\nif not (c.sp and c.cl) then b[#b + 1] = '<div class=\"dnd-opt-d\">종족·클래스를 먼저 골라 주십시오.</div>' end\r\nb[#b + 1] = '<div class=\"dnd-opt-d\">아래 입력창에 어떤 사람이었는지 적어 보내십시오. 예: <b>GM: 배경은 등대지기. 외딴 섬에서 밤마다 불을 지킨 사람</b>. 능력치·기술·재주까지 정해 두었다면 같이 적으면 됩니다. AI가 배경을 짓고 위에서 고른 대로 캐릭터를 만듭니다.</div>'\r\nb[#b + 1] = '<div class=\"dnd-opt-btns\" style=\"margin-top:10px\">' .. btn(\"처음부터\", \"dnd_cg_reset\", false) .. '</div>'\r\nelse\r\n\r\nlocal o = {}\r\no[#o + 1] = \"종족 \" .. (c.sp and koName(c.sp) or \"—\") .. \" · 클래스 \" .. (c.cl and koName(c.cl) or \"—\") .. \" · 배경 \" .. (c.bg and koName(c.bg) or \"—\") .. \" · \"\r\n.. ((c.mc and (c.lv or 1) > 1) and string.format(\"1레벨로 만들고 %d레벨까지 레벨 업 %d번 (멀티클래스)\", c.lv, c.lv - 1) or ((c.lv or 1) .. \"레벨\"))\r\nlocal sl = scoreLine()\r\nif sl then o[#o + 1] = \"능력치 \" .. sl end\r\nif fields then\r\nlocal sk = {}\r\nfor _, k in ipairs(BACKGROUNDS[c.bg].skills) do sk[#sk + 1] = koName(k) end\r\nfor k in fields[7]:gmatch(\"[^,]+\") do sk[#sk + 1] = koName(k) end\r\no[#o + 1] = \"기술 \" .. table.concat(sk, \", \")\r\no[#o + 1] = \"장비 \" .. fields[8]:sub(1, 1) .. \": \" .. gear(cl.equipment[fields[8]:sub(1, 1)])\r\nend\r\nb[#b + 1] = '<div class=\"dnd-opt-t\">이대로 만들겠습니까?</div><div class=\"dnd-opt-d\">' .. esc(table.concat(o, \"\\n\")):gsub(\"\\n\", \"<br>\") .. '</div>'\r\nif not fields then b[#b + 1] = need end\r\nb[#b + 1] = '<div class=\"dnd-opt-btns\" style=\"margin-top:10px\">' .. btn(\"이 캐릭터로 시작\", \"dnd_cg_go\", fields and true or false)\r\n.. btn(\"처음부터\", \"dnd_cg_reset\", false) .. '</div>'\r\nend\r\nif c.err then b[#b + 1] = '<div class=\"dnd-opt-d\" style=\"color:#ff8a80\">' .. esc(c.err) .. '</div>' end\r\n\r\nlocal nav = {}\r\nif step > 1 then nav[#nav + 1] = btn(\"◀ 이전 · \" .. K.Cg.PAGES[step - 1], \"dnd_cg_nav_prev\", false) end\r\nif step < #K.Cg.PAGES then nav[#nav + 1] = btn(K.Cg.PAGES[step + 1] .. \" · 다음 ▶\", \"dnd_cg_nav_next\", true) end\r\nb[#b + 1] = '<div class=\"dnd-opt-btns\" style=\"margin-top:10px\">' .. table.concat(nav) .. '</div></div>'\r\nBTN_FIRST = keep\r\nreturn table.concat(b)\r\nend\r\n\r\n\r\nfunction K.Form.html(id, text, idx)\r\nlocal f = K.Form.fields(text)\r\nlocal rest = {}\r\nfor line in (text:gsub(\"：\", \":\") .. \"\\n\"):gmatch(\"([^\\n]*)\\n\") do\r\nlocal k = line:match(\"^%s*[%-%*]?%s*([^:]-)%s*:\")\r\nif not (k and K.Form.LABELS[k:lower()]) and line:find(\"%S\") then rest[#rest + 1] = line end\r\nend\r\nlocal parts = {}\r\nfor _, k in ipairs({ { \"species\", \"종족\" }, { \"class\", \"클래스\" }, { \"background\", \"배경\" }, { \"scores\", \"능력치\" }, { \"bonus\", \"보너스\" },\r\n{ \"skills\", \"기술\" }, { \"equipment\", \"장비\" }, { \"level\", \"레벨\" } }) do\r\nif (f[k[1]] or \"\") ~= \"\" then parts[#parts + 1] = k[2] .. \" \" .. f[k[1]] end\r\nend\r\nlocal st, note = \"\", \"\"\r\nif idx and idx >= getChatLength(id) - 2 then st, note = tostring(getChatVar(id, \"dnd_form\") or \"\"):match(\"^(%a*)|(.*)$\") end\r\nst, note = st or \"\", note or \"\"\r\nlocal head = st == \"ok\" and note or \"캐릭터 시트\"\r\nlocal sub = st == \"ok\" and '<span class=\"dnd-vd\">Lua ok</span> · 만들어졌습니다'\r\nor st == \"bad\" and ('<span class=\"dnd-vd\">Lua bad</span> · ' .. esc(note))\r\nor \"양식\"\r\nlocal box = string.format('<div class=\"dnd-tag chk\" data-v=\"%s\"><div class=\"dnd-h\"><span class=\"dnd-chip\">❖ 캐릭터 시트</span><b>%s</b></div><div class=\"dnd-sub\">%s</div><div class=\"dnd-sub\">%s</div></div>',\r\nst == \"bad\" and \"bad:form\" or \"ok\", esc(head), esc(table.concat(parts, \" · \")), sub)\r\nreturn (#rest > 0 and (table.concat(rest, \"\\n\") .. \"\\n\\n\") or \"\") .. box\r\nend\r\n\r\nlocal function displayMessage(id, text, meta)\r\n\r\n\r\nlocal idx = type(meta) == \"table\" and tonumber(meta.index) or nil\r\nif K.CharCode.find(text) then return K.CharCode.html(id, text, idx) end\r\nif K.Form.fields(text) then return K.Form.html(id, text, idx) end\r\n\r\nlocal held = {}\r\nfor _, t in ipairs({ \"Thoughts\", \"thoughts\", \"Thinking\", \"thinking\", \"think\", \"Think\" }) do\r\ntext = text:gsub(\"<\" .. t .. \">.-</\" .. t .. \">\", function(s)\r\nheld[#held + 1] = s\r\nreturn \"\\2\" .. #held .. \"\\2\"\r\nend)\r\nend\r\ntext = K.holdQuoted(text, held)\r\n\r\nif not idx or idx >= getChatLength(id) - 4 then text = K.cutLeak(text) end\r\nlocal function back(s)\r\nif #held == 0 then return s end\r\nreturn (s:gsub(\"\\2(%d+)\\2\", function(i) return held[tonumber(i)] end))\r\nend\r\ntext = K.gmFix(text)\r\nlocal recent = not idx or idx >= getChatLength(id) - 4\r\n\r\nlocal um = recent and idx and idx >= 0 and getChat(id, idx)\r\nlocal mine = type(um) == \"table\" and um.role == \"user\"\r\n\r\nlocal korig = text\r\nif text:find(FIRST_MARK, 1, true) and K.En.on(id) then text = K.En.greeting(text) or text end\r\nif recent and not mine and familiarity(id) ~= \"3\" then\r\nlocal okt, t2 = pcall(termify, text)\r\nif okt and type(t2) == \"string\" then text = t2 end\r\nend\r\nif text:find(FIRST_MARK, 1, true) then\r\nlocal ui = \"\"\r\nif getChatLength(id) == 0 then\r\nlocal okd, d = pcall(buildDrawer, id, true, \"g\")\r\nlocal create = text:find(FIRST_MARK .. \"C\", 1, true)\r\nlocal start = korig:find(\"짐꾼\", 1, true) and \"porter\" or \"table\"\r\nlocal okc, cg = true, \"\"\r\nif create then okc, cg = pcall(K.Cg.html, id, start) end\r\nlocal intro = CREATE_INTRO:gsub(\"@START@\", function() return K.START_LINE[start] end)\r\nif okd and type(d) == \"string\" then ui = (create and ((okc and cg or \"\") .. intro) or FIRST_INTRO) .. \"\\n\" .. d end\r\nend\r\ntext = text:gsub(FIRST_MARK .. \"C?\\n?\", function() return ui ~= \"\" and (ui .. \"\\n\") or \"\" end, 1)\r\nend\r\nif not text:find(\"[\", 1, true) then return back(text) end\r\nlocal novice, atkShown = familiarity(id) == \"1\", false\r\nlocal latest = K.isNewest(id, idx)\r\nlocal optN = 0\r\nlocal debugOn = getChatVar(id, \"dnd_opt_debug\") == \"1\"\r\n\r\nif K.LANG_KO == nil or latest then K.LANG_KO = langKo() end\r\nK.MON_KO = K.LANG_KO\r\n\r\n\r\nif latest then\r\nlocal okc, rc = pcall(loadPC, id)\r\nif okc and type(rc) == \"table\" then Cond.cur = rc end\r\nend\r\nlocal ok, out = pcall(function()\r\nlocal drawTag\r\n\r\n\r\nlocal function drawOne(tag, rest)\r\nlocal fixed = K.isFixed(tag, rest)\r\nlocal h = drawTag(tag, fixed and K.fixShown(tag, rest) or rest)\r\nif type(h) == \"string\" and fixed then\r\nh = h:gsub('data%-v=\"bad:', 'data-v=\"fix:'):gsub(\"Lua bad:\", \"Lua 고침 · \")\r\nend\r\nreturn h\r\nend\r\ndrawTag = function(tag, rest)\r\n\r\nif (tag == \"CHECK\" or tag == \"SAVE\") and type(rest) == \"string\" then rest = K.dropWill(tag, rest) end\r\nif tag == \"ROUND\" then\r\nlocal rn = tonumber((rest or \"\"):match(\"^%s*(%d+)\"))\r\nreturn rn and K.roundHtml(rn) or \"\"\r\nend\r\nif tag == \"STATUS\" then\r\nlocal sf = split(rest)\r\nif latest and #sf >= 12 then\r\nlocal okS, h = pcall(statusHtml, id, sf, idx)\r\nif okS and type(h) == \"string\" then return h end\r\nend\r\n\r\n\r\nif #sf > 12 then return \"[STATUS|\" .. table.concat(sf, \"|\", 1, 12) .. \"]\" end\r\nreturn nil\r\nend\r\nlocal f = split(rest)\r\n\r\nif tag == \"EQUIP\" and #f == 4 and (f[2] == \"main\" or f[2] == \"off\") then table.remove(f, 2) end\r\n\r\n\r\n\r\nif not debugOn and rest:find(\"|bad:the same tag twice, ignored|\", 1, true) then return \"\" end\r\nif tag == \"OPT\" and not (f[#args(f) + 1] or \"\"):match(\"^bad:\") then\r\n\r\nlocal oa = args(f)\r\nlocal okOpt = f[#oa + 1] == \"ok\"\r\nif okOpt then optN = optN + 1 end\r\nreturn optHtml(f, (latest and okOpt) and optN or nil)\r\nend\r\n\r\n\r\nif tag == \"HP\" and latest then\r\n\r\n\r\nif loadCombat(id).active and text:find(\"[STATUS|\", 1, true) then return \"\" end\r\nlocal mine, foes = (f[2] or \"\"):match(\"^(.-) ‖ (.*)$\")\r\nif mine then\r\n\r\n\r\n\r\n\r\nif foes:find(\"전투 종료\", 1, true) then return \"\" end\r\nreturn '<div class=\"dnd-fight\">' .. ('<span class=\"dnd-g\">† 순서</span>' .. esc(toKo(f[1] or \"\"))\r\n.. '<div class=\"dnd-hr\"></div>') .. '<div class=\"dnd-us\"><span class=\"dnd-g\">♥ 아군</span>' .. esc(toKo(mine)) .. '</div>'\r\n.. '<div class=\"dnd-them\"><span class=\"dnd-g\">♥ 적</span>' .. esc(toKo(foes)) .. '</div></div>'\r\nend\r\nend\r\nif tag == \"GM\" then\r\nreturn '<div class=\"dnd-intro\" style=\"margin:10px auto 6px\"><div class=\"dnd-intro-t\">❖ GM 조언</div><div>' .. esc(table.concat(f, \", \")) .. '</div></div>'\r\nend\r\nif tag == \"ALLY\" then return Ally.html(f) end\r\nif tag == \"GIVE\" then\r\n\r\nlocal a = args(f)\r\nlocal verdict = f[#a + 1] or \"\"\r\nlocal function who(v) v = trim(v or \"\"); return (v == \"Player\" or v == \"\") and \"당신\" or v end\r\nlocal res = f[#a + 2] or \"\"\r\nlocal slot = res:match(\"^worn (%a+)$\")\r\nlocal where = slot and ({ armor = \"입었습니다\", main = \"손에 들었습니다\", off = \"들었습니다\" })[slot] or \"가방에 넣었습니다\"\r\nlocal n = tonumber(a[4] or \"1\") or 1\r\nreturn string.format('<div class=\"dnd-tag%s\" data-v=\"%s\"><div class=\"dnd-h\"><span class=\"dnd-chip\">▪ 건네주기</span><b>%s</b>%s · %s → %s</div><div class=\"dnd-sub\">%s</div></div>',\r\nverdict == \"\" and \" pend\" or \"\", esc(verdict), esc(koName(Canon.name(a[3] or \"\"))), n > 1 and (\" ×\" .. n) or \"\",\r\nesc(who(a[1])), esc(who(a[2])),\r\nverdict == \"ok\" and (esc(who(a[2])) .. K.josa(who(a[2]), \"이\", \"가\") .. \" \" .. where .. \" · \" .. esc(K.acdc(f[#a + 3] or \"\")) .. ' · <span class=\"dnd-vd\">Lua ok</span>')\r\nor K.vdHtml(verdict))\r\nend\r\nif tag == \"FIX\" then\r\n\r\nlocal who, msg = Ally.ko(f[2] or \"\"), nil\r\nif f[1] == \"up\" then\r\nmsg = who .. K.josa(who, \"은\", \"는\") .. \" 쓰러지지 않았습니다 (생명력 \" .. (f[3] or \"\") .. \")\"\r\nelseif f[1] == \"down\" then\r\nmsg = who .. K.josa(who, \"이\", \"가\") .. \" 쓰러졌습니다 (생명력 \" .. (f[3] or \"\") .. \")\"\r\nelseif f[1] == \"still\" then\r\nmsg = who .. K.josa(who, \"은\", \"는\") .. \" 아직 쓰러져 있습니다 (생명력 \" .. (f[3] or \"\") .. \")\"\r\nelseif f[1] == \"rose\" then\r\nmsg = who .. K.josa(who, \"이\", \"가\") .. \" 다시 일어났습니다 (생명력 \" .. (f[3] or \"\") .. \")\"\r\nelseif f[1] == \"attack\" then\r\nlocal hit = f[4] == \"miss\" and \"빗나갔습니다\" or \"맞았습니다\"\r\nmsg = f[2] == \"Player\" and (\"당신의 공격은 \" .. hit .. \" (\" .. Ally.ko(f[3] or \"\") .. \")\")\r\nor (who .. \"의 공격은 당신에게 \" .. hit)\r\nelseif f[1] == \"check\" then\r\nmsg = \"당신의 \" .. toKo(f[2] or \"\") .. \" 판정은 \" .. (f[3] == \"success\" and \"성공했습니다\" or \"실패했습니다\")\r\nelseif f[1] == \"save\" then\r\nmsg = who .. \"의 내성은 \" .. (f[3] == \"success\" and \"성공했습니다\" or \"실패했습니다\") .. (f[4] == \"lr\" and \" (전설 저항)\"\r\nor f[4] == \"nolr\" and \" (피해만 주는 효과라 전설 저항을 쓰지 않음)\" or f[4] == \"mr\" and \" (마법 저항)\" or \"\")\r\nelseif f[1] == \"death\" and f[2] == \"norise\" then\r\nmsg = \"당신은 깨어나지 못했습니다 (죽음 내성은 20이 아니라 \" .. (f[3] == \"success\" and \"성공\" or \"실패\") .. \")\"\r\nelseif f[1] == \"death\" and f[2] == \"rose\" then\r\nmsg = \"죽음 내성에서 20이 나와 당신이 깨어났습니다 (생명력 1)\"\r\nelseif f[1] == \"death\" then\r\nmsg = \"당신의 죽음 내성은 \" .. (f[2] == \"success\" and \"성공이었습니다\" or \"실패였습니다\")\r\nelseif f[1] == \"insp\" then\r\n\r\nmsg = \"영웅적 영감으로 죽음 내성을 다시 굴렸습니다 (\" .. (f[2] or \"?\") .. \" → \" .. (f[3] or \"?\") .. \"): \"\r\n.. (f[4] == \"rose\" and \"20, 생명력 1로 깨어났습니다\" or f[4] == \"success\" and \"성공, 아직 살아 있습니다\"\r\nor f[4] == \"dead\" and \"그래도 실패, 죽었습니다\" or \"실패\")\r\nelseif f[1] == \"absent\" then\r\n\r\nmsg = who .. K.josa(who, \"은\", \"는\") .. \" 싸움에 끼지 않았습니다 (이 레벨에 너무 센 싸움이라 Lua가 뺐습니다)\"\r\nelseif f[1] == \"dead\" then\r\n\r\nmsg = \"당신은 죽었습니다\" .. (f[3] == \"massive\" and \" (대량 피해: 남은 생명력을 넘은 피해가 최대 생명력 이상)\" or \"\")\r\n.. \". 이 뒤의 이야기는 일어나지 않았습니다\"\r\nend\r\nreturn msg and ('<div class=\"dnd-passive miss\">⚖ 판정 정정 · ' .. esc(msg) .. '</div>') or \"\"\r\nend\r\nif tag == \"CONCSAVE\" then\r\n\r\n\r\nlocal total, lost = (tonumber(f[3]) or 0) + (tonumber(f[4]) or 0), f[6] == \"lost\"\r\nreturn '<div class=\"dnd-passive' .. (lost and \" miss\" or \"\") .. '\">◌ 집중 내성 · ' .. esc(Ally.ko(f[1] or \"\")) .. ' · '\r\n.. esc(koName(f[2] or \"\")) .. ' · 건강 내성 ' .. total .. ' vs 난이도 ' .. esc(f[5] or \"\") .. ' · '\r\n.. (lost and \"깨짐 · 이 답 끝까지는 유지\" or \"유지\") .. '</div>'\r\nend\r\nif tag == \"PLACE\" then\r\nlocal a = args(f)\r\nlocal where = f[#a + 2]\r\n\r\nlocal change, nm = f[#a + 3], f[#a + 4]\r\nif change then\r\nlocal parts = {}\r\nif (nm or \"\") ~= \"\" then parts[#parts + 1] = esc(nm) end\r\nif change == \"enter\" then parts[#parts + 1] = \"마을에 들어섰습니다 · 상점이 열립니다\" elseif change == \"leave\" then parts[#parts + 1] = \"마을을 벗어났습니다 · 상점이 닫힙니다\" end\r\nif #parts == 0 then return \"\" end\r\nreturn '<div class=\"dnd-passive\">◇ ' .. table.concat(parts, \" · \") .. '</div>'\r\nend\r\nif where == \"town\" then return '<div class=\"dnd-passive\">◇ 마을에 들어섰습니다 · 상점이 열립니다</div>' end\r\nif where == \"wild\" then return '<div class=\"dnd-passive\">◇ 마을을 벗어났습니다 · 상점이 닫힙니다</div>' end\r\nreturn debugOn and ('<div class=\"dnd-passive miss\">◇ 장소 · ' .. esc(table.concat(f, \" · \")) .. '</div>') or \"\"\r\nend\r\nif tag == \"COMBAT\" then\r\n\r\n\r\n\r\n\r\nlocal verdict, surp, names, deadlyF = \"\", nil, {}, false\r\nlocal uwF = false\r\nfor _, v in ipairs(f) do\r\nif v == \"ok\" or v:match(\"^bad\") then verdict = v\r\nelseif v == \"surprise\" or v == \"ambush\" then surp = v\r\nelseif v == \"deadly\" then deadlyF = verdict ~= \"\"\r\nelseif v == \"underwater\" then uwF = true\r\nelseif v ~= \"\" then names[#names + 1] = v end\r\nend\r\n\r\nlocal leftOut = {}\r\nfor nm in ((verdict:match(\"XP: ([^;]-) left out\") or \"\") .. \",\"):gmatch(\"%s*([^,]+),\") do leftOut[trim(nm)] = true end\r\nlocal started = verdict ~= \"\" and not verdict:find(\"already in combat\", 1, true)\r\nlocal count, chips = {}, {}\r\nfor _, v in ipairs(names) do\r\nlocal h = v:match(\"^%s*%+%s*(.-)%s*$\")\r\nif h then\r\n\r\nlocal nm = h:match(\"^([^/]+)/\")\r\nlocal hk = not nm and Canon.name(h)\r\nlocal label = nm and trim(nm) or hk\r\nif started and hk and MONSTERS[hk] then\r\ncount[hk] = (count[hk] or 0) + 1\r\nlabel = hk .. \" \" .. count[hk]\r\nend\r\nchips[#chips + 1] = '<span class=\"dnd-foe\" style=\"border-color:#6a9a6a;color:#9fd09f\">도움 · ' .. esc(toKo(label)) .. '</span>'\r\nelse\r\nlocal base, hpo = v:match(\"^(.-)%s*%([Hh][Pp]%s*(%d+)%)%s*$\")\r\nlocal kind = base or v\r\nlocal label = kind\r\nif started and MONSTERS[kind] then\r\ncount[kind] = (count[kind] or 0) + 1\r\nlabel = kind .. \" \" .. count[kind]\r\nend\r\nlocal out = leftOut[label]\r\nchips[#chips + 1] = '<span class=\"dnd-foe' .. ((MONSTERS[kind] and not out) and \"\" or \" unk\") .. '\"' .. (out and ' style=\"text-decoration:line-through;opacity:.55\"' or \"\")\r\n.. '>' .. esc(toKo(label)) .. (hpo and (' <small>생명력 ' .. hpo .. '</small>') or \"\") .. '</span>'\r\nend\r\nend\r\nlocal sub = (uwF and \"물속 싸움 · \" or \"\") .. (surp == \"surprise\" and \"기습 · 적이 놀라 우선권 굴림에 불리점을 받았습니다 · \"\r\nor surp == \"ambush\" and \"매복 · 우리 편이 놀라 우선권 굴림에 불리점을 받았습니다 · \" or \"\")\r\n\r\n\r\nlocal warn = deadlyF and '<div class=\"dnd-sub\" style=\"color:#e06060;font-weight:700\">⚠ 절망적인 싸움 · 이길 수 없을지도 모릅니다. 도망, 항복, 협상도 길입니다.</div>' or \"\"\r\n\r\n\r\n\r\n\r\n\r\nlocal hint = \"\"\r\nif latest and started then\r\nlocal cb = loadCombat(id)\r\nlocal opened = cb.active and cb.last == \"Player\"\r\nlocal t = opened and \"싸움을 연 행동은 바로 나갔습니다. 다음 메시지에 다음 행동을 쓰면 적들의 차례 뒤 당신 차례에 나가고, 아무 말 없이 보내면 알아서 진행됩니다.\"\r\nor surp == \"ambush\" and \"적이 먼저 덮쳤습니다. 다음 메시지에 행동을 쓰면 우선권 순서대로 당신 차례에 나가고, 아무 말 없이 보내면 알아서 진행됩니다.\"\r\n\r\nor \"우선권이 정해졌습니다. 아무 말 없이 보내면 1라운드가 우선권 순서대로 진행되고, 선언한 행동은 당신 차례에 나갑니다. 다른 행동을 쓰거나 선택지를 고르면 그 행동으로 바뀝니다.\"\r\nhint = '<div class=\"dnd-sub\" style=\"color:#e2b75a;font-weight:600\">▶ ' .. t .. '</div>'\r\nend\r\nreturn string.format('<div class=\"dnd-tag war\" data-v=\"%s\"><div class=\"dnd-h\"><span class=\"dnd-chip\">◈ 전투 시작</span>%s</div>%s<div class=\"dnd-sub\">%s%s</div>%s</div>',\r\nesc(verdict), table.concat(chips), warn, esc(sub), verdict == \"\" and \"검증 전\" or ('<span class=\"dnd-vd\">Lua ' .. esc(verdict) .. \"</span>\"), hint)\r\nend\r\nif tag == \"COMBAT_END\" then\r\n\r\nlocal why = trim(table.concat(f, \"|\"))\r\nlocal ko = K.END_KO[why:lower()] or toKo(why)\r\nreturn '<div class=\"dnd-tag war\"><div class=\"dnd-h\"><span class=\"dnd-chip\">◇ 전투 종료</span>' .. esc(ko) .. '</div></div>'\r\nend\r\n\r\nif tag == \"ADVANCE\" then\r\nlocal a = args(f)\r\nlocal verdict, note = f[#a + 1] or \"\", f[#a + 2] or \"\"\r\nnote = note:gsub(\"^miss (%(.*)$\", \"%1\")\r\nlocal function nm(x) return (x == \"Player\" or x == \"\") and \"당신\" or toKo(x or \"\") end\r\n\r\nlocal recipKo = \"\"\r\nlocal rAt = note:find(\"; reciprocal: \", 1, true)\r\nif rAt then\r\nlocal r = note:sub(rAt + 14)\r\nnote = note:sub(1, rAt - 1)\r\nlocal rw, rd, rb = r:match(\"^(.-) Constitution save d20 (%d+)([%+%-]%d+) vs DC 15\")\r\nlocal rn, rrest = r:match(\", failed: (%d+)[^,]*, (.*)$\")\r\nrecipKo = \" · 상호: \" .. nm(rw) .. \" \" .. koName(\"Constitution\") .. \" 내성 d20 \" .. tostring(rd or \"?\") .. tostring(rb or \"\")\r\n.. (rn and (\" 실패, 자극 \\2\" .. rn .. \"\\3, \" .. K.arResultKo((rw == \"Player\" or rw == \"\") and \"내\" or toKo(rw or \"\"), rrest, nil, rn)) or \", 버팀\")\r\nend\r\nlocal res = ({ hit = \"명중\", miss = \"빗나감\", crit = \"치명\" })[(a[8] or \"\"):lower()] or (a[8] or \"\")\r\n\r\n\r\nlocal bigStim = \"\"\r\nif (a[8] or \"\"):lower() ~= \"miss\" and verdict ~= \"\" then\r\nlocal vv = verdict:gsub(\"%-&gt;\", \"->\")\r\nlocal n = tonumber(vv:match(\"stim %-?%d+%->(%d+)\") or a[11] or \"\")\r\nif n then\r\nfor _, more in note:gmatch(\"%(([%a' ]+): %+(%d+) %a+%)\") do n = n + (tonumber(more) or 0) end\r\nlocal ty = note:match(\"^(%u%l+) \")\r\nbigStim = ' · 자극 <span class=\"dnd-big\">' .. n .. '</span>' .. (ty and (\" \" .. esc(K.stimKo(ty))) or \"\")\r\nend\r\nend\r\nlocal shown = K.climaxKo(note):gsub(\"^(%a+) \", function(ty) return K.stimKo(ty) .. \" \" end):gsub(\"numbness %-?\", \"둔감 -\")\r\n:gsub(\", Edging: (%d+) successes, (%d+) failures\", \", 임계: 성공 %1 · 실패 %2\"):gsub(\", Edging\", \", 임계\")\r\n:gsub(\", CLIMAX: arousal (%d+)%->(%d+) %(recovery dice (%d+)%)\", \", 절정: %1→%2 (회복 주사위 %3)\")\r\n:gsub(\"Incapacitated until round (%d+) %b()\", \"%1라운드까지 행동불능\"):gsub(\"Incapacitated until round (%d+)\", \"%1라운드까지 행동불능\"):gsub(\"Incapacitated for (%d+) rounds?\", \"%1라운드 행동불능\")\r\nreturn (string.format('<div class=\"dnd-tag atk\" data-v=\"%s\"><div class=\"dnd-h\"><span class=\"dnd-chip\">♡ 접근</span><b>%s → %s</b> · %s · %s%s</div><div class=\"dnd-sub\">d20 %s %s · 방어도 %s · %s%s%s</div></div>',\r\nesc(verdict), esc(nm(a[1])), esc(nm(a[2])), esc(toKo(a[3] or \"\")), (a[4] or \"\"):lower() == \"unwilling\" and \"비동의\" or \"동의\", bigStim,\r\nK.d20Html(a[5] or \"?\"), esc(a[6] or \"\"), esc(a[7] or \"?\"), esc(res), (shown ~= \"\" and shown ~= \"-\" and shown ~= \"miss\")\r\nand (\" · \" .. esc(K.arResultKo((a[2] == \"Player\" or a[2] == \"\") and \"내\" or toKo(a[2] or \"\"), note, nil, a[11])) .. esc(recipKo)) or \"\",\r\n\" · \" .. (verdict == \"\" and \"검증 전\" or K.vdHtml(verdict))):gsub(\"\\2\", '<span class=\"dnd-big\">'):gsub(\"\\3\", \"</span>\"))\r\nend\r\n\r\nif tag == \"SCENE\" then\r\nlocal a = args(f)\r\nlocal verdict, note = f[#a + 1] or \"\", f[#a + 2] or \"\"\r\nlocal what\r\nif (a[1] or \"\"):lower() == \"end\" then what = \"장면 끝\"\r\nelse\r\nlocal o = {}\r\nfor nm, kd in (note:gsub(\"^scene: \", \"\") .. \", \"):gmatch(\"(.-) %((.-)%), \") do o[#o + 1] = toKo(nm) .. \" (\" .. toKo(kd) .. \" 대역)\" end\r\nwhat = #o > 0 and table.concat(o, \", \") or toKo(a[1] or \"\")\r\nend\r\nreturn string.format('<div class=\"dnd-tag\" data-v=\"%s\"><div class=\"dnd-h\"><span class=\"dnd-chip\">◇ 장면</span><b>%s</b> · %s</div></div>',\r\nesc(verdict), esc(what), verdict == \"\" and \"검증 전\" or K.vdHtml(verdict))\r\nend\r\n\r\nif tag == \"HDHEAL\" then\r\nlocal a = args(f)\r\nlocal verdict, note = f[#a + 1] or \"\", f[#a + 2] or \"\"\r\nlocal function nm(x) return (x == \"Player\" or x == \"\") and \"당신\" or toKo(x or \"\") end\r\n\r\nlocal shown = note:gsub(\"^(%d+) Hit Point Dice %(([^)]*)%), %+(%d+) HP, (%d+)/(%d+)\", \"생명력 주사위 %1개를 써서(%2) 생명력 +%3, %4/%5\")\r\n\r\nshown = shown:gsub(\" %(kit uses (%d+)%)\", \" · \" .. koName(K.KIT) .. \" %1회 남음\")\r\n:gsub(\" %(([^():]+): half%)\", function(w) return \" · \" .. toKo(w) .. \": 절반\" end)\r\n:gsub(\" %(([^()]-) (%d+) left%)\", function(w, n) return \" · \" .. toKo(w) .. \" \" .. n .. \"회 남음\" end)\r\n:gsub(\" %(free%)\", \" · 대가 없이\")\r\nreturn string.format('<div class=\"dnd-tag heal\" data-v=\"%s\"><div class=\"dnd-h\"><span class=\"dnd-chip\">✚ 회복</span><b>%s → %s</b> · %s</div><div class=\"dnd-sub\">%s%s</div></div>',\r\nesc(verdict), esc(nm(a[1])), esc(nm(a[2])), esc(toKo(a[3] or \"\")), shown ~= \"\" and (esc(shown) .. \" · \") or \"\", verdict == \"\" and \"검증 전\" or K.vdHtml(verdict))\r\nend\r\nif tag == \"REACT\" or tag == \"BOND\" then\r\nlocal a = args(f)\r\nlocal verdict = f[#a + 1] or \"\"\r\nlocal function nm(x) return (x == \"Player\" or x == \"\") and \"당신\" or toKo(x or \"\") end\r\nlocal what = tag == \"REACT\" and (nm(a[1]) .. \" · \" .. toKo(a[2] or \"\") .. ((a[3] or \"\") ~= \"\" and (\" → \" .. ((a[3] or \"\"):lower() == \"all\" and \"아군 모두\" or nm(a[3]))) or \"\"))\r\nor (nm(a[1]) .. \" ↔ \" .. nm(a[2]) .. \" · \" .. toKo(a[3] or \"\"))\r\nreturn string.format('<div class=\"dnd-tag\" data-v=\"%s\"><div class=\"dnd-h\"><span class=\"dnd-chip\">%s</span><b>%s</b></div><div class=\"dnd-sub\">%s</div></div>',\r\nesc(verdict), tag == \"REACT\" and \"♡ 반응\" or \"♡ 묶기\", esc(what), verdict == \"\" and \"검증 전\" or K.vdHtml(verdict))\r\nend\r\n\r\nif tag == \"SWAP\" then\r\nlocal a = args(f)\r\nlocal verdict = f[#a + 1] or \"\"\r\nlocal function nm(x) return (x == \"Player\" or x == \"\") and \"당신\" or toKo(x or \"\") end\r\nreturn string.format('<div class=\"dnd-tag\" data-v=\"%s\"><div class=\"dnd-h\"><span class=\"dnd-chip\">♡ 감각 묶기</span><b>%s ↔ %s</b> · %s</div><div class=\"dnd-sub\">%s</div></div>',\r\nesc(verdict), esc(nm(a[1])), esc(nm(a[2])), esc(toKo(a[3] or \"\")), verdict == \"\" and \"검증 전\" or K.vdHtml(verdict))\r\nend\r\n\r\nif tag == \"INHIB\" then\r\nlocal a = args(f)\r\nlocal verdict, note = f[#a + 1] or \"\", f[#a + 2] or \"\"\r\nlocal who = (a[1] == \"Player\" or a[1] == \"\") and \"당신\" or toKo(a[1] or \"\")\r\nlocal shown = note:gsub(\"→\", \"->\"):gsub(\"%-&gt;\", \"->\"):gsub(\"^inhibition ([+-]%d+) %-> ([+-]%d+)$\", \"억제 %1 → %2\")\r\n:gsub(\"^inhibition ([+-]%d+) < spell attack ([+-]%d+): it works$\", \"억제 %1 < 주문 공격 %2: 통함\")\r\n:gsub(\"^inhibition ([+-]%d+) >= spell attack ([+-]%d+): no effect$\", \"억제 %1 ≥ 주문 공격 %2: 효과 없음\")\r\nreturn string.format('<div class=\"dnd-tag\" data-v=\"%s\"><div class=\"dnd-h\"><span class=\"dnd-chip\">♡ 억제</span><b>%s</b> · %s</div><div class=\"dnd-sub\">%s%s</div></div>',\r\nesc(verdict), esc(who), esc(toKo(a[2] or \"\")), shown ~= \"\" and shown ~= \"-\" and (esc(shown) .. \" · \") or \"\",\r\nverdict == \"\" and \"검증 전\" or K.vdHtml(verdict))\r\nend\r\n\r\nif tag == \"CLIMAX\" then\r\nlocal a = args(f)\r\nlocal verdict, note = f[#a + 1] or \"\", f[#a + 2] or \"\"\r\nlocal who = (a[1] == \"Player\" or a[1] == \"\") and \"당신\" or toKo(a[1] or \"\")\r\nlocal res = (a[5] or \"\"):lower() == \"success\" and \"성공\" or (a[5] or \"\"):lower() == \"failure\" and \"실패\" or (a[5] or \"\")\r\nlocal shown = K.climaxKo(note):gsub(\"CLIMAX: arousal (%d+)%->(%d+) %(recovery dice (%d+)%)\", \"절정: 흥분도 %1→%2 (회복 주사위 %3)\")\r\n:gsub(\"Incapacitated until round (%d+) %b()\", \"%1라운드까지 행동불능\"):gsub(\"Incapacitated until round (%d+)\", \"%1라운드까지 행동불능\"):gsub(\"Incapacitated for (%d+) rounds?\", \"%1라운드 행동불능\")\r\n:gsub(\"Edging: (%d+) successes, (%d+) failures\", \"임계: 성공 %1 · 실패 %2\"):gsub(\"three successes: no longer Edging\", \"성공 셋: 임계에서 벗어남\")\r\n:gsub(\"a natural 20: no longer Edging\", \"자연 20: 임계에서 벗어남\"):gsub(\"arousal (%d+)/(%d+)\", \"흥분도 %1/%2\")\r\n:gsub(\"CLIMAX with no recovery dice left: out of the fight, as one defeated\", \"회복 주사위 없이 절정: 싸움에서 빠짐\")\r\n:gsub(\"no longer Edging %(it ended earlier in this reply%): nothing more\", \"이번 답에서 임계가 이미 끝나 더 굴리지 않음\")\r\n\r\nlocal md = (a[2] or \"\"):lower()\r\nif md == \"now\" or md == \"end\" or md == \"vuln\" then\r\nshown = shown:gsub(\"^no climax: (%d+) to its maximum, not under (%d+)\", \"절정 없음: 최대까지 %1 남음 (%2 미만이어야 함)\")\r\n:gsub(\"^no climax: \", \"절정 없음: \"):gsub(\"^no longer Incapacitated\", \"행동불능 끝\"):gsub(\", numbness (%d+)\", \", 둔감 %1\")\r\n:gsub(\"^vulnerable to stimulation while that climax's Incapacitated lasts\", \"그 절정의 행동불능 동안 자극에 취약\")\r\nlocal chip = md == \"now\" and \"♡ 절정\" or md == \"end\" and \"♡ 절정 끝\" or \"♡ 절정 뒤 취약\"\r\nreturn string.format('<div class=\"dnd-tag chk\" data-v=\"%s\"><div class=\"dnd-h\"><span class=\"dnd-chip\">%s</span><b>%s</b>%s</div><div class=\"dnd-sub\">%s%s</div></div>',\r\nesc(verdict), chip, esc(who), (a[3] and trim(a[3]) ~= \"\") and (\" · \" .. esc(toKo(a[3]))) or \"\",\r\nshown ~= \"\" and shown ~= \"-\" and (esc(shown) .. \" · \") or \"\", verdict == \"\" and \"검증 전\" or K.vdHtml(verdict))\r\nend\r\nreturn string.format('<div class=\"dnd-tag chk\" data-v=\"%s\"><div class=\"dnd-h\"><span class=\"dnd-chip\">♡ 절정 내성</span><b>%s</b> d20 %s %s · 난이도 %s · %s</div><div class=\"dnd-sub\">%s%s</div></div>',\r\nesc(verdict), esc(who), K.d20Html(a[2] or \"?\"), esc(a[3] or \"\"), esc(a[4] or \"15\"), esc(res), shown ~= \"\" and shown ~= \"-\" and (esc(shown) .. \" · \") or \"\",\r\nverdict == \"\" and \"검증 전\" or K.vdHtml(verdict))\r\nend\r\n\r\nif tag == \"STIM\" or tag == \"SOOTHE\" or tag == \"NUMB\" then\r\nlocal a = args(f)\r\nlocal verdict, note = f[#a + 1] or \"\", f[#a + 2] or \"\"\r\nlocal who = (a[1] == \"Player\" or a[1] == \"\") and \"당신\" or toKo(a[1] or \"\")\r\nlocal chip = tag == \"STIM\" and \"♡ 자극\" or tag == \"SOOTHE\" and \"♡ 진정\" or \"♡ 둔감\"\r\nlocal what\r\nif tag == \"STIM\" then\r\nlocal ty = (a[3] or \"\"):lower():gsub(\"^%l\", string.upper)\r\nwhat = who .. \" · +\" .. (a[6] or \"?\") .. \" \" .. K.stimKo(ty) .. ((a[7] or \"\"):lower() == \"half\" and \" (절반)\" or \"\")\r\nelseif tag == \"SOOTHE\" then what = who .. \" · -\" .. (a[5] or \"?\")\r\nelse what = who .. \" · \" .. (a[2] or \"?\") end\r\nnote = note:gsub(\" %(resisted: ([^)]*)%)\", function(w) return \" (저항: \" .. K.stimWhyKo(w) .. \")\" end)\r\n:gsub(\" %(vulnerable: ([^)]*)%)\", function(w) return \" (취약: \" .. K.stimWhyKo(w) .. \")\" end)\r\nlocal shown = (note ~= \"\" and note ~= \"-\") and (\"흥분도 \" .. note:gsub(\"numbness %-?\", \"둔감 -\"):gsub(\"^numbness \", \"\")\r\n:gsub(\", Edging: (%d+) successes, (%d+) failures\", \", 임계: 성공 %1 · 실패 %2\"):gsub(\", Edging\", \", 임계\")\r\n:gsub(\", CLIMAX: arousal (%d+)%->(%d+) %(recovery dice (%d+)%)\", \", 절정: %1→%2 (회복 주사위 %3)\")\r\n:gsub(\"Incapacitated until round (%d+) %b()\", \"%1라운드까지 행동불능\"):gsub(\"Incapacitated until round (%d+)\", \"%1라운드까지 행동불능\"):gsub(\"Incapacitated for (%d+) rounds?\", \"%1라운드 행동불능\")\r\n:gsub(\", CLIMAX with no recovery dice left: out of the fight, as one defeated\", \", 회복 주사위 없이 절정: 싸움에서 빠짐\")) or \"\"\r\nif tag == \"NUMB\" then shown = (note:match(\"numbness (%d+)\") and (\"둔감 \" .. note:match(\"numbness (%d+)\"))) or \"\" end\r\nif tag == \"STIM\" and shown ~= \"\" then\r\nlocal ty = (a[3] or \"\"):lower():gsub(\"^%l\", string.upper)\r\nshown = K.arResultKo((a[1] == \"Player\" or a[1] == \"\") and \"내\" or toKo(a[1] or \"\"), f[#a + 2] or \"\", ty, a[6])\r\nwhat = ((a[1] == \"Player\" or a[1] == \"\") and \"당신\" or toKo(a[1] or \"\")) .. ((a[7] or \"\"):lower() == \"half\" and \" (절반)\" or \"\")\r\nend\r\n\r\nlocal vv = verdict:gsub(\"%-&gt;\", \"->\")\r\nlocal big = \"\"\r\nif tag == \"STIM\" then\r\nlocal n = vv:match(\"amount %-?%d+%->(%d+)\") or vv:match(\"stim %-?%d+%->(%d+)\") or a[6]\r\nlocal ty = (a[3] or \"\"):lower():gsub(\"^%l\", string.upper)\r\nbig = ' · <span class=\"dnd-big\">+' .. esc(tostring(n or \"?\")) .. '</span> ' .. esc(K.stimKo(ty))\r\nelseif tag == \"SOOTHE\" then\r\nbig = ' · <span class=\"dnd-big\">-' .. esc(tostring(vv:match(\"amount %-?%d+%->(%d+)\") or a[5] or \"?\")) .. '</span>'\r\nelseif tag == \"NUMB\" then\r\nbig = ' · <span class=\"dnd-big\">' .. esc(tostring(note:match(\"numbness (%d+)\") or a[2] or \"?\")) .. '</span>'\r\nwhat = who\r\nend\r\nif tag == \"SOOTHE\" then what = who end\r\nif tag == \"STIM\" then what = who .. ((a[7] or \"\"):lower() == \"half\" and \" (절반)\" or \"\") end\r\nreturn string.format('<div class=\"dnd-tag\" data-v=\"%s\"><div class=\"dnd-h\"><span class=\"dnd-chip\">%s</span><b>%s</b>%s</div><div class=\"dnd-sub\">%s%s</div></div>',\r\nesc(verdict), chip, esc(what), big, shown ~= \"\" and (esc(shown) .. \" · \") or \"\", verdict == \"\" and \"검증 전\" or K.vdHtml(verdict))\r\nend\r\nif tag == \"REST\" then\r\n\r\nlocal verdict, note = \"\", {}\r\nfor i = 2, #f do\r\nlocal v = f[i]\r\nif verdict == \"\" and (v == \"ok\" or v:match(\"^bad\")) then verdict = v\r\nelseif verdict ~= \"\" then note[#note + 1] = v end\r\nend\r\nlocal what = f[1] == \"long\" and \"긴 휴식\" or f[1] == \"short\" and \"짧은 휴식\" or toKo(f[1] or \"\")\r\nlocal res = toKo(table.concat(note, \"|\")):gsub(\"arousal \", \"흥분도 \"):gsub(\"recovery dice\", \"회복 주사위\")\r\n:gsub(\"overstimulation\", \"과자극\")\r\nreturn string.format('<div class=\"dnd-tag\" data-v=\"%s\"><div class=\"dnd-h\"><span class=\"dnd-chip\">☾ 휴식</span><b>%s</b>%s</div><div class=\"dnd-sub\">%s</div></div>',\r\nesc(verdict), esc(what), (res ~= \"\" and res ~= \"-\") and (\" · \" .. esc(res)) or \"\",\r\nverdict == \"\" and \"검증 전\" or ('<span class=\"dnd-vd\">Lua ' .. esc(verdict) .. \"</span>\"))\r\nend\r\n\r\n\r\nif tag == \"SPELLBOOK\" then\r\nlocal a = args(f)\r\nlocal verdict, note = f[#a + 1] or \"\", f[#a + 2] or \"\"\r\nlocal o = {}\r\nfor _, n in ipairs(splitNames(a[1] or \"\")) do o[#o + 1] = (n:gsub(\"^%+%s*\", \"\")) end\r\nlocal num, copied = note:match(\"^book (%d+)\"), note:match(\"copied for (.+)$\")\r\nreturn string.format('<div class=\"dnd-tag chk%s\" data-v=\"%s\"><div class=\"dnd-h\"><span class=\"dnd-chip\">❖ 주문책</span><b>%s</b></div>%s<div class=\"dnd-sub\">%s%s</div></div>',\r\nverdict == \"\" and \" pend\" or \"\", esc(verdict), \"주문 \" .. #o .. \"개\", K.spellChipRows(o),\r\nnum and (\"주문책 \" .. num .. \"개\" .. (copied and (\" · 베끼는 값 \" .. esc(toKo(copied))) or \"\") .. \" · \") or \"\", K.vdHtml(verdict))\r\nend\r\nif tag == \"INITIATE\" then\r\nlocal a = args(f)\r\nlocal verdict = f[#a + 1] or \"\"\r\nlocal list = verdict == \"ok\" and f[#a + 2]\r\nlocal o = splitNames(a[1] or \"\")\r\nif trim(a[2] or \"\") ~= \"\" then o[#o + 1] = trim(a[2]) end\r\nlocal vd = K.vdHtml(verdict)\r\nreturn string.format('<div class=\"dnd-tag chk%s\" data-v=\"%s\"><div class=\"dnd-h\"><span class=\"dnd-chip\">❖ 마법 입문자</span><b>%s</b>%s</div>%s%s</div>',\r\nverdict == \"\" and \" pend\" or \"\", esc(verdict), list and esc(toKo(list) .. \" 주문 목록\") or \"\", verdict == \"ok\" and (\" \" .. vd) or \"\",\r\nK.spellChipRows(o), verdict ~= \"ok\" and ('<div class=\"dnd-sub\">' .. vd .. \"</div>\") or \"\")\r\nend\r\nif tag == \"SPELLS\" then\r\nlocal a = args(f)\r\nlocal verdict = f[#a + 1] or \"\"\r\nlocal can, prep = splitNames(a[1]), splitNames(a[2])\r\nlocal all = {}\r\nfor _, n in ipairs(can) do all[#all + 1] = n end\r\nfor _, n in ipairs(prep) do all[#all + 1] = n end\r\nlocal vd = K.vdHtml(verdict)\r\n\r\nlocal always = (f[#a + 2] or \"\"):match(\"%((.-) always prepared, not counted%)\")\r\nlocal skip, kos, prepN = {}, {}, 0\r\nfor _, n in ipairs(always and splitNames(always) or {}) do skip[n] = true; kos[#kos + 1] = koName(n) end\r\nfor _, n in ipairs(prep) do if not skip[n] then prepN = prepN + 1 end end\r\nlocal alwaysNote = #kos > 0 and ('<div class=\"dnd-sub\">' .. esc(table.concat(kos, \", \")) .. ': 늘 준비된 주문이라 준비 칸을 차지하지 않습니다.</div>') or \"\"\r\nreturn string.format('<div class=\"dnd-tag chk%s\" data-v=\"%s\"><div class=\"dnd-h\"><span class=\"dnd-chip\">❖ 주문</span><b>%s</b>%s</div>%s%s%s</div>',\r\nverdict == \"\" and \" pend\" or \"\", esc(verdict), (#can > 0 and (\"소마법 \" .. #can .. \" · \") or \"\") .. \"준비 \" .. prepN,\r\nverdict == \"ok\" and (\" \" .. vd) or \"\", K.spellChipRows(all), alwaysNote, verdict ~= \"ok\" and ('<div class=\"dnd-sub\">' .. vd .. \"</div>\") or \"\")\r\nend\r\nif tag == \"WEAR\" then\r\nlocal a = args(f)\r\nlocal verdict, res = f[#a + 1] or \"\", f[#a + 2] or \"\"\r\nlocal what = verdict == \"\" and \"검증 전\" or res == \"destroyed\" and \"부서짐\" or res == \"repaired\" and \"수리됨\"\r\nor (res:gsub(\"^attack %-\", \"명중 -\"):gsub(\"^AC %-\", \"방어도 -\"))\r\nif verdict:match(\"^bad\") then what = \"Lua \" .. verdict end\r\nreturn '<div class=\"dnd-passive' .. ((res == \"destroyed\" or verdict:match(\"^bad\")) and \" miss\" or \"\") .. '\">⚒ 장비 손상 · '\r\n.. esc(Ally.ko(a[1] or \"\")) .. ' · ' .. esc(what) .. '</div>'\r\nend\r\n\r\nif tag == \"BACKGROUND\" then\r\nlocal a = args(f)\r\nlocal verdict = f[#a + 1] or \"\"\r\nlocal function kos(v) local o = {} for _, x in ipairs(listOf(v)) do o[#o + 1] = koName(abilityName(x) or x) end return table.concat(o, \"·\") end\r\nlocal fraw = trim(a[4] or \"\")\r\nlocal fe, fl = fraw:match(\"^(.-)%s*%((%a+)%)$\")\r\nfe = fe or fraw\r\nlocal fko = (Feat.KO.feat[fe] or koName(fe)) .. (fl and (\" (\" .. koName(fl) .. \")\") or \"\")\r\nreturn '<div class=\"dnd-passive' .. (verdict == \"ok\" and \"\" or \" miss\") .. '\">❖ 새 배경 · ' .. esc(a[1] or \"\") .. ' · 능력치 '\r\n.. esc(kos(a[2])) .. ' · 기술 ' .. esc(kos(a[3])) .. ' · 재주 ' .. esc(fko)\r\n.. (verdict == \"ok\" and \"\" or (' · Lua ' .. esc(verdict ~= \"\" and verdict or \"검증 전\"))) .. '</div>'\r\nend\r\n\r\nif tag == \"COVER\" then\r\nlocal a = args(f)\r\nlocal verdict = f[#a + 1] or \"\"\r\nlocal cov = K.COVER_WORD[trim(a[2] or \"\"):lower()]\r\nlocal who = toKo(a[1] or \"\")\r\nlocal what = (cov and cov > 0) and string.format(\"%s · 원거리 공격과 민첩 내성 +%d\", NAMES_KO[K.COVER_EN[cov]], cov)\r\nor \"엄폐에서 나옴\"\r\nif verdict ~= \"ok\" then\r\nif not debugOn then return \"\" end\r\nwhat = what .. \" · Lua \" .. (verdict ~= \"\" and verdict or \"검증 전\")\r\nend\r\nreturn '<div class=\"dnd-passive\">◫ 엄폐 · ' .. esc(who) .. ' · ' .. esc(what) .. '</div>'\r\nend\r\nif tag == \"PASSIVE\" then\r\nlocal a = args(f)\r\nlocal verdict, score = f[#a + 1] or \"\", f[#a + 2] or \"\"\r\nlocal found = verdict == \"ok\" and a[3] == \"success\"\r\nif not found and not debugOn then return \"\" end\r\nreturn string.format('<div class=\"dnd-passive%s\">◇ 상시 판정 · %s %s · %s%s</div>', found and \"\" or \" miss\",\r\nesc(Ally.ko(a[1] or \"\")), esc(score), found and \"알아챔\" or \"놓침\",\r\nverdict == \"ok\" and \"\" or (\" · Lua \" .. esc(verdict ~= \"\" and verdict or \"검증 전\")))\r\nend\r\nlocal explain = \"\"\r\n\r\n\r\nlocal atkIn = tag == \"ATTACK\" and K.monKind(f[1]) and true or false\r\n\r\nlocal ourSave = tag == \"SAVE\" and not K.monKind(f[1])\r\n\r\n\r\nlocal onFoe = (tag == \"SAVE\" or tag == \"HAZARD\" or tag == \"DAMAGE\")\r\nand K.monKind(f[1]) and true or false\r\nif novice and tag == \"CHECK\" and f[1] then explain = \"\\n\" .. checkExplain(f[1]:match(\"/%s*(.-)%s*$\") or f[1]) end\r\nif novice and tag == \"ATTACK\" and f[1] == \"Player\" and not atkShown then\r\natkShown = true\r\nexplain = \"\\n\" .. ATTACK_EXPLAIN\r\nend\r\n\r\nlocal raw2 = tag == \"HAZARD\" and f[2] or nil\r\nlocal rawLast = f[#f]\r\nlocal pk = (tag == \"CHECK\" or tag == \"USE\" or tag == \"ATTUNE\") and 1 or tag == \"TRAP\" and 2 or nil\r\nfor i, v in ipairs(f) do\r\nif not (v == \"ok\" or v:match(\"^bad:\")) then f[i] = K.acdc((i == pk) and Ally.ko(v) or toKo(v)) end\r\nend\r\nif tag == \"THREAD\" then return \"\" end\r\n\r\n\r\nif tag == \"ATTACK\" and #f == 11 and (f[10] == \"ok\" or f[10]:match(\"^bad\")) then\r\n\r\nlocal cov = \"\"\r\nf[11] = f[11]:gsub(\" ?(%((%S+) 엄폐 %+%d%))\", function(all) cov = \" \" .. all; return \"\" end)\r\n\r\nlocal sty = f[11]:match(\"^(%u%l+) %d+/%d+\") or f[11]:match(\"^(%u%l+) %-$\")\r\nif sty and DAMAGE_KO[sty] then\r\nreturn string.format('<div class=\"dnd-tag atk %s\" data-v=\"%s\"><div class=\"dnd-h\"><span class=\"dnd-chip\">♡ %s</span><b>%s</b> → <b>%s</b>'\r\n.. ' · <b class=\"dnd-r\" data-r=\"%s\">%s</b> · 자극 <span class=\"dnd-big\">%s</span></div>%s</div>',\r\natkIn and \"in\" or \"out\", esc(f[10]), atkIn and \"주문 자극 받음\" or \"주문 자극\", esc(f[1]), esc(f[2]), esc(f[6]), esc(f[6]), esc(f[9]),\r\nK.sfRow({ { \"명중\", K.d20Html(f[3]) .. \" \" .. esc(f[4]) .. \" vs 방어도 \" .. esc(f[5]) .. esc(cov) }, K.sfDamage(f[7], f[8]),\r\n{ \"결과\", esc(K.arResultKo(f[2] == \"Player\" and \"내\" or toKo(f[2]), f[11], nil, f[9])) } }, '<span class=\"dnd-vd\">Lua ' .. esc(f[10]) .. '</span>')) .. explain\r\nend\r\nreturn string.format('<div class=\"dnd-tag atk %s\" data-v=\"%s\"><div class=\"dnd-h\"><span class=\"dnd-chip\">%s</span><b>%s</b> → <b>%s</b>'\r\n.. ' · <b class=\"dnd-r\" data-r=\"%s\">%s</b> · 피해 <span class=\"dnd-big\">%s</span></div>%s</div>',\r\natkIn and \"in\" or \"out\", esc(f[10]), atkIn and \"† 피격\" or \"† 공격\", esc(f[1]), esc(f[2]), esc(f[6]), esc(f[6]), esc(f[9]),\r\nK.sfRow({ { \"명중\", K.d20Html(f[3]) .. \" \" .. esc(f[4]) .. \" vs 방어도 \" .. esc(f[5]) .. esc(cov) }, K.sfDamage(f[7], f[8]),\r\n{ esc(f[2]) .. \" 생명력\", esc(f[11]) } }, '<span class=\"dnd-vd\">Lua ' .. esc(f[10]) .. '</span>')) .. explain\r\nend\r\n\r\n\r\nif tag == \"BUFF\" then\r\nlocal a = args(f)\r\nlocal verdict = f[#a + 1] or \"\"\r\nlocal sname = Canon.name(a[2] or \"\")\r\n\r\nif verdict == \"auto\" then\r\nlocal what = f[#a + 2] or \"\"\r\nwhat = what:find(\"up at 1\", 1, true) and \"생명력 1로 일어납니다\" or what\r\nreturn string.format('<div class=\"dnd-tag chk\" data-v=\"ok\"><div class=\"dnd-h\"><span class=\"dnd-chip\">✦ 버프</span><b>%s</b> · %s</div>'\r\n.. '<div class=\"dnd-sub\">턴 시작 · %s · <span class=\"dnd-vd\">Lua</span></div></div>',\r\nesc(toKo((a[1] == \"Player\" or a[1] == \"\") and \"당신\" or a[1])), esc(koName(sname)), esc(what))\r\nend\r\nlocal eff = K.castEffectKo(sname, nil)\r\nreturn string.format('<div class=\"dnd-tag chk%s\" data-v=\"%s\"><div class=\"dnd-h\"><span class=\"dnd-chip\">✦ 버프</span><b>%s</b> · %s%s</div>%s<div class=\"dnd-sub\">%s</div></div>',\r\nverdict == \"\" and \" pend\" or \"\", esc(verdict), esc(toKo((a[1] == \"Player\" or a[1] == \"\") and \"당신\" or a[1])), esc(koName(sname)),\r\n\r\n(a[3] or \"\") ~= \"\" and (\" · \" .. esc(DAMAGE_KO[Canon.name(a[3])] or koName(Canon.name(a[3])))) or \"\",\r\neff ~= \"\" and ('<div class=\"dnd-sub\" style=\"white-space:normal\">' .. esc(eff) .. '</div>') or \"\",\r\nverdict == \"\" and \"검증 전\" or ('<span class=\"dnd-vd\">Lua ' .. esc(verdict) .. \"</span>\"))\r\nend\r\nif tag == \"MP\" and #f == 4 and (f[3] == \"ok\" or f[3]:match(\"^bad\")) then\r\nlocal mw, ml = f[4]:match(\"^(%S+) (%d+/%d+)$\")\r\nreturn string.format('<div class=\"dnd-tag heal\" data-v=\"%s\"><div class=\"dnd-h\"><span class=\"dnd-chip\">✚ 회복</span><b>%s</b> <span class=\"dnd-big\">%s %s</span>%s</div><div class=\"dnd-sub\"><span class=\"dnd-vd\">Lua %s</span></div></div>',\r\nesc(f[3]), esc((f[1] == \"Player\" or f[1] == \"\") and \"당신\" or f[1]), esc(mw or \"MP\"), esc(f[2]), ml and (\" · \" .. esc(ml) .. \" 남음\") or \"\", esc(f[3]))\r\nend\r\nif tag == \"REVIVE\" then\r\nlocal a = args(f)\r\nlocal verdict, res = f[#a + 1] or \"\", f[#a + 2] or \"\"\r\nlocal who = (a[1] == nil or a[1] == \"\" or a[1] == \"Player\") and \"당신\" or a[1]\r\n\r\nlocal hp, body, ord = res:match(\"^(%d+/%d+)\"), res:match(\"new body: (%a+)\"), res:match(\"ordeal: %-(%d+)\")\r\nlocal paid = res:match(\"paid (%d+) gp\") or res:match(\"paid 금화 (%d+)\")\r\nlocal sub = {}\r\nif body then sub[#sub + 1] = \"새 몸: \" .. koName(body) end\r\nif ord then sub[#sub + 1] = \"부활의 시련 -\" .. ord .. \" (긴 휴식마다 1씩 줄어듭니다)\" end\r\nif paid then sub[#sub + 1] = \"사제에게 금화 \" .. paid end\r\nif res:find(\"taxed\", 1, true) then sub[#sub + 1] = \"시전자는 긴 휴식까지 주문을 쓰지 못합니다\" end\r\nreturn string.format('<div class=\"dnd-tag heal%s\" data-v=\"%s\"><div class=\"dnd-h\"><span class=\"dnd-chip\">✚ 부활</span><b>%s</b> · %s%s</div>'\r\n.. '<div class=\"dnd-sub\" style=\"white-space:normal\">%s%s</div></div>',\r\nverdict == \"\" and \" pend\" or \"\", esc(verdict), esc(toKo(who)), esc(koName(Canon.name(a[2] or \"\"))),\r\nhp and (' · 생명력 <span class=\"dnd-big\">' .. esc(hp) .. \"</span>\") or \"\", esc(table.concat(sub, \" · \")),\r\n(#sub > 0 and \" · \" or \"\") .. K.vdHtml(verdict))\r\nend\r\nif tag == \"SUMMON\" or tag == \"MOUNT\" then\r\nlocal a = args(f)\r\nlocal verdict, res = f[#a + 1] or \"\", f[#a + 2] or \"\"\r\nlocal sub\r\nlocal raw = verdict == \"ok\" and rawLast or \"\"\r\nif tag == \"SUMMON\" then\r\nlocal names, hp, span = raw:match(\"^(.-) %(HP (%d+),? ?(.-)%)$\")\r\nlocal ko = {}\r\nfor n in ((names or \"\") .. \",\"):gmatch(\"%s*([^,]-)%s*,\") do if n ~= \"\" then ko[#ko + 1] = toKo(n) end end\r\nspan = (span or \"\"):gsub(\"(%d+) hours?\", \"%1시간\"):gsub(\"(%d+) days?\", \"%1일\"):gsub(\"(%d+) minutes?\", \"%1분\")\r\n\r\nspan = (toKo(span):gsub(\"(%d+) left\", \"%1 남음\"))\r\nsub = names and (table.concat(ko, \", \") .. \" · 생명력 \" .. hp .. (span ~= \"\" and (\" · \" .. span) or \"\")) or \"\"\r\nelse\r\nlocal who, sp = raw:match(\"^riding (.-), Speed (%d+) ft$\")\r\nsub = who and (toKo(who) .. \"에 탔습니다 · 속도 \" .. sp .. \"피트\") or (raw == \"on foot\" and \"내렸습니다\" or \"\")\r\nend\r\nreturn string.format('<div class=\"dnd-tag chk%s\" data-v=\"%s\"><div class=\"dnd-h\"><span class=\"dnd-chip\">%s</span><b>%s</b></div>'\r\n.. '<div class=\"dnd-sub\" style=\"white-space:normal\">%s%s</div></div>',\r\nverdict == \"\" and \" pend\" or \"\", esc(verdict), tag == \"SUMMON\" and \"✧ 소환\" or \"✧ 탈것\", esc(tag == \"SUMMON\" and koName(Canon.name(a[1] or \"\")) or toKo(a[1] or \"\")),\r\nesc(sub), (sub ~= \"\" and \" · \" or \"\") .. K.vdHtml(verdict))\r\nend\r\nif tag == \"CRAFT\" then\r\nlocal a = args(f)\r\nlocal verdict, res = f[#a + 1] or \"\", f[#a + 2] or \"\"\r\nlocal n, what, d = res:match(\"^(%d+) (.-) made, (%d+) days?\")\r\nlocal mat, left = res:match(\"materials (.-), (.-) left$\")\r\nlocal sub = n and string.format(\"%s개 · 일 %s일 · 재료 %s · 남은 돈 %s\", n, d, mat or \"\", left or \"\") or \"\"\r\nreturn string.format('<div class=\"dnd-tag chk%s\" data-v=\"%s\"><div class=\"dnd-h\"><span class=\"dnd-chip\">⚒ 제작</span><b>%s</b></div>'\r\n.. '<div class=\"dnd-sub\" style=\"white-space:normal\">%s%s</div></div>',\r\nverdict == \"\" and \" pend\" or \"\", esc(verdict), esc(n and koName(what) or (a[1] or \"\")), esc(sub), (sub ~= \"\" and \" · \" or \"\") .. K.vdHtml(verdict))\r\nend\r\nif tag == \"ATTUNE\" then\r\nlocal a = args(f)\r\nlocal verdict, res = f[#a + 1] or \"\", f[#a + 2] or \"\"\r\nlocal who, nm = (a[1] or \"\"):match(\"^(.-) · (.+)$\")\r\nnm = nm or a[1] or \"\"\r\nlocal off = nm:match(\"^%-%s*(.+)$\")\r\nlocal cnt, names, note = res:match(\"^attuned (%d+/3):? ?(.-)%s*%((.-)%)$\")\r\nif not cnt then cnt, names = res:match(\"^attuned (%d+/3):? ?(.-)$\") end\r\nlocal ko = {}\r\nfor n in ((names or \"\") .. \",\"):gmatch(\"%s*([^,]-)%s*,\") do if n ~= \"\" then ko[#ko + 1] = koName(n) end end\r\nlocal sub = cnt and (\"조율 \" .. cnt .. (#ko > 0 and (\" · \" .. table.concat(ko, \", \")) or \"\")) or \"\"\r\nif note then sub = sub .. (note == \"1 hour\" and \" · 1시간 걸림\" or \" · 짧은 휴식 동안\") end\r\nreturn string.format('<div class=\"dnd-tag chk%s\" data-v=\"%s\"><div class=\"dnd-h\"><span class=\"dnd-chip\">✧ 조율</span><b>%s%s</b>%s</div>'\r\n.. '<div class=\"dnd-sub\" style=\"white-space:normal\">%s%s</div></div>',\r\nverdict == \"\" and \" pend\" or \"\", esc(verdict), who and esc(who .. \" · \") or \"\", esc(off or nm), off and \" · 조율 풀기\" or \"\",\r\nesc(sub), (sub ~= \"\" and \" · \" or \"\") .. K.vdHtml(verdict))\r\nend\r\nif tag == \"HEAL\" and (#f == 4 or #f == 7) and K.isAid(f[2]) and (f[#f - 1] == \"ok\" or f[#f - 1]:match(\"^bad\")) then\r\nlocal vd, res = f[#f - 1], f[#f]\r\nreturn string.format('<div class=\"dnd-tag heal\" data-v=\"%s\"><div class=\"dnd-h\"><span class=\"dnd-chip\">✚ 회복</span><b>응급 치료</b> <span class=\"dnd-big\">+%s</span> · %s 생명력 %s</div>%s</div>',\r\nesc(vd), esc(res:match(\"%(%+(%d+):\") or \"0\"), esc(f[1]), esc(toKo(res)),\r\nK.sfRow({}, '<span class=\"dnd-vd\">Lua ' .. esc(vd) .. '</span>'))\r\nend\r\nif tag == \"HEAL\" and #f == 5 and K.isNpc(f[3]) and (f[4] == \"ok\" or f[4]:match(\"^bad\")) then\r\nreturn string.format('<div class=\"dnd-tag heal\" data-v=\"%s\"><div class=\"dnd-h\"><span class=\"dnd-chip\">✚ 회복</span><b>사제의 %s</b> <span class=\"dnd-big\">+%s</span> · %s 생명력 %s</div>%s</div>',\r\nesc(f[4]), esc((K.npcFree(f[3]) and \"무료 · \" or \"\") .. koName(f[2])), esc(f[5]:match(\"%(%+(%d+):\") or \"0\"), esc(f[1]), esc(toKo(f[5])),\r\nK.sfRow({}, '<span class=\"dnd-vd\">Lua ' .. esc(f[4]) .. '</span>'))\r\nend\r\nif tag == \"HEAL\" and #f == 7 and (f[6] == \"ok\" or f[6]:match(\"^bad\")) then\r\nreturn string.format('<div class=\"dnd-tag heal\" data-v=\"%s\"><div class=\"dnd-h\"><span class=\"dnd-chip\">✚ 회복</span><b>%s</b> <span class=\"dnd-big\">+%s</span> · %s 생명력 %s</div>%s</div>',\r\nesc(f[6]), esc(f[2] == \"Rest\" and \"휴식\" or f[2]), esc(f[5]), esc(f[1]), esc(toKo(f[7])),\r\nK.sfRow({ K.sfDamage(f[3], f[4], \"굴림\") }, '<span class=\"dnd-vd\">Lua ' .. esc(f[6]) .. '</span>'))\r\nend\r\n\r\n\r\n\r\nif tag == \"CHECK\" and #f == 7 and (f[6] == \"ok\" or f[6]:match(\"^bad\")) then\r\n\r\nlocal total, note = f[7]:match(\"^(%S+)%s+%((.+)%)$\")\r\nreturn string.format('<div class=\"dnd-tag chk\" data-v=\"%s\"><div class=\"dnd-h\"><span class=\"dnd-chip\">◆ 판정</span><b>%s</b>'\r\n.. ' <span class=\"dnd-big\">%s</span> vs 난이도 %s · <b class=\"dnd-r\" data-r=\"%s\">%s</b></div><div class=\"dnd-sub\">d20 %s %s'\r\n.. '%s · <span class=\"dnd-vd\">Lua %s</span></div></div>',\r\nesc(f[6]), esc(f[1]), esc(total or f[7]), esc(f[4]), esc(f[5]), esc(f[5]), K.d20Html(f[2]), esc(f[3]),\r\nnote and (\" · \" .. esc(note)) or \"\", esc(f[6])) .. explain\r\nend\r\nif tag == \"DEATH\" and #f == 4 and (f[3] == \"ok\" or f[3]:match(\"^bad\")) then\r\nreturn string.format('<div class=\"dnd-tag die\" data-v=\"%s\"><div class=\"dnd-h\"><span class=\"dnd-chip\">✝ 죽음 내성</span><b class=\"dnd-r\" data-r=\"%s\">%s</b>'\r\n.. ' · %s</div><div class=\"dnd-sub\">d20 %s · <span class=\"dnd-vd\">Lua %s</span></div></div>',\r\nesc(f[3]), esc(f[2]), esc(f[2]), esc(f[4]), K.d20Html(f[1]), esc(f[3]))\r\nend\r\nif tag == \"USE\" then\r\nlocal a = args(f)\r\nlocal verdict, left = f[#a + 1] or \"\", f[#a + 2] or \"\"\r\nlocal name = a[1] or \"\"\r\n\r\n\r\nlocal cw, cn, cl = left:match(\"^(.-) coated(.-), 1 minute; (%d+) left$\")\r\nif verdict == \"ok\" and cw then\r\nreturn string.format('<div class=\"dnd-tag chk\" data-v=\"ok\"><div class=\"dnd-h\"><span class=\"dnd-chip\">✧ 물품 사용</span><b>%s</b></div>'\r\n.. '<div class=\"dnd-sub\" style=\"white-space:normal\">%s에 발랐습니다%s · 1분, 첫 관통·참격 명중에 독성 1d4 · 기본 독 %s개 남음 · <span class=\"dnd-vd\">Lua ok</span></div></div>',\r\nesc(name), esc(koName(cw)), esc(cn ~= \"\" and (\" \" .. cn:gsub(\"[()]\", \"\") .. \"개\") or \"\"), esc(cl))\r\nend\r\nif verdict == \"ok\" and (left:find(\"used up\", 1, true) or left:find(\"per dawn\", 1, true)) then\r\nreturn string.format('<div class=\"dnd-tag chk\" data-v=\"ok\"><div class=\"dnd-h\"><span class=\"dnd-chip\">✧ 물품 사용</span><b>%s</b>%s</div>'\r\n.. '<div class=\"dnd-sub\" style=\"white-space:normal\">%s · <span class=\"dnd-vd\">Lua ok</span></div></div>',\r\nesc(name), (a[2] or \"\") ~= \"\" and (\" · \" .. esc(a[2])) or \"\", esc(K.miUseKo(left)))\r\nend\r\nlocal slot = name:match(\"^Spell Slot (%d)$\")\r\nreturn string.format('<div class=\"dnd-tag chk%s\" data-v=\"%s\"><div class=\"dnd-h\"><span class=\"dnd-chip\">❖ 기능 사용</span><b>%s</b></div><div class=\"dnd-sub\">%s</div></div>',\r\nverdict == \"\" and \" pend\" or \"\", esc(verdict), esc(slot and (slot .. \"레벨 슬롯\") or name),\r\nverdict == \"\" and \"검증 전\" or ((left:match(\"^%-%d+, %S+ %d+/%d+\") and esc(left:gsub(\"^%-(%d+), (%S+) (%d+/%d+)\", \"%2 %1 씀 · %3 남음\"))\r\nor ((left:match(\"^%d+/%d+\") and '남은 횟수 ' or \"\") .. esc(K.useLeftKo(left)))) .. ' · <span class=\"dnd-vd\">Lua ' .. esc(verdict) .. \"</span>\"))\r\nend\r\nif tag == \"HAZARD\" then\r\nlocal a = args(f)\r\nlocal verdict, res = f[#a + 1] or \"\", f[#a + 2] or \"\"\r\nlocal vd = verdict == \"\" and \"검증 전\" or ('<span class=\"dnd-vd\">Lua ' .. esc(verdict) .. \"</span>\")\r\nlocal sev, dt = (a[2] or \"\"):match(\"^(%S+)%s+(.+)$\")\r\nlocal what = K.HAZ_SEV[(sev or \"\"):lower()] and ((K.HAZ_SEV[sev:lower()] == \"deadly\" and \"위험한 \" or \"가벼운 \") .. \"환경 · \" .. (DAMAGE_KO[dt] or dt))\r\nor ((a[2] or \"\"):match(\"^[Ff]all%s*(%d+)\") and (\"낙하 \" .. a[2]:match(\"(%d+)\") .. \"피트\"))\r\nor ((a[2] or \"\") == \"Shove\" and \"밀치기\") or nil\r\nif not what then\r\n\r\nlocal base, ty = (a[2] or \"\"):match(\"^(.-)%s*%((%a+)%)$\")\r\nwhat = (base and DAMAGE_KO[ty]) and (koName(base) .. \" (\" .. DAMAGE_KO[ty] .. \")\") or koName(a[2] or \"\")\r\nend\r\n\r\nlocal abil = ({ [\"근력\"] = true, [\"민첩\"] = true, [\"건강\"] = true, [\"지능\"] = true, [\"지혜\"] = true, [\"매력\"] = true })[a[3] or \"\"]\r\nlocal roll = (a[3] or \"-\") ~= \"-\" and { esc(a[3] or \"\") .. (abil and \" 내성\" or \"\"), K.d20Html(a[4] or \"\") .. \" \" .. esc(a[5] or \"\") .. \" vs 난이도 \" .. esc(a[6] or \"\") } or nil\r\n\r\n\r\nlocal rb = Canon.name(trim(((raw2 or \"\"):gsub(\"%s*%b()%s*$\", \"\"))))\r\nlocal chip = (rb == \"Turn Undead\" or rb == \"Divine Spark\") and \"✦ 신성 변환\" or K.featHaz(rb) and \"✦ 기능\" or \"✦ 즉흥 효과\"\r\nreturn string.format('<div class=\"dnd-tag atk%s%s\" data-v=\"%s\"><div class=\"dnd-h\"><span class=\"dnd-chip\">%s</span><b>%s</b> · %s%s · 피해 <span class=\"dnd-big\">%s</span></div>%s</div>',\r\nverdict ~= \"\" and (onFoe and \" out\" or \" in\") or \"\", verdict == \"\" and \" pend\" or \"\", esc(verdict), chip, esc(a[1] or \"\"), esc(what),\r\n(a[3] or \"-\") ~= \"-\" and (' · ' .. K.resChip(a[7], onFoe)) or \"\", esc(a[10] or \"\"),\r\nK.sfRow({ roll, K.sfDamage(a[8], a[9]), { esc(a[1] or \"\") .. \" 생명력\", esc(toKo(res)) } }, vd))\r\nend\r\nif tag == \"CAST\" or tag == \"SAVE\" or tag == \"DAMAGE\" or tag == \"CONC\" then\r\nlocal a = args(f)\r\nlocal verdict, res = f[#a + 1] or \"\", f[#a + 2] or \"\"\r\nif tag == \"CONC\" and verdict == \"auto\" then verdict = \"ok\" end\r\nlocal vd = verdict == \"\" and \"검증 전\" or ('<span class=\"dnd-vd\">Lua ' .. esc(verdict) .. \"</span>\")\r\nlocal pend = verdict == \"\" and \" pend\" or \"\"\r\nif tag == \"CAST\" then\r\n\r\nlocal stab = res:match(\" %((당신 안정)%)$\")\r\nif stab then res = res:gsub(\" %(당신 안정%)$\", \"\") end\r\nlocal lv, left = res:match(\"^slot (%d+): (%d+/%d+)\")\r\nlocal ends = res:match(\"ends (.+)$\")\r\nlocal sub = res == \"cantrip\" and \"소마법\" or (lv and (lv .. \"레벨 슬롯 · \" .. left .. \" 남음\") or \"\")\r\nlocal own, ownLeft = res:match(\"^(.-) (%d+/%d+)\")\r\nlocal mpCost, mpWord, mpLeft = res:match(\"^%-(%d+), (%S+) (%d+/%d+)\")\r\n\r\nlocal scroll, chk = res:match(\"^Spell Scroll %((.-)%)(.*)$\")\r\nlocal aw = res:match(\"^(.-), at will$\")\r\nif mpCost then sub = mpWord .. \" \" .. mpCost .. \" 씀 · \" .. mpLeft .. \" 남음\"\r\nelseif scroll then\r\nlocal d, m, dc = chk:match(\"d20 (%d+)([%+%-]%d+) vs %S+ (%d+)\")\r\nsub = koName(\"Spell Scroll\") .. \" 씀\" .. (d and (\" · 판정 d20 \" .. d .. m .. \" vs 난이도 \" .. dc) or \"\")\r\nelseif aw and K.MI.maybe(aw) then sub = koName(aw) .. \" · 무제한\"\r\nelseif not lv and own and res ~= \"cantrip\" then\r\nsub = koName(own) .. \" · \" .. ownLeft .. \" 남음\"\r\nlocal ld = res:match(\"the last charge: d20 (%d+)\")\r\nif ld then sub = sub .. \" · 마지막 충전 d20 \" .. ld .. (res:find(\"destroyed\", 1, true) and \": 물품이 부서졌습니다\" or \": 그대로입니다\") end\r\nend\r\n\r\nlocal upf, upt = res:match(\"%(no level (%d) slot left: cast at level (%d)%)\")\r\nif upf then sub = sub .. \" · \" .. upf .. \"레벨 슬롯이 없어 \" .. upt .. \"레벨로 올려 씀\" end\r\nif ends then sub = sub .. \" · \" .. esc(toKo(ends)) .. \" 집중 끝\" end\r\nif stab then sub = sub .. \" · \" .. stab end\r\nlocal by = (a[3] or \"\") ~= \"\" and a[3] ~= \"당신\" and (a[3] .. \" · \") or \"\"\r\nlocal eff = K.castEffectKo(Canon.name(a[1] or \"\"), tonumber(lv) or tonumber(a[2]))\r\nreturn string.format('<div class=\"dnd-tag chk%s\" data-v=\"%s\"><div class=\"dnd-h\"><span class=\"dnd-chip\">✦ 주문</span><b>%s%s</b></div><div class=\"dnd-sub\">%s · %s</div>%s</div>',\r\npend, esc(verdict), esc(by), esc(a[1] or \"\"), esc(sub), vd,\r\neff ~= \"\" and ('<div class=\"dnd-sub\" style=\"white-space:normal\">' .. esc(eff) .. '</div>') or \"\")\r\nelseif tag == \"SAVE\" and ourSave and trim(a[2] or \"-\") == \"-\" then\r\n\r\nreturn string.format('<div class=\"dnd-tag atk in%s\" data-v=\"%s\"><div class=\"dnd-h\"><span class=\"dnd-chip\">◆ 피해</span><b>%s</b> · 피해 <span class=\"dnd-big\">%s</span></div>%s</div>',\r\npend, esc(verdict), esc(a[1] or \"\"), esc(a[9] or \"\"),\r\nK.sfRow({ K.sfDamage(a[7], a[8]), { esc(a[1] or \"\") .. \" 생명력\", esc(toKo(res)) } }, vd))\r\nelseif tag == \"SAVE\" then\r\nreturn string.format('<div class=\"dnd-tag atk%s%s\" data-v=\"%s\"><div class=\"dnd-h\"><span class=\"dnd-chip\">%s</span><b>%s</b> · %s 내성 · %s · 피해 <span class=\"dnd-big\">%s</span></div>%s</div>',\r\nourSave and \" in\" or (pend == \"\" and \" out\" or \"\"), pend, esc(verdict), ourSave and \"◆ 내성\" or \"✦ 주문 내성\", esc(a[1] or \"\"), esc(toKo(a[2] or \"\")), K.resChip(a[6], not ourSave), esc(a[9] or \"\"),\r\nK.sfRow({ { \"내성\", K.d20Html(a[3] or \"\") .. \" \" .. esc(a[4] or \"\") .. \" vs 난이도 \" .. esc(a[5] or \"\") }, K.sfDamage(a[7], a[8]),\r\n{ esc(a[1] or \"\") .. \" 생명력\", esc(toKo(res)) } }, vd))\r\nelseif tag == \"DAMAGE\" then\r\nreturn string.format('<div class=\"dnd-tag atk%s%s\" data-v=\"%s\"><div class=\"dnd-h\"><span class=\"dnd-chip\">✦ 자동 명중</span><b>%s</b> · 피해 <span class=\"dnd-big\">%s</span></div>%s</div>',\r\npend == \"\" and (onFoe and \" out\" or \" in\") or \"\", pend, esc(verdict), esc(a[1] or \"\"), esc(a[4] or \"\"),\r\nK.sfRow({ K.sfDamage(a[2], a[3]), { esc(a[1] or \"\") .. \" 생명력\", esc(res) } }, vd))\r\nend\r\n\r\nlocal cw = a[2] or \"\"\r\nlocal cby = (cw ~= \"\" and cw ~= \"Player\" and cw ~= \"당신\") and (cw .. \" · \") or \"\"\r\nreturn string.format('<div class=\"dnd-tag%s\" data-v=\"%s\"><div class=\"dnd-h\"><span class=\"dnd-chip\">◌ 집중 끝</span><b>%s%s</b></div><div class=\"dnd-sub\">%s</div></div>',\r\npend, esc(verdict), esc(cby), esc(toKo(res)), vd)\r\nend\r\nif tag == \"NPC\" or tag == \"SECRET\" then return \"\" end\r\nif tag == \"COND\" then\r\nlocal a = args(f)\r\nlocal verdict, now = f[#a + 1] or \"\", f[#a + 2] or \"\"\r\nlocal ko = {}\r\n\r\nlocal imm = now:match(\"^immune %((.-)%)$\") or now:match(\"^면역 %((.-)%)$\")\r\nif imm then ko[1] = \"면역 (\" .. (NAMES_KO[imm] or imm) .. \")\" end\r\n\r\nlocal stayOn, sd, sb = now:match(\"^stays on (.-) %(Dexterity save d20 (%d+)([%+%-]%d+) vs [^%d]-10%)$\")\r\nif stayOn then ko[1] = toKo(stayOn) .. \"에 그대로 탐 (민첩 내성 d20 \" .. sd .. sb .. \", 난이도 10)\" end\r\nlocal fellOff = now:match(\" %(fell off (.-)%)$\")\r\nif fellOff then now = now:gsub(\" %(fell off .-%)$\", \"\") end\r\nlocal kept = imm or stayOn\r\nfor n in (kept and \"\" or (now .. \",\")):gmatch(\"%s*([^,]-)%s*,\") do\r\nif n ~= \"\" then\r\nlocal nm, lv = n:match(\"^(.-) (%d)$\")\r\nko[#ko + 1] = nm and (koName(nm) .. \" \" .. lv) or (n == \"none\" and \"없음\" or koName(n))\r\nend\r\nend\r\n\r\n\r\nlocal who, ch, d = \"당신\", a[1] or \"\", a[2] or \"\"\r\nif not ch:match(\"^%s*[+-]\") and (a[2] or \"\"):match(\"^%s*[+-]\") then who, ch, d = toKo(trim(a[1] or \"\")), a[2] or \"\", a[3] or \"\" end\r\nlocal sign, cname = ch:match(\"^%s*([+-])%s*(.-)%s*$\")\r\nlocal cko = cname and koName(Canon.name(cname)) or ch\r\nd = (d == \"\" or d == \"-\") and \"풀릴 때까지\" or toKo(d:gsub(\"^%+\", \"\"):gsub(\"(%d+)m$\", \"%1분\"):gsub(\"(%d+)h$\", \"%1시간\"):gsub(\"(%d+)d$\", \"%1일\"))\r\nif fellOff then ko[#ko + 1] = \"(\" .. toKo(fellOff) .. \"에서 떨어짐)\" end\r\n\r\nlocal title = who .. \" · \" .. cko .. (sign == \"-\" and \" 풀림\" or (sign == \"+\" and (kept and \" 막음\" or \" 걸림\") or \"\"))\r\nreturn string.format('<div class=\"dnd-tag die%s\" data-v=\"%s\"><div class=\"dnd-h\"><span class=\"dnd-chip\">◐ 상태 이상</span><b>%s</b>%s</div><div class=\"dnd-sub\">%s</div></div>',\r\nverdict == \"\" and \" pend\" or \"\", esc(verdict), esc(title), (sign == \"+\" and not kept) and (\" · \" .. esc(d)) or \"\",\r\nverdict == \"\" and \"검증 전\" or (\"지금: \" .. esc(table.concat(ko, \" · \")) .. ' · <span class=\"dnd-vd\">Lua ' .. esc(verdict) .. \"</span>\"))\r\nend\r\n\r\nlocal kitLeft = tag == \"ITEM\" and rest:match(\"|kit uses (%d+)$\")\r\nif kitLeft then\r\nlocal verdict = f[3] or \"\"\r\nlocal spent = tonumber(f[2] or \"\") or 1\r\nlocal short = verdict:match(\"^bad:only (%d+) uses\")\r\nreturn string.format('<div class=\"dnd-tag\" data-v=\"%s\"><div class=\"dnd-h\"><span class=\"dnd-chip\">▪ 소지품</span><b>%s</b> · %d회 사용</div><div class=\"dnd-sub\">남은 횟수 %s · %s</div></div>',\r\nshort and \"fix:kit\" or esc(verdict), esc(koName(K.KIT)), short and tonumber(short) or spent, kitLeft,\r\nshort and (\"남은 횟수가 \" .. short .. \"회뿐이라 \" .. short .. \"회만 · \" .. '<span class=\"dnd-vd\">Lua 고침</span>') or ('<span class=\"dnd-vd\">Lua ' .. esc(verdict) .. \"</span>\"))\r\nend\r\nif tag == \"ITEM\" and rest:find(\"|bad:story gear\", 1, true) then\r\n\r\nlocal nm = ((split(rest)[1] or \"\"):gsub(\"^%s*[%+%-]%s*\", \"\"))\r\nlocal _, ko = K.storyGear(nm)\r\nreturn '<div class=\"dnd-tag\" data-v=\"fix:story\"><div class=\"dnd-h\"><span class=\"dnd-chip\">▪ 소지품</span><b>' .. esc(ko or nm)\r\n.. '</b></div><div class=\"dnd-sub\">이야기 속에서 가지고 있는 물건입니다 · Lua가 세지 않습니다</div></div>'\r\nend\r\nif tag == \"STAGE\" then\r\n\r\nif not debugOn then return \"\" end\r\nreturn '<div class=\"dnd-passive miss\">◇ 의뢰 단계 · ' .. esc(table.concat(f, \" · \")) .. '</div>'\r\nend\r\nif tag == \"QUEST\" then\r\nlocal a = args(f)\r\nlocal verdict = f[#a + 1] or \"\"\r\n\r\nif a[1] == \"advance\" then\r\nlocal gp = (a[3] or a[2] or \"\"):match(\"(%d+)\")\r\nreturn string.format('<div class=\"dnd-tag chk%s\" data-v=\"%s\"><div class=\"dnd-h\"><span class=\"dnd-chip\">❖ 의뢰 선수금</span><b>%s</b> · 금화 +%s</div><div class=\"dnd-sub\">%s</div></div>',\r\nverdict == \"\" and \" pend\" or \"\", esc(verdict), esc(f[#a + 2] or \"\"), esc(gp or \"?\"),\r\nverdict == \"ok\" and (\"끝나면 받을 보수 금화 \" .. esc(f[#a + 3] or \"0\") .. ' · <span class=\"dnd-vd\">Lua ok</span>')\r\nor (verdict == \"\" and \"검증 전\" or ('<span class=\"dnd-vd\">Lua ' .. esc(verdict) .. \"</span>\")))\r\nend\r\nif a[1] == \"done\" then\r\nlocal ko = { success = \"성공\", partial = \"부분 성공\", fail = \"실패\" }\r\nreturn string.format('<div class=\"dnd-tag chk%s\" data-v=\"%s\"><div class=\"dnd-h\"><span class=\"dnd-chip\">❖ 의뢰 끝</span><b>%s</b> · %s</div><div class=\"dnd-sub\">%s</div></div>',\r\nverdict == \"\" and \" pend\" or \"\", esc(verdict), esc(f[#a + 2] or a[2] or \"\"), esc(ko[a[3]] or a[3] or \"\"),\r\nverdict == \"ok\" and (\"경험치 +\" .. esc(f[#a + 3] or \"0\") .. \" · 금화 +\" .. esc(f[#a + 4] or \"0\") .. ' · <span class=\"dnd-vd\">Lua ok</span>')\r\nor (verdict == \"\" and \"검증 전\" or ('<span class=\"dnd-vd\">Lua ' .. esc(verdict) .. \"</span>\")))\r\nend\r\n\r\nif a[1] == \"reward\" then\r\nreturn string.format('<div class=\"dnd-tag chk%s\" data-v=\"%s\"><div class=\"dnd-h\"><span class=\"dnd-chip\">❖ 의뢰 보수 바뀜</span><b>%s</b></div><div class=\"dnd-sub\">%s</div></div>',\r\nverdict == \"\" and \" pend\" or \"\", esc(verdict), esc(a[2] or \"\"),\r\nverdict == \"\" and \"검증 전\" or (\"새로 약속된 보수 \" .. esc(toKo(f[#a + 2] or a[3] or \"\")) .. ' · <span class=\"dnd-vd\">Lua ' .. esc(verdict) .. \"</span>\"))\r\nend\r\nlocal title = (a[1] or \"\"):gsub(\"^%+\", \"\")\r\nreturn string.format('<div class=\"dnd-tag chk%s\" data-v=\"%s\"><div class=\"dnd-h\"><span class=\"dnd-chip\">❖ 의뢰</span><b>%s</b></div><div class=\"dnd-sub\">%s%s · %s</div></div>',\r\nverdict == \"\" and \" pend\" or \"\", esc(verdict), esc(title), (a[2] or \"\") ~= \"\" and (\"의뢰인 \" .. esc(a[2]) .. \" · \") or \"\", esc(a[3] or \"\"),\r\nverdict == \"\" and \"검증 전\" or (\"약속된 보수 \" .. esc(toKo(f[#a + 3] or \"\")) .. ' · <span class=\"dnd-vd\">Lua ' .. esc(verdict) .. \"</span>\"))\r\nend\r\nif tag == \"LOOT\" then\r\nlocal a = args(f)\r\nlocal verdict, plus = f[#a + 1] or \"\", f[#a + 2] or \"\"\r\n\r\n\r\nlocal pwEn = f[#a + 3] or \"\"\r\nlocal grade = a[2] or \"\"\r\nfor g in verdict:gmatch(\"grade %u%->(%u)\") do grade = g end\r\nlocal what = (a[3] or \"-\") ~= \"-\" and (esc(a[3]) .. (plus ~= \"-\" and plus ~= \"\" and (\" \" .. esc(plus)) or \"\"))\r\nor (pwEn ~= \"\" and \"장신구 (지니면 효과)\" or K.lootKindKo(grade:upper(), false))\r\nif pwEn ~= \"\" then\r\nwhat = what .. \" · \" .. esc(K.lootPwKo(pwEn))\r\nend\r\nreturn string.format('<div class=\"dnd-tag chk%s\" data-v=\"%s\"><div class=\"dnd-h\"><span class=\"dnd-chip\">✧ 전리품 · %s등급</span><b>%s</b> · %s</div><div class=\"dnd-sub\">%s%s</div></div>',\r\nverdict == \"\" and \" pend\" or \"\", esc(verdict), esc(grade), esc(a[1] or \"\"), what,\r\n(a[4] or \"\") ~= \"\" and (esc(a[4]) .. \" · \") or \"\",\r\nverdict == \"\" and \"검증 전\" or ('<span class=\"dnd-vd\">Lua ' .. esc(verdict) .. \"</span>\"))\r\nend\r\nif tag == \"TRAP\" then\r\nlocal a = args(f)\r\nlocal verdict, hp = f[#a + 1] or \"\", f[#a + 2] or \"\"\r\n\r\nlocal fallFt = (a[1] or \"\"):match(\"^[Ff]all%s*(%d+)\") or (a[1] or \"\"):match(\"^낙하%s*(%d+)\")\r\nif fallFt then\r\nreturn string.format('<div class=\"dnd-tag atk%s\" data-v=\"%s\"><div class=\"dnd-h\"><span class=\"dnd-chip\">⚠ 낙하</span><b>%s피트</b> · 내성 없음 · 피해 <span class=\"dnd-big\">%s</span></div>%s</div>',\r\nverdict == \"\" and \" pend\" or \"\", esc(verdict), esc(fallFt), esc(a[9] or \"\"),\r\nK.sfRow({ K.sfDamage(a[7], a[8]), verdict ~= \"\" and { \"생명력\", esc(toKo(hp)) } or nil },\r\nverdict == \"\" and \"검증 전\" or ('<span class=\"dnd-vd\">Lua ' .. esc(verdict) .. \"</span>\")))\r\nend\r\nreturn string.format('<div class=\"dnd-tag atk%s\" data-v=\"%s\"><div class=\"dnd-h\"><span class=\"dnd-chip\">⚠ 함정 · %s</span><b>%s</b> vs 난이도 %s · <b class=\"dnd-r\" data-r=\"%s\">%s</b> · 피해 <span class=\"dnd-big\">%s</span></div>%s</div>',\r\nverdict == \"\" and \" pend\" or \"\", esc(verdict), esc(a[1] or \"\"), esc(a[2] or \"\"), esc(a[5] or \"\"), esc(a[6] or \"\"), esc(a[6] or \"\"), esc(a[9] or \"\"),\r\nK.sfRow({ { \"굴림\", K.d20Html(a[3] or \"\") .. \" \" .. esc(a[4] or \"\") }, K.sfDamage(a[7], a[8]),\r\nverdict ~= \"\" and { \"생명력\", esc(toKo(hp)) } or nil },\r\nverdict == \"\" and \"검증 전\" or ('<span class=\"dnd-vd\">Lua ' .. esc(verdict) .. \"</span>\")))\r\nend\r\nif tag == \"BUY\" or tag == \"SELL\" then\r\nlocal a = args(f)\r\nlocal verdict, money, have = f[#a + 1] or \"\", f[#a + 2] or \"\", f[#a + 3] or \"\"\r\nlocal sub = verdict == \"\" and \"검증 전\"\r\nor (\"남은 돈 \" .. esc(money) .. \" · \" .. (have == \"-\" and \"따로 세지 않는 물건\" or (\"보유 \" .. esc(have)))\r\n.. ' · <span class=\"dnd-vd\">Lua ' .. esc(verdict) .. \"</span>\")\r\nreturn string.format('<div class=\"dnd-tag chk%s\" data-v=\"%s\"><div class=\"dnd-h\"><span class=\"dnd-chip\">¤ %s</span><b>%s</b> ×%s · %s</div><div class=\"dnd-sub\">%s</div></div>',\r\nverdict == \"\" and \" pend\" or \"\", esc(verdict), tag == \"BUY\" and \"구매\" or \"판매\",\r\nesc(a[1] or \"\"), esc(a[2] or \"\"), esc(a[3] or \"\"), sub)\r\nend\r\nif tag == \"ROLL_STATS\" then\r\nlocal ok2 = f[1] == \"ok\"\r\nreturn string.format('<div class=\"dnd-tag chk%s\"><div class=\"dnd-h\"><span class=\"dnd-chip\">❖ 능력치 굴림</span><b>%s</b></div><div class=\"dnd-sub\">4d6에서 가장 낮은 주사위를 뺀 값 6개 · %s</div></div>',\r\nok2 and \"\" or \" pend\", esc(f[2] or \"\"), ok2 and \"Lua ok\" or \"검증 전\")\r\nend\r\nif tag == \"PC\" then\r\nlocal a = args(f)\r\n\r\nif not table.concat(a, \"\"):find(\"%a\") then return \"[PC]\" end\r\nlocal verdict = f[#a + 1] or \"\"\r\n\r\n\r\nlocal base, plus, ab, sk = {}, {}, {}, {}\r\nfor n in (a[5] or \"\"):gmatch(\"%d+\") do base[#base + 1] = tonumber(n) end\r\nfor n, x in (a[6] or \"\"):gmatch(\"%+%s*(%d)%s*(%a+)\") do\r\nlocal k = abilityName(x)\r\nif k then plus[k] = (plus[k] or 0) + tonumber(n) end\r\nend\r\nif #base == 6 then\r\nfor i, k in ipairs(ABILS) do ab[#ab + 1] = K.chip(koName(k) .. \" \" .. math.min(20, base[i] + (plus[k] or 0)), plus[k] and (\"+\" .. plus[k])) end\r\nend\r\nfor _, k in ipairs(splitNames(a[7])) do sk[#sk + 1] = K.chip(koName(k)) end\r\nlocal how = ({ standard = \"표준 배열\", pointbuy = \"포인트 구매\", roll = \"굴림\" })[(a[4] or \"\"):lower()]\r\nlocal co, bo = (a[8] or \"\"):gsub(\"%s\", \"\"):match(\"^(%a),(%a)$\")\r\nlocal sub = { \"배경 \" .. esc(toKo(trim(a[3] or \"\"))) }\r\nif how then sub[#sub + 1] = \"능력치 \" .. how end\r\nif co then sub[#sub + 1] = \"시작 장비 클래스 \" .. co:upper() .. \", 배경 \" .. bo:upper() end\r\n\r\n\r\nlocal refused = verdict:match(\"^bad:\") and trim(f[#a + 2] or \"\") == \"-\"\r\nsub[#sub + 1] = refused and ('<span class=\"dnd-vd\">Lua bad</span> · ' .. esc(K.Form.why(\"|\" .. verdict .. \"|\"))) or K.vdHtml(verdict)\r\nreturn string.format('<div class=\"dnd-tag chk\" data-v=\"%s\"><div class=\"dnd-h\"><span class=\"dnd-chip\">❖ 캐릭터</span><b>%s</b></div>%s%s<div class=\"dnd-sub\">%s</div></div>',\r\nesc(verdict), esc(toKo(trim(a[1] or \"\")) .. \" \" .. toKo(trim(a[2] or \"\")) .. \" \" .. (tonumber(a[9] or \"\") or 1) .. \"레벨\"),\r\nK.chipRow(\"능력치\", ab), K.chipRow(\"기술\", sk), table.concat(sub, \" · \"))\r\nend\r\n\r\n\r\nif tag == \"XP\" and #f >= 4 and (f[3]:match(\"^bad:cap\") or f[4]:find(\"(max level)\", 1, true)) then\r\nlocal maxed = f[4]:find(\"(max level)\", 1, true) ~= nil\r\nlocal gave = f[3]:match(\"^bad:cap (%d+)\") or f[1]\r\nreturn string.format('<div class=\"dnd-tag chk\" data-v=\"%s\"><div class=\"dnd-h\"><span class=\"dnd-chip\">✦ 경험치</span>%s</div><div class=\"dnd-sub\">%s%s</div></div>',\r\nmaxed and \"ok\" or esc(f[3]),\r\nmaxed and \"최고 레벨이라 더 쌓이지 않습니다\" or ('<span class=\"dnd-big\">+' .. esc(gave) .. '</span> · 한 답에 받을 수 있는 만큼만'),\r\nesc(f[2] or \"\"), maxed and \"\" or (' · <span class=\"dnd-vd\">Lua ' .. esc(f[3]) .. '</span>'))\r\nend\r\n\r\n\r\n\r\n\r\nif tag == \"PLAN\" and not debugOn then return \"\" end\r\nlocal MISC = { IMPREG = \"♀ 임신 판정\", PREG = \"♀ 임신\", OVERSTIM = \"♡ 과자극\", SCORE = \"▼ 능력치\", MAXDOWN = \"▼ 최대치\", BADEND = \"✖ 배드 엔드\",\r\nKNOCKOUT = \"✦ 기절\", BIND = \"⛓ 구속\", ESCAPE = \"⛓ 탈출\", CURSE = \"☠ 저주\", BRAND = \"☠ 낙인\", FETISH = \"♡ 페티시\", VICE = \"◈ 중독\",\r\nIMPLANT = \"◈ 주문 심기\", TRIGGER = \"◈ 심은 주문 발동\", PLAN = \"◇ 미리 둔 적\", STRIP = \"♡ 벗기기\" }\r\nif MISC[tag] then\r\nlocal a = args(f)\r\nlocal verdict, note = f[#a + 1] or \"\", (f[#a + 2] or \"\"):gsub(\"%-&gt;\", \"->\"):gsub(\"→\", \"->\")\r\nlocal function nm(x) x = trim(x or \"\"); return (x == \"Player\" or x == \"\") and \"당신\" or toKo(x) end\r\nlocal function ab(x) return koName(Canon.name(trim(x or \"\"))) end\r\nlocal title, sub = \"\", {}\r\nlocal RES = { success = \"성공\", failure = \"실패\", [\"성공\"] = \"성공\", [\"실패\"] = \"실패\" }\r\nif tag == \"IMPREG\" then\r\n\r\nlocal bonus, dc = a[4], a[5]\r\nlocal nb = verdict:match(\"bonus [%+%-]?%d+%->([%+%-]?%d+)\")\r\nlocal nd = verdict:match(\"DC %d+%->(%d+)\")\r\ntitle = nm(a[1]) .. \" → \" .. nm(a[2])\r\nsub[#sub + 1] = \"d20 \" .. K.d20Ko(a[3] or \"?\") .. \" \" .. tostring(nb or bonus or \"\") .. \" · 난이도 \" .. tostring(nd or dc or \"?\")\r\n\r\nlocal an, ad = note:match(\"%(([^:()]+): Advantage, Lua[^%d]-second d20 (%d+)%)\")\r\nif not ad then an, ad = note:match(\"%(([^:()]+): 이점, Lua의 두 번째 d20 (%d+)%)\") end\r\nif ad then sub[#sub + 1] = toKo(trim(an)) .. \": 이점, Lua의 두 번째 d20 \" .. ad end\r\nlocal r = note:match(\"^([^%s:]+)\")\r\nif RES[r or \"\"] then\r\nlocal how = note:find(\"nontraditional\", 1, true) and \"비전통\" or note:find(\"traditional\", 1, true) and \"전통\" or nil\r\nsub[#sub + 1] = RES[r] .. ((r == \"success\" and how) and (\": 임신(\" .. how .. \")\") or \"\")\r\nend\r\nelseif tag == \"PREG\" then\r\nlocal op = trim(a[2] or \"\")\r\ntitle = nm(a[1])\r\nif op == \"+\" then sub[#sub + 1] = \"임신\" .. ((a[3] or \"\") ~= \"\" and (\" · \" .. toKo(a[3])) or \"\") .. (((a[4] or \"\"):find(\"nontrad\")) and \" · 비전통\" or \"\")\r\nelseif op == \"shows\" then sub[#sub + 1] = \"임신이 드러남\"\r\nelseif op == \"-\" then sub[#sub + 1] = ((a[3] or \"\"):lower() == \"birth\") and \"출산\" or \"임신 끝남\"\r\nelseif op == \"term\" then sub[#sub + 1] = \"비전통으로 바뀜\"\r\nelseif op == \"move\" then sub[#sub + 1] = \"임신이 \" .. nm(a[3]) .. \"에게 옮겨감\" end\r\nlocal due = note:match(\"birth at ([^%)%]]+)\")\r\nif due then sub[#sub + 1] = \"출산 \" .. toKo(due) end\r\nelseif tag == \"OVERSTIM\" then\r\ntitle = nm(a[1]) .. \" \" .. tostring(a[2] or \"\")\r\nlocal w, n2 = note:match(\"overstimulation (%d+)%->(%d+)\")\r\nif w then sub[#sub + 1] = \"과자극 \" .. w .. \"→\" .. n2 .. (note:find(\"BAD END\", 1, true) and \" · 배드 엔드\" or \"\") end\r\nelseif tag == \"SCORE\" then\r\ntitle = nm(a[1]) .. \" · \" .. ab(a[2]) .. \" \" .. tostring(a[3] or \"\")\r\nelseif tag == \"MAXDOWN\" then\r\ntitle = nm(a[1]) .. \" · \" .. (((a[2] or \"\"):lower() == \"hp\") and \"생명력\" or \"흥분도\") .. \" 최대치 \" .. tostring(a[3] or \"\")\r\nelseif tag == \"BADEND\" then\r\ntitle = nm(a[1]) .. \" · \" .. toKo(a[2] or \"\")\r\nelseif tag == \"KNOCKOUT\" then\r\ntitle = nm(a[1])\r\nif note:find(\"knocked out\", 1, true) then sub[#sub + 1] = \"생명력 1로 기절, 살아 있음\" end\r\nelseif tag == \"BIND\" then\r\nif trim(a[1] or \"\") == \"-\" then title = nm(a[2]) .. \" · 풀림\"\r\nelse\r\ntitle = nm(a[1]) .. \" → \" .. nm(a[2]) .. \" · \" .. toKo(a[3] or \"\") .. ((a[4] or \"\") ~= \"\" and (\" · \" .. toKo(a[4])) or \"\")\r\nlocal e1, b1 = note:match(\"escape DC (%d+), break DC (%d+)\")\r\nif e1 then sub[#sub + 1] = \"탈출 난이도 \" .. e1 .. \" · 끊기 난이도 \" .. b1 end\r\nend\r\nelseif tag == \"STRIP\" then\r\nlocal w0, t0 = (a[1] or \"\"):match(\"^(.-)/(.+)$\")\r\ntitle = (w0 and (nm(w0) .. \" → \") or \"\") .. nm(t0 or a[1])\r\nsub[#sub + 1] = \"손재주 \" .. K.d20Ko(a[2] or \"?\") .. \" \" .. tostring(a[3] or \"\") .. \" vs 방어도 \" .. tostring(a[4] or \"?\")\r\nlocal acN = (tostring(verdict) .. \" \" .. tostring(note)):match(\"(%d+) now\")\r\nsub[#sub + 1] = acN and (\"한 겹 벗겨짐 · 방어도 \" .. acN) or \"못 벗김\"\r\nelseif tag == \"ESCAPE\" then\r\ntitle = nm(a[1]) .. \" · \" .. toKo(a[2] or \"\") .. \" · \" .. ab(a[3])\r\nsub[#sub + 1] = \"d20 \" .. K.d20Ko(a[4] or \"?\") .. \" \" .. tostring(a[5] or \"\") .. \" · 난이도 \" .. tostring(a[6] or \"?\")\r\nif note:find(\"free\", 1, true) then sub[#sub + 1] = \"벗어남\" elseif note:find(\"still bound\", 1, true) then sub[#sub + 1] = \"못 벗어남\" end\r\nelseif tag == \"CURSE\" or tag == \"BRAND\" or tag == \"FETISH\" then\r\nlocal sign, n2 = (a[2] or \"\"):match(\"^%s*([+-]?)%s*(.-)%s*$\")\r\ntitle = nm(a[1]) .. \" · \" .. toKo(n2 or \"\")\r\nif sign == \"+\" then sub[#sub + 1] = \"붙음\" elseif sign == \"-\" then sub[#sub + 1] = \"풀림\"\r\nelseif tag == \"BRAND\" then sub[#sub + 1] = \"단계 \" .. tostring(a[3] or \"\") end\r\nelseif tag == \"PLAN\" then\r\nlocal o = {}\r\nfor _, x in ipairs(a) do o[#o + 1] = trim(x) == \"-\" and \"지움\" or toKo(Canon.name(trim(x))) end\r\ntitle = table.concat(o, \", \")\r\nlocal pps = {}\r\nfor pp in note:gmatch(\"passive Perception (%d+)\") do pps[#pps + 1] = pp end\r\nif #pps > 0 then sub[#sub + 1] = \"수동 감지 \" .. table.concat(pps, \", \") end\r\nelseif tag == \"IMPLANT\" or tag == \"TRIGGER\" then\r\ntitle = nm(a[1]) .. \" · \" .. koName(Canon.name(trim(a[2] or \"\")))\r\nif tag == \"IMPLANT\" then\r\nlocal lv = note:match(\" level (%d+) on \")\r\nif lv then sub[#sub + 1] = lv == \"0\" and \"소마법\" or (lv .. \"레벨\") end\r\nif trim(a[4] or \"\") ~= \"\" then sub[#sub + 1] = \"신호 «\" .. esc(trim(a[4])) .. \"»\" end\r\nlocal span = note:match('\", (.-), %d+/%d+ held')\r\nif span then sub[#sub + 1] = span == \"an action\" and \"행동 하나\" or (span:gsub(\"(%d+) hours?\", \"%1시간\"):gsub(\"(%d+) minutes?\", \"%1분\")) end\r\nlocal h1, h2 = note:match(\"(%d+)/(%d+) held\")\r\nif h1 then sub[#sub + 1] = \"심긴 주문 \" .. h1 .. \"/\" .. h2 end\r\nelse\r\nsub[#sub + 1] = \"슬롯 없이 시전 · 첫 내성은 자동 실패\"\r\nend\r\nelseif tag == \"VICE\" then\r\ntitle = nm(a[1]) .. \" · \" .. toKo(a[2] or \"\")\r\nsub[#sub + 1] = \"d20 \" .. K.d20Ko(a[4] or \"?\") .. \" \" .. tostring(a[5] or \"\") .. \" · 난이도 \" .. tostring(a[6] or \"?\")\r\nif note:find(\"addicted (\", 1, true) then sub[#sub + 1] = \"중독됨\" elseif note:find(\"still addicted\", 1, true) then sub[#sub + 1] = \"여전히 중독\" elseif note:find(\"not addicted\", 1, true) then sub[#sub + 1] = \"중독 안 됨\" end\r\nend\r\nsub[#sub + 1] = verdict == \"\" and \"검증 전\" or K.vdHtml(verdict)\r\nreturn string.format('<div class=\"dnd-tag%s\" data-v=\"%s\"><div class=\"dnd-h\"><span class=\"dnd-chip\">%s</span><b>%s</b></div><div class=\"dnd-sub\">%s</div></div>',\r\nverdict == \"\" and \" pend\" or \"\", esc(verdict), MISC[tag], esc(title), table.concat(sub, \" · \")) .. explain\r\nend\r\n\r\nlocal bi\r\nfor i, v in ipairs(f) do if v:match(\"^bad:\") then bi = i break end end\r\nif bi then\r\nlocal shown = { tag }\r\nfor i = 1, bi - 1 do if f[i] ~= \"\" and f[i] ~= \"-\" then shown[#shown + 1] = f[i] end end\r\nreturn string.format('<div class=\"dnd-tag chk\" data-v=\"%s\"><div class=\"dnd-h\"><span class=\"dnd-chip\">◇ 처리 못 한 태그</span><b>%s</b></div><div class=\"dnd-sub\">%s</div></div>',\r\nesc(f[bi]), esc(table.concat(shown, \" · \")), K.vdHtml(f[bi])) .. explain\r\nend\r\nreturn \"[\" .. tag .. \"|\" .. table.concat(f, \"|\") .. \"]\" .. explain\r\nend\r\nreturn (text:gsub(\"%[([%u_]+)|([^%]]*)%]\", drawOne))\r\nend)\r\nif not ok then return back(text) end\r\n\r\nlocal s = out:find('<div class=\"dnd-st\">', 1, true) or out:find(\"[STATUS|\", 1, true)\r\nif s and latest then\r\nlocal okd, ui = pcall(buildDrawer, id, false, idx, getChatLength(id) - 1)\r\nif okd and type(ui) == \"string\" then out = out:sub(1, s - 1) .. ui .. \"\\n\" .. out:sub(s) end\r\n\r\nlocal okn, note = pcall(K.pickNotice, id)\r\nif okn and note ~= \"\" then out = \"{{#when::{{chat_index}}::is::{{lastmessageid}}}}\" .. note .. \"{{/when}}\\n\" .. out end\r\nend\r\nreturn back(out)\r\nend\r\n\r\n\r\n\r\nfunction K.pickNotice(id)\r\nlocal sh = loadSheet(id)\r\napplySheet(sh)\r\nlocal pc = loadPC(id)\r\nlocal names = {}\r\nlocal _, expLeft = expertiseChoices(sh)\r\nif expLeft > 0 then names[#names + 1] = (K.cl(sh, \"Wizard\") >= 2 and K.cl(sh, \"Rogue\") + K.cl(sh, \"Bard\") + K.cl(sh, \"Ranger\") == 0) and \"학자 기술\" or \"숙달\" end\r\nfor _, row in ipairs(Feat.pending(sh, pc)) do\r\nnames[#names + 1] = ((Feat.TITLE[row.key] or row.key):gsub(\" · .*$\", \"\"))\r\nend\r\nif sh.asi_pending then names[#names + 1] = \"능력치 점수 상승\" end\r\nif sh.hp_pending then names[#names + 1] = \"생명력\" end\r\nlocal onTab = #names\r\nif Feat.miOpen(sh) then names[#names + 1] = \"마법 입문자 주문(GM과 정하기)\" end\r\n\r\nlocal room = K.bookClass(sh) and Spell.bookRoom(sh) or 0\r\nif room > 0 then names[#names + 1] = string.format(\"주문서 빈칸 %d(GM과 정하기)\", room) end\r\n\r\n\r\nlocal cviews = K.casterViews(sh)\r\nfor i, csh in ipairs(cviews) do\r\nlocal row = CLASSES[csh.class].levels[csh.level]\r\nlocal tag = #cviews > 1 and (koName(csh.class) .. \" \") or \"\"\r\nif row and (#(csh.cantrips or {}) > 0 or #(csh.spells or {}) > 0) then\r\nlocal oc = Spell.cantripsOpen(csh, row)\r\nlocal op = math.max(0, (row.prepared or 0) - #(csh.spells or {}))\r\nif oc > 0 then names[#names + 1] = string.format(\"%s소마법 빈칸 %d(주문 칸에서 누르거나 GM과 정하기)\", tag, oc) end\r\nif op > 0 then names[#names + 1] = string.format(\"%s준비 주문 빈칸 %d(GM과 정하기)\", tag, op) end\r\nelseif row and i > 1 then\r\nnames[#names + 1] = tag .. \"주문(GM과 정하기)\"\r\nend\r\nend\r\nif #names == 0 then return \"\" end\r\nlocal how = onTab == 0 and \"GM에게 말을 걸면 함께 고릅니다. 맡기셔도 됩니다.\"\r\nor #names > onTab and \"오른쪽 위 ❖ 설정을 눌러 캐릭터 탭에서 고르십시오. GM과 정하기라고 적힌 것은 GM에게 말을 걸면 함께 고릅니다.\"\r\nor \"오른쪽 위 ❖ 설정을 눌러 캐릭터 탭에서 고르십시오.\"\r\n\r\nif Feat.miOpen(sh) then how = how .. \" 마법 입문자 주문(소마법 둘과 1레벨 주문 하나)은 클래스 주문과 따로, GM에게 \\\"마법 입문자 주문 정하자\\\"라고 말을 걸어 고릅니다.\" end\r\nreturn '<div class=\"dnd-tag\" style=\"border-color:#e06060\"><div class=\"dnd-h\" style=\"color:#e06060;font-weight:700\">⚠ 고를 것이 남아 있습니다 · '\r\n.. esc(table.concat(names, \", \")) .. '</div><div class=\"dnd-sub\">' .. how .. '</div></div>'\r\nend\r\n\r\n\r\n\r\n\r\n\r\nfunction K.errToast(id, idx)\r\nlocal err = getChatVar(id, \"dnd_lua_error\")\r\nif not err or err == \"\" or err == \"null\" then return \"\" end\r\nif getChatVar(id, \"dnd_drawer_open\") == \"1\" then return \"\" end\r\n\r\n\r\nlocal m = getChat(id, idx)\r\nif type(m) == \"table\" and m.role == \"user\" then return \"\" end\r\nlocal okc, cut = pcall(utf8.offset, err, 121)\r\nlocal short = (okc and cut) and (err:sub(1, cut - 1) .. \"…\") or err\r\nreturn '\\n<div class=\"dnd-toast\">⚠ Lua 오류 · ' .. esc(short) .. ' · 자세한 내용은 ❖ 설정 서랍 맨 위에 있습니다</div>'\r\nend\r\n\r\n\r\n\r\n\r\nlistenEdit(\"editDisplay\", function(id, text, meta)\r\nif type(text) ~= \"string\" then return text end\r\nlocal t0 = clockNow()\r\nlocal idx = type(meta) == \"table\" and tonumber(meta.index) or nil\r\n\r\n\r\n\r\nlocal oks, sec = pcall(os.time)\r\n\r\nlocal okd, dm = pcall(function() return tostring(getChatVar(id, \"dnd_dlc_mode\")) .. tostring(getChatVar(id, \"dnd_dlc_perm\"))\r\n.. tostring(getChatVar(id, \"dnd_dlc_furry\")) .. tostring(getChatVar(id, \"dnd_dlc_xeno\")) .. tostring(getChatVar(id, \"dnd_dlc_adult\"))\r\n.. tostring(getChatVar(id, \"dnd_dlc_omega\")) end)\r\ndm = okd and dm or \"\"\r\nlocal okf, fpv = pcall(getChatVar, id, \"dnd_pack_fp\")\r\nfpv = okf and tostring(fpv) or \"\"\r\nif not K.PACK.seen or K.PACK.seenD2 ~= dm or (fpv ~= \"\" and fpv ~= \"null\" and fpv ~= \"nil\" and fpv ~= K.PACK.seenFp) then\r\nK.PACK.seen, K.PACK.seenD2, K.PACK.seenFp = oks and sec or 0, dm, fpv\r\npcall(K.packs, id)\r\nend\r\nK.fxMemo = setmetatable({}, { __mode = \"k\" })\r\nK.SC = {}\r\nlocal ok, out = pcall(displayMessage, id, text, meta)\r\nK.SC = nil\r\nif ok and K.LITE then out = K.liteMP(K.liteSwap(out)) end\r\nlocal okn, newest = pcall(K.isNewest, id, idx)\r\nnewest = okn and newest\r\n\r\nif ok and type(out) == \"string\" then\r\nout = out:gsub('(<span class=\"dnd%-vd\">Lua bad:)(.-)(</span>)', function(a, why, b) return a .. K.acdc(K.whyKo(K.downKo(K.raiseKo(K.miKo(why))))) .. b end)\r\n:gsub('(<span class=\"dnd%-vd\">Lua 고침 · )(.-)(</span>)', function(a, why, b) return a .. K.acdc(K.whyKo(K.downKo(K.raiseKo(K.miKo(why))))) .. b end)\r\nif getChatVar(id, \"dnd_opt_debug\") ~= \"1\" then\r\nout = out:gsub(' · <span class=\"dnd%-vd\">Lua ok</span>', \"\"):gsub('<span class=\"dnd%-vd\">Lua ok</span> · ', \"\"):gsub('<span class=\"dnd%-vd\">Lua ok</span>', \"\")\r\nelseif newest then\r\n\r\nout = out .. '<span class=\"dnd-dbg-on\" style=\"display:none\"></span>'\r\nend\r\nend\r\nif ok and type(out) == \"string\" and newest then\r\nlocal okt, toast = pcall(K.errToast, id, idx)\r\nif okt and toast then out = out .. toast end\r\nend\r\nlocal ms = (clockNow() - t0) * 1000\r\nK.PERF = K.PERF or { max = 0 }\r\nif newest then\r\nK.PERF.last = ms\r\nif ms > K.PERF.max then K.PERF.max = ms end\r\nend\r\n\r\n\r\n\r\nlocal okt, sec = pcall(os.time)\r\nif okt and sec then\r\nlocal b = K.PERF.burst\r\nif not b or b.at ~= sec then\r\nif b and b.old and (not K.PERF.bmax or b.ms > K.PERF.bmax.ms) then K.PERF.bmax = b end\r\nb = { at = sec, ms = 0, n = 0 }\r\nK.PERF.burst = b\r\nend\r\nb.ms, b.n = b.ms + ms, b.n + 1\r\nif idx and idx < getChatLength(id) - 1 and not newest then b.old = true end\r\nend\r\nif ok and type(out) == \"string\" then return out end\r\nreturn text\r\nend)\r\n","type":"triggerlua"}],"lowLevelAccess":false,"type":"start"}],"utilityBot":false,"viewScreen":"none","virtualscript":"","vits":{}}},"first_mes":"※※C\n모험을 시작하기 전에, 잠깐 테이블에 앉아 보십시오.\n\n이 판은 5.5판(2024년 개정 규칙)으로 굴러갑니다. 주사위와 숫자는 Lua가 세고, 저는 세계와 그 안의 사람들, 그리고 당신의 선택이 불러오는 일을 들려드리겠습니다.\n\n먼저 함께 갈 캐릭터를 정합니다. 아래 캐릭터 만들기에서 종족과 클래스, 배경을 고르거나, 해 보고 싶은 캐릭터를 말로 들려주셔도 됩니다. \"불을 다루는 엘프 마법사\"처럼 한 줄이면 충분합니다.\n\n그다음 첫 장면을 정합니다.\n- 바라는 곳을 한 줄로 말해 주십시오. 항구 도시의 뒷골목, 눈보라 속 산장, 무너진 성채 앞, 어디든 좋습니다.\n- 모험 모듈을 함께 넣었다면 \"모듈로 시작\"이라고만 해 주십시오. 그 모험의 첫 장면에서 시작하겠습니다.\n- 아무것도 정하지 않으면 당신의 캐릭터에 어울리는 곳에서 이야기를 열겠습니다.\n\n자, 당신은 어떤 사람입니까?\n","group_only_greetings":[],"mes_example":"","modification_date":1793904049,"name":"던전 앤 다이스","nickname":"","personality":"","post_history_instructions":"","scenario":"","source":["risurealm:07e953e0-4261-410c-b030-cec446390695"],"system_prompt":"","tags":[]},"spec":"chara_card_v3","spec_version":"3.0"}