/* ************************************************************************ * file: magic.c , Implementation of spells. Part of DIKUMUD * * Usage : The actual effect of magic. * * Copyright (C) 1990, 1991 - see 'license.doc' for complete information. * ************************************************************************* */ #include <stdio.h> #include <assert.h> #include "structs.h" #include "utils.h" #include "comm.h" #include "spells.h" #include "handler.h" #include "limits.h" #include "db.h" /* Extern structures */ extern struct room_data *world; extern struct zone_data *zone_table; extern struct obj_data *object_list; extern struct char_data *character_list; /* Extern procedures */ void damage(struct char_data *ch, struct char_data *victim, int damage, int weapontype); bool saves_spell(struct char_data *ch, sh_int spell); void weight_change_object(struct obj_data *obj, int weight); char *strdup(char *source); int dice(int number, int size); void check_killer(struct char_data *ch, struct char_data *victim); bool nokill(struct char_data *ch, struct char_data *victim); void lose_exp_by_flight(struct char_data *ch,struct char_data *was_fighting); void do_look(struct char_data *ch, char *argument, int cmd); /* Offensive Spells */ void spell_magic_missile(byte level, struct char_data *ch, struct char_data *victim, struct obj_data *obj) { int dam; int dam_each[] = {0, 3,3,4,4,5, 6,6,6,6,6, 6,6,6,6,6, 6,6,6,6,6, 6,6,6,6,6, 6,6,6,6,6}; assert(victim && ch); assert(level >= 1); dam = number(dam_each[level]>>1, dam_each[level]<<1); if ( saves_spell(victim, SAVING_SPELL) ) dam >>= 1; damage(ch, victim, dam, SPELL_MAGIC_MISSILE); } void spell_chill_touch(byte level, struct char_data *ch, struct char_data *victim, struct obj_data *obj) { struct affected_type af; int dam; int dam_each[] = {0, 0,0,8,7,9, 9,12,13,13,13, 13,13,13,13,13, 13,13,13,13,13, 13,13,13,13,13, 13,13,13,13,13}; assert(victim && ch); assert(level >= 3); dam = number(dam_each[level]>>1, dam_each[level]<<1); if ( !saves_spell(victim, SAVING_SPELL) ) { af.type = SPELL_CHILL_TOUCH; af.duration = 6; af.modifier = -1; af.location = APPLY_STR; af.bitvector = 0; affect_join(victim, &af, TRUE, FALSE); } else { dam >>= 1; } damage(ch, victim, dam, SPELL_CHILL_TOUCH); } void spell_burning_hands(byte level, struct char_data *ch, struct char_data *victim, struct obj_data *obj) { int dam; int dam_each[] = {0, 0,0,0,0,19, 17,20,19,19,19, 19,19,19,19,19, 19,19,19,19,19, 19,19,19,19,19, 19,19,19,19,19}; assert(victim && ch); assert(level >= 5); dam = number(dam_each[level]>>1, dam_each[level]<<1); if ( saves_spell(victim, SAVING_SPELL) ) dam >>= 1; damage(ch, victim, dam, SPELL_BURNING_HANDS); } void spell_shocking_grasp(byte level, struct char_data *ch, struct char_data *victim, struct obj_data *obj) { int dam; int dam_each[] = {0, 0,0,0,0,0, 0,41,33,29,27, 25,25,25,25,25, 25,25,25,25,25, 25,25,25,25,25, 25,25,25,25,25}; assert(victim && ch); assert(level >= 7); dam = number(dam_each[level]>>1, dam_each[level]<<1); if ( saves_spell(victim, SAVING_SPELL) ) dam >>= 1; damage(ch, victim, dam, SPELL_SHOCKING_GRASP); } void spell_lightning_bolt(byte level, struct char_data *ch, struct char_data *victim, struct obj_data *obj) { int dam; int dam_each[] = {0, 0,0,0,0,0, 0,0,0,59,46, 39,35,38,36,36, 36,36,36,36,36, 36,36,36,36,36, 36,36,36,36,36}; assert(victim && ch); assert(level >= 9); dam = number(dam_each[level]>>1, dam_each[level]<<1); if ( saves_spell(victim, SAVING_SPELL) ) dam >>= 1; damage(ch, victim, dam, SPELL_LIGHTNING_BOLT); } void spell_colour_spray(byte level, struct char_data *ch, struct char_data *victim, struct obj_data *obj) { int dam; int dam_each[] = {0, 0,0,0,0,0, 0,0,0,0,0, 79,60,57,51,47, 44,44,44,44,44, 44,44,44,44,44, 44,44,44,44,44}; assert(victim && ch); assert(level >= 11); dam = number(dam_each[level]-20, dam_each[level]+20); if ( saves_spell(victim, SAVING_SPELL) ) dam >>= 1; damage(ch, victim, dam, SPELL_COLOUR_SPRAY); } /* Drain XP, MANA, HP - caster gains HP and MANA */ void spell_energy_drain(byte level, struct char_data *ch, struct char_data *victim, struct obj_data *obj) { int dam, xp, mana; void set_title(struct char_data *ch); void gain_exp(struct char_data *ch, int gain); assert(victim && ch); assert(level >= 13); if ( !saves_spell(victim, SAVING_SPELL) ) { GET_ALIGNMENT(ch) = MIN(-1000, GET_ALIGNMENT(ch)-200); if (GET_LEVEL(victim) <= 2) { damage(ch, victim, 100, SPELL_ENERGY_DRAIN); /* Kill the sucker */ } else { if(!IS_SET(world[ch->in_room].room_flags,ARENA)) { xp = number(level>>1,level)*1000; gain_exp(victim, -xp); } dam = dice(1,10); mana = GET_MANA(victim)>>1; GET_MOVE(victim) >>= 1; GET_MANA(victim) = mana; GET_MANA(ch) += mana>>1; GET_HIT(ch) += dam; send_to_char("Your life energy is drained!\n\r", victim); damage(ch, victim, dam, SPELL_ENERGY_DRAIN); } } else { damage(ch, victim, 0, SPELL_ENERGY_DRAIN); /* Miss */ } } void spell_fireball(byte level, struct char_data *ch, struct char_data *victim, struct obj_data *obj) { int dam; assert(victim && ch); assert(level >= 15); dam = MIN(150,number(40+level,70+level*5)); if (saves_spell(victim, SAVING_SPELL) ) dam >>= 1; damage(ch, victim, dam, SPELL_FIREBALL); } void spell_earthquake(byte level, struct char_data *ch, struct char_data *victim, struct obj_data *obj) { int dam; struct char_data *tmp_victim, *temp; assert(ch); assert(level >= 7); dam = dice(1,8)+level; send_to_char("The earth trembles beneath your feet!\n\r", ch); act("$n makes the earth tremble and shiver\n\rYou fall, and hit yourself!", FALSE, ch, 0, 0, TO_ROOM); for(tmp_victim = character_list; tmp_victim; tmp_victim = temp) { temp = tmp_victim->next; if((ch->in_room == tmp_victim->in_room) && (ch != tmp_victim) && !IS_TRUSTED(tmp_victim)) { damage(ch, tmp_victim, dam, SPELL_EARTHQUAKE); } else if (world[ch->in_room].zone == world[tmp_victim->in_room].zone) send_to_char("The earth trembles and shivers.", tmp_victim); } } void spell_dispel_evil(byte level, struct char_data *ch, struct char_data *victim, struct obj_data *obj) { int dam; assert(ch && victim); assert(level >= 10); if (IS_EVIL(ch)) { act("You feel unwanted.",FALSE,ch,0,0,TO_CHAR); return; } else if (!IS_EVIL(victim)) { act("But $N is not evil!", FALSE, ch, 0, victim, TO_CHAR); return; } dam = dice(level,4); if(saves_spell(victim, SAVING_SPELL)) dam >>= 1; damage(ch, victim, dam, SPELL_DISPEL_EVIL); } void spell_call_lightning(byte level, struct char_data *ch, struct char_data *victim, struct obj_data *obj) { int dam; assert(victim && ch); assert(level >= 12); dam = dice(MIN(level,15), 8); if (OUTSIDE(ch) && (zone_table[world[ch->in_room].zone].conditions.precip_rate > 5)) { if ( saves_spell(victim, SAVING_SPELL) ) dam >>= 1; damage(ch, victim, dam, SPELL_CALL_LIGHTNING); } } void spell_harm(byte level, struct char_data *ch, struct char_data *victim, struct obj_data *obj) { int dam; assert(victim && ch); assert(level >= 15); /* dam = GET_HIT(victim) - dice(1,4); ***old version */ /* put in a check for to_hit.. */ if(to_hit_char(ch,victim)) { dam = 5*level; if(dam >= (GET_HIT(victim)-4)) dam = GET_HIT(victim)-number(1,4); } else { /* This should really be done through the messages... but there's no entry for harm there... */ act("$n tries to touch $N, but misses!",TRUE,ch,0,victim,TO_NOTVICT); act("$n tries to touch you, but misses!",TRUE,ch,0,victim,TO_VICT); act("You try to touch $N, but miss!",TRUE,ch,0,victim,TO_CHAR); return; } if (dam < 0) dam = 0; /* Kill the suffering bastard */ else if ( saves_spell(victim, SAVING_SPELL) ) { dam = MIN(50, dam/2); } damage(ch, victim, dam, SPELL_HARM); } /* spells2.c - Not directly offensive spells */ void spell_armor(byte level, struct char_data *ch, struct char_data *victim, struct obj_data *obj) { struct affected_type af; assert(victim); assert(level >= 0); if (!affected_by_spell(victim, SPELL_ARMOR)) { af.type = SPELL_ARMOR; af.duration = 24; af.modifier = -20; af.location = APPLY_AC; af.bitvector = 0; affect_to_char(victim, &af); send_to_char("You feel someone protecting you.\n\r", victim); } } void spell_teleport(byte level, struct char_data *ch, struct char_data *victim, struct obj_data *obj) { int to_room,low,high,i; extern int top_of_world; /* ref to the top element of world */ void teleport_to(struct char_data *ch,int to_room); if(!ch || !victim) { log("Bad call to spell_teleport"); return; } if(world[ch->in_room].zone!=world[victim->in_room].zone) { send_to_char("Teleports must be with nearby people.",ch); return; } low=MAX(2,zone_table[world[ch->in_room].zone].real_bottom); high=zone_table[world[ch->in_room].zone].real_top; /* So people can't enter or leave arena by this spell */ if(IS_SET(world[victim->in_room].room_flags,ARENA)) { do { to_room = number(low, high); } while(!can_enter_room(victim,to_room,FALSE) && --level && IS_SET(world[to_room].room_flags,ARENA) && IS_SET(world[to_room].room_flags,NO_TELEPORT)); } else { do { to_room = number(low, high); } while(!can_enter_room(victim,to_room,FALSE) && --level && !IS_SET(world[to_room].room_flags,ARENA) && IS_SET(world[to_room].room_flags,NO_TELEPORT)); } if(level) teleport_to(victim,to_room); else { act("$n blurs for a moment, but remains here.",FALSE,victim,0,0,TO_ROOM); send_to_char("You feel weird for a second, but it fades away.\n\r",victim); } } void teleport_to(struct char_data *ch,int to_room) { act("$n slowly fades out of existence.", FALSE,ch,0,0,TO_ROOM); char_from_room(ch); char_to_room(ch, to_room,0); act("$n slowly fades into existence.", FALSE,ch,0,0,TO_ROOM); do_look(ch, "", 0); if (IS_SET(world[to_room].room_flags, DEATH) && !IS_TRUSTED(ch)) { death_cry(ch); extract_char(ch); } } void spell_bless(byte level, struct char_data *ch, struct char_data *victim, struct obj_data *obj) { struct affected_type af; assert(ch && (victim || obj)); assert(level >= 0); if (obj) { if ( (5*GET_LEVEL(ch) > GET_OBJ_WEIGHT(obj)) && (GET_POS(ch) != POSITION_FIGHTING) && !IS_OBJ_STAT(obj, ITEM_EVIL)) { SET_BIT(obj->obj_flags.extra_flags, ITEM_BLESS); act("$p briefly glows.",FALSE,ch,obj,0,TO_CHAR); } } else { if ((GET_POS(victim) != POSITION_FIGHTING) && (!affected_by_spell(victim, SPELL_BLESS))) { send_to_char("You feel righteous.\n\r", victim); af.type = SPELL_BLESS; af.duration = 6; af.modifier = 1; af.location = APPLY_HITROLL; af.bitvector = 0; affect_to_char(victim, &af); af.location = APPLY_SAVING_SPELL; af.modifier = -1; /* Make better */ affect_to_char(victim, &af); } } } void spell_blindness(byte level, struct char_data *ch, struct char_data *victim, struct obj_data *obj) { struct affected_type af; assert(ch && victim); assert(level >= 0); if(nokill(ch,victim)==TRUE){ return; } check_killer(ch,victim); if (saves_spell(victim, SAVING_SPELL) || affected_by_spell(victim, SPELL_BLINDNESS)) return; act("$n seems to be blinded!", TRUE, victim, 0, 0, TO_ROOM); send_to_char("You have been blinded!\n\r", victim); af.type = SPELL_BLINDNESS; af.location = APPLY_HITROLL; af.modifier = -4; /* Make hitroll worse */ af.duration = 1; af.bitvector = AFF_BLIND; affect_to_char(victim, &af); af.location = APPLY_AC; af.modifier = +40; /* Make AC Worse! */ affect_to_char(victim, &af); } void spell_clone(byte level, struct char_data *ch, struct char_data *victim, struct obj_data *obj) { assert(ch && (victim || obj)); assert(level >= 0); send_to_char("Clone is not ready yet.", ch); if (obj) { } else { /* clone_char(victim); */ } } void spell_control_weather(byte level, struct char_data *ch, struct char_data *victim, struct obj_data *obj) { /* Control Weather is not possible here!!! */ /* Better/Worse can not be transferred */ } void spell_create_food(byte level, struct char_data *ch, struct char_data *victim, struct obj_data *obj) { struct obj_data *tmp_obj; assert(ch); assert(level >= 0); if(!(tmp_obj=read_object(900,VIRTUAL))) { send_to_char("Bug! Please report!",ch); return; } tmp_obj->obj_flags.value[0] = 5+level; obj_to_room(tmp_obj,ch->in_room); act("$p suddenly appears.",TRUE,ch,tmp_obj,0,TO_ROOM); act("$p suddenly appears.",TRUE,ch,tmp_obj,0,TO_CHAR); } void spell_create_water(byte level, struct char_data *ch, struct char_data *victim, struct obj_data *obj) { int water; void name_to_drinkcon(struct obj_data *obj,int type); void name_from_drinkcon(struct obj_data *obj); assert(ch && obj); if (GET_ITEM_TYPE(obj) == ITEM_DRINKCON) { if ((obj->obj_flags.value[2] != LIQ_WATER) && (obj->obj_flags.value[1] != 0)) { name_from_drinkcon(obj); obj->obj_flags.value[2] = LIQ_SLIME; name_to_drinkcon(obj, LIQ_SLIME); } else { water = 2*level * ((zone_table[world[ch->in_room].zone].conditions.precip_rate > 5) ? 2 : 1); /* Calculate water it can contain, or water created */ water = MIN(obj->obj_flags.value[0]-obj->obj_flags.value[1], water); if (water > 0) { obj->obj_flags.value[2] = LIQ_WATER; obj->obj_flags.value[1] += water; weight_change_object(obj, water); name_from_drinkcon(obj); name_to_drinkcon(obj, LIQ_WATER); act("$p is filled.", FALSE, ch,obj,0,TO_CHAR); } } } } void spell_cure_blind(byte level, struct char_data *ch, struct char_data *victim, struct obj_data *obj) { assert(victim); assert(level >= 0); if (affected_by_spell(victim, SPELL_BLINDNESS)) { affect_from_char(victim, SPELL_BLINDNESS); send_to_char("Your vision returns!\n\r", victim); } } void spell_cure_critic(byte level, struct char_data *ch, struct char_data *victim, struct obj_data *obj) { int healpoints; assert(victim); assert(level >= 0); healpoints = dice(3,8)+3; if ( (healpoints + GET_HIT(victim)) > hit_limit(victim) ) GET_HIT(victim) = hit_limit(victim); else GET_HIT(victim) += healpoints; send_to_char("You feel better!\n\r", victim); update_pos(victim); } void spell_cure_light(byte level, struct char_data *ch, struct char_data *victim, struct obj_data *obj) { int healpoints; assert(ch && victim); assert(level >= 0); healpoints = dice(1,8); if ( (healpoints+GET_HIT(victim)) > hit_limit(victim) ) GET_HIT(victim) = hit_limit(victim); else GET_HIT(victim) += healpoints; update_pos( victim ); send_to_char("You feel better!\n\r", victim); } void spell_curse(byte level, struct char_data *ch, struct char_data *victim, struct obj_data *obj) { struct affected_type af; assert(victim || obj); assert(level >= 0); if(nokill(ch,victim)==TRUE){ return; } if(victim) check_killer(ch,victim); if (obj) { SET_BIT(obj->obj_flags.extra_flags, ITEM_EVIL); SET_BIT(obj->obj_flags.extra_flags, ITEM_NODROP); /* LOWER ATTACK DICE BY -1 */ if(obj->obj_flags.type_flag == ITEM_WEAPON) { if (obj->obj_flags.value[2] > 1) { obj->obj_flags.value[2]--; act("$p glows red.", FALSE, ch, obj, 0, TO_CHAR); } else { send_to_char("Nothing happens.\n\r", ch); } } } else { if ( saves_spell(victim, SAVING_SPELL) || affected_by_spell(victim, SPELL_CURSE)) return; af.type = SPELL_CURSE; af.duration = 24*7; /* 7 Days */ af.modifier = -1; af.location = APPLY_HITROLL; af.bitvector = AFF_CURSE; affect_to_char(victim, &af); af.location = APPLY_SAVING_PARA; af.modifier = 1; /* Make worse */ affect_to_char(victim, &af); act("$n briefly reveal a red aura!", FALSE, victim, 0, 0, TO_ROOM); act("You feel very uncomfortable.",FALSE,victim,0,0,TO_CHAR); } } void spell_detect_evil(byte level, struct char_data *ch, struct char_data *victim, struct obj_data *obj) { struct affected_type af; assert(victim); assert(level >= 0); if ( affected_by_spell(victim, SPELL_DETECT_EVIL) ) return; af.type = SPELL_DETECT_EVIL; af.duration = level*5; af.modifier = 0; af.location = APPLY_NONE; af.bitvector = AFF_DETECT_EVIL; affect_to_char(victim, &af); send_to_char("Your eyes tingle.\n\r", victim); } void spell_detect_invisibility(byte level, struct char_data *ch, struct char_data *victim, struct obj_data *obj) { struct affected_type af; assert(victim); assert(level >= 0); if ( affected_by_spell(victim, SPELL_DETECT_INVISIBLE) ) return; af.type = SPELL_DETECT_INVISIBLE; af.duration = level*5; af.modifier = 0; af.location = APPLY_NONE; af.bitvector = AFF_DETECT_INVISIBLE; affect_to_char(victim, &af); send_to_char("Your eyes tingle.\n\r", victim); } void spell_detect_magic(byte level, struct char_data *ch, struct char_data *victim, struct obj_data *obj) { struct affected_type af; assert(victim); assert(level >= 0); if ( affected_by_spell(victim, SPELL_DETECT_MAGIC) ) return; af.type = SPELL_DETECT_MAGIC; af.duration = level*5; af.modifier = 0; af.location = APPLY_NONE; af.bitvector = AFF_DETECT_MAGIC; affect_to_char(victim, &af); send_to_char("Your eyes tingle.\n\r", victim); } void spell_detect_poison(byte level, struct char_data *ch, struct char_data *victim, struct obj_data *obj) { assert(ch && (victim || obj)); if (victim) { if (victim == ch) if (IS_AFFECTED(victim, AFF_POISON)) send_to_char("You can sense poison in your blood.\n\r", ch); else send_to_char("You feel healthy.\n\r", ch); else if (IS_AFFECTED(victim, AFF_POISON)) { act("You sense that $E is poisoned.",FALSE,ch,0,victim,TO_CHAR); } else { act("You sense that $E is healthy.",FALSE,ch,0,victim,TO_CHAR); } } else { /* It's an object */ if ((obj->obj_flags.type_flag == ITEM_DRINKCON) || (obj->obj_flags.type_flag == ITEM_FOOD)) { if (obj->obj_flags.value[3]) act("Poisonous fumes are revealed.",FALSE, ch, 0, 0, TO_CHAR); else send_to_char("It looks very delicious.\n\r", ch); } } } void spell_enchant_weapon(byte level, struct char_data *ch, struct char_data *victim, struct obj_data *obj) { int i; assert(ch && obj); assert(MAX_OBJ_AFFECT >= 2); if ((GET_ITEM_TYPE(obj) == ITEM_WEAPON) && !IS_SET(obj->obj_flags.extra_flags, ITEM_MAGIC)) { for (i=0; i < MAX_OBJ_AFFECT; i++) if (obj->affected[i].location != APPLY_NONE) return; SET_BIT(obj->obj_flags.extra_flags, ITEM_MAGIC); obj->affected[0].location = APPLY_HITROLL; obj->affected[0].modifier = 1 + (level >= 18); obj->affected[1].location = APPLY_DAMROLL; obj->affected[1].modifier = 1 + (level >= 20); if (IS_GOOD(ch)) { SET_BIT(obj->obj_flags.extra_flags, ITEM_ANTI_EVIL); act("$p glows blue.",FALSE,ch,obj,0,TO_CHAR); } else if (IS_EVIL(ch)) { SET_BIT(obj->obj_flags.extra_flags, ITEM_ANTI_GOOD); act("$p glows red.",FALSE,ch,obj,0,TO_CHAR); } else { act("$p glows yellow.",FALSE,ch,obj,0,TO_CHAR); } } } void spell_heal(byte level, struct char_data *ch, struct char_data *victim, struct obj_data *obj) { assert(victim); spell_cure_blind(level, ch, victim, obj); GET_HIT(victim) += 100; if (GET_HIT(victim) >= hit_limit(victim)) GET_HIT(victim) = hit_limit(victim)-dice(1,4); update_pos( victim ); send_to_char("A warm feeling fills your body.\n\r", victim); } void spell_invisibility(byte level, struct char_data *ch, struct char_data *victim, struct obj_data *obj) { struct affected_type af; assert((ch && obj) || victim); if (obj) { if ( !IS_SET(obj->obj_flags.extra_flags, ITEM_INVISIBLE) ) { act("$p turns invisible.",FALSE,ch,obj,0,TO_CHAR); act("$p turns invisible.",TRUE,ch,obj,0,TO_ROOM); SET_BIT(obj->obj_flags.extra_flags, ITEM_INVISIBLE); } } else { /* Then it is a PC | NPC */ if (!affected_by_spell(victim, SPELL_INVISIBLE)) { act("$n slowly fade out of existence.", TRUE, victim,0,0,TO_ROOM); send_to_char("You vanish.\n\r", victim); af.type = SPELL_INVISIBLE; af.duration = 24; af.modifier = -40; af.location = APPLY_AC; af.bitvector = AFF_INVISIBLE; affect_to_char(victim, &af); } } } void spell_locate_object(byte level, struct char_data *ch, struct char_data *victim, struct obj_data *obj) { struct obj_data *i; char name[256]; char buf[MAX_STRING_LENGTH]; int j; assert(ch); strcpy(name, fname(obj->name)); j=level>>1; for (i = object_list; i && (j>0); i = i->next) if (isname(name, i->name)) { if((!IS_TRUSTED(ch) && number(0,100)<level*4) || !CAN_SEE_OBJ(ch,i)) ; else { if(i->carried_by) { sprintf(buf,"%s carried by %s.\n\r", i->short_description,PERS(i->carried_by,ch)); send_to_char(buf,ch); } else if (i->in_obj) { sprintf(buf,"%s in %s.\n\r", i->short_description, i->in_obj->short_description); send_to_char(buf,ch); } else if(i->equipped_by) { sprintf(buf,"%s equipped by %s.\n\r", i->short_description,PERS(i->equipped_by,ch)); send_to_char(buf,ch); } else { sprintf(buf,"%s in %s.\n\r", i->short_description, (i->in_room == NOWHERE ? "Uncertain." : world[i->in_room].name)); send_to_char(buf,ch); } if(!IS_TRUSTED(ch)) j--; } } if(j==0) send_to_char("You are very confused.\n\r",ch); if(j==level>>1) send_to_char("No such object.\n\r",ch); } void spell_poison(byte level, struct char_data *ch, struct char_data *victim, struct obj_data *obj) { struct affected_type af; assert(victim || obj); if (victim) { if(nokill(ch,victim)==TRUE){ return; } check_killer(ch,victim); if(!saves_spell(victim, SAVING_PARA)) { af.type = SPELL_POISON; af.duration = level*2; af.modifier = -2; af.location = APPLY_STR; af.bitvector = AFF_POISON; affect_join(victim, &af, FALSE, FALSE); send_to_char("You feel very sick.\n\r", victim); } } else { /* Object poison */ if ((obj->obj_flags.type_flag == ITEM_DRINKCON) || (obj->obj_flags.type_flag == ITEM_FOOD)) { obj->obj_flags.value[3] = 1; } } } void spell_protection_from_evil(byte level, struct char_data *ch, struct char_data *victim, struct obj_data *obj) { struct affected_type af; assert(victim); if (!affected_by_spell(victim, SPELL_PROTECT_FROM_EVIL) ) { af.type = SPELL_PROTECT_FROM_EVIL; af.duration = 24; af.modifier = 0; af.location = APPLY_NONE; af.bitvector = AFF_PROTECT_EVIL; affect_to_char(victim, &af); send_to_char("You have a righteous feeling!\n\r", victim); } } void spell_remove_curse(byte level, struct char_data *ch, struct char_data *victim, struct obj_data *obj) { struct affected_type af; assert(ch && (victim || obj)); if (obj) { if ( IS_SET(obj->obj_flags.extra_flags, ITEM_EVIL) || IS_SET(obj->obj_flags.extra_flags, ITEM_NODROP)) { act("$p briefly glows blue.", TRUE, ch, obj, 0, TO_CHAR); REMOVE_BIT(obj->obj_flags.extra_flags, ITEM_EVIL); REMOVE_BIT(obj->obj_flags.extra_flags, ITEM_NODROP); } } else { /* Then it is a PC | NPC */ if (affected_by_spell(victim, SPELL_CURSE) ) { act("$n briefly glows red, then blue.",FALSE,victim,0,0,TO_ROOM); act("You feel better.",FALSE,victim,0,0,TO_CHAR); affect_from_char(victim, SPELL_CURSE); } } } void spell_remove_poison(byte level, struct char_data *ch, struct char_data *victim, struct obj_data *obj) { assert(ch && (victim || obj)); if (victim) { if(affected_by_spell(victim,SPELL_POISON)) { affect_from_char(victim,SPELL_POISON); act("A warm feeling runs through your body.",FALSE,victim,0,0,TO_CHAR); act("$N looks better.",FALSE,ch,0,victim,TO_ROOM); } } else { if ((obj->obj_flags.type_flag == ITEM_DRINKCON) || (obj->obj_flags.type_flag == ITEM_FOOD)) { obj->obj_flags.value[3] = 0; act("The $p steams briefly.",FALSE,ch,obj,0,TO_CHAR); } } } void spell_sanctuary(byte level, struct char_data *ch, struct char_data *victim, struct obj_data *obj) { struct affected_type af; if (!affected_by_spell(victim, SPELL_SANCTUARY) && !(victim->specials.affected_by & AFF_SANCTUARY) ) { act("$n is surrounded by a white aura.",TRUE,victim,0,0,TO_ROOM); act("You start glowing.",TRUE,victim,0,0,TO_CHAR); af.type = SPELL_SANCTUARY; af.duration = (!IS_TRUSTED(ch)) ? 3 : level; af.modifier = 0; af.location = APPLY_NONE; af.bitvector = AFF_SANCTUARY; affect_to_char(victim, &af); } } void spell_sleep(byte level, struct char_data *ch, struct char_data *victim, struct obj_data *obj) { struct affected_type af; char buf[80]; assert(victim); /* You can't sleep someone higher level than you except in the arena*/ if ((GET_LEVEL(ch)<GET_LEVEL(victim))&& !IS_SET(world[ch->in_room].room_flags,ARENA)){ sprintf(buf,"%s laughs in your face at your feeble attempt.\n\r", GET_NAME(victim)); send_to_char(buf,ch); sprintf(buf,"%s tries to sleep you, but fails horribly.\n\r", GET_NAME(ch)); send_to_char(buf,ch); return; } if ( !saves_spell(victim, SAVING_SPELL) ) { af.type = SPELL_SLEEP; af.duration = 4+level; af.modifier = 0; af.location = APPLY_NONE; af.bitvector = AFF_SLEEP; affect_join(victim, &af, FALSE, FALSE); if (GET_POS(victim)>POSITION_SLEEPING) { act("You feel very sleepy... Zzzzzz",FALSE,victim,0,0,TO_CHAR); act("$n go to sleep.",TRUE,victim,0,0,TO_ROOM); GET_POS(victim)=POSITION_SLEEPING; } return; } } void spell_strength(byte level, struct char_data *ch, struct char_data *victim, struct obj_data *obj) { struct affected_type af; assert(victim); act("You feel stronger.", FALSE, victim,0,0,TO_CHAR); af.type = SPELL_STRENGTH; af.duration = level; af.modifier = 1+(level>18); af.location = APPLY_STR; af.bitvector = 0; affect_join(victim, &af, TRUE, FALSE); } void spell_ventriloquate(byte level, struct char_data *ch, struct char_data *victim, struct obj_data *obj) { /* Not possible!! No argument! */ } void spell_word_of_recall(byte level, struct char_data *ch, struct char_data *victim, struct obj_data *obj) { extern int top_of_world; int loc_nr,location; bool found = FALSE; assert(victim); if (IS_NPC(victim)) return; loc_nr = default_loc(GET_HOME(victim)); if (loc_nr==-1 || (location=real_room(loc_nr))==NOWHERE) { send_to_char("You are lost!\n\r",ch); log("RECALL: character's dest location not found."); return; } if(IS_SET(world[ch->in_room].room_flags,ARENA)) { act("$n is wrenched by a spell, but it fizzles out before completion.", FALSE,ch,0,0,TO_ROOM); act("You are tossed around by some force, which quickly dissipates.", FALSE,ch,0,0,TO_CHAR); return; } /* a location has been found. */ if(victim->specials.fighting) { lose_exp_by_flight(victim,victim->specials.fighting); stop_fighting(victim); } act("$n disappears.", TRUE, victim, 0, 0, TO_ROOM); char_from_room(victim); char_to_room(victim, location,0); act("$n appears in the middle of the room.", TRUE, victim, 0, 0, TO_ROOM); do_look(victim, "",15); } void spell_summon(byte level, struct char_data *ch, struct char_data *victim, struct obj_data *obj) { sh_int target; assert(ch && victim); if (IS_SET(victim->specials.act, PLR_NOSUMMON) && level < LV_DEMIGOD) { send_to_char("You failed.\n\r",ch); return; } if ((IS_SET(world[victim->in_room].room_flags, SAFE) || IS_SET(world[victim->in_room].room_flags, ARENA))&& !IS_TRUSTED(ch)){ send_to_char("That person is in a safe area!\n\r",ch); return; } if(IS_NPC(victim)&& !IS_TRUSTED(ch) && IS_SET(world[ch->in_room].room_flags, SAFE)) { send_to_char("You can't summon creatures to a safe area!\n\r",ch); return; } if(!IS_TRUSTED(ch) && IS_NPC(victim) && IS_SET(victim->specials.act,ACT_AGGRESSIVE)) { send_to_char("You feel a sudden surge of hatred and halt the spell.\n\r",ch); return; } if(!IS_NPC(victim) && IS_SET(world[ch->in_room].room_flags,ARENA)) { send_to_char("You can't bring in help in the arena.\n\r",ch); return; } if(!can_enter_room(victim,ch->in_room,FALSE)) { send_to_char("That person can't come here.\n\r",ch); return; } if(IS_SET(world[ch->in_room].room_flags, ARENA)) { send_to_char("The Arena Gods forbid outside help!\n\r",ch); return; } if (GET_LEVEL(victim) > level+3 || (IS_TRUSTED(victim) && !IS_TRUSTED(ch))) { send_to_char("You failed.\n\r",ch); return; } if (IS_NPC(victim) && saves_spell(victim, SAVING_SPELL) ) { send_to_char("You failed.\n\r", ch); return; } act("$n disappears suddenly.",TRUE,victim,0,0,TO_ROOM); target = ch->in_room; char_from_room(victim); char_to_room(victim,target,0); act("$n arrives suddenly.",TRUE,victim,0,0,TO_ROOM); act("$n has summoned you!",FALSE,ch,0,victim,TO_VICT); do_look(victim,"",15); if(!IS_NPC(victim)) SET_BIT(victim->specials.act,PLR_NOSUMMON); } void spell_charm_person(byte level, struct char_data *ch, struct char_data *victim, struct obj_data *obj) { struct affected_type af; void add_follower(struct char_data *ch, struct char_data *leader); bool circle_follow(struct char_data *ch, struct char_data *victim); void stop_follower(struct char_data *ch); assert(ch && victim); if (!IS_NPC(victim) && (GET_LEVEL(ch) < LV_DEMIGOD)) { send_to_char("Do to abuse, players can no longer be charmed.\n\r", ch); return; } /* By testing for IS_AFFECTED we avoid ei. Mordenkainens sword to be */ /* abel to be "recharmed" with duration */ if (victim == ch) { send_to_char("You like yourself even better!\n\r", ch); return; } if (!IS_AFFECTED(victim, AFF_CHARM) && !IS_AFFECTED(ch, AFF_CHARM) && (level >= GET_LEVEL(victim))) { if (circle_follow(victim, ch)) { send_to_char("Sorry, following in circles can not be allowed.\n\r", ch); return; } if (saves_spell(victim, SAVING_PARA)) return; if(IS_NPC(victim) && IS_SET(victim->specials.act,ACT_BREAK_CHARM)) { return; } if (victim->master) stop_follower(victim); add_follower(victim, ch); af.type = SPELL_CHARM_PERSON; if (GET_INT(victim)) af.duration = 24*18/GET_INT(victim); else af.duration = 24*18; af.modifier = 0; af.location = 0; af.bitvector = AFF_CHARM; affect_to_char(victim, &af); act("Isn't $n just such a nice fellow?",FALSE,ch,0,victim,TO_VICT); } } void spell_sense_life(byte level, struct char_data *ch, struct char_data *victim, struct obj_data *obj) { struct affected_type af; assert(victim); if (!affected_by_spell(victim, SPELL_SENSE_LIFE)) { send_to_char("Your feel your awareness improve.\n\r", ch); af.type = SPELL_SENSE_LIFE; af.duration = 5*level; af.modifier = 0; af.location = APPLY_NONE; af.bitvector = AFF_SENSE_LIFE; affect_to_char(victim, &af); } } /* *************************************************************************** * Not cast-able spells * * ************************************************************************* */ void spell_identify(byte level, struct char_data *ch, struct char_data *victim, struct obj_data *obj) { char buf[256], buf2[256]; int i; bool found; struct time_info_data age(struct char_data *ch); /* Spell Names */ extern char *spells[]; /* For Objects */ extern char *item_types[]; extern char *extra_bits[]; extern char *apply_types[]; extern char *affected_bits[]; assert(ch && (obj || victim)); if (obj) { send_to_char("You feel informed:\n\r", ch); sprintf(buf, "Object '%s', Item type: ", obj->name); sprinttype(GET_ITEM_TYPE(obj),item_types,buf2); strcat(buf,buf2); strcat(buf,"\n\r"); send_to_char(buf, ch); if (obj->obj_flags.bitvector) { send_to_char("Item will give you following abilities: ", ch); sprintbit(obj->obj_flags.bitvector,affected_bits,buf); strcat(buf,"\n\r"); send_to_char(buf, ch); } send_to_char("Item is: ", ch); sprintbit(obj->obj_flags.extra_flags,extra_bits,buf); strcat(buf,"\n\r"); send_to_char(buf,ch); sprintf(buf,"Weight: %d, Value: %d\n\r", obj->obj_flags.weight, obj->obj_flags.cost); send_to_char(buf, ch); switch (GET_ITEM_TYPE(obj)) { case ITEM_SCROLL : case ITEM_POTION : sprintf(buf, "Level %d spells of:\n\r", obj->obj_flags.value[0]); send_to_char(buf, ch); if (obj->obj_flags.value[1] >= 1) { sprinttype(obj->obj_flags.value[1]-1,spells,buf); strcat(buf,"\n\r"); send_to_char(buf, ch); } if (obj->obj_flags.value[2] >= 1) { sprinttype(obj->obj_flags.value[2]-1,spells,buf); strcat(buf,"\n\r"); send_to_char(buf, ch); } if (obj->obj_flags.value[3] >= 1) { sprinttype(obj->obj_flags.value[3]-1,spells,buf); strcat(buf,"\n\r"); send_to_char(buf, ch); } break; case ITEM_WAND : case ITEM_STAFF : sprintf(buf, "Has %d charges, with %d charges left.\n\r", obj->obj_flags.value[1], obj->obj_flags.value[2]); send_to_char(buf, ch); sprintf(buf, "Level %d spell of:\n\r", obj->obj_flags.value[0]); send_to_char(buf, ch); if (obj->obj_flags.value[3] >= 1) { sprinttype(obj->obj_flags.value[3]-1,spells,buf); strcat(buf,"\n\r"); send_to_char(buf, ch); } break; case ITEM_WEAPON : sprintf(buf, "Damage Dice is '%dD%d'\n\r", obj->obj_flags.value[1], obj->obj_flags.value[2]); send_to_char(buf, ch); break; case ITEM_ARMOR : sprintf(buf, "AC-apply is %d\n\r", obj->obj_flags.value[0]); send_to_char(buf, ch); break; } found = FALSE; for (i=0;i<MAX_OBJ_AFFECT;i++) { if ((obj->affected[i].location != APPLY_NONE) && (obj->affected[i].modifier != 0)) { if (!found) { send_to_char("Can affect you as :\n\r", ch); found = TRUE; } sprinttype(obj->affected[i].location,apply_types,buf2); sprintf(buf," Affects : %s By %d\n\r", buf2,obj->affected[i].modifier); send_to_char(buf, ch); } } } else { /* victim */ if (!IS_NPC(victim)) { sprintf(buf,"%d Years, %d Months, %d Days, %d Hours old.\n\r", age(victim).year, age(victim).month, age(victim).day, age(victim).hours); send_to_char(buf,ch); sprintf(buf,"Height %dcm Weight %dpounds \n\r", GET_HEIGHT(victim), GET_WEIGHT(victim)); send_to_char(buf,ch); /* sprintf(buf,"Str %d/%d, Int %d, Wis %d, Dex %d, Con %d\n\r", GET_STR(victim), GET_ADD(victim), GET_INT(victim), GET_WIS(victim), GET_DEX(victim), GET_CON(victim) ); send_to_char(buf,ch); */ } else { send_to_char("You learn nothing new.\n\r", ch); } } } /* *************************************************************************** * NPC spells.. * * ************************************************************************* */ void spell_fire_breath(byte level, struct char_data *ch, struct char_data *victim, struct obj_data *obj) { int dam; int hpch; struct obj_data *burn; assert(victim && ch); assert(level >= 1); hpch = GET_HIT(ch); if(hpch<10) hpch=10; dam = number(0,hpch>>2); if ( saves_spell(victim, SAVING_BREATH) ) dam >>= 1; damage(ch, victim, dam, SPELL_FIRE_BREATH); /* And now for the damage on inventory */ if(number(0,30)<GET_LEVEL(ch)) { if (!saves_spell(victim, SAVING_BREATH) ) { for(burn=victim->carrying ; burn && (burn->obj_flags.type_flag!=ITEM_SCROLL) && (burn->obj_flags.type_flag!=ITEM_WAND) && (burn->obj_flags.type_flag!=ITEM_STAFF) && (burn->obj_flags.type_flag!=ITEM_NOTE) && (number(0,2)==0) ; burn=burn->next_content); if(burn) { act("$o burns",0,victim,burn,0,TO_CHAR); extract_obj(burn); } } } } void spell_frost_breath(byte level, struct char_data *ch, struct char_data *victim, struct obj_data *obj) { int dam; int hpch; struct obj_data *frozen; assert(victim && ch); assert(level >= 1); hpch = GET_HIT(ch); if(hpch<10) hpch=10; dam = number(0,hpch>>2); if ( saves_spell(victim, SAVING_BREATH) ) dam >>= 1; damage(ch, victim, dam, SPELL_FROST_BREATH); /* And now for the damage on inventory */ if(number(0,30)<GET_LEVEL(ch)) { if (!saves_spell(victim, SAVING_BREATH) ) { for(frozen=victim->carrying ; frozen && (frozen->obj_flags.type_flag!=ITEM_DRINKCON) && (frozen->obj_flags.type_flag!=ITEM_FOOD) && (frozen->obj_flags.type_flag!=ITEM_POTION) && (number(0,2)==0) ; frozen=frozen->next_content); if(frozen) { act("$o breaks.",0,victim,frozen,0,TO_CHAR); extract_obj(frozen); } } } } void spell_acid_breath(byte level, struct char_data *ch, struct char_data *victim, struct obj_data *obj) { int dam; int hpch; int damaged; int apply_ac(struct char_data *ch, int eq_pos); assert(victim && ch); assert(level >= 1); hpch = GET_HIT(ch); if(hpch<10) hpch=10; dam = number(0,hpch>>2); if ( saves_spell(victim, SAVING_BREATH) ) dam >>= 1; damage(ch, victim, dam, SPELL_ACID_BREATH); /* And now for the damage on equipment */ if(number(0,30)<GET_LEVEL(ch)) { if (!saves_spell(victim, SAVING_BREATH) ) { for(damaged = 0; damaged<MAX_WEAR && (victim->equipment[damaged]) && (victim->equipment[damaged]->obj_flags.type_flag!=ITEM_ARMOR) && (victim->equipment[damaged]->obj_flags.value[0]>0) && (number(0,2)==0) ; damaged++); if(victim->equipment[damaged] && damaged<MAX_WEAR) { act("$o is damaged.",0,victim,victim->equipment[damaged],0,TO_CHAR); GET_AC(victim)-=apply_ac(victim,damaged); victim->equipment[damaged]->obj_flags.value[0]-=number(1,7); GET_AC(victim)+=apply_ac(victim,damaged); victim->equipment[damaged]->obj_flags.cost = 0; } } } } void spell_gas_breath(byte level, struct char_data *ch, struct char_data *victim, struct obj_data *obj) { int dam; int hpch; assert(victim && ch); assert(level >= 1); hpch = GET_HIT(ch); if(hpch<10) hpch=10; dam = number(0,hpch>>2); if ( saves_spell(victim, SAVING_BREATH) ) dam >>= 1; damage(ch, victim, dam, SPELL_GAS_BREATH); } void spell_lightning_breath(byte level, struct char_data *ch, struct char_data *victim, struct obj_data *obj) { int dam; int hpch; assert(victim && ch); assert(level >= 1); hpch = GET_HIT(ch); if(hpch<10) hpch=10; dam = number(0,hpch>>2); if ( saves_spell(victim, SAVING_BREATH) ) dam >>= 1; damage(ch, victim, dam, SPELL_LIGHTNING_BREATH); } void spell_levitate(byte level, struct char_data *ch, struct char_data *victim, struct obj_data *obj) { struct affected_type af; assert(victim); assert(level >= 0); af.type = SPELL_LEVITATE; af.duration = 2*GET_LEVEL(ch); af.modifier = 0; af.location = APPLY_NONE; af.bitvector = AFF_LEVITATE; if(GET_POS(victim)<POSITION_LEVITATED) { act("You float up in the air!",FALSE,victim,0,0,TO_CHAR); act("$n floats up in the air!",TRUE,victim,0,0,TO_ROOM); GET_POS(victim)=POSITION_LEVITATED; } affect_join(victim, &af, FALSE, FALSE); } void spell_fly(byte level, struct char_data *ch, struct char_data *victim, struct obj_data *obj) { struct affected_type af; assert(victim); assert(level >= 0); af.type = SPELL_FLY; af.duration = 2*GET_LEVEL(ch); af.modifier = 0; af.location = APPLY_NONE; af.bitvector = AFF_FLY; if(GET_POS(victim)<POSITION_FLYING) { act("You fly through the air, free as a bird!", FALSE,victim,0,0,TO_CHAR); act("$n flies through the air, free as a bird!",TRUE, victim,0,0,TO_ROOM); GET_POS(victim)=POSITION_FLYING; } affect_join(victim, &af, FALSE, FALSE); } /* A routine for ITEM_TELEPORT objects */ bool check_item_teleport(struct char_data *ch,char *arg,int cmd) { struct obj_data *obj=NULL; struct char_data *dummy; int bits; bits=generic_find(arg,FIND_OBJ_INV|FIND_OBJ_EQUIP|FIND_OBJ_ROOM,ch,&dummy,&obj); if(!obj) return FALSE; if(obj->obj_flags.type_flag!= ITEM_TELEPORT || obj->obj_flags.value[1]!=cmd) return FALSE; if(IS_SET(world[ch->in_room].room_flags,NO_MAGIC)) { send_to_char("That doesn't seem to do anything!\n\r",ch); return FALSE; } /* Ignore argument for now...eventually we could "throw dust Dbra"..*/ if(!obj->obj_flags.value[2] || (IS_SET(world[ch->in_room].room_flags,ARENA)!=IS_SET(world[real_room(obj->obj_flags.value[0])].room_flags,ARENA))) { send_to_char("Nothing happens.\n\r\n\r",ch); return; } act("$p in $n's hands suddenly glows brightly!",FALSE,ch,obj,0,TO_ROOM); act("$p in your hands suddenly glows brightly!",FALSE,ch,obj,0,TO_CHAR); teleport_to(ch,real_room(obj->obj_flags.value[0])); if(obj->obj_flags.value[2]>0) { if(!--obj->obj_flags.value[2]) { act("$p in $n's hands shatters and the pieces disappear in smoke.",TRUE,ch,obj,0,TO_ROOM); act("$p in your hands shatters and the pieces disappear in smoke.",TRUE,ch,obj,0,TO_CHAR); extract_obj(obj); } } } void spell_quickness(byte level, struct char_data *ch, struct char_data *victim, struct obj_data *obj) { struct affected_type af; assert(victim); act("You feel nimbler.", FALSE, victim,0,0,TO_CHAR); af.type = SPELL_QUICKNESS; af.duration = level; af.modifier = 1; af.location = APPLY_DEX; af.bitvector = 0; affect_join(victim, &af, TRUE, FALSE); }