version 1.61 | | version 1.62 |
---|
| | |
/* | | /* |
* static char *rcsid_object_c = | | * static char *rcsid_object_c = |
* "$Id: object.c,v 1.61 2002/12/25 06:45:46 garbled Exp $"; | | * "$Id: object.c,v 1.62 2003/01/08 08:39:17 mwedel Exp $"; |
*/ | | */ |
| | |
/* | | /* |
| | |
int freedir[SIZEOFFREE]= { | | int freedir[SIZEOFFREE]= { |
0,1,2,3,4,5,6,7,8,1,2,2,2,3,4,4,4,5,6,6,6,7,8,8,8, | | 0,1,2,3,4,5,6,7,8,1,2,2,2,3,4,4,4,5,6,6,6,7,8,8,8, |
1,2,2,2,2,2,3,4,4,4,4,4,5,6,6,6,6,6,7,8,8,8,8,8}; | | 1,2,2,2,2,2,3,4,4,4,4,4,5,6,6,6,6,6,7,8,8,8,8,8}; |
int rightof_x[9]= {0, 1, -1, 0, -1, -1, 1, 0, 1}; | | |
int rightof_y[9]= {0, 0, -1, -1, 1, 0, 1, 1, -1}; | | |
int leftof_x[9] = {0, -1, 1, 0, 1, 1, -1, 0, -1}; | | |
int leftof_y[9] = {0, 0, 1, 1, -1, 0, -1, -1, 1}; | | |
| | |
/* Moved this out of define.h and in here, since this is the only file | | /* Moved this out of define.h and in here, since this is the only file |
* it is used in. Also, make it an inline function for cleaner | | * it is used in. Also, make it an inline function for cleaner |
| | |
} | | } |
if (ob->inv) { | | if (ob->inv) { |
if (ob->map==NULL || ob->map->in_memory!=MAP_IN_MEMORY || | | if (ob->map==NULL || ob->map->in_memory!=MAP_IN_MEMORY || |
wall(ob->map,ob->x,ob->y)) | | (get_map_flags(ob->map, NULL, ob->x, ob->y, NULL, NULL) & P_NO_PASS)) |
{ | | { |
op=ob->inv; | | op=ob->inv; |
while(op!=NULL) { | | while(op!=NULL) { |
| | |
op=tmp; | | op=tmp; |
} | | } |
} | | } |
else { | | else { /* Put objects in inventory onto this space */ |
op=ob->inv; | | op=ob->inv; |
while(op!=NULL) { | | while(op!=NULL) { |
tmp=op->below; | | tmp=op->below; |
| | |
op->type==RUNE) | | op->type==RUNE) |
free_object(op); | | free_object(op); |
else { | | else { |
op->x=ob->x,op->y=ob->y; | | op->x=ob->x; |
| | op->y=ob->y; |
insert_ob_in_map(op,ob->map,NULL,0); /* Insert in same map as the envir */ | | insert_ob_in_map(op,ob->map,NULL,0); /* Insert in same map as the envir */ |
} | | } |
op=tmp; | | op=tmp; |
| | |
| | |
SET_FLAG(ob, FLAG_FREED); | | SET_FLAG(ob, FLAG_FREED); |
ob->count = 0; | | ob->count = 0; |
/* First free the object from the used objects list: */ | | |
| | /* Remove this object from the list of used objects */ |
if(ob->prev==NULL) { | | if(ob->prev==NULL) { |
objects=ob->next; | | objects=ob->next; |
if(objects!=NULL) | | if(objects!=NULL) |
| | |
ob->next->prev=ob->prev; | | ob->next->prev=ob->prev; |
} | | } |
| | |
if(ob->name!=NULL) { | | if(ob->name!=NULL) FREE_AND_CLEAR_STR(ob->name); |
free_string(ob->name); | | if(ob->name_pl!=NULL) FREE_AND_CLEAR_STR(ob->name_pl); |
ob->name=NULL; | | if(ob->title!=NULL) FREE_AND_CLEAR_STR(ob->title); |
} | | if(ob->race!=NULL) FREE_AND_CLEAR_STR(ob->race); |
if(ob->name_pl!=NULL) { | | if(ob->slaying!=NULL) FREE_AND_CLEAR_STR(ob->slaying); |
free_string(ob->name_pl); | | if(ob->msg!=NULL) FREE_AND_CLEAR_STR(ob->msg); |
ob->name_pl=NULL; | | |
} | | |
if(ob->title!=NULL) { | | |
free_string(ob->title); | | |
ob->title=NULL; | | |
} | | |
if(ob->race!=NULL) { | | |
free_string(ob->race); | | |
ob->race=NULL; | | |
} | | |
if(ob->slaying!=NULL) { | | |
free_string(ob->slaying); | | |
ob->slaying=NULL; | | |
} | | |
if(ob->msg!=NULL) { | | |
free_string(ob->msg); | | |
ob->msg=NULL; | | |
} | | |
| | |
#if 0 /* MEMORY_DEBUG*/ | | #if 0 /* MEMORY_DEBUG*/ |
/* This is a nice idea. Unfortunately, a lot of the code in crossfire | | /* This is a nice idea. Unfortunately, a lot of the code in crossfire |
| | |
*/ | | */ |
free(ob); | | free(ob); |
#else | | #else |
| | |
/* Now link it with the free_objects list: */ | | /* Now link it with the free_objects list: */ |
ob->prev=NULL; | | ob->prev=NULL; |
ob->next=free_objects; | | ob->next=free_objects; |
| | |
free_objects=ob; | | free_objects=ob; |
nroffreeobjects++; | | nroffreeobjects++; |
#endif | | #endif |
| | |
} | | } |
| | |
/* | | /* |
| | |
x = op->x; | | x = op->x; |
y = op->y; | | y = op->y; |
op->map=get_map_from_coord(m, &x, &y); | | op->map=get_map_from_coord(m, &x, &y); |
/* Ideally, the caller figures this out */ | | /* Ideally, the caller figures this out. However, it complicates a lot |
| | * of areas of callers (eg, anything that uses find_free_spot would now |
| | * need extra work |
| | */ |
if (op->map != m) { | | if (op->map != m) { |
/* coordinates should not change unless map also changes */ | | /* coordinates should not change unless map also changes */ |
op->x = x; | | op->x = x; |
op->y = y; | | op->y = y; |
#if 0 | | |
LOG(llevDebug,"insert_ob_in_map not called with proper tiled map: %s != %s, orig coord = %d, %d\n", | | |
op->map->path, m->path, op->ox, op->oy); | | |
#endif | | |
} | | } |
| | |
CLEAR_FLAG(op,FLAG_APPLIED); /* hack for fixing F_APPLIED in items of dead people */ | | CLEAR_FLAG(op,FLAG_APPLIED); /* hack for fixing F_APPLIED in items of dead people */ |
| | |
* Need to find the object that in fact blocks view, otherwise | | * Need to find the object that in fact blocks view, otherwise |
* stacking is a bit odd. | | * stacking is a bit odd. |
*/ | | */ |
if (!(flag & INS_ON_TOP) && blocks_view(op->map, op->x, op->y) && | | if (!(flag & INS_ON_TOP) && |
| | (get_map_flags(op->map, NULL, op->x, op->y, NULL, NULL) & P_BLOCKSVIEW) && |
(op->face && !op->face->visibility)) { | | (op->face && !op->face->visibility)) { |
for (last=top; last != floor; last=last->below) | | for (last=top; last != floor; last=last->below) |
if QUERY_FLAG(last, FLAG_BLOCKSVIEW) break; | | if QUERY_FLAG(last, FLAG_BLOCKSVIEW) break; |
| | |
* Note - this only checks to see if there is space for the head of the | | * Note - this only checks to see if there is space for the head of the |
* object - if it is a multispace object, this should be called for all | | * object - if it is a multispace object, this should be called for all |
* pieces. | | * pieces. |
| | * Note2: This function does correctly handle tiled maps, but does not |
| | * inform the caller. However, insert_ob_in_map will update as |
| | * necessary, so the caller shouldn't need to do any special work. |
*/ | | */ |
| | |
int find_free_spot(archetype *at, mapstruct *m,int x,int y,int start,int stop) { | | int find_free_spot(archetype *at, mapstruct *m,int x,int y,int start,int stop) { |
int i,index=0; | | int i,index=0, flag; |
static int altern[SIZEOFFREE]; | | static int altern[SIZEOFFREE]; |
| | |
for(i=start;i<stop;i++) { | | for(i=start;i<stop;i++) { |
/* Surprised the out_of_map check was missing. Without it, we may | | flag = arch_blocked(at,m,x+freearr_x[i],y+freearr_y[i]); |
* end up accessing garbage, which may say a space is free | | if(!flag) |
*/ | | |
if (arch_out_of_map(at, m, x+freearr_x[i],y+freearr_y[i])) continue; | | |
if(!arch_blocked(at,m,x+freearr_x[i],y+freearr_y[i])) | | |
altern[index++]=i; | | altern[index++]=i; |
else if(wall(m,x+freearr_x[i],y+freearr_y[i])&&maxfree[i]<stop) | | /* Basically, if we find a wall on a space, we cut down the search size. |
| | * In this way, we won't return spaces that are on another side of a wall. |
| | * This mostly work, but it cuts down the search size in all directions - |
| | * if the space being examined only has a wall to the north and empty |
| | * spaces in all the other directions, this will reduce the search space |
| | * to only the spaces immediately surrounding the target area, and |
| | * won't look 2 spaces south of the target space. |
| | */ |
| | else if ((flag & P_NO_PASS) && maxfree[i]<stop) |
stop=maxfree[i]; | | stop=maxfree[i]; |
} | | } |
if(!index) return -1; | | if(!index) return -1; |
| | |
int find_first_free_spot(archetype *at, mapstruct *m,int x,int y) { | | int find_first_free_spot(archetype *at, mapstruct *m,int x,int y) { |
int i; | | int i; |
for(i=0;i<SIZEOFFREE;i++) { | | for(i=0;i<SIZEOFFREE;i++) { |
if (out_of_map(m,x+freearr_x[i],y+freearr_y[i])) continue; | | |
if(!arch_blocked(at,m,x+freearr_x[i],y+freearr_y[i])) | | if(!arch_blocked(at,m,x+freearr_x[i],y+freearr_y[i])) |
return i; | | return i; |
} | | } |
| | |
/* | | /* |
* find_dir(map, x, y, exclude) will search some close squares in the | | * find_dir(map, x, y, exclude) will search some close squares in the |
* given map at the given coordinates for live objects. | | * given map at the given coordinates for live objects. |
* It will not considered the object given as exlude among possible | | * It will not considered the object given as exclude among possible |
* live objects. | | * live objects. |
* It returns the direction toward the first/closest live object if finds | | * It returns the direction toward the first/closest live object if finds |
* any, otherwise 0. | | * any, otherwise 0. |
*/ | | */ |
| | |
int find_dir(mapstruct *m, int x, int y, object *exclude) { | | int find_dir(mapstruct *m, int x, int y, object *exclude) { |
int i,max=SIZEOFFREE; | | int i,max=SIZEOFFREE, mflags; |
| | sint16 nx, ny; |
object *tmp; | | object *tmp; |
| | mapstruct *mp; |
| | |
if (exclude && exclude->head) | | if (exclude && exclude->head) |
exclude = exclude->head; | | exclude = exclude->head; |
| | |
for(i=1;i<max;i++) { | | for(i=1;i<max;i++) { |
if(wall(m, x+freearr_x[i],y+freearr_y[i])) | | mp = m; |
| | nx = x + freearr_x[i]; |
| | ny = y + freearr_y[i]; |
| | |
| | mflags = get_map_flags(m, &mp, nx, ny, &nx, &ny); |
| | |
| | if (mflags & P_WALL) |
max=maxfree[i]; | | max=maxfree[i]; |
else { | | else if (mflags & P_IS_ALIVE) { |
tmp=GET_MAP_OB(m,x+freearr_x[i],y+freearr_y[i]); | | for (tmp=GET_MAP_OB(mp,nx,ny); tmp!= NULL; tmp=tmp->above) { |
while(tmp!=NULL && ((tmp!=NULL&&!QUERY_FLAG(tmp,FLAG_MONSTER)&& | | if ((QUERY_FLAG(tmp,FLAG_MONSTER) || tmp->type==PLAYER) && |
tmp->type!=PLAYER) || (tmp == exclude || | | (tmp != exclude ||(tmp->head && tmp->head != exclude))) break; |
(tmp->head && tmp->head == exclude)))) | | } |
tmp=tmp->above; | | if(tmp) |
if(tmp!=NULL) | | |
return freedir[i]; | | return freedir[i]; |
} | | } |
} | | } |