1 /* File: mind.c */
2
3 /* Purpose: Mindcrafter code */
4
5 /*
6 * Copyright (c) 1989 James E. Wilson, Robert A. Koeneke
7 *
8 * This software may be copied and distributed for educational, research, and
9 * not for profit purposes provided that this copyright and statement are
10 * included in all such copies.
11 */
12
13 #include "angband.h"
14
15 /* Level gained, cost, %fail, name */
16 mindcraft_power mindcraft_powers[MINDCRAFT_MAX] =
17 {
18 {1, 1, 15, "Neural Blast"},
19 {2, 1, 20, "Precognition"},
20 {3, 2, 25, "Minor Displacement"},
21 {7, 6, 35, "Major Displacement"},
22 {9, 7, 50, "Domination"},
23 {11, 7, 30, "Pulverise"},
24 {13, 12, 50, "Character Armour"},
25 {15, 12, 60, "Psychometry"},
26 {18, 10, 45, "Mind Wave"},
27 {23, 15, 50, "Adrenaline Channeling"},
28 {25, 10, 40, "Psychic Drain"},
29 {28, 20, 45, "Telekinetic Wave"}
30 };
31
32
mindcraft_info(char * p,int power)33 void mindcraft_info(char *p, int power)
34 {
35 int plev = p_ptr->lev;
36
37 p[0] = 0;
38
39 switch (power)
40 {
41 case MINDCRAFT_NEURAL_BLAST:
42 {
43 strnfmt(p, 80, " dam %dd%d", 3 + ((plev - 1) / 4), 3 + plev / 15);
44 break;
45 }
46 case MINDCRAFT_PRECOGNITION:
47 {
48 break;
49 }
50 case MINDCRAFT_MINOR_DISPLACEMENT:
51 {
52 strnfmt(p, 80, " range %d", (plev < 40 ? 10 : plev + 2));
53 break;
54 }
55 case MINDCRAFT_MAJOR_DISPLACEMENT:
56 {
57 strnfmt(p, 80, " range %d", plev * 5);
58 break;
59 }
60 case MINDCRAFT_DOMINATION:
61 {
62 break;
63 }
64 case MINDCRAFT_PULVERISE:
65 {
66 strnfmt(p, 80, " dam %dd8", 8 + ((plev - 5) / 4));
67 break;
68 }
69 case MINDCRAFT_CHARACTER_ARMOUR:
70 {
71 strnfmt(p, 80, " dur %d", plev);
72 break;
73 }
74 case MINDCRAFT_PSYCHOMETRY:
75 {
76 break;
77 }
78 case MINDCRAFT_MIND_WAVE:
79 {
80 strnfmt(p, 80, " dam %d", plev * ((plev - 5) / 10 + 1));
81 break;
82 }
83 case MINDCRAFT_ADRENALINE_CHANNELING:
84 {
85 strnfmt(p, 80, " dur 11-%d", plev + plev / 2 + 10);
86 break;
87 }
88 case MINDCRAFT_PSYCHIC_DRAIN:
89 {
90 strnfmt(p, 80, " dam %dd6", plev / 2);
91 break;
92 }
93 case MINDCRAFT_TELEKINETIC_WAVE:
94 {
95 strnfmt(p, 80, " dam %d", plev * (plev > 39 ? 4 : 3));
96 break;
97 }
98 }
99 }
100
101
102 /*
103 * Allow user to choose a mindcrafter power.
104 *
105 * If a valid spell is chosen, saves it in '*sn' and returns TRUE
106 * If the user hits escape, returns FALSE, and set '*sn' to -1
107 * If there are no legal choices, returns FALSE, and sets '*sn' to -2
108 *
109 * The "prompt" should be "cast", "recite", or "study"
110 * The "known" should be TRUE for cast/pray, FALSE for study
111 *
112 * nb: This function has a (trivial) display bug which will be obvious
113 * when you run it. It's probably easy to fix but I haven't tried,
114 * sorry.
115 *
116 * What bug? -SF-
117 */
get_mindcraft_power(int * sn)118 static int get_mindcraft_power(int *sn)
119 {
120 int i;
121 int num = 0;
122 int y = 1;
123 int x = 20;
124 int minfail;
125 int plev = p_ptr->lev;
126 int chance;
127 int ask;
128 char choice;
129 char out_val[160];
130 char comment[80];
131 cptr p = "power";
132 mindcraft_power spell;
133 bool flag;
134
135 /* Assume cancelled */
136 *sn = (-1);
137
138 /* Get the spell, if available */
139 if (repeat_pull(sn))
140 {
141 /* Verify the spell */
142 if (mindcraft_powers[*sn].min_lev <= plev)
143 {
144 /* Success */
145 return (TRUE);
146 }
147 }
148
149 /* Nothing chosen yet */
150 flag = FALSE;
151
152 for (i = 0; i < MINDCRAFT_MAX; i++)
153 {
154 if (mindcraft_powers[i].min_lev <= plev)
155 {
156 num++;
157 }
158 }
159
160 /* Build a prompt (accept all spells) */
161 (void)strnfmt(out_val, 78, "(%^ss %c-%c, ESC=exit) Use which %s? ",
162 p, I2A(0), I2A(num - 1), p);
163
164 /* Save the screen */
165 screen_save();
166
167 /* Display a list of spells */
168 prtf(x, y, "");
169 put_fstr(x + 5, y, "Name");
170 put_fstr(x + 35, y, "Lv Mana Fail Info");
171
172 /* Dump the spells */
173 for (i = 0; i < MINDCRAFT_MAX; i++)
174 {
175 /* Access the spell */
176 spell = mindcraft_powers[i];
177 if (spell.min_lev > plev) break;
178
179 chance = spell.fail;
180
181 /* Reduce failure rate by "effective" level adjustment */
182 chance -= 3 * (plev - spell.min_lev);
183
184 /* Reduce failure rate by INT/WIS adjustment */
185 chance -= adj_mag_stat[p_ptr->stat[mp_ptr->spell_stat].ind] - 3;
186
187 /* Not enough mana to cast */
188 if (spell.mana_cost > p_ptr->csp)
189 {
190 chance += 5 * (spell.mana_cost - p_ptr->csp);
191 }
192
193 /* Extract the minimum failure rate */
194 minfail = adj_mag_fail[p_ptr->stat[mp_ptr->spell_stat].ind];
195
196 /* Minimum failure rate */
197 if (chance < minfail) chance = minfail;
198
199 /* Stunning makes spells harder */
200 if (p_ptr->tim.stun > 50) chance += 25;
201 else if (p_ptr->tim.stun) chance += 15;
202
203 /* Always a 5 percent chance of working */
204 if (chance > 95) chance = 95;
205
206 /* Get info */
207 mindcraft_info(comment, i);
208
209 /* Dump the spell --(-- */
210 prtf(x, y + i + 1, " %c) %-30s%2d %4d %3d%%%s",
211 I2A(i), spell.name,
212 spell.min_lev, spell.mana_cost, chance, comment);
213 }
214
215 /* Clear the bottom line */
216 prtf(x, y + i + 1, "");
217
218 /* Get a spell from the user */
219 while (!flag && get_com(out_val, &choice))
220 {
221 /* Note verify */
222 ask = isupper(choice);
223
224 /* Lowercase */
225 if (ask) choice = tolower(choice);
226
227 /* Extract request */
228 i = (islower(choice) ? A2I(choice) : -1);
229
230 /* Totally Illegal */
231 if ((i < 0) || (i >= num))
232 {
233 bell("Illegal mindcrafter power choice!");
234 continue;
235 }
236
237 /* Save the spell index */
238 spell = mindcraft_powers[i];
239
240 /* Verify it */
241 if (ask)
242 {
243 /* Belay that order */
244 if (!get_check("Use %s? ", mindcraft_powers[i].name)) continue;
245 }
246
247 /* Stop the loop */
248 flag = TRUE;
249 }
250
251 /* Restore the screen */
252 screen_load();
253
254 /* Show choices */
255 /* Update */
256 p_ptr->window |= (PW_SPELL);
257
258 /* Window stuff */
259 window_stuff();
260
261 /* Abort if needed */
262 if (!flag) return (FALSE);
263
264 /* Save the choice */
265 (*sn) = i;
266
267 repeat_push(*sn);
268
269 /* Success */
270 return (TRUE);
271 }
272
273
274 /*
275 * do_cmd_cast calls this function if the player's class
276 * is 'mindcrafter'.
277 */
cast_mindcrafter_spell(int spell)278 static bool cast_mindcrafter_spell(int spell)
279 {
280 int b;
281 int dir;
282 int plev = p_ptr->lev;
283
284
285 /* spell code */
286 switch (spell)
287 {
288 case MINDCRAFT_NEURAL_BLAST:
289 /* Mindblast */
290 if (!get_aim_dir(&dir)) return FALSE;
291
292 if (randint1(100) < plev * 2)
293 (void)fire_beam(GF_PSI, dir,
294 damroll(3 + ((plev - 1) / 4), (3 + plev / 15)));
295 else
296 (void)fire_ball(GF_PSI, dir,
297 damroll(3 + ((plev - 1) / 4), (3 + plev / 15)),
298 0);
299 break;
300 case MINDCRAFT_PRECOGNITION:
301 if (plev > 44)
302 wiz_lite();
303 else if (plev > 19)
304 map_area();
305
306 if (plev < 30)
307 {
308 b = detect_monsters_normal();
309 if (plev > 14)
310 b |= detect_monsters_invis();
311
312 if (plev > 4)
313 {
314 b |= detect_traps(TRUE);
315 b |= detect_doors();
316 }
317 }
318 else
319 {
320 b = detect_all();
321 }
322
323 if ((plev > 24) && (plev < 40))
324 {
325 (void)inc_tim_esp(plev);
326 }
327
328 if (!b) msgf("You feel safe.");
329 break;
330 case MINDCRAFT_MINOR_DISPLACEMENT:
331 /* Minor displace */
332 if (plev < 40)
333 {
334 teleport_player(10);
335 }
336 else
337 {
338 msgf("You open a dimensional gate. Choose a destination.");
339 return dimension_door();
340 }
341 break;
342 case MINDCRAFT_MAJOR_DISPLACEMENT:
343 /* Major displace */
344 if (plev > 29) (void)banish_monsters(plev);
345
346 teleport_player(plev * 5);
347 break;
348 case MINDCRAFT_DOMINATION:
349 /* Domination */
350 if (plev < 30)
351 {
352 if (!get_aim_dir(&dir)) return FALSE;
353
354 (void)fire_ball(GF_DOMINATION, dir, plev, 0);
355 }
356 else
357 {
358 (void)charm_monsters(plev * 2);
359 }
360 break;
361 case MINDCRAFT_PULVERISE:
362 /* Fist of Force --- not 'true' TK */
363 if (!get_aim_dir(&dir)) return FALSE;
364
365 (void)fire_ball(GF_SOUND, dir, damroll(8 + ((plev - 5) / 4), 8),
366 (plev > 20 ? (plev - 20) / 8 + 1 : 0));
367 break;
368 case MINDCRAFT_CHARACTER_ARMOUR:
369 /* Character Armour */
370 (void)inc_shield(plev);
371 if (plev > 16) (void)inc_oppose_acid(plev);
372 if (plev > 20) (void)inc_oppose_fire(plev);
373 if (plev > 24) (void)inc_oppose_cold(plev);
374 if (plev > 28) (void)inc_oppose_elec(plev);
375 if (plev > 32) (void)inc_oppose_pois(plev);
376 break;
377 case MINDCRAFT_PSYCHOMETRY:
378 /* Psychometry */
379 if (plev < 25)
380 return psychometry();
381 else
382 return ident_spell();
383 case MINDCRAFT_MIND_WAVE:
384 /* Mindwave */
385 msgf("Mind-warping forces emanate from your brain!");
386 if (plev < 25)
387 (void)project(0, 2 + plev / 10, p_ptr->px, p_ptr->py,
388 (plev * 3) / 2, GF_PSI, PROJECT_KILL);
389 else
390 (void)mindblast_monsters(plev * ((plev - 5) / 10 + 1));
391 break;
392 case MINDCRAFT_ADRENALINE_CHANNELING:
393 /* Adrenaline */
394 (void)clear_afraid();
395 (void)clear_stun();
396
397 /*
398 * Only heal when Adrenalin Channeling is not active. We check
399 * that by checking if the player isn't fast and 'heroed' atm.
400 */
401 if (!p_ptr->tim.fast || !(p_ptr->tim.hero || p_ptr->tim.shero))
402 {
403 (void)hp_player(plev);
404 }
405
406 b = 10 + randint1((plev * 3) / 2);
407 if (plev < 35)
408 (void)inc_hero(b);
409 else
410 (void)inc_shero(b);
411
412 /* Haste */
413 (void)inc_fast(b);
414
415 break;
416 case MINDCRAFT_PSYCHIC_DRAIN:
417 /* Psychic Drain */
418 if (!get_aim_dir(&dir)) return FALSE;
419
420 b = damroll(plev / 2, 6);
421
422 /* This is always a radius-0 ball now */
423 if (fire_ball(GF_PSI_DRAIN, dir, b, 0))
424 p_ptr->energy -= randint1(150);
425 break;
426 case MINDCRAFT_TELEKINETIC_WAVE:
427 /* Telekinesis */
428 msgf
429 ("A wave of pure physical force radiates out from your body!");
430 (void)project(0, 3 + plev / 10, p_ptr->px, p_ptr->py,
431 plev * (plev > 39 ? 4 : 3), GF_TELEKINESIS,
432 PROJECT_KILL | PROJECT_ITEM | PROJECT_GRID);
433 break;
434 default:
435 msgf("Unknown Mindcrafter power!");
436 }
437
438 return TRUE;
439 }
440
441
442 /*
443 * do_cmd_cast calls this function if the player's class
444 * is 'mindcrafter'.
445 */
do_cmd_mindcraft(void)446 void do_cmd_mindcraft(void)
447 {
448 int n = 0;
449 int chance;
450 int minfail;
451 int plev = p_ptr->lev;
452 int old_csp = p_ptr->csp;
453 mindcraft_power spell;
454 bool cast;
455
456
457 /* not if confused */
458 if (p_ptr->tim.confused)
459 {
460 msgf("You are too confused!");
461 return;
462 }
463
464 /* get power */
465 if (!get_mindcraft_power(&n)) return;
466
467 spell = mindcraft_powers[n];
468
469 /* Verify "dangerous" spells */
470 if (spell.mana_cost > p_ptr->csp)
471 {
472 /* Warning */
473 msgf("You do not have enough mana to use this power.");
474
475 /* Verify */
476 if (!get_check("Attempt it anyway? ")) return;
477 }
478
479 /* Spell failure chance */
480 chance = spell.fail;
481
482 /* Reduce failure rate by "effective" level adjustment */
483 chance -= 3 * (plev - spell.min_lev);
484
485 /* Reduce failure rate by INT/WIS adjustment */
486 chance -= adj_mag_stat[p_ptr->stat[mp_ptr->spell_stat].ind] - 3;
487
488 /* Not enough mana to cast */
489 if (spell.mana_cost > p_ptr->csp)
490 {
491 chance += 5 * (spell.mana_cost - p_ptr->csp);
492 }
493
494 /* Extract the minimum failure rate */
495 minfail = adj_mag_fail[p_ptr->stat[mp_ptr->spell_stat].ind];
496
497 /* Minimum failure rate */
498 if (chance < minfail) chance = minfail;
499
500 /* Stunning makes spells harder */
501 if (p_ptr->tim.stun > 50) chance += 25;
502 else if (p_ptr->tim.stun) chance += 15;
503
504 /* Always a 5 percent chance of working */
505 if (chance > 95) chance = 95;
506
507 /* Failed spell */
508 if (randint0(100) < chance)
509 {
510 if (flush_failure) flush();
511 msgf("You failed to concentrate hard enough!");
512 sound(SOUND_FAIL);
513
514 /* Backfire */
515 if (randint1(100) < (chance / 2))
516 {
517 int b = randint1(100);
518
519 if (b < 5)
520 {
521 msgf("Oh, no! Your mind has gone blank!");
522 (void)lose_all_info();
523 }
524 else if (b < 15)
525 {
526 msgf("Weird visions seem to dance before your eyes...");
527 (void)inc_image(rand_range(5, 15));
528 }
529 else if (b < 45)
530 {
531 msgf("Your brain is addled!");
532 (void)inc_confused(randint1(8));
533 }
534 else if (b < 90)
535 {
536 (void)inc_stun(randint1(8));
537 }
538 else
539 {
540 /* Mana storm */
541 msgf
542 ("Your mind unleashes its power in an uncontrollable storm!");
543 (void)project(1, 2 + plev / 10, p_ptr->px, p_ptr->py, plev * 2,
544 GF_MANA,
545 PROJECT_JUMP | PROJECT_KILL | PROJECT_GRID |
546 PROJECT_ITEM);
547 p_ptr->csp = MAX(0, p_ptr->csp - plev * MAX(1, plev / 10));
548 }
549 }
550 }
551 else
552 {
553 sound(SOUND_ZAP);
554
555 /* Cast the spell */
556 cast = cast_mindcrafter_spell(n);
557
558 if (!cast) return;
559 }
560
561 /* Take a turn */
562 p_ptr->state.energy_use = 100;
563
564 /* Sufficient mana */
565 if (spell.mana_cost <= old_csp)
566 {
567 /* Use some mana */
568 p_ptr->csp -= spell.mana_cost;
569
570 /* Limit */
571 if (p_ptr->csp < 0) p_ptr->csp = 0;
572 }
573
574 /* Over-exert the player */
575 else
576 {
577 int oops = spell.mana_cost - old_csp;
578
579 /* No mana left */
580 p_ptr->csp = 0;
581 p_ptr->csp_frac = 0;
582
583 /* Message */
584 msgf("You faint from the effort!");
585
586 /* Hack -- Bypass free action */
587 (void)inc_paralyzed(randint1(5 * oops + 1));
588
589 /* Damage WIS (possibly permanently) */
590 if (randint0(100) < 50)
591 {
592 bool perm = (randint0(100) < 25);
593
594 /* Message */
595 msgf("You have damaged your mind!");
596
597 /* Reduce constitution */
598 (void)dec_stat(A_WIS, rand_range(15, 25), perm);
599 }
600 }
601
602 /* Redraw mana */
603 p_ptr->redraw |= (PR_MANA);
604
605 /* Window stuff */
606 p_ptr->window |= (PW_PLAYER);
607 p_ptr->window |= (PW_SPELL);
608 }
609