version 1.69 | | version 1.70 |
---|
| | |
/* | | /* |
* static char *rcsid_attack_c = | | * static char *rcsid_attack_c = |
* "$Id: attack.c,v 1.69 2002/07/15 04:57:13 mwedel Exp $"; | | * "$Id: attack.c,v 1.70 2002/07/25 06:57:14 mwedel Exp $"; |
*/ | | */ |
/* | | /* |
CrossFire, A Multiplayer game for X-windows | | CrossFire, A Multiplayer game for X-windows |
| | |
* It was initially used by (kill-object) developed for the Collector's | | * It was initially used by (kill-object) developed for the Collector's |
* Sword. Note that nothing has been changed from the original version | | * Sword. Note that nothing has been changed from the original version |
* of the following code. | | * of the following code. |
| | * op is what is being killed. |
| | * dam is the damage done to it. |
| | * hitter is what is hitting it. |
| | * type is the attacktype. |
| | * |
| | * This function was a bit of a mess with hitter getting changed, |
| | * values being stored away but not used, etc. I've cleaned it up |
| | * a bit - I think it should be functionally equivalant. |
| | * MSW 2002-07-17 |
*/ | | */ |
int kill_object(object *op,int dam, object *hitter, int type) | | int kill_object(object *op,int dam, object *hitter, int type) |
{ | | { |
char buf[MAX_BUF]; | | char buf[MAX_BUF]; |
object *old_hitter=NULL; /* this is used in case of servant monsters */ | | |
int maxdam=0; | | int maxdam=0; |
int battleg=0; /* true if op standing on battleground */ | | int battleg=0; /* true if op standing on battleground */ |
int killed_script_rtn = 0; | | int killed_script_rtn = 0; |
object *owner=NULL; | | object *owner=NULL, *old_skill; |
int evtid; | | int evtid; |
| | |
#ifdef PLUGINS | | #ifdef PLUGINS |
CFParm CFP; | | CFParm CFP; |
#endif | | #endif |
/* Object has been killed. Lets clean it up */ | | if (op->stats.hp>=0) |
if (op->stats.hp<0) { | | return -1; |
| | |
| | |
#ifdef PLUGINS | | #ifdef PLUGINS |
/* GROS: Handle for plugin death event */ | | /* GROS: Handle for plugin death event */ |
if(op->event_hook[EVENT_DEATH] != NULL) | | if(op->event_hook[EVENT_DEATH] != NULL) |
| | |
if (get_owner (op) != NULL && op->owner->type == PLAYER) | | if (get_owner (op) != NULL && op->owner->type == PLAYER) |
op->owner->contr->golem=NULL; | | op->owner->contr->golem=NULL; |
else | | else |
LOG (llevError, "BUG: hit_player(): Encountered golem " | | LOG (llevError, "BUG: hit_player(): Encountered golem without owner.\n"); |
"without owner.\n"); | | |
remove_ob(op); | | remove_ob(op); |
free_object(op); | | free_object(op); |
return maxdam; | | return maxdam; |
| | |
tmv = localtime(&t); | | tmv = localtime(&t); |
strftime(buf, 256,"%a %b %d %H:%M:%S %Y", tmv); | | strftime(buf, 256,"%a %b %d %H:%M:%S %Y", tmv); |
| | |
| | |
LOG(llevInfo,"%s PLAYER_KILL_PLAYER: %s (%s) killed %s\n", | | LOG(llevInfo,"%s PLAYER_KILL_PLAYER: %s (%s) killed %s\n", |
buf, owner->name, owner->contr->socket.host, query_name(op)); | | buf, owner->name, owner->contr->socket.host, query_name(op)); |
} | | } |
| | |
/* This appears to be doing primitive filtering to only | | /* try to filter some things out - basically, if you are |
* display the more interesting monsters. | | * killing a level 1 creature and your level 20, you |
| | * probably don't want to see that. |
*/ | | */ |
if ( owner->level/2<op->level || op->stats.exp>1000) { | | if ( owner->level < op->level * 2|| op->stats.exp>1000) { |
if(owner!=hitter) { | | if(owner!=hitter) { |
(void) sprintf(buf,"You killed %s with %s.",query_name(op) | | new_draw_info_format(NDI_BLACK, 0, owner, |
,query_name(hitter)); | | "You killed %s with %s.",query_name(op), |
old_hitter = hitter; | | query_name(hitter)); |
owner->exp_obj=hitter->exp_obj; | | |
} | | } |
else { | | else { |
(void) sprintf(buf,"You killed %s.",query_name(op)); | | new_draw_info_format(NDI_BLACK, 0, owner, |
| | "You killed %s.",query_name(op)); |
} | | } |
| | /* Only play sounds for melee kills */ |
| | if (hitter->type == PLAYER) |
play_sound_map(owner->map, owner->x, owner->y, SOUND_PLAYER_KILLS); | | play_sound_map(owner->map, owner->x, owner->y, SOUND_PLAYER_KILLS); |
new_draw_info(NDI_BLACK, 0,owner,buf); | | } |
} /* message should be displayed */ | | |
| | |
/* If a player kills another player with melee, not on | | /* If a player kills another player with melee, not on |
* battleground, the "killer" looses 1 luck. Since this is | | * battleground, the "killer" looses 1 luck. Since this is |
* not reversible, it's actually quite a pain IMHO. -AV | | * not reversible, it's actually quite a pain IMHO. -AV |
| | * Fix bug in that we were changing the luck of the hitter, not |
| | * player that the object belonged to - so if you killed another player |
| | * with spells, pets, whatever, there was no penalty. |
*/ | | */ |
if(op->type == PLAYER && hitter != op && !battleg) | | if(op->type == PLAYER && hitter != op && !battleg) |
change_luck(hitter, -1); | | change_luck(owner, -1); |
} /* was a player that hit this creature */ | | } /* Was it a player that hit somethign */ |
| | |
| | |
/* Pet killed something. */ | | /* Pet (or spell) killed something. */ |
if(get_owner(hitter)!=NULL) { | | if(owner != hitter ) { |
(void) sprintf(buf,"%s killed %s with %s%s.",hitter->owner->name, | | (void) sprintf(buf,"%s killed %s with %s%s.",owner->name, |
query_name(op),query_name(hitter), battleg? " (duel)":""); | | query_name(op),query_name(hitter), battleg? " (duel)":""); |
old_hitter = hitter; | | |
owner->exp_obj=hitter->exp_obj; | | owner->exp_obj=hitter->exp_obj; |
hitter=hitter->owner; | | |
} | | } |
else | | else |
(void) sprintf(buf,"%s killed %s%s.",hitter->name,op->name, | | (void) sprintf(buf,"%s killed %s%s.",hitter->name,op->name, |
battleg? " (duel)":""); | | battleg? " (duel)":""); |
| | |
| | new_draw_info(NDI_ALL, op->type==PLAYER?1:10, NULL, buf); |
| | |
/* If you didn't kill yourself, and your not the wizard */ | | /* If you didn't kill yourself, and your not the wizard */ |
if(hitter!=op&&!QUERY_FLAG(op, FLAG_WAS_WIZ)) { | | if(hitter!=op&&!QUERY_FLAG(op, FLAG_WAS_WIZ)) { |
int exp=op->stats.exp; | | int exp=op->stats.exp; |
| | |
if(!settings.simple_exp && hitter->level>op->level) | | if(!settings.simple_exp && hitter->level>op->level) |
exp=(exp*(op->level+1))/MAX(hitter->level+1, 1); | | exp=(exp*(op->level+1))/MAX(hitter->level+1, 1); |
| | |
/* new exp system in here. Try to insure the right skill is modifying gained exp */ | | if (owner != hitter) { |
if(hitter->type==PLAYER && !old_hitter) | | old_skill = owner->chosen_skill; |
exp = calc_skill_exp(hitter,op); | | owner->chosen_skill = hitter->chosen_skill; |
/* case for attack spells, summoned monsters killing */ | | owner->exp_obj=hitter->exp_obj; |
if (old_hitter && hitter->type==PLAYER) { | | |
object *old_skill = hitter->chosen_skill; | | /* Not sure if this will happen or not - I'm think it could with |
| | * summoned pets - they may use a skill and thus the chosen_skill |
hitter->chosen_skill=old_hitter->chosen_skill; | | * gets updated to something they have. |
exp = calc_skill_exp(hitter,op); | | */ |
hitter->chosen_skill = old_skill; | | if (owner->chosen_skill && owner->chosen_skill->env != owner) { |
| | LOG(llevDebug,"kill_object: chosen skill doesn't belong to owner? (%s, %s)\n", |
| | owner->chosen_skill->name, owner->name); |
| | owner->chosen_skill = NULL; |
| | } |
| | if (owner->exp_obj && owner->exp_obj->env != owner) { |
| | LOG(llevDebug,"kill_object: exp_obj doesn't belong to owner? (%s, %s)\n", |
| | owner->exp_obj->name, owner->name); |
| | owner->exp_obj = NULL; |
} | | } |
| | } |
| | |
| | exp = calc_skill_exp(owner,op); |
| | |
/* Really don't give much experience for killing other players */ | | /* Really don't give much experience for killing other players */ |
if (op->type==PLAYER) { | | if (op->type==PLAYER) { |
if (battleg) { | | if (battleg) { |
new_draw_info(NDI_UNIQUE, 0,hitter, "Your foe has fallen!"); | | new_draw_info(NDI_UNIQUE, 0,owner, "Your foe has fallen!"); |
new_draw_info(NDI_UNIQUE, 0,hitter, "VICTORY!!!"); | | new_draw_info(NDI_UNIQUE, 0,owner, "VICTORY!!!"); |
} | | } |
else | | else |
exp = MIN(5000000, MAX(0, exp/10)); | | exp = MIN(5000000, MAX(0, exp/10)); |
| | |
* exp by killing him | | * exp by killing him |
*/ | | */ |
if (battleg) exp = 0; | | if (battleg) exp = 0; |
if(hitter->type!=PLAYER || hitter->contr->party_number<=0) { | | |
add_exp(hitter,exp); | | if(owner->type!=PLAYER || owner->contr->party_number<=0) { |
| | add_exp(owner,exp); |
} | | } |
else { | | else { |
int shares=0,count=0; | | int shares=0,count=0; |
| | |
player *pl; | | player *pl; |
int no=hitter->contr->party_number; | | |
| | int no=owner->contr->party_number; |
#ifdef PARTY_KILL_LOG | | #ifdef PARTY_KILL_LOG |
add_kill_to_party(no,query_name(hitter),query_name(op),exp); | | add_kill_to_party(no,query_name(owner),query_name(op),exp); |
#endif | | #endif |
for(pl=first_player;pl!=NULL;pl=pl->next) { | | for(pl=first_player;pl!=NULL;pl=pl->next) { |
if(pl->ob->contr->party_number==no && on_same_map(pl->ob, hitter)) { | | if(pl->ob->contr->party_number==no && on_same_map(pl->ob, owner)) { |
count++; | | count++; |
shares+=(pl->ob->level+4); | | shares+=(pl->ob->level+4); |
} | | } |
} | | } |
if(count==1 || shares>exp) | | if(count==1 || shares>exp) |
add_exp(hitter,exp); | | add_exp(owner,exp); |
else { | | else { |
int share=exp/shares,given=0,nexp; | | int share=exp/shares,given=0,nexp; |
for(pl=first_player;pl!=NULL;pl=pl->next) { | | for(pl=first_player;pl!=NULL;pl=pl->next) { |
if(pl->ob->contr->party_number==no && on_same_map(pl->ob, hitter)) | | if(pl->ob->contr->party_number==no && on_same_map(pl->ob, owner)) { |
{ | | |
nexp=(pl->ob->level+4)*share; | | nexp=(pl->ob->level+4)*share; |
add_exp(pl->ob,nexp); | | add_exp(pl->ob,nexp); |
given+=nexp; | | given+=nexp; |
} | | } |
} | | } |
exp-=given; | | exp-=given; |
add_exp(hitter,exp); /* give any remainder to the player */ | | add_exp(owner,exp); /* give any remainder to the player */ |
} | | |
} | | |
} | | } |
| | } /* else part of a party */ |
| | |
| | /* set this back after we have added the experience */ |
| | if (owner != hitter) owner->chosen_skill = old_skill; |
| | |
| | } /* end if person didn't kill himself */ |
| | |
if(op->type!=PLAYER) { | | if(op->type!=PLAYER) { |
new_draw_info(NDI_ALL, 10, NULL, buf); | | |
if(QUERY_FLAG(op,FLAG_FRIENDLY)) { | | if(QUERY_FLAG(op,FLAG_FRIENDLY)) { |
object *owner = get_owner(op); | | object *owner1 = get_owner(op); |
if(owner!= NULL && owner->type == PLAYER) { | | |
sprintf(buf,"Your pet, the %s, is killed by %s.", | | if(owner1!= NULL && owner1->type == PLAYER) { |
| | play_sound_player_only(owner1->contr, SOUND_PET_IS_KILLED,0,0); |
| | /* Maybe we should include the owner that killed this, maybe not */ |
| | new_draw_info_format(NDI_UNIQUE, 0,owner1,"Your pet, the %s, is killed by %s.", |
op->name,hitter->name); | | op->name,hitter->name); |
play_sound_player_only(owner->contr, SOUND_PET_IS_KILLED,0,0); | | |
new_draw_info(NDI_UNIQUE, 0,owner,buf); | | |
} | | } |
remove_friendly_object(op); | | remove_friendly_object(op); |
} | | } |
| | |
} | | } |
/* Player has been killed! */ | | /* Player has been killed! */ |
else { | | else { |
new_draw_info(NDI_ALL, 1, NULL, buf); | | if(owner->type==PLAYER) { |
if(hitter->type==PLAYER) { | | snprintf(op->contr->killer, BIG_NAME, "%s the %s",owner->name,owner->contr->title); |
sprintf(buf,"%s the %s",hitter->name,hitter->contr->title); | | |
strncpy(op->contr->killer,buf,BIG_NAME); | | |
} | | } |
else { | | else { |
strncpy(op->contr->killer,hitter->name,BIG_NAME); | | strncpy(op->contr->killer,hitter->name,BIG_NAME); |
op->contr->killer[BIG_NAME-1]='\0'; | | op->contr->killer[BIG_NAME-1]='\0'; |
} | | } |
} | | } |
} | | /* This was return -1 - that doesn't seem correct - if we return -1, process |
return -1; | | * continues in the calling function. |
| | */ |
| | return maxdam; |
} | | } |
| | |
/* This isn't used just for players, but in fact most objects. | | /* This isn't used just for players, but in fact most objects. |
| | |
tear_down_wall(op); | | tear_down_wall(op); |
return maxdam; /* nothing more to do for wall */ | | return maxdam; /* nothing more to do for wall */ |
} | | } |
/* Start of creature kill processing */ | | |
| | |
| | /* See if the creature has been killed */ |
rtn_kill = kill_object(op, dam, hitter, type); | | rtn_kill = kill_object(op, dam, hitter, type); |
if (rtn_kill != -1) | | if (rtn_kill != -1) |
{ | | |
return rtn_kill; | | return rtn_kill; |
}; | | |
| | |
/* End of creature kill processing */ | | |
| | |
/* Used to be ghosthit removal - we now use the ONE_HIT flag. Note | | /* Used to be ghosthit removal - we now use the ONE_HIT flag. Note |
* that before if the player was immune to ghosthit, the monster | | * that before if the player was immune to ghosthit, the monster |