1 /* omega copyright (C) by Laurence Raphael Brothers, 1987,1988,1989 */
2 /* spell.c */
3 /* functions having to do with spellcasting */
4
5 #include "glob.h"
6
7
s_wish()8 void s_wish()
9 {
10 if (random_range(100) > Player.iq+Player.pow+Player.level) {
11 mprint("Your concentration is flawed!");
12 mprint("The spell energy backfires!");
13 p_damage(random_range(Spells[S_WISH].powerdrain),
14 UNSTOPPABLE,
15 "a backfired wish spell");
16 }
17 else {
18 wish(0);
19 if (Spells[S_WISH].known) {
20 mprint("The power of the spell is too much for you to withstand!");
21 mprint("All memory of the spell is expunged from your brain.");
22 Spells[S_WISH].known = FALSE;
23 }
24 }
25 }
26
s_firebolt()27 void s_firebolt()
28 {
29 int x=Player.x,y=Player.y;
30 setspot(&x,&y);
31 fbolt(Player.x,Player.y,x,y,Player.dex*2+Player.level,Player.level*10+10);
32 }
33
s_missile()34 void s_missile()
35 {
36 int x=Player.x,y=Player.y;
37 setspot(&x,&y);
38 nbolt(Player.x,Player.y,x,y,Player.dex*2+Player.level,Player.level*3+3);
39 }
40
s_teleport()41 void s_teleport()
42 {
43 p_teleport(0);
44 }
45
s_disrupt()46 void s_disrupt()
47 {
48 int x=Player.x,y=Player.y;
49 setspot(&x,&y);
50 disrupt(x,y,Player.level*10+25);
51 }
52
53
s_disintegrate()54 void s_disintegrate()
55 {
56 int x=Player.x,y=Player.y;
57 setspot(&x,&y);
58 disintegrate(x,y);
59 }
60
61
s_sleep()62 void s_sleep()
63 {
64 sleep_monster(0);
65 }
66
s_heal()67 void s_heal()
68 {
69 heal(3);
70 }
71
s_dispel()72 void s_dispel()
73 {
74 dispel((Player.level+Player.maxpow)/10);
75 }
76
s_breathe()77 void s_breathe()
78 {
79 breathe(0);
80 }
81
s_invisible()82 void s_invisible()
83 {
84 invisible(0);
85 }
86
87
s_warp()88 void s_warp()
89 {
90 warp(1);
91 }
92
s_enchant()93 void s_enchant()
94 {
95 enchant(1);
96 }
97
98
s_bless()99 void s_bless()
100 {
101 bless(0);
102 }
103
104
s_restore()105 void s_restore()
106 {
107 recover_stat(0);
108 }
109
110
s_cure()111 void s_cure()
112 {
113 cure(0);
114 }
115
116
s_truesight()117 void s_truesight()
118 {
119 truesight(0);
120 }
121
122
s_hellfire()123 void s_hellfire()
124 {
125 int x=Player.x,y=Player.y;
126 setspot(&x,&y);
127 hellfire(x,y,0);
128 }
129
130
s_knowledge()131 void s_knowledge()
132 {
133 knowledge(0);
134 }
135
136
s_hero()137 void s_hero()
138 {
139 hero(0);
140 }
141
142 /* spell takes longer and longer to work deeper into dungeon */
s_return()143 void s_return()
144 {
145 mprint("You hear a whine as your spell begins to charge up.");
146 Player.status[RETURNING] =
147 ((Current_Environment == Current_Dungeon) ? difficulty() : 1);
148 }
149
s_desecrate()150 void s_desecrate()
151 {
152 sanctify(-1);
153 }
154
155
s_haste()156 void s_haste()
157 {
158 haste(0);
159 }
160
161
s_summon()162 void s_summon()
163 {
164 summon(0,-1);
165 }
166
167
s_sanctuary()168 void s_sanctuary()
169 {
170 sanctuary();
171 }
172
s_sanctify()173 void s_sanctify()
174 {
175 sanctify(1);
176 }
177
178
s_accuracy()179 void s_accuracy()
180 {
181 accuracy(0);
182 }
183
s_fear()184 void s_fear()
185 {
186 int x = Player.x,y=Player.y;
187 setspot(&x,&y);
188 inflict_fear(x,y);
189 }
190
191
192 /* Has all kinds of effects in different circumstances.
193 Eventually will be more interesting */
s_ritual()194 void s_ritual()
195 {
196 pob symbol;
197 int i,roomno;
198 int x,y;
199
200 mprint("You begin your ritual....");
201 mprint("You enter a deep trance. Time Passes...");
202 setgamestatus(SKIP_PLAYER);
203 time_clock(FALSE);
204 setgamestatus(SKIP_PLAYER);
205 time_clock(FALSE);
206 setgamestatus(SKIP_PLAYER);
207 time_clock(FALSE);
208 setgamestatus(SKIP_PLAYER);
209 time_clock(FALSE);
210 setgamestatus(SKIP_PLAYER);
211 time_clock(FALSE);
212 if (RitualHour == hour())
213 mprint("Your mental fatigue prevents from completing the ritual!");
214 else if (random_range(100) > Player.iq+Player.pow+Player.level)
215 mprint("Your concentration was broken -- the ritual fails!");
216 else {
217 mprint("You charge the ritual with magical energy and focus your will.");
218 mprint("Time Passes...");
219 setgamestatus(SKIP_PLAYER);
220 time_clock(FALSE);
221 setgamestatus(SKIP_PLAYER);
222 time_clock(FALSE);
223 setgamestatus(SKIP_PLAYER);
224 time_clock(FALSE);
225 setgamestatus(SKIP_PLAYER);
226 time_clock(FALSE);
227 setgamestatus(SKIP_PLAYER);
228 time_clock(FALSE);
229 RitualHour = hour();
230 /* set of random conditions for different ritual effects */
231 if (Current_Environment == E_CITY) {
232 mprint("Flowing waves of mystical light congeal all around you.");
233 mprint("'Like wow, man! Colors!'");
234 mprint("Appreciative citizens throw you spare change.");
235 Player.cash +=random_range(50);
236 }
237 else if ((roomno=Level->site[Player.x][Player.y].roomnumber) >= 0) {
238 if (RitualRoom == roomno)
239 mprint("For some reason the ritual doesn't work this time...");
240 else {
241 RitualRoom = roomno;
242 switch (RitualRoom) {
243 case ROOMBASE+9: /* ransacked treasure chamber */
244 mprint("Your spell sets off frenetic growth all around you!");
245 for(i=0;i<8;i++){
246 Level->site[Player.x+Dirs[0][i]][Player.y+Dirs[1][i]].locchar =
247 HEDGE;
248 Level->site[Player.x+Dirs[0][i]][Player.y+Dirs[1][i]].p_locf =
249 L_TRIFID;
250 lset(Player.x+Dirs[0][i], Player.y+Dirs[1][i], CHANGED);
251 }
252 break;
253 case ROOMBASE+13: /* harem */
254 case ROOMBASE+22: /* boudoir */
255 mprint("A secret panel opens next to the bed....");
256 if (random_range(2))
257 summon(0,INCUBUS); /* succubus/incubus */
258 else summon(0,SATYR); /* satyr/nymph */
259 break;
260 case ROOMBASE+26: /*shrine to high magic */
261 mprint("A storm of mana coaelesces around you.");
262 mprint("You are buffeted by bursts of random magic.");
263 p_damage(random_range(Player.pow),UNSTOPPABLE,"high magic");
264 mprint("Continue ritual? Could be dangerous.... [yn] ");
265 if (ynq()=='y') s_wish();
266 else mprint("The mana fades away to nothingness.");
267 x = Player.x;
268 y = Player.y;
269 while (x >= 0 && Level->site[x - 1][y].roomnumber == ROOMBASE+26)
270 x--;
271 while (y >= 0 && Level->site[x][y - 1].roomnumber == ROOMBASE+26)
272 y--;
273 for (i = 0; Level->site[x][y].roomnumber == ROOMBASE+26;) {
274 Level->site[x][y].roomnumber = RS_ZORCH;
275 x++;
276 i++;
277 if (Level->site[x][y].roomnumber != ROOMBASE+26) {
278 x -= i;
279 i = 0;
280 y++;
281 }
282 }
283 lset(Player.x, Player.y, CHANGED);
284 break;
285 case ROOMBASE+27: /* magician's lab */
286 mprint("Your magical activity sets off a latent spell in the lab!");
287 cast_spell(random_range(NUMSPELLS));
288 break;
289 case ROOMBASE+28: /* pentagram room */
290 mprint("A smoky form begins to coalesce....");
291 summon(-1,-1);
292 mprint("Fortunately, it seems confined to the pentagram.");
293 m_status_reset(Level->mlist->m,MOBILE);
294 break;
295 case ROOMBASE+29: /* blue omega room */
296 mprint("The Lords of Destiny look upon you....");
297 if (Player.level > 10) {
298 mprint("A curtain of blue flames leaps up from the omega.");
299 morewait();
300 l_adept();
301 }
302 else {
303 if (Player.patron == DESTINY) {
304 mprint("Your patrons take pity on you.");
305 if ((Player.rank[PRIESTHOOD]<SPRIEST) &&
306 (! find_item(&symbol,ARTIFACTID+19,-1))) {
307 symbol = ((pob) checkmalloc(sizeof(objtype)));
308 *symbol = Objects[ARTIFACTID+19];
309 symbol->known = 2;
310 symbol->charge = 17;
311 gain_item(symbol);
312 mprint("You feel uplifted.");
313 }
314 else gain_experience(min(1000,Player.xp));
315 }
316 else if (random_range(3)==1) {
317 mprint("You feel Fated.");
318 gain_experience(Player.level*Player.level*10);
319 Player.hp = max(Player.hp, Player.maxhp);
320 }
321 else if (random_range(2)) {
322 mprint("You feel Doomed.");
323 Player.hp = 1;
324 Player.mana = 0;
325 Player.xp = 0;
326 }
327 else mprint("The Lords of Destiny laugh at you!");
328 }
329 break;
330 default:
331 mprint("Well, not much effect. Chalk it up to experience.");
332 gain_experience(Player.level*5);
333 break;
334 }
335 }
336 }
337 else {
338 if (RitualRoom == Level->site[Player.x][Player.y].roomnumber)
339 mprint("The ritual fails for some unexplainable reason.");
340 else {
341 mprint("The ritual seems to be generating some spell effect.");
342 RitualRoom = Level->site[Player.x][Player.y].roomnumber;
343 switch (RitualRoom) {
344 case RS_WALLSPACE:
345 shadowform();
346 break;
347 case RS_CORRIDOR:
348 haste(0);
349 break;
350 case RS_PONDS:
351 breathe(0);
352 break;
353 case RS_ADEPT:
354 hero(1);
355 break;
356 default:
357 mprint("The ritual doesn't seem to produce any tangible results...");
358 gain_experience(Player.level*6);
359 }
360 }
361 }
362 }
363 }
364
365
366
s_apport()367 void s_apport()
368 {
369 apport(0);
370 }
371
s_shadowform()372 void s_shadowform()
373 {
374 shadowform();
375 }
376
s_alert()377 void s_alert()
378 {
379 alert(0);
380 }
381
s_regenerate()382 void s_regenerate()
383 {
384 regenerate(0);
385 }
386
s_clairvoyance()387 void s_clairvoyance()
388 {
389 clairvoyance(10);
390 }
391
s_drain()392 void s_drain()
393 {
394 drain(0);
395 }
396
s_levitate()397 void s_levitate()
398 {
399 levitate(0);
400 }
401
s_polymorph()402 void s_polymorph()
403 {
404 polymorph(0);
405 }
406
407
408 /* lball spell */
s_lball()409 void s_lball()
410 {
411 int x=Player.x,y=Player.y;
412 setspot(&x,&y);
413 lball(Player.x,Player.y,x,y,Player.level*10+10);
414 }
415
s_identify()416 void s_identify()
417 {
418 identify(0);
419 }
420
s_objdet()421 void s_objdet()
422 {
423 objdet(1);
424 }
425
s_mondet()426 void s_mondet()
427 {
428 mondet(1);
429 }
430
431
432 /* select a spell to cast */
getspell()433 int getspell()
434 {
435 int spell= ABORT - 1;
436
437 do {
438 mprint("Cast Spell: [type spell abbrev, ?, or ESCAPE]: ");
439 spell = spellparse();
440 } while (spell < ABORT);
441 return(spell);
442 }
443
444
spellid(id)445 char *spellid(id)
446 int id;
447 {
448 switch(id) {
449 case S_MON_DET:return("monster detection");
450 case S_OBJ_DET:return("object detection");
451 case S_IDENTIFY:return("identification");
452 case S_FIREBOLT:return("firebolt");
453 case S_LBALL:return("ball lightning");
454 case S_SLEEP:return("sleep");
455 case S_DISRUPT:return("disrupt");
456 case S_DISINTEGRATE:return("disintegrate");
457 case S_TELEPORT:return("teleport");
458 case S_MISSILE:return("magic missile");
459 case S_HEAL:return("healing");
460 case S_DISPEL:return("dispelling");
461 case S_BREATHE:return("breathing");
462 case S_INVISIBLE:return("invisibility");
463 case S_WARP:return("the warp");
464 case S_ENCHANT:return("enchantment");
465 case S_BLESS:return("blessing");
466 case S_RESTORE:return("restoration");
467 case S_CURE:return("curing");
468 case S_TRUESIGHT:return("true sight");
469 case S_HELLFIRE:return("hellfire");
470 case S_KNOWLEDGE:return("self knowledge");
471 case S_HERO:return("heroism");
472 case S_RETURN:return("return");
473 case S_DESECRATE:return("desecration");
474 case S_HASTE:return("haste");
475 case S_SUMMON:return("summoning");
476 case S_SANCTUARY:return("sanctuary");
477 case S_ACCURACY:return("accuracy");
478 case S_RITUAL:return("ritual magic");
479 case S_APPORT:return("apportation");
480 case S_SHADOWFORM:return("shadow form");
481 case S_ALERT:return("alertness");
482 case S_REGENERATE:return("regeneration");
483 case S_SANCTIFY:return("sanctification");
484 case S_CLAIRVOYANCE:return("clairvoyance");
485 case S_DRAIN:return("energy drain");
486 case S_LEVITATE:return("levitate");
487 case S_POLYMORPH:return("polymorph");
488 case S_FEAR:return("fear");
489 case S_WISH:return("wishing");
490 default:return("???");
491 }
492 }
493
494
495
initspells()496 void initspells()
497 {
498 int i;
499
500 for (i=0; i<NUMSPELLS; i++)
501 Spells[i].known = FALSE;
502
503 Spells[S_MON_DET].powerdrain = 3;
504 Spells[S_MON_DET].id = S_MON_DET;
505
506 Spells[S_OBJ_DET].powerdrain = 3;
507 Spells[S_OBJ_DET].id = S_OBJ_DET;
508
509 Spells[S_IDENTIFY].powerdrain = 10;
510 Spells[S_IDENTIFY].id = S_IDENTIFY;
511
512 Spells[S_FIREBOLT].powerdrain = 20;
513 Spells[S_FIREBOLT].id = S_FIREBOLT;
514
515 Spells[S_SLEEP].powerdrain = 15;
516 Spells[S_SLEEP].id = S_SLEEP;
517
518 Spells[S_LBALL].powerdrain = 25;
519 Spells[S_LBALL].id = S_LBALL;
520
521 Spells[S_TELEPORT].powerdrain = 20;
522 Spells[S_TELEPORT].id = S_TELEPORT;
523
524 Spells[S_DISRUPT].powerdrain = 30;
525 Spells[S_DISRUPT].id = S_DISRUPT;
526
527 Spells[S_DISINTEGRATE].powerdrain = 40;
528 Spells[S_DISINTEGRATE].id = S_DISINTEGRATE;
529
530 Spells[S_MISSILE].powerdrain = 10;
531 Spells[S_MISSILE].id = S_MISSILE;
532
533 Spells[S_HEAL].powerdrain = 15;
534 Spells[S_HEAL].id = S_HEAL;
535
536 Spells[S_DISPEL].powerdrain = 40;
537 Spells[S_DISPEL].id = S_DISPEL;
538
539 Spells[S_BREATHE].powerdrain = 20;
540 Spells[S_BREATHE].id = S_BREATHE;
541
542 Spells[S_INVISIBLE].powerdrain = 15;
543 Spells[S_INVISIBLE].id = S_INVISIBLE;
544
545 Spells[S_WARP].powerdrain = 50;
546 Spells[S_WARP].id = S_WARP;
547
548 Spells[S_ENCHANT].powerdrain = 30;
549 Spells[S_ENCHANT].id = S_ENCHANT;
550
551 Spells[S_BLESS].powerdrain = 30;
552 Spells[S_BLESS].id = S_BLESS;
553
554 Spells[S_RESTORE].powerdrain = 20;
555 Spells[S_RESTORE].id = S_RESTORE;
556
557 Spells[S_CURE].powerdrain = 20;
558 Spells[S_CURE].id = S_CURE;
559
560 Spells[S_TRUESIGHT].powerdrain = 20;
561 Spells[S_TRUESIGHT].id = S_TRUESIGHT;
562
563 Spells[S_HELLFIRE].powerdrain = 90;
564 Spells[S_HELLFIRE].id = S_HELLFIRE;
565
566 Spells[S_KNOWLEDGE].powerdrain = 10;
567 Spells[S_KNOWLEDGE].id = S_KNOWLEDGE;
568
569 Spells[S_HERO].powerdrain = 20;
570 Spells[S_HERO].id = S_HERO;
571
572 Spells[S_RETURN].powerdrain = 10;
573 Spells[S_RETURN].id = S_RETURN;
574
575 Spells[S_DESECRATE].powerdrain = 50;
576 Spells[S_DESECRATE].id = S_DESECRATE;
577
578 Spells[S_HASTE].powerdrain = 15;
579 Spells[S_HASTE].id = S_HASTE;
580
581 Spells[S_SUMMON].powerdrain = 20;
582 Spells[S_SUMMON].id = S_SUMMON;
583
584 Spells[S_SANCTUARY].powerdrain = 75;
585 Spells[S_SANCTUARY].id = S_SANCTUARY;
586
587 Spells[S_ACCURACY].powerdrain = 20;
588 Spells[S_ACCURACY].id = S_ACCURACY;
589
590 Spells[S_RITUAL].powerdrain = 50;
591 Spells[S_RITUAL].id = S_RITUAL;
592
593 Spells[S_APPORT].powerdrain = 15;
594 Spells[S_APPORT].id = S_APPORT;
595
596 Spells[S_SHADOWFORM].powerdrain = 50;
597 Spells[S_SHADOWFORM].id = S_SHADOWFORM;
598
599 Spells[S_ALERT].powerdrain = 15;
600 Spells[S_ALERT].id = S_ALERT;
601
602 Spells[S_REGENERATE].powerdrain = 20;
603 Spells[S_REGENERATE].id = S_REGENERATE;
604
605 Spells[S_SANCTIFY].powerdrain = 75;
606 Spells[S_SANCTIFY].id = S_SANCTIFY;
607
608 Spells[S_CLAIRVOYANCE].powerdrain = 10;
609 Spells[S_CLAIRVOYANCE].id = S_CLAIRVOYANCE;
610
611 Spells[S_DRAIN].powerdrain = 40;
612 Spells[S_DRAIN].id = S_DRAIN;
613
614 Spells[S_LEVITATE].powerdrain = 25;
615 Spells[S_LEVITATE].id = S_LEVITATE;
616
617 Spells[S_POLYMORPH].powerdrain = 30;
618 Spells[S_POLYMORPH].id = S_POLYMORPH;
619
620 Spells[S_FEAR].powerdrain = 10;
621 Spells[S_FEAR].id = S_FEAR;
622
623 Spells[S_WISH].powerdrain = 100;
624 Spells[S_WISH].id = S_WISH;
625
626 }
627
628
629
630
631
632
cast_spell(spell)633 void cast_spell(spell)
634 int spell;
635 {
636 switch(spell) {
637 case S_MON_DET:s_mondet();
638 break;
639 case S_OBJ_DET:s_objdet();
640 break;
641 case S_IDENTIFY:s_identify();
642 break;
643 case S_FIREBOLT:s_firebolt();
644 break;
645 case S_SLEEP:s_sleep();
646 break;
647 case S_LBALL:s_lball();
648 break;
649 case S_TELEPORT:s_teleport();
650 break;
651 case S_DISRUPT:s_disrupt();
652 break;
653 case S_DISINTEGRATE:s_disintegrate();
654 break;
655 case S_MISSILE:s_missile();
656 break;
657 case S_HEAL:s_heal();
658 break;
659 case S_DISPEL:s_dispel();
660 break;
661 case S_BREATHE:s_breathe();
662 break;
663 case S_INVISIBLE:s_invisible();
664 break;
665 case S_WARP:s_warp();
666 break;
667 case S_ENCHANT:s_enchant();
668 break;
669 case S_BLESS:s_bless();
670 break;
671 case S_RESTORE:s_restore();
672 break;
673 case S_CURE:s_cure();
674 break;
675 case S_TRUESIGHT:s_truesight();
676 break;
677 case S_HELLFIRE:s_hellfire();
678 break;
679 case S_KNOWLEDGE:s_knowledge();
680 break;
681 case S_HERO:s_hero();
682 break;
683 case S_RETURN:s_return();
684 break;
685 case S_DESECRATE:s_desecrate();
686 break;
687 case S_HASTE:s_haste();
688 break;
689 case S_SUMMON:s_summon();
690 break;
691 case S_SANCTUARY:s_sanctuary();
692 break;
693 case S_ACCURACY:s_accuracy();
694 break;
695 case S_RITUAL:s_ritual();
696 break;
697 case S_APPORT:s_apport();
698 break;
699 case S_SHADOWFORM:s_shadowform();
700 break;
701 case S_ALERT:s_alert();
702 break;
703 case S_REGENERATE:s_regenerate();
704 break;
705 case S_SANCTIFY:s_sanctify();
706 break;
707 case S_CLAIRVOYANCE:s_clairvoyance();
708 break;
709 case S_DRAIN:s_drain();
710 break;
711 case S_LEVITATE:s_levitate();
712 break;
713 case S_FEAR:s_fear();
714 break;
715 case S_POLYMORPH:s_polymorph();
716 break;
717 case S_WISH:s_wish();
718 break;
719 default: mprint("Your odd spell fizzles with a small 'sput'.");
720 break;
721 }
722 }
723
724
725
726 static char *spell_names[] = { /* alphabetical listing */
727 "accuracy", "alertness", "apportation", "ball lightning", "blessing",
728 "breathing", "clairvoyance", "curing", "desecration", "disintegrate",
729 "dispelling", "disrupt", "enchantment", "energy drain", "fear", "firebolt",
730 "haste", "healing", "hellfire", "heroism", "identification", "invisibility",
731 "levitate", "magic missile", "monster detection", "object detection",
732 "polymorph", "regeneration", "restoration", "return", "ritual magic",
733 "sanctification", "sanctuary", "self knowledge", "shadow form", "sleep",
734 "summoning", "teleport", "the warp", "true sight", "wishing" };
735
736 static int spell_ids[] = { /* in the same order as spell_names[] */
737 S_ACCURACY, S_ALERT, S_APPORT, S_LBALL, S_BLESS, S_BREATHE, S_CLAIRVOYANCE,
738 S_CURE, S_DESECRATE, S_DISINTEGRATE, S_DISPEL, S_DISRUPT, S_ENCHANT, S_DRAIN,
739 S_FEAR, S_FIREBOLT, S_HASTE, S_HEAL, S_HELLFIRE, S_HERO, S_IDENTIFY,
740 S_INVISIBLE, S_LEVITATE, S_MISSILE, S_MON_DET, S_OBJ_DET, S_POLYMORPH,
741 S_REGENERATE, S_RESTORE, S_RETURN, S_RITUAL, S_SANCTIFY, S_SANCTUARY,
742 S_KNOWLEDGE, S_SHADOWFORM, S_SLEEP, S_SUMMON, S_TELEPORT, S_WARP, S_TRUESIGHT,
743 S_WISH };
744
showknownspells(first,last)745 void showknownspells(first, last)
746 int first, last;
747 {
748 int i,printed=FALSE;
749
750 menuclear();
751 menuprint("\nPossible Spells:\n");
752 for (i = first; i <= last; i++)
753 if (Spells[spell_ids[i]].known) {
754 printed = TRUE;
755 menuprint(spell_names[i]);
756 menuprint(" (");
757 menunumprint(Spells[spell_ids[i]].powerdrain);
758 menuprint(" mana)");
759 menuprint("\n");
760 }
761 if (! printed)
762 menuprint("\nNo spells match that prefix!");
763 showmenu();
764 }
765
spellparse()766 int spellparse()
767 {
768 int first, last, pos;
769 char byte, prefix[80];
770 int found = 0;
771 int f, l;
772
773 first = 0;
774 while (first < NUMSPELLS && !Spells[spell_ids[first]].known)
775 first++;
776 if (first == NUMSPELLS) {
777 print1("You don't know any spells!");
778 return ABORT;
779 }
780 last = NUMSPELLS - 1;
781 pos = 0;
782 print2("");
783 do {
784 byte = mgetc();
785 if (byte == BACKSPACE || byte == DELETE) {
786 if (pos > 0) {
787 prefix[--pos] = '\0';
788 byte = prefix[pos - 1];
789 f = first;
790 while (f >= 0 && !strncmp(prefix, spell_names[f], pos)) {
791 if (Spells[spell_ids[f]].known)
792 first = f;
793 f--;
794 }
795 l = last;
796 while (l < NUMSPELLS && !strncmp(prefix, spell_names[l], pos)) {
797 if (Spells[spell_ids[l]].known)
798 last = l;
799 l++;
800 }
801 if (found)
802 found = 0;
803 print2(prefix);
804 }
805 if (pos == 0) {
806 first = 0;
807 last = NUMSPELLS - 1;
808 found = 0;
809 print2("");
810 }
811 }
812 else if (byte == ESCAPE) {
813 xredraw();
814 return ABORT;
815 }
816 else if (byte == '?')
817 showknownspells(first, last);
818 else if (byte != '\n') {
819 if (byte >= 'A' && byte <= 'Z')
820 byte += 'a' - 'A';
821 if (found)
822 continue;
823 f = first;
824 l = last;
825 while (f < NUMSPELLS &&
826 (!Spells[spell_ids[f]].known ||
827 strlen(spell_names[f]) < pos || spell_names[f][pos] < byte))
828 f++;
829 while (l >= 0 && (!Spells[spell_ids[l]].known ||
830 strlen(spell_names[l]) < pos || spell_names[l][pos] > byte))
831 l--;
832 if (l < f)
833 continue;
834 prefix[pos++] = byte;
835 prefix[pos] = '\0';
836 nprint2(prefix + pos - 1);
837 first = f;
838 last = l;
839 if (first == last && !found) { /* unique name */
840 found = 1;
841 nprint2(spell_names[first] + pos);
842 }
843 }
844 } while (byte != '\n');
845 xredraw();
846 if (found)
847 return spell_ids[first];
848 else {
849 print3("That is an ambiguous abbreviation!");
850 return ABORT;
851 }
852 }
853