All files / js questpgr.js

95.67% Statements 1326/1386
63.93% Branches 117/183
75% Functions 18/24
95.67% Lines 1326/1386

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 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 138773x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x               73x 73x 73x 22x 22x 22x 22x 22x 22x 22x 22x 73x 73x 13x 13x 13x 73x 73x 73x 73x                     73x 73x 73x                                   73x 73x 48x 48x 48x 48x 48x 48x 48x 48x 48x 73x 73x 4x 4x 4x 4x 4x 73x 73x 22x 22x 22x 73x 73x 73x     73x 73x 12x 12x 12x 12x 27x 27x 12x 73x 73x         73x 73x       73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 69x 69x 69x 69x 69x 69x 69x 69x 69x 69x 69x 69x 69x 69x 69x 2x       69x 69x 69x 188x 188x 188x 188x 188x 188x 188x 188x 188x 188x 188x 188x 188x 188x 188x 188x 188x 188x 188x 188x 188x 188x 188x 188x 188x 188x 188x 69x 69x 69x 29x 29x 29x 29x 28x 29x 69x 69x 69x 69x 69x 14251x 14251x 14063x 14063x 14063x 188x 188x 188x 188x 188x 188x 188x 188x 188x 188x     188x 1x 1x 188x 16x 16x 188x 188x 188x 29x 29x 29x 29x     29x 188x 5x 5x 188x     188x     188x 9x 9x 188x 1x 1x 188x 127x 127x 188x 188x 188x 188x 188x 188x 69x 69x 73x 40x 40x 40x 40x 40x 40x 40x 40x 40x 28x 28x 28x 28x 28x 28x 40x 40x 40x 40x 40x 40x 290x 290x 40x 40x 40x 40x 40x 40x 40x 40x 40x 40x 40x 40x 49x 49x 49x 40x 40x 40x 40x 40x 40x 40x 40x 40x 40x 40x 40x 40x 40x 73x 73x 54x 54x 54x 54x 54x 54x 54x 54x 54x 54x 54x 51x 51x 51x 51x 51x 51x 54x 54x 54x 54x 54x 54x 54x 54x 45x 53x   9x 3x 3x 3x 3x 54x 54x 54x       48x 48x 48x 48x 54x 40x 40x 48x 54x 8x 53x 40x 40x     48x 48x 54x 54x 54x 54x 48x 21x 21x 21x 48x 48x 48x 54x 73x 73x 73x 3x 3x 73x 73x 73x 48x 48x 48x 48x 73x 73x 73x 133x 133x 107x 107x 107x 107x 107x 107x 133x 133x 133x 133x 133x 133x 73x 73x 73x 189x 4x 4x 4x 189x  
// questpgr.js — Quest-specific pager routines (port of questpgr.c)
// Quest text display, variable substitution, and quest monster types.
 
import { game } from './gstate.js';
import { rn2 } from './rng.js';
import { pline, putmsghistory } from './pline.js';
import { align_gname, align_gtitle } from './pray.js';
import { nhgetch, more } from './input.js';
import { enterModal, exitModal } from './modal_guard.js';
import { mons, M2_PNAME } from './monsters.js';
import { NON_PM, G_GENOD, MIN_QUEST_LEVEL, TOPLINE_NEED_MORE } from './const.js';
import { cls, docrt, erase_menu_or_text, flush_screen, NHW_TEXT, setBotlx, tty_clear_nhwindow, tty_create_nhwindow, tty_dismiss_nhwindow } from './display.js';
import { s_suffix } from './hacklib.js';
import { mkclass } from './makemon.js';
import { artiname, is_quest_artifact } from './artifact.js';
import { an as withAn, makeplural, the as withThe } from './objnam.js';
import { rank_of } from './botl.js';
 
// C ref: questpgr.c:30 quest_info
export function quest_info(typ) {
    const urole = game.urole;
    switch (typ) {
    case 0: return urole?.questarti ?? 0;
    // MS_LEADER, MS_NEMESIS, MS_GUARDIAN handled via constants
    default: return 0;
    }
}
 
// C ref: questpgr.c:49 ldrname
export function ldrname() {
    const urole = game.urole;
    const i = urole?.ldrnum ?? 0;
    const mon = mons[i];
    if (!mon) return 'leader';
    const name = mon.pmnames?.[2] ?? mon.mname ?? 'leader'; // NEUTRAL=2
    const prefix = (mon.mflags2 & M2_PNAME) ? '' : 'the ';
    return `${prefix}${name}`;
}
 
// C ref: questpgr.c:60 intermed
function intermed() {
    return game.urole?.intermed ?? '';
}
 
// C ref: questpgr.c:66 is_quest_artifact
 
// C ref: questpgr.c:72 find_qarti
function find_qarti(ochain) {
    for (let otmp = ochain; otmp; otmp = otmp.nobj) {
        if (is_quest_artifact(otmp)) return otmp;
        if (otmp.cobj) {
            const qarti = find_qarti(otmp.cobj);
            if (qarti) return qarti;
        }
    }
    return null;
}
 
// C ref: questpgr.c:88 find_quest_artifact
export function find_quest_artifact(whichchains) {
    let qarti = null;
    const OBJ_INVENT = 0, OBJ_FLOOR = 1, OBJ_MINVENT = 2,
          OBJ_MIGRATING = 3, OBJ_BURIED = 4;

    if (whichchains & (1 << OBJ_INVENT))
        qarti = find_qarti(game.invent);
    if (!qarti && (whichchains & (1 << OBJ_FLOOR)))
        qarti = find_qarti(game.level?.objlist ?? null);
    if (!qarti && (whichchains & (1 << OBJ_MINVENT))) {
        for (let mtmp = game.level?.monlist; mtmp; mtmp = mtmp.nmon) {
            if (mtmp.mhp <= 0) continue;
            qarti = find_qarti(mtmp.minvent);
            if (qarti) break;
        }
    }
    return qarti;
}
 
// C ref: questpgr.c:123 neminame
function neminame() {
    const urole = game.urole;
    const i = urole?.neminum ?? 0;
    const mon = mons[i];
    if (!mon) return 'nemesis';
    const name = mon.pmnames?.[2] ?? mon.mname ?? 'nemesis';
    const prefix = (mon.mflags2 & M2_PNAME) ? '' : 'the ';
    return `${prefix}${name}`;
}
 
// C ref: questpgr.c:133 guardname
function guardname() {
    const i = game.urole?.guardnum ?? 0;
    const mon = mons[i];
    return mon?.pmnames?.[2] ?? mon?.mname ?? 'guard';
}
 
// C ref: questpgr.c:141 homebase
function homebase() {
    return game.urole?.homebase ?? '';
}
 
// C ref: questpgr.c:149 stinky_nemesis — not ported (needs Lua text)
export function stinky_nemesis(mon) {
    return 0;
}
 
// C ref: questpgr.c:422 deliver_by_pline
async function deliver_by_pline(str) {
    if (!str) return;
    const lines = str.split('\n');
    for (const line of lines) {
        if (line) await pline(line);
    }
}
 
// C ref: questpgr.c:438 deliver_by_window
async function deliver_by_window(msg, how) {
    // Simplified: deliver via pline
    await deliver_by_pline(msg);
}
 
// C ref: questpgr.c:458 skip_pager
function skip_pager() {
    return false;
}
 
// C ref data: dat/quest.lua role text snippets used by currently exercised paths.
const QUEST_TEXT = {
    common: {
        quest_portal: {
            output: 'pline',
            text: `You receive a faint telepathic message from %l:\nYour help is urgently needed at %H!\nLook for a ...ic transporter.\nYou couldn't quite make out that last message.`,
        },
        quest_portal_again: {
            text: 'You again sense %l pleading for help.',
        },
        quest_portal_demand: {
            text: 'You again sense %l demanding your attendance.',
        },
    },
    Arc: {
        firsttime: `You are suddenly in familiar surroundings.  The buildings in the distance
seem to be those of your old alma mater, but something is wrong.  It feels
as if there has been a riot recently, or %H has
been under siege.
 
All of the windows are boarded up, and there are objects scattered around
the entrance.
 
Strange forbidding shapes seem to be moving in the distance.`,
        nexttime: 'Once again, you are back at %H.',
        othertime: `You are back at %H.
You have an odd feeling this may be the last time you ever come here.`,
        leader_first: `"Finally you have returned, %p.  You were always
my most promising student.  Allow me to see if you are ready for the
most difficult task of your career."`,
        leader_next: `"Again, %p, you stand before me.
Let me see if you have gained experience in the interim."`,
        leader_other: `"Once more, %p, you have returned from the field.
Are you finally ready for the task that must be accomplished?"`,
        leader_last: `"%p, you have failed us.  All of my careful training has been in
vain.  Begone!  Your tenure at this college has been revoked!
 
"You are a disgrace to the profession!"`,
        assignquest: `"Grave times have befallen the college, for %na has
stolen %o.  Without it, the board of directors of
the university will soon have no choice but to revoke our research grants.
 
"You must locate the entrance to %i.  Within it,
you will find %n.
 
"You must then defeat %n and return %o
to me.
 
"Only in this way will we be able to prevent the budget cuts that could
close this college.
 
"May the wisdom of %d be your guide."`,
        badalign: `"%pC!  I've heard that you've been using sloppy techniques.  Your
results lately can hardly be called suitable for %ra!
 
"How could you have strayed from the %a path?  Go from here, and come
back only when you have purified yourself."`,
        badlevel: `"%p, you are yet too inexperienced to undertake such a demanding
quest.  A mere %r could not possibly face the rigors demanded and
survive.  Go forth, and come here again when your adventures have further
taught you."`,
        discourage: [
            '"Try your best, %p.  You cannot defeat me."',
            '"I shall rend the flesh from your body whilst you still breathe!"',
            '"First you, %p, then I shall destroy your mentor, %l."',
            '"Tiring yet, %p?  I draw my power from my master and cannot falter!"',
            '"I shall rend thy soul from thy body and consume it!"',
            '"You are far too %a -- it weakens you.  You shall die in this place."',
            '"%d has forsaken you!  You are lost now!"',
            '"A mere %r cannot hope to defeat me!"',
            '"If you are the best %l can send, I have nothing to fear."',
            '"Die %c!  I shall exhibit your carcass as a trophy."',
        ],
        encourage: [
            '"Beware, for %n is powerful and cunning."',
            '"To locate the entrance to %i, you must pass many traps."',
            '"A %nt may be vulnerable to attacks by magical cold."',
            '"Call upon %d when you encounter %n."',
            '"You must destroy %n.  It will pursue you otherwise."',
            '"%oC is a mighty talisman.  With it you can destroy %n."',
            '"Go forth with the blessings of %d."',
            '"I will have my %gP watch for your return."',
            '"Remember not to stray from the true %a path."',
            '"You may be able to sense %o when you are near."',
        ],
        locate_first: `A plain opens before you.  Beyond the plain lies a foreboding edifice.
 
You have the feeling that you will soon find the entrance to
%i.`,
        locate_next: 'Once again, you are near the entrance to %i.',
        nemesis_first: `"So, %p, you think that you can succeed in recovering
%o, when your teacher, %l, has already failed.
 
"Come, try your best!  I shall destroy you, and gnaw on your bones."`,
        nemesis_next: `"Again you try to best me, eh %p?  Well, you shall fail again.
 
"You shall never recover %o.
 
"I shall bear your soul to the Plane of Origins for my master's pleasure."`,
        nemesis_other: '"You persist yet %p!  Good.  Now, you shall die!"',
        nemesis_wantsit: `"I shall have %o from you, %p, then feast
upon your entrails!"`,
        goal_first: `A strange feeling washes over you, and you think back to things you
learned during the many lectures of %l.
 
You realize the feeling must be the presence of %o.`,
        goal_next: 'The familiar presence of %o is in the ether.',
        goal_alt: 'You have returned to %ns lair.',
        posthanks: `"Welcome back, %p.  Have you progressed with your quest to
regain the Amulet of Yendor for %d?"`,
    },
    Hea: {
        firsttime: `What sorcery has brought you back to %H?  The smell
of fresh funeral pyres tells you that something is amiss with the healing
powers that used to practice here.
 
No rhizotomists are tending the materia medica gardens, and where are the
common folk who used to come for the cures?
 
You know that you must quickly make your way to the collegium, and
%ls iatreion, and find out what has happened in your absence.`,
        leader_first: `Feebly, %l raises %lj head to look at you.
 
"It is good to see you again, %p.  I see the concern in your
eyes, but do not worry for me.  I am not ready for Hades yet.  We have
exhausted much of our healing powers holding off %n.
I need your fresh strength to carry on our work.
 
"Come closer and let me lay hands on you, and determine if you have
the skills necessary to accomplish this mission."`,
        leader_next: `"Again you return to me, %p.  I sense that each trip back
the pleurisy and maladies of our land begin to infect you.  Let us
hope and pray to %d that you become ready for your task before
you fall victim to the bad humors."`,
        assignquest: `For the first time, you sense a smile on %ls face.
 
    "You have indeed learned as much as we can teach you in preparation
    for this task.  Let me tell you what I know of the symptoms and hope
    that you can provide a cure.
 
    "A short while ago, the dreaded %nt was fooled by the gods
    into thinking that %nh could use %o to find a
    cure for old age.  Think of it, eternal youth!  But %nj good
    health is accomplished by drawing the health from those around %ni.
 
    "He has exhausted %nj own supply of healthy people and now %nh seeks to
    extend %nj influence into our world.  You must recover from %ni
    %o and break the spell.
 
    "You must travel into the swamps to %i, and from there
    follow the trail to %ns island lair.  Be careful."`,
        locate_first: `You stand before the entrance to %i.  Strange
scratching noises come from within the building.
 
The swampy ground around you seems to stink with disease.`,
        locate_next: 'Once again you stand at the entrance to %i.',
        goal_first: `You stand within sight of the infamous Isle of %n.  Even
the words of %l had not prepared you for this.
 
Steeling yourself against the wails of the ill that pierce your ears,
you hurry on your task.  Maybe with %o you can
heal them on your return, but not now.`,
        goal_next: 'Once again, you %x the Isle of %n in the distance.',
    },
    Bar: {
        firsttime: `Warily you scan your surroundings, all of your senses alert for signs
of possible danger.  Off in the distance, you can %x the familiar shapes
of %H.
 
But why, you think, should %l be there?
 
Suddenly, the hairs on your neck stand on end as you detect the aura of
evil magic in the air.
 
Without thought, you ready your weapon, and mutter under your breath:
 
    "By %d, there will be blood spilt today."`,
        leader_first: `Ah, %p.  You have returned at last.  The world is in dire
need of your help.  There is a great quest you must undertake.
 
"But first, I must see if you are ready to take on such a challenge.`,
        leader_next: `"%p, you are back.  Are you ready now for the challenge?"`,
        assignquest: `The world is in great need of your assistance, %p.
 
"About six months ago, I learned that a mysterious sorcerer, known
as %n, had begun to gather a large group of cutthroats and brigands
about %ni.
 
"At about the same time, these people you once rode with \`liberated' a
potent magical talisman, %o, from a Turanian caravan.
 
"%nC and %nj Black Horde swept down upon %i and defeated
the people there, driving them out into the desert.  He has taken
%o, and seeks to bend it to %nj will.  I detected the
subtle changes in the currents of fate, and joined these people.
Then I sent forth a summons for you.
 
"If %n can bend %o to %nj will, he will become
almost indestructible.  He will then be able to enslave the minds of
men across the world.  You are the only hope.  The gods smile upon you,
and with %d behind you, you alone can defeat %n.
 
"You must go to %i.  From there, you can track down
%n, defeat %ni, and return %o to us.  Only
then will the world be safe.`,
        locate_first: `The scent of water comes to you in the desert breeze.  You know that
you have located %i.`,
        locate_next: `Yet again you have a chance to infiltrate %i.`,
        goal_first: `The hairs on the nape of your neck lift as you sense an energy in the
very air around you.  You fight down a primordial panic that seeks to
make you turn and run.  This is surely the lair of %n.`,
        goal_next: `Yet again you feel the air around you heavy with malevolent magical energy.`,
        nexttime: `Once again, you near %H.  You know that %l
will be waiting.`,
        othertime: `Again, and you think possibly for the last time, you approach
%H.`,
    },
    Cav: {
        firsttime: `You descend through a barely familiar stairwell that you remember
%l showing you when you embarked upon your vision quest.
 
You arrive back at %H, but something seems
wrong here.  The usual smoke and glowing light of the fires of the
outer caves are absent, and an uneasy quiet fills the damp air.`,
        nexttime: 'Once again, you arrive back at %H.',
        othertime: `For some reason, you think that this may be the last time you will
enter %H.`,
        leader_first: `"You have returned from your vision quest, %p.  Thank %d.
 
"We are in dire need of your help, my %S.
 
"But first, I must see if you are yet capable of the quest I would
ask you to undertake."`,
        leader_next: '"Again, you return to us, %p.  Let me see if you are ready now."',
        leader_other: '"Ah, %p.  Are you finally ready?"',
        leader_last: `"%pC!  You have sealed our fate.  You seem unable to reform yourself,
so I must select another to take your place.
 
"Begone from %H!  You have betrayed us by choosing
the path of the %C over the true path of the %L.
 
"You no longer live in our eyes."`,
        assignquest: `"You are indeed ready now, %p.  I shall tell you a tale of
great suffering among your people:
 
"Shortly after you left on your vision quest, the caves were invaded by
the creatures sent against us by %n.
 
"She, herself, could not attack us due to her great size, but her minions
have harassed us ever since.  In the first attacks, many died, and the
minions of %n managed to steal %o.
They took it to %i and there, none of our
%g warriors have been able to go.
 
"You must find %i, and within it wrest
%o from %n.  She guards it as
jealously as she guards all treasures she attains.  But with it,
we can make our caves safe once more.
 
"Please, %p, recover %o for us, and return it here."`,
        badalign: `"%pC!  You have deviated from my teachings.  You no longer follow
the path of the %a as you should.  I banish you from these caves, to
go forth and purify yourself.  Then, you might be able to accomplish this
quest."`,
        badlevel: `"Alas, %p, you are as yet too inexperienced to embark upon such
a difficult quest as that I propose to give you.
 
"%rA could not possibly survive the rigors demanded to find
%i, never mind to confront %n herself.
 
"Adventure some more, and you will learn the skills you will require.
%d decrees it."`,
        discourage: [
            '"You are weak, %c.  No challenge for the Mother of all Dragons."',
            '"I grow hungry, %r.  You look like a nice appetizer!"',
            '"Join me for lunch?  You\'re the main course, %c."',
            '"With %o, I am invincible!  You cannot succeed."',
            '"Your mentor, %l has failed.  You are nothing to fear."',
            '"You shall die here, %c.  %rA cannot hope to defeat me."',
            '"You, a mere %r challenge the might of %n?  Hah!"',
            '"I am the Mother of all Dragons!  You cannot hope to defeat me."',
            '"My claws are sharp now.  I shall rip you to shreds!"',
            '"%d has deserted you, %c.  This is my domain."',
        ],
        encourage: [
            '"%nC is immune to her own breath weapons. You should use magic upon her that she does not use herself."',
            '"When you encounter %n, call upon %d for assistance."',
            '"There will be nowhere to hide inside %ns inner sanctum."',
            '"Your best chance with %n will be to keep moving."',
            '"Do not be distracted by the great treasures in %ns lair. Concentrate on %o."',
            '"%oC is the only object that %n truly fears."',
            '"Do not be fooled by %ns size.  She is fast, and it is rumored that she uses magic."',
            '"I would send a party of %gP with you, but we will need all of our strength to defend ourselves."',
            '"Remember, be %a at all times.  This is your strength."',
            '"If only we had an amulet of reflection, this would not have happened."',
        ],
        locate_first: `You %x many large claw marks on the ground.  The tunnels ahead
of you are larger than most of those in any cave complex you have
ever been in before.
 
Your nose detects the smell of carrion from within, and bones litter
the sides of the tunnels.`,
        locate_next: 'Once again, you approach %i.',
        nemesis_first: `"So, follower of %l, you seek to invade the lair of
%n.  Only my meals are allowed down here.  Prepare
to be eaten!"`,
        nemesis_next: `"So, again you face me, %c.  No one has ever before escaped me.
Now I shall kill you."`,
        nemesis_other: '"You are getting annoying, %c.  Prepare to die."',
        nemesis_wantsit: '"I\'ll have %o from you, %c.  You shall die."',
        goal_first: `You find yourself in a large cavern, with neatly polished walls, that
nevertheless show signs of being scorched by fire.
 
Bones litter the floor, and there are objects scattered everywhere.
The air is close with the stench of sulphurous fumes.
 
%nC is clearly visible, but %nh seems to be asleep.`,
        goal_next: 'Once again, you find yourself in the lair of %n.',
        posthanks: `"%pC!  Welcome back.
How goes your quest to recover the Amulet for %d?"`,
    },
    Kni: {
        assignquest: `Ah, %p.  Thou art truly ready, as no %c before thee hath
been.  Hear now Our words:
 
"As thou noticed as thou approached %H, a great battle hath
been fought recently in these fields.  Know thou that Merlin himself
came to aid Us here as We battled the foul %n.  In the midst of that
battle, %n struck Merlin a great blow, felling him.  Then, as Our
forces were pressed back, %n stole %o.
 
"We eventually turned the tide, but lost many %cP in doing so.
Merlin was taken off by his apprentice, but hath not recovered.  We have
been told that so long as %n possesseth %o,
Merlin will not regain his health.
 
"We hereby charge thee with this most important of duties:
 
"Go forth from this place, to the fens, and there thou wilt find
%i.  From there, thou must track down %n.  Destroy the
beast, and return to Us %o.  Only then can
We restore Merlin to health.`,
        badalign: `Thou dishonourest Us, %p!  Thou hast strayed from the path of
chivalry! Go from Our presence and do penance.  Only when thou art again
pure mayst thou return hence.`,
        badlevel: `Verily, %p, thou hast done well.  That thou hast survived thus
far is a credit to thy valor, but thou art yet unprepared for
the demands required as Our Champion.  %rA, no matter how
pure, could never hope to defeat the foul %n.
 
"Journey forth from this place, and hone thy skills.  Return to
Our presence when thou hast attained the noble title of %R.`,
        discourage: [
            '"A mere %r can never withstand me!"',
            '"I shall kill thee now, and feast!"',
            '"Puny %c.  What manner of death dost thou wish?"',
            '"First thee, %p, then I shall feast upon %l."',
            '"Hah!  Thou hast failed, %r.  Now thou shalt die."',
            '"Die, %c.  Thou art as nothing against my might."',
            '"I shall suck the marrow from thy bones, %c."',
            `"Let's see...  Baked?  No.  Fried?  Nay.  Broiled?  Yea verily, that is the way I like my %c for dinner."`,
            '"Thy strength waneth, %p.  The time of thy death draweth near."',
            '"Call upon thy precious %d, %p.  It shall not avail thee."',
        ],
        encourage: [
            '"Remember, %p, follow always the path of %d."',
            '"Though %n is verily a mighty foe, We have confidence in thy victory."',
            '"Beware, for %n hath surrounded %niself with hordes of foul creatures."',
            `"Great treasure, 'tis said, is hoarded in the lair of %n."`,
            '"If thou possessest %o, %p, %ns magic shall therewith be thwarted."',
            '"The gates of %i are guarded by forces unseen, %p. Go carefully."',
            '"Return %o to Us quickly, %p."',
            '"Destroy %n, %p, else %H shall surely fall."',
            '"Call upon %d when thou art in need."',
            '"To find %i, thou must keep thy heart pure."',
        ],
        firsttime: `You materialize in the shadows of %H.  Immediately, you notice
that something is wrong.  The fields around the castle are trampled and
withered, as if some great battle has been recently fought.
 
Exploring further, you %x long gouges in the walls of %H.
You know of only one creature that makes those kinds of marks...`,
        goal_first: `As you exit the swamps, you %x before you a huge, gaping hole in the
side of a hill.  From within, you smell the foul stench of carrion.
 
The pools on either side of the entrance are fouled with blood, and
pieces of rusted metal and broken weapons show above the surface.`,
        goal_next: 'Again, you stand at the entrance to %ns lair.',
        leader_first: `Ah, %p.  We see thou hast received Our summons.
We are in dire need of thy prowess.  But first, We must needs
decide if thou art ready for this great undertaking.`,
        leader_last: `Thou disgracest this noble court with thine impure presence.  We have been
lenient with thee, but no more.  Thy name shall be spoken no more.  We
hereby strip thee of thy title, thy lands, and thy standing as %ca.
Begone from Our sight!`,
        leader_next: '"Welcome again, %p.  We hope thou art ready now."',
        leader_other: '"Once again, thou standest before Us, %p.  Art thou ready now?"',
        locate_first: `You stand at the foot of %i.  Atop, you can %x a shrine.
Strange energies seem to be focused here, and the hair on the back of
your neck stands on end.`,
        locate_next: 'Again, you stand at the foot of %i.',
        nemesis_first: `Hah!  Another puny %c seeks death.  I shall dine well tonight,
then tomorrow, %H shall fall!`,
        nemesis_next: '"Again, thou challengest me, %r?  So be it.  Thou wilt die here."',
        nemesis_other: '"Thou art truly foolish, %r.  I shall dispatch thee anon."',
        nemesis_wantsit: `So, thou darest touch MY property!  I shall have that bauble back,
puny %r.  Thou wilt die in agony!`,
        nexttime: 'Once again you stand in the shadows of %H.',
        othertime: `Again, you stand before %H.  You vaguely sense that this
may be the last time you stand before %l.`,
        posthanks: '"Well met, %p.  How goeth thy search for the Amulet of Yendor?"',
    },
    Mon: {
        firsttime: `You find yourself standing in sight of %H.
Something is obviously wrong here.  Strange shapes lumber around
outside %H!
 
You realize that %l needs your assistance!`,
        leader_first: `"Ah, %p, my %S.  You have returned to us at last.
A great blow has befallen our order; perhaps you can help us.
First, however, I must determine if you are prepared for this
great challenge."`,
        leader_next: '"Again, my %S, you stand before me.  Are you ready now to help us?"',
        assignquest: `Yes, %p.  You are truly ready now.  Attend to me and I shall
tell you of what has transpired:
 
"During one of the Great Meditations a short time ago, %n and
a legion of elementals invaded %H.  Many %gP
were killed, including the one bearing %o.
 
Now, there are barely enough %gP left to keep the elementals
at bay.
 
"We need you to find %i, then, from there,
travel to %ns lair.  If you can manage to defeat %n and
return %o here, we can then drive off the legions
of elementals that slay our students.
 
"Go with %d as your guide, %p.`,
        locate_first: `You remember the descriptions of %i, given
to you by %l.  It is ahead that you will find
%n's trail.`,
        locate_next: 'Again, you stand before %i.',
        goal_first: `The stench of brimstone is all about you, and the elementals close in
from all sides!
 
Ahead, there is a small clearing amidst the bubbling pits of lava...`,
        goal_next: 'Again, you have invaded %ns domain.',
        nexttime: 'Once again, you stand before %H.',
    },
    Pri: {
        firsttime: `You find yourself standing in sight of %H.  Something
is obviously wrong here.  The doors to %H, which usually
stand open, are closed.  Strange human shapes shamble around
outside.
 
You realize that %l needs your assistance!`,
        nexttime: 'Once again, you stand before %H.',
        othertime: `Again you face %H.  Your intuition hints that this may be
the final time you come here.`,
        leader_first: `"Ah, %p, my %S.  You have returned to us at last.
A great blow has befallen our order; perhaps you can help us.
First, however, I must determine if you are prepared for this
great challenge."`,
        leader_next: '"Again, my %S, you stand before me.  Are you ready now to help us?"',
        leader_other: '"Once more, %p, you stand within the sanctum.  Are you ready now?"',
        leader_last: `"You are a heretic, %p!  How can you, %ra, deviate so from the
teachings of %d?  Begone from this temple.  You are no longer
%sa to this order.  We will pray to %d for other assistance,
as you have failed us utterly."`,
        assignquest: `"Yes, %p.  You are truly ready now.  Attend to me and I shall
tell you of what has transpired:
 
"At one of the Great Festivals a short time ago, %n and a legion
of undead invaded %H.  Many %gP were killed, including
the one carrying %o.
 
"As a final act of vengefulness, %n desecrated the altar here.
Without it, we could not mount a counter-attack.  Now, there are
barely enough %gP left to keep the undead at bay.
 
"We need you to find %i, then, from there, travel
to %ns lair.  If you can manage to defeat %n and return
%o here, we can then drive off the legions of
undead that befoul the land.
 
"Go with %d as your guide, %p."`,
        badalign: `"This is terrible, %p.  You have deviated from the true path!
You know that %d requires the most strident devotion of this
order.  The %shood must stand for utmost piety.
 
"Go from here, atone for your sins against %d.  Return only when
you have purified yourself."`,
        badlevel: `"Alas, %p, it is not yet to be.  A mere %r could never
withstand the might of %n.  Go forth, again into the world, and return
when you have attained the post of %R."`,
        discourage: [
            '"Submit to my will, %c, and I shall spare you."',
            '"Your puny powers are no match for me, %c."',
            '"I shall have you turned into a zombie for my pleasure!"',
            '"Despair now, %r.  %d cannot help you."',
            '"I shall feast upon your soul for many days, %c."',
            '"Your death will be slow and painful.  That I promise!"',
            '"You cannot defeat %n, you fool.  I shall kill you now."',
            '"Your precious %lt will be my next victim."',
            '"I feel your powers failing you, %r.  You shall die now."',
            '"With %o, nothing can stand in my way."',
        ],
        encourage: [
            '"You can prevail, if you rely on %d."',
            '"Remember that %n has great magic at his command."',
            '"Be pure, my %S."',
            '"Beware, %i is surrounded by a great graveyard."',
            '"You may be able to affect %n with magical cold."',
            '"Acquire and wear %o if you can.  It will aid you against %n."',
            '"Call upon %d when your need is greatest.  You will be answered."',
            '"The undead legions are weakest during the daylight hours."',
            '"Do not lose faith, %p.  If you do so, %n will grow stronger."',
            '"Wear %o.  It will assist you against the undead."',
        ],
        locate_first: `You stand facing a large graveyard.  The sky above is filled with clouds
that seem to get thicker closer to the center.  You sense the presence of
undead in larger numbers than you have ever encountered before.
 
You remember the descriptions of %i, given to you by
%l.  It is ahead that you will find %ns trail.`,
        locate_next: 'Again, you stand before %i.',
        nemesis_first: `"Ah, so %l has sent another %gC to retrieve
%o.
 
"No, I see you are no %gC.  Perhaps I shall have some fun today
after all.  Prepare to die, %r!  You shall never regain
%o."`,
        nemesis_next: '"So, %r.  Again you challenge me."',
        nemesis_other: '"Die now, %r.  %d has no power here to aid you."',
        nemesis_wantsit: '"You shall die, %r, and I will have %o back."',
        goal_first: `The stench of brimstone is all about you, and the shrieks and moans
of tortured souls assault your psyche.
 
Ahead, there is a small clearing amidst the bubbling pits of lava...`,
        goal_next: 'Again, you have invaded %ns domain.',
        posthanks: '"Welcome back, %p.  How is your quest for the Amulet going?"',
    },
    Ran: {
        firsttime: `You arrive in familiar surroundings.  In the distance, you %x the
ancient forest grove, the place of worship to %d.
 
Something is wrong, though.  Surrounding the grove are centaurs!
And they've noticed you!`,
        nexttime: 'Once again, you stand before %H.',
        othertime: `You have the oddest feeling that this may be the last time you
are to enter %H.`,
    },
    Rog: {
        firsttime: `Unexpectedly, you find yourself back in Ransmannsby, where you trained to
be a thief.  Quickly you make the guild sign, hoping that you AND word
of your arrival reach %ls den.`,
        nexttime: `Once again, you find yourself back in Ransmannsby.  Fond memories are
replaced by fear, knowing that %l is waiting for you.`,
        othertime: `You rub your hands through your hair, hoping that the little ones on
the back of your neck stay down, and prepare yourself for your meeting
with %l.`,
        leader_first: `"Well, look who it is boys -- %p has come home.  You seem to have
fallen behind in your dues.  I should kill you as an example to these
other worthless cutpurses, but I have a better plan.  If you are ready
maybe you could work off your back dues by performing a little job for
me.  Let us just see if you are ready..."`,
        leader_next: `"Well, I didn't expect to see you back.  It shows that you are either stupid,
or you are finally ready to accept my offer.  Let us hope for your sake it
isn't stupidity that brings you back."`,
        leader_other: `"Did you perhaps mistake me for some other %lt?  You must
think me as stupid as your behavior.  I warn you not to try my patience."`,
        leader_last: `"Well %gp, it looks like our friend has forgotten who is the boss
around here.  Our friend seems to think that %rp have been put in
charge.  Wrong.  DEAD WRONG!"
 
Your sudden shift in surroundings prevents you from hearing the end
of %ls curse.`,
        assignquest: `"Will everyone not going to retrieve %o from that
jerk, %n, take one step backwards.  Good choice,
%p, because I was going to send you anyway.  My other %gp
are too valuable to me.
 
"Here's the deal.  I want %o, %n
has %o.  You are going to get %o
and bring it back to me.  So simple an assignment even you can understand
it."`,
        badalign: `"Maybe I should chain you to my perch here for a while.  Perhaps watching
real %a men at work will bring some sense back to you.  I don't
think I could stand the sight of you for that long though.  Come back
when you can be trusted to act properly."`,
        badlevel: `"In the time that you've been gone you've only been able to master the
arts of %ra?  I've trained ten times again as many %Rp
in that time.  Maybe I should send one of them, no?  Where would that
leave you, %p?  Oh yeah, I remember, I was going to kill you!"`,
        discourage: [
            '"May I suggest a compromise.  Are you interested in gold or gems?"',
            '"Please don\'t force me to kill you."',
            '"Grim times are upon us all.  Will you not see reason?"',
            '"I knew %l, and you\'re no %lt, thankfully."',
            '"It is a shame that we are not meeting under more pleasant circumstances."',
            '"I was once like you are now, %p.  Believe in me -- our way is better."',
            '"Stay with me, and I will make you %os guardian."',
            '"When you return, with or without %o, %l will have you killed."',
            '"Do not be fooled; I am prepared to kill to defend %o."',
            '"I can reunite you with the Twain.  Oh, the stories you can swap."',
        ],
        encourage: [
            '"You don\'t seem to understand, %o isn\'t here so neither should you be!"',
            '"May %d curse you with lead fingers.  Get going!"',
            '"We don\'t have all year.  GET GOING!"',
            '"How would you like a scar necklace?  I\'m just the jeweler to do it!"',
            '"Lazy S.O.B.  Maybe I should call up someone else..."',
            '"Maybe I should open your skull and see if my instructions are inside?"',
            '"This is not a task you can complete in the afterlife, you know."',
            '"Inside every living person is a dead person trying to get out, and I have your key!"',
            '"We\'re almost out of hell-hound chow, so why don\'t you just get moving!"',
            '"You know, %o isn\'t going to come when you whistle.  You must get it yourself."',
        ],
        locate_first: 'Those damn little hairs tell you that you are nearer to %o.',
        locate_next: 'Not wanting to face %l without having stolen %o, you continue.',
        nemesis_first: '"Ah!  You must be %ls ... er, `hero\'.  A pleasure to meet you."',
        nemesis_next: '"We meet again.  Please reconsider your actions."',
        nemesis_other: `"Surely, %p, you have learned that you cannot trust any bargains
that %l has made.  I can show you how to continue on
your quest without having to run into him again."`,
        nemesis_wantsit: `"Please, think for a moment about what you are doing.  Do you truly
believe that %d would want %l to have
%o?"`,
        goal_first: `You feel a great swelling up of courage, sensing the presence of
%o.  Or is it fear?`,
        goal_next: "The hairs on the back of your neck whisper -- it's fear.",
        posthanks: `"Quite the little thief, aren't we, %p.  Can I interest you in a
swap for %o?  Look around, anything in the keep
is yours for the asking."`,
    },
    Sam: {
        firsttime: `Even before your senses adjust, you recognize the kami of
%H.
 
You %x the standard of your teki, %n, flying above
the town.  How could such a thing have happened?  Why are ninja
wandering freely; where are the samurai of your daimyo, %l?
 
You quickly say a prayer to Izanagi and Izanami and walk towards
town.`,
        nexttime: 'Once again, you are back at %H.',
        othertime: `You are back at %H.
 
Instantly you sense a subtle change in your karma.  You seem to know that
if you do not succeed in your quest, %n will have destroyed
the kami of %H before you return again.`,
        leader_first: `"Ah, %p-san, it is good to see you again.  I need someone who can
lead my samurai against %n.  If you are ready, you will be
that person."`,
        leader_next: `"Once again, %p-san, you kneel before me.  Are you yet capable of
being my vassal?"`,
        leader_other: `"You begin to test my matsu, %p-san.
If you cannot determine what I want in a samurai, how can I rely on you
to figure out what I need from a samurai?"`,
        leader_last: `"You are no longer my samurai, %p.
 
"Hara-kiri is denied.  You are ordered to shave your head and then to
become a monk.  Your fief and family are forfeit.  Wakarimasu ka?"`,
        assignquest: `"Domo %p-san, indeed you are ready.  I can now tell you what
it is that I require of you.
 
"The daimyo, %n, has betrayed us.  He has stolen from us
%o and taken it to his donjon deep within
%i.
 
"If I cannot show the emperor %o when he comes
for the festival he will know that I have failed in my duty, and
request that I commit seppuku.
 
"You must gain entrance to %i and retrieve the
emperor's property.  Be quick!  The emperor will be here for the
cha-no-you in 5 sticks.
 
"Wakarimasu ka?"`,
        badalign: `"%p-san, you would do better to join the kyokaku.
 
"You have skills, but until you can call upon the bushido to know when and
how to use them you are not samurai.  When you can think %a and
act %a then return."`,
        badlevel: `"%p-san, you have learned well and honored your family.
I require the skills of %Ra in order to defeat %n.
Go and seek out teachers.  Learn what they have learned.  When you
are ready, return to me."`,
        discourage: [
            '"Ahh, I finally meet the daimyo of the kyokaku!"',
            '"There is no honor for me in your death."',
            '"You know that I cannot resash my swords until they have killed."',
            '"Your presence only compounds the dishonor of %l in not coming %liself."',
            '"I will make tea with your hair and serve it to %l."',
            '"Your fear shows in your eyes, coward!"',
            '"I have not heard of you, %p-san; has your life been that unworthy?"',
            '"If you will not obey me, you will die."',
            '"Kneel now and make the two cuts of honor.  I will tell your %sp of your honorable death."',
            '"Your master was a poor teacher.  You will pay for his mistakes in your teaching."',
        ],
        encourage: [
            '"To defeat %n you must overcome the seven emotions: hate, adoration, joy, anxiety, anger, grief, and fear."',
            '"Remember your honor is my honor, you perform in my name."',
            '"I will go to the temple and burn incense for your safe return."',
            '"Sayonara."',
            '"There can be honor in defeat, but no gain."',
            '"Your kami must be strong in order to succeed."',
            '"You are indeed a worthy %R, but now you must be a worthy samurai."',
            '"If you fail, %n will be like a tai-fun on the land."',
            '"If you are truly %a, %d will listen."',
            '"Sharpen your swords and your wits for the task before you."',
        ],
        locate_first: `You instinctively reach for your swords.  You do not recognize the
lay of this land, but you know that your teki are everywhere.`,
        locate_next: `Thankful that your %sp at %H cannot see
your fear, you prepare again to advance.`,
        nemesis_first: `"Ah, so it is to be you, %p-san.  I offer you seppuku.
I will be your second if you wish."`,
        nemesis_next: `"I have offered you the honorable exit.  Now I will have your
head to send unwashed to %l."`,
        nemesis_other: '"After I have dispatched you, I will curse your kami."',
        nemesis_wantsit: `"You have fought my samurai; surely you must know that you
will not be able to take %o back to
%H."`,
        goal_first: `In your mind, you hear the taunts of %n.
 
You become like the rice plant and bend to the ground, offering a
prayer to %d.  But when the wind has passed, you stand
proudly again.  Putting your kami in the hands of fate, you advance.`,
        goal_next: `As you arrive once again at the home of %n, your thoughts
turn only to %o.`,
        goal_alt: 'As you arrive once again at the home of %n.',
        posthanks: '%lC bows.  "%p-sama, tell us of your search for the Amulet."',
    },
    Tou: {
        firsttime: `You breathe a sigh of relief as you find yourself back in the familiar
surroundings of %H.
 
You quickly notice that things do not appear the way they did when you
left.  The town is dark and quiet.  There are no sounds coming from
behind the town walls, and no campfires burning in the fields.  As a
matter of fact, you do not %x any movement in the fields at all, and
the crops seem as though they have been untended for many weeks.`,
        nexttime: 'Once again, you are back at %H.',
        othertime: `You are back at %H.
Things appear to have become so bad that you fear that soon
%H will not be here to return to.`,
        leader_first: `"Is it really you, %p!  I had given up hope for your return.
As you can %x, we are desperately in need of your talents.  Someone must
defeat %n if our town is to become what it once was.
 
"Let me see if you are ready to be that someone."`,
        leader_next: '"Things are getting worse, %p.  I hope that this time you are ready."',
        leader_other: '"I hope that for the sake of %H you have prepared yourself this time."',
        leader_last: `"It is too late, %p.  You are not even worthy to die amongst us.
Leave %H and never return."`,
        assignquest: `"You have indeed proven yourself a worthy %c, %p.
 
"But now your kinfolk and I must ask you to put aside your travels and
help us in our time of need.  After you left us we elected a new mayor,
%n.  He proved to be a most heinous and vile creature.
 
"Soon after taking office he absconded with %o
and fled town, leaving behind his henchmen to rule over us.  In order
for us to regain control of our town, you must enter %i
and recover %o.
 
"Do not be distracted on your quest.  If you do not return quickly I fear
that all will be lost.  Let us both pray now that %d will guide you
and keep you safe."`,
        badalign: `"It would be an affront to %d to have one not true to the
%a path undertake her bidding.
 
"You must not return to us until you have purified yourself of these
bad influences on your actions.  Remember, only by following the %a
path can you hope to overcome the obstacles you will face."`,
        badlevel: `"There is still too much that you have to learn before you can undertake
the next step.  Return to us as a proven %R, and perhaps then
you will be ready.
 
"Go back now, and may the teachings of %d serve you well."`,
        discourage: [
            '"I defeated %l and I will defeat you, %p."',
            '"Where is %d now!  You must realize no one can help you here."',
            '"Beg for mercy now and I may be lenient on you."',
            '"If you were not so %a, you might have stood a chance."',
            '"Vengeance is mine at last, %p."',
            '"I only wish that %l had a more worthy %r to send against me."',
            '"With %o in my possession you cannot hope to defeat me."',
            '"%nC has never been defeated, NEVER!"',
            '"Are you truly the best %H has to send against me?  I pity %l."',
            '"How do you spell %p?  I want to ensure the marker on your grave is correct as a warning to your %sp."',
        ],
        encourage: [
            '"Do not be fooled by the false promises of %n."',
            '"To enter %i you must pass many traps."',
            '"If you do not return with %o, your quest will be in vain."',
            '"Do not be afraid to call upon %d if you truly need help."',
            '"If you do not destroy %n, he will follow you back here!"',
            '"Take %o from %n and you may be able to defeat him."',
            '"You must hurry, %p!"',
            '"You are like %Sa to me, %p.  Do not let me down."',
            '"If you are %a at all times you may succeed, %p."',
            '"Let all who meet you on your journey know that you are on a quest for %l and grant safe passage."',
        ],
        locate_first: `Only your faith in %d keeps you from trembling.  You %x
the handiwork of %ns henchlings everywhere.`,
        locate_next: 'You know that this time you must find and destroy %n.',
        nemesis_first: `"So, %p, %l thinks that you can wrest
%o from me!
 
"It only proves how desperate he has become that he sends %ra to
try to defeat me.  When this day is over, I will have you enslaved
in the mines where you will rue the day that you ever entered
%i."`,
        nemesis_next: `"I let you live the last time because it gave me pleasure.
This time I will destroy you, %p."`,
        nemesis_other: `"These meetings come to bore me.  You disturb my workings with
%o.
 
"If you do not run away now, I will inflict so much suffering on you that
%l will feel guilty for ever having sent his %S to me!"`,
        nemesis_wantsit: `"You fool.  You do not know how to call upon the powers of
%o.
 
"Return it to me and I will teach you how to use it, and together we
will rule %H.  But do so now, as my patience grows thin."`,
        goal_first: 'You sense the presence of %o.',
        goal_next: `You gain confidence, knowing that you may soon be united with
%o.`,
        goal_alt: 'You have returned to %ns lair.',
        posthanks: `"I could not be more proud than if you were my own %S, %p!
Tell me of your adventures in quest of the Amulet of Yendor."`,
    },
    Val: {
        firsttime: `You materialize at the base of a snowy hill.  Atop the hill sits
a place you know well, %H.  You immediately realize
that something here is very wrong!
 
In places, the snow and ice have been melted into steaming pools of
water.  Fumaroles and pools of bubbling lava surround the hill.
The stench of sulphur is carried through the air, and you %x creatures
that should not be able to live in this environment moving towards you.`,
        nexttime: 'Once again, you are near the abode of %l.',
        othertime: `Again you materialize near %ls abode.  You have a nagging feeling
that this may be the last time you come here.`,
        leader_first: `"Ah, %p, my %S.  You have returned to %H
at last.  We are in dire need of your aid, but I must determine if you
are yet ready for such an undertaking.
 
"Let me read your fate..."`,
        leader_next: `"Let me read the future for you now, %p, perhaps you have managed to
change it enough..."`,
        leader_other: `"Again, I shall read your fate, my %S.  Let us both hope that you have
made changes to become ready for this task..."`,
        leader_last: `"No, %p.  Your fate is sealed.  I must cast about for another
champion.  Begone from my presence, and never return.  Know this, that
you shall never succeed in this life, and Valhalla is denied to you."`,
        assignquest: `"It is not clear, %p, for my sight is limited without our relic.
But it is now likely that you can defeat %n, and recover
%o.
 
"A short time ago, %n and his minions attacked this place.  They
opened the huge volcanic vents you %x about the hill, and attacked.  I knew
that this was to come to pass, and had asked %d for a group of %gP
to help defend this place.  The few you %x here are the mightiest of
Valhalla's own, and are all that are left of one hundred %d sent.
 
"Despite the great and glorious battle we fought, %n managed at
last to steal %o.  This has upset the balance of the universe,
and unless %oh is returned into my care, %n may start Ragnarok.
 
"You must find the entrance to %i.  Travel downward
from there and you will find %ns lair.  Defeat him and
return %o to me."`,
        badalign: `"NO!  This is terrible.  I see you becoming an ally of %n, and
leading his armies in the final great battles.  This must not come to
pass!  You have strayed from the %a path.  You must purge yourself,
and return here only when you have regained a state of purity."`,
        badlevel: `"I see you and %n fighting, %p.  But you are not prepared and
shall die at %ns hand if you proceed.  No.  This will not do.
Go back out into the world, and grow more experienced at the ways of war.
Only when you have returned %Ra will you be able to defeat %n."`,
        discourage: [
            '"I am your death, %c."',
            '"You cannot prevail, %r.  I have foreseen your every move."',
            '"With you out of the way, Valhalla will be mine for the taking."',
            '"I killed scores of %ds best when I took %o. Do you really think that one %c can stand against me?"',
            '"Who bears the souls of %cPs to Valhalla, %r?"',
            '"No, %d cannot help you here."',
            '"Some instrument of %d you are, %p.  You are a weakling!"',
            '"Never have I seen %ca so clumsy in battle."',
            '"You die now, little %s."',
            '"Your body I destroy now, your soul when my hordes overrun Valhalla!"',
        ],
        encourage: [
            '"Go with the blessings of %d."',
            '"Call upon %d when you are in need."',
            '"Use %o if you can.  It will protect you."',
            '"Magical cold is very effective against %n."',
            '"To face %n, you will need to be immune to fire."',
            '"May %d strengthen your sword-arm."',
            '"Trust in %d.  He will not desert you."',
            '"It becomes more likely that Ragnarok will come with every passing moment. You must hurry, %p."',
            '"If %n can master %o, he will be powerful enough to face %d far earlier than is fated.  This must not be!"',
            '"Remember your training, %p.  You can succeed."',
        ],
        locate_first: `The ice and snow gives way to a valley floor.  You %x ahead of you
a huge round hill surrounded by pools of lava.  This then is the entrance
to %i.  It looks like you're not going to get in without
a fight though.`,
        locate_next: 'Once again, you stand before the entrance to %i.',
        nemesis_first: `"So!  %lC has finally sent %ca to challenge me!
 
"I thought that mastering %o would enable me to challenge
%d, but it has shown me that first I must kill you!  So come, little
%s.  Once I defeat you, I can at last begin the final battle with %d."`,
        nemesis_next: '"Again you challenge me, %r.  Good.  I will kill you now."',
        nemesis_other: '"Have you not learned yet?  You cannot defeat %n!"',
        nemesis_wantsit: '"I will kill you, %c, and wrest %o from your mangled hands."',
        goal_first: `Through clouds of sulphurous gasses, you %x a rock palisade
surrounded with a moat of bubbling lava.  You remember the description
from something that %l said.  This is the lair of %n.`,
        goal_next: 'Once again, you stand in sight of %ns lair.',
        posthanks: `"Greetings, %p.  I have not been able to pay as much attention to
your search for the Amulet as I have wished.  How do you fare?"`,
    },
    Wiz: {
        firsttime: `You are suddenly in familiar surroundings.  You notice what appears to
be a large, squat stone structure nearby.  Wait!  That looks like the
tower of your former teacher, %l.
 
However, things are not the same as when you were last here.  Mists and
areas of unexplained darkness surround the tower.  There is movement in
the shadows.
 
Your teacher would never allow such unaesthetic forms to surround the
tower...  unless something were dreadfully wrong!`,
    },
};
 
// C ref data: dat/quest.lua synopsis entries.
const QUEST_SYNOPSIS = {
    common: {
        firsttime: '[%dC has chosen you to recover the Amulet of Yendor for %dI.]',
        banished: {
            synopsis: `[You are banished from %H for betraying your allegiance to %d.]`,
            output: 'text',
            text: `"You have betrayed all those who hold allegiance to %d, as you once did.\nMy allegiance to %d holds fast and I cannot condone or accept what you\nhave done.\n\nLeave this place.  You shall never set foot at %H again.\nThat which you seek is now lost forever, for without the Bell of Opening,\nyou will never be able to enter the place where he who has the Amulet\nresides.\n\nGo now!  You are banished from this place.`,
        },
        legacy: {
            synopsis: `[%dC has chosen you to recover the Amulet of Yendor for %dI.]`,
            output: 'menu',
            text: `It is written in the Book of %d:\n\n    After the Creation, the cruel god Moloch rebelled\n    against the authority of Marduk the Creator.\n    Moloch stole from Marduk the most powerful of all\n    the artifacts of the gods, the Amulet of Yendor,\n    and he hid it in the dark cavities of Gehennom, the\n    Under World, where he now lurks, and bides his time.\n\nYour %G %d seeks to possess the Amulet, and with it\nto gain deserved ascendance over the other gods.\n\nYou, a newly trained %r, have been heralded\nfrom birth as the instrument of %d.  You are destined\nto recover the Amulet for your deity, or die in the\nattempt.  Your hour of destiny has come.  For the sake\nof us all:  Go bravely with %d!`,
        },
        pauper_legacy: {
            synopsis: `[%dC has chosen you to recover the Amulet of Yendor for %dI.]`,
            output: 'menu',
            text: `It is written in the Book of %d:\n\n    After the Creation, the cruel god Moloch rebelled\n    against the authority of Marduk the Creator.\n    Moloch stole from Marduk the most powerful of all\n    the artifacts of the gods, the Amulet of Yendor,\n    and he hid it in the dark cavities of Gehennom, the\n    Under World, where he now lurks, and bides his time.\n\nYour %G %d seeks to possess the Amulet, and with it\nto gain deserved ascendance over the other gods.\n\nYou, an untrained %r, have been unable to adequately\nprepare for the recovery of the Amulet.  Nevertheless,\nyou feel ready to take on this demanding quest.  For the\nsake of us all:  Go bravely with %d!`,
        },
        quest_portal: {
            output: 'pline',
            text: `You receive a faint telepathic message from %l:\nYour help is urgently needed at %H!\nLook for a ...ic transporter.\nYou couldn't quite make out that last message.`,
        },
        quest_portal_again: {
            text: `You again sense %l pleading for help.`,
        },
    },
    Hea: {
        assignquest: '[Travel to %i on your way to recover %o from %n.]',
        firsttime: '[You arrive back at %H and must find %l.]',
        leader_first: '[%l is weak from the struggle with %n.  %lH wants to examine you.]',
        locate_first: '[You have reached %i but all is not well.]',
        goal_first: '[You have reached the lair of %n.  Take %o away from %ni.]',
    },
};
 
function expand_quest_text(text) {
    if (!text) return '';
    // C ref: questpgr.c convert_arg()/convert_line().
    const u = game.u || {};
    const cap = (s) => (s ? (s.charAt(0).toUpperCase() + s.slice(1)) : '');
    const stripThe = (s) => (s && /^the /i.test(s) ? s.slice(4) : s);
    const questArti = withThe(artiname(game.urole?.questarti ?? 0));
    const questArtiShort = (() => {
        const ofIdx = questArti.toLowerCase().indexOf(' of ');
        return ofIdx >= 0 ? questArti.slice(0, ofIdx) : questArti;
    })();
    const roleName = (game.flags?.female && game.urole?.name?.f)
        ? game.urole.name.f
        : (game.urole?.name?.m || 'adventurer');
    const alignName = (algn) => {
        if (algn === 0) return 'lawful';
        if (algn === 1) return 'neutral';
        if (algn === 2) return 'chaotic';
        return 'unaligned';
    };
 
    const convertArg = (code) => {
        switch (code) {
        case 'p': return game.plname || 'player';
        case 'c': return roleName;
        case 'r': return rank_of(u.ulevel ?? 1, game.urole?.mnum ?? 0, !!game.flags?.female);
        case 'R': return rank_of(MIN_QUEST_LEVEL, game.urole?.mnum ?? 0, !!game.flags?.female);
        case 's': return game.flags?.female ? 'sister' : 'brother';
        case 'S': return game.flags?.female ? 'daughter' : 'son';
        case 'l': return ldrname();
        case 'i': return intermed();
        case 'O': return questArtiShort;
        case 'o': return questArti;
        case 'n': return neminame();
        case 'g': return guardname();
        case 'G': return align_gtitle(u.ualignbase?.[0] ?? u.ualign?.type ?? 0);
        case 'H': return homebase();
        case 'a': return alignName(u.ualignbase?.[0] ?? u.ualign?.type ?? 0);
        case 'A': return alignName(u.ualign?.type ?? 0);
        case 'd': return align_gname(u.ualignbase?.[0] ?? u.ualign?.type ?? 0);
        case 'D': return align_gname(0);
        case 'C': return 'chaotic';
        case 'N': return 'neutral';
        case 'L': return 'lawful';
        case 'x': return u.blind ? 'sense' : 'see';
        case 'Z': return game?.dungeons?.[0]?.dname || '';
        case '%': return '%';
        default: return '';
        }
    };
 
    const pronounFor = (who, which) => {
        // C uses quest_status genders; current JS quest data assumes male
        // for deity/leader/nemesis and neuter for quest artifact.
        const isArtifact = who === 'o';
        if (which === 'h') return isArtifact ? 'it' : 'he';
        if (which === 'i') return isArtifact ? 'it' : 'him';
        return isArtifact ? 'its' : 'his';
    };
 
    const out = [];
    const src = String(text);
    for (let i = 0; i < src.length; i++) {
        const ch = src[i];
        if (ch !== '%' || i + 1 >= src.length) {
            out.push(ch);
            continue;
        }
 
        const base = src[i + 1];
        let cvt = convertArg(base);
        i += 1;
 
        const mod = src[i + 1];
        if (mod) {
            let consumed = true;
            switch (mod) {
            case 'A':
                cvt = cap(withAn(cvt));
                break;
            case 'a':
                cvt = withAn(cvt);
                break;
            case 'C':
                cvt = cap(cvt);
                break;
            case 'h': case 'H':
            case 'i': case 'I':
            case 'j': case 'J':
                if ('dlno'.includes(base.toLowerCase())) {
                    cvt = pronounFor(base.toLowerCase(), mod.toLowerCase());
                    if (mod === mod.toUpperCase()) cvt = cap(cvt);
                } else {
                    consumed = false;
                }
                break;
            case 'P':
                cvt = cap(makeplural(cvt));
                break;
            case 'p':
                cvt = makeplural(cvt);
                break;
            case 'S':
                cvt = cap(s_suffix(cvt));
                break;
            case 's':
                cvt = s_suffix(cvt);
                break;
            case 't':
                cvt = stripThe(cvt);
                break;
            default:
                consumed = false;
                break;
            }
            if (consumed) i += 1;
        }
 
        out.push(cvt);
    }
    return out.join('');
}
 
async function display_quest_text_window(lines) {
    const display = game?.nhDisplay || null;
    const textWin = tty_create_nhwindow(NHW_TEXT);
    if (game.wins[textWin]) game.wins[textWin].active = true;
 
    // C ref: tty_display_nhwindow(WIN_MESSAGE) before text-window display.
    // This consumes a pending message-space dismiss before the text window's
    // own xwaitforspace loop begins.
    if (display && display.toplin === TOPLINE_NEED_MORE) {
        await more(display);
        // C path (tty_display_nhwindow WIN_MESSAGE): more() then
        // tty_clear_nhwindow(WIN_MESSAGE), which emits tty_clear_msg/toplin.
        display.toplin = TOPLINE_NEED_MORE;
        await tty_clear_nhwindow('message');
    }
 
    if (display) {
        const rows = display.rows || 24;
        const cols = display.cols || 80;
        for (let r = 0; r < rows; r++) display.clearRow(r);
        for (let i = 0; i < lines.length && i < rows - 1; i++) {
            display.putstr(0, i, String(lines[i] || '').slice(0, cols));
        }
        const endLine = rows - 1;
        const endStr = '--More--';
        display.putstr(0, endLine, endStr);
        if (typeof display.setCursor === 'function') {
            display.setCursor(endStr.length, endLine);
        }
    }
    game._menuActive = true;
 
    enterModal('quest-text-window');
    try {
        while (true) {
            const ch = await nhgetch();
            if (ch === 32 || ch === 13 || ch === 10 || ch === 27) break;
        }
    } finally {
        exitModal('quest-text-window');
    }
 
    tty_dismiss_nhwindow(textWin);
    erase_menu_or_text(textWin, 0, lines.length);
    if (textWin >= 0 && game.wins[textWin]) game.wins[textWin] = null;
    game._menuActive = false;
    // C ref: after text window dismiss, docrt() repaints the map.
    await cls();
    setBotlx('docrt_flags');
    await docrt(false, true);
    await flush_screen(1);
}
 
// C ref: questpgr.c:467 com_pager_core — Lua-dependent, simplified stub
async function com_pager_core(section, msgid, showerror, rawtext, consumeLuaInitRng = true) {
    const BUFSZ = 256; // C ref: BUFSZ buffer threshold for pager fallback.
    const HOW_PLINE = 'pline';
    const HOW_WINDOW = 'window';
    const HOW_TEXT = 'text';
    const HOW_MENU = 'menu';
    const HOW_DEFAULT = 'default';
 
    void section;
 
    if (consumeLuaInitRng) {
        // C ref: questpgr.c com_pager_core() creates a fresh Lua state
        // (nhl_init -> nhlib.lua) for EVERY pager fetch; that consumes the
        // align[] shuffle RNG pair at load time.
        rn2(3);
        rn2(2);
    }
 
    const sectionText = QUEST_TEXT[section] || null;
    const entry = sectionText?.[msgid] ?? null;
    let text = null;
    let output = HOW_DEFAULT;
    let synopsisTemplate = null;
 
    if (typeof entry === 'string') {
        text = entry;
    } else if (Array.isArray(entry)) {
        if (entry.length > 0) text = entry[rn2(entry.length)];
    } else if (entry && typeof entry === 'object') {
        text = typeof entry.text === 'string' ? entry.text : null;
        if (typeof entry.output === 'string') output = entry.output;
        if (typeof entry.synopsis === 'string') synopsisTemplate = entry.synopsis;
    }
 
    if (!text) return false;
    if (rawtext) {
        rawtext.value = text;
        return true;
    }
 
    const expanded = expand_quest_text(text);
    // C ref: questpgr.c default output mode toggles to window when text has
    // embedded newlines or is too long for a safe single pline buffer.
    if (output === HOW_DEFAULT && (expanded.includes('\n') || expanded.length >= (BUFSZ - 1))) {
        output = HOW_TEXT;
    }
 
    if (output === HOW_PLINE || output === HOW_DEFAULT) {
        await deliver_by_pline(expanded);
    } else if (output === HOW_WINDOW || output === HOW_TEXT || output === HOW_MENU) {
        await display_quest_text_window(expanded.split('\n'));
    } else {
        await deliver_by_pline(expanded);
    }
 
    // C ref: questpgr.c:597-609 — put synopsis into message history for ^P recall
    const roleSynopsis = QUEST_SYNOPSIS[section] || null;
    const commonSynopsis = QUEST_SYNOPSIS.common || null;
    if (!synopsisTemplate)
        synopsisTemplate = roleSynopsis?.[msgid] || commonSynopsis?.[msgid] || null;
    if (synopsisTemplate) {
        const synopsis = expand_quest_text(synopsisTemplate);
        putmsghistory(synopsis);
    }
 
    // Keep qt_pager() from issuing an extra fallback lookup pass.
    return true;
}
 
// C ref: questpgr.c:623 com_pager
export async function com_pager(msgid) {
    await com_pager_core('common', msgid, true, null);
}
 
// C ref: questpgr.c:629 qt_pager
export async function qt_pager(msgid) {
    const urole = game.urole;
    if (!await com_pager_core(urole?.filecode ?? '', msgid, false, null, true))
        await com_pager_core('common', msgid, true, null, false);
}
 
// C ref: questpgr.c:636 qt_montype
export function qt_montype() {
    const urole = game.urole;
    if (rn2(5)) {
        const qpm = urole?.enemy1num ?? NON_PM;
        if (qpm !== NON_PM && rn2(5)
            && !((game.mvitals?.[qpm]?.mvflags ?? 0) & G_GENOD))
            return mons[qpm];
        return mkclass(urole?.enemy1sym ?? 0, 0);
    }
    const qpm = urole?.enemy2num ?? NON_PM;
    if (qpm !== NON_PM && rn2(5)
        && !((game.mvitals?.[qpm]?.mvflags ?? 0) & G_GENOD))
        return mons[qpm];
    return mkclass(urole?.enemy2sym ?? 0, 0);
}
 
// C ref: questpgr.c:653 deliver_splev_message
export async function deliver_splev_message() {
    if (game.lev_message) {
        await deliver_by_pline(game.lev_message);
        game.lev_message = null;
    }
}