summaryrefslogtreecommitdiff
path: root/src/map/map.c
diff options
context:
space:
mode:
authorMichieru <Michieru@users.noreply.github.com>2014-11-03 11:46:22 +0100
committerMichieru <Michieru@users.noreply.github.com>2014-11-03 11:46:22 +0100
commitb8abf962fd079bc3cad4498aa968f2318d1f5fde (patch)
tree941b9d312ded4e3b75360febb73922a79637c10c /src/map/map.c
parent1c76a4249ea878bd133c16a7e8b799d51b7e8594 (diff)
downloadhercules-b8abf962fd079bc3cad4498aa968f2318d1f5fde.tar.gz
hercules-b8abf962fd079bc3cad4498aa968f2318d1f5fde.tar.bz2
hercules-b8abf962fd079bc3cad4498aa968f2318d1f5fde.tar.xz
hercules-b8abf962fd079bc3cad4498aa968f2318d1f5fde.zip
* No cell stacking implemented (official version)
- Split config cell_stack_limit into custom_cell_stack_limit (previous feature) and official_cell_stack_limit (see below) - Expanded map_count_oncell by a flag parameter, currently only one flag is supported: only count standing units (needed for official cell stack feature) - Added a new function map_closest_freecell that will return the closest free cell using the same order that official servers use - Monsters will now actively search for a free cell when starting to walk randomly and when unlocking target - When any unit finishes walking (regularly) and is not on a free cell, it will now actively search for a free cell - Step actions will be delayed until a suitable cell was found, they will even be executed when the player walked slightly out of attack range - Monsters will now stop instantly if their target is completely non-existent * This is mainly for looters that had their loot taken * Hide and most other situations still use the configuration setting monster_chase_refresh Mega Thanks to Playtester
Diffstat (limited to 'src/map/map.c')
-rw-r--r--src/map/map.c114
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