version 1.86 | | version 1.87 |
---|
| | |
/* | | /* |
* static char *rcsid_apply_c = | | * static char *rcsid_apply_c = |
* "$Id: apply.c,v 1.86 2003/09/04 06:25:32 temitchell Exp $"; | | * "$Id: apply.c,v 1.87 2003/09/13 05:02:07 mwedel Exp $"; |
*/ | | */ |
/* | | /* |
CrossFire, A Multiplayer game for X-windows | | CrossFire, A Multiplayer game for X-windows |
| | |
identify(tmp); | | identify(tmp); |
} | | } |
| | |
/* only players get this */ | | /* Potion of restoration - only for players */ |
if (op->type==PLAYER&&(tmp->attacktype & AT_DEPLETE)) { /* Potion of restoration */ | | if (op->type==PLAYER&&(tmp->attacktype & AT_DEPLETE)) { |
object *depl; | | object *depl; |
archetype *at; | | archetype *at; |
| | |
| | |
fix_player(op); | | fix_player(op); |
} | | } |
else | | else |
new_draw_info(NDI_UNIQUE,0,op, "You feel a great loss..."); | | new_draw_info(NDI_UNIQUE,0,op, "You potion had no effect."); |
| | |
decrease_ob(tmp); | | decrease_ob(tmp); |
return 1; | | return 1; |
} | | } |
/* only players get this */ | | |
if(op->type==PLAYER&&tmp->attacktype&AT_GODPOWER) { /* improvement potion */ | | /* improvement potion - only for players */ |
| | if(op->type==PLAYER&&tmp->attacktype&AT_GODPOWER) { |
| | |
for(i=1;i<MIN(11,op->level);i++) { | | for(i=1;i<MIN(11,op->level);i++) { |
if (QUERY_FLAG(tmp,FLAG_CURSED) || QUERY_FLAG(tmp,FLAG_DAMNED)) { | | if (QUERY_FLAG(tmp,FLAG_CURSED) || QUERY_FLAG(tmp,FLAG_DAMNED)) { |
| | |
| | |
| | |
/* A potion that casts a spell. Healing, restore spellpoint (power potion) | | /* A potion that casts a spell. Healing, restore spellpoint (power potion) |
* and heroism all fit into this category. | | * and heroism all fit into this category. Given the spell object code, |
| | * there is no limit to the number of spells that potions can be cast, |
| | * but direction is problematic to try and imbue fireball potions for example. |
*/ | | */ |
if (tmp->stats.sp) { | | if (tmp->inv) { |
if(QUERY_FLAG(tmp, FLAG_CURSED) || QUERY_FLAG(tmp, FLAG_DAMNED)) { | | if(QUERY_FLAG(tmp, FLAG_CURSED) || QUERY_FLAG(tmp, FLAG_DAMNED)) { |
| | object *fball; |
| | |
new_draw_info(NDI_UNIQUE,0,op, "Yech! Your lungs are on fire!"); | | new_draw_info(NDI_UNIQUE,0,op, "Yech! Your lungs are on fire!"); |
cast_spell(op,tmp, 0, 3, 1, spellPotion,NULL); | | /* Explodes a fireball centered at player */ |
| | fball = get_archetype(EXPLODING_FIREBALL); |
| | fball->dam_modifier=random_roll(1, op->level, op, PREFER_LOW)/5+1; |
| | fball->stats.maxhp=random_roll(1, op->level, op, PREFER_LOW)/10+2; |
| | fball->x = op->x; |
| | fball->y = op->y; |
| | insert_ob_in_map(fball, op->map, NULL, 0); |
} else | | } else |
cast_spell(op,tmp, op->facing, tmp->stats.sp, 1, spellPotion,NULL); | | cast_spell(op,tmp, op->facing, tmp->inv, NULL); |
| | |
decrease_ob(tmp); | | decrease_ob(tmp); |
/* if youre dead, no point in doing this... */ | | /* if youre dead, no point in doing this... */ |
if(!QUERY_FLAG(op,FLAG_REMOVED)) fix_player(op); | | if(!QUERY_FLAG(op,FLAG_REMOVED)) fix_player(op); |
| | |
| | |
/* Only thing left are the stat potions */ | | /* Only thing left are the stat potions */ |
if(op->type==PLAYER) { /* only for players */ | | if(op->type==PLAYER) { /* only for players */ |
if((QUERY_FLAG(tmp, FLAG_CURSED) || QUERY_FLAG(tmp, FLAG_DAMNED)) | | if((QUERY_FLAG(tmp, FLAG_CURSED) || QUERY_FLAG(tmp, FLAG_DAMNED)) && tmp->value!=0) |
&& tmp->value!=0) | | |
CLEAR_FLAG(tmp, FLAG_APPLIED); | | CLEAR_FLAG(tmp, FLAG_APPLIED); |
else | | else |
SET_FLAG(tmp, FLAG_APPLIED); | | SET_FLAG(tmp, FLAG_APPLIED); |
| | |
static int apply_altar (object *altar, object *sacrifice, object *originator) | | static int apply_altar (object *altar, object *sacrifice, object *originator) |
{ | | { |
/* Only players can make sacrifices on spell casting altars. */ | | /* Only players can make sacrifices on spell casting altars. */ |
if (altar->stats.sp && ( ! originator || originator->type != PLAYER)) | | if (altar->inv && ( ! originator || originator->type != PLAYER)) |
return 0; | | return 0; |
if (operate_altar (altar, &sacrifice)) | | |
{ | | if (operate_altar (altar, &sacrifice)) { |
/* Simple check. Unfortunately, it means you can't cast magic bullet | | /* Simple check. Unfortunately, it means you can't cast magic bullet |
* with an altar. We call it a Potion - altars are stationary - it | | * with an altar. We call it a Potion - altars are stationary - it |
* is up to map designers to use them properly. | | * is up to map designers to use them properly. |
*/ | | */ |
if (altar->stats.sp) | | if (altar->inv && altar->inv->type==SPELL) { |
{ | | |
new_draw_info_format (NDI_BLACK, 0, originator, "The altar casts %s.", | | new_draw_info_format (NDI_BLACK, 0, originator, "The altar casts %s.", |
spells[altar->stats.sp].name); | | altar->inv->name); |
cast_spell (originator, altar, 0, altar->stats.sp, 0, spellPotion, NULL); | | cast_spell (originator, altar, 0, altar->inv, NULL); |
/* If it is connected, push the button. Fixes some problems with | | /* If it is connected, push the button. Fixes some problems with |
* old maps. | | * old maps. |
*/ | | */ |
push_button (altar); | | /* push_button (altar);*/ |
} else { | | } else { |
altar->value = 1; /* works only once */ | | altar->value = 1; /* works only once */ |
push_button (altar); | | push_button (altar); |
| | |
apply_altar (trap, victim, originator); | | apply_altar (trap, victim, originator); |
goto leave; | | goto leave; |
| | |
case MMISSILE: | | |
if (QUERY_FLAG (victim, FLAG_ALIVE)) { | | |
tag_t trap_tag = trap->count; | | |
hit_player (victim, trap->stats.dam, trap, AT_MAGIC); | | |
if ( ! was_destroyed (trap, trap_tag)) { | | |
remove_ob (trap); | | |
free_object (trap); | | |
} | | |
} | | |
goto leave; | | |
| | |
case THROWN_OBJ: | | case THROWN_OBJ: |
if (trap->inv == NULL) | | if (trap->inv == NULL) |
goto leave; | | goto leave; |
| | |
hit_with_arrow (trap, victim); | | hit_with_arrow (trap, victim); |
goto leave; | | goto leave; |
| | |
case CANCELLATION: | | |
case BALL_LIGHTNING: | | |
if (QUERY_FLAG (victim, FLAG_ALIVE)) | | |
hit_player (victim, trap->stats.dam, trap, trap->attacktype); | | |
else if (victim->material || victim->materialname) | | |
save_throw_object (victim, trap->attacktype, trap); | | |
goto leave; | | |
| | |
case CONE: | | |
if(QUERY_FLAG(victim, FLAG_ALIVE)&&trap->speed) { | | |
uint32 attacktype = trap->attacktype & ~AT_COUNTERSPELL; | | |
if (attacktype) | | |
hit_player(victim,trap->stats.dam,trap,attacktype); | | |
} | | |
goto leave; | | |
| | |
case FBULLET: | | case SPELL_EFFECT: |
case BULLET: | | apply_spell_effect(trap, victim); |
if (QUERY_FLAG (victim, FLAG_NO_PASS) | | |
|| QUERY_FLAG (victim, FLAG_ALIVE)) | | |
check_fired_arch (trap); | | |
goto leave; | | goto leave; |
| | |
case TRAPDOOR: | | case TRAPDOOR: |
| | |
static void apply_book (object *op, object *tmp) | | static void apply_book (object *op, object *tmp) |
{ | | { |
int lev_diff; | | int lev_diff; |
| | object *skill_ob; |
event *evt; | | event *evt; |
| | |
if(QUERY_FLAG(op, FLAG_BLIND)&&!QUERY_FLAG(op,FLAG_WIZ)) { | | if(QUERY_FLAG(op, FLAG_BLIND)&&!QUERY_FLAG(op,FLAG_WIZ)) { |
| | |
} | | } |
| | |
/* need a literacy skill to read stuff! */ | | /* need a literacy skill to read stuff! */ |
if ( ! change_skill(op,SK_LITERACY)) { | | skill_ob = find_skill_by_name(op, tmp->skill); |
| | if ( ! skill_ob) { |
new_draw_info(NDI_UNIQUE, 0,op, | | new_draw_info(NDI_UNIQUE, 0,op, |
"You are unable to decipher the strange symbols."); | | "You are unable to decipher the strange symbols."); |
return; | | return; |
} | | } |
lev_diff = tmp->level - (SK_level(op) + 5); | | lev_diff = tmp->level - (skill_ob->level + 5); |
if ( ! QUERY_FLAG (op, FLAG_WIZ) && lev_diff > 0) | | if ( ! QUERY_FLAG (op, FLAG_WIZ) && lev_diff > 0) { |
{ | | |
if (lev_diff < 2) | | if (lev_diff < 2) |
new_draw_info(NDI_UNIQUE, 0,op,"This book is just barely beyond your comprehension."); | | new_draw_info(NDI_UNIQUE, 0,op,"This book is just barely beyond your comprehension."); |
else if (lev_diff < 3) | | else if (lev_diff < 3) |
| | |
| | |
new_draw_info_format (NDI_UNIQUE, 0, op, | | new_draw_info_format (NDI_UNIQUE, 0, op, |
"You open the %s and start reading.", tmp->name); | | "You open the %s and start reading.", tmp->name); |
| | |
/* GROS: Handle for plugin trigger event */ | | /* GROS: Handle for plugin trigger event */ |
if ((evt = find_event(tmp, EVENT_APPLY)) != NULL) | | if ((evt = find_event(tmp, EVENT_APPLY)) != NULL) |
{ | | { |
| | |
| | |
/* gain xp from reading */ | | /* gain xp from reading */ |
if(!QUERY_FLAG(tmp,FLAG_NO_SKILL_IDENT)) { /* only if not read before */ | | if(!QUERY_FLAG(tmp,FLAG_NO_SKILL_IDENT)) { /* only if not read before */ |
int exp_gain=calc_skill_exp(op,tmp); | | int exp_gain=calc_skill_exp(op,tmp, skill_ob); |
if(!QUERY_FLAG(tmp,FLAG_IDENTIFIED)) { | | if(!QUERY_FLAG(tmp,FLAG_IDENTIFIED)) { |
/*exp_gain *= 2; because they just identified it too */ | | /*exp_gain *= 2; because they just identified it too */ |
SET_FLAG(tmp,FLAG_IDENTIFIED); | | SET_FLAG(tmp,FLAG_IDENTIFIED); |
| | |
if(tmp->env) esrv_update_item(UPD_FLAGS|UPD_NAME, op,tmp); | | if(tmp->env) esrv_update_item(UPD_FLAGS|UPD_NAME, op,tmp); |
else op->contr->socket.update_look=1; | | else op->contr->socket.update_look=1; |
} | | } |
add_exp(op,exp_gain); | | change_exp(op,exp_gain, skill_ob->skill, 0); |
SET_FLAG(tmp,FLAG_NO_SKILL_IDENT); /* so no more xp gained from this book */ | | SET_FLAG(tmp,FLAG_NO_SKILL_IDENT); /* so no more xp gained from this book */ |
} | | } |
} | | } |
| | |
| | /* op is the person learning the skill, tmp is the skill scroll object */ |
| | |
| | |
static void apply_skillscroll (object *op, object *tmp) | | static void apply_skillscroll (object *op, object *tmp) |
{ | | { |
switch ((int) learn_skill (op, tmp)) | | switch ((int) learn_skill (op, tmp)) { |
{ | | |
case 0: | | case 0: |
new_draw_info(NDI_UNIQUE, 0,op,"You already possess the knowledge "); | | new_draw_info(NDI_UNIQUE, 0,op,"You already possess the knowledge "); |
new_draw_info_format(NDI_UNIQUE, 0,op,"held within the %s.\n",query_name(tmp)); | | new_draw_info_format(NDI_UNIQUE, 0,op,"held within the %s.\n",query_name(tmp)); |
| | |
| | |
case 1: | | case 1: |
new_draw_info_format(NDI_UNIQUE, 0,op,"You succeed in learning %s", | | new_draw_info_format(NDI_UNIQUE, 0,op,"You succeed in learning %s", |
skills[tmp->stats.sp].name); | | tmp->name); |
new_draw_info_format(NDI_UNIQUE, 0, op, | | new_draw_info_format(NDI_UNIQUE, 0, op, |
"Type 'bind ready_skill %s",skills[tmp->stats.sp].name); | | "Type 'bind ready_skill %s",tmp->name); |
new_draw_info(NDI_UNIQUE, 0,op,"to store the skill in a key."); | | new_draw_info(NDI_UNIQUE, 0,op,"to store the skill in a key."); |
fix_player(op); /* to immediately link new skill to exp object */ | | |
decrease_ob(tmp); | | decrease_ob(tmp); |
return; | | return; |
| | |
| | |
* prayers are special. | | * prayers are special. |
*/ | | */ |
| | |
static object *find_special_prayer_mark (object *op, int spell) | | static object *find_special_prayer_mark (object *op, char *spell) |
{ | | { |
object *tmp; | | object *tmp; |
| | |
for (tmp = op->inv; tmp; tmp = tmp->below) | | for (tmp = op->inv; tmp; tmp = tmp->below) |
if (tmp->type == FORCE && tmp->slaying | | if (tmp->type == FORCE && tmp->slaying |
&& strcmp (tmp->slaying, "special prayer") == 0 | | && !strcmp (tmp->slaying, "special prayer") |
&& tmp->stats.sp == spell) | | && !strcmp(tmp->name, spell)) |
return tmp; | | return tmp; |
return 0; | | return 0; |
} | | } |
| | |
static void insert_special_prayer_mark (object *op, int spell) | | static void insert_special_prayer_mark (object *op, char *spell) |
{ | | { |
object *force = get_archetype ("force"); | | object *force = get_archetype ("force"); |
force->speed = 0; | | force->speed = 0; |
update_ob_speed (force); | | update_ob_speed (force); |
force->slaying = add_string ("special prayer"); | | force->slaying = add_string ("special prayer"); |
force->stats.sp = spell; | | if (force->name) free_string(force->name); |
| | force->name = add_string(spell); |
insert_ob_in_ob (force, op); | | insert_ob_in_ob (force, op); |
} | | } |
| | |
extern void do_learn_spell (object *op, int spell, int special_prayer) | | void do_learn_spell (object *op, object *spell, int special_prayer) |
{ | | { |
object *tmp = find_special_prayer_mark (op, spell); | | object *tmp = find_special_prayer_mark (op, spell->name); |
| | |
if (op->type != PLAYER) { | | if (op->type != PLAYER) { |
LOG (llevError, "BUG: do_forget_spell(): not a player\n"); | | LOG (llevError, "BUG: do_learn_spell(): not a player\n"); |
return; | | return; |
} | | } |
| | |
/* Upgrade special prayers to normal prayers */ | | /* Upgrade special prayers to normal prayers */ |
if (check_spell_known (op, spell)) { | | if (check_spell_known (op, spell->name)) { |
if (special_prayer || ! tmp) { | | if (special_prayer || ! tmp) { |
LOG (llevError, "BUG: do_learn_spell(): spell already known, but " | | LOG (llevError, "BUG: do_learn_spell(): spell already known, but can't upgrade it\n"); |
"can't upgrade it\n"); | | |
return; | | return; |
} | | } |
remove_ob (tmp); | | remove_ob (tmp); |
| | |
| | |
/* Learn new spell/prayer */ | | /* Learn new spell/prayer */ |
if (tmp) { | | if (tmp) { |
LOG (llevError, "BUG: do_learn_spell(): spell unknown, but special " | | LOG (llevError, "BUG: do_learn_spell(): spell unknown, but special prayer mark present\n"); |
"prayer mark present\n"); | | |
remove_ob (tmp); | | remove_ob (tmp); |
free_object (tmp); | | free_object (tmp); |
} | | } |
play_sound_player_only (op->contr, SOUND_LEARN_SPELL, 0, 0); | | play_sound_player_only (op->contr, SOUND_LEARN_SPELL, 0, 0); |
op->contr->known_spells[op->contr->nrofknownspells++] = spell; | | tmp = get_object(); |
if (op->contr->nrofknownspells == 1) | | copy_object(spell, tmp); |
op->contr->chosen_spell = spell; | | insert_ob_in_ob(tmp, op); |
| | |
/* For godgiven spells the player gets a reminder-mark inserted, | | /* For godgiven spells the player gets a reminder-mark inserted, |
that this spell must be removed on changing cults! */ | | * that this spell must be removed on changing cults! |
if (special_prayer) | | */ |
insert_special_prayer_mark (op, spell); | | if (special_prayer) { |
| | insert_special_prayer_mark (op, spell->name); |
| | SET_FLAG(tmp, FLAG_STARTEQUIP); |
| | } |
| | |
new_draw_info_format (NDI_UNIQUE, 0, op, | | new_draw_info_format (NDI_UNIQUE, 0, op, |
"Type 'bind cast %s", spells[spell].name); | | "Type 'bind cast %s", spell->name); |
new_draw_info (NDI_UNIQUE, 0, op, "to store the spell in a key."); | | new_draw_info (NDI_UNIQUE, 0, op, "to store the spell in a key."); |
} | | } |
| | |
extern void do_forget_spell (object *op, int spell) | | void do_forget_spell (object *op, char *spell) |
{ | | { |
object *tmp; | | object *tmp, *spob; |
int i; | | |
| | |
if (op->type != PLAYER) { | | if (op->type != PLAYER) { |
LOG (llevError, "BUG: do_forget_spell(): not a player\n"); | | LOG (llevError, "BUG: do_forget_spell(): not a player\n"); |
return; | | return; |
} | | } |
if ( ! check_spell_known (op, spell)) { | | if ( (spob=check_spell_known (op, spell)) == NULL) { |
LOG (llevError, "BUG: do_forget_spell(): spell not known\n"); | | LOG (llevError, "BUG: do_forget_spell(): spell not known\n"); |
return; | | return; |
} | | } |
| | |
new_draw_info_format (NDI_UNIQUE|NDI_NAVY, 0, op, | | new_draw_info_format (NDI_UNIQUE|NDI_NAVY, 0, op, |
"You lose knowledge of %s.", spells[spell].name); | | "You lose knowledge of %s.", spell); |
| | |
tmp = find_special_prayer_mark (op, spell); | | tmp = find_special_prayer_mark (op, spell); |
if (tmp) { | | if (tmp) { |
remove_ob (tmp); | | remove_ob (tmp); |
free_object (tmp); | | free_object (tmp); |
} | | } |
| | remove_ob(spob); |
for (i = 0; i < op->contr->nrofknownspells; i++) | | free_object(spob); |
{ | | |
if (op->contr->known_spells[i] == spell) { | | |
op->contr->known_spells[i] = | | |
op->contr->known_spells[--op->contr->nrofknownspells]; | | |
return; | | |
} | | |
} | | |
LOG (llevError, "BUG: do_forget_spell(): couldn't find spell\n"); | | |
} | | } |
| | |
static void apply_spellbook (object *op, object *tmp) | | static void apply_spellbook (object *op, object *tmp) |
{ | | { |
| | object *skop, *spell, *spell_skill; |
| | |
if(QUERY_FLAG(op, FLAG_BLIND)&&!QUERY_FLAG(op,FLAG_WIZ)) { | | if(QUERY_FLAG(op, FLAG_BLIND)&&!QUERY_FLAG(op,FLAG_WIZ)) { |
new_draw_info(NDI_UNIQUE, 0,op,"You are unable to read while blind."); | | new_draw_info(NDI_UNIQUE, 0,op,"You are unable to read while blind."); |
return; | | return; |
} | | } |
| | |
/* artifact_spellbooks have 'slaying' field point to a spell name, | | /* artifact_spellbooks have 'slaying' field point to a spell name, |
** instead of having their spell stored in stats.sp. We should update | | * instead of having their spell stored in stats.sp. These are |
** stats->sp to point to that spell */ | | * legacy spellbooks |
| | */ |
| | |
if(tmp->slaying != NULL) { | | if(tmp->slaying != NULL) { |
if((tmp->stats.sp = look_up_spell_name(tmp->slaying)) <0 ){ | | spell=arch_to_object(find_archetype_by_object_name(tmp->slaying)); |
tmp->stats.sp = -1; | | if (!spell) { |
new_draw_info_format(NDI_UNIQUE, 0, op, | | new_draw_info_format(NDI_UNIQUE, 0, op, |
"The book's formula for %s is incomplete", tmp->slaying); | | "The book's formula for %s is incomplete", tmp->slaying); |
return; | | return; |
} | | } |
/* now clear tmp->slaying since we no longer need it */ | | else |
| | insert_ob_in_ob(spell, tmp); |
free_string(tmp->slaying); | | free_string(tmp->slaying); |
tmp->slaying=NULL; | | tmp->slaying=NULL; |
} | | } |
| | |
| | skop = find_skill_by_name(op, tmp->skill); |
| | |
/* need a literacy skill to learn spells. Also, having a literacy level | | /* need a literacy skill to learn spells. Also, having a literacy level |
* lower than the spell will make learning the spell more difficult */ | | * lower than the spell will make learning the spell more difficult */ |
if ( ! change_skill(op,SK_LITERACY)) { | | if ( !skop) { |
new_draw_info(NDI_UNIQUE, 0,op,"You can't read! Your attempt fails."); | | new_draw_info(NDI_UNIQUE, 0,op,"You can't read! Your attempt fails."); |
return; | | return; |
} | | } |
if(tmp->stats.sp < 0 || tmp->stats.sp > NROFREALSPELLS | | |
|| spells[tmp->stats.sp].level>(SK_level(op)+10)) { | | spell = tmp->inv; |
| | if (!spell) { |
| | LOG(llevError,"apply_spellbook: Book %s has no spell in it!\n", tmp->name); |
| | new_draw_info(NDI_UNIQUE, 0,op,"The spellbook symbols make no sense."); |
| | } |
| | if (spell->level > (skop->level+10)) { |
new_draw_info(NDI_UNIQUE, 0,op,"You are unable to decipher the strange symbols."); | | new_draw_info(NDI_UNIQUE, 0,op,"You are unable to decipher the strange symbols."); |
return; | | return; |
} | | } |
| | |
new_draw_info_format(NDI_UNIQUE, 0, op, | | new_draw_info_format(NDI_UNIQUE, 0, op, |
"The spellbook contains the %s level spell %s.", | | "The spellbook contains the %s level spell %s.", |
get_levelnumber(spells[tmp->stats.sp].level), | | get_levelnumber(spell->level), spell->name); |
spells[tmp->stats.sp].name); | | |
| | |
if (!QUERY_FLAG(tmp, FLAG_IDENTIFIED)) { | | if (!QUERY_FLAG(tmp, FLAG_IDENTIFIED)) { |
identify(tmp); | | identify(tmp); |
| | |
op->contr->socket.update_look=1; | | op->contr->socket.update_look=1; |
} | | } |
| | |
if (check_spell_known (op, tmp->stats.sp) && (tmp->stats.Wis || | | /* I removed the check for special_prayer_mark here - it didn't make |
find_special_prayer_mark (op, tmp->stats.sp) == NULL)) | | * a lot of sense - special prayers are not found in spellbooks, and |
{ | | * if the player doesn't know the spell, doesn't make a lot of sense that |
| | * they would have a special prayer mark. |
| | */ |
| | if (check_spell_known (op, spell->name)) { |
new_draw_info(NDI_UNIQUE, 0,op,"You already know that spell.\n"); | | new_draw_info(NDI_UNIQUE, 0,op,"You already know that spell.\n"); |
return; | | return; |
} | | } |
| | |
/* I changed spell learning in 3 ways: | | if (spell->skill) { |
| | spell_skill = find_skill_by_name(op, spell->skill); |
| | if (!spell_skill) { |
| | new_draw_info_format(NDI_UNIQUE, 0, op, |
| | "You lack the skill %s to use this spell", |
| | spell->skill); |
| | return; |
| | } |
| | if (spell_skill->level < spell->level) { |
| | new_draw_info_format(NDI_UNIQUE, 0, op, |
| | "You need to be level %d in %s to learn this spell.", |
| | spell->level, spell->skill); |
| | return; |
| | } |
| | } |
| | |
| | /* Logic as follows |
* | | * |
* 1- MU spells use Int to learn, Cleric spells use Wisdom | | * 1- MU spells use Int to learn, Cleric spells use Wisdom |
* | | * |
* 2- The learner's level (in skills sytem level==literacy level; if no | | * 2- The learner's skill level in literacy adjusts the chance to learn |
* skills level == overall level) impacts the chances of spell learning. | | * a spell. |
* | | * |
* 3 -Automatically fail to learn if you read while confused | | * 3 -Automatically fail to learn if you read while confused |
* | | * |
| | |
*/ | | */ |
if(QUERY_FLAG(op,FLAG_CONFUSED)) { | | if(QUERY_FLAG(op,FLAG_CONFUSED)) { |
new_draw_info(NDI_UNIQUE,0,op,"In your confused state you flub the wording of the text!"); | | new_draw_info(NDI_UNIQUE,0,op,"In your confused state you flub the wording of the text!"); |
/* this needs to be a - number [garbled] */ | | scroll_failure(op, 0 - random_roll(0, spell->level, op, PREFER_LOW), MAX(spell->stats.sp, spell->stats.grace)); |
scroll_failure(op, 0 - random_roll(0, spells[tmp->stats.sp].level, op, PREFER_LOW), spells[tmp->stats.sp].sp); | | } else if(QUERY_FLAG(tmp,FLAG_STARTEQUIP) || |
} else if(QUERY_FLAG(tmp,FLAG_STARTEQUIP) || random_roll(0, 149, op, PREFER_LOW)-(2*SK_level(op)) < | | (random_roll(0, 100, op, PREFER_LOW)-(5*skop->level)) < |
learn_spell[spells[tmp->stats.sp].cleric ? op->stats.Wis : op->stats.Int]) { | | learn_spell[spell->stats.grace ? op->stats.Wis : op->stats.Int]) { |
| | |
new_draw_info(NDI_UNIQUE, 0,op,"You succeed in learning the spell!"); | | new_draw_info(NDI_UNIQUE, 0,op,"You succeed in learning the spell!"); |
do_learn_spell (op, tmp->stats.sp, 0); | | do_learn_spell (op, spell, 0); |
| | |
/* xp gain to literacy for spell learning */ | | /* xp gain to literacy for spell learning */ |
if ( ! QUERY_FLAG (tmp, FLAG_STARTEQUIP)) | | if ( ! QUERY_FLAG (tmp, FLAG_STARTEQUIP)) |
add_exp(op,calc_skill_exp(op,tmp)); | | change_exp(op,calc_skill_exp(op,tmp,skop), skop->skill, 0); |
} else { | | } else { |
play_sound_player_only(op->contr, SOUND_FUMBLE_SPELL,0,0); | | play_sound_player_only(op->contr, SOUND_FUMBLE_SPELL,0,0); |
new_draw_info(NDI_UNIQUE, 0,op,"You fail to learn the spell.\n"); | | new_draw_info(NDI_UNIQUE, 0,op,"You fail to learn the spell.\n"); |
| | |
| | |
void apply_scroll (object *op, object *tmp, int dir) | | void apply_scroll (object *op, object *tmp, int dir) |
{ | | { |
int scroll_spell=tmp->stats.sp, old_spell=0; | | object *skop; |
rangetype old_shoot=range_none; | | |
char buf[MAX_BUF]; | | |
| | |
if(QUERY_FLAG(op, FLAG_BLIND)&&!QUERY_FLAG(op,FLAG_WIZ)) { | | if(QUERY_FLAG(op, FLAG_BLIND)&&!QUERY_FLAG(op,FLAG_WIZ)) { |
new_draw_info(NDI_UNIQUE, 0,op, "You are unable to read while blind."); | | new_draw_info(NDI_UNIQUE, 0,op, "You are unable to read while blind."); |
| | |
if (!QUERY_FLAG(tmp, FLAG_IDENTIFIED)) | | if (!QUERY_FLAG(tmp, FLAG_IDENTIFIED)) |
identify(tmp); | | identify(tmp); |
| | |
if( scroll_spell < 0 || scroll_spell >= NROFREALSPELLS) { | | if (!tmp->inv || tmp->inv->type != SPELL) { |
new_draw_info (NDI_UNIQUE, 0, op, | | new_draw_info (NDI_UNIQUE, 0, op, |
"The scroll just doesn't make sense!"); | | "The scroll just doesn't make sense!"); |
return; | | return; |
| | |
/* players need a literacy skill to read stuff! */ | | /* players need a literacy skill to read stuff! */ |
int exp_gain=0; | | int exp_gain=0; |
| | |
if ( ! change_skill(op,SK_LITERACY)) { | | /* hard code literacy - tmp->skill points to where the exp |
| | * should go for anything killed by the spell. |
| | */ |
| | skop = find_skill_by_name(op, skill_names[SK_LITERACY]); |
| | |
| | if ( ! skop) { |
new_draw_info(NDI_UNIQUE, 0,op, | | new_draw_info(NDI_UNIQUE, 0,op, |
"You are unable to decipher the strange symbols."); | | "You are unable to decipher the strange symbols."); |
return; | | return; |
} | | } |
| | |
/* We give exp for reading the scroll. I reduced this (0.95.3) to | | if((exp_gain = calc_skill_exp(op,tmp, skop))) |
* give half as much since there is no longer any risk. Even this | | change_exp(op,exp_gain, skop->skill, 0); |
* could be excessive. | | |
*/ | | |
if((exp_gain = calc_skill_exp(op,tmp))) | | |
add_exp(op,exp_gain/2); | | |
| | |
| | |
/* Now, call here so the right skill is readied -- literacy | | |
* isnt necesarily connected to the exp obj to which the xp | | |
* will go (for kills made by the magic of the scroll) | | |
*/ | | |
SET_FLAG(tmp,FLAG_APPLIED); | | |
(void) check_skill_to_apply(op,tmp); | | |
CLEAR_FLAG(tmp,FLAG_APPLIED); | | |
old_shoot= op->contr->shoottype; | | |
old_spell = op->contr->chosen_spell; | | |
op->contr->shoottype=range_golem; | | |
op->contr->chosen_spell = scroll_spell; | | |
} | | } |
| | |
new_draw_info_format(NDI_BLACK, 0, op, | | new_draw_info_format(NDI_BLACK, 0, op, |
"The scroll of %s turns to dust.", spells[tmp->stats.sp].name); | | "The scroll of %s turns to dust.", tmp->inv->name); |
| | |
/* Not sure if there is a reason to inform everyone on the map of this, but whatever */ | | |
sprintf(buf, "%s reads a scroll of %s.",op->name,spells[tmp->stats.sp].name); | | |
new_info_map(NDI_ORANGE, op->map, buf); | | |
| | |
cast_spell(op,tmp,dir,scroll_spell,0,spellScroll,NULL); | | cast_spell(op,tmp,dir,tmp->inv, NULL); |
decrease_ob(tmp); | | decrease_ob(tmp); |
| | |
if(op->type==PLAYER && op->contr->golem==NULL) { | | |
op->contr->shoottype=old_shoot; | | |
op->contr->chosen_spell = old_spell; | | |
} | | |
} | | } |
| | |
/* Applies a treasure object - by default, chest. op | | /* Applies a treasure object - by default, chest. op |
| | |
return 1; | | return 1; |
| | |
case POTION: | | case POTION: |
SET_FLAG(tmp,FLAG_APPLIED); | | |
(void) check_skill_to_apply(op,tmp); | | |
CLEAR_FLAG(tmp,FLAG_APPLIED); | | |
(void) apply_potion(op, tmp); | | (void) apply_potion(op, tmp); |
return 1; | | return 1; |
| | |
| | |
new_draw_info_format(NDI_UNIQUE, 0, who, "You unwield %s.",query_name(op)); | | new_draw_info_format(NDI_UNIQUE, 0, who, "You unwield %s.",query_name(op)); |
| | |
(void) change_abil (who,op); | | (void) change_abil (who,op); |
/* 'unready' melee weapons skill if it is current skill */ | | |
(void) check_skill_to_apply(who,op); | | |
if(QUERY_FLAG(who,FLAG_READY_WEAPON)) | | if(QUERY_FLAG(who,FLAG_READY_WEAPON)) |
CLEAR_FLAG(who,FLAG_READY_WEAPON); | | CLEAR_FLAG(who,FLAG_READY_WEAPON); |
/* GROS: update the current_weapon_script field (used with script_attack for weapons) */ | | /* GROS: update the current_weapon_script field (used with script_attack for weapons) */ |
who->current_weapon_script = NULL; | | who->current_weapon_script = NULL; |
who->current_weapon = NULL; | | who->current_weapon = NULL; |
| | clear_skill(who); |
break; | | break; |
| | |
case SKILL: /* allows objects to impart skills */ | | case SKILL: /* allows objects to impart skills */ |
| | case SKILL_TOOL: |
if (op != who->chosen_skill) { | | if (op != who->chosen_skill) { |
LOG (llevError, "BUG: apply_special(): applied skill is not a chosen skill\n"); | | LOG (llevError, "BUG: apply_special(): applied skill is not a chosen skill\n"); |
} | | } |
if (who->type==PLAYER) { | | if (who->type==PLAYER) { |
| | if (who->contr->shoottype == range_skill) |
who->contr->shoottype = range_none; | | who->contr->shoottype = range_none; |
if ( ! op->invisible) { | | if ( ! op->invisible) { |
/* its a tool, need to unlink it */ | | |
unlink_skill (op); | | |
new_draw_info_format (NDI_UNIQUE, 0, who, | | new_draw_info_format (NDI_UNIQUE, 0, who, |
"You stop using the %s.", query_name(op)); | | "You stop using the %s.", query_name(op)); |
| | } else { |
new_draw_info_format (NDI_UNIQUE, 0, who, | | new_draw_info_format (NDI_UNIQUE, 0, who, |
"You can no longer use the skill: %s.", | | "You can no longer use the skill: %s.", |
skills[op->stats.sp].name); | | op->skill); |
} | | } |
} | | } |
(void) change_abil (who, op); | | (void) change_abil (who, op); |
| | |
case WAND: | | case WAND: |
case ROD: | | case ROD: |
case HORN: | | case HORN: |
(void) check_skill_to_apply(who,op); | | clear_skill(who); |
new_draw_info_format(NDI_UNIQUE, 0, who, "You unready %s.",query_name(op)); | | new_draw_info_format(NDI_UNIQUE, 0, who, "You unready %s.",query_name(op)); |
if(who->type==PLAYER) { | | if(who->type==PLAYER) { |
who->contr->shoottype = range_none; | | who->contr->shoottype = range_none; |
| | |
int apply_special (object *who, object *op, int aflags) | | int apply_special (object *who, object *op, int aflags) |
{ | | { |
int basic_flag = aflags & AP_BASIC_FLAGS; | | int basic_flag = aflags & AP_BASIC_FLAGS; |
object *tmp, *tmp2; | | object *tmp, *tmp2, *skop=NULL; |
event *evt; | | event *evt; |
int i; | | int i; |
| | |
| | |
| | |
i = can_apply_object(who, op); | | i = can_apply_object(who, op); |
| | |
/* Somewhere around here the item_power check should be done */ | | |
| | |
/* Can't just apply this object. Lets see what not and what to do */ | | /* Can't just apply this object. Lets see what not and what to do */ |
if (i) { | | if (i) { |
if (i & CAN_APPLY_NEVER) { | | if (i & CAN_APPLY_NEVER) { |
| | |
} | | } |
} | | } |
} | | } |
| | if (op->skill && op->type != SKILL && op->type != SKILL_TOOL) { |
| | skop=find_skill_by_name(who, op->skill); |
| | if (!skop) { |
| | new_draw_info_format(NDI_UNIQUE, 0, who, "You need the %s skill to use this item!", op->skill); |
| | return 1; |
| | } else { |
| | /* While experience will be credited properly, we want to change the |
| | * skill so that the dam and wc get updated |
| | */ |
| | change_skill(who, skop, 0); |
| | } |
| | } |
| | |
| | if (who->type == PLAYER && op->item_power && |
| | (op->item_power + who->item_power) > (settings.item_power_factor * who->level)) { |
| | new_draw_info(NDI_UNIQUE, 0, who, "Equipping that combined with other items would consume your soul!"); |
| | return 1; |
| | } |
| | |
| | |
/* Ok. We are now at the state where we can apply the new object. | | /* Ok. We are now at the state where we can apply the new object. |
* Note that we don't have the checks for can_use_... | | * Note that we don't have the checks for can_use_... |
* below - that is already taken care of by can_apply_object. | | * below - that is already taken care of by can_apply_object. |
| | |
} | | } |
SET_FLAG(op, FLAG_APPLIED); | | SET_FLAG(op, FLAG_APPLIED); |
| | |
/* check for melee weapons skill, alter player status. | | if (skop) change_skill(who, skop, 1); |
* Note that we need to call this *before* change_abil */ | | |
if(!check_skill_to_apply(who,op)) return 1; | | |
if(!QUERY_FLAG(who,FLAG_READY_WEAPON)) | | if(!QUERY_FLAG(who,FLAG_READY_WEAPON)) |
SET_FLAG(who, FLAG_READY_WEAPON); | | SET_FLAG(who, FLAG_READY_WEAPON); |
| | |
| | |
new_draw_info_format(NDI_UNIQUE, 0, who, "You turn on your %s.", | | new_draw_info_format(NDI_UNIQUE, 0, who, "You turn on your %s.", |
op->name); | | op->name); |
tmp2 = arch_to_object(op->other_arch); | | tmp2 = arch_to_object(op->other_arch); |
tmp2->x = op->x; | | |
tmp2->y = op->y; | | |
tmp2->map = op->map; | | |
tmp2->below = op->below; | | |
tmp2->above = op->above; | | |
tmp2->stats.food = op->stats.food; | | tmp2->stats.food = op->stats.food; |
SET_FLAG(tmp2, FLAG_APPLIED); | | SET_FLAG(tmp2, FLAG_APPLIED); |
if (tmp == NULL) { | | if (tmp == NULL) { |
| | |
esrv_send_item(who, tmp2); | | esrv_send_item(who, tmp2); |
return 0; | | return 0; |
break; | | break; |
| | |
/* this part is needed for skill-tools */ | | /* this part is needed for skill-tools */ |
case SKILL: | | case SKILL: |
| | case SKILL_TOOL: |
if (who->chosen_skill) { | | if (who->chosen_skill) { |
LOG (llevError, "BUG: apply_special(): can't apply two skills\n"); | | LOG (llevError, "BUG: apply_special(): can't apply two skills\n"); |
return 1; | | return 1; |
} | | } |
if (who->type == PLAYER) { | | if (who->type == PLAYER) { |
who->contr->shoottype = range_skill; | | who->contr->shoottype = range_skill; |
| | who->contr->ranges[range_skill] = op; |
if ( ! op->invisible) { | | if ( ! op->invisible) { |
/* for tools */ | | |
if (op->exp_obj) | | |
LOG (llevError, "BUG: apply_special(SKILL): found unapplied tool with experience object (%s)\n", op->name); | | |
else | | |
(void) link_player_skill (who, op); | | |
new_draw_info_format (NDI_UNIQUE, 0, who, "You ready %s.", | | new_draw_info_format (NDI_UNIQUE, 0, who, "You ready %s.", |
query_name (op)); | | query_name (op)); |
new_draw_info_format (NDI_UNIQUE, 0, who, | | new_draw_info_format (NDI_UNIQUE, 0, who, |
"You can now use the skill: %s.", | | "You can now use the skill: %s.", |
skills[op->stats.sp].name); | | op->skill); |
} else { | | } else { |
new_draw_info_format (NDI_UNIQUE, 0, who, "Readied skill: %s.", | | new_draw_info_format (NDI_UNIQUE, 0, who, "Readied skill: %s.", |
skills[op->stats.sp].name); | | op->skill? op->skill:op->name); |
} | | } |
} | | } |
SET_FLAG (op, FLAG_APPLIED); | | SET_FLAG (op, FLAG_APPLIED); |
| | |
case HORN: | | case HORN: |
/* check for skill, alter player status */ | | /* check for skill, alter player status */ |
SET_FLAG(op, FLAG_APPLIED); | | SET_FLAG(op, FLAG_APPLIED); |
if(!check_skill_to_apply(who,op)) return 1; | | if (skop) change_skill(who, skop, 0); |
new_draw_info_format (NDI_UNIQUE, 0, who, "You ready %s.", query_name(op)); | | new_draw_info_format (NDI_UNIQUE, 0, who, "You ready %s.", query_name(op)); |
| | |
if(who->type==PLAYER) { | | if(who->type==PLAYER) { |
| | |
op->stats.exp?op->stats.exp:MAX(op->map->difficulty, 5)))==NULL&&--i); | | op->stats.exp?op->stats.exp:MAX(op->map->difficulty, 5)))==NULL&&--i); |
if(tmp==NULL) | | if(tmp==NULL) |
return 0; | | return 0; |
if(QUERY_FLAG(tmp, FLAG_CURSED) || QUERY_FLAG(tmp, FLAG_DAMNED)) | | if(QUERY_FLAG(tmp, FLAG_CURSED) || QUERY_FLAG(tmp, FLAG_DAMNED)) { |
{ | | |
free_object(tmp); | | free_object(tmp); |
tmp = NULL; | | tmp = NULL; |
} | | } |
} while(!tmp); | | } while(!tmp); |
| | tmp->x=op->x; |
tmp->x=op->x,tmp->y=op->y; | | tmp->y=op->y; |
SET_FLAG(tmp,FLAG_UNPAID); | | SET_FLAG(tmp,FLAG_UNPAID); |
insert_ob_in_map(tmp,op->map,NULL,0); | | insert_ob_in_map(tmp,op->map,NULL,0); |
CLEAR_FLAG(op,FLAG_AUTO_APPLY); | | CLEAR_FLAG(op,FLAG_AUTO_APPLY); |
| | |
free_object(op); | | free_object(op); |
break; | | break; |
} | | } |
| | |
return tmp ? 1 : 0; | | return tmp ? 1 : 0; |
} | | } |
| | |
| | |
| | |
if (tmp->inv) { | | if (tmp->inv) { |
object *invtmp, *invnext; | | object *invtmp, *invnext; |
| | |
for (invtmp=tmp->inv; invtmp != NULL; invtmp = invnext) { | | for (invtmp=tmp->inv; invtmp != NULL; invtmp = invnext) { |
invnext = invtmp->below; | | invnext = invtmp->below; |
if(QUERY_FLAG(invtmp,FLAG_AUTO_APPLY)) | | if(QUERY_FLAG(invtmp,FLAG_AUTO_APPLY)) |
| | |
tmp->speed = 0; | | tmp->speed = 0; |
update_ob_speed(tmp); | | update_ob_speed(tmp); |
} | | } |
else if(tmp && tmp->arch && tmp->type!=PLAYER && tmp->type!=TREASURE && HAS_RANDOM_ITEMS(tmp)) | | else if(tmp && tmp->arch && tmp->type!=PLAYER && tmp->type!=TREASURE && |
| | tmp->type != SPELL && HAS_RANDOM_ITEMS(tmp)) |
create_treasure(tmp->randomitems, tmp, GT_APPLY, | | create_treasure(tmp->randomitems, tmp, GT_APPLY, |
m->difficulty,0); | | m->difficulty,0); |
} | | } |
/*end of cycle through map square*/ | | |
for(x=0;x<MAP_WIDTH(m);x++) | | for(x=0;x<MAP_WIDTH(m);x++) |
for(y=0;y<MAP_HEIGHT(m);y++) | | for(y=0;y<MAP_HEIGHT(m);y++) |
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) |
| | |
} | | } |
| | |
/* eat_special_food() - some food may (temporarily) alter | | /* eat_special_food() - some food may (temporarily) alter |
* player status. We do it w/ this routine and cast_change_attr(). | | * player status. This used to call cast_change_attr(), but |
* Note the dircection is set to "99" so that cast_change_attr() | | * that doesn't work with the new spell code. Since we know what |
* will only modify the user's status. We shouldnt be able to | | * the food changes, just grab a force and use that instead. |
* effect others by eating food! | | |
* -b.t. | | |
*/ | | */ |
| | |
void eat_special_food(object *who, object *food) { | | void eat_special_food(object *who, object *food) { |
/* Corresponding spell to cast to get protection to | | object *force; |
* the attactkype. This matches the order of ATNR values | | int i, did_one=0, k; |
* in attack.h | | |
*/ | | |
static int sp_type[NROFATTACKS] = { SP_ARMOUR, SP_PROT_MAGIC, SP_PROT_FIRE, | | |
SP_PROT_ELEC, SP_PROT_COLD, SP_PROT_CONFUSE, -1 /*acid */, | | |
SP_PROT_DRAIN, -1 /*weaponmagic*/, -1 /*ghosthit*/, SP_PROT_POISON, | | |
SP_PROT_SLOW, SP_PROT_PARALYZE, -1 /* turn undead */, | | |
-1 /* fear */, SP_PROT_CANCEL, SP_PROT_DEPLETE, -1 /* death*/, | | |
-1 /* chaos */, -1 /*counterspell */, -1 /* godpower */, | | |
-1 /*holyword */, -1 /*blind*/, -1 /*internal */ }; | | |
| | |
/* matrix for stats we can increase by eating */ | | force = get_archetype(FORCE_NAME); |
int i; | | |
/* Declare these static so they only get initialzed once. IT doesn't appear | | |
* that we are modifying these, so this works out ok. | | |
*/ | | |
static int stat[] = { STR, DEX, CON, CHA }, | | |
mod_stat[] = {SP_STRENGTH, SP_DEXTERITY, SP_CONSTITUTION, SP_CHARISMA }; | | |
| | |
/* check if food modifies stats of the eater */ | | for (i=0; i < NUM_STATS; i++) { |
for(i=0; i<(sizeof(stat)/sizeof(int)); i++) | | k = get_attr_value(&food->stats, i); |
if(get_attr_value(&food->stats, stat[i])) | | if (k) { |
cast_change_attr(who,who,99,mod_stat[i]); | | set_attr_value(&force->stats, i, k); |
| | did_one = 1; |
| | } |
| | } |
| | |
/* check if we can protect the eater */ | | /* check if we can protect the eater */ |
for (i=0; i<NROFATTACKS; i++) { | | for (i=0; i<NROFATTACKS; i++) { |
if (food->resist[i]>0 && sp_type[i]!=-1) | | if (food->resist[i]>0) { |
cast_change_attr(who,who,99,sp_type[i]); | | force->resist[i] = food->resist[i] / 2; |
| | did_one = 1; |
| | } |
| | } |
| | if (did_one) { |
| | force->speed = 0.1; |
| | update_ob_speed(force); |
| | /* bigger morsel of food = longer effect time */ |
| | force->stats.food = food->stats.food / 5; |
| | SET_FLAG(force, FLAG_IS_USED_UP); |
| | SET_FLAG(force, FLAG_APPLIED); |
| | change_abil(who, force); |
| | insert_ob_in_ob(force, who); |
| | } else { |
| | free_object(force); |
} | | } |
| | |
/* check for hp, sp change */ | | /* check for hp, sp change */ |
| | |
/* place limit on max sp from food? */ | | /* place limit on max sp from food? */ |
} | | } |
} | | } |
| | fix_player(who); |
} | | } |
| | |
| | |
| | |
| | |
if(failure<= -1&&failure > -15) {/* wonder */ | | if(failure<= -1&&failure > -15) {/* wonder */ |
new_draw_info(NDI_UNIQUE, 0,op,"Your spell warps!."); | | new_draw_info(NDI_UNIQUE, 0,op,"Your spell warps!."); |
cast_cone(op,op,0,10,SP_WOW,spellarch[SP_WOW],0); | | object *tmp; |
| | tmp=get_archetype(SPELL_WONDER); |
| | cast_wonder(op, op, 0, tmp); |
| | free_object(tmp); |
} else if (failure <= -15&&failure > -35) {/* drain mana */ | | } else if (failure <= -15&&failure > -35) {/* drain mana */ |
new_draw_info(NDI_UNIQUE, 0,op,"Your mana is drained!."); | | new_draw_info(NDI_UNIQUE, 0,op,"Your mana is drained!."); |
op->stats.sp -= random_roll(0, power-1, op, PREFER_LOW); | | op->stats.sp -= random_roll(0, power-1, op, PREFER_LOW); |
| | |
new_draw_info(NDI_UNIQUE, 0,op,"The magic recoils on you!"); | | new_draw_info(NDI_UNIQUE, 0,op,"The magic recoils on you!"); |
blind_player(op,op,power); | | blind_player(op,op,power); |
} else if (failure <= -80) {/* blast the immediate area */ | | } else if (failure <= -80) {/* blast the immediate area */ |
| | object *tmp; |
| | tmp=get_archetype(LOOSE_MANA); |
| | cast_magic_storm(op,tmp, power); |
new_draw_info(NDI_UNIQUE, 0,op,"You unlease uncontrolled mana!"); | | new_draw_info(NDI_UNIQUE, 0,op,"You unlease uncontrolled mana!"); |
cast_mana_storm(op,power); | | free_object(tmp); |
} | | } |
} | | } |
} | | } |