version 1.131 | | version 1.132 |
---|
| | |
/* | | /* |
* static char *rcsid_player_c = | | * static char *rcsid_player_c = |
* "$Id: player.c,v 1.131 2003/09/04 06:25:32 temitchell Exp $"; | | * "$Id: player.c,v 1.132 2003/09/13 05:02:12 mwedel Exp $"; |
*/ | | */ |
| | |
/* | | /* |
| | |
strncpy(p->title,op->arch->clone.name,MAX_NAME); | | strncpy(p->title,op->arch->clone.name,MAX_NAME); |
op->race = add_string (op->arch->clone.race); | | op->race = add_string (op->arch->clone.race); |
| | |
/* Would be better of '0' was not a defined spell */ | | |
for(i=0;i<NROFREALSPELLS;i++) | | |
p->known_spells[i]= -1; | | |
| | |
p->chosen_spell = -1; | | |
CLEAR_FLAG(op,FLAG_READY_SKILL); | | CLEAR_FLAG(op,FLAG_READY_SKILL); |
| | |
/* we need to clear these to -1 and not zero - otherwise, | | /* we need to clear these to -1 and not zero - otherwise, |
| | |
* send new values to the client, as things like exp start | | * send new values to the client, as things like exp start |
* at zero. | | * at zero. |
*/ | | */ |
for (i=0; i < MAX_EXP_CAT; i++) { | | for (i=0; i < NUM_SKILLS; i++) { |
p->last_skill_exp[i] = -1; | | p->last_skill_exp[i] = -1; |
p->last_skill_level[i] = -1; | | p->last_skill_ob[i] = NULL; |
} | | } |
for (i=0; i < NROFATTACKS; i++) { | | for (i=0; i < NROFATTACKS; i++) { |
p->last_resist[i] = -1; | | p->last_resist[i] = -1; |
} | | } |
p->last_skill_index = -1; | | |
p->last_stats.exp = -1; | | p->last_stats.exp = -1; |
| | |
p->socket.update_look=0; | | p->socket.update_look=0; |
| | |
| | |
void give_initial_items(object *pl,treasurelist *items) { | | void give_initial_items(object *pl,treasurelist *items) { |
object *op,*next=NULL; | | object *op,*next=NULL; |
/* Lets at least use the SP_ values here and not just numbers, like 0, 1, ... */ | | |
| | |
int start_spells[] = {SP_BULLET, SP_S_FIREBALL, SP_BURNING_HANDS, | | |
SP_S_LIGHTNING, SP_M_MISSILE ,SP_ICESTORM, SP_S_SNOWSTORM}; | | |
int nrof_start_spells = sizeof start_spells / sizeof start_spells[0]; | | |
| | |
int start_prayers[] = {SP_TURN_UNDEAD, SP_HOLY_WORD, SP_MINOR_HEAL, | | |
SP_CAUSE_LIGHT}; | | |
int nrof_start_prayers = sizeof start_prayers / sizeof start_prayers[0]; | | |
int idx; | | |
| | |
| | |
if(pl->randomitems!=NULL) | | if(pl->randomitems!=NULL) |
create_treasure(items,pl,GT_STARTEQUIP | GT_ONLY_GOOD,1,0); | | create_treasure(items,pl,GT_STARTEQUIP | GT_ONLY_GOOD,1,0); |
| | |
next = op->below; | | next = op->below; |
| | |
/* Forces get applied per default, unless they have the | | /* Forces get applied per default, unless they have the |
flag "neutral" set. Sorry but I can't think of a better way */ | | * flag "neutral" set. Sorry but I can't think of a better way |
| | */ |
if(op->type==FORCE && !QUERY_FLAG(op, FLAG_NEUTRAL)) | | if(op->type==FORCE && !QUERY_FLAG(op, FLAG_NEUTRAL)) |
{ SET_FLAG(op,FLAG_APPLIED);}; | | SET_FLAG(op,FLAG_APPLIED); |
| | |
/* we never give weapons/armour if these cannot be used | | /* we never give weapons/armour if these cannot be used |
by this player due to race restrictions */ | | * by this player due to race restrictions |
| | */ |
if (pl->type == PLAYER) { | | if (pl->type == PLAYER) { |
if ((!QUERY_FLAG(pl, FLAG_USE_ARMOUR) && | | if ((!QUERY_FLAG(pl, FLAG_USE_ARMOUR) && |
(op->type == ARMOUR || op->type == BOOTS || | | (op->type == ARMOUR || op->type == BOOTS || |
| | |
} | | } |
} | | } |
| | |
if(op->type==SPELLBOOK) { /* fix spells for first level spells */ | | /* This really needs to be better - we should really give |
if (strcmp (op->arch->name, "cleric_book") == 0) { | | * a substitute spellbook. The problem is that we don't really |
if (nrof_start_prayers <= 0) { | | * have a good idea what to replace it with (need something like |
remove_ob (op); | | * a first level treasurelist for each skill.) |
free_object (op); | | * remove duplicate skills also |
continue; | | */ |
} | | if(op->type==SPELLBOOK || op->type == SKILL) { |
idx = RANDOM() % nrof_start_prayers; | | object *tmp; |
op->stats.sp = start_prayers[idx]; | | |
/* This makes sure the character does not get duplicate spells */ | | for (tmp=op->below; tmp; tmp=tmp->below) |
start_prayers[idx] = start_prayers[nrof_start_prayers - 1]; | | if (tmp->type == op->type && tmp->name == op->name) break; |
nrof_start_prayers--; | | |
} else { | | if (tmp) { |
if (nrof_start_spells <= 0) { | | |
remove_ob (op); | | remove_ob (op); |
free_object (op); | | free_object (op); |
| | LOG(llevError,"give_initial_items: Removing duplicate object %s\n", |
| | tmp->name); |
continue; | | continue; |
} | | } |
idx = RANDOM() % nrof_start_spells; | | if (op->nrof > 1) op->nrof = 1; |
op->stats.sp = start_spells[idx]; | | |
start_spells[idx] = start_spells[nrof_start_spells - 1]; | | |
nrof_start_spells--; | | |
} | | } |
| | |
| | if (op->type == SPELLBOOK && op->inv) { |
| | CLEAR_FLAG(op->inv, FLAG_STARTEQUIP); |
} | | } |
| | |
/* Give starting characters identified, uncursed, and undamned | | /* Give starting characters identified, uncursed, and undamned |
* items. Just don't identify gold or silver, or it won't be | | * items. Just don't identify gold or silver, or it won't be |
* merged properly. | | * merged properly. |
| | |
CLEAR_FLAG(op, FLAG_CURSED); | | CLEAR_FLAG(op, FLAG_CURSED); |
CLEAR_FLAG(op, FLAG_DAMNED); | | CLEAR_FLAG(op, FLAG_DAMNED); |
} | | } |
if(op->type==ABILITY) { | | if(op->type==SPELL) { |
pl->contr->known_spells[pl->contr->nrofknownspells++]=op->stats.sp; | | |
remove_ob(op); | | remove_ob(op); |
free_object(op); | | free_object(op); |
continue; | | continue; |
} | | } |
| | if(op->type==SKILL) { |
| | SET_FLAG(op, FLAG_CAN_USE_SKILL); |
| | op->stats.exp = 0; |
| | op->level = 1; |
| | } |
} /* for loop of objects in player inv */ | | } /* for loop of objects in player inv */ |
| | |
| | /* Need to set up the skill pointers */ |
| | link_player_skills(pl); |
} | | } |
| | |
void get_name(object *op) { | | void get_name(object *op) { |
| | |
#endif | | #endif |
start_info(op); | | start_info(op); |
CLEAR_FLAG(op, FLAG_WIZ); | | CLEAR_FLAG(op, FLAG_WIZ); |
(void) init_player_exp(op); | | |
give_initial_items(op,op->randomitems); | | give_initial_items(op,op->randomitems); |
(void) link_player_skills(op); | | link_player_skills(op); |
esrv_send_inventory(op, op); | | esrv_send_inventory(op, op); |
return 0; | | return 0; |
} | | } |
| | |
{ | | { |
object *tmp = NULL; | | object *tmp = NULL; |
mapstruct *m; | | mapstruct *m; |
int i, mflags, found, number, dex; | | int i, mflags, found, number; |
sint16 x, y; | | sint16 x, y; |
| | |
if (op->map == NULL) | | if (op->map == NULL) |
return find_arrow(op, type); | | return find_arrow(op, type); |
| | |
/* do a dex check */ | | /* do a dex check */ |
dex = get_skill_stat1(op) ? get_skill_stat1(op) : 10; | | |
number = (die_roll(2, 40, op, PREFER_LOW)-2)/2; | | number = (die_roll(2, 40, op, PREFER_LOW)-2)/2; |
if (number > (dex + SK_level(op))) | | if (number > (op->stats.Dex + (op->chosen_skill?op->chosen_skill->level:op->level))) |
return find_arrow(op, type); | | return find_arrow(op, type); |
| | |
m = op->map; | | m = op->map; |
| | |
return 0; | | return 0; |
} | | } |
} | | } |
if( !bow->race ) { | | if( !bow->race || !bow->skill) { |
new_draw_info_format(NDI_UNIQUE, 0, op, "Your %s is broken.", bow->name); | | new_draw_info_format(NDI_UNIQUE, 0, op, "Your %s is broken.", bow->name); |
return 0; | | return 0; |
} | | } |
| | |
return 0; | | return 0; |
} | | } |
set_owner(arrow, op); | | set_owner(arrow, op); |
| | if (arrow->skill) free_string(arrow->skill); |
| | arrow->skill = add_refcount(bow->skill); |
| | |
arrow->direction=dir; | | arrow->direction=dir; |
arrow->x = sx; | | arrow->x = sx; |
| | |
| | |
| | |
if (op->type == PLAYER) { | | if (op->type == PLAYER) { |
arrow->stats.wc = 20 - bow->magic - arrow->magic - SK_level(op) - | | arrow->stats.wc = 20 - bow->magic - arrow->magic - |
| | (op->chosen_skill?op->chosen_skill->level:op->level) - |
dex_bonus[op->stats.Dex] - thaco_bonus[op->stats.Str] - | | dex_bonus[op->stats.Dex] - thaco_bonus[op->stats.Str] - |
arrow->stats.wc - bow->stats.wc + wc_mod; | | arrow->stats.wc - bow->stats.wc + wc_mod; |
| | |
arrow->level = SK_level (op); | | arrow->level = op->chosen_skill?op->chosen_skill->level:op->level; |
} else { | | } else { |
arrow->stats.wc= op->stats.wc - bow->magic - arrow->magic - | | arrow->stats.wc= op->stats.wc - bow->magic - arrow->magic - |
arrow->stats.wc + wc_mod; | | arrow->stats.wc + wc_mod; |
| | |
} | | } |
| | |
item = op->contr->ranges[range_misc]; | | item = op->contr->ranges[range_misc]; |
| | if (!item->inv) { |
| | LOG(llevError,"Object %s lacks a spell\n", item->name); |
| | return; |
| | } |
if (item->type == WAND) { | | if (item->type == WAND) { |
if(item->stats.food<=0) { | | if(item->stats.food<=0) { |
play_sound_player_only(op->contr, SOUND_WAND_POOF,0,0); | | play_sound_player_only(op->contr, SOUND_WAND_POOF,0,0); |
| | |
return; | | return; |
} | | } |
} else if (item->type == ROD || item->type==HORN) { | | } else if (item->type == ROD || item->type==HORN) { |
if(item->stats.hp<spells[item->stats.sp].sp) { | | if(item->stats.hp<MAX(item->inv->stats.sp, item->inv->stats.grace)) { |
play_sound_player_only(op->contr, SOUND_WAND_POOF,0,0); | | play_sound_player_only(op->contr, SOUND_WAND_POOF,0,0); |
if (item->type== ROD) | | if (item->type== ROD) |
new_draw_info_format(NDI_UNIQUE, 0,op, | | new_draw_info_format(NDI_UNIQUE, 0,op, |
| | |
} | | } |
} | | } |
| | |
if(cast_spell(op,item,dir,item->stats.sp,0,spellMisc,NULL)) { | | if(cast_spell(op,item,dir,item->inv,NULL)) { |
SET_FLAG(op, FLAG_BEEN_APPLIED); /* You now know something about it */ | | SET_FLAG(op, FLAG_BEEN_APPLIED); /* You now know something about it */ |
if (item->type == WAND) { | | if (item->type == WAND) { |
if (!(--item->stats.food)) { | | if (!(--item->stats.food)) { |
| | |
} | | } |
} | | } |
| | |
| | /* Received a fire command for the player - go and do it. |
| | */ |
void fire(object *op,int dir) { | | void fire(object *op,int dir) { |
int spellcost=0; | | int spellcost=0; |
| | |
/* check for loss of invisiblity/hide */ | | /* check for loss of invisiblity/hide */ |
if (action_makes_visible(op)) make_visible(op); | | if (action_makes_visible(op)) make_visible(op); |
| | |
/* a check for players, make sure things are groovy. This routine | | |
* will change the skill of the player as appropriate in order to | | |
* fire whatever is requested. In the case of spells (range_magic) | | |
* it handles whether cleric or mage spell is requested to be cast. | | |
* -b.t. | | |
*/ | | |
if(op->type==PLAYER) | | |
if(!check_skill_to_fire(op)) return; | | |
| | |
switch(op->contr->shoottype) { | | switch(op->contr->shoottype) { |
case range_none: | | case range_none: |
return; | | return; |
| | |
return; | | return; |
| | |
case range_magic: /* Casting spells */ | | case range_magic: /* Casting spells */ |
op->contr->shoottype= range_magic; | | spellcost=cast_spell(op,op,dir,op->contr->ranges[range_magic],NULL); |
spellcost=cast_spell(op,op,dir,op->contr->chosen_spell,0,spellNormal,NULL); | | |
| | |
if(spells[op->contr->chosen_spell].cleric) | | |
op->stats.grace-=spellcost; | | |
else | | |
op->stats.sp-=spellcost; | | |
return; | | return; |
| | |
case range_misc: | | case range_misc: |
| | |
return; | | return; |
| | |
case range_golem: /* Control summoned monsters from scrolls */ | | case range_golem: /* Control summoned monsters from scrolls */ |
if(op->contr->golem==NULL) { | | if(op->contr->ranges[range_golem]==NULL || |
| | op->contr->golem_count != op->contr->ranges[range_golem]->count) { |
| | op->contr->ranges[range_golem] = NULL; |
op->contr->shoottype=range_none; | | op->contr->shoottype=range_none; |
op->contr->chosen_spell= -1; | | op->contr->golem_count = 0; |
} | | } |
else | | else |
control_golem(op->contr->golem, dir); | | control_golem(op->contr->ranges[range_golem], dir); |
return; | | return; |
| | |
case range_skill: | | case range_skill: |
| | |
new_draw_info(NDI_UNIQUE, 0,op,"You have no applicable skill to use."); | | new_draw_info(NDI_UNIQUE, 0,op,"You have no applicable skill to use."); |
return; | | return; |
} | | } |
(void) do_skill(op,op,dir,NULL); | | (void) do_skill(op,op,op->chosen_skill,dir,NULL); |
return; | | return; |
default: | | default: |
new_draw_info(NDI_UNIQUE, 0,op,"Illegal shoot type."); | | new_draw_info(NDI_UNIQUE, 0,op,"Illegal shoot type."); |
| | |
| | |
op->contr->has_hit = 1; /* The last action was to hit, so use weapon_sp */ | | op->contr->has_hit = 1; /* The last action was to hit, so use weapon_sp */ |
| | |
skill_attack(mon, op, 0, NULL); | | skill_attack(mon, op, 0, NULL, NULL); |
/* If attacking another player, that player gets automatic | | /* If attacking another player, that player gets automatic |
* hitback, and doesn't loose luck either. | | * hitback, and doesn't loose luck either. |
*/ | | */ |
if (mon->type == PLAYER && mon->stats.hp >= 0 && !mon->contr->has_hit) { | | if (mon->type == PLAYER && mon->stats.hp >= 0 && !mon->contr->has_hit) { |
short luck = mon->stats.luck; | | short luck = mon->stats.luck; |
mon->contr->has_hit = 1; | | mon->contr->has_hit = 1; |
skill_attack(op, mon, 0, NULL); | | skill_attack(op, mon, 0, NULL, NULL); |
mon->stats.luck = luck; | | mon->stats.luck = luck; |
} | | } |
if(action_makes_visible(op)) make_visible(op); | | if(action_makes_visible(op)) make_visible(op); |
| | |
* destroys the golem looks correct, and it doesn't always happen, so | | * destroys the golem looks correct, and it doesn't always happen, so |
* put this in a a workaround to clean up the golem pointer. | | * put this in a a workaround to clean up the golem pointer. |
*/ | | */ |
if (op->contr->golem && | | if (op->contr->ranges[range_golem] && |
((op->contr->golem_count != op->contr->golem->count) || | | ((op->contr->golem_count != op->contr->ranges[range_golem]->count) || |
QUERY_FLAG(op->contr->golem, FLAG_REMOVED))) { | | QUERY_FLAG(op->contr->ranges[range_golem], FLAG_REMOVED))) { |
op->contr->golem = NULL; | | op->contr->ranges[range_golem] = NULL; |
op->contr->golem_count = 0; | | op->contr->golem_count = 0; |
} | | } |
| | |
| | |
} | | } |
| | |
/* Regenerate Spell Points */ | | /* Regenerate Spell Points */ |
if(op->contr->golem==NULL&&--op->last_sp<0) { | | if(op->contr->ranges[range_golem]==NULL && --op->last_sp<0) { |
gen_sp = gen_sp * 10 / (op->contr->gen_sp_armour < 10? 10 : op->contr->gen_sp_armour); | | gen_sp = gen_sp * 10 / (op->contr->gen_sp_armour < 10? 10 : op->contr->gen_sp_armour); |
if(op->stats.sp<op->stats.maxsp) { | | if(op->stats.sp<op->stats.maxsp) { |
op->stats.sp++; | | op->stats.sp++; |
| | |
char buf[MAX_BUF]; | | char buf[MAX_BUF]; |
int x,y,i; | | int x,y,i; |
mapstruct *map; /* this is for resurrection */ | | mapstruct *map; /* this is for resurrection */ |
object *tmp; | | |
int z; | | int z; |
int num_stats_lose; | | int num_stats_lose; |
int lost_a_stat; | | int lost_a_stat; |
| | |
int killed_script_rtn; /* GROS: For script return value */ | | int killed_script_rtn; /* GROS: For script return value */ |
CFParm CFP; | | CFParm CFP; |
int evtid; | | int evtid; |
| | archetype *at; |
| | object *tmp; |
event *evt; | | event *evt; |
| | |
if(save_life(op)) | | if(save_life(op)) |
return; | | return; |
| | |
| | |
/* If player dies on BATTLEGROUND, no stat/exp loss! For Combat-Arenas | | /* If player dies on BATTLEGROUND, no stat/exp loss! For Combat-Arenas |
* in cities ONLY!!! It is very important that this doesn't get abused. | | * in cities ONLY!!! It is very important that this doesn't get abused. |
* Look at op_on_battleground() for more info --AndreasV | | * Look at op_on_battleground() for more info --AndreasV |
| | |
"Local medics have saved your life..."); | | "Local medics have saved your life..."); |
| | |
/* restore player */ | | /* restore player */ |
cast_heal(op, 0, SP_CURE_POISON); | | at = find_archetype("poisoning"); |
cast_heal(op, 0, SP_CURE_CONFUSION); | | tmp=present_arch_in_ob(at,op); |
| | if (tmp) { |
| | remove_ob(tmp); |
| | free_object(tmp); |
| | new_draw_info(NDI_UNIQUE, 0,op, "Your body feels cleansed"); |
| | } |
| | |
| | at = find_archetype("confusion"); |
| | tmp=present_arch_in_ob(at,op); |
| | if (tmp) { |
| | remove_ob(tmp); |
| | free_object(tmp); |
| | new_draw_info(NDI_UNIQUE, 0,tmp, "Your mind feels clearer"); |
| | } |
| | |
cure_disease(op,0); /* remove any disease */ | | cure_disease(op,0); /* remove any disease */ |
op->stats.hp=op->stats.maxhp; | | op->stats.hp=op->stats.maxhp; |
if (op->stats.food<=0) op->stats.food=999; | | if (op->stats.food<=0) op->stats.food=999; |
| | |
/**************************************/ | | /**************************************/ |
| | |
/* remove any poisoning and confusion the character may be suffering.*/ | | /* remove any poisoning and confusion the character may be suffering.*/ |
cast_heal(op, 0, SP_CURE_POISON); | | /* restore player */ |
cast_heal(op, 0, SP_CURE_CONFUSION); | | at = find_archetype("poisoning"); |
| | tmp=present_arch_in_ob(at,op); |
| | if (tmp) { |
| | remove_ob(tmp); |
| | free_object(tmp); |
| | new_draw_info(NDI_UNIQUE, 0,op, "Your body feels cleansed"); |
| | } |
| | |
| | at = find_archetype("confusion"); |
| | tmp=present_arch_in_ob(at,op); |
| | if (tmp) { |
| | remove_ob(tmp); |
| | free_object(tmp); |
| | new_draw_info(NDI_UNIQUE, 0,tmp, "Your mind feels clearer"); |
| | } |
cure_disease(op,0); /* remove any disease */ | | cure_disease(op,0); /* remove any disease */ |
| | |
/*add_exp(op, (op->stats.exp * -0.20)); */ | | /*add_exp(op, (op->stats.exp * -0.20)); */ |
| | |
op->contr->own_title[0]='\0'; | | op->contr->own_title[0]='\0'; |
new_draw_info(NDI_UNIQUE|NDI_ALL, 0,NULL, buf); | | new_draw_info(NDI_UNIQUE|NDI_ALL, 0,NULL, buf); |
check_score(op); | | check_score(op); |
if(op->contr->golem!=NULL) { | | if(op->contr->ranges[range_golem]!=NULL) { |
remove_friendly_object(op->contr->golem); | | remove_friendly_object(op->contr->ranges[range_golem]); |
remove_ob(op->contr->golem); | | remove_ob(op->contr->ranges[range_golem]); |
free_object(op->contr->golem); | | free_object(op->contr->ranges[range_golem]); |
op->contr->golem=NULL; | | op->contr->ranges[range_golem]=NULL; |
| | op->contr->golem_count=0; |
} | | } |
loot_object(op); /* Remove some of the items for good */ | | loot_object(op); /* Remove some of the items for good */ |
remove_ob(op); | | remove_ob(op); |
| | |
} | | } |
| | |
| | |
/* cast_dust() - handles op throwing objects of type 'DUST' */ | | /* cast_dust() - handles op throwing objects of type 'DUST'. |
| | * This is much simpler in the new spell code - we basically |
| | * just treat this as any other spell casting object. |
| | */ |
| | |
void cast_dust (object *op, object *throw_ob, int dir) { | | void cast_dust (object *op, object *throw_ob, int dir) { |
archetype *arch = find_archetype(spells[throw_ob->stats.sp].archname); | | object *skop, *spob; |
| | |
| | skop = find_skill_by_name(op, throw_ob->skill); |
| | |
/* casting POTION 'dusts' is really a use_magic_item skill */ | | /* casting POTION 'dusts' is really a use_magic_item skill */ |
if(op->type==PLAYER&&throw_ob->type==POTION | | if(op->type==PLAYER && throw_ob->type==POTION && !skop) { |
&&!change_skill(op,SK_USE_MAGIC_ITEM)) { | | |
LOG(llevError,"Player %s lacks critical skill use_magic_item!\n", | | LOG(llevError,"Player %s lacks critical skill use_magic_item!\n", |
op->name); | | op->name); |
return; | | return; |
} | | } |
| | spob = throw_ob->inv; |
| | if (op->type==PLAYER && spob) |
| | new_draw_info_format(NDI_UNIQUE, 0,op,"You cast %s.",spob->name); |
| | |
if(throw_ob->type==POTION&&arch!= NULL) | | cast_spell(op, throw_ob, dir, spob, NULL); |
cast_cone(op,throw_ob,dir,10,throw_ob->stats.sp,arch,1); | | |
else if((arch=find_archetype("dust_effect"))!=NULL) { /* dust_effect */ | | |
cast_cone(op,throw_ob,dir,1,0,arch,0); | | |
} else /* problem occured! */ | | |
LOG(llevError,"cast_dust() can't find an archetype to use!\n"); | | |
| | |
if (op->type==PLAYER&&arch) | | |
new_draw_info_format(NDI_UNIQUE, 0,op,"You cast %s.",query_name(throw_ob)); | | |
if(!QUERY_FLAG(throw_ob,FLAG_REMOVED)) remove_ob(throw_ob); | | if(!QUERY_FLAG(throw_ob,FLAG_REMOVED)) remove_ob(throw_ob); |
free_object(throw_ob); | | free_object(throw_ob); |
} | | } |
| | |
void make_visible (object *op) { | | void make_visible (object *op) { |
op->hide = 0; | | op->hide = 0; |
op->invisible = 0; | | op->invisible = 0; |
if(op->type==PLAYER) | | if(op->type==PLAYER) { |
op->contr->tmp_invis = 0; | | op->contr->tmp_invis = 0; |
CLEAR_FLAG(op, FLAG_INVIS_UNDEAD); | | if (op->contr->invis_race) FREE_AND_CLEAR_STR(op->contr->invis_race); |
| | } |
update_object(op,UP_OBJ_FACE); | | update_object(op,UP_OBJ_FACE); |
} | | } |
| | |
| | |
| | |
void do_hidden_move (object *op) { | | void do_hidden_move (object *op) { |
int hide=0, num=random_roll(0, 19, op, PREFER_LOW); | | int hide=0, num=random_roll(0, 19, op, PREFER_LOW); |
| | object *skop; |
| | |
if(!op || !op->map) return; | | if(!op || !op->map) return; |
| | |
/* its *extremely* hard to run and sneak/hide at the same time! */ | | /* its *extremely* hard to run and sneak/hide at the same time! */ |
if(op->type==PLAYER && op->contr->run_on) { | | if(op->type==PLAYER && op->contr->run_on) { |
if(num >= SK_level(op)) { | | skop = find_obj_by_type_subtype(op, SKILL, SK_HIDING); |
| | |
| | if(!skop || num >= skop->level) { |
new_draw_info(NDI_UNIQUE,0,op,"You ran too much! You are no longer hidden!"); | | new_draw_info(NDI_UNIQUE,0,op,"You ran too much! You are no longer hidden!"); |
make_visible(op); | | make_visible(op); |
return; | | return; |
| | |
if(op->type==PLAYER) new_draw_info(NDI_UNIQUE, 0,op, | | if(op->type==PLAYER) new_draw_info(NDI_UNIQUE, 0,op, |
"You moved out of hiding! You are visible!"); | | "You moved out of hiding! You are visible!"); |
} | | } |
| | else if (op->type == PLAYER && skop) { |
| | change_exp(op, calc_skill_exp(op, NULL, skop), skop->skill, 0); |
| | } |
} | | } |
| | |
/* determine if who is standing near a hostile creature. */ | | /* determine if who is standing near a hostile creature. */ |
| | |
if(op->invisible && QUERY_FLAG(op,FLAG_ALIVE)) { | | if(op->invisible && QUERY_FLAG(op,FLAG_ALIVE)) { |
if(QUERY_FLAG(op,FLAG_MAKE_INVIS)) | | if(QUERY_FLAG(op,FLAG_MAKE_INVIS)) |
return 0; | | return 0; |
else if(op->hide || (op->contr&&op->contr->tmp_invis)) { | | |
| | if (op->contr && op->contr->tmp_invis == 0) return 0; |
| | |
| | /* If monsters, they should become visible */ |
| | if(op->hide || !op->contr || (op->contr && op->contr->tmp_invis)) { |
new_draw_info_format(NDI_UNIQUE, 0,op,"You become %s!",op->hide?"unhidden":"visible"); | | new_draw_info_format(NDI_UNIQUE, 0,op,"You become %s!",op->hide?"unhidden":"visible"); |
return 1; | | return 1; |
} else if(op->contr && !op->contr->shoottype==range_magic) { | | |
/* improved invis is lost EXCEPT for case of casting of magic */ | | |
new_draw_info(NDI_UNIQUE, 0,op,"Your invisibility spell is broken!"); | | |
return 1; | | |
} | | } |
} | | } |
| | |
return 0; | | return 0; |
} | | } |
| | |
| | |
void dragon_ability_gain(object *who, int atnr, int level) { | | void dragon_ability_gain(object *who, int atnr, int level) { |
treasurelist *trlist = NULL; /* treasurelist */ | | treasurelist *trlist = NULL; /* treasurelist */ |
treasure *tr; /* treasure */ | | treasure *tr; /* treasure */ |
object *tmp; /* tmp. object */ | | object *tmp,*skop; /* tmp. object */ |
object *item; /* treasure object */ | | object *item; /* treasure object */ |
char buf[MAX_BUF]; /* tmp. string buffer */ | | char buf[MAX_BUF]; /* tmp. string buffer */ |
int i=0, j=0; | | int i=0, j=0; |
| | |
| | |
/* grant direct spell */ | | /* grant direct spell */ |
if (item->type == SPELLBOOK) { | | if (item->type == SPELLBOOK) { |
int spell = look_up_spell_name (item->slaying); | | if (check_spell_known (who, item->inv->name)) |
if (spell<0 || check_spell_known (who, spell)) | | |
return; | | return; |
if (item->invisible) { | | if (item->invisible) { |
sprintf(buf, "You gained the ability of %s", spells[spell].name); | | new_draw_info_format(NDI_UNIQUE|NDI_BLUE, 0, who, "You gained the ability of %s", item->inv->name); |
new_draw_info(NDI_UNIQUE|NDI_BLUE, 0, who, buf); | | do_learn_spell (who, item->inv, 0); |
do_learn_spell (who, spell, 0); | | |
return; | | return; |
} | | } |
} | | } |
else if (item->type == SKILL) { | | else if (item->type == SKILL) { |
if (strcmp(item->title, "clawing") == 0 && | | if (item->subtype == SK_CLAWING && (skop=find_skill_by_name(who, item->skill))!=NULL) { |
change_skill (who, lookup_skill_by_name("clawing"))) { | | |
/* adding new attacktypes to the clawing skill */ | | |
tmp = who->chosen_skill; /* clawing skill object */ | | |
| | |
if (tmp->type == SKILL && strcmp(tmp->name, "clawing")==0 | | /* should this perhaps be (skop->attackyp & item->attacktype)!=item->attacktype ... |
&& !(tmp->attacktype & item->attacktype)) { | | * in this way, if the player is missing any of the attacktypes, he gets |
| | * them. As it is now, if the player has any that match the granted skill, |
| | * but not all of them, he gets nothing. |
| | */ |
| | if (!(skop->attacktype & item->attacktype)) { |
/* always add physical if there's none */ | | /* always add physical if there's none */ |
if (tmp->attacktype == 0) tmp->attacktype = AT_PHYSICAL; | | if (skop->attacktype == 0) skop->attacktype = AT_PHYSICAL; |
| | |
/* we add the new attacktype to the clawing ability */ | | /* we add the new attacktype to the clawing ability */ |
tmp->attacktype += item->attacktype; | | skop->attacktype |= item->attacktype; |
| | |
if (item->msg != NULL) | | if (item->msg != NULL) |
new_draw_info(NDI_UNIQUE|NDI_BLUE, 0, who, item->msg); | | new_draw_info(NDI_UNIQUE|NDI_BLUE, 0, who, item->msg); |
| | |
| | |
/* adding new spellpath attunements */ | | /* adding new spellpath attunements */ |
if (item->path_attuned > 0 && !(skin->path_attuned & item->path_attuned)) { | | if (item->path_attuned > 0 && !(skin->path_attuned & item->path_attuned)) { |
skin->path_attuned += item->path_attuned; /* add attunement to skin */ | | skin->path_attuned |= item->path_attuned; /* add attunement to skin */ |
| | |
/* print message */ | | /* print message */ |
sprintf(buf, "You feel attuned to "); | | sprintf(buf, "You feel attuned to "); |
| | |
else { | | else { |
/* generate misc. treasure */ | | /* generate misc. treasure */ |
tmp = arch_to_object (tr->item); | | tmp = arch_to_object (tr->item); |
sprintf(buf, "You gained %s", query_short_name(tmp)); | | new_draw_info_format(NDI_UNIQUE|NDI_BLUE, 0, who, "You gained %s", query_short_name(tmp)); |
new_draw_info(NDI_UNIQUE|NDI_BLUE, 0, who, buf); | | |
tmp = insert_ob_in_ob (tmp, who); | | tmp = insert_ob_in_ob (tmp, who); |
if (who->type == PLAYER) | | if (who->type == PLAYER) |
esrv_send_item(who, tmp); | | esrv_send_item(who, tmp); |