Mercurial > hg > early-roguelike
comparison urogue/magic.c @ 256:c495a4f288c6
Import UltraRogue from the Roguelike Restoration Project (r1490)
author | John "Elwin" Edwards |
---|---|
date | Tue, 31 Jan 2017 19:56:04 -0500 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
253:d9badb9c0179 | 256:c495a4f288c6 |
---|---|
1 /* | |
2 magic.c - This file contains functions for casting magic spells | |
3 | |
4 UltraRogue: The Ultimate Adventure in the Dungeons of Doom | |
5 Copyright (C) 1986, 1992, 1993, 1995 Herb Chong | |
6 All rights reserved. | |
7 | |
8 Based on "Advanced Rogue" | |
9 Copyright (C) 1984, 1985 Michael Morgan, Ken Dalka | |
10 All rights reserved. | |
11 | |
12 Based on "Rogue: Exploring the Dungeons of Doom" | |
13 Copyright (C) 1980, 1981 Michael Toy, Ken Arnold and Glenn Wichman | |
14 All rights reserved. | |
15 | |
16 See the file LICENSE.TXT for full copyright and licensing information. | |
17 */ | |
18 | |
19 #include <stdlib.h> | |
20 #include <string.h> | |
21 #include <ctype.h> | |
22 #include "rogue.h" | |
23 | |
24 /* | |
25 Cost for each level of spells level: | |
26 */ | |
27 | |
28 static const int spell_cost[] = {1, 5, 17, 29, 53, 91, 159, 247, 396}; | |
29 | |
30 static struct spells monst_spells[] = | |
31 { | |
32 {5, S_SELFTELEP, SCR_MAGIC}, | |
33 {4, P_HEALING, POT_MAGIC | _TWO_}, | |
34 {3, P_REGENERATE, POT_MAGIC}, | |
35 {2, P_HEALING, POT_MAGIC}, | |
36 {4, P_HASTE, POT_MAGIC}, | |
37 {2, P_SEEINVIS, POT_MAGIC}, | |
38 {3, P_SHERO, POT_MAGIC}, | |
39 {5, P_PHASE, POT_MAGIC}, | |
40 {4, P_INVIS, POT_MAGIC}, | |
41 {4, WS_CANCEL, ZAP_MAGIC}, | |
42 | |
43 /* In reverse order of damage ability */ | |
44 {6, WS_ELECT, ZAP_MAGIC | _TWO_}, | |
45 {6, WS_FIRE, ZAP_MAGIC | _TWO_}, | |
46 {6, WS_COLD, ZAP_MAGIC | _TWO_}, | |
47 {6, WS_MISSILE, ZAP_MAGIC | _TWO_}, | |
48 {5, WS_ELECT, ZAP_MAGIC}, | |
49 {5, WS_FIRE, ZAP_MAGIC}, | |
50 {5, WS_COLD, ZAP_MAGIC}, | |
51 {4, WS_ELECT, ZAP_MAGIC | ISCURSED}, | |
52 {4, WS_FIRE, ZAP_MAGIC | ISCURSED}, | |
53 {4, WS_COLD, ZAP_MAGIC | ISCURSED}, | |
54 {3, WS_MISSILE, ZAP_MAGIC}, | |
55 {1, WS_MISSILE, ZAP_MAGIC | ISCURSED}, | |
56 | |
57 {-1, -1, 0} | |
58 }; | |
59 | |
60 /* | |
61 Spells that a player can cast Non-mus only know ISKNOW spells until found | |
62 in the dungeon. Special classes know their spells one level lower, and | |
63 blessed one above. | |
64 */ | |
65 | |
66 static struct spells player_spells[] = | |
67 { | |
68 {1, WS_KNOCK, ZAP_MAGIC | ISKNOW}, | |
69 {1, S_SUMFAMILIAR, SCR_MAGIC | SP_DRUID | SP_MAGIC | SP_CLERIC, SP_ILLUSION }, | |
70 {1, S_GFIND, SCR_MAGIC | ISKNOW}, | |
71 {1, P_MONSTDET, POT_MAGIC | ISKNOW | SP_DRUID}, | |
72 {1, P_TREASDET, POT_MAGIC | ISKNOW | SP_MAGIC}, | |
73 {1, S_FOODDET, SCR_MAGIC | ISKNOW | SP_CLERIC}, | |
74 {1, S_LIGHT, SCR_MAGIC | ISKNOW | SP_ILLUSION}, | |
75 | |
76 {2, WS_CLOSE, ZAP_MAGIC | ISKNOW}, | |
77 {2, S_IDENTIFY, SCR_MAGIC | ISKNOW}, | |
78 {2, WS_HIT, ZAP_MAGIC | ISKNOW | SP_PRAYER}, | |
79 {2, P_SHIELD, POT_MAGIC | ISKNOW | SP_MAGIC}, | |
80 {2, P_COLDRESIST, POT_MAGIC | SP_WIZARD}, | |
81 {2, P_SEEINVIS, POT_MAGIC | SP_ILLUSION}, | |
82 {2, S_CONFUSE, SCR_MAGIC | SP_CLERIC}, | |
83 {2, P_SMELL, POT_MAGIC | SP_DRUID}, | |
84 {2, WS_MISSILE, ZAP_MAGIC | SP_MAGIC}, | |
85 {2, P_HEAR, POT_MAGIC}, | |
86 | |
87 {3, P_CLEAR, POT_MAGIC | ISKNOW}, | |
88 {3, P_HEALING, POT_MAGIC | ISKNOW | SP_PRAYER}, | |
89 {3, S_CURING, SCR_MAGIC | ISKNOW | SP_PRAYER}, | |
90 {3, WS_MONSTELEP, ZAP_MAGIC | SP_MAGIC}, | |
91 {3, WS_CANCEL, ZAP_MAGIC | SP_WIZARD}, | |
92 {3, S_SELFTELEP, SCR_MAGIC | SP_WIZARD}, | |
93 {3, P_FIRERESIST, POT_MAGIC | SP_WIZARD | SP_DRUID}, | |
94 {3, S_MAP, SCR_MAGIC | SP_ILLUSION | SP_DRUID}, | |
95 {3, S_REMOVECURSE, SCR_MAGIC | SP_PRAYER}, | |
96 {3, S_HOLD, SCR_MAGIC | SP_CLERIC}, | |
97 {3, S_SLEEP, SCR_MAGIC | SP_DRUID}, | |
98 {3, P_HASOXYGEN, POT_MAGIC | SP_DRUID}, | |
99 {3, WS_XENOHEALING, ZAP_MAGIC | SP_DRUID}, | |
100 {3, P_RESTORE, POT_MAGIC}, | |
101 | |
102 {4, S_MSHIELD, SCR_MAGIC | ISKNOW | SP_ILLUSION}, | |
103 {4, P_INVIS, POT_MAGIC | SP_ILLUSION}, | |
104 {4, S_REFLECT, SCR_MAGIC | SP_ILLUSION}, | |
105 {4, P_TRUESEE, POT_MAGIC | SP_ILLUSION}, | |
106 {4, P_REGENERATE, POT_MAGIC | SP_CLERIC}, | |
107 {4, WS_DRAIN, ZAP_MAGIC | SP_CLERIC}, | |
108 {4, P_HASTE, POT_MAGIC | SP_ILLUSION | SP_CLERIC}, | |
109 {4, P_LEVITATION, POT_MAGIC | SP_WIZARD | SP_DRUID}, | |
110 {4, WS_WEB, ZAP_MAGIC | SP_MAGIC}, | |
111 {4, P_PHASE, POT_MAGIC}, | |
112 | |
113 {5, P_SHERO, POT_MAGIC | ISKNOW}, | |
114 {5, S_PETRIFY, SCR_MAGIC | SP_MAGIC}, | |
115 {5, S_SCARE, SCR_MAGIC | _TWO_ | SP_PRAYER}, | |
116 {5, WS_COLD, ZAP_MAGIC | SP_DRUID}, | |
117 {5, WS_FIRE, ZAP_MAGIC | SP_CLERIC}, | |
118 {5, WS_ELECT, ZAP_MAGIC | SP_WIZARD}, | |
119 {5, WS_ANTIMATTER, ZAP_MAGIC | SP_ILLUSION}, | |
120 {5, S_ELECTRIFY, SCR_MAGIC | SP_ILLUSION}, | |
121 | |
122 {6, WS_DISINTEGRATE, ZAP_MAGIC | ISKNOW}, | |
123 {6, S_OWNERSHIP, SCR_MAGIC | SP_ALL}, | |
124 | |
125 {7, S_ENCHANT, SCR_MAGIC | SP_MAGIC}, | |
126 | |
127 {-1, -1, 0} | |
128 }; | |
129 | |
130 /* | |
131 incant() | |
132 Cast a spell | |
133 */ | |
134 | |
135 void | |
136 incant(struct thing *caster, coord dir) | |
137 { | |
138 int i; | |
139 struct stats *curp; | |
140 struct stats *maxp; | |
141 int is_player = (caster == &player); | |
142 int points_casters; | |
143 char *casters_name = (on(player, ISBLIND)) ? "it" : | |
144 monsters[caster->t_index].m_name; | |
145 struct spells *sp; | |
146 char *cast_name; /* = spell_name(sp) */ | |
147 char *spell_type; /* spell or prayer */ | |
148 int casting_cost; /* from spell_cost[] */ | |
149 int spell_roll; /* sucess/fail 1D100 die roll */ | |
150 int fumble_chance; /* Spell fumble chance */ | |
151 int num_fumbles = 0; /* for fumble_spell() */ | |
152 int bless_or_curse = ISNORMAL; /* blessed or cursed? */ | |
153 int message_flags = CAST_NORMAL; /* which message to print out */ | |
154 int class_casters; /* For determining ISKNOW */ | |
155 int stat_casters; /* s_intel or s_wisdom */ | |
156 int level_casters; /* spellcasting level */ | |
157 char buf[2 * LINELEN]; | |
158 struct spells sorted_spells[MAX_SPELLS]; | |
159 char spellbuf[2 * LINELEN]; | |
160 char spellbuf2[2 * LINELEN]; | |
161 | |
162 curp = &(caster->t_stats); | |
163 maxp = &(caster->maxstats); | |
164 points_casters = curp->s_power; | |
165 | |
166 if (points_casters <= 0) | |
167 { | |
168 if (is_player) | |
169 msg("You don't have any spell points."); | |
170 | |
171 return; | |
172 } | |
173 | |
174 /* | |
175 * Paladins, Rangers, ringwearers, and monsters cast at 4 levels | |
176 * below. Other non-specialists at 8 below | |
177 */ | |
178 | |
179 level_casters = curp->s_lvl; | |
180 | |
181 switch (caster->t_ctype) | |
182 { | |
183 case C_PALADIN: | |
184 level_casters -= 4; | |
185 /* fallthrough */ | |
186 case C_CLERIC: | |
187 class_casters = SP_CLERIC; | |
188 stat_casters = curp->s_wisdom; | |
189 break; | |
190 case C_RANGER: | |
191 level_casters -= 4; | |
192 /* fallthrough */ | |
193 case C_DRUID: | |
194 class_casters = SP_DRUID; | |
195 stat_casters = curp->s_wisdom; | |
196 break; | |
197 case C_MAGICIAN: | |
198 class_casters = SP_WIZARD; | |
199 stat_casters = curp->s_intel; | |
200 break; | |
201 case C_ILLUSION: | |
202 class_casters = SP_ILLUSION; | |
203 stat_casters = curp->s_intel; | |
204 break; | |
205 case C_MONSTER: | |
206 if (off(*caster, ISUNIQUE)) | |
207 level_casters -= 4; | |
208 class_casters = 0x0; | |
209 stat_casters = curp->s_intel; | |
210 break; | |
211 | |
212 default: | |
213 if (is_wearing(R_WIZARD)) | |
214 { | |
215 level_casters -= 4; | |
216 class_casters = (rnd(4) ? SP_WIZARD : SP_ILLUSION); | |
217 stat_casters = curp->s_intel; | |
218 } | |
219 else if (is_wearing(R_PIETY)) | |
220 { | |
221 level_casters -= 4; | |
222 class_casters = (rnd(4) ? SP_CLERIC : SP_DRUID); | |
223 stat_casters = curp->s_wisdom; | |
224 } | |
225 else | |
226 { | |
227 level_casters -= 8; | |
228 class_casters = 0x0; | |
229 stat_casters = (rnd(2) ? curp->s_wisdom : curp->s_intel); | |
230 } | |
231 } | |
232 | |
233 /* Bug - What about when WIS == INT? */ | |
234 | |
235 spell_type = (stat_casters == curp->s_intel) ? "spell" : "prayer"; | |
236 | |
237 if (!is_player && (sp = pick_monster_spell(caster)) == NULL) | |
238 return; | |
239 else if (is_player) | |
240 { | |
241 int num_spells = -1; /* num of spells cheap enough */ | |
242 | |
243 sorted_spells[0].sp_cost = -1; | |
244 | |
245 for (sp = player_spells; sp->sp_level != -1; sp++) | |
246 { | |
247 if (sp->sp_flags & class_casters) /* Does class know spell? */ | |
248 { | |
249 int rnd_number = rnd(2 * sp->sp_level) - sp->sp_level; | |
250 | |
251 /* Knows normal spell one level below others */ | |
252 | |
253 casting_cost = spell_cost[sp->sp_level - 1] + rnd_number; | |
254 | |
255 if (points_casters >= casting_cost) | |
256 { | |
257 sorted_spells[++num_spells] = *sp; | |
258 sorted_spells[num_spells].sp_cost = casting_cost; | |
259 sorted_spells[num_spells].sp_level = sp->sp_level - 1; | |
260 } | |
261 | |
262 /* Knows blessed spell one level above others */ | |
263 | |
264 casting_cost = spell_cost[sp->sp_level + 1] + rnd_number; | |
265 | |
266 if (points_casters >= casting_cost) | |
267 { | |
268 sorted_spells[++num_spells] = *sp; | |
269 sorted_spells[num_spells].sp_level = sp->sp_level + 1; | |
270 sorted_spells[num_spells].sp_cost = casting_cost; | |
271 sorted_spells[num_spells].sp_flags |= ISBLESSED; | |
272 } | |
273 } /* If class doesn't know spell, see if its a ISKNOW */ | |
274 else if (sp->sp_flags & ISKNOW) | |
275 { | |
276 int rnd_number = rnd(4 * sp->sp_level) - sp->sp_level; | |
277 | |
278 casting_cost = spell_cost[sp->sp_level] + rnd_number; | |
279 | |
280 if (points_casters >= casting_cost) | |
281 { | |
282 sorted_spells[++num_spells] = *sp; | |
283 sorted_spells[num_spells].sp_cost = casting_cost; | |
284 } | |
285 } | |
286 /* else this spell is unknown */ | |
287 } | |
288 | |
289 if (sorted_spells[0].sp_cost == -1) | |
290 { | |
291 msg("You don't have enough %s points.", spell_type); | |
292 after = FALSE; | |
293 return; | |
294 } | |
295 | |
296 qsort(sorted_spells,num_spells + 1,sizeof(struct spells),sort_spells); | |
297 | |
298 do /* Prompt for spells */ | |
299 { | |
300 struct spells *which_spell = NULL; | |
301 | |
302 buf[0] = '\0'; | |
303 msg("");/* Get rid of --More-- */ | |
304 msg("Which %s are you casting [%d points left] (* for list)? ", | |
305 spell_type, points_casters); | |
306 | |
307 switch(get_string(buf, cw)) | |
308 { | |
309 case NORM: break; | |
310 case QUIT: return; /* ESC - lose turn */ | |
311 default: continue; | |
312 } | |
313 | |
314 if (buf[0] == '*') /* print list */ | |
315 { | |
316 add_line("Cost Abbreviation Full Name"); | |
317 | |
318 for (i = 0; i <= num_spells; i++) | |
319 { | |
320 sp = &sorted_spells[i]; | |
321 sprintf(buf, "[%3d] %-12s\t%s", | |
322 sp->sp_cost, spell_abrev(sp,spellbuf2), | |
323 spell_name(sp,spellbuf)); | |
324 add_line(buf); | |
325 } | |
326 end_line(); | |
327 sp = NULL; | |
328 continue; | |
329 } | |
330 | |
331 if (isupper(buf[0])) /* Uppercase Abbreviation */ | |
332 { | |
333 for (i = 0; i <= num_spells; i++) | |
334 { | |
335 sp = &sorted_spells[i]; | |
336 | |
337 if ((strcmp(spell_abrev(sp,spellbuf2), buf) == 0)) | |
338 { | |
339 which_spell = sp; | |
340 break; | |
341 } | |
342 } | |
343 } | |
344 else /* Full Spell Name */ | |
345 { | |
346 for (i = 0; i <= num_spells; i++) | |
347 { | |
348 sp = &sorted_spells[i]; | |
349 | |
350 if ((strcmp(spell_name(sp,spellbuf), buf) == 0)) | |
351 { | |
352 which_spell = sp; | |
353 break; | |
354 } | |
355 } | |
356 } | |
357 | |
358 sp = which_spell; | |
359 } | |
360 while (sp == NULL); | |
361 } | |
362 | |
363 /* Common monster and player code */ | |
364 | |
365 cast_name = spell_name(sp,spellbuf); | |
366 | |
367 fumble_chance = (10 * sp->sp_level / 4 - 10 * level_casters / 13) * 5; | |
368 | |
369 if (cur_weapon != NULL && wield_ok(caster, cur_weapon, FALSE) == FALSE) | |
370 { | |
371 switch (caster->t_ctype) | |
372 { | |
373 case C_MAGICIAN: | |
374 case C_ILLUSION: | |
375 msg("You should have both hands free."); | |
376 fumble_chance += rnd(level_casters) * 5; | |
377 break; | |
378 | |
379 case C_CLERIC: | |
380 case C_DRUID: | |
381 case C_PALADIN: | |
382 msg("Your god looks askance at the weapon you wield."); | |
383 fumble_chance += rnd(level_casters) * 5; | |
384 break; | |
385 | |
386 default: | |
387 break; | |
388 } | |
389 } | |
390 | |
391 if (fumble_chance >= MAX_FUMBLE_CHANCE) | |
392 fumble_chance = MAX_FUMBLE_CHANCE; | |
393 else if (fumble_chance <= MIN_FUMBLE_CHANCE + sp->sp_level) | |
394 fumble_chance = MIN_FUMBLE_CHANCE + sp->sp_level; | |
395 | |
396 if (fumble_chance > (30 + rnd(50))) | |
397 { | |
398 if (is_player) | |
399 { | |
400 int answer; | |
401 | |
402 msg("Are you sure you want to try for that hard a %s? [n]", | |
403 spell_type); | |
404 | |
405 answer = readchar(); | |
406 | |
407 if (tolower(answer) != 'y') | |
408 { | |
409 after = FALSE; | |
410 return; | |
411 } | |
412 else | |
413 msg("Here goes..."); | |
414 } | |
415 else /* Only if the monster is desperate */ | |
416 { | |
417 if (curp->s_hpt > maxp->s_hpt / 2) | |
418 return; | |
419 } | |
420 } | |
421 | |
422 /* casting costs food energy */ | |
423 | |
424 food_left -= sp->sp_cost; | |
425 | |
426 spell_roll = rnd(100); | |
427 | |
428 debug("%s(%d) cast '%s' fumble %%%d (rolled %d) ", | |
429 monsters[caster->t_index].m_name, curp->s_power, cast_name, | |
430 fumble_chance, spell_roll); | |
431 | |
432 caster->t_rest_hpt = caster->t_rest_pow = 0; | |
433 | |
434 if (!is_player) /* Stop running. */ | |
435 { | |
436 running = FALSE; | |
437 msg("The %s is casting '%s'.", casters_name, cast_name); | |
438 } | |
439 | |
440 /* The Crown of Might insures that your spells never fumble */ | |
441 | |
442 if (spell_roll < fumble_chance) | |
443 { | |
444 if (is_carrying(TR_CROWN)) | |
445 message_flags |= CAST_CROWN; | |
446 else | |
447 { | |
448 message_flags |= CAST_CURSED; | |
449 | |
450 curp->s_power -= min(curp->s_power, | |
451 (2 * sp->sp_cost)); /* 2x cost */ | |
452 num_fumbles = rnd(((fumble_chance - spell_roll) / 10) | |
453 + 1) + rnd(sp->sp_level) + rnd(curp->s_lvl); | |
454 num_fumbles = min(10, max(0, num_fumbles)); | |
455 | |
456 if (num_fumbles >= 6 && rnd(1) == 0) | |
457 bless_or_curse = ISCURSED; | |
458 else if (num_fumbles < 4) | |
459 { | |
460 if (is_player) | |
461 msg("Your %s fails.", spell_type); | |
462 return; | |
463 } | |
464 } | |
465 } | |
466 else if (spell_roll > MAX_FUMBLE_CHANCE) | |
467 { | |
468 if (is_player) | |
469 { | |
470 message_flags |= CAST_BLESSED; | |
471 pstats.s_exp += 3 * sp->sp_cost * curp->s_lvl; | |
472 check_level(); | |
473 } | |
474 | |
475 maxp->s_power += sp->sp_cost; | |
476 bless_or_curse = ISBLESSED; | |
477 } | |
478 else | |
479 { | |
480 if (is_player) /* extra exp for sucessful spells */ | |
481 { | |
482 if (player.t_ctype == C_MAGICIAN || player.t_ctype == C_ILLUSION) | |
483 { | |
484 pstats.s_exp += sp->sp_cost * curp->s_lvl; | |
485 check_level(); | |
486 } | |
487 } | |
488 | |
489 bless_or_curse = sp->sp_flags & ISBLESSED; | |
490 curp->s_power -= sp->sp_cost; | |
491 } | |
492 | |
493 /* The Sceptre of Might blesses all your spells */ | |
494 | |
495 if (is_player && ((bless_or_curse & ISBLESSED) == 0) && | |
496 is_carrying(TR_SCEPTRE)) | |
497 { | |
498 message_flags |= CAST_SEPTRE; | |
499 bless_or_curse = ISBLESSED; | |
500 } | |
501 | |
502 if (sp->sp_flags & POT_MAGIC) | |
503 quaff(caster, sp->sp_which, bless_or_curse); | |
504 else if (sp->sp_flags & SCR_MAGIC) | |
505 read_scroll(caster, sp->sp_which, bless_or_curse); | |
506 else if (sp->sp_flags & ZAP_MAGIC) | |
507 { | |
508 if (is_player) | |
509 { | |
510 do /* Must pick a direction */ | |
511 { | |
512 msg("Which direction?"); | |
513 } | |
514 while (get_dir() == FALSE); | |
515 } | |
516 else | |
517 { | |
518 delta.x = dir.x; | |
519 delta.y = dir.y; | |
520 } | |
521 do_zap(caster, sp->sp_which, bless_or_curse); | |
522 } | |
523 else | |
524 msg("What a strange %s!", spell_type); | |
525 | |
526 /* | |
527 * Print messages and take fumbles *after* spell has gone off. This | |
528 * makes ENCHANT, etc more dangerous | |
529 */ | |
530 | |
531 if (is_player) | |
532 { | |
533 if (message_flags & CAST_SEPTRE) | |
534 msg("The Sceptre enhanced your %s.", spell_type); | |
535 if (message_flags & CAST_CROWN) | |
536 msg("The Crown wordlessly corrected your %s.", | |
537 spell_type); | |
538 | |
539 switch (message_flags & 0x1) | |
540 { | |
541 case CAST_CURSED: | |
542 msg("You botched your '%s' %s.", cast_name, | |
543 spell_type); | |
544 fumble_spell(caster, num_fumbles); | |
545 break; | |
546 case CAST_NORMAL: | |
547 msg("You sucessfully cast your '%s' %s.", | |
548 cast_name, spell_type); | |
549 break; | |
550 | |
551 case CAST_BLESSED: | |
552 msg("Your '%s' %s went superbly.", cast_name, | |
553 spell_type); | |
554 break; | |
555 } | |
556 } | |
557 } | |
558 | |
559 /* | |
560 spell_name() | |
561 returns pointer to spell name | |
562 */ | |
563 | |
564 char * | |
565 spell_name(struct spells *sp, char *buf) | |
566 { | |
567 if (buf == NULL) | |
568 return("UltraRogue Bug #105"); | |
569 | |
570 if (sp->sp_flags & POT_MAGIC) | |
571 strcpy(buf, p_magic[sp->sp_which].mi_name); | |
572 else if (sp->sp_flags & SCR_MAGIC) | |
573 strcpy(buf, s_magic[sp->sp_which].mi_name); | |
574 else if (sp->sp_flags & ZAP_MAGIC) | |
575 strcpy(buf, ws_magic[sp->sp_which].mi_name); | |
576 else | |
577 strcpy(buf, "unknown spell type"); | |
578 | |
579 if (sp->sp_flags & ISBLESSED) | |
580 strcat(buf, " 2"); | |
581 | |
582 return(buf); | |
583 } | |
584 | |
585 /* | |
586 spell_abrev() | |
587 returns pointer to capital letter spell abbreviation | |
588 */ | |
589 | |
590 char * | |
591 spell_abrev(struct spells *sp, char *buf) | |
592 { | |
593 if (buf == NULL) | |
594 return("UltraRogue Bug #106"); | |
595 | |
596 if (sp->sp_flags & POT_MAGIC) | |
597 strcpy(buf, p_magic[sp->sp_which].mi_abrev); | |
598 else if (sp->sp_flags & SCR_MAGIC) | |
599 strcpy(buf, s_magic[sp->sp_which].mi_abrev); | |
600 else if (sp->sp_flags & ZAP_MAGIC) | |
601 strcpy(buf, ws_magic[sp->sp_which].mi_abrev); | |
602 else | |
603 strcpy(buf, "?????"); | |
604 | |
605 if (sp->sp_flags & ISBLESSED) | |
606 strcat(buf, " 2"); | |
607 | |
608 return(buf); | |
609 } | |
610 | |
611 /* | |
612 fumble_spell() | |
613 he blew it. Make him pay | |
614 */ | |
615 | |
616 void | |
617 fumble_spell(struct thing *caster, int num_fumbles) | |
618 { | |
619 struct stats *curp = &(caster->t_stats); | |
620 struct stats *maxp = &(caster->maxstats); | |
621 int is_player = (caster == &player); | |
622 | |
623 debug("Taking %d fumbles.", num_fumbles); | |
624 | |
625 switch (num_fumbles) | |
626 { | |
627 case 10: /* Lose ability */ | |
628 if (rnd(5) == 0) | |
629 quaff(caster, P_GAINABIL, ISCURSED); | |
630 break; | |
631 | |
632 case 9: /* Lose max spell points */ | |
633 | |
634 if (rnd(4) == 0) | |
635 { | |
636 maxp->s_power -= rnd(10); | |
637 | |
638 if (maxp->s_power <= 5) | |
639 maxp->s_power = 5; | |
640 } | |
641 break; | |
642 | |
643 case 8: /* Lose all current spell points */ | |
644 | |
645 if (rnd(3) == 0) | |
646 curp->s_power = 0; | |
647 else | |
648 curp->s_power /= 2; | |
649 break; | |
650 | |
651 case 7: /* Freeze */ | |
652 | |
653 if (rnd(2) == 0) | |
654 { | |
655 if (is_player) | |
656 no_command++; | |
657 else | |
658 caster->t_no_move++; | |
659 } | |
660 break; | |
661 | |
662 case 6: /* Cast a cursed spell - see below */ | |
663 break; | |
664 | |
665 case 5: /* Become dazed and confused */ | |
666 | |
667 if (rnd(5) == 0) | |
668 quaff(caster, P_CLEAR, ISCURSED); | |
669 break; | |
670 | |
671 case 4: /* Lose hit points */ | |
672 | |
673 if (is_player) | |
674 feel_message(); | |
675 if ((curp->s_hpt -= rnd(10)) <= 0) | |
676 { | |
677 if (is_player) | |
678 death(D_SPELLFUMBLE); | |
679 else | |
680 killed(caster, find_mons(caster->t_pos.y, caster->t_pos.x), | |
681 NOMESSAGE, NOPOINTS); | |
682 return; | |
683 } | |
684 break; | |
685 | |
686 case 3: /* Spell fails */ | |
687 break; | |
688 | |
689 case 2: /* Freeze */ | |
690 | |
691 if (is_player) | |
692 no_command++; | |
693 else | |
694 caster->t_no_move++; | |
695 | |
696 break; | |
697 | |
698 default: | |
699 case 1: /* Take double spell points - handled in incant() */ | |
700 break; | |
701 } | |
702 } | |
703 | |
704 /* | |
705 learn_new_spells() | |
706 go through player_spells and ISKNOW identified potions, | |
707 scrolls, and sticks | |
708 */ | |
709 | |
710 void | |
711 learn_new_spells(void) | |
712 { | |
713 struct spells *sp; | |
714 int kludge = 0; | |
715 char spellbuf[2*LINELEN]; | |
716 | |
717 for (sp = player_spells; sp->sp_level != -1; sp++) | |
718 { | |
719 if (sp->sp_flags & POT_MAGIC) | |
720 kludge = TYP_POTION; | |
721 else if (sp->sp_flags & SCR_MAGIC) | |
722 kludge = TYP_SCROLL; | |
723 else if (sp->sp_flags & ZAP_MAGIC) | |
724 kludge = TYP_STICK; | |
725 | |
726 if (know_items[kludge][sp->sp_which]) | |
727 { | |
728 if ((sp->sp_flags & ISKNOW) == FALSE) | |
729 debug("Learned new spell '%s'", spell_name(sp,spellbuf)); | |
730 sp->sp_flags |= ISKNOW; | |
731 } | |
732 } | |
733 } | |
734 | |
735 /* | |
736 pick_monster_spell() | |
737 decide which spell from monst_spells will be cast | |
738 returns pointer to spell in monst_spells | |
739 */ | |
740 | |
741 struct spells * | |
742 pick_monster_spell(struct thing *caster) | |
743 { | |
744 struct spells *sp = NULL; | |
745 struct stats *curp = &(caster->t_stats); | |
746 int points_casters = curp->s_power; | |
747 | |
748 /* Discover castable spells */ | |
749 | |
750 for (sp = monst_spells; sp->sp_level != -1; sp++) | |
751 { | |
752 int rnd_number = rnd(2 * sp->sp_level) - sp->sp_level; | |
753 int casting_cost = spell_cost[sp->sp_level] + rnd_number; | |
754 | |
755 if (points_casters >= casting_cost) | |
756 sp->sp_flags |= ISKNOW; | |
757 } | |
758 | |
759 /* Decide which spell to cast */ | |
760 | |
761 if (curp->s_hpt < rnd(caster->maxstats.s_hpt)) /* think defense */ | |
762 { | |
763 int i; | |
764 static const int run_or_heal[NUM_RUN] = | |
765 { M_SELFTELEP, M_HLNG2, M_HLNG, M_REGENERATE }; | |
766 | |
767 for (i = 0; i < NUM_RUN; i++) | |
768 { | |
769 sp = &monst_spells[run_or_heal[i]]; | |
770 | |
771 if ((sp->sp_flags & ISKNOW) && rnd(1)) | |
772 return(sp); | |
773 } | |
774 } | |
775 | |
776 if (on(*caster, ISSLOW)) /* cancel a slow */ | |
777 { | |
778 sp = &monst_spells[M_HASTE]; | |
779 | |
780 if (sp->sp_flags & ISKNOW) | |
781 return (sp); | |
782 } | |
783 | |
784 if (on(*caster, ISFLEE)) /* stop running away */ | |
785 { | |
786 sp = &monst_spells[M_SHERO]; | |
787 | |
788 if (sp->sp_flags & ISKNOW) | |
789 return (sp); | |
790 } | |
791 | |
792 if (on(player, ISINVIS) || on(player, ISDISGUISE)) | |
793 { | |
794 if (off(*caster, CANSEE)) /* look for him */ | |
795 { | |
796 sp = &monst_spells[M_SEEINVIS]; | |
797 | |
798 if (sp->sp_flags & ISKNOW) | |
799 return (sp); | |
800 } | |
801 else if (off(*caster, ISINVIS)) /* go invisible */ | |
802 { | |
803 sp = &monst_spells[M_INVIS]; | |
804 | |
805 if (sp->sp_flags & ISKNOW) | |
806 return (sp); | |
807 } | |
808 } | |
809 | |
810 if (on(player, CANINWALL) && (off(*caster, CANINWALL)) && | |
811 (rnd(5) == 0)) | |
812 { | |
813 sp = &monst_spells[M_PHASE]; | |
814 | |
815 if (sp->sp_flags & ISKNOW) | |
816 return (sp); | |
817 } | |
818 | |
819 if (rnd(5) == 0 && has_defensive_spell(player)) | |
820 { | |
821 sp = &monst_spells[M_CANCEL]; | |
822 | |
823 if (sp->sp_flags & ISKNOW) | |
824 return (sp); | |
825 } | |
826 | |
827 /* Cast an offensive spell */ | |
828 | |
829 for (sp = &monst_spells[M_OFFENSE]; sp->sp_level != 1; sp++) | |
830 { | |
831 if ((rnd(3) == 0) && (sp->sp_flags & ISKNOW)) | |
832 return (sp); | |
833 | |
834 if ((rnd(3) == 0) && (sp->sp_flags & ISKNOW)) | |
835 { | |
836 if (sp->sp_which != WS_MISSILE && | |
837 DISTANCE(caster->t_pos, hero) > BOLT_LENGTH) | |
838 continue; | |
839 else | |
840 return(sp); | |
841 } | |
842 } | |
843 | |
844 return(NULL); | |
845 } | |
846 | |
847 /* | |
848 sort_spells() | |
849 called by qsort() | |
850 */ | |
851 | |
852 int | |
853 sort_spells(const void *a, const void *b) | |
854 { | |
855 struct spells *sp1, *sp2; | |
856 int diff; | |
857 char spellbuf[2 * LINELEN]; | |
858 char spellbuf2[2 * LINELEN]; | |
859 | |
860 union /* hack to prevent 'lint' from complaining */ | |
861 { | |
862 struct spells *s; | |
863 const void *vptr; | |
864 } s1,s2; | |
865 | |
866 s1.vptr = a; | |
867 s2.vptr = b; | |
868 | |
869 sp1 = s1.s; | |
870 sp2 = s2.s; | |
871 | |
872 diff = sp1->sp_cost - sp2->sp_cost; | |
873 | |
874 if (diff != 0) | |
875 return(diff); | |
876 else | |
877 return(strcmp(spell_name(sp1,spellbuf), spell_name(sp1,spellbuf2))); | |
878 } |