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