version 1.72 | | version 1.73 |
---|
| | |
/* | | /* |
* static char *rcsid_spell_util_c = | | * static char *rcsid_spell_util_c = |
* "$Id: spell_util.c,v 1.72 2003/01/04 00:28:52 mwedel Exp $"; | | * "$Id: spell_util.c,v 1.73 2003/01/08 08:39:21 mwedel Exp $"; |
*/ | | */ |
| | |
| | |
| | |
int cast_spell(object *op,object *caster,int dir,int type,int ability,SpellTypeFrom item,char *stringarg) { | | int cast_spell(object *op,object *caster,int dir,int type,int ability,SpellTypeFrom item,char *stringarg) { |
char *godname; | | char *godname; |
spell *s=find_spell(type); | | spell *s=find_spell(type); |
int success=0,bonus; | | int success=0,bonus, mflags; |
int duration=SP_PARAMETERS[type].bdur; /* get the base duration */ | | int duration=SP_PARAMETERS[type].bdur; /* get the base duration */ |
| | |
if(!strcmp((godname=determine_god(op)),"none")) godname="A random spirit"; | | if(!strcmp((godname=determine_god(op)),"none")) godname="A random spirit"; |
| | |
if( spells[type].onself) dir = 0; | | if( spells[type].onself) dir = 0; |
} | | } |
| | |
| | /* Do a bunch of sanity checks to see if the player can cast the spell. |
| | * wizards bypass these checks. If your using a wand or potion, these |
| | * checks don't apply either. If your doing a summon spell and |
| | * have a golem, special work is needed there also. |
| | */ |
| | |
if(!(QUERY_FLAG(op, FLAG_WIZ))&& (op->type==PLAYER) && (op->contr->shoottype==range_magic) && | | if(!(QUERY_FLAG(op, FLAG_WIZ))&& (op->type==PLAYER) && (op->contr->shoottype==range_magic) && |
(item!=spellPotion)&& (!(IS_SUMMON_SPELL(type)&&op->contr->golem!=NULL))) { | | (item!=spellPotion)&& (!(IS_SUMMON_SPELL(type)&&op->contr->golem!=NULL))) { |
if( !spells[type].cleric && op->stats.sp<SP_level_spellpoint_cost(op,caster,type)) { | | if( !spells[type].cleric && op->stats.sp<SP_level_spellpoint_cost(op,caster,type)) { |
| | |
} | | } |
else if(spells[type].cleric && op->stats.grace<SP_level_spellpoint_cost(op,caster,type)) | | else if(spells[type].cleric && op->stats.grace<SP_level_spellpoint_cost(op,caster,type)) |
{ | | { |
/* it's possible for grace to go negative */ | | /* it's possible for grace to go negative |
/* Fine - let grace go negative, but how negative it is should really | | * Fine - let grace go negative, but how negative it is should really |
* put a limit on things - in the old method, chance was the same | | * put a limit on things - in the old method, chance was the same |
* no matter how negative it was. | | * no matter how negative it was. |
* Instead of subtracting 10 from the roll, add in grace (which is | | * Instead of subtracting 10 from the roll, add in grace (which is |
| | |
new_draw_info_format(NDI_UNIQUE, 0,op, | | new_draw_info_format(NDI_UNIQUE, 0,op, |
"%s grants your prayer, though you are unworthy.",godname); | | "%s grants your prayer, though you are unworthy.",godname); |
} | | } |
else | | else { |
{ | | |
prayer_failure(op,op->stats.grace,SP_level_spellpoint_cost(op,caster,type)); | | prayer_failure(op,op->stats.grace,SP_level_spellpoint_cost(op,caster,type)); |
new_draw_info_format(NDI_UNIQUE, 0,op,"%s ignores your prayer.",godname); | | new_draw_info_format(NDI_UNIQUE, 0,op,"%s ignores your prayer.",godname); |
return 0; | | return 0; |
| | |
new_draw_info(NDI_UNIQUE, 0,op, "You are unable to cast that spell."); | | new_draw_info(NDI_UNIQUE, 0,op, "You are unable to cast that spell."); |
return 0; | | return 0; |
} | | } |
| | |
/* If it is an ability, assume that the designer of the archetype knows | | /* If it is an ability, assume that the designer of the archetype knows |
* what they are doing. | | * what they are doing. |
*/ | | */ |
| | |
op->spelltype = type; | | op->spelltype = type; |
op->spell_state = 1; | | op->spell_state = 1; |
/* put the stringarg into the object struct so that when the | | /* put the stringarg into the object struct so that when the |
spell is actually cast, it knows about the stringarg. | | * spell is actually cast, it knows about the stringarg. |
necessary for the invoke command spells. */ | | * necessary for the invoke command spells. |
| | */ |
if(stringarg) { | | if(stringarg) { |
op->spellarg = strdup_local(stringarg); | | op->spellarg = strdup_local(stringarg); |
} | | } |
| | |
} | | } |
| | |
/* ban removed on clerical spells in no-magic areas */ | | /* ban removed on clerical spells in no-magic areas */ |
| | mflags = get_map_flags(op->map, NULL, op->x, op->y, NULL, NULL); |
| | |
if (!ability && item != spellPotion && | | if (!ability && item != spellPotion && |
( ((!s->cleric)&&blocks_magic(op->map,op->x,op->y))|| | | ( (!s->cleric && (mflags & P_NO_MAGIC)) || |
(( s->cleric)&&blocks_cleric(op->map,op->x,op->y)))) { | | (s->cleric && (mflags & P_NO_CLERIC)))) { |
| | |
if (op->type!=PLAYER) | | if (op->type!=PLAYER) |
return 0; | | return 0; |
| | |
if(s->cleric) | | if(s->cleric) |
new_draw_info_format(NDI_UNIQUE, 0,op,"This ground is unholy! %s ignores you.",godname); | | new_draw_info_format(NDI_UNIQUE, 0,op,"This ground is unholy! %s ignores you.",godname); |
else | | else |
| | |
} | | } |
if(s->sp==0) /* Shouldn't happen... */ | | if(s->sp==0) /* Shouldn't happen... */ |
return 0; | | return 0; |
return(random_roll(1, SP_level_spellpoint_cost(op,caster,type), op, | | return(random_roll(1, SP_level_spellpoint_cost(op,caster,type), op, PREFER_LOW)); |
PREFER_LOW)); | | |
} | | } |
if(settings.spell_encumbrance == TRUE && item == spellNormal && | | if(settings.spell_encumbrance == TRUE && item == spellNormal && |
op->type==PLAYER && (!s->cleric) ) { | | op->type==PLAYER && (!s->cleric) ) { |
| | |
int failure = random_roll(0, 199, op, PREFER_LOW) - | | int failure = random_roll(0, 199, op, PREFER_LOW) - |
op->contr->encumbrance +op->level -s->level +35; | | op->contr->encumbrance +op->level -s->level +35; |
| | |
| | |
*/ | | */ |
op->speed_left -= (s->time*PATH_TIME_MULT(op,s) / 10) * FABS(op->speed); | | op->speed_left -= (s->time*PATH_TIME_MULT(op,s) / 10) * FABS(op->speed); |
} | | } |
| | |
switch((enum spellnrs) type) { | | switch((enum spellnrs) type) { |
case SP_BULLET: | | case SP_BULLET: |
case SP_LARGE_BULLET: | | case SP_LARGE_BULLET: |
| | case SP_CAUSE_LIGHT: |
| | case SP_CAUSE_HEAVY: |
| | case SP_CAUSE_MEDIUM: |
| | case SP_CAUSE_CRITICAL: |
success = fire_arch(op,caster,dir,spellarch[type],type,1); | | success = fire_arch(op,caster,dir,spellarch[type],type,1); |
break; | | break; |
| | |
case SP_HOLY_ORB: | | case SP_HOLY_ORB: |
success = fire_arch(op,caster,dir,spellarch[type],type,0); | | success = fire_arch(op,caster,dir,spellarch[type],type,0); |
break; | | break; |
| | |
case SP_S_FIREBALL: | | case SP_S_FIREBALL: |
case SP_M_FIREBALL: | | case SP_M_FIREBALL: |
case SP_L_FIREBALL: | | case SP_L_FIREBALL: |
| | |
case SP_S_MANABALL: | | case SP_S_MANABALL: |
case SP_M_MANABALL: | | case SP_M_MANABALL: |
case SP_L_MANABALL: | | case SP_L_MANABALL: |
| | case SP_BALL_LIGHTNING: |
| | case SP_DIVINE_SHOCK: |
| | case SP_POISON_FOG: |
success = fire_arch(op,caster,dir,spellarch[type],type, !ability); | | success = fire_arch(op,caster,dir,spellarch[type],type, !ability); |
break; | | break; |
| | |
case SP_VITRIOL: | | case SP_VITRIOL: |
success = fire_arch(op,caster,dir,spellarch[type],type,0); | | success = fire_arch(op,caster,dir,spellarch[type],type,0); |
break; | | break; |
| | |
case SP_MASS_CONFUSION: | | case SP_MASS_CONFUSION: |
case SP_SHOCKWAVE: | | case SP_SHOCKWAVE: |
case SP_COLOR_SPRAY: | | case SP_COLOR_SPRAY: |
| | |
case SP_WRATHFUL_EYE: | | case SP_WRATHFUL_EYE: |
success = cast_cone(op,caster,dir,duration,type,spellarch[type],!ability); | | success = cast_cone(op,caster,dir,duration,type,spellarch[type],!ability); |
break; | | break; |
| | |
case SP_TURN_UNDEAD: | | case SP_TURN_UNDEAD: |
if(QUERY_FLAG(op,FLAG_UNDEAD)) { /* the undead *don't* cast this */ | | if(QUERY_FLAG(op,FLAG_UNDEAD)) { /* the undead *don't* cast this */ |
new_draw_info(NDI_UNIQUE, 0,op,"Your undead nature prevents you from turning undead!"); | | new_draw_info(NDI_UNIQUE, 0,op,"Your undead nature prevents you from turning undead!"); |
success=0; break; | | success=0; |
| | break; |
} | | } |
| | /* else fall through to holy word below */ |
case SP_HOLY_WORD: | | case SP_HOLY_WORD: |
success = cast_cone(op,caster,dir,duration+(turn_bonus[op->stats.Wis]/5),type, | | success = cast_cone(op,caster,dir,duration+(turn_bonus[op->stats.Wis]/5),type, |
spellarch[type],0); | | spellarch[type],0); |
break; | | break; |
| | |
case SP_HOLY_WRATH: | | case SP_HOLY_WRATH: |
case SP_INSECT_PLAGUE: | | case SP_INSECT_PLAGUE: |
case SP_RETRIBUTION: | | case SP_RETRIBUTION: |
success = cast_smite_spell(op,caster,dir,type); | | success = cast_smite_spell(op,caster,dir,type); |
break; | | break; |
| | |
case SP_SUNSPEAR: | | case SP_SUNSPEAR: |
case SP_FIREBOLT: | | case SP_FIREBOLT: |
case SP_FROSTBOLT: | | case SP_FROSTBOLT: |
| | |
case SP_MANA_BOLT: | | case SP_MANA_BOLT: |
success = fire_bolt(op,caster,dir,type,!ability); | | success = fire_bolt(op,caster,dir,type,!ability); |
break; | | break; |
| | |
case SP_BOMB: | | case SP_BOMB: |
success = create_bomb(op,caster,dir,type,"bomb"); | | success = create_bomb(op,caster,dir,type,"bomb"); |
break; | | break; |
| | |
case SP_GOLEM: | | case SP_GOLEM: |
case SP_FIRE_ELEM: | | case SP_FIRE_ELEM: |
case SP_WATER_ELEM: | | case SP_WATER_ELEM: |
case SP_EARTH_ELEM: | | case SP_EARTH_ELEM: |
case SP_AIR_ELEM: | | case SP_AIR_ELEM: |
| | case SP_MYSTIC_FIST: |
success = summon_monster(op,caster,dir,spellarch[type],type); | | success = summon_monster(op,caster,dir,spellarch[type],type); |
break; | | break; |
| | |
case SP_FINGER_DEATH: | | case SP_FINGER_DEATH: |
success = finger_of_death(op,caster,dir); | | success = finger_of_death(op,caster,dir); |
break; | | break; |
| | |
case SP_SUMMON_AVATAR: | | case SP_SUMMON_AVATAR: |
case SP_HOLY_SERVANT: { | | case SP_HOLY_SERVANT: { |
archetype *spat = find_archetype((type==SP_SUMMON_AVATAR)?"avatar":"holy_servant"); | | archetype *spat = find_archetype((type==SP_SUMMON_AVATAR)?"avatar":"holy_servant"); |
success = summon_avatar(op,caster,dir,spat,type); | | success = summon_avatar(op,caster,dir,spat,type); |
break; } | | break; |
| | } |
| | |
case SP_CONSECRATE: | | case SP_CONSECRATE: |
success = cast_consecrate(op); | | success = cast_consecrate(op); |
break; | | break; |
| | |
case SP_SUMMON_CULT: | | case SP_SUMMON_CULT: |
success = summon_cult_monsters(op,dir); | | success = summon_cult_monsters(op,dir); |
break; | | break; |
| | |
case SP_PET: | | case SP_PET: |
success = summon_pet(op,dir, item); | | success = summon_pet(op,dir, item); |
break; | | break; |
| | |
case SP_D_DOOR: | | case SP_D_DOOR: |
/* dimension door needs the actual caster, because that is what is | | /* dimension door needs the actual caster, because that is what is |
* moved. | | * moved. |
*/ | | */ |
success = dimension_door(op,dir); | | success = dimension_door(op,dir); |
break; | | break; |
| | |
case SP_DARKNESS: | | case SP_DARKNESS: |
case SP_WALL_OF_THORNS: | | case SP_WALL_OF_THORNS: |
case SP_CHAOS_POOL: | | case SP_CHAOS_POOL: |
| | |
case SP_EARTH_WALL: | | case SP_EARTH_WALL: |
success = magic_wall(op,caster,dir,type); | | success = magic_wall(op,caster,dir,type); |
break; | | break; |
| | |
case SP_MAGIC_MAPPING: | | case SP_MAGIC_MAPPING: |
if(op->type==PLAYER) { | | if(op->type==PLAYER) { |
spell_effect(SP_MAGIC_MAPPING, op->x, op->y, op->map, op); | | spell_effect(SP_MAGIC_MAPPING, op->x, op->y, op->map, op); |
| | |
success=1; | | success=1; |
} | | } |
break; | | break; |
| | |
case SP_FEAR: | | case SP_FEAR: |
if(op->type==PLAYER) | | if(op->type==PLAYER) |
bonus=fear_bonus[op->stats.Cha]; | | bonus=fear_bonus[op->stats.Cha]; |
| | |
bonus=caster->head==NULL?caster->level/3+1:caster->head->level/3+1; | | bonus=caster->head==NULL?caster->level/3+1:caster->head->level/3+1; |
success = cast_cone(op,caster,dir,duration+bonus,SP_FEAR,spellarch[type],!ability); | | success = cast_cone(op,caster,dir,duration+bonus,SP_FEAR,spellarch[type],!ability); |
break; | | break; |
| | |
case SP_WOW: | | case SP_WOW: |
success = cast_wow(op,dir,ability, item); | | success = cast_wow(op,dir,ability, item); |
break; | | break; |
| | |
case SP_DESTRUCTION: | | case SP_DESTRUCTION: |
success = cast_destruction(op,caster,5+op->stats.Int,AT_MAGIC); | | success = cast_destruction(op,caster,5+op->stats.Int,AT_MAGIC); |
break; | | break; |
| | |
case SP_PERCEIVE: | | case SP_PERCEIVE: |
success = perceive_self(op); | | success = perceive_self(op); |
break; | | break; |
| | |
case SP_WOR: | | case SP_WOR: |
success = cast_wor(op,caster); | | success = cast_wor(op,caster); |
break; | | break; |
| | |
case SP_INVIS: | | case SP_INVIS: |
case SP_INVIS_UNDEAD: | | case SP_INVIS_UNDEAD: |
case SP_IMPROVED_INVIS: | | case SP_IMPROVED_INVIS: |
success = cast_invisible(op,caster,type); | | success = cast_invisible(op,caster,type); |
break; | | break; |
| | |
case SP_PROBE: | | case SP_PROBE: |
success = probe(op,dir); | | success = probe(op,dir); |
break; | | break; |
| | |
case SP_CREATE_FOOD: | | case SP_CREATE_FOOD: |
success = cast_create_food(op,caster,dir,stringarg); | | success = cast_create_food(op,caster,dir,stringarg); |
break; | | break; |
| | |
case SP_EARTH_DUST: | | case SP_EARTH_DUST: |
success = cast_earth2dust(op,caster); | | success = cast_earth2dust(op,caster); |
break; | | break; |
| | |
case SP_REGENERATION: | | case SP_REGENERATION: |
case SP_BLESS: | | case SP_BLESS: |
case SP_CURSE: | | case SP_CURSE: |
| | |
case SP_RAGE: | | case SP_RAGE: |
success = cast_change_attr(op,caster,dir,type); | | success = cast_change_attr(op,caster,dir,type); |
break; | | break; |
| | |
case SP_RESTORATION: | | case SP_RESTORATION: |
case SP_HEAL: | | case SP_HEAL: |
case SP_MINOR_HEAL: | | case SP_MINOR_HEAL: |
| | |
case SP_CURE_DISEASE: | | case SP_CURE_DISEASE: |
success = cast_heal(op,dir,type); | | success = cast_heal(op,dir,type); |
break; | | break; |
| | |
case SP_REGENERATE_SPELLPOINTS: | | case SP_REGENERATE_SPELLPOINTS: |
success = cast_regenerate_spellpoints(op); | | success = cast_regenerate_spellpoints(op); |
break; | | break; |
| | |
case SP_SMALL_SPEEDBALL: | | case SP_SMALL_SPEEDBALL: |
case SP_LARGE_SPEEDBALL: | | case SP_LARGE_SPEEDBALL: |
success = cast_speedball(op,dir,type); | | success = cast_speedball(op,dir,type); |
break; | | break; |
| | |
case SP_POLYMORPH: | | case SP_POLYMORPH: |
#ifdef NO_POLYMORPH | | #ifdef NO_POLYMORPH |
/* Not great, but at least provide feedback so if players do have | | /* Not great, but at least provide feedback so if players do have |
| | |
success = cast_polymorph(op,dir); | | success = cast_polymorph(op,dir); |
#endif | | #endif |
break; | | break; |
| | |
case SP_CHARGING: | | case SP_CHARGING: |
success = recharge(op); | | success = recharge(op); |
break; | | break; |
| | |
case SP_CANCELLATION: | | case SP_CANCELLATION: |
success = fire_cancellation(op,dir,spellarch[type],!ability); | | success = fire_cancellation(op,dir,spellarch[type],!ability); |
break; | | break; |
| | |
case SP_ALCHEMY: | | case SP_ALCHEMY: |
success = alchemy(op); | | success = alchemy(op); |
break; | | break; |
| | |
case SP_REMOVE_CURSE: | | case SP_REMOVE_CURSE: |
case SP_REMOVE_DAMNATION: | | case SP_REMOVE_DAMNATION: |
success = remove_curse(op, type, item); | | success = remove_curse(op, type, item); |
break; | | break; |
| | |
case SP_IDENTIFY: | | case SP_IDENTIFY: |
success = cast_identify(op); | | success = cast_identify(op); |
break; | | break; |
| | |
case SP_DETECT_MAGIC: | | case SP_DETECT_MAGIC: |
case SP_DETECT_MONSTER: | | case SP_DETECT_MONSTER: |
case SP_DETECT_EVIL: | | case SP_DETECT_EVIL: |
| | |
case SP_SHOW_INVIS: | | case SP_SHOW_INVIS: |
success = cast_detection(op, type); | | success = cast_detection(op, type); |
break; | | break; |
| | |
case SP_AGGRAVATION: | | case SP_AGGRAVATION: |
aggravate_monsters(op); | | aggravate_monsters(op); |
success = 1; | | success = 1; |
break; | | break; |
case SP_BALL_LIGHTNING: | | |
case SP_DIVINE_SHOCK: | | case SP_METEOR_SWARM: |
case SP_POISON_FOG: | | |
success = fire_arch(op,caster,dir,spellarch[type],type,!ability); | | |
break; | | |
case SP_METEOR_SWARM: { | | |
success = 1; | | success = 1; |
fire_swarm(op, caster, dir, spellarch[type], SP_METEOR, | | fire_swarm(op, caster, dir, spellarch[type], SP_METEOR, |
die_roll(3, 3, op, PREFER_HIGH) + | | die_roll(3, 3, op, PREFER_HIGH) + |
SP_level_strength_adjust(op,caster, type), 0); | | SP_level_strength_adjust(op,caster, type), 0); |
break; | | break; |
} | | |
case SP_BULLET_SWARM: { | | case SP_BULLET_SWARM: |
success = 1; | | success = 1; |
fire_swarm(op, caster, dir, spellarch[type], SP_BULLET, | | fire_swarm(op, caster, dir, spellarch[type], SP_BULLET, |
die_roll(3, 3, op, PREFER_HIGH) + | | die_roll(3, 3, op, PREFER_HIGH) + |
SP_level_strength_adjust(op,caster, type), 0); | | SP_level_strength_adjust(op,caster, type), 0); |
break; | | break; |
} | | |
case SP_BULLET_STORM: { | | case SP_BULLET_STORM: |
success = 1; | | success = 1; |
fire_swarm(op, caster, dir, spellarch[type], SP_LARGE_BULLET, | | fire_swarm(op, caster, dir, spellarch[type], SP_LARGE_BULLET, |
die_roll(3, 3, op, PREFER_HIGH) + | | die_roll(3, 3, op, PREFER_HIGH) + |
SP_level_strength_adjust(op,caster, type), 0); | | SP_level_strength_adjust(op,caster, type), 0); |
break; | | break; |
} | | |
case SP_CAUSE_MANY: { | | case SP_CAUSE_MANY: |
success = 1; | | success = 1; |
fire_swarm(op, caster, dir, spellarch[type], SP_CAUSE_HEAVY, | | fire_swarm(op, caster, dir, spellarch[type], SP_CAUSE_HEAVY, |
die_roll(3, 3, op, PREFER_HIGH) + | | die_roll(3, 3, op, PREFER_HIGH) + |
SP_level_strength_adjust(op,caster, type), 0); | | SP_level_strength_adjust(op,caster, type), 0); |
break; | | break; |
} | | |
| | case SP_MISSILE_SWARM: |
| | success = 1; |
| | fire_swarm(op, caster, dir, spellarch[type], SP_M_MISSILE, |
| | die_roll(3, 3, op, PREFER_HIGH) + |
| | SP_level_strength_adjust(op,caster, type), 0); |
| | break; |
| | |
case SP_METEOR: | | case SP_METEOR: |
success = fire_arch(op,caster,dir,find_archetype("meteor"),type,0); | | success = fire_arch(op,caster,dir,find_archetype("meteor"),type,0); |
break; | | break; |
case SP_MYSTIC_FIST: | | |
success = summon_monster(op,caster,dir,spellarch[type],type); | | |
break; | | |
case SP_RAISE_DEAD: | | case SP_RAISE_DEAD: |
case SP_RESURRECTION: | | case SP_RESURRECTION: |
success = cast_raise_dead_spell(op,dir,type, NULL); | | success = cast_raise_dead_spell(op,dir,type, NULL); |
break; | | break; |
/* mlee */ | | |
case SP_IMMUNE_COLD: | | case SP_IMMUNE_COLD: |
case SP_IMMUNE_FIRE: | | case SP_IMMUNE_FIRE: |
case SP_IMMUNE_ELEC: | | case SP_IMMUNE_ELEC: |
| | |
case SP_HASTE: | | case SP_HASTE: |
success=cast_change_attr(op,caster,dir,type); | | success=cast_change_attr(op,caster,dir,type); |
break; | | break; |
/* peterm, additional spells added */ | | |
| | |
case SP_BUILD_DIRECTOR: | | case SP_BUILD_DIRECTOR: |
case SP_BUILD_BWALL: | | case SP_BUILD_BWALL: |
case SP_BUILD_LWALL: | | case SP_BUILD_LWALL: |
case SP_BUILD_FWALL: | | case SP_BUILD_FWALL: |
success=create_the_feature(op,caster,dir,type); | | success=create_the_feature(op,caster,dir,type); |
break; | | break; |
| | |
case SP_RUNE_FIRE: | | case SP_RUNE_FIRE: |
case SP_RUNE_FROST: | | case SP_RUNE_FROST: |
case SP_RUNE_SHOCK: | | case SP_RUNE_SHOCK: |
| | |
case SP_RUNE_ANTIMAGIC: | | case SP_RUNE_ANTIMAGIC: |
success = write_rune(op,dir,0,caster->level,s->archname); | | success = write_rune(op,dir,0,caster->level,s->archname); |
break; | | break; |
| | |
case SP_RUNE_DRAINSP: | | case SP_RUNE_DRAINSP: |
success = write_rune(op,dir,SP_MAGIC_DRAIN,caster->level,s->archname); | | success = write_rune(op,dir,SP_MAGIC_DRAIN,caster->level,s->archname); |
break; | | break; |
| | |
case SP_RUNE_TRANSFER: | | case SP_RUNE_TRANSFER: |
success= write_rune(op,dir,SP_TRANSFER,caster->level,s->archname); | | success= write_rune(op,dir,SP_TRANSFER,caster->level,s->archname); |
break; | | break; |
| | |
case SP_TRANSFER: | | case SP_TRANSFER: |
success = cast_transfer(op,dir); | | success = cast_transfer(op,dir); |
break; | | break; |
| | |
case SP_MAGIC_DRAIN: | | case SP_MAGIC_DRAIN: |
success= drain_magic(op,dir); | | success= drain_magic(op,dir); |
break; | | break; |
| | |
case SP_DISPEL_RUNE: | | case SP_DISPEL_RUNE: |
success = dispel_rune(op,dir,0); /* 0 means no risk of detonating rune */ | | success = dispel_rune(op,dir,0); /* 0 means no risk of detonating rune */ |
break; | | break; |
| | |
case SP_SUMMON_EVIL_MONST: | | case SP_SUMMON_EVIL_MONST: |
if(op->type==PLAYER) return 0; | | if(op->type==PLAYER) return 0; |
success = summon_hostile_monsters(op,op->stats.maxhp,op->race); | | success = summon_hostile_monsters(op,op->stats.maxhp,op->race); |
break; | | break; |
| | |
case SP_REINCARNATION: | | case SP_REINCARNATION: { |
{ | | |
object * dummy; | | object * dummy; |
if(stringarg==NULL) { | | if(stringarg==NULL) { |
new_draw_info(NDI_UNIQUE, 0,op,"Reincarnate WHO?"); | | new_draw_info(NDI_UNIQUE, 0,op,"Reincarnate WHO?"); |
| | |
free_object(dummy); | | free_object(dummy); |
} | | } |
break; | | break; |
| | |
case SP_RUNE_MAGIC: | | case SP_RUNE_MAGIC: |
case SP_GLYPH: | | case SP_GLYPH: |
return cast_generic_rune(op, caster, dir, stringarg, type); | | return cast_generic_rune(op, caster, dir, stringarg, type); |
| | |
stringarg=NULL; | | stringarg=NULL; |
} | | } |
break; | | break; |
| | |
case SP_LIGHT: | | case SP_LIGHT: |
success = cast_light(op,caster,dir); | | success = cast_light(op,caster,dir); |
break; | | break; |
| | |
case SP_DAYLIGHT: | | case SP_DAYLIGHT: |
success = cast_daylight(op); | | success = cast_daylight(op); |
break; | | break; |
| | |
case SP_NIGHTFALL: | | case SP_NIGHTFALL: |
success = cast_nightfall(op); | | success = cast_nightfall(op); |
break; | | break; |
| | |
case SP_FAERY_FIRE: | | case SP_FAERY_FIRE: |
success = cast_faery_fire(op,caster); | | success = cast_faery_fire(op,caster); |
break; | | break; |
case SP_CAUSE_LIGHT: | | |
case SP_CAUSE_HEAVY: | | |
case SP_CAUSE_MEDIUM: | | |
case SP_CAUSE_CRITICAL: | | |
success = fire_arch(op,caster,dir,spellarch[type],type,1); /* don't want to OR magic */ | | |
break; | | |
case SP_SUMMON_FOG: | | case SP_SUMMON_FOG: |
success = summon_fog(op,caster,dir,type); | | success = summon_fog(op,caster,dir,type); |
break; | | break; |
| | |
case SP_PACIFY: | | case SP_PACIFY: |
cast_pacify(op,caster,spellarch[type],type); | | cast_pacify(op,caster,spellarch[type],type); |
success = 1; | | success = 1; |
break; | | break; |
| | |
case SP_COMMAND_UNDEAD: | | case SP_COMMAND_UNDEAD: |
cast_charm_undead(op,caster,spellarch[type],type); | | cast_charm_undead(op,caster,spellarch[type],type); |
success = 1; | | success = 1; |
break; | | break; |
| | |
case SP_CHARM: | | case SP_CHARM: |
cast_charm(op,caster,spellarch[type],type); | | cast_charm(op,caster,spellarch[type],type); |
success = 1; | | success = 1; |
break; | | break; |
/* huma */ | | |
case SP_CREATE_MISSILE: | | case SP_CREATE_MISSILE: |
success = cast_create_missile(op,caster,dir,stringarg); | | success = cast_create_missile(op,caster,dir,stringarg); |
break; | | break; |
| | |
case SP_CAUSE_COLD: | | case SP_CAUSE_COLD: |
case SP_CAUSE_EBOLA: | | case SP_CAUSE_EBOLA: |
case SP_CAUSE_FLU: | | case SP_CAUSE_FLU: |
| | |
case SP_CAUSE_RABIES: | | case SP_CAUSE_RABIES: |
success = cast_cause_disease(op,caster,dir,spellarch[type],type); | | success = cast_cause_disease(op,caster,dir,spellarch[type],type); |
break; | | break; |
/* DAMN */ | | |
case SP_DANCING_SWORD: | | case SP_DANCING_SWORD: |
case SP_STAFF_TO_SNAKE: | | case SP_STAFF_TO_SNAKE: |
case SP_ANIMATE_WEAPON: | | case SP_ANIMATE_WEAPON: |
success = animate_weapon(op,caster,dir,spellarch[type],type); | | success = animate_weapon(op,caster,dir,spellarch[type],type); |
break; | | break; |
| | |
case SP_SANCTUARY: | | case SP_SANCTUARY: |
case SP_FLAME_AURA: | | case SP_FLAME_AURA: |
success = create_aura(op,caster,spellarch[type],type,0); | | success = create_aura(op,caster,spellarch[type],type,0); |
break; | | break; |
| | |
case SP_CONFLICT: | | case SP_CONFLICT: |
success = cast_cause_conflict(op,caster,spellarch[type],type); | | success = cast_cause_conflict(op,caster,spellarch[type],type); |
break; | | break; |
| | |
case SP_TOWN_PORTAL: | | case SP_TOWN_PORTAL: |
success= cast_create_town_portal (op,caster,dir); | | success= cast_create_town_portal (op,caster,dir); |
break; | | break; |
case SP_MISSILE_SWARM: { | | |
success = 1; | | |
fire_swarm(op, caster, dir, spellarch[type], SP_M_MISSILE, | | |
die_roll(3, 3, op, PREFER_HIGH) + | | |
SP_level_strength_adjust(op,caster, type), 0); | | |
break; | | |
} | | |
} | | } |
| | |
play_sound_map(op->map, op->x, op->y, SOUND_CAST_SPELL_0 + type); | | play_sound_map(op->map, op->x, op->y, SOUND_CAST_SPELL_0 + type); |
| | |
| | |
int cast_create_obj(object *op,object *caster,object *new_op, int dir) | | int cast_create_obj(object *op,object *caster,object *new_op, int dir) |
{ | | { |
if(dir && blocked(op->map,op->x+freearr_x[dir],op->y+freearr_y[dir])) { | | if(dir && |
| | (get_map_flags(op->map,NULL, op->x+freearr_x[dir],op->y+freearr_y[dir], NULL, NULL) & (P_BLOCKED | P_OUT_OF_MAP))) { |
new_draw_info(NDI_UNIQUE, 0,op,"Something is in the way."); | | new_draw_info(NDI_UNIQUE, 0,op,"Something is in the way."); |
new_draw_info(NDI_UNIQUE, 0,op,"You cast it at your feet."); | | new_draw_info(NDI_UNIQUE, 0,op,"You cast it at your feet."); |
dir = 0; | | dir = 0; |
| | |
| | |
int summon_monster(object *op,object *caster,int dir,archetype *at,int spellnum) { | | int summon_monster(object *op,object *caster,int dir,archetype *at,int spellnum) { |
object *tmp; | | object *tmp; |
| | sint16 x, y; |
| | mapstruct *m; |
| | |
if(op->type==PLAYER) | | if(op->type==PLAYER) |
if(op->contr->golem!=NULL&&!QUERY_FLAG(op->contr->golem,FLAG_FREED)) { | | if (op->contr->golem!=NULL && op->contr->golem_count == op->contr->golem->count) { |
control_golem(op->contr->golem,dir); | | control_golem(op->contr->golem,dir); |
return 0; | | return 0; |
} | | } |
| | |
if(!dir) | | if(!dir) |
dir=find_free_spot(NULL,op->map,op->x,op->y,1,9); | | dir=find_free_spot(NULL,op->map,op->x,op->y,1,9); |
if((dir==-1) || blocked(op->map,op->x+freearr_x[dir],op->y+freearr_y[dir])) { | | |
| | m = op->map; |
| | x = op->x+freearr_x[dir]; |
| | y = op->y+freearr_y[dir]; |
| | |
| | if((dir==-1) || get_map_flags(m, &m, x, y, &x, &y) & (P_BLOCKED | P_OUT_OF_MAP)) { |
new_draw_info(NDI_UNIQUE, 0,op,"There is something in the way."); | | new_draw_info(NDI_UNIQUE, 0,op,"There is something in the way."); |
return 0; | | return 0; |
} | | } |
| | |
tmp=arch_to_object(at); | | tmp=arch_to_object(at); |
if(op->type==PLAYER) { | | if(op->type==PLAYER) { |
CLEAR_FLAG(tmp, FLAG_MONSTER); | | CLEAR_FLAG(tmp, FLAG_MONSTER); |
| | |
} | | } |
| | |
/* make the speed positive.*/ | | /* make the speed positive.*/ |
| | tmp->speed = FABS(tmp->speed); |
if(tmp->speed < 0) tmp->speed = -tmp->speed; | | |
| | |
/* This sets the level dependencies on dam and hp for monsters */ | | /* This sets the level dependencies on dam and hp for monsters */ |
if(op->type==PLAYER) { /* players can't cope with too strong summonings. */ | | /* players can't cope with too strong summonings. */ |
/* but monsters can. reserve these for players. */ | | /* but monsters can. reserve these for players. */ |
| | if(op->type==PLAYER) { |
tmp->stats.hp = SP_PARAMETERS[spellnum].bdur + | | tmp->stats.hp = SP_PARAMETERS[spellnum].bdur + |
10 * SP_level_strength_adjust(op,caster,spellnum); | | 10 * SP_level_strength_adjust(op,caster,spellnum); |
tmp->stats.dam= SP_PARAMETERS[spellnum].bdam + | | tmp->stats.dam= SP_PARAMETERS[spellnum].bdam + |
| | |
/* make experience increase in proportion to the strength of the summoned creature. */ | | /* make experience increase in proportion to the strength of the summoned creature. */ |
tmp->stats.exp *= SP_level_spellpoint_cost(op,caster,spellnum)/spells[spellnum].sp; | | tmp->stats.exp *= SP_level_spellpoint_cost(op,caster,spellnum)/spells[spellnum].sp; |
tmp->speed_left= -1; | | tmp->speed_left= -1; |
tmp->x=op->x+freearr_x[dir],tmp->y=op->y+freearr_y[dir]; | | tmp->x=x; |
| | tmp->y=y; |
tmp->direction=dir; | | tmp->direction=dir; |
insert_ob_in_map(tmp,op->map,op,0); | | insert_ob_in_map(tmp,m,op,0); |
return 1; | | return 1; |
} | | } |
| | |
| | |
* function doing so. | | * function doing so. |
*/ | | */ |
| | |
static int ok_to_put_more(mapstruct *m,int x,int y,object *op,int immune_stop) { | | static int ok_to_put_more(mapstruct *m,sint16 x,sint16 y,object *op,int immune_stop) { |
object *tmp; | | object *tmp; |
| | int mflags; |
| | mapstruct *mp; |
| | |
/* No check for out of map was here before - probably caught when the | | mp = m; |
* calling function tries to insert the object. But a check here | | mflags = get_map_flags(m, &mp, x, y, &x, &y); |
* should only be a minor performance hit, and is a good thing. | | |
*/ | | |
| | |
if (out_of_map(m,x,y)) return 0; | | |
| | |
if (OUT_OF_REAL_MAP(m,x,y)) | | if (mflags & P_OUT_OF_MAP) return 0; |
m = get_map_from_coord(m,&x,&y); | | |
| | |
/* if there is a wall, certainly can't put the spell there. The blocks | | if(mflags & P_WALL) return 0; |
* view check is historic from the old calling functions - my personal | | |
* view is that blocks view should not affect spells in any way, but | | |
* I will leave it in for now. | | |
*/ | | |
if(wall(m,x,y) || blocks_view(m,x,y)) return 0; | | |
| | |
for(tmp=get_map_ob(m,x,y);tmp!=NULL;tmp=tmp->above) { | | for(tmp=get_map_ob(m,x,y);tmp!=NULL;tmp=tmp->above) { |
/* If there is a counterspell on the space, and this | | /* If there is a counterspell on the space, and this |
| | |
| | |
int fire_bolt(object *op,object *caster,int dir,int type,int magic) { | | int fire_bolt(object *op,object *caster,int dir,int type,int magic) { |
object *tmp=NULL; | | object *tmp=NULL; |
| | int mflags; |
| | |
if (!spellarch[type]) | | if (!spellarch[type]) |
return 0; | | return 0; |
| | |
tmp=arch_to_object(spellarch[type]); | | tmp=arch_to_object(spellarch[type]); |
if(tmp==NULL) | | if(tmp==NULL) |
return 0; | | return 0; |
| | |
/* peterm: level dependency for bolts */ | | /* peterm: level dependency for bolts */ |
tmp->stats.dam = SP_PARAMETERS[type].bdam + SP_level_dam_adjust(op,caster,type); | | tmp->stats.dam = SP_PARAMETERS[type].bdam + SP_level_dam_adjust(op,caster,type); |
tmp->stats.hp = SP_PARAMETERS[type].bdur + SP_level_strength_adjust(op,caster,type); | | tmp->stats.hp = SP_PARAMETERS[type].bdur + SP_level_strength_adjust(op,caster,type); |
if(magic) | | if(magic) |
tmp->attacktype|=AT_MAGIC; | | tmp->attacktype|=AT_MAGIC; |
| | |
tmp->x=op->x,tmp->y=op->y; | | tmp->x=op->x,tmp->y=op->y; |
tmp->direction=dir; | | tmp->direction=dir; |
if(QUERY_FLAG(tmp, FLAG_IS_TURNABLE)) | | if(QUERY_FLAG(tmp, FLAG_IS_TURNABLE)) |
SET_ANIMATION(tmp, dir); | | SET_ANIMATION(tmp, dir); |
set_owner(tmp,op); | | set_owner(tmp,op); |
tmp->level = SK_level (caster); | | tmp->level = SK_level (caster); |
tmp->x+=DIRX(tmp),tmp->y+=DIRY(tmp); | | tmp->x+=DIRX(tmp); |
if(wall(op->map,tmp->x,tmp->y)) { | | tmp->y+=DIRY(tmp); |
| | tmp->map = op->map; |
| | |
| | mflags = get_map_flags(tmp->map, &tmp->map, tmp->x, tmp->y, &tmp->x, &tmp->y); |
| | if (mflags & P_OUT_OF_MAP) { |
| | free_object(tmp); |
| | return 0; |
| | } |
| | if (mflags & P_WALL) { |
if(!QUERY_FLAG(tmp, FLAG_REFLECTING)) { | | if(!QUERY_FLAG(tmp, FLAG_REFLECTING)) { |
free_object(tmp); | | free_object(tmp); |
return 0; | | return 0; |
} | | } |
tmp->x=op->x,tmp->y=op->y; | | tmp->x=op->x,tmp->y=op->y; |
tmp->direction=absdir(tmp->direction+4); | | tmp->direction=absdir(tmp->direction+4); |
| | tmp->map = op->map; |
} | | } |
if ((tmp = insert_ob_in_map(tmp,op->map,op,0)) != NULL) | | if ((tmp = insert_ob_in_map(tmp,tmp->map,op,0)) != NULL) |
move_bolt (tmp); | | move_bolt (tmp); |
return 1; | | return 1; |
} | | } |
| | |
object *tmp; | | object *tmp; |
int i,success=0,range_min= -1,range_max=1; | | int i,success=0,range_min= -1,range_max=1; |
| | |
if(!dir) | | if(!dir) { |
range_min= -3,range_max=4,strength/=2; | | range_min= -3; |
| | range_max=4; |
| | strength/=2; |
| | } |
| | |
for(i=range_min;i<=range_max;i++) { | | for(i=range_min;i<=range_max;i++) { |
int x=op->x+freearr_x[absdir(dir+i)], | | int x=op->x+freearr_x[absdir(dir+i)], |
y=op->y+freearr_y[absdir(dir+i)]; | | y=op->y+freearr_y[absdir(dir+i)]; |
if(wall(op->map,x,y)) | | |
| | if(get_map_flags(op->map,NULL, x,y, NULL, NULL) & P_WALL) |
continue; | | continue; |
| | |
success=1; | | success=1; |
tmp=arch_to_object(spell_arch); | | tmp=arch_to_object(spell_arch); |
set_owner(tmp,op); | | set_owner(tmp,op); |
| | |
if((tmp->attacktype&AT_HOLYWORD)||(tmp->attacktype&AT_GODPOWER)) { | | if((tmp->attacktype&AT_HOLYWORD)||(tmp->attacktype&AT_GODPOWER)) { |
if(!tailor_god_spell(tmp,op)) return 0; | | if(!tailor_god_spell(tmp,op)) return 0; |
} else /* god/holy word isnt really 'magic' */ | | } else /* god/holy word isnt really 'magic' */ |
| | |
if(magic) | | if(magic) |
tmp->attacktype|=AT_MAGIC; /* JWI cone attacks should be considered | | tmp->attacktype|=AT_MAGIC; /* JWI cone attacks should be considered |
magical in nature ;) */ | | magical in nature ;) */ |
| | |
tmp->stats.sp=dir; | | tmp->stats.sp=dir; |
else | | else |
tmp->stats.sp=i; | | tmp->stats.sp=i; |
| | |
tmp->stats.hp=strength+SP_level_strength_adjust(op,caster,spell_type); | | tmp->stats.hp=strength+SP_level_strength_adjust(op,caster,spell_type); |
tmp->stats.dam=SP_PARAMETERS[spell_type].bdam + | | tmp->stats.dam=SP_PARAMETERS[spell_type].bdam + |
SP_level_dam_adjust(op,caster,spell_type); | | SP_level_dam_adjust(op,caster,spell_type); |
tmp->stats.maxhp=tmp->count; | | tmp->stats.maxhp=tmp->count; |
| | |
if ( ! QUERY_FLAG (tmp, FLAG_FLYING)) | | if ( ! QUERY_FLAG (tmp, FLAG_FLYING)) |
LOG (llevDebug, "cast_cone(): arch %s doesn't have flying 1\n", | | LOG (llevDebug, "cast_cone(): arch %s doesn't have flying 1\n", |
spell_arch->name); | | spell_arch->name); |
| | |
if (( ! QUERY_FLAG (tmp, FLAG_WALK_ON) || ! QUERY_FLAG (tmp, FLAG_FLY_ON)) | | if (( ! QUERY_FLAG (tmp, FLAG_WALK_ON) || ! QUERY_FLAG (tmp, FLAG_FLY_ON)) |
&& tmp->stats.dam) | | && tmp->stats.dam) |
| | |
LOG (llevDebug, "cast_cone(): arch %s doesn't have walk_on 1 and " | | LOG (llevDebug, "cast_cone(): arch %s doesn't have walk_on 1 and " |
"fly_on 1\n", spell_arch->name); | | "fly_on 1\n", spell_arch->name); |
| | |
insert_ob_in_map(tmp,op->map,op,0); | | insert_ob_in_map(tmp,op->map,op,0); |
if(tmp->other_arch) cone_drop(tmp); | | if(tmp->other_arch) cone_drop(tmp); |
} | | } |
| | |
move_object(tmp, absdir(op->stats.sp)); | | move_object(tmp, absdir(op->stats.sp)); |
} | | } |
| | |
#if 0 | | |
int nx,ny; | | |
/* This block of code doesn't work for multispaced monsters (or potentially | | |
* other multispaced objects). Since we already have move_ob which will | | |
* do most of this work for us, might as well use that. | | |
*/ | | |
| | |
nx = op->x + freearr_x[absdir(op->stats.sp)]; | | |
ny = op->y + freearr_y[absdir(op->stats.sp)]; | | |
| | |
/* don't try to move something someplace where it can't go */ | | |
if(arch_blocked(tmp->arch,op->map,nx,ny)) continue; | | |
| | |
/* OK, now we decide if we're going to move it */ | | |
/* assume a weightless thing is a spell or whatever */ | | |
if(tmp->weight==0) continue; | | |
| | |
/* count the object's sections */ | | |
for(tmp2 = tmp; tmp2!=NULL;tmp2=tmp2->more) num_sections++; | | |
| | |
if(rndm(0, weight_move-1) > tmp->weight/num_sections) { /* move it. */ | | |
remove_ob(tmp); | | |
tmp->x = nx; | | |
tmp->y = ny; | | |
insert_ob_in_map(tmp,op->map,op,0); | | |
} | | |
#endif | | |
} | | } |
} | | } |
| | |
| | |
free_object(op); | | free_object(op); |
return; | | return; |
} | | } |
if(op->above!=NULL&&op->above->type!=PLAYER) { | | |
SET_FLAG (op, FLAG_NO_APPLY); | | |
remove_ob(op); | | |
insert_ob_in_map(op,op->map,op,0); | | |
CLEAR_FLAG (op, FLAG_NO_APPLY); | | |
} | | |
hit_map(op,0,op->attacktype); | | hit_map(op,0,op->attacktype); |
| | |
if(op->stats.hp>2&&!op->value) { | | if(op->stats.hp>2&&!op->value) { |
op->value=1; | | op->value=1; |
for(i=1;i<9;i++) { | | for(i=1;i<9;i++) { |
int dx,dy; | | int dx,dy; |
if(wall(op->map,dx=op->x+freearr_x[i],dy=op->y+freearr_y[i])) | | |
continue; | | dx=op->x+freearr_x[i]; |
if(blocks_view(op->map, dx, dy)) | | dy=op->y+freearr_y[i]; |
continue; | | /* ok_to_put_more already does things like checks for walls, |
| | * out of map, etc. |
| | */ |
if(ok_to_put_more(op->map,dx,dy,op,op->attacktype)) { | | if(ok_to_put_more(op->map,dx,dy,op,op->attacktype)) { |
tmp=get_object(); | | tmp=get_object(); |
copy_object(op,tmp); /* This is probably overkill on slow computers.. */ | | copy_object(op,tmp); /* This is probably overkill on slow computers.. */ |
| | |
tmp->speed_left= -0.21; | | tmp->speed_left= -0.21; |
tmp->stats.hp--; | | tmp->stats.hp--; |
tmp->value=0; | | tmp->value=0; |
tmp->x=dx,tmp->y=dy; | | tmp->x=dx; |
| | tmp->y=dy; |
insert_ob_in_map(tmp,m,op,0); | | insert_ob_in_map(tmp,m,op,0); |
} | | } |
} | | } |
| | |
int t_dir; /* stores temporary dir calculation */ | | int t_dir; /* stores temporary dir calculation */ |
| | |
/* pick a fork direction. tmp->stats.Con is the left bias | | /* pick a fork direction. tmp->stats.Con is the left bias |
i.e., the chance in 100 of forking LEFT | | * i.e., the chance in 100 of forking LEFT |
Should start out at 50, down to 25 for one already going left | | * Should start out at 50, down to 25 for one already going left |
down to 0 for one going 90 degrees left off original path*/ | | * down to 0 for one going 90 degrees left off original path |
| | */ |
| | |
if(rndm(0, 99) < tmp->stats.Con) /* fork left */ | | if(rndm(0, 99) < tmp->stats.Con) /* fork left */ |
new_dir = -1; | | new_dir = -1; |
| | |
/* check the new dir for a wall and in the map*/ | | /* check the new dir for a wall and in the map*/ |
t_dir = absdir(tmp->direction + new_dir); | | t_dir = absdir(tmp->direction + new_dir); |
if(wall(tmp->map,tmp->x + freearr_x[t_dir],tmp->y + freearr_y[t_dir]) | | |
|| out_of_map(tmp->map,tmp->x + freearr_x[t_dir],tmp->y + freearr_y[t_dir])) | | if(get_map_flags(tmp->map,NULL, tmp->x + freearr_x[t_dir],tmp->y + freearr_y[t_dir], |
| | NULL, NULL) & (P_WALL | P_OUT_OF_MAP)) |
new_dir = 0; | | new_dir = 0; |
| | |
if(new_dir) { /* OK, we made a fork */ | | if(new_dir) { /* OK, we made a fork */ |
object *new_bolt = get_object(); | | object *new_bolt = get_object(); |
| | |
copy_object(tmp,new_bolt); | | copy_object(tmp,new_bolt); |
| | |
/* reduce chances of subsequent forking */ | | /* reduce chances of subsequent forking */ |
| | |
* be reflected from the given mapsquare. Returns 1 if true. | | * be reflected from the given mapsquare. Returns 1 if true. |
* (Note that for living creatures there is a small chance that | | * (Note that for living creatures there is a small chance that |
* reflect_spell fails.) | | * reflect_spell fails.) |
| | * Caller should be sure it passes us valid map coordinates |
| | * eg, updated for tiled maps. |
*/ | | */ |
int reflwall(mapstruct *m,int x,int y, object *sp_op) { | | int reflwall(mapstruct *m,int x,int y, object *sp_op) { |
object *op; | | object *op; |
if(out_of_map(m,x,y)) return 0; | | |
| | if(OUT_OF_REAL_MAP(m,x,y)) return 0; |
for(op=get_map_ob(m,x,y);op!=NULL;op=op->above) | | for(op=get_map_ob(m,x,y);op!=NULL;op=op->above) |
if(QUERY_FLAG(op, FLAG_REFL_SPELL) && (!QUERY_FLAG(op, FLAG_ALIVE) || | | if(QUERY_FLAG(op, FLAG_REFL_SPELL) && (!QUERY_FLAG(op, FLAG_ALIVE) || |
sp_op->type==LIGHTNING || (rndm(0, 99)) < 90-sp_op->level/10)) | | sp_op->type==LIGHTNING || (rndm(0, 99)) < 90-sp_op->level/10)) |
return 1; | | return 1; |
| | |
return 0; | | return 0; |
} | | } |
| | |
void move_bolt(object *op) { | | void move_bolt(object *op) { |
object *tmp; | | object *tmp; |
int w,r; | | int r, mflags; |
| | sint16 x, y; |
| | mapstruct *m; |
| | |
if(--(op->stats.hp)<0) { | | if(--(op->stats.hp)<0) { |
remove_ob(op); | | remove_ob(op); |
free_object(op); | | free_object(op); |
return; | | return; |
} | | } |
hit_map(op,0,op->attacktype); | | hit_map(op,0,op->attacktype); |
| | |
if(!op->value&&--(op->stats.exp)>0) { | | if(!op->value&&--(op->stats.exp)>0) { |
op->value=1; | | op->value=1; |
if(!op->direction) | | if(!op->direction) |
return; | | return; |
| | |
if(blocks_view(op->map,op->x+DIRX(op),op->y+DIRY(op))) | | x = op->x+DIRX(op); |
return; | | y = op->y+DIRY(op); |
w=wall(op->map,op->x+DIRX(op),op->y+DIRY(op)); | | m = op->map; |
r=reflwall(op->map,op->x+DIRX(op),op->y+DIRY(op), op); | | mflags = get_map_flags(op->map, &m, x, y, &x, &y); |
if(w&&!QUERY_FLAG(op, FLAG_REFLECTING)) | | |
return; | | r=reflwall(m, x, y, op); |
if(w||r) { /* We're about to bounce */ | | /* We are about to run into something - we may bounce */ |
| | if((mflags & P_WALL) || r ) { /* We're about to bounce */ |
if(!QUERY_FLAG(op, FLAG_REFLECTING)) | | if(!QUERY_FLAG(op, FLAG_REFLECTING)) |
return; | | return; |
| | |
op->value=0; | | op->value=0; |
| | /* Since walls don't run diagonal, if the bolt is in |
| | * one of 4 main directions, it just reflects back in the |
| | * opposite direction. However, if the bolt is travelling |
| | * on the diagonal, it is trickier - eg, a bolt travelling |
| | * northwest bounces different if it hits a north/south |
| | * wall (bounces to northeast) vs an east/west (bounces |
| | * to the southwest. |
| | */ |
if(op->direction&1) | | if(op->direction&1) |
op->direction=absdir(op->direction+4); | | op->direction=absdir(op->direction+4); |
else { | | else { |
int left= wall(op->map,op->x+freearr_x[absdir(op->direction-1)], | | int left, right; |
op->y+freearr_y[absdir(op->direction-1)]), | | |
right=wall(op->map,op->x+freearr_x[absdir(op->direction+1)], | | left = get_map_flags(op->map, NULL, op->x+freearr_x[absdir(op->direction-1)], |
op->y+freearr_y[absdir(op->direction+1)]); | | op->y+freearr_y[absdir(op->direction-1)], NULL, NULL) & P_WALL; |
| | |
| | right = get_map_flags(op->map,NULL, op->x+freearr_x[absdir(op->direction+1)], |
| | op->y+freearr_y[absdir(op->direction+1)], NULL, NULL) & P_WALL; |
| | |
if(left==right) | | if(left==right) |
op->direction=absdir(op->direction+4); | | op->direction=absdir(op->direction+4); |
else if(left) | | else if(left) |
| | |
tmp = insert_ob_in_map(tmp,op->map,op,0); | | tmp = insert_ob_in_map(tmp,op->map,op,0); |
| | |
/* New forking code. Possibly create forks of this object | | /* New forking code. Possibly create forks of this object |
going off in other directions. */ | | * going off in other directions. |
| | */ |
| | |
if(rndm(0, 99)< tmp->stats.Dex) { /* stats.Dex % of forking */ | | if(rndm(0, 99)< tmp->stats.Dex) { /* stats.Dex % of forking */ |
forklightning(op,tmp); | | forklightning(op,tmp); |
| | |
} else { | | } else { |
tmp->stats.food = 0; | | tmp->stats.food = 0; |
} | | } |
} | | } /* if tmp */ |
} | | } /* copy object and move it along */ |
} | | } /* if move bolt along */ |
} | | } |
| | |
| | |
| | |
| | |
| | |
void move_missile(object *op) { | | void move_missile(object *op) { |
int i; | | int i, mflags; |
object *owner; | | object *owner; |
sint16 new_x, new_y; | | sint16 new_x, new_y; |
| | |
owner = get_owner(op); | | owner = get_owner(op); |
| | /* It'd make things nastier if this wasn't here - spells cast by |
| | * monster that are then killed would continue to survive |
| | */ |
if (owner == NULL) { | | if (owner == NULL) { |
remove_ob(op); | | remove_ob(op); |
free_object(op); | | free_object(op); |
| | |
new_x = op->x + DIRX(op); | | new_x = op->x + DIRX(op); |
new_y = op->y + DIRY(op); | | new_y = op->y + DIRY(op); |
| | |
if (blocked (op->map, new_x, new_y)) { | | mflags = get_map_flags(op->map, NULL, new_x, new_y, NULL, NULL); |
| | |
| | if (mflags & P_BLOCKED) { |
tag_t tag = op->count; | | tag_t tag = op->count; |
hit_map (op, op->direction, AT_MAGIC); | | hit_map (op, op->direction, AT_MAGIC); |
if ( ! was_destroyed (op, tag)) { | | if ( ! was_destroyed (op, tag)) { |
| | |
} | | } |
| | |
remove_ob(op); | | remove_ob(op); |
if ( ! op->direction || wall (op->map, new_x, new_y) | | if ( ! op->direction || (mflags & P_WALL)) { |
|| blocks_view (op->map, new_x, new_y)) | | |
{ | | |
free_object(op); | | free_object(op); |
return; | | return; |
} | | } |
| | |
{ | | { |
tag_t op_tag = op->count, tmp_tag; | | tag_t op_tag = op->count, tmp_tag; |
object *tmp; | | object *tmp; |
int dam; | | int dam, mflags; |
| | |
| | mflags = get_map_flags(op->map, NULL, op->x, op->y, NULL, NULL); |
| | |
if ( ! blocked (op->map, op->x, op->y)) | | if ( ! (mflags & P_BLOCKED)) |
return; | | return; |
| | |
if (op->other_arch) { | | if (op->other_arch) { |
| | |
return; | | return; |
} | | } |
| | |
| | /* If nothing alive on this space, no reason to do anything further */ |
| | if (!(mflags & P_IS_ALIVE)) return; |
| | |
for (tmp = get_map_ob (op->map,op->x,op->y); tmp != NULL; tmp = tmp->above) | | for (tmp = get_map_ob (op->map,op->x,op->y); tmp != NULL; tmp = tmp->above) |
{ | | { |
if (QUERY_FLAG (tmp, FLAG_ALIVE)) { | | if (QUERY_FLAG (tmp, FLAG_ALIVE)) { |
| | |
void move_fired_arch (object *op) | | void move_fired_arch (object *op) |
{ | | { |
tag_t op_tag = op->count; | | tag_t op_tag = op->count; |
int new_x, new_y; | | sint16 new_x, new_y; |
| | int mflags; |
| | mapstruct *m; |
| | |
| | |
/* peterm: added to make comet leave a trail of burnouts | | /* peterm: added to make comet leave a trail of burnouts |
it's an unadulterated hack, but the effect is cool. */ | | it's an unadulterated hack, but the effect is cool. */ |
| | |
| | |
new_x = op->x + DIRX(op); | | new_x = op->x + DIRX(op); |
new_y = op->y + DIRY(op); | | new_y = op->y + DIRY(op); |
if (out_of_map (op->map, new_x, new_y)) { | | m = op->map; |
| | mflags = get_map_flags(m, &m, new_x, new_y, &new_x, &new_y); |
| | |
| | if (mflags & P_OUT_OF_MAP) { |
remove_ob (op); | | remove_ob (op); |
free_object (op); | | free_object (op); |
return; | | return; |
} | | } |
| | |
if ( ! op->direction || wall (op->map, new_x, new_y)) { | | if ( ! op->direction || (mflags & P_WALL)) { |
if (op->other_arch) { | | if (op->other_arch) { |
explode_object (op); | | explode_object (op); |
} else { | | } else { |
| | |
remove_ob (op); | | remove_ob (op); |
op->x = new_x; | | op->x = new_x; |
op->y = new_y; | | op->y = new_y; |
if ((op = insert_ob_in_map (op, op->map, op,0)) == NULL) | | if ((op = insert_ob_in_map (op, m, op,0)) == NULL) |
return; | | return; |
| | |
if (reflwall (op->map, op->x, op->y, op)) { | | if (reflwall (op->map, op->x, op->y, op)) { |
| | |
} | | } |
| | |
| | |
/* peterm: ball lightning mover. */ | | /* peterm: ball lightning mover. |
/* ball lightning automatically seeks out a victim, if | | * ball lightning automatically seeks out a victim, if |
it sees any monsters close enough. */ | | * it sees any monsters close enough. |
| | */ |
void move_ball_lightning(object *op) { | | void move_ball_lightning(object *op) { |
int i,nx,ny,j,dam_save,dir; | | int i,nx,ny,j,dam_save,dir, mflags; |
object *owner; | | object *owner; |
| | mapstruct *m; |
| | |
owner = get_owner(op); | | owner = get_owner(op); |
| | |
| | |
} | | } |
| | |
/* the following logic makes sure that the ball | | /* the following logic makes sure that the ball |
doesn't move into a wall, and makes | | * doesn't move into a wall, and makes |
sure that it will move along a wall to try and | | * sure that it will move along a wall to try and |
get at it's victim. */ | | * get at it's victim. |
| | */ |
| | |
dir = 0; | | dir = 0; |
| | |
if(!(rndm(0, 3))) | | if(!(rndm(0, 3))) |
j = rndm(0, 1); | | j = rndm(0, 1); |
else j=0; /* ? j wasn't being assigned to anything before */ | | else j=0; /* ? j wasn't being assigned to anything before */ |
| | |
for(i = 1; i < 9; i++) { | | for(i = 1; i < 9; i++) { |
/* i bit 0: alters sign of offset | | /* i bit 0: alters sign of offset |
* otther bits (i / 2): absolute value of offset | | * otther bits (i / 2): absolute value of offset |
| | |
| | |
int offset = ((i ^ j) & 1) ? (i / 2) : - (i / 2); | | int offset = ((i ^ j) & 1) ? (i / 2) : - (i / 2); |
int tmpdir = absdir (op->direction + offset); | | int tmpdir = absdir (op->direction + offset); |
| | |
nx = op->x + freearr_x[tmpdir]; | | nx = op->x + freearr_x[tmpdir]; |
ny = op->y + freearr_y[tmpdir]; | | ny = op->y + freearr_y[tmpdir]; |
if ( ! wall (op->map, nx, ny) ) { | | if ( ! (get_map_flags(op->map, NULL, nx, ny, NULL, NULL) & P_WALL)) { |
dir = tmpdir; | | dir = tmpdir; |
break; | | break; |
} | | } |
| | |
| | |
/* loop over current square and neighbors to hit. */ | | /* loop over current square and neighbors to hit. */ |
for(j=0;j<9;j++) { | | for(j=0;j<9;j++) { |
int hx,hy; /* hit these squares */ | | sint16 hx,hy; /* hit these squares */ |
object *new_ob; | | object *new_ob; |
| | |
hx = nx+freearr_x[j]; hy = ny+freearr_y[j]; | | hx = nx+freearr_x[j]; |
| | hy = ny+freearr_y[j]; |
| | |
| | m = op->map; |
| | mflags = get_map_flags(m, &m, hx, hy, &hx, &hy); |
| | |
| | if (mflags & P_OUT_OF_MAP) continue; |
| | |
/* first, don't ever, ever hit the owner. Don't hit out | | /* first, don't ever, ever hit the owner. Don't hit out |
of the map either.*/ | | * of the map either. |
if(! (owner && owner->x==hx && owner->y==hy) && !out_of_map(op->map,hx,hy)) { | | */ |
if(j) op->stats.dam = dam_save/2; | | |
| | |
if(blocked(op->map,hx,hy)) hit_map(op,j,op->attacktype); | | if((mflags & P_IS_ALIVE) && (!owner || owner->x!=hx || owner->y!=hy || owner->map != m)) { |
| | if(j) op->stats.dam = dam_save/2; |
| | hit_map(op,j,op->attacktype); |
| | |
} | | } |
if(out_of_map(op->map,hx,hy) || | | if(!(mflags & P_WALL) && op->other_arch) { /* insert the other arch */ |
wall(op->map,hx,hy)) continue; | | |
if(op->other_arch) { /* insert the other arch */ | | |
new_ob = arch_to_object(op->other_arch); | | new_ob = arch_to_object(op->other_arch); |
new_ob->x = hx; | | new_ob->x = hx; |
new_ob->y = hy; | | new_ob->y = hy; |
insert_ob_in_map(new_ob,op->map,op,0); | | insert_ob_in_map(new_ob,m,op,0); |
} | | } |
} | | } |
| | |
/* restore to the center location and damage*/ | | /* restore to the center location and damage*/ |
op->stats.dam = dam_save; | | op->stats.dam = dam_save; |
i=spell_find_dir(op->map,op->x,op->y,get_owner(op)); | | i=spell_find_dir(op->map,op->x,op->y,get_owner(op)); |
| | |
if(i>=0) { /* we have a preferred direction! */ | | if(i>=0) { /* we have a preferred direction! */ |
/* pick another direction if the preferred dir is blocked. */ | | /* pick another direction if the preferred dir is blocked. */ |
if(wall(op->map,nx + freearr_x[i], ny + freearr_y[i])) { | | if(get_map_flags(op->map,NULL, nx + freearr_x[i], ny + freearr_y[i],NULL,NULL) & P_WALL) { |
i+= rndm(0, 2)-1; /* -1, 0, +1 */ | | i= absdir(i + rndm(0, 2) -1); /* -1, 0, +1 */ |
if(i==0) i=8; | | |
if(i==9) i=1; | | |
} | | } |
op->direction=i; | | op->direction=i; |
} | | } |
| | |
| | |
| | |
int can_see_monsterP(mapstruct *m, int x, int y,int dir) { | | int can_see_monsterP(mapstruct *m, int x, int y,int dir) { |
int dx, dy; /* delta (dx) */ | | sint16 dx, dy; |
| | int mflags; |
| | |
if(dir<0) return 0; /* exit condition: invalid direction */ | | if(dir<0) return 0; /* exit condition: invalid direction */ |
| | |
dx = x + freearr_x[dir]; | | dx = x + freearr_x[dir]; |
dy = y + freearr_y[dir]; | | dy = y + freearr_y[dir]; |
| | |
if (out_of_map(m, dx, dy)) return 0; | | mflags = get_map_flags(m, &m, dx, dy, &dx, &dy); |
| | |
m = get_map_from_coord(m, &dx, &dy); | | if (mflags & (P_OUT_OF_MAP | P_WALL)) return 0; |
| | |
if(wall(m,dx,dy)) return 0; | | |
| | |
/* yes, can see. */ | | /* yes, can see. */ |
if(dir < 9) return 1; | | if(dir < 9) return 1; |
| | |
* spell_find_dir(map, x, y, exclude) will search first the center square | | * spell_find_dir(map, x, y, exclude) will search first the center square |
* then some close squares in the given map at the given coordinates for | | * then some close squares in the given map at the given coordinates for |
* live objects. | | * live objects. |
* It will not consider the object given as exlude (= caster) among possible | | * It will not consider the object given as exclude (= caster) among possible |
* live objects. If the caster is a player, the spell will go after | | * live objects. If the caster is a player, the spell will go after |
* monsters/generators only. If not, the spell will hunt players only. | | * monsters/generators only. If not, the spell will hunt players only. |
* It returns the direction toward the first/closest live object if it finds | | * It returns the direction toward the first/closest live object if it finds |
| | |
| | |
int spell_find_dir(mapstruct *m, int x, int y, object *exclude) { | | int spell_find_dir(mapstruct *m, int x, int y, object *exclude) { |
int i,max=SIZEOFFREE; | | int i,max=SIZEOFFREE; |
int nx,ny; | | sint16 nx,ny; |
int owner_type=0; | | int owner_type=0, mflags; |
object *tmp; | | object *tmp; |
| | mapstruct *mp; |
| | |
if (exclude && exclude->head) | | if (exclude && exclude->head) |
exclude = exclude->head; | | exclude = exclude->head; |
| | |
for(i=rndm(1, 8);i<max;i++) { | | for(i=rndm(1, 8);i<max;i++) { |
nx = x + freearr_x[i]; | | nx = x + freearr_x[i]; |
ny = y + freearr_y[i]; | | ny = y + freearr_y[i]; |
if(!out_of_map(m,nx,ny)) { | | mp = m; |
tmp=get_map_ob(m,nx,ny); | | mflags = get_map_flags(m, &mp, nx, ny, &nx, &ny); |
| | if (mflags & P_OUT_OF_MAP) continue; |
| | |
| | tmp=get_map_ob(mp,nx,ny); |
| | |
while(tmp!=NULL && (((owner_type==PLAYER && | | while(tmp!=NULL && (((owner_type==PLAYER && |
!QUERY_FLAG(tmp,FLAG_MONSTER) && !QUERY_FLAG(tmp,FLAG_GENERATOR)) || | | !QUERY_FLAG(tmp,FLAG_MONSTER) && !QUERY_FLAG(tmp,FLAG_GENERATOR)) || |
(owner_type!=PLAYER && tmp->type!=PLAYER)) || | | (owner_type!=PLAYER && tmp->type!=PLAYER)) || |
(tmp == exclude || (tmp->head && tmp->head == exclude)))) | | (tmp == exclude || (tmp->head && tmp->head == exclude)))) |
tmp=tmp->above; | | tmp=tmp->above; |
if(tmp!=NULL && can_see_monsterP(m,x,y,i) && !blocks_view(m,nx,ny)) | | |
| | if(tmp!=NULL && can_see_monsterP(m,x,y,i) && !(mflags & P_BLOCKSVIEW)) |
return freedir[i]; | | return freedir[i]; |
} | | } |
} | | |
return -1; /* flag for "keep going the way you were" */ | | return -1; /* flag for "keep going the way you were" */ |
} | | } |
| | |
| | |
| | |
| | |
| | |
/* move_swarm_spell: peterm */ | | /* move_swarm_spell: peterm |
/* This is an implementation of the swarm spell. It was written for | | * This is an implementation of the swarm spell. It was written for |
meteor swarm, but it could be used for any swarm. A swarm spell | | * meteor swarm, but it could be used for any swarm. A swarm spell |
is a special type of object that casts swarms of other types | | * is a special type of object that casts swarms of other types |
of spells. Which spell it casts is flexible. It fires the spells | | * of spells. Which spell it casts is flexible. It fires the spells |
from a set of squares surrounding the caster, in a given direction. */ | | * from a set of squares surrounding the caster, in a given direction. |
| | */ |
| | |
void move_swarm_spell(object *op) | | void move_swarm_spell(object *op) |
{ | | { |
| | |
} | | } |
| | |
/* new offset calculation to make swarm element distribution | | /* new offset calculation to make swarm element distribution |
more uniform */ | | * more uniform |
| | */ |
if(op->stats.hp) { | | if(op->stats.hp) { |
if(basedir & 1) { | | if(basedir & 1) { |
adjustdir = cardinal_adjust[rndm(0, 8)]; | | adjustdir = cardinal_adjust[rndm(0, 8)]; |
| | |
target_y = op->y + freearr_y[absdir(basedir + adjustdir)]; | | target_y = op->y + freearr_y[absdir(basedir + adjustdir)]; |
| | |
/* back up one space so we can hit point-blank targets, but this | | /* back up one space so we can hit point-blank targets, but this |
necessitates extra out_of_map check below */ | | * necessitates extra out_of_map check below |
| | */ |
origin_x = target_x - freearr_x[basedir]; | | origin_x = target_x - freearr_x[basedir]; |
origin_y = target_y - freearr_y[basedir]; | | origin_y = target_y - freearr_y[basedir]; |
| | |
/* for level dependence, we need to know what spell is fired. */ | | /* for level dependence, we need to know what spell is fired. */ |
/* that's stored in op->stats.sp by fire_swarm */ | | /* that's stored in op->stats.sp by fire_swarm */ |
if ( ! wall (op->map, target_x, target_y) | | if ( !(get_map_flags(op->map, NULL, target_x, target_y, NULL, NULL) & P_WALL) |
&& ! out_of_map(op->map, origin_x, origin_y)) | | && ! out_of_map(op->map, origin_x, origin_y)) |
fire_arch_from_position (op, op, origin_x, origin_y, basedir, | | fire_arch_from_position (op, op, origin_x, origin_y, basedir, |
op->other_arch, op->stats.sp, op->magic); | | op->other_arch, op->stats.sp, op->magic); |
| | |
| | |
object *get_pointed_target(object *op, int dir) { | | object *get_pointed_target(object *op, int dir) { |
object *target; | | object *target; |
int x,y; | | sint16 x,y; |
| | int dist, mflags; |
| | mapstruct *mp; |
| | |
if (dir==0) return NULL; | | if (dir==0) return NULL; |
for(x=op->x+freearr_x[dir],y=op->y+freearr_y[dir] | | /* limit of 20 is arbitrary - really, we should get this |
;!out_of_map(op->map,x,y)&&!blocks_view(op->map,x,y) | | * from spell parameter or something. But there has to be |
&&!wall(op->map,x,y);x+=freearr_x[dir],y+=freearr_y[dir]) | | * some upper limit due to the nature of tiled maps. |
for(target=get_map_ob(op->map,x,y);target;target=target->above) { | | * Note also that the check for no magic is perhaps bogus |
| | * if this function is also used for cleric spells. |
| | */ |
| | for (dist=1; dist<20; dist++) { |
| | x = op->x + freearr_x[dir] * dist; |
| | y = op->y + freearr_y[dir] * dist; |
| | mp = op->map; |
| | mflags = get_map_flags(op->map, &mp, x, y, &x, &y); |
| | |
| | if (mflags & (P_OUT_OF_MAP | P_WALL | P_NO_MAGIC)) return NULL; |
| | if (mflags & P_IS_ALIVE) { |
| | for(target=get_map_ob(mp,x,y); target; target=target->above) { |
if(QUERY_FLAG(target->head?target->head:target,FLAG_MONSTER)) { | | if(QUERY_FLAG(target->head?target->head:target,FLAG_MONSTER)) { |
if(!blocks_magic(op->map,x,y)) | | |
return target; | | return target; |
else break; | | |
} | | } |
} | | } |
| | } |
return ((object *) NULL); | | } |
| | return NULL; |
} | | } |
| | |
/* cast_smite_arch() - the priest points to a creature and causes | | /* cast_smite_arch() - the priest points to a creature and causes |