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