/*==========================================
* Move bl and do func* with va_list while moving.
* Movement is set by dx dy which are distance in x and y
*------------------------------------------*/
int map_foreachinmovearea(int (*func)(struct block_list*,va_list), struct block_list* center, int16 range, int16 dx, int16 dy, int type, ...)
{
int bx, by, m;
int returnCount = 0; //total sum of returned values of func() [Skotlex]
struct block_list *bl;
int blockcount = bl_list_count, i;
int16 x0, x1, y0, y1;
va_list ap;
if ( !range ) return 0;
if ( !dx && !dy ) return 0; //No movement.
m = center->m;
struct map_data *mapdata = map_getmapdata(m);
x0 = center->x - range;
x1 = center->x + range;
y0 = center->y - range;
y1 = center->y + range;
if ( x1 < x0 )
SWAP(x0, x1);
if ( y1 < y0 )
SWAP(y0, y1);
if( dx == 0 || dy == 0 ) {
//Movement along one axis only.
if( dx == 0 ){
if( dy < 0 ) //Moving south
y0 = y1 + dy + 1;
else //North
y1 = y0 + dy - 1;
} else { //dy == 0
if( dx < 0 ) //West
x0 = x1 + dx + 1;
else //East
x1 = x0 + dx - 1;
}
x0 = i16max(x0, 0);
y0 = i16max(y0, 0);
x1 = i16min(x1, mapdata->xs - 1);
y1 = i16min(y1, mapdata->ys - 1);
for( by = y0 / BLOCK_SIZE; by <= y1 / BLOCK_SIZE; by++ ) {
for( bx = x0 / BLOCK_SIZE; bx <= x1 / BLOCK_SIZE; bx++ ) {
if ( type&~BL_MOB ) {
for( bl = mapdata->block[ bx + by * mapdata->bxs ]; bl != NULL; bl = bl->next ) {
if( bl->type&type &&
bl->x >= x0 && bl->x <= x1 &&
bl->y >= y0 && bl->y <= y1 &&
bl_list_count < BL_LIST_MAX )
bl_list[ bl_list_count++ ] = bl;
}
}
if ( type&BL_MOB ) {
for( bl = mapdata->block_mob[ bx + by * mapdata->bxs ]; bl != NULL; bl = bl->next ) {
if( bl->x >= x0 && bl->x <= x1 &&
bl->y >= y0 && bl->y <= y1 &&
bl_list_count < BL_LIST_MAX )
bl_list[ bl_list_count++ ] = bl;
}
}
}
}
} else { // Diagonal movement
x0 = i16max(x0, 0);
y0 = i16max(y0, 0);
x1 = i16min(x1, mapdata->xs - 1);
y1 = i16min(y1, mapdata->ys - 1);
for( by = y0 / BLOCK_SIZE; by <= y1 / BLOCK_SIZE; by++ ) {
for( bx = x0 / BLOCK_SIZE; bx <= x1 / BLOCK_SIZE; bx++ ) {
if ( type & ~BL_MOB ) {
for( bl = mapdata->block[ bx + by * mapdata->bxs ]; bl != NULL; bl = bl->next ) {
if( bl->type&type &&
bl->x >= x0 && bl->x <= x1 &&
bl->y >= y0 && bl->y <= y1 &&
bl_list_count < BL_LIST_MAX )
if( ( dx > 0 && bl->x < x0 + dx) ||
( dx < 0 && bl->x > x1 + dx) ||
( dy > 0 && bl->y < y0 + dy) ||
( dy < 0 && bl->y > y1 + dy) )
bl_list[ bl_list_count++ ] = bl;
}
}
if ( type&BL_MOB ) {
for( bl = mapdata->block_mob[ bx + by * mapdata->bxs ]; bl != NULL; bl = bl->next ) {
if( bl->x >= x0 && bl->x <= x1 &&
bl->y >= y0 && bl->y <= y1 &&
bl_list_count < BL_LIST_MAX)
if( ( dx > 0 && bl->x < x0 + dx) ||
( dx < 0 && bl->x > x1 + dx) ||
( dy > 0 && bl->y < y0 + dy) ||
( dy < 0 && bl->y > y1 + dy) )
bl_list[ bl_list_count++ ] = bl;
}
}
}
}
}
if( bl_list_count >= BL_LIST_MAX )
ShowWarning("map_foreachinmovearea: block count too many!\n");
map_freeblock_lock(); // Prohibit the release from memory
for( i = blockcount; i < bl_list_count; i++ )
if( bl_list[ i ]->prev ) { //func() may delete this bl_list[] slot, checking for prev ensures it wasn't queued for deletion.
va_start(ap, type);
returnCount += func(bl_list[ i ], ap);
va_end(ap);
}
map_freeblock_unlock(); // Allow Free
bl_list_count = blockcount;
return returnCount;
}