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);