version 1.42 | | version 1.43 |
---|
| | |
/* | | /* |
* static char *rcsid_attack_c = | | * static char *rcsid_attack_c = |
* "$Id: attack.c,v 1.42 2001/09/26 21:34:08 garbled Exp $"; | | * "$Id: attack.c,v 1.43 2001/10/07 07:17:46 garbled Exp $"; |
*/ | | */ |
/* | | /* |
CrossFire, A Multiplayer game for X-windows | | CrossFire, A Multiplayer game for X-windows |
| | |
#include <global.h> | | #include <global.h> |
#include <living.h> | | #include <living.h> |
#include <material.h> | | #include <material.h> |
| | #include <skills.h> |
| | |
#ifndef __CEXTRACT__ | | #ifndef __CEXTRACT__ |
#include <sproto.h> | | #include <sproto.h> |
| | |
#endif | | #endif |
} | | } |
| | |
static att_msg *attack_message(int dam) { | | void attack_message(int dam, int type, object *op, object *hitter) { |
static att_msg messages; | | char buf[MAX_BUF], buf1[MAX_BUF], buf2[MAX_BUF]; |
static char buf1[MAX_BUF],buf2[MAX_BUF]; | | int i, found=0; |
| | |
| | /* put in a few special messages for some of the common attacktypes |
| | * a player might have. For example, fire, electric, cold, etc |
| | * [garbled 20010919] |
| | */ |
| | |
if(dam<0) { | | if(dam<0) { |
strcpy(buf1,"hit"); | | sprintf(buf1, "hit %s", op->name); |
buf2[0]='\0'; | | sprintf(buf2, " hit"); |
| | found++; |
} else if(dam==0) { | | } else if(dam==0) { |
strcpy(buf1,"missed"); | | sprintf(buf1, "missed %s", op->name); |
buf2[0]='\0'; | | sprintf(buf2, " missed"); |
} else if(dam<3) { | | found++; |
strcpy(buf1,"grazed"); | | } else if (hitter->type == PLAYER && IS_LIVE(op)) { |
buf2[0]='\0'; | | if (USING_SKILL(hitter, SK_KARATE)) { |
} else if(dam<6) { | | for (i=0; i < MAXATTACKMESS && attack_mess[ATM_KARATE][i].level != -1; |
strcpy(buf1,"hit"); | | i++) |
buf2[0]='\0'; | | if (dam < attack_mess[ATM_KARATE][i].level) { |
} else if(dam<9) { | | sprintf(buf1, "%s %s%s", attack_mess[ATM_KARATE][i].buf1, |
strcpy(buf1,"hit"); | | op->name, attack_mess[ATM_KARATE][i].buf2); |
strcpy(buf2," hard"); | | sprintf(buf2, "%s", attack_mess[ATM_KARATE][i].buf3); |
} else if(dam<12) { | | found++; |
strcpy(buf1,"hit"); | | break; |
strcpy(buf2," very hard"); | | } |
} else if(dam<16) { | | } else if (USING_SKILL(hitter, SK_CLAWING)) { |
strcpy(buf1,"hit"); | | for (i=0; i < MAXATTACKMESS && attack_mess[ATM_CLAW][i].level != -1; |
strcpy(buf2," extremely hard"); | | i++) |
} else if(dam<20) { | | if (dam < attack_mess[ATM_CLAW][i].level) { |
strcpy(buf1,"crush"); | | sprintf(buf1, "%s %s%s", attack_mess[ATM_CLAW][i].buf1, |
strcpy(buf2," very hard"); | | op->name, attack_mess[ATM_CLAW][i].buf2); |
} else if(dam<27) { | | sprintf(buf2, "%s", attack_mess[ATM_CLAW][i].buf3); |
strcpy(buf1,"smash"); | | found++; |
strcpy(buf2," with a bonecrunching sound"); | | break; |
} else if(dam<40) { | | } |
strcpy(buf1,"shred"); | | } else if (USING_SKILL(hitter, SK_BOXING)) { |
strcpy(buf2," to pieces"); | | for (i=0; i < MAXATTACKMESS && attack_mess[ATM_PUNCH][i].level != -1; |
} else if(dam<70) { | | i++) |
strcpy(buf1,"beat"); | | if (dam < attack_mess[ATM_PUNCH][i].level) { |
strcpy(buf2," to a pulp"); | | sprintf(buf1, "%s %s%s", attack_mess[ATM_PUNCH][i].buf1, |
} else if(dam<130) { | | op->name, attack_mess[ATM_PUNCH][i].buf2); |
strcpy(buf1,"grind"); | | sprintf(buf2, "%s", attack_mess[ATM_PUNCH][i].buf3); |
strcpy(buf2," to dust"); | | found++; |
} else if(dam<250) { | | break; |
strcpy(buf1,"atomize"); | | } |
buf2[0]='\0'; | | } |
} else { | | } |
strcpy(buf1,"annihilate"); | | if (IS_ARROW(hitter) && (type == AT_PHYSICAL || type == AT_MAGIC) && |
buf2[0]='\0'; | | !found) { |
| | sprintf(buf1, "hit"); /* just in case */ |
| | for (i=0; i < MAXATTACKMESS; i++) |
| | if (dam < attack_mess[ATM_ARROW][i].level) { |
| | sprintf(buf2, "%s", attack_mess[ATM_ARROW][i].buf3); |
| | break; |
| | } |
| | } else if (type & AT_DRAIN && IS_LIVE(op) && !found) { |
| | /* drain is first, because some items have multiple attypes */ |
| | for (i=0; i < MAXATTACKMESS && attack_mess[ATM_DRAIN][i].level != -1; |
| | i++) |
| | if (dam < attack_mess[ATM_DRAIN][i].level) { |
| | sprintf(buf1, "%s %s%s", attack_mess[ATM_DRAIN][i].buf1, |
| | op->name, attack_mess[ATM_DRAIN][i].buf2); |
| | sprintf(buf2, "%s", attack_mess[ATM_DRAIN][i].buf3); |
| | break; |
| | } |
| | } else if (type & AT_ELECTRICITY && IS_LIVE(op) && !found) { |
| | for (i=0; i < MAXATTACKMESS && attack_mess[ATM_ELEC][i].level != -1; |
| | i++) |
| | if (dam < attack_mess[ATM_ELEC][i].level) { |
| | sprintf(buf1, "%s %s%s", attack_mess[ATM_ELEC][i].buf1, |
| | op->name, attack_mess[ATM_ELEC][i].buf2); |
| | sprintf(buf2, "%s", attack_mess[ATM_ELEC][i].buf3); |
| | break; |
| | } |
| | } else if (type & AT_COLD && IS_LIVE(op) && !found) { |
| | for (i=0; i < MAXATTACKMESS && attack_mess[ATM_COLD][i].level != -1; |
| | i++) |
| | if (dam < attack_mess[ATM_COLD][i].level) { |
| | sprintf(buf1, "%s %s%s", attack_mess[ATM_COLD][i].buf1, |
| | op->name, attack_mess[ATM_COLD][i].buf2); |
| | sprintf(buf2, "%s", attack_mess[ATM_COLD][i].buf3); |
| | break; |
| | } |
| | } else if (type & AT_FIRE && !found) { |
| | for (i=0; i < MAXATTACKMESS && attack_mess[ATM_FIRE][i].level != -1; |
| | i++) |
| | if (dam < attack_mess[ATM_FIRE][i].level) { |
| | sprintf(buf1, "%s %s%s", attack_mess[ATM_FIRE][i].buf1, |
| | op->name, attack_mess[ATM_FIRE][i].buf2); |
| | sprintf(buf2, "%s", attack_mess[ATM_FIRE][i].buf3); |
| | break; |
| | } |
| | } else if (!found){ |
| | for (i=0; i < MAXATTACKMESS && attack_mess[ATM_BASIC][i].level != -1; |
| | i++) |
| | if (dam < attack_mess[ATM_BASIC][i].level) { |
| | sprintf(buf1, "%s %s%s", attack_mess[ATM_BASIC][i].buf1, |
| | op->name, attack_mess[ATM_BASIC][i].buf2); |
| | sprintf(buf2, "%s", attack_mess[ATM_BASIC][i].buf3); |
| | break; |
| | } |
| | } |
| | /* Did a player hurt another player? Inform both! */ |
| | if(op->type==PLAYER&& |
| | (get_owner(hitter)==NULL?hitter->type:hitter->owner->type)==PLAYER) { |
| | if(get_owner(hitter)!=NULL) |
| | sprintf(buf,"%s's %s %s you.", |
| | hitter->owner->name, hitter->name, buf2); |
| | else { |
| | sprintf(buf,"%s%s you.",hitter->name, buf2); |
| | if (dam != 0) { |
| | if (dam < 10) |
| | play_sound_player_only(op->contr, SOUND_PLAYER_IS_HIT1,0,0); |
| | else if (dam < 20) |
| | play_sound_player_only(op->contr, SOUND_PLAYER_IS_HIT2,0,0); |
| | else |
| | play_sound_player_only(op->contr, SOUND_PLAYER_IS_HIT3,0,0); |
| | } |
| | } |
| | new_draw_info(NDI_BLACK, 0,op,buf); |
| | } /* end of player hitting player */ |
| | |
| | if(hitter->type==PLAYER) { |
| | sprintf(buf,"You %s.",buf1); |
| | if (dam != 0) { |
| | if (dam < 10) |
| | play_sound_player_only(hitter->contr, SOUND_PLAYER_HITS1,0,0); |
| | else if (dam < 20) |
| | play_sound_player_only(hitter->contr, SOUND_PLAYER_HITS2,0,0); |
| | else |
| | play_sound_player_only(hitter->contr, SOUND_PLAYER_HITS3,0,0); |
| | } |
| | new_draw_info(NDI_BLACK, 0, hitter, buf); |
| | } else if(get_owner(hitter)!=NULL&&hitter->owner->type==PLAYER) { |
| | sprintf(buf,"Your %s%s %s.", hitter->name, buf2, op->name); |
| | play_sound_map(op->map, op->x, op->y, SOUND_PLAYER_HITS4); |
| | new_draw_info(NDI_BLACK, 0, hitter->owner, buf); |
} | | } |
messages.msg1=buf1,messages.msg2=buf2; | | |
return &messages; | | |
} | | } |
| | |
| | |
| | |
} /* end of if hitter hit op */ | | } /* end of if hitter hit op */ |
/* if we missed, dam=0 */ | | /* if we missed, dam=0 */ |
| | |
msg=attack_message(dam); | | /*attack_message(dam, type, op, hitter);*/ |
| | |
/* Did a player hurt another player? Inform both! */ | | |
if(op->type==PLAYER&& | | |
(get_owner(hitter)==NULL?hitter->type:hitter->owner->type)==PLAYER) { | | |
if(get_owner(hitter)!=NULL) | | |
sprintf(buf,"%s %ss you%s with %s.", | | |
hitter->owner->name,msg->msg1,msg->msg2,hitter->name); | | |
else { | | |
sprintf(buf,"%s %ss you%s.",hitter->name,msg->msg1,msg->msg2); | | |
if (dam != 0) { | | |
if (dam < 10) | | |
play_sound_player_only(op->contr, SOUND_PLAYER_IS_HIT1,0,0); | | |
else if (dam < 20) | | |
play_sound_player_only(op->contr, SOUND_PLAYER_IS_HIT2,0,0); | | |
else | | |
play_sound_player_only(op->contr, SOUND_PLAYER_IS_HIT3,0,0); | | |
} | | |
} | | |
new_draw_info(NDI_BLACK, 0,op,buf); | | |
} /* end of player hitting player */ | | |
| | |
if(hitter->type==PLAYER) { | | |
sprintf(buf,"You %s %s%s.",msg->msg1,op_name,msg->msg2); | | |
if (dam != 0) { | | |
if (dam < 10) | | |
play_sound_player_only(hitter->contr, SOUND_PLAYER_HITS1,0,0); | | |
else if (dam < 20) | | |
play_sound_player_only(hitter->contr, SOUND_PLAYER_HITS2,0,0); | | |
else | | |
play_sound_player_only(hitter->contr, SOUND_PLAYER_HITS3,0,0); | | |
} | | |
new_draw_info(NDI_BLACK, 0, hitter, buf); | | |
} else if(get_owner(hitter)!=NULL&&hitter->owner->type==PLAYER) { | | |
sprintf(buf,"You %s %s%s with %s.", | | |
msg->msg1,op_name,msg->msg2,hitter->name); | | |
play_sound_map(op->map, op->x, op->y, SOUND_PLAYER_HITS4); | | |
new_draw_info(NDI_BLACK, 0, hitter->owner, buf); | | |
} | | |
| | |
goto leave; | | goto leave; |
| | |
| | |
* which needs new attacktype AT_HOLYWORD to work . b.t. */ | | * which needs new attacktype AT_HOLYWORD to work . b.t. */ |
| | |
int hit_player(object *op,int dam, object *hitter, int type) { | | int hit_player(object *op,int dam, object *hitter, int type) { |
int maxdam=0,ndam,attacktype=1,attacknum,magic=(type & AT_MAGIC); | | int maxdam=0, ndam=0, attacktype=1, magic=(type & AT_MAGIC); |
| | int maxattacktype, attacknum; |
int body_attack = op && op->head; /* Did we hit op's head? */ | | int body_attack = op && op->head; /* Did we hit op's head? */ |
int simple_attack; | | int simple_attack; |
tag_t op_tag, hitter_tag; | | tag_t op_tag, hitter_tag; |
| | |
return 0; | | return 0; |
} | | } |
| | |
| | maxattacktype = type; /* initialize this to something */ |
for (attacknum=0; attacknum<NROFATTACKS; attacknum++, attacktype=1<<attacknum) { | | for (attacknum=0; attacknum<NROFATTACKS; attacknum++, attacktype=1<<attacknum) { |
/* Magic isn't really a true attack type - it gets combined with other | | /* Magic isn't really a true attack type - it gets combined with other |
* attack types. As such, skip it over. However, if magic is | | * attack types. As such, skip it over. However, if magic is |
| | |
*/ | | */ |
if (type & attacktype) { | | if (type & attacktype) { |
ndam=hit_player_attacktype(op,hitter,dam,attacknum,magic); | | ndam=hit_player_attacktype(op,hitter,dam,attacknum,magic); |
maxdam=(maxdam>ndam)?maxdam:ndam; | | /* the >= causes us to prefer messages from special attacks, if |
| | * the damage is equal. |
| | */ |
| | if (ndam >= maxdam) { |
| | maxdam = ndam; |
| | maxattacktype = 1<<attacknum; |
| | } |
} | | } |
} | | } |
| | |
#ifdef ATTACK_DEBUG | | #ifdef ATTACK_DEBUG |
LOG(llevDebug,"Attacktype %d did %d damage\n", type, maxdam); | | LOG(llevDebug,"Attacktype %d did %d damage\n", type, maxdam); |
#endif | | #endif |
| | |
if(magic && (random_roll(1, 20, op, PREFER_HIGH))>=savethrow[op->level]) | | if(magic && (random_roll(1, 20, op, PREFER_HIGH))>=savethrow[op->level]) |
maxdam=maxdam/2; | | maxdam=maxdam/2; |
| | |
| | attack_message(maxdam, maxattacktype, op, hitter); |
| | |
op->stats.hp-=maxdam; | | op->stats.hp-=maxdam; |
| | |
/* Eneq(@csd.uu.se): Check to see if monster runs away. */ | | /* Eneq(@csd.uu.se): Check to see if monster runs away. */ |