diff options
Diffstat (limited to 'src/map/map.c')
-rw-r--r-- | src/map/map.c | 114 |
1 files changed, 105 insertions, 9 deletions
diff --git a/src/map/map.c b/src/map/map.c index bb3b17822..b3efe7c57 100644 --- a/src/map/map.c +++ b/src/map/map.c @@ -395,9 +395,11 @@ int map_moveblock(struct block_list *bl, int x1, int y1, int64 tick) { /*========================================== * Counts specified number of objects on given cell. + * flag:
+ * 0x1 - only count standing units * TODO: merge with bl_getall_area *------------------------------------------*/ -int map_count_oncell(int16 m, int16 x, int16 y, int type) { +int map_count_oncell(int16 m, int16 x, int16 y, int type, int flag) { int bx,by; struct block_list *bl; int count = 0; @@ -410,13 +412,27 @@ int map_count_oncell(int16 m, int16 x, int16 y, int type) { if (type&~BL_MOB) for( bl = map->list[m].block[bx+by*map->list[m].bxs] ; bl != NULL ; bl = bl->next ) - if(bl->x == x && bl->y == y && bl->type&type) - count++; + if(bl->x == x && bl->y == y && bl->type&type) {
+ if(flag&1) {
+ struct unit_data *ud = unit->bl2ud(bl);
+ if(!ud || ud->walktimer == INVALID_TIMER)
+ count++;
+ } else {
+ count++;
+ }
+ } if (type&BL_MOB) for( bl = map->list[m].block_mob[bx+by*map->list[m].bxs] ; bl != NULL ; bl = bl->next ) - if(bl->x == x && bl->y == y) - count++; + if(bl->x == x && bl->y == y) {
+ if(flag&1) {
+ struct unit_data *ud = unit->bl2ud(bl);
+ if(!ud || ud->walktimer == INVALID_TIMER)
+ count++;
+ } else {
+ count++;
+ }
+ } return count; } @@ -1379,7 +1395,7 @@ int map_searchrandfreecell(int16 m,int16 *x,int16 *y,int stack) { if(map->getcell(m,j+*x,i+*y,CELL_CHKNOPASS) && !map->getcell(m,j+*x,i+*y,CELL_CHKICEWALL)) continue; //Avoid item stacking to prevent against exploits. [Skotlex] - if(stack && map->count_oncell(m,j+*x,i+*y, BL_ITEM) > stack) + if(stack && map->count_oncell(m,j+*x,i+*y, BL_ITEM, 0) > stack) continue; free_cells[free_cell][0] = j+*x; free_cells[free_cell++][1] = i+*y; @@ -1472,6 +1488,85 @@ int map_search_freecell(struct block_list *src, int16 m, int16 *x,int16 *y, int1 return 0; } +/*==========================================
+ * Locates the closest, walkable cell with no blocks of a certain type on it
+ * Returns true on success and sets x and y to cell found.
+ * Otherwise returns false and x and y are not changed.
+ * type: Types of block to count
+ * flag:
+ * 0x1 - only count standing units
+ *------------------------------------------*/
+bool map_closest_freecell(int16 m, int16 *x, int16 *y, int type, int flag)
+{
+ uint8 dir = 6;
+ int16 tx = *x;
+ int16 ty = *y;
+ int costrange = 10;
+
+ if(!map->count_oncell(m, tx, ty, type, flag))
+ return true; //Current cell is free
+
+ //Algorithm only works up to costrange of 34
+ while(costrange <= 34) {
+ short dx = dirx[dir];
+ short dy = diry[dir];
+
+ //Linear search
+ if(dir%2 == 0 && costrange%MOVE_COST == 0) {
+ tx = *x+dx*(costrange/MOVE_COST);
+ ty = *y+dy*(costrange/MOVE_COST);
+ if(!map->count_oncell(m, tx, ty, type, flag) && map->getcell(m,tx,ty,CELL_CHKPASS)) {
+ *x = tx;
+ *y = ty;
+ return true;
+ }
+ }
+ //Full diagonal search
+ else if(dir%2 == 1 && costrange%MOVE_DIAGONAL_COST == 0) {
+ tx = *x+dx*(costrange/MOVE_DIAGONAL_COST);
+ ty = *y+dy*(costrange/MOVE_DIAGONAL_COST);
+ if(!map->count_oncell(m, tx, ty, type, flag) && map->getcell(m,tx,ty,CELL_CHKPASS)) {
+ *x = tx;
+ *y = ty;
+ return true;
+ }
+ }
+ //One cell diagonal, rest linear (TODO: Find a better algorithm for this)
+ else if(dir%2 == 1 && costrange%MOVE_COST == 4) {
+ tx = *x+dx*((dir%4==3)?(costrange/MOVE_COST):1);
+ ty = *y+dy*((dir%4==1)?(costrange/MOVE_COST):1);
+ if(!map->count_oncell(m, tx, ty, type, flag) && map->getcell(m,tx,ty,CELL_CHKPASS)) {
+ *x = tx;
+ *y = ty;
+ return true;
+ }
+ tx = *x+dx*((dir%4==1)?(costrange/MOVE_COST):1);
+ ty = *y+dy*((dir%4==3)?(costrange/MOVE_COST):1);
+ if(!map->count_oncell(m, tx, ty, type, flag) && map->getcell(m,tx,ty,CELL_CHKPASS)) {
+ *x = tx;
+ *y = ty;
+ return true;
+ }
+ }
+
+ //Get next direction
+ if (dir == 5) {
+ //Diagonal search complete, repeat with higher cost range
+ if(costrange == 14) costrange += 6;
+ else if(costrange == 28 || costrange >= 38) costrange += 2;
+ else costrange += 4;
+ dir = 6;
+ } else if (dir == 4) {
+ //Linear search complete, switch to diagonal directions
+ dir = 7;
+ } else {
+ dir = (dir+2)%8;
+ }
+ }
+
+ return false;
+} + /*========================================== * Add an item to location (m,x,y) * Parameters @@ -2592,21 +2687,21 @@ int map_getcellp(struct map_data* m,int16 x,int16 y,cell_chk cellchk) { // special checks case CELL_CHKPASS: #ifdef CELL_NOSTACK - if (cell.cell_bl >= battle_config.cell_stack_limit) return 0; + if (cell.cell_bl >= battle_config.custom_cell_stack_limit) return 0; #endif case CELL_CHKREACH: return (cell.walkable); case CELL_CHKNOPASS: #ifdef CELL_NOSTACK - if (cell.cell_bl >= battle_config.cell_stack_limit) return 1; + if (cell.cell_bl >= battle_config.custom_cell_stack_limit) return 1; #endif case CELL_CHKNOREACH: return (!cell.walkable); case CELL_CHKSTACK: #ifdef CELL_NOSTACK - return (cell.cell_bl >= battle_config.cell_stack_limit); + return (cell.cell_bl >= battle_config.custom_cell_stack_limit); #else return 0; #endif @@ -6000,6 +6095,7 @@ void map_defaults(void) { // search and creation map->get_new_object_id = map_get_new_object_id; map->search_freecell = map_search_freecell; + map->closest_freecell = map_closest_freecell; // map->quit = map_quit; // npc |