/* File: cmd5.c */ /* Purpose: Class commands */ /* * Copyright (c) 1989 James E. Wilson, Robert A. Koeneke * * This software may be copied and distributed for educational, research, and * not for profit purposes provided that this copyright and statement are * included in all such copies. */ #include "angband.h" #include "lua/lua.h" #include "tolua.h" #include extern lua_State *L; /* Maximum number of tries for teleporting */ #define MAX_TRIES 300 bool_ is_school_book(object_type *o_ptr) { if (o_ptr->tval == TV_BOOK) { return TRUE; } else if (o_ptr->tval == TV_DAEMON_BOOK) { return TRUE; } else if (o_ptr->tval == TV_INSTRUMENT) { return TRUE; } else { return FALSE; } } /* Does it contains a schooled spell ? */ static bool_ hook_school_spellable(object_type *o_ptr) { if (is_school_book(o_ptr)) return TRUE; else { u32b f1, f2, f3, f4, f5, esp; /* Extract object flags */ object_flags(o_ptr, &f1, &f2, &f3, &f4, &f5, &esp); if ((f5 & TR5_SPELL_CONTAIN) && (o_ptr->pval2 != -1)) return TRUE; } return FALSE; } /* Is it a book */ bool_ item_tester_hook_browsable(object_type *o_ptr) { if (hook_school_spellable(o_ptr)) return TRUE; if (o_ptr->tval >= TV_BOOK) return TRUE; return FALSE; } /* * Are we using a mage staff */ bool_ is_magestaff() { int i; i = 0; while (p_ptr->body_parts[i] == INVEN_WIELD) { object_type *o_ptr = &p_ptr->inventory[INVEN_WIELD + i]; /* Wielding a mage staff */ if ((o_ptr->k_idx) && (o_ptr->tval == TV_MSTAFF)) return (TRUE); /* Next slot */ i++; /* Paranoia */ if (i >= (INVEN_TOTAL - INVEN_WIELD)) break; } /* Not wielding a mage staff */ return (FALSE); } /* * Peruse the spells/prayers in a book * * Note that *all* spells in the book are listed * * Note that browsing is allowed while confused or blind, * and in the dark, primarily to allow browsing in stores. */ extern void do_cmd_browse_aux(object_type *o_ptr) { u32b f1, f2, f3, f4, f5, esp; object_flags(o_ptr, &f1, &f2, &f3, &f4, &f5, &esp); if (is_school_book(o_ptr)) browse_school_spell(o_ptr->sval, o_ptr->pval, o_ptr); else if (f5 & TR5_SPELL_CONTAIN && o_ptr->pval2 != -1) browse_school_spell(255, o_ptr->pval2, o_ptr); } void do_cmd_browse(void) { int item; cptr q, s; object_type *o_ptr; /* Restrict choices to "useful" books */ item_tester_hook = item_tester_hook_browsable; /* Get an item */ q = "Browse which book? "; s = "You have no books that you can read."; if (!get_item(&item, q, s, (USE_INVEN | USE_EQUIP | USE_FLOOR))) return; /* Get the item */ o_ptr = get_object(item); do_cmd_browse_aux(o_ptr); } void do_poly_wounds(void) { /* Changed to always provide at least _some_ healing */ s16b wounds = p_ptr->cut; s16b hit_p = (p_ptr->mhp - p_ptr->chp); s16b change = damroll(p_ptr->lev, 5); bool_ Nasty_effect = (randint(5) == 1); if (!(wounds || hit_p || Nasty_effect)) return; msg_print("Your wounds are polymorphed into less serious ones."); hp_player(change); if (Nasty_effect) { msg_print("A new wound was created!"); take_hit(change / 2, "a polymorphed wound"); set_cut(change); } else { set_cut((p_ptr->cut) - (change / 2)); } } void do_poly_self(void) { int power = p_ptr->lev; int poly_power; msg_print("You feel a change coming over you..."); if ((power > rand_int(20)) && (rand_int(3) == 0)) { char effect_msg[80] = ""; int new_race, expfact, goalexpfact; /* Some form of racial polymorph... */ power -= 10; if ((power > rand_int(5)) && (rand_int(4) == 0)) { /* sex change */ power -= 2; if (p_ptr->psex == SEX_MALE) { p_ptr->psex = SEX_FEMALE; sp_ptr = &sex_info[p_ptr->psex]; strcpy(effect_msg, "female"); } else { p_ptr->psex = SEX_MALE; sp_ptr = &sex_info[p_ptr->psex]; strcpy(effect_msg, "male"); } } if ((power > rand_int(30)) && (rand_int(5) == 0)) { int tmp = 0; /* Harmful deformity */ power -= 15; while (tmp < 6) { if ( rand_int(2) == 0) { (void)dec_stat(tmp, randint(6) + 6, (rand_int(3) == 0)); power -= 1; } tmp++; } /* Deformities are discriminated against! */ (void)dec_stat(A_CHR, randint(6), TRUE); if (effect_msg[0]) { char tmp_msg[10]; strnfmt(tmp_msg, 10, "%s", effect_msg); strnfmt(effect_msg, 80, "deformed %s", tmp_msg); } else { strcpy(effect_msg, "deformed"); } } while ((power > rand_int(20)) && (rand_int(10) == 0)) { /* Polymorph into a less corrupted form */ power -= 10; lose_corruption(); } /* * I'm not sure 'power' is always positive, with *so* many minuses. * Also, passing zero / negative numbers to randint/rand_int can * cause a zero divide exception, IIRC, not to speak of its absurdity * -- pelpel */ poly_power = (power > 1) ? power : 1; /* * Restrict the race choices by exp penalty so weak polymorph * always means weak race */ goalexpfact = 100 + 3 * rand_int(poly_power); /* Roll until an appropriate selection is made */ while (1) { new_race = rand_int(max_rp_idx); expfact = race_info[new_race].r_exp; if ((new_race != p_ptr->prace) && (expfact <= goalexpfact)) break; } if (effect_msg[0]) { msg_format("You turn into a%s %s!", ((is_a_vowel(rp_name[race_info[new_race].title])) ? "n" : ""), race_info[new_race].title + rp_name); } else { msg_format("You turn into a %s %s!", effect_msg, race_info[new_race].title); } p_ptr->prace = new_race; rp_ptr = &race_info[p_ptr->prace]; /* Experience factor */ p_ptr->expfact = rp_ptr->r_exp + rmp_ptr->r_exp + cp_ptr->c_exp; /* Calculate the height/weight */ get_height_weight(); check_experience(); p_ptr->max_plv = p_ptr->lev; p_ptr->redraw |= (PR_BASIC); p_ptr->update |= (PU_BONUS); handle_stuff(); lite_spot(p_ptr->py, p_ptr->px); } if ((power > rand_int(30)) && (rand_int(6) == 0)) { int tmp = 0; /* Abomination! */ power -= 20; msg_print("Your internal organs are rearranged!"); while (tmp < 6) { (void)dec_stat(tmp, randint(6) + 6, (rand_int(3) == 0)); tmp++; } if (rand_int(6) == 0) { msg_print("You find living difficult in your present form!"); take_hit(damroll(randint(10), p_ptr->lev), "a lethal corruption"); power -= 10; } } if ((power > rand_int(20)) && (rand_int(4) == 0)) { power -= 10; do_cmd_rerate(); } while ((power > rand_int(15)) && (rand_int(3) == 0)) { power -= 7; (void) gain_random_corruption(0); } if (power > rand_int(5)) { power -= 5; do_poly_wounds(); } /* Note: earlier deductions may have left power < 0 already. */ while (power > 0) { corrupt_player(); power--; } } /* * Brand the current weapon */ void brand_weapon(int brand_type) { object_type *o_ptr; cptr act = NULL; char o_name[80]; o_ptr = &p_ptr->inventory[INVEN_WIELD]; /* * You can never modify artifacts / ego-items * You can never modify cursed items * * TY: You _can_ modify broken items (if you're silly enough) */ if (!o_ptr->k_idx || artifact_p(o_ptr) || ego_item_p(o_ptr) || o_ptr->art_name || cursed_p(o_ptr)) { if (flush_failure) flush(); msg_print("The Branding failed."); return; } /* Save the old name */ object_desc(o_name, o_ptr, FALSE, 0); switch (brand_type) { case 6: { act = "glows with godly power."; o_ptr->name2 = EGO_BLESS_BLADE; o_ptr->pval = randint(4); break; } case 5: { act = "seems very powerful."; o_ptr->name2 = EGO_EARTHQUAKES; o_ptr->pval = randint(3); break; } case 4: { act = "seems very unstable now."; o_ptr->name2 = EGO_DRAGON; o_ptr->pval = randint(2); break; } case 3: { act = "thirsts for blood!"; o_ptr->name2 = EGO_VAMPIRIC; break; } case 2: { act = "is coated with poison."; o_ptr->name2 = EGO_BRAND_POIS; break; } case 1: { act = "is engulfed in raw chaos!"; o_ptr->name2 = EGO_CHAOTIC; break; } default: { if (rand_int(100) < 25) { act = "is covered in a fiery shield!"; o_ptr->name2 = EGO_BRAND_FIRE; } else { act = "glows deep, icy blue!"; o_ptr->name2 = EGO_BRAND_COLD; } } } /* Apply the ego */ apply_magic(o_ptr, dun_level, FALSE, FALSE, FALSE); o_ptr->discount = 100; msg_format("Your %s %s", o_name, act); enchant(o_ptr, rand_int(3) + 4, ENCH_TOHIT | ENCH_TODAM); } /* * Fetch an item (teleport it right underneath the caster) */ void fetch(int dir, int wgt, bool_ require_los) { int ty, tx, i; cave_type *c_ptr; object_type *o_ptr; char o_name[80]; /* Check to see if an object is already there */ if (cave[p_ptr->py][p_ptr->px].o_idx) { msg_print("You can't fetch when you're already standing on something."); return; } /* Use a target */ if ((dir == 5) && target_okay()) { tx = target_col; ty = target_row; if (distance(p_ptr->py, p_ptr->px, ty, tx) > MAX_RANGE) { msg_print("You can't fetch something that far away!"); return; } c_ptr = &cave[ty][tx]; if (!c_ptr->o_idx) { msg_print("There is no object at this place."); return; } if (require_los && (!player_has_los_bold(ty, tx))) { msg_print("You have no direct line of sight to that location."); return; } } else { /* Use a direction */ ty = p_ptr->py; /* Where to drop the item */ tx = p_ptr->px; while (1) { ty += ddy[dir]; tx += ddx[dir]; c_ptr = &cave[ty][tx]; if ((distance(p_ptr->py, p_ptr->px, ty, tx) > MAX_RANGE) || !cave_floor_bold(ty, tx)) return; if (c_ptr->o_idx) break; } } o_ptr = &o_list[c_ptr->o_idx]; if (o_ptr->weight > wgt) { /* Too heavy to 'fetch' */ msg_print("The object is too heavy."); return; } i = c_ptr->o_idx; c_ptr->o_idx = o_ptr->next_o_idx; cave[p_ptr->py][p_ptr->px].o_idx = i; /* 'move' it */ o_ptr->next_o_idx = 0; o_ptr->iy = p_ptr->py; o_ptr->ix = p_ptr->px; object_desc(o_name, o_ptr, TRUE, 0); msg_format("%^s flies through the air to your feet.", o_name); note_spot(p_ptr->py, p_ptr->px); p_ptr->redraw |= PR_MAP; } /* * Handle random effects of player shrieking */ void shriek_effect() { switch (randint(9)) { case 1: case 5: case 8: case 9: { msg_print("You make a high-pitched shriek!"); aggravate_monsters(1); break; } case 2: case 6: { msg_print("Oops! You call a monster."); summon_specific(p_ptr->py, p_ptr->px, max_dlv[dungeon_type], 0); break; } case 3: case 7: { msg_print("The dungeon collapses!"); earthquake(p_ptr->py, p_ptr->px, 5); break; } case 4: { msg_print("Your shriek is so horrible that you damage your health!"); take_hit(damroll(p_ptr->lev / 5, 8), "inner hemorrhaging"); break; } } } /* * Like all the random effect codes, this is *ugly*, * and there is not a single line of comment, so I can't tell * some fall throughs are really intended. Well, I know it's * intended to be bizarre :) -- pelpel */ void wild_magic(int spell) { int counter = 0; int type = SUMMON_BIZARRE1 - 1 + randint(6); if (type < SUMMON_BIZARRE1) type = SUMMON_BIZARRE1; else if (type > SUMMON_BIZARRE6) type = SUMMON_BIZARRE6; switch (randint(spell) + randint(8) + 1) { case 1: case 2: case 3: { teleport_player(10); break; } case 4: case 5: case 6: { teleport_player(100); break; } case 7: case 8: { teleport_player(200); break; } case 9: case 10: case 11: { unlite_area(10, 3); break; } case 12: case 13: case 14: { lite_area(damroll(2, 3), 2); break; } case 15: { destroy_doors_touch(); break; } case 16: case 17: { wall_breaker(); /* I don't think this is a fall through -- pelpel */ break; } case 18: { sleep_monsters_touch(); break; } case 19: case 20: { trap_creation(); break; } case 21: case 22: { door_creation(); break; } case 23: case 24: case 25: { aggravate_monsters(1); break; } case 26: { /* Prevent destruction of quest levels and town */ if (!is_quest(dun_level) && dun_level) earthquake(p_ptr->py, p_ptr->px, 5); break; } case 27: case 28: { break; } case 29: case 30: { apply_disenchant(0); break; } case 31: { lose_all_info(); break; } case 32: { fire_ball(GF_CHAOS, 0, spell + 5, 1 + (spell / 10)); break; } case 33: { wall_stone(p_ptr->py, p_ptr->px); break; } case 34: case 35: { while (counter++ < 8) { (void) summon_specific(p_ptr->py, p_ptr->px, (dun_level * 3) / 2, type); } break; } case 36: case 37: { activate_hi_summon(); break; } case 38: { summon_cyber(); /* I don't think this is a fall through -- pelpel */ break; } default: { activate_ty_curse(); } } return; } /* * Hack -- Determine if the player is wearing an artefact ring * specified by art_type, that should be an index into a_info */ bool_ check_ring(int art_type) { int i; /* We are only interested in ring slots */ i = INVEN_RING; /* Scan the list of rings until we reach the end */ while (p_ptr->body_parts[i - INVEN_WIELD] == INVEN_RING) { /* Found the ring we were looking for */ if (p_ptr->inventory[i].k_idx && (p_ptr->inventory[i].name1 == art_type)) { return (TRUE); } /* Next item */ i++; } /* Found nothing */ return (FALSE); } /* * Return the symbiote's name or description. */ cptr symbiote_name(bool_ capitalize) { object_type *o_ptr = &p_ptr->inventory[INVEN_CARRY]; static char buf[80]; /* Make sure there actually is a symbiote there... */ if (!o_ptr->k_idx) { strcpy(buf, "A non-existent symbiote"); } else { monster_race *r_ptr = &r_info[o_ptr->pval]; cptr s = NULL; if (r_ptr->flags1 & RF1_UNIQUE) { /* Unique monster; no preceding "your", and ignore our name. */ strncpy(buf, r_name + r_ptr->name, sizeof(buf)); } else if (o_ptr->note && (s = strstr(quark_str(o_ptr->note), "#named ")) != NULL) { /* We've named it. */ strncpy(buf, s + 7, sizeof(buf)); } else { /* No special cases, just return "Your ". */ strcpy(buf, "your "); strncpy(buf + 5, r_name + r_ptr->name, sizeof(buf) - 5); } } /* Just in case... */ buf[sizeof(buf) - 1] = '\0'; if (capitalize) buf[0] = toupper(buf[0]); return buf; } /* * Use a power of the monster in symbiosis */ int use_symbiotic_power(int r_idx, bool_ great, bool_ only_number, bool_ no_cost) { int power = -1; int num = 0, dir = 0 , i; int powers[96]; bool_ flag, redraw; int ask, plev = p_ptr->lev; char choice; char out_val[160]; monster_race *r_ptr = &r_info[r_idx]; int rlev = ((r_ptr->level >= 1) ? r_ptr->level : 1); int x = p_ptr->px, y = p_ptr->py, k; int rad; int label; /* List the monster powers -- RF4_* */ for (i = 0; i < 32; i++) { if (r_ptr->flags4 & BIT(i)) { if (monster_powers[i].great && (!great)) continue; if (!monster_powers[i].power) continue; powers[num++] = i; } } /* List the monster powers -- RF5_* */ for (i = 0; i < 32; i++) { if (r_ptr->flags5 & BIT(i)) { if (monster_powers[i + 32].great && (!great)) continue; if (!monster_powers[i + 32].power) continue; powers[num++] = i + 32; } } /* List the monster powers -- RF6_* */ for (i = 0; i < 32; i++) { if (r_ptr->flags6 & BIT(i)) { if (monster_powers[i + 64].great && (!great)) continue; if (!monster_powers[i + 64].power) continue; powers[num++] = i + 64; } } if (!num) { msg_print("You have no powers you can use."); return (0); } if (only_number) return (num); /* Nothing chosen yet */ flag = FALSE; /* No redraw yet */ redraw = FALSE; /* Get the last label */ label = (num <= 26) ? I2A(num - 1) : I2D(num - 1 - 26); /* Build a prompt (accept all spells) */ /* Mega Hack -- if no_cost is false, we're actually a Possessor -dsb */ strnfmt(out_val, 78, "(Powers a-%c, *=List, ESC=exit) Use which power of your %s? ", label, (no_cost ? "symbiote" : "body")); /* Get a spell from the user */ while (!flag && get_com(out_val, &choice)) { /* Request redraw */ if ((choice == ' ') || (choice == '*') || (choice == '?')) { /* Show the list */ if (!redraw) { byte y = 1, x = 0; int ctr = 0; char dummy[80]; strcpy(dummy, ""); /* Show list */ redraw = TRUE; /* Save the screen */ character_icky = TRUE; Term_save(); prt ("", y++, x); while (ctr < num) { monster_power *mp_ptr = &monster_powers[powers[ctr]]; int mana = mp_ptr->mana / 10; if (mana > p_ptr->msp) mana = p_ptr->msp; if (!mana) mana = 1; label = (ctr < 26) ? I2A(ctr) : I2D(ctr - 26); if (!no_cost) { strnfmt(dummy, 80, " %c) %2d %s", label, mana, mp_ptr->name); } else { strnfmt(dummy, 80, " %c) %s", label, mp_ptr->name); } if (ctr < 17) { prt(dummy, y + ctr, x); } else { prt(dummy, y + ctr - 17, x + 40); } ctr++; } if (ctr < 17) { prt ("", y + ctr, x); } else { prt ("", y + 17, x); } } /* Hide the list */ else { /* Hide list */ redraw = FALSE; /* Restore the screen */ Term_load(); character_icky = FALSE; } /* Redo asking */ continue; } if (choice == '\r' && num == 1) { choice = 'a'; } if (isalpha(choice)) { /* Note verify */ ask = (isupper(choice)); /* Lowercase */ if (ask) choice = tolower(choice); /* Extract request */ i = (islower(choice) ? A2I(choice) : -1); } else { /* Can't uppercase digits XXX XXX XXX */ ask = FALSE; i = choice - '0' + 26; } /* Totally Illegal */ if ((i < 0) || (i >= num)) { bell(); continue; } /* Save the spell index */ power = powers[i]; /* Verify it */ if (ask) { char tmp_val[160]; /* Prompt */ strnfmt(tmp_val, 78, "Use %s? ", monster_powers[power].name); /* Belay that order */ if (!get_check(tmp_val)) continue; } /* Stop the loop */ flag = TRUE; } /* Restore the screen */ if (redraw) { Term_load(); character_icky = FALSE; } /* Abort if needed */ if (!flag) { energy_use = 0; return -1; } /* 'Powerful' monsters have wider radii */ if (r_ptr->flags2 & RF2_POWERFUL) { rad = 1 + (p_ptr->lev / 15); } else { rad = 1 + (p_ptr->lev / 20); } /* Analyse power */ switch (power) { /**** RF4 (bit position) ****/ /* SHRIEK */ case 0: { aggravate_monsters( -1); break; } /* MULTIPLY */ case 1: { do_cmd_wiz_named_friendly(p_ptr->body_monster, FALSE); break; } /* S_ANIMAL */ case 2: { summon_specific_friendly(y, x, rlev, SUMMON_ANIMAL, TRUE); break; } /* ROCKET */ case 3: { if (!get_aim_dir(&dir)) break; fire_ball(GF_ROCKET, dir, p_ptr->lev * 12, 1 + (p_ptr->lev / 20)); break; } /* ARROW_1 */ case 4: { if (!get_aim_dir(&dir)) break; fire_bolt(GF_ARROW, dir, damroll(1, 6)); break; } /* ARROW_2 */ case 5: { if (!get_aim_dir(&dir)) break; fire_bolt(GF_ARROW, dir, damroll(3, 6)); break; } /* ARROW_3 */ case 6: { if (!get_aim_dir(&dir)) break; fire_bolt(GF_ARROW, dir, damroll(5, 6)); break; } /* ARROW_4 */ case 7: { if (!get_aim_dir(&dir)) break; fire_bolt(GF_ARROW, dir, damroll(7, 6)); break; } /* BR_ACID */ case 8: { if (!get_aim_dir(&dir)) break; fire_ball(GF_ACID, dir, p_ptr->lev * 5, rad); break; } /* BR_ELEC */ case 9: { if (!get_aim_dir(&dir)) break; fire_ball(GF_ELEC, dir, p_ptr->lev * 5, rad); break; } /* BR_FIRE */ case 10: { if (!get_aim_dir(&dir)) break; fire_ball(GF_FIRE, dir, p_ptr->lev * 5, rad); break; } /* BR_COLD */ case 11: { if (!get_aim_dir(&dir)) break; fire_ball(GF_COLD, dir, p_ptr->lev * 5, rad); break; } /* BR_POIS */ case 12: { if (!get_aim_dir(&dir)) break; fire_ball(GF_POIS, dir, p_ptr->lev * 5, rad); break; } /* BR_NETH */ case 13: { if (!get_aim_dir(&dir)) break; fire_ball(GF_NETHER, dir, p_ptr->lev * 5, rad); break; } /* BR_LITE */ case 14: { if (!get_aim_dir(&dir)) break; fire_ball(GF_LITE, dir, p_ptr->lev * 8, rad); break; } /* BR_DARK */ case 15: { if (!get_aim_dir(&dir)) break; fire_ball(GF_DARK, dir, p_ptr->lev * 8, rad); break; } /* BR_CONF */ case 16: { if (!get_aim_dir(&dir)) break; fire_ball(GF_CONFUSION, dir, p_ptr->lev * 8, rad); break; } /* BR_SOUN */ case 17: { if (!get_aim_dir(&dir)) break; fire_ball(GF_SOUND, dir, p_ptr->lev * 8, rad); break; } /* BR_CHAO */ case 18: { if (!get_aim_dir(&dir)) break; fire_ball(GF_CHAOS, dir, p_ptr->lev * 7, rad); break; } /* BR_DISE */ case 19: { if (!get_aim_dir(&dir)) break; fire_ball(GF_DISENCHANT, dir, p_ptr->lev * 7, rad); break; } /* BR_NEXU */ case 20: { if (!get_aim_dir(&dir)) break; fire_ball(GF_NEXUS, dir, p_ptr->lev * 5, rad); break; } /* BR_TIME */ case 21: { if (!get_aim_dir(&dir)) break; fire_ball(GF_TIME, dir, p_ptr->lev * 3, rad); break; } /* BR_INER */ case 22: { if (!get_aim_dir(&dir)) break; fire_ball(GF_INERTIA, dir, p_ptr->lev * 4, rad); break; } /* BR_GRAV */ case 23: { if (!get_aim_dir(&dir)) break; fire_ball(GF_GRAVITY, dir, p_ptr->lev * 4, rad); break; } /* BR_SHAR */ case 24: { if (!get_aim_dir(&dir)) break; fire_ball(GF_SHARDS, dir, p_ptr->lev * 8, rad); break; } /* BR_PLAS */ case 25: { if (!get_aim_dir(&dir)) break; fire_ball(GF_PLASMA, dir, p_ptr->lev * 3, rad); break; } /* BR_WALL */ case 26: { if (!get_aim_dir(&dir)) break; fire_ball(GF_FORCE, dir, p_ptr->lev * 4, rad); break; } /* BR_MANA */ case 27: { if (!get_aim_dir(&dir)) break; fire_ball(GF_MANA, dir, p_ptr->lev * 5, rad); break; } /* BA_NUKE */ case 28: { if (!get_aim_dir(&dir)) break; fire_ball(GF_NUKE, dir, p_ptr->lev * 8, 1 + (p_ptr->lev / 20)); break; } /* BR_NUKE */ case 29: { if (!get_aim_dir(&dir)) break; fire_ball(GF_NUKE, dir, p_ptr->lev * 8, 1 + (p_ptr->lev / 20)); break; } /* BA_CHAO */ case 30: { if (!get_aim_dir(&dir)) break; fire_ball(GF_CHAOS, dir, p_ptr->lev * 4, 2); break; } /* BR_DISI */ case 31: { if (!get_aim_dir(&dir)) break; fire_ball(GF_DISINTEGRATE, dir, p_ptr->lev * 5, 1 + (p_ptr->lev / 20)); break; } /**** RF5 (bit position + 32) ****/ /* BA_ACID */ case 32: { if (!get_aim_dir(&dir)) break; fire_ball(GF_ACID, dir, randint(p_ptr->lev * 6) + 20, 2); break; } /* BA_ELEC */ case 33: { if (!get_aim_dir(&dir)) break; fire_ball(GF_ELEC, dir, randint(p_ptr->lev * 3) + 20, 2); break; } /* BA_FIRE */ case 34: { if (!get_aim_dir(&dir)) break; fire_ball(GF_FIRE, dir, randint(p_ptr->lev * 7) + 20, 2); break; } /* BA_COLD */ case 35: { if (!get_aim_dir(&dir)) break; fire_ball(GF_COLD, dir, randint(p_ptr->lev * 3) + 20, 2); break; } /* BA_POIS */ case 36: { if (!get_aim_dir(&dir)) break; fire_ball(GF_POIS, dir, damroll(12, 2), 2); break; } /* BA_NETH */ case 37: { if (!get_aim_dir(&dir)) break; fire_ball(GF_NETHER, dir, randint(p_ptr->lev * 4) + 20, 2); break; } /* BA_WATE */ case 38: { if (!get_aim_dir(&dir)) break; fire_ball(GF_WATER, dir, randint(p_ptr->lev * 4) + 20, 2); break; } /* BA_MANA */ case 39: { if (!get_aim_dir(&dir)) break; fire_ball(GF_MANA, dir, randint(p_ptr->lev * 3) + 20, 2); break; } /* BA_DARK */ case 40: { if (!get_aim_dir(&dir)) break; fire_ball(GF_DARK, dir, randint(p_ptr->lev * 3) + 20, 2); break; } /* 41 DRAIN_MANA -- Not available */ /* 42 MIND_BLAST -- Not available */ /* 43 BRAIN_SMASH -- Not available */ /* CAUSE_1 */ case 44: { if (!get_aim_dir(&dir)) break; fire_bolt(GF_MANA, dir, damroll(3, 8)); break; } /* CAUSE_2 */ case 45: { if (!get_aim_dir(&dir)) break; fire_bolt(GF_MANA, dir, damroll(8, 8)); break; } /* CAUSE_3 */ case 46: { if (!get_aim_dir(&dir)) break; fire_bolt(GF_MANA, dir, damroll(10, 15)); break; } /* CAUSE_4 */ case 47: { if (!get_aim_dir(&dir)) break; fire_bolt(GF_MANA, dir, damroll(15, 15)); break; } /* BO_ACID */ case 48: { if (!get_aim_dir(&dir)) break; fire_bolt(GF_ACID, dir, damroll(7, 8) + (p_ptr->lev / 3)); break; } /* BO_ELEC */ case 49: { if (!get_aim_dir(&dir)) break; fire_bolt(GF_ELEC, dir, damroll(4, 8) + (p_ptr->lev / 3)); break; } /* BO_FIRE */ case 50: { if (!get_aim_dir(&dir)) break; fire_bolt(GF_FIRE, dir, damroll(9, 8) + (p_ptr->lev / 3)); break; } /* BO_COLD */ case 51: { if (!get_aim_dir(&dir)) break; fire_bolt(GF_COLD, dir, damroll(6, 8) + (p_ptr->lev / 3)); break; } /* BO_POIS */ case 52: { if (!get_aim_dir(&dir)) break; fire_bolt(GF_POIS, dir, damroll(7, 8) + (p_ptr->lev / 3)); break; } /* BO_NETH */ case 53: { if (!get_aim_dir(&dir)) break; fire_bolt(GF_NETHER, dir, damroll(5, 5) + (p_ptr->lev / 3)); break; } /* BO_WATE */ case 54: { if (!get_aim_dir(&dir)) break; fire_bolt(GF_WATER, dir, damroll(10, 10) + (p_ptr->lev / 3)); break; } /* BO_MANA */ case 55: { if (!get_aim_dir(&dir)) break; fire_bolt(GF_MANA, dir, damroll(3, 8) + (p_ptr->lev / 3)); break; } /* BO_PLAS */ case 56: { if (!get_aim_dir(&dir)) break; fire_bolt(GF_PLASMA, dir, damroll(8, 8) + (p_ptr->lev / 3)); break; } /* BO_ICEE */ case 57: { if (!get_aim_dir(&dir)) break; fire_bolt(GF_ICE, dir, damroll(6, 6) + (p_ptr->lev / 3)); break; } /* MISSILE */ case 58: { if (!get_aim_dir(&dir)) break; fire_bolt(GF_MISSILE, dir, damroll(2, 6) + (p_ptr->lev / 3)); break; } /* SCARE */ case 59: { if (!get_aim_dir(&dir)) break; fear_monster(dir, plev); break; } /* BLIND */ case 60: { if (!get_aim_dir(&dir)) break; fire_bolt(GF_CONFUSION, dir, damroll(1, 8) + (p_ptr->lev / 3)); break; } /* CONF */ case 61: { if (!get_aim_dir(&dir)) break; fire_bolt(GF_CONFUSION, dir, damroll(7, 8) + (p_ptr->lev / 3)); break; } /* SLOW */ case 62: { if (!get_aim_dir(&dir)) break; fire_bolt(GF_OLD_SLOW, dir, damroll(6, 8) + (p_ptr->lev / 3)); break; } /* HOLD */ case 63: { if (!get_aim_dir(&dir)) break; fire_bolt(GF_OLD_SLEEP, dir, damroll(5, 8) + (p_ptr->lev / 3)); break; } /**** RF6 (bit position + 64) ****/ /* HASTE */ case 64: { if (!p_ptr->fast) { (void)set_fast(randint(20 + (plev) ) + plev, 10); } else { (void)set_fast(p_ptr->fast + randint(5), 10); } break; } /* HAND_DOOM */ case 65: { if (!get_aim_dir(&dir)) break; fire_bolt(GF_MANA, dir, damroll(10, 8) + (p_ptr->lev)); break; } /* HEAL */ case 66: { hp_player(damroll(8, 5)); break; } /* S_ANIMALS */ case 67: { for (k = 0; k < 4; k++) { summon_specific_friendly(y, x, rlev, SUMMON_ANIMAL, TRUE); } break; } /* BLINK */ case 68: { if (dungeon_flags2 & DF2_NO_TELEPORT) { msg_print("No teleport on special levels..."); break; } teleport_player(10); break; } /* TPORT */ case 69: { if (dungeon_flags2 & DF2_NO_TELEPORT) { msg_print("No teleport on special levels..."); break; } teleport_player(plev * 5); break; } /* TELE_TO */ case 70: { int ii, ij; if (dungeon_flags2 & DF2_NO_TELEPORT) { msg_print("No teleport on special levels..."); break; } msg_print("You go between."); if (!tgt_pt(&ii, &ij)) break; p_ptr->energy -= 60 - plev; if (!cave_empty_bold(ij, ii) || (cave[ij][ii].info & CAVE_ICKY) || (distance(ij, ii, p_ptr->py, p_ptr->px) > plev * 20 + 2)) { msg_print("You fail to show the destination correctly!"); p_ptr->energy -= 100; teleport_player(10); } else teleport_player_to(ij, ii); break; } /* TELE_AWAY */ case 71: { if (dungeon_flags2 & DF2_NO_TELEPORT) { msg_print("No teleport on special levels..."); break; } if (!get_aim_dir(&dir)) break; (void)fire_beam(GF_AWAY_ALL, dir, plev); break; } /* TELE_LEVEL */ case 72: { if (dungeon_flags2 & DF2_NO_TELEPORT) { msg_print("No teleport on special levels..."); break; } teleport_player_level(); break; } /* DARKNESS */ case 73: { (void)project( -1, 3, p_ptr->py, p_ptr->px, 0, GF_DARK_WEAK, PROJECT_GRID | PROJECT_KILL); /* Unlite the room */ unlite_room(p_ptr->py, p_ptr->px); break; } /* TRAPS */ case 74: { trap_creation(); break; } /* 75 FORGET -- Not available */ /* ANIM_DEAD -- Use the same code as the nether spell */ case 76: { if (!get_aim_dir(&dir)) break; fire_ball(GF_RAISE, dir, 1, 0); break; } /* 77 S_BUG -- Not available, well we do that anyway ;) */ /* 78 S_RNG -- Not available, who dares? */ /* S_THUNDERLORD */ case 79: { for (k = 0; k < 1; k++) { summon_specific_friendly(y, x, rlev, SUMMON_THUNDERLORD, TRUE); } break; } /* S_KIN -- Summon Kin, because we code bugs :) */ case 80: { /* Big hack */ summon_kin_type = r_ptr->d_char; for (k = 0; k < 6; k++) { summon_specific_friendly(y, x, rlev, SUMMON_KIN, TRUE); } break; } /* S_HI_DEMON */ case 81: { for (k = 0; k < 1; k++) { summon_specific_friendly(y, x, rlev, SUMMON_HI_DEMON, TRUE); } break; } /* S_MONSTER */ case 82: { for (k = 0; k < 1; k++) { summon_specific_friendly(y, x, rlev, 0, TRUE); } break; } /* S_MONSTERS */ case 83: { for (k = 0; k < 6; k++) { summon_specific_friendly(y, x, rlev, 0, TRUE); } break; } /* S_ANT */ case 84: { for (k = 0; k < 6; k++) { summon_specific_friendly(y, x, rlev, SUMMON_ANT, TRUE); } break; } /* S_SPIDER */ case 85: { for (k = 0; k < 6; k++) { summon_specific_friendly(y, x, rlev, SUMMON_SPIDER, TRUE); } break; } /* S_HOUND */ case 86: { for (k = 0; k < 6; k++) { summon_specific_friendly(y, x, rlev, SUMMON_HOUND, TRUE); } break; } /* S_HYDRA */ case 87: { for (k = 0; k < 6; k++) { summon_specific_friendly(y, x, rlev, SUMMON_HYDRA, TRUE); } break; } /* S_ANGEL */ case 88: { for (k = 0; k < 1; k++) { summon_specific_friendly(y, x, rlev, SUMMON_ANGEL, TRUE); } break; } /* S_DEMON */ case 89: { for (k = 0; k < 1; k++) { summon_specific_friendly(y, x, rlev, SUMMON_DEMON, TRUE); } break; } /* S_UNDEAD */ case 90: { for (k = 0; k < 1; k++) { summon_specific_friendly(y, x, rlev, SUMMON_UNDEAD, TRUE); } break; } /* S_DRAGON */ case 91: { for (k = 0; k < 1; k++) { summon_specific_friendly(y, x, rlev, SUMMON_DRAGON, TRUE); } break; } /* S_HI_UNDEAD */ case 92: { for (k = 0; k < 8; k++) { summon_specific_friendly(y, x, rlev, SUMMON_HI_UNDEAD_NO_UNIQUES, TRUE); } break; } /* S_HI_DRAGON */ case 93: { for (k = 0; k < 8; k++) { summon_specific_friendly(y, x, rlev, SUMMON_HI_DRAGON_NO_UNIQUES, TRUE); } break; } /* S_WRAITH */ case 94: { for (k = 0; k < 8; k++) { summon_specific_friendly(y, x, rlev, SUMMON_WRAITH, TRUE); } break; } /* 95 S_UNIQUE -- Not available */ } /* Take some SP */ if (!no_cost) { int chance, pchance; chance = (monster_powers[power].mana + r_ptr->level); pchance = adj_str_wgt[p_ptr->stat_ind[A_WIS]] / 2 + get_skill(SKILL_POSSESSION); if (rand_int(chance) >= pchance) { int m = monster_powers[power].mana / 10; if (m > p_ptr->msp) m = p_ptr->msp; if (!m) m = 1; p_ptr->csp -= m; } } /* Redraw mana */ p_ptr->redraw |= (PR_MANA); /* Window stuff */ p_ptr->window |= (PW_PLAYER); return (num); } /* * Schooled magic */ /* * Find a spell in any books/objects */ static int hack_force_spell = -1; static object_type *hack_force_spell_obj = NULL; bool_ get_item_hook_find_spell(int *item) { int i, spell; char buf[80]; strcpy(buf, "Manathrust"); if (!get_string("Spell name? ", buf, 79)) return FALSE; spell = find_spell(buf); if (spell == -1) return FALSE; for (i = 0; i < INVEN_TOTAL; i++) { object_type *o_ptr = &p_ptr->inventory[i]; u32b f1, f2, f3, f4, f5, esp; /* Must we wield it ? */ object_flags(o_ptr, &f1, &f2, &f3, &f4, &f5, &esp); if ((wield_slot(o_ptr) != -1) && (i < INVEN_WIELD) && (f5 & TR5_WIELD_CAST)) continue; /* Is it a non-book? */ if (!is_school_book(o_ptr)) { u32b f1, f2, f3, f4, f5, esp; /* Extract object flags */ object_flags(o_ptr, &f1, &f2, &f3, &f4, &f5, &esp); if ((f5 & TR5_SPELL_CONTAIN) && (o_ptr->pval2 == spell)) { *item = i; hack_force_spell = spell; hack_force_spell_obj = o_ptr; return TRUE; } } /* A random book ? */ else if (school_book_contains_spell(o_ptr->sval, spell)) { *item = i; hack_force_spell = spell; hack_force_spell_obj = o_ptr; return TRUE; } } return FALSE; } /* * Is the spell castable? */ bool_ is_ok_spell(s32b spell_idx, object_type *o_ptr) { spell_type *spell = spell_at(spell_idx); assert(o_ptr != NULL); if (get_level(spell_idx, 50, 0) == 0) { return FALSE; } if (o_ptr->pval < spell->minimum_pval) { return FALSE; } return TRUE; } /* * Get a spell from a book */ s32b get_school_spell(cptr do_what, s16b force_book) { int i, item; s32b spell = -1; int num = 0; s32b where = 1; int ask; bool_ flag, redraw; char choice; char out_val[160]; char buf2[40]; char buf3[40]; object_type *o_ptr, forge; int tmp; int sval, pval; u32b f1, f2, f3, f4, f5, esp; hack_force_spell = -1; hack_force_spell_obj = NULL; /* Ok do we need to ask for a book ? */ if (!force_book) { get_item_extra_hook = get_item_hook_find_spell; item_tester_hook = hook_school_spellable; sprintf(buf2, "You have no book to %s from", do_what); sprintf(buf3, "%s from which book?", do_what); if (!get_item(&item, buf3, buf2, USE_INVEN | USE_EQUIP | USE_EXTRA )) return -1; /* Get the item */ o_ptr = get_object(item); object_flags(o_ptr, &f1, &f2, &f3, &f4, &f5, &esp); /* If it can be wielded, it must */ if ((wield_slot(o_ptr) != -1) && (item < INVEN_WIELD) && (f5 & TR5_WIELD_CAST)) { msg_format("You cannot %s from that object; it must be wielded first.", do_what); return -1; } } else { o_ptr = &forge; o_ptr->tval = TV_BOOK; o_ptr->sval = force_book; o_ptr->pval = 0; } if (repeat_pull(&tmp)) { return tmp; } /* Nothing chosen yet */ flag = FALSE; /* No redraw yet */ redraw = FALSE; /* Show choices */ if (show_choices) { /* Window stuff */ window_stuff(); } /* No spell to cast by default */ spell = -1; /* Is it a random book, or something else ? */ if (is_school_book(o_ptr)) { sval = o_ptr->sval; pval = o_ptr->pval; } else { sval = 255; pval = o_ptr->pval2; } if (hack_force_spell == -1) { num = school_book_length(sval); /* Build a prompt (accept all spells) */ strnfmt(out_val, 78, "(Spells %c-%c, Descs %c-%c, *=List, ESC=exit) %^s which spell? ", I2A(0), I2A(num - 1), I2A(0) - 'a' + 'A', I2A(num - 1) - 'a' + 'A', do_what); /* Get a spell from the user */ while (!flag && get_com(out_val, &choice)) { /* Request redraw */ if (((choice == ' ') || (choice == '*') || (choice == '?'))) { /* Show the list */ if (!redraw) { /* Show list */ redraw = TRUE; /* Save the screen */ character_icky = TRUE; Term_save(); /* Display a list of spells */ where = print_book(sval, pval, o_ptr); } /* Hide the list */ else { /* Hide list */ redraw = FALSE; where = 1; /* Restore the screen */ Term_load(); character_icky = FALSE; } /* Redo asking */ continue; } /* Note verify */ ask = (isupper(choice)); /* Lowercase */ if (ask) choice = tolower(choice); /* Extract request */ i = (islower(choice) ? A2I(choice) : -1); /* Totally Illegal */ if ((i < 0) || (i >= num)) { bell(); continue; } /* Verify it */ if (ask) { /* Show the list */ if (!redraw) { /* Show list */ redraw = TRUE; /* Save the screen */ character_icky = TRUE; Term_load(); Term_save(); } /* Rstore the screen */ else { /* Restore the screen */ Term_load(); } /* Display a list of spells */ where = print_book(sval, pval, o_ptr); print_spell_desc(spell_x(sval, pval, i), where); } else { bool_ ok; /* Save the spell index */ spell = spell_x(sval, pval, i); /* Do we need to do some pre test */ ok = is_ok_spell(spell, o_ptr); /* Require "okay" spells */ if (!ok) { bell(); msg_format("You may not %s that spell.", do_what); spell = -1; continue; } /* Stop the loop */ flag = TRUE; } } } else { bool_ ok; /* Require "okay" spells */ ok = is_ok_spell(hack_force_spell, hack_force_spell_obj); if (ok) { flag = TRUE; spell = hack_force_spell; } else { bell(); msg_format("You may not %s that spell.", do_what); spell = -1; } } /* Restore the screen */ if (redraw) { Term_load(); character_icky = FALSE; } /* Show choices */ if (show_choices) { /* Window stuff */ window_stuff(); } /* Abort if needed */ if (!flag) return -1; tmp = spell; repeat_push(tmp); return spell; } void cast_school_spell() { int spell; /* No magic */ if (p_ptr->antimagic) { msg_print("Your anti-magic field disrupts any magic attempts."); return; } /* No magic */ if (p_ptr->anti_magic) { msg_print("Your anti-magic shell disrupts any magic attempts."); return; } spell = get_school_spell("cast", 0); /* Actualy cast the choice */ if (spell != -1) { lua_cast_school_spell(spell, FALSE); } } void browse_school_spell(int book, int pval, object_type *o_ptr) { int i; int num = 0, where = 1; int ask; char choice; char out_val[160]; /* Show choices */ if (show_choices) { /* Window stuff */ window_stuff(); } num = school_book_length(book); /* Build a prompt (accept all spells) */ strnfmt(out_val, 78, "(Spells %c-%c, ESC=exit) cast which spell? ", I2A(0), I2A(num - 1)); /* Save the screen */ character_icky = TRUE; Term_save(); /* Display a list of spells */ where = print_book(book, pval, o_ptr); /* Get a spell from the user */ while (get_com(out_val, &choice)) { /* Display a list of spells */ where = print_book(book, pval, o_ptr); /* Note verify */ ask = (isupper(choice)); /* Lowercase */ if (ask) choice = tolower(choice); /* Extract request */ i = (islower(choice) ? A2I(choice) : -1); /* Totally Illegal */ if ((i < 0) || (i >= num)) { bell(); continue; } /* Restore the screen */ Term_load(); /* Display a list of spells */ where = print_book(book, pval, o_ptr); print_spell_desc(spell_x(book, pval, i), where); } /* Restore the screen */ Term_load(); character_icky = FALSE; /* Show choices */ if (show_choices) { /* Window stuff */ window_stuff(); } } /* Can it contains a schooled spell ? */ static bool_ hook_school_can_spellable(object_type *o_ptr) { u32b f1, f2, f3, f4, f5, esp; /* Extract object flags */ object_flags(o_ptr, &f1, &f2, &f3, &f4, &f5, &esp); if ((f5 & TR5_SPELL_CONTAIN) && (o_ptr->pval2 == -1)) return TRUE; return FALSE; } /* * Copy a spell from a bok to an object */ void do_cmd_copy_spell() { int spell = get_school_spell("copy", 0); int item; object_type *o_ptr; if (spell == -1) return; /* Spells that cannot be randomly created cannot be copied */ if (can_spell_random(spell) <= 0) { msg_print("This spell cannot be copied."); return; } item_tester_hook = hook_school_can_spellable; if (!get_item(&item, "Copy to which object? ", "You have no object to copy to.", (USE_INVEN | USE_EQUIP))) return; o_ptr = get_object(item); msg_print("You copy the spell!"); o_ptr->pval2 = spell; inven_item_describe(item); }