version 1.47 | | version 1.48 |
---|
| | |
/* | | /* |
* static char *rcsid_monster_c = | | * static char *rcsid_monster_c = |
* "$Id: monster.c,v 1.47 2002/08/26 07:14:11 mwedel Exp $"; | | * "$Id: monster.c,v 1.48 2002/09/01 06:32:31 mwedel Exp $"; |
*/ | | */ |
| | |
/* | | /* |
| | |
* which CAN attack the owner. */ | | * which CAN attack the owner. */ |
if ((npc->move_type & HI4) == PETMOVE) | | if ((npc->move_type & HI4) == PETMOVE) |
{ | | { |
if (npc->owner != NULL) | | if (npc->owner == NULL) |
return npc->enemy = npc->owner->enemy; | | npc->enemy = NULL; |
else npc->enemy = NULL; | | else if (npc->enemy == NULL) |
| | npc->enemy = npc->owner->enemy; |
} | | } |
| | |
/* periodically, a monster mayu change its target. Also, if the object | | /* periodically, a monster mayu change its target. Also, if the object |
| | |
| | |
if(npc->enemy) | | if(npc->enemy) |
{ | | { |
if (QUERY_FLAG(npc->enemy,FLAG_REMOVED)||QUERY_FLAG(npc->enemy,FLAG_FREED) | | /* I broke these if's apart to better be able to see what |
|| !on_same_map(npc, npc->enemy) ||npc == npc->enemy || | | * the grouping checks are. Code is the same. |
QUERY_FLAG(npc, FLAG_NEUTRAL) || QUERY_FLAG(npc->enemy, FLAG_NEUTRAL) || /* neutral */ | | */ |
(QUERY_FLAG(npc, FLAG_FRIENDLY) && QUERY_FLAG(npc->enemy, FLAG_FRIENDLY)) || | | if ( QUERY_FLAG(npc->enemy,FLAG_REMOVED) || |
(!QUERY_FLAG(npc, FLAG_FRIENDLY) && | | QUERY_FLAG(npc->enemy,FLAG_FREED) || |
(!QUERY_FLAG(npc->enemy, FLAG_FRIENDLY) && npc->enemy->type!=PLAYER)) ) | | !on_same_map(npc, npc->enemy) || |
| | npc == npc->enemy || |
| | QUERY_FLAG(npc, FLAG_NEUTRAL) || |
| | QUERY_FLAG(npc->enemy, FLAG_NEUTRAL)) |
| | npc->enemy = NULL; |
| | |
| | else if (QUERY_FLAG(npc, FLAG_FRIENDLY) && |
| | (QUERY_FLAG(npc->enemy, FLAG_FRIENDLY) || |
| | npc->enemy->type == PLAYER || npc->enemy == npc->owner)) |
| | npc->enemy = NULL; |
| | |
| | else if (!QUERY_FLAG(npc, FLAG_FRIENDLY) && |
| | (!QUERY_FLAG(npc->enemy, FLAG_FRIENDLY) && npc->enemy->type!=PLAYER)) |
npc->enemy=NULL; | | npc->enemy=NULL; |
} | | } |
return can_detect_enemy(npc,npc->enemy,rv)?npc->enemy:NULL; | | return can_detect_enemy(npc,npc->enemy,rv)?npc->enemy:NULL; |
| | |
* this function is map tile aware. | | * this function is map tile aware. |
*/ | | */ |
object *find_nearest_living_creature(object *npc) { | | object *find_nearest_living_creature(object *npc) { |
int i,j=0,start; | | int i; |
int nx,ny; | | int nx,ny; |
mapstruct *m; | | mapstruct *m; |
object *tmp; | | object *tmp; |
| | int search_arr[SIZEOFFREE]; |
| | |
start = (RANDOM()%8)+1; | | get_search_arr(search_arr); |
for(i=start;j<SIZEOFFREE;j++, i=(i+1)%SIZEOFFREE) { | | for(i=0;i<SIZEOFFREE;i++) { |
nx = npc->x + freearr_x[i]; | | /* modified to implement smart searching using search_arr |
ny = npc->y + freearr_y[i]; | | * guidance array to determine direction of search order |
| | */ |
| | nx = npc->x + freearr_x[search_arr[i]]; |
| | ny = npc->y + freearr_y[search_arr[i]]; |
if (out_of_map(npc->map,nx,ny)) continue; | | if (out_of_map(npc->map,nx,ny)) continue; |
m = get_map_from_coord(npc->map, &nx, &ny); | | m = get_map_from_coord(npc->map, &nx, &ny); |
| | |
| | |
} | | } |
| | |
int can_hit(object *ob1,object *ob2, rv_vector *rv) { | | int can_hit(object *ob1,object *ob2, rv_vector *rv) { |
| | object *more; |
| | rv_vector rv1; |
| | |
if(QUERY_FLAG(ob1,FLAG_CONFUSED)&&!(RANDOM()%3)) | | if(QUERY_FLAG(ob1,FLAG_CONFUSED)&&!(RANDOM()%3)) |
return 0; | | return 0; |
return abs(rv->distance_x)<2&&abs(rv->distance_y)<2; | | |
| | if (abs(rv->distance_x)<2&&abs(rv->distance_y)<2) return 1; |
| | |
| | /* check all the parts of ob2 - just because we can't get to |
| | * its head doesn't mean we don't want to pound its feet |
| | */ |
| | for (more = ob2->more; more!=NULL; more = more->more) { |
| | get_rangevector(ob1, more, &rv1, 0); |
| | if (abs(rv1.distance_x)<2&&abs(rv1.distance_y)<2) return 1; |
| | } |
| | return 0; |
| | |
} | | } |
| | |
/* Returns 1 is monster should cast spell sp at an enemy | | /* Returns 1 is monster should cast spell sp at an enemy |
| | |
| | |
void check_earthwalls(object *op, int x, int y) { | | void check_earthwalls(object *op, int x, int y) { |
object *tmp; | | object *tmp; |
tmp = get_map_ob(op->map, x, y); | | for (tmp = get_map_ob(op->map, x, y); tmp!=NULL; tmp=tmp->above) { |
if (tmp!= NULL) | | if (tmp->type == EARTHWALL) { |
while(tmp->above != NULL) | | |
tmp=tmp->above; | | |
if (tmp!= NULL && tmp->type == EARTHWALL) | | |
hit_player(tmp,op->stats.dam,op,AT_PHYSICAL); | | hit_player(tmp,op->stats.dam,op,AT_PHYSICAL); |
| | return; |
| | } |
| | } |
} | | } |
| | |
void check_doors(object *op, int x, int y) { | | void check_doors(object *op, int x, int y) { |
object *tmp; | | object *tmp; |
tmp = get_map_ob(op->map, x, y); | | for (tmp = get_map_ob(op->map, x, y); tmp!=NULL; tmp=tmp->above) { |
if (tmp!= NULL) | | if (tmp->type == DOOR) { |
while(tmp->above != NULL) | | |
tmp=tmp->above; | | |
if (tmp!= NULL && tmp->type == DOOR) | | |
hit_player(tmp,1000,op,AT_PHYSICAL); | | hit_player(tmp,1000,op,AT_PHYSICAL); |
| | return; |
} | | } |
| | |
/* | | |
* move_object() tries to move object op in the direction "dir". | | |
* If it fails (something blocks the passage), it returns 0, | | |
* otherwise 1. | | |
* This is an improvement from the previous move_ob(), which | | |
* removed and inserted objects even if they were unable to move. | | |
*/ | | |
| | |
int move_object(object *op, int dir) { | | |
int newx = op->x+freearr_x[dir]; | | |
int newy = op->y+freearr_y[dir]; | | |
object *tmp; | | |
| | |
/* 0.94.2 - we need to set the direction for the new animation code. | | |
* it uses it to figure out face to use - I can't see it | | |
* breaking anything, but it might. | | |
*/ | | |
op->direction = dir; | | |
if(blocked_link(op, newx, newy)) /* Not all features from blocked_two yet */ | | |
return 0; /* (Not efficient enough yet) */ | | |
if(op->more != NULL && !move_object(op->more, dir)) | | |
return 0; | | |
if(op->will_apply&4) | | |
check_earthwalls(op,newx,newy); | | |
if(op->will_apply&8) | | |
check_doors(op,newx,newy); | | |
| | |
/* 0.94.1 - I got a stack trace that showed it crash with remove_ob trying | | |
* to remove a removed object, and this function was the culprit. A possible | | |
* guess I have is that check_doors above ran into a trap, killing the | | |
* monster. | | |
* | | |
* Unfortunately, it doesn't appear that the calling functions of move_object | | |
* deal very well with op being killed, so all this might do is just | | |
* migrate the problem someplace else. | | |
*/ | | |
| | |
if (QUERY_FLAG(op, FLAG_REMOVED)) { | | |
LOG(llevDebug,"move_object: monster has been removed - will not process further\n"); | | |
/* Was not successful, but don't want to try and move again */ | | |
return 1; | | |
} | | } |
if(op->head) | | |
return 1; | | |
| | |
remove_ob(op); | | |
| | |
for(tmp = op; tmp != NULL; tmp = tmp->more) | | |
tmp->x+=freearr_x[dir], tmp->y+=freearr_y[dir]; | | |
| | |
insert_ob_in_map(op, op->map, op,0); | | |
return 1; | | |
} | | } |
| | |
static void free_messages(msglang *msgs) { | | static void free_messages(msglang *msgs) { |