Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 | // botl_descriptions.js — Status line field descriptions from the Guidebook. // Used by the hover panel to explain botl elements on rows 22-23. export const botlDescriptions = { // Row 22 fields (status line 1) 'title': { label: 'Title', desc: 'Your character\'s name and professional ranking, based on role and experience level.', }, 'St': { label: 'Strength', desc: 'A measure of your character\'s physical strength. Affects how successfully you perform physical tasks, how much damage you do in combat, and how much loot you can carry. Super-strengths of the form 18/xx are possible.', }, 'Dx': { label: 'Dexterity', desc: 'Affects your chances to hit in combat, to avoid traps, and do other tasks requiring agility or manipulation of objects.', }, 'Co': { label: 'Constitution', desc: 'Affects your ability to recover from injuries and other strains on your stamina. When strength is low, constitution also affects how much you can carry.', }, 'In': { label: 'Intelligence', desc: 'Affects your ability to cast spells and read spellbooks.', }, 'Wi': { label: 'Wisdom', desc: 'Comes from your practical experience, especially when dealing with magic. Affects your magical energy.', }, 'Ch': { label: 'Charisma', desc: 'Affects how certain creatures react toward you. In particular, it can affect the prices shopkeepers offer you.', }, 'Lawful': { label: 'Alignment: Lawful', desc: 'Often taken as good. Your alignment influences how other monsters react toward you. Monsters of a like alignment are more likely to be non-aggressive.', }, 'Neutral': { label: 'Alignment: Neutral', desc: 'Between law and chaos. Your alignment influences how other monsters react toward you. Monsters of a like alignment are more likely to be non-aggressive.', }, 'Chaotic': { label: 'Alignment: Chaotic', desc: 'Often taken as evil, but legal and ethical do not always coincide. Your alignment influences how other monsters react toward you.', }, // Row 23 fields (status line 2) 'Dlvl': { label: 'Dungeon Level', desc: 'How deep you are in the dungeon. You start at level one and the number increases as you go deeper. The Amulet of Yendor is reputed to be somewhere beneath the twentieth level.', }, '$': { label: 'Gold', desc: 'The number of gold pieces you are openly carrying. Gold concealed in containers is not counted.', }, 'HP': { label: 'Hit Points', desc: 'Your current and maximum hit points. Hit points indicate how much damage you can take before you die. You can regain hit points by resting, or by using certain magical items or spells.', }, 'Pw': { label: 'Power (Mana)', desc: 'Spell points. How much mystic energy you have available for spell casting. Resting will regenerate the amount available.', }, 'AC': { label: 'Armor Class', desc: 'A measure of how effectively your armor stops blows. The lower this number, the more effective the armor. It is quite possible to have negative armor class.', }, 'Xp': { label: 'Experience', desc: 'Your current experience level. As you adventure, you gain experience points. At certain totals, you gain a level. The more experienced you are, the better you fight and withstand magical attacks.', }, 'T': { label: 'Time (Turns)', desc: 'The number of turns elapsed so far.', }, // Status conditions 'Satiated': { label: 'Satiated', desc: 'You have eaten too much. You may vomit if you eat more.', }, 'Hungry': { label: 'Hungry', desc: 'You are getting hungry. Find something to eat soon.', }, 'Weak': { label: 'Weak', desc: 'You are weak from hunger. You are in danger of fainting.', }, 'Fainting': { label: 'Fainting', desc: 'You are about to faint from lack of food. Eat something immediately!', }, 'Burdened': { label: 'Burdened', desc: 'You are carrying a bit too much. Your movement is slightly slowed.', }, 'Stressed': { label: 'Stressed', desc: 'You are carrying too much. Your movement is noticeably slower.', }, 'Strained': { label: 'Strained', desc: 'You are severely overloaded. Movement is very slow.', }, 'Overtaxed': { label: 'Overtaxed', desc: 'You can barely move under the weight you carry.', }, 'Overloaded': { label: 'Overloaded', desc: 'You cannot move! Drop something.', }, 'Stone': { label: 'Petrifying', desc: 'You are turning to stone. Find a cure quickly or you will die!', }, 'Slime': { label: 'Sliming', desc: 'You are turning into green slime. Fire or a cure is needed urgently.', }, 'Strngl': { label: 'Strangled', desc: 'You are being strangled and will die soon if you don\'t escape.', }, 'FoodPois': { label: 'Food Poisoning', desc: 'You are suffering from acute food poisoning. Pray, heal, or cure it quickly.', }, 'TermIll': { label: 'Terminally Ill', desc: 'You are suffering from a terminal illness. Without a cure, death is imminent.', }, 'Blind': { label: 'Blind', desc: 'You can\'t see. Your map is not updated and you can\'t read.', }, 'Deaf': { label: 'Deaf', desc: 'You can\'t hear. You won\'t receive auditory messages.', }, 'Stun': { label: 'Stunned', desc: 'You are stunned. Movement and combat are unreliable.', }, 'Conf': { label: 'Confused', desc: 'You are confused. Reading, spellcasting, and movement directions may go awry.', }, 'Hallu': { label: 'Hallucinating', desc: 'You are hallucinating. Monsters and objects appear as random things.', }, 'Lev': { label: 'Levitating', desc: 'You are floating in the air. You cannot pick things up from the floor.', }, 'Fly': { label: 'Flying', desc: 'You are flying. You can cross water and lava safely.', }, 'Ride': { label: 'Riding', desc: 'You are riding a saddled steed.', }, }; // Parse a status line and return field regions as {start, end, key} ranges. // Row 22 example: "Merlin the Evoker St:12 Dx:12 Co:13 In:18 Wi:12 Ch:8 Neutral" // Row 23 example: "Dlvl:1 $:0 HP:12(12) Pw:8(8) AC:9 Xp:1" export function parseBotlFields(lineText, row) { const fields = []; if (!lineText) return fields; if (row === 22) { // Row 22: Title ... St:N Dx:N Co:N In:N Wi:N Ch:N Alignment // Find stat fields by pattern const statRe = /\b(St|Dx|Co|In|Wi|Ch):(\d+(?:\/\d+)?)/g; let m; let firstStatStart = lineText.length; while ((m = statRe.exec(lineText)) !== null) { fields.push({ start: m.index, end: m.index + m[0].length, key: m[1] }); if (m.index < firstStatStart) firstStatStart = m.index; } // Title is everything before the first stat if (firstStatStart > 0) { fields.push({ start: 0, end: firstStatStart, key: 'title' }); } // Alignment is after the last stat for (const align of ['Lawful', 'Neutral', 'Chaotic']) { const ai = lineText.indexOf(align); if (ai >= 0) { fields.push({ start: ai, end: ai + align.length, key: align }); break; } } } else if (row === 23) { // Row 23: Dlvl:N $:N HP:N(N) Pw:N(N) AC:N Xp:N T:N [conditions] const fieldRe = /\b(Dlvl|HP|Pw|AC|Xp|T):(-?\d+(?:\(\d+\))?(?:\/\d+)?)/g; let m; while ((m = fieldRe.exec(lineText)) !== null) { fields.push({ start: m.index, end: m.index + m[0].length, key: m[1] }); } // Gold: $:N const goldRe = /\$:(\d+)/; const gm = goldRe.exec(lineText); if (gm) { fields.push({ start: gm.index, end: gm.index + gm[0].length, key: '$' }); } // Status conditions — check for known keywords const conditions = ['Satiated', 'Hungry', 'Weak', 'Fainting', 'Burdened', 'Stressed', 'Strained', 'Overtaxed', 'Overloaded', 'Stone', 'Slime', 'Strngl', 'FoodPois', 'TermIll', 'Blind', 'Deaf', 'Stun', 'Conf', 'Hallu', 'Lev', 'Fly', 'Ride']; for (const cond of conditions) { const ci = lineText.indexOf(cond); if (ci >= 0) { fields.push({ start: ci, end: ci + cond.length, key: cond }); } } } return fields; } // Find which botl field the cursor is in. // Returns {label, desc, encycTerm?} or null. export function getBotlFieldAt(lineText, col, row) { const fields = parseBotlFields(lineText, row); for (const f of fields) { if (col >= f.start && col < f.end) { const info = botlDescriptions[f.key]; if (!info) return null; const rawText = lineText.slice(f.start, f.end).trim(); const result = { label: info.label, desc: info.desc, rawText: rawText }; // For the title field, extract the rank name for display and encyclopedia. // Title format: "Name the Rank" — show just the rank in big text. if (f.key === 'title') { const theIdx = rawText.indexOf(' the '); if (theIdx >= 0) { const rank = rawText.slice(theIdx + 5).trim(); result.rawText = rank; result.encycTerm = rank; result.encycPreformatted = true; // rank tables should not be re-wrapped } } return result; } } return null; } |