int cast_spell (struct char_data *ch, struct char_data *tch, struct obj_data *tobj, int spellnum) { if (spellnum < 0 || spellnum > TOP_SPELL_DEFINE) { log ("SYSERR: cast_spell trying to call spellnum %d/%d.\n", spellnum, TOP_SPELL_DEFINE); return (0); } if (GET_POS (ch) < SINFO.min_position) { switch (GET_POS (ch)) { case POS_SLEEPING: send_to_char ("You dream about great magical powers.\r\n", ch); break; case POS_RESTING: send_to_char ("You cannot concentrate while resting.\r\n", ch); break; case POS_SITTING: send_to_char ("You can't do this sitting!\r\n", ch); break; case POS_FIGHTING: send_to_char ("Impossible! You can't concentrate enough!\r\n", ch); break; default: send_to_char ("You can't do much of anything like this!\r\n", ch); break; } return (0); } if (AFF_FLAGGED (ch, AFF_CHARM) && (ch->master == tch)) { send_to_char ("You are afraid you might hurt your master!\r\n", ch); return (0); } if ((tch != ch) && IS_SET (SINFO.targets, TAR_SELF_ONLY)) { send_to_char ("You can only cast this spell upon yourself!\r\n", ch); return (0); } if ((tch == ch) && IS_SET (SINFO.targets, TAR_NOT_SELF)) { send_to_char ("You cannot cast this spell upon yourself!\r\n", ch); return (0); } if (IS_SET (SINFO.routines, MAG_GROUPS) && !AFF_FLAGGED (ch, AFF_GROUP)) { send_to_char ("You can't cast this spell if you're not in a group!\r\n", ch); return (0); } send_to_char (OK, ch); say_spell (ch, spellnum, tch, tobj); return (call_magic (ch, tch, tobj, spellnum, GET_LEVEL (ch), CAST_SPELL)); }
/* mag_objectmagic: This is the entry-point for all magic items. This should * only be called by the 'quaff', 'use', 'recite', etc. routines. * For reference, object values 0-3: * staff - [0] level [1] max charges [2] num charges [3] spell num * wand - [0] level [1] max charges [2] num charges [3] spell num * scroll - [0] level [1] spell num [2] spell num [3] spell num * potion - [0] level [1] spell num [2] spell num [3] spell num * Staves and wands will default to level 14 if the level is not specified; the * DikuMUD format did not specify staff and wand levels in the world files */ void mag_objectmagic(struct char_data *ch, struct obj_data *obj, char *argument) { char arg[MAX_INPUT_LENGTH]; int i, k; struct char_data *tch = NULL, *next_tch; struct obj_data *tobj = NULL; one_argument(argument, arg); k = generic_find(arg, FIND_CHAR_ROOM | FIND_OBJ_INV | FIND_OBJ_ROOM | FIND_OBJ_EQUIP, ch, &tch, &tobj); switch (GET_OBJ_TYPE(obj)) { case ITEM_STAFF: act("You tap $p three times on the ground.", FALSE, ch, obj, 0, TO_CHAR); if (obj->action_description) act(obj->action_description, FALSE, ch, obj, 0, TO_ROOM); else act("$n taps $p three times on the ground.", FALSE, ch, obj, 0, TO_ROOM); if (GET_OBJ_VAL(obj, 2) <= 0) { send_to_char(ch, "It seems powerless.\r\n"); act("Nothing seems to happen.", FALSE, ch, obj, 0, TO_ROOM); } else { GET_OBJ_VAL(obj, 2)--; WAIT_STATE(ch, PULSE_VIOLENCE); /* Level to cast spell at. */ k = GET_OBJ_VAL(obj, 0) ? GET_OBJ_VAL(obj, 0) : DEFAULT_STAFF_LVL; /* Area/mass spells on staves can cause crashes. So we use special cases * for those spells spells here. */ if (HAS_SPELL_ROUTINE(GET_OBJ_VAL(obj, 3), MAG_MASSES | MAG_AREAS)) { for (i = 0, tch = world[IN_ROOM(ch)].people; tch; tch = tch->next_in_room) i++; while (i-- > 0) call_magic(ch, NULL, NULL, GET_OBJ_VAL(obj, 3), k, CAST_STAFF); } else { for (tch = world[IN_ROOM(ch)].people; tch; tch = next_tch) { next_tch = tch->next_in_room; if (ch != tch) call_magic(ch, tch, NULL, GET_OBJ_VAL(obj, 3), k, CAST_STAFF); } } } break; case ITEM_WAND: if (k == FIND_CHAR_ROOM) { if (tch == ch) { act("You point $p at yourself.", FALSE, ch, obj, 0, TO_CHAR); act("$n points $p at $mself.", FALSE, ch, obj, 0, TO_ROOM); } else { act("You point $p at $N.", FALSE, ch, obj, tch, TO_CHAR); if (obj->action_description) act(obj->action_description, FALSE, ch, obj, tch, TO_ROOM); else act("$n points $p at $N.", TRUE, ch, obj, tch, TO_ROOM); } } else if (tobj != NULL) { act("You point $p at $P.", FALSE, ch, obj, tobj, TO_CHAR); if (obj->action_description) act(obj->action_description, FALSE, ch, obj, tobj, TO_ROOM); else act("$n points $p at $P.", TRUE, ch, obj, tobj, TO_ROOM); } else if (IS_SET(spell_info[GET_OBJ_VAL(obj, 3)].routines, MAG_AREAS | MAG_MASSES)) { /* Wands with area spells don't need to be pointed. */ act("You point $p outward.", FALSE, ch, obj, NULL, TO_CHAR); act("$n points $p outward.", TRUE, ch, obj, NULL, TO_ROOM); } else { act("At what should $p be pointed?", FALSE, ch, obj, NULL, TO_CHAR); return; } if (GET_OBJ_VAL(obj, 2) <= 0) { send_to_char(ch, "It seems powerless.\r\n"); act("Nothing seems to happen.", FALSE, ch, obj, 0, TO_ROOM); return; } GET_OBJ_VAL(obj, 2)--; WAIT_STATE(ch, PULSE_VIOLENCE); if (GET_OBJ_VAL(obj, 0)) call_magic(ch, tch, tobj, GET_OBJ_VAL(obj, 3), GET_OBJ_VAL(obj, 0), CAST_WAND); else call_magic(ch, tch, tobj, GET_OBJ_VAL(obj, 3), DEFAULT_WAND_LVL, CAST_WAND); break; case ITEM_SCROLL: if (*arg) { if (!k) { act("There is nothing to here to affect with $p.", FALSE, ch, obj, NULL, TO_CHAR); return; } } else tch = ch; act("You recite $p which dissolves.", TRUE, ch, obj, 0, TO_CHAR); if (obj->action_description) act(obj->action_description, FALSE, ch, obj, tch, TO_ROOM); else act("$n recites $p.", FALSE, ch, obj, NULL, TO_ROOM); WAIT_STATE(ch, PULSE_VIOLENCE); for (i = 1; i <= 3; i++) if (call_magic(ch, tch, tobj, GET_OBJ_VAL(obj, i), GET_OBJ_VAL(obj, 0), CAST_SCROLL) <= 0) break; if (obj != NULL) extract_obj(obj); break; case ITEM_POTION: tch = ch; if (!consume_otrigger(obj, ch, OCMD_QUAFF)) /* check trigger */ return; act("You quaff $p.", FALSE, ch, obj, NULL, TO_CHAR); if (obj->action_description) act(obj->action_description, FALSE, ch, obj, NULL, TO_ROOM); else act("$n quaffs $p.", TRUE, ch, obj, NULL, TO_ROOM); WAIT_STATE(ch, PULSE_VIOLENCE); for (i = 1; i <= 3; i++) if (call_magic(ch, ch, NULL, GET_OBJ_VAL(obj, i), GET_OBJ_VAL(obj, 0), CAST_POTION) <= 0) break; if (obj != NULL) extract_obj(obj); break; default: log("SYSERR: Unknown object_type %d in mag_objectmagic.", GET_OBJ_TYPE(obj)); break; } }
/* code borrowed from do_cast() */ void do_dg_cast(void *go, struct script_data *sc, trig_data *trig, int type, char *cmd) { struct char_data *caster = NULL; struct char_data *tch = NULL; struct obj_data *tobj = NULL; struct room_data *caster_room = NULL; char *s, *t; int spellnum, target = 0; /* need to get the caster or the room of the temporary caster */ switch (type) { case MOB_TRIGGER: caster = (struct char_data *)go; break; case WLD_TRIGGER: caster_room = (struct room_data *)go; break; case OBJ_TRIGGER: caster_room = dg_room_of_obj((struct obj_data *)go); if (!caster_room) { script_log("dg_do_cast: unknown room for object-caster!"); return; } break; default: script_log("dg_do_cast: unknown trigger type!"); return; } /* get: blank, spell name, target name */ s = strtok(cmd, "'"); if (s == NULL) { sprintf(buf2, "Trigger: %s, VNum %d. dg_cast needs spell name.", GET_TRIG_NAME(trig), GET_TRIG_VNUM(trig)); script_log(buf2); return; } s = strtok(NULL, "'"); if (s == NULL) { sprintf(buf2, "Trigger: %s, VNum %d. dg_cast needs spell name in `'s.", GET_TRIG_NAME(trig), GET_TRIG_VNUM(trig)); script_log(buf2); return; } t = strtok(NULL, "\0"); /* spellnum = search_block(s, spells, 0); */ spellnum = find_abil_num(s,spells); if ((spellnum < 1) || (spellnum > MAX_SPELLS)) { sprintf(buf2, "Trigger: %s, VNum %d. dg_cast: invalid spell name (%s)", GET_TRIG_NAME(trig), GET_TRIG_VNUM(trig), cmd); script_log(buf2); return; } /* Find the target */ if (t != NULL) { one_argument(strcpy(arg, t), t); skip_spaces(&t); } if (IS_SET(SINFO.targets, TAR_IGNORE)) { target = TRUE; } else if (t != NULL && *t) { if (!target && (IS_SET(SINFO.targets, TAR_CHAR_ROOM) || IS_SET(SINFO.targets, TAR_CHAR_WORLD))) { if ((tch = get_char(t)) != NULL) target = TRUE; } if (!target && (IS_SET(SINFO.targets, TAR_OBJ_INV) || IS_SET(SINFO.targets, TAR_OBJ_EQUIP) || IS_SET(SINFO.targets, TAR_OBJ_ROOM) || IS_SET(SINFO.targets, TAR_OBJ_WORLD))) { if ((tobj = get_obj(t)) != NULL) target = TRUE; } if (!target) { sprintf(buf2, "Trigger: %s, VNum %d. dg_cast: target not found (%s)", GET_TRIG_NAME(trig), GET_TRIG_VNUM(trig), cmd); script_log(buf2); return; } } if (IS_SET(SINFO.routines, MAG_GROUPS)) { sprintf(buf2, "Trigger: %s, VNum %d. dg_cast: group spells not permitted (%s)", GET_TRIG_NAME(trig), GET_TRIG_VNUM(trig), cmd); script_log(buf2); return; } if (!caster) { caster = read_mobile(DG_CASTER_PROXY, VIRTUAL); if (!caster) { script_log("dg_cast: Cannot load the caster mob!"); return; } /* set the caster's name to that of the object, or the gods.... */ /* take select pieces from char_to_room(); */ if (type==OBJ_TRIGGER) caster->player.short_descr = str_dup(((struct obj_data *)go)->short_description); else if (type==WLD_TRIGGER) caster->player.short_descr = str_dup("The gods"); caster->next_in_room = caster_room->people; caster_room->people = caster; caster->in_room = real_room(caster_room->number); call_magic(caster, tch, tobj, spellnum, ABT_SPELL, GET_LEVEL(caster), CAST_SPELL, FALSE); extract_char(caster); } else call_magic(caster, tch, tobj, spellnum, ABT_SPELL, GET_LEVEL(caster), CAST_SPELL, FALSE); }
/* ========================================================================= NAME : use_tattoo() DESCRIPTION: RETURNS : TRUE if a tattoo was used WARNINGS : HISTORY : Created by dlkarnes 970417 OTHER : ========================================================================= */ int use_tattoo( struct char_data *ch ) { void add_follower_quiet(struct char_data *ch, struct char_data *leader); if (ch && !IS_NPC(ch)) { if (TAT_TIMER(ch)) { char mybuf[256]; sprintf(mybuf, "You can't use your tattoo's magick for " "%d more hour%s.\r\n", TAT_TIMER(ch),TAT_TIMER(ch)>1?"s":""); send_to_char(mybuf, ch); return(FALSE); } switch (GET_TATTOO(ch)) { case TATTOO_NONE: send_to_char ("You don't have a tattoo.\r\n", ch); break; case TATTOO_SKULL: { struct char_data *skull = read_mobile(9, VIRTUAL); struct affected_type af; char_to_room(skull, ch->in_room); add_follower_quiet(skull, ch); IS_CARRYING_W(skull) = 0; IS_CARRYING_N(skull) = 0; af.type = SPELL_CHARM; af.duration = 20; af.modifier = 0; af.location = 0; af.bitvector = AFF_CHARM; affect_to_char(skull, &af); act("$n's tattoo glows brightly for a second, and $N appears!", TRUE, ch, 0, skull, TO_ROOM); act("Your tattoo glows brightly for a second, and $N appears!", TRUE, ch, 0, skull, TO_CHAR); } break; case TATTOO_EYE: call_magic(ch, ch, NULL, SPELL_GREATPERCEPT, DEFAULT_WAND_LVL, CAST_WAND); break; case TATTOO_SHIP: call_magic(ch, ch, NULL, SPELL_CHANGE_DENSITY, DEFAULT_WAND_LVL, CAST_WAND); break; case TATTOO_ANGEL: call_magic(ch, ch, NULL, SPELL_BLESS, DEFAULT_WAND_LVL, CAST_WAND); break; default: send_to_char("Your tattoo can't be 'use'd.\r\n", ch); return (FALSE); } TAT_TIMER(ch)=24; } return(FALSE); }
void perform_smoke(struct creature *ch, int type) { const char *to_vict = NULL; struct affected_type af; int hp_mod = 0, mana_mod = 0, move_mod = 0, spell = 0; uint8_t lev = 0; int accum_dur = 0, accum_affect = 0; init_affect(&af); af.type = SMOKE_EFFECTS; af.level = 30; af.owner = GET_IDNUM(ch); switch (type) { case SMOKE_DIRTWEED: to_vict = "Your head hurts."; af.duration = 3; af.modifier = -2; af.location = APPLY_INT; af.bitvector = AFF_CONFUSION; af.aff_index = 1; accum_dur = 1; accum_affect = 1; move_mod = -number(3, 10); mana_mod = -number(1, 2); break; case SMOKE_DESERTWEED: af.location = APPLY_MOVE; af.duration = 4; af.modifier = 10; mana_mod = dice(1, 4); move_mod = dice(3, 4); break; case SMOKE_INDICA: to_vict = "Your mind is elevated to another plane."; af.location = APPLY_WIS; af.duration = 5; af.modifier = number(1, 2); mana_mod = dice(6, 4); move_mod = -number(1, 3); break; case SMOKE_UNHOLY_REEFER: af.location = APPLY_WIS; af.duration = 5; af.modifier = number(0, 2); mana_mod = number(1, 4); move_mod = -number(1, 3); spell = SPELL_ESSENCE_OF_EVIL; lev = 20; break; case SMOKE_MARIJUANA: to_vict = "You feel stoned."; af.location = APPLY_INT; af.duration = 3; af.modifier = -1; mana_mod = dice(4, 4); break; case SMOKE_TOBACCO: af.location = APPLY_MOVE; af.duration = 3; af.modifier = -number(10, 20); accum_dur = 1; mana_mod = dice(3, 3); break; case SMOKE_HEMLOCK: to_vict = "The smoke burns your lungs!"; af.location = APPLY_HIT; af.duration = number(3, 6); af.modifier = -number(30, 60); accum_affect = 1; hp_mod = -number(10, 16); mana_mod = -10; move_mod = -10; spell = SPELL_POISON; lev = LVL_AMBASSADOR; break; case SMOKE_PEYOTE: to_vict = "You feel a strange sensation."; spell = SPELL_ASTRAL_SPELL; lev = LVL_GRIMP; af.location = APPLY_MANA; af.modifier = number(10, 20); af.duration = number(1, 3); move_mod = number(6, 12); break; case SMOKE_HOMEGROWN: to_vict = "There's no place like home..."; spell = SPELL_WORD_OF_RECALL; lev = number(30, 60); mana_mod = number(20, 40); move_mod = number(2, 10); break; default: af.type = 0; break; } if (to_vict) act(to_vict, false, ch, NULL, NULL, TO_CHAR); GET_HIT(ch) = MIN(MAX(GET_HIT(ch) + hp_mod, 0), GET_MAX_HIT(ch)); GET_MANA(ch) = MIN(MAX(GET_MANA(ch) + mana_mod, 0), GET_MAX_MANA(ch)); GET_MOVE(ch) = MIN(MAX(GET_MOVE(ch) + move_mod, 0), GET_MAX_MOVE(ch)); if (af.type && (!affected_by_spell(ch, af.type) || accum_affect || accum_dur)) affect_join(ch, &af, accum_dur, true, accum_affect, true); if (spell && lev) call_magic(ch, ch, NULL, NULL, spell, (int)lev, CAST_CHEM); WAIT_STATE(ch, 6); }
int cast_spell(struct char_data *ch, struct char_data *tch, struct obj_data *tobj, struct spell_info_type *sptr, char *tar_str) { if (!magic_enabled) return (0); if (!sptr) { extended_mudlog(NRM, SYSL_BUGS, TRUE, "cast_spell() called without a valid sptr: ch: %s, tch: %s", GET_NAME(ch), GET_NAME(tch)); return (0); } if (GET_POS(ch) < sptr->min_position) { switch (GET_POS(ch)) { case POS_SLEEPING: send_to_char("You dream about great magical powers.\r\n", ch); break; case POS_RESTING: send_to_char("You cannot concentrate while resting.\r\n", ch); break; case POS_SITTING: send_to_char("You can't do this sitting!\r\n", ch); break; case POS_FIGHTING: send_to_char("Impossible! You can't concentrate enough!\r\n", ch); break; default: send_to_char("You can't do much of anything like this!\r\n", ch); break; } return (0); } if (AFF_FLAGGED(ch, AFF_CHARM) && (ch->master == tch)) { send_to_char("You are afraid you might hurt your master!\r\n", ch); return (0); } if ((tch != ch) && IS_SET(sptr->targets, TAR_SELF_ONLY)) { send_to_char("You can only cast this spell upon yourself!\r\n", ch); return (0); } if ((tch == ch) && IS_SET(sptr->targets, TAR_NOT_SELF)) { send_to_char("You cannot cast this spell upon yourself!\r\n", ch); return (0); } if (IS_SET(sptr->routines, MAG_GROUPS) && !AFF_FLAGGED(ch, AFF_GROUP)) { send_to_char("You can't cast this spell if you're not in a group!\r\n",ch); return (0); } if (cast_mtrigger(tch, ch, tar_str, sptr) == 0) return (0); if (cast_otrigger(tobj, ch, tar_str, sptr) == 0) return (0); if (cast_wtrigger(ch, tch, tobj, tar_str, sptr) == 0) return (0); send_to_char(OK, ch); say_spell(ch, sptr, tch, tobj); return (call_magic(ch, tch, tobj, sptr, (GET_SKILL(ch, sptr->skill)/100), CAST_SPELL, tar_str)); }
void mag_objectmagic(struct char_data *ch, struct obj_data *obj, char *argument) { int i, k; struct char_data *tch = NULL, *next_tch; struct obj_data *tobj = NULL; if (!magic_enabled) return; one_argument(argument, arg); k = generic_find(arg, FIND_CHAR_ROOM | FIND_OBJ_INV | FIND_OBJ_ROOM | FIND_OBJ_EQUIP, ch, &tch, &tobj); switch (GET_OBJ_TYPE(obj)) { case ITEM_STAFF: act("You tap $p three times on the ground.", FALSE, ch, obj, 0, TO_CHAR); if (obj->action_description) act(obj->action_description, FALSE, ch, obj, 0, TO_ROOM); else act("$n taps $p three times on the ground.", FALSE, ch, obj, 0, TO_ROOM); if (GET_OBJ_VAL(obj, 2) <= 0) { send_to_char("It seems powerless.\r\n", ch); act("Nothing seems to happen.", FALSE, ch, obj, 0, TO_ROOM); } else { GET_OBJ_VAL(obj, 2)--; WAIT_STATE(ch, PULSE_VIOLENCE); /* Level to cast spell at. */ k = GET_OBJ_VAL(obj, 0) ? GET_OBJ_VAL(obj, 0) : DEFAULT_STAFF_LVL; /* * Problem : Area/mass spells on staves can cause crashes. * Solution: Remove the special nature of area/mass spells on staves. * Problem : People like that behavior. * Solution: We special case the area/mass spells here. */ if (HAS_SPELL_ROUTINE(get_spell(GET_OBJ_VAL(obj, 3), __FILE__, __FUNCTION__), MAG_MASSES | MAG_AREAS)) { for (i = 0, tch = world[IN_ROOM(ch)].people; tch; tch = tch->next_in_room) i++; while (i-- > 0) call_magic(ch, NULL, NULL, get_spell(GET_OBJ_VAL(obj, 3), __FILE__, __FUNCTION__), k, CAST_STAFF, 0); } else { for (tch = world[IN_ROOM(ch)].people; tch; tch = next_tch) { next_tch = tch->next_in_room; if (ch != tch) call_magic(ch, tch, NULL, get_spell(GET_OBJ_VAL(obj, 3), __FILE__, __FUNCTION__), k, CAST_STAFF, 0); } } } break; case ITEM_WAND: if (k == FIND_CHAR_ROOM) { if (tch == ch) { act("You point $p at yourself.", FALSE, ch, obj, 0, TO_CHAR); act("$n points $p at $mself.", FALSE, ch, obj, 0, TO_ROOM); } else { act("You point $p at $N.", FALSE, ch, obj, tch, TO_CHAR); if (obj->action_description) act(obj->action_description, FALSE, ch, obj, tch, TO_ROOM); else act("$n points $p at $N.", TRUE, ch, obj, tch, TO_ROOM); } } else if (tobj != NULL) { act("You point $p at $P.", FALSE, ch, obj, tobj, TO_CHAR); if (obj->action_description) act(obj->action_description, FALSE, ch, obj, tobj, TO_ROOM); else act("$n points $p at $P.", TRUE, ch, obj, tobj, TO_ROOM); } else if (IS_SET(get_spell(GET_OBJ_VAL(obj, 3), __FILE__, __FUNCTION__)->routines, MAG_AREAS | MAG_MASSES)) { /* Wands with area spells don't need to be pointed. */ act("You point $p outward.", FALSE, ch, obj, NULL, TO_CHAR); act("$n points $p outward.", TRUE, ch, obj, NULL, TO_ROOM); } else { act("At what should $p be pointed?", FALSE, ch, obj, NULL, TO_CHAR); return; } if (GET_OBJ_VAL(obj, 2) <= 0) { send_to_char("It seems powerless.\r\n", ch); act("Nothing seems to happen.", FALSE, ch, obj, 0, TO_ROOM); return; } GET_OBJ_VAL(obj, 2)--; WAIT_STATE(ch, PULSE_VIOLENCE); if (GET_OBJ_VAL(obj, 0)) call_magic(ch, tch, tobj, get_spell(GET_OBJ_VAL(obj, 3), __FILE__, __FUNCTION__), GET_OBJ_VAL(obj, 0), CAST_WAND, 0); else call_magic(ch, tch, tobj, get_spell(GET_OBJ_VAL(obj, 3), __FILE__, __FUNCTION__), DEFAULT_WAND_LVL, CAST_WAND, 0); break; case ITEM_SCROLL: if (*arg) { if (!k) { act("There is nothing to here to affect with $p.", FALSE, ch, obj, NULL, TO_CHAR); return; } } else tch = ch; act("You recite $p which dissolves.", TRUE, ch, obj, 0, TO_CHAR); if (obj->action_description) act(obj->action_description, FALSE, ch, obj, NULL, TO_ROOM); else act("$n recites $p.", FALSE, ch, obj, NULL, TO_ROOM); WAIT_STATE(ch, PULSE_VIOLENCE); for (i = 1; i <= 3; i++) if (call_magic(ch, tch, tobj, get_spell(GET_OBJ_VAL(obj, i), __FILE__, __FUNCTION__), GET_OBJ_VAL(obj, 0), CAST_SCROLL, 0) <= 0) break; if (obj != NULL) extract_obj(obj); break; case ITEM_POTION: tch = ch; act("You quaff $p.", FALSE, ch, obj, NULL, TO_CHAR); if (obj->action_description) act(obj->action_description, FALSE, ch, obj, NULL, TO_ROOM); else act("$n quaffs $p.", TRUE, ch, obj, NULL, TO_ROOM); WAIT_STATE(ch, PULSE_VIOLENCE); for (i = 1; i <= 3; i++) if (call_magic(ch, ch, NULL, get_spell(GET_OBJ_VAL(obj, i), __FILE__, __FUNCTION__), GET_OBJ_VAL(obj, 0), CAST_POTION, 0) <= 0) break; if (obj != NULL) extract_obj(obj); break; case ITEM_SPELLBOOK: tch = ch; act("You study $p.", FALSE, ch, obj, NULL, TO_CHAR); if (obj->action_description) act(obj->action_description, FALSE, ch, obj, NULL, TO_ROOM); else act("$n studies $p.", TRUE, ch, obj, NULL, TO_ROOM); WAIT_STATE(ch, PULSE_VIOLENCE); for (i = 1; i <= 3; i++) { if (GET_OBJ_VAL(obj, i) < 0) break; if (GET_SKILL(ch, GET_OBJ_VAL(obj, i)) < 1) SET_SKILL(ch, GET_OBJ_VAL(obj, i), GET_OBJ_VAL(obj, 0)); } if (obj != NULL) extract_obj(obj); break; default: extended_mudlog(NRM, SYSL_BUGS, TRUE, "Unknown object_type %d in mag_objectmagic.", GET_OBJ_TYPE(obj)); break; } }