diff options
Diffstat (limited to 'src/map/map.c')
-rw-r--r-- | src/map/map.c | 2098 |
1 files changed, 1341 insertions, 757 deletions
diff --git a/src/map/map.c b/src/map/map.c index 3a7d752c3..40e66e4df 100644 --- a/src/map/map.c +++ b/src/map/map.c @@ -2,8 +2,8 @@ * This file is part of Hercules. * http://herc.ws - http://github.com/HerculesWS/Hercules * - * Copyright (C) 2012-2015 Hercules Dev Team - * Copyright (C) Athena Dev Teams + * Copyright (C) 2012-2020 Hercules Dev Team + * Copyright (C) Athena Dev Teams * * Hercules is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -30,6 +30,7 @@ #include "map/channel.h" #include "map/chat.h" #include "map/chrif.h" +#include "map/clan.h" #include "map/clif.h" #include "map/duel.h" #include "map/elemental.h" @@ -44,7 +45,6 @@ #include "map/mapreg.h" #include "map/mercenary.h" #include "map/mob.h" -#include "map/npc.h" #include "map/npc.h" // npc_setcells(), npc_unsetcells() #include "map/party.h" #include "map/path.h" @@ -55,8 +55,12 @@ #include "map/skill.h" #include "map/status.h" #include "map/storage.h" +#include "map/stylist.h" +#include "map/rodex.h" +#include "map/refine.h" #include "map/trade.h" #include "map/unit.h" +#include "map/achievement.h" #include "common/HPM.h" #include "common/cbasetypes.h" #include "common/conf.h" @@ -64,6 +68,7 @@ #include "common/core.h" #include "common/ers.h" #include "common/grfio.h" +#include "common/md5calc.h" #include "common/memmgr.h" #include "common/nullpo.h" #include "common/random.h" @@ -79,12 +84,13 @@ #include <stdio.h> #include <stdlib.h> #include <string.h> +#include <sys/stat.h> #ifndef _WIN32 #include <unistd.h> #endif -struct map_interface map_s; -struct mapit_interface mapit_s; +static struct map_interface map_s; +static struct mapit_interface mapit_s; struct map_interface *map; struct mapit_interface *mapit; @@ -92,18 +98,21 @@ struct mapit_interface *mapit; /*========================================== * server player count (of all mapservers) *------------------------------------------*/ -void map_setusers(int users) { +static void map_setusers(int users) +{ map->users = users; } -int map_getusers(void) { +static int map_getusers(void) +{ return map->users; } /** * Expands map->bl_list on demand **/ -static inline void map_bl_list_expand(void) { +static inline void map_bl_list_expand(void) +{ map->bl_list_size += 250; RECREATE(map->bl_list, struct block_list *, map->bl_list_size); } @@ -111,7 +120,8 @@ static inline void map_bl_list_expand(void) { /** * Expands map->block_free on demand **/ -static inline void map_block_free_expand(void) { +static inline void map_block_free_expand(void) +{ map->block_free_list_size += 100; RECREATE(map->block_free, struct block_list *, map->block_free_list_size); } @@ -119,14 +129,16 @@ static inline void map_block_free_expand(void) { /*========================================== * server player count (this mapserver only) *------------------------------------------*/ -int map_usercount(void) { +static int map_usercount(void) +{ return db_size(map->pc_db); } /*========================================== * Attempt to free a map blocklist *------------------------------------------*/ -int map_freeblock (struct block_list *bl) { +static int map_freeblock(struct block_list *bl) +{ nullpo_retr(map->block_free_lock, bl); if (map->block_free_lock == 0) { @@ -147,14 +159,16 @@ int map_freeblock (struct block_list *bl) { /*========================================== * Lock blocklist, (prevent map->freeblock usage) *------------------------------------------*/ -int map_freeblock_lock (void) { +static int map_freeblock_lock(void) +{ return ++map->block_free_lock; } /*========================================== * Remove the lock on map_bl *------------------------------------------*/ -int map_freeblock_unlock (void) { +static int map_freeblock_unlock(void) +{ if ((--map->block_free_lock) == 0) { int i; for (i = 0; i < map->block_free_count; i++) { @@ -175,7 +189,8 @@ int map_freeblock_unlock (void) { // Timer function to check if there some remaining lock and remove them if so. // Called each 1s -int map_freeblock_timer(int tid, int64 tick, int id, intptr_t data) { +static int map_freeblock_timer(int tid, int64 tick, int id, intptr_t data) +{ if (map->block_free_lock > 0) { ShowError("map_freeblock_timer: block_free_lock(%d) is invalid.\n", map->block_free_lock); map->block_free_lock = 1; @@ -189,7 +204,8 @@ int map_freeblock_timer(int tid, int64 tick, int id, intptr_t data) { * Updates the counter (cell.cell_bl) of how many objects are on a tile. * @param add Whether the counter should be increased or decreased **/ -void map_update_cell_bl( struct block_list *bl, bool increase ) { +static void map_update_cell_bl(struct block_list *bl, bool increase) +{ #ifdef CELL_NOSTACK int pos; @@ -218,7 +234,7 @@ void map_update_cell_bl( struct block_list *bl, bool increase ) { * Adds a block to the map. * Returns 0 on success, 1 on failure (illegal coordinates). *------------------------------------------*/ -int map_addblock(struct block_list* bl) +static int map_addblock(struct block_list *bl) { int16 m, x, y; int pos; @@ -266,7 +282,7 @@ int map_addblock(struct block_list* bl) /*========================================== * Removes a block from the map. *------------------------------------------*/ -int map_delblock(struct block_list* bl) +static int map_delblock(struct block_list *bl) { int pos; nullpo_ret(bl); @@ -309,7 +325,8 @@ int map_delblock(struct block_list* bl) * Pass flag as 1 to prevent doing skill->unit_move checks * (which are executed by default on BL_CHAR types) *------------------------------------------*/ -int map_moveblock(struct block_list *bl, int x1, int y1, int64 tick) { +static int map_moveblock(struct block_list *bl, int x1, int y1, int64 tick) +{ struct status_change *sc = NULL; int x0, y0; int moveblock; @@ -336,6 +353,7 @@ int map_moveblock(struct block_list *bl, int x1, int y1, int64 tick) { //status_change_end(bl, SC_BLADESTOP, INVALID_TIMER); //Won't stop when you are knocked away, go figure... status_change_end(bl, SC_NJ_TATAMIGAESHI, INVALID_TIMER); status_change_end(bl, SC_MAGICROD, INVALID_TIMER); + status_change_end(bl, SC_SU_STOOP, INVALID_TIMER); if (sc && sc->data[SC_PROPERTYWALK] && sc->data[SC_PROPERTYWALK]->val3 >= skill->get_maxcount(sc->data[SC_PROPERTYWALK]->val1,sc->data[SC_PROPERTYWALK]->val2) ) status_change_end(bl,SC_PROPERTYWALK,INVALID_TIMER); @@ -426,7 +444,8 @@ int map_moveblock(struct block_list *bl, int x1, int y1, int64 tick) { * 0x2 - don't count invinsible units * TODO: merge with bl_getall_area *------------------------------------------*/ -int map_count_oncell(int16 m, int16 x, int16 y, int type, int flag) { +static int map_count_oncell(int16 m, int16 x, int16 y, int type, int flag) +{ int bx,by; struct block_list *bl; int count = 0; @@ -444,6 +463,11 @@ int map_count_oncell(int16 m, int16 x, int16 y, int type, int flag) { struct status_change *sc = status->get_sc(bl); if (sc && (sc->option&OPTION_INVISIBLE)) continue; + if (bl->type == BL_NPC) { + const struct npc_data *nd = BL_UCCAST(BL_NPC, bl); + if (nd->class_ == FAKE_NPC || nd->class_ == HIDDEN_WARP_CLASS) + continue; + } } if (flag&0x1) { struct unit_data *ud = unit->bl2ud(bl); @@ -479,7 +503,8 @@ int map_count_oncell(int16 m, int16 x, int16 y, int type, int flag) { * Looks for a skill unit on a given cell * flag&1: runs battle_check_target check based on unit->group->target_flag */ -struct skill_unit* map_find_skill_unit_oncell(struct block_list* target,int16 x,int16 y,uint16 skill_id,struct skill_unit* out_unit, int flag) { +static struct skill_unit *map_find_skill_unit_oncell(struct block_list *target, int16 x, int16 y, uint16 skill_id, struct skill_unit *out_unit, int flag) +{ int16 m,bx,by; struct block_list *bl; struct skill_unit *su; @@ -506,10 +531,12 @@ struct skill_unit* map_find_skill_unit_oncell(struct block_list* target,int16 x, return NULL; } -/** @name Functions for block_list search and manipulation +/** + * @name Functions for block_list search and manipulation + * + * @{ */ -/* @{ */ /** * Applies func to every block_list in bl_list starting with bl_list[blockcount]. * Sets bl_list_count back to blockcount. @@ -520,7 +547,8 @@ struct skill_unit* map_find_skill_unit_oncell(struct block_list* target,int16 x, * @param args Extra arguments for func * @return Sum of the values returned by func */ -static int bl_vforeach(int (*func)(struct block_list*, va_list), int blockcount, int max, va_list args) { +static int bl_vforeach(int (*func)(struct block_list*, va_list), int blockcount, int max, va_list args) +{ int i; int returnCount = 0; @@ -549,7 +577,8 @@ static int bl_vforeach(int (*func)(struct block_list*, va_list), int blockcount, * @param args Extra arguments for func * @return Sum of the values returned by func */ -static int map_vforeachinmap(int (*func)(struct block_list*, va_list), int16 m, int type, va_list args) { +static int map_vforeachinmap(int (*func)(struct block_list*, va_list), int16 m, int type, va_list args) +{ int i; int returnCount = 0; int bsize; @@ -597,7 +626,8 @@ static int map_vforeachinmap(int (*func)(struct block_list*, va_list), int16 m, * @param ... Extra arguments for func * @return Sum of the values returned by func */ -int map_foreachinmap(int (*func)(struct block_list*, va_list), int16 m, int type, ...) { +static int map_foreachinmap(int (*func)(struct block_list*, va_list), int16 m, int type, ...) +{ int returnCount; va_list ap; @@ -608,6 +638,21 @@ int map_foreachinmap(int (*func)(struct block_list*, va_list), int16 m, int type return returnCount; } +static int map_forcountinmap(int (*func)(struct block_list*, va_list), int16 m, int count, int type, ...) +{ + int returnCount = 0; + va_list ap; + + if (m < 0) + return returnCount; + + va_start(ap, type); + returnCount = map->vforcountinarea(func, m, 0, 0, map->list[m].xs, map->list[m].ys, count, type, ap); + va_end(ap); + + return returnCount; +} + /** * Applies func to every block_list object of bl_type type on all maps * of instance instance_id. @@ -619,7 +664,8 @@ int map_foreachinmap(int (*func)(struct block_list*, va_list), int16 m, int type * @param ap Extra arguments for func * @return Sum of the values returned by func */ -int map_vforeachininstance(int (*func)(struct block_list*, va_list), int16 instance_id, int type, va_list ap) { +static int map_vforeachininstance(int (*func)(struct block_list*, va_list), int16 instance_id, int type, va_list ap) +{ int i; int returnCount = 0; @@ -645,7 +691,8 @@ int map_vforeachininstance(int (*func)(struct block_list*, va_list), int16 insta * @param ... Extra arguments for func * @return Sum of the values returned by func */ -int map_foreachininstance(int (*func)(struct block_list*, va_list), int16 instance_id, int type, ...) { +static int map_foreachininstance(int (*func)(struct block_list*, va_list), int16 instance_id, int type, ...) +{ int returnCount; va_list ap; @@ -665,7 +712,8 @@ int map_foreachininstance(int (*func)(struct block_list*, va_list), int16 instan * @param ... Extra arguments for func * @return Number of found objects */ -static int bl_getall_area(int type, int m, int x0, int y0, int x1, int y1, int (*func)(struct block_list*, va_list), ...) { +static int bl_getall_area(int type, int m, int x0, int y0, int x1, int y1, int (*func)(struct block_list*, va_list), ...) +{ va_list args; int bx, by; struct block_list *bl; @@ -683,49 +731,95 @@ static int bl_getall_area(int type, int m, int x0, int y0, int x1, int y1, int ( x1 = min(x1, map->list[m].xs - 1); y1 = min(y1, map->list[m].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 = map->list[m].block[bx + by * map->list[m].bxs]; bl != NULL; bl = bl->next) { - if (bl->type&type && bl->x >= x0 && bl->x <= x1 && bl->y >= y0 && bl->y <= y1) { - if( map->bl_list_count >= map->bl_list_size ) - map_bl_list_expand(); - if (func) { - va_start(args, func); - if (func(bl, args)) { + { + const int x0b = x0 / BLOCK_SIZE; + const int x1b = x1 / BLOCK_SIZE; + const int y0b = y0 / BLOCK_SIZE; + const int y1b = y1 / BLOCK_SIZE; + const struct map_data *const listm = &map->list[m]; + const int bxs0 = listm->bxs; + + // duplication for better performance + if (func != NULL) { + if (type & ~BL_MOB) { + for (by = y0b; by <= y1b; by++) { + const int bxs = by * bxs0; + for (bx = x0b; bx <= x1b; bx++) { + for (bl = listm->block[bx + bxs]; bl != NULL; bl = bl->next) { + const int x = bl->x; + const int y = bl->y; + if (bl->type & type && x >= x0 && x <= x1 && y >= y0 && y <= y1) { + va_start(args, func); + if (func(bl, args)) { + if (map->bl_list_count >= map->bl_list_size) + map_bl_list_expand(); + map->bl_list[map->bl_list_count++] = bl; + found++; + } + va_end(args); + } + } + } + } + } + if (type & BL_MOB) { + for (by = y0b; by <= y1b; by++) { + const int bxs = by * bxs0; + for (bx = x0b; bx <= x1b; bx++) { + for (bl = listm->block_mob[bx + bxs]; bl != NULL; bl = bl->next) { + const int x = bl->x; + const int y = bl->y; + if (x >= x0 && x <= x1 && y >= y0 && y <= y1) { + va_start(args, func); + if (func(bl, args)) { + if (map->bl_list_count >= map->bl_list_size) + map_bl_list_expand(); + map->bl_list[map->bl_list_count++] = bl; + found++; + } + va_end(args); + } + } + } + } + } + } else { // func != NULL + if (type & ~BL_MOB) { + for (by = y0b; by <= y1b; by++) { + const int bxs = by * bxs0; + for (bx = x0b; bx <= x1b; bx++) { + for (bl = listm->block[bx + bxs]; bl != NULL; bl = bl->next) { + const int x = bl->x; + const int y = bl->y; + if (bl->type & type && x >= x0 && x <= x1 && y >= y0 && y <= y1) { + if (map->bl_list_count >= map->bl_list_size) + map_bl_list_expand(); map->bl_list[map->bl_list_count++] = bl; found++; } - va_end(args); - } else { - map->bl_list[map->bl_list_count++] = bl; - found++; } } } } - if (type&BL_MOB) { // TODO: fix this code duplication - for (bl = map->list[m].block_mob[bx + by * map->list[m].bxs]; bl != NULL; bl = bl->next) { - if (bl->x >= x0 && bl->x <= x1 && bl->y >= y0 && bl->y <= y1) { - if( map->bl_list_count >= map->bl_list_size ) - map_bl_list_expand(); - if (func) { - va_start(args, func); - if (func(bl, args)) { + if (type & BL_MOB) { + for (by = y0b; by <= y1b; by++) { + const int bxs = by * bxs0; + for (bx = x0b; bx <= x1b; bx++) { + for (bl = listm->block_mob[bx + bxs]; bl != NULL; bl = bl->next) { + const int x = bl->x; + const int y = bl->y; + if (x >= x0 && x <= x1 && y >= y0 && y <= y1) { + if (map->bl_list_count >= map->bl_list_size) + map_bl_list_expand(); map->bl_list[map->bl_list_count++] = bl; found++; } - va_end(args); - } else { - map->bl_list[map->bl_list_count++] = bl; - found++; } } } } } } - return found; } @@ -757,7 +851,8 @@ static int bl_vgetall_inrange(struct block_list *bl, va_list args) * @param ap Extra arguments for func * @return Sum of the values returned by func */ -int map_vforeachinrange(int (*func)(struct block_list*, va_list), struct block_list* center, int16 range, int type, va_list ap) { +static int map_vforeachinrange(int (*func)(struct block_list*, va_list), struct block_list *center, int16 range, int type, va_list ap) +{ int returnCount = 0; int blockcount = map->bl_list_count; va_list apcopy; @@ -785,7 +880,8 @@ int map_vforeachinrange(int (*func)(struct block_list*, va_list), struct block_l * @param ... Extra arguments for func * @return Sum of the values returned by func */ -int map_foreachinrange(int (*func)(struct block_list*, va_list), struct block_list* center, int16 range, int type, ...) { +static int map_foreachinrange(int (*func)(struct block_list*, va_list), struct block_list *center, int16 range, int type, ...) +{ int returnCount; va_list ap; @@ -809,7 +905,8 @@ int map_foreachinrange(int (*func)(struct block_list*, va_list), struct block_li * @param ap Extra arguments for func * @return Sum of the values returned by func */ -int map_vforcountinrange(int (*func)(struct block_list*, va_list), struct block_list* center, int16 range, int count, int type, va_list ap) { +static int map_vforcountinrange(int (*func)(struct block_list*, va_list), struct block_list *center, int16 range, int count, int type, va_list ap) +{ int returnCount = 0; int blockcount = map->bl_list_count; va_list apcopy; @@ -839,7 +936,8 @@ int map_vforcountinrange(int (*func)(struct block_list*, va_list), struct block_ * @param ... Extra arguments for func * @return Sum of the values returned by func */ -int map_forcountinrange(int (*func)(struct block_list*, va_list), struct block_list* center, int16 range, int count, int type, ...) { +static int map_forcountinrange(int (*func)(struct block_list*, va_list), struct block_list *center, int16 range, int count, int type, ...) +{ int returnCount; va_list ap; @@ -885,7 +983,8 @@ static int bl_vgetall_inshootrange(struct block_list *bl, va_list args) * @param ap Extra arguments for func * @return Sum of the values returned by func */ -int map_vforeachinshootrange(int (*func)(struct block_list*, va_list), struct block_list* center, int16 range, int type, va_list ap) { +static int map_vforeachinshootrange(int (*func)(struct block_list*, va_list), struct block_list *center, int16 range, int type, va_list ap) +{ int returnCount = 0; int blockcount = map->bl_list_count; va_list apcopy; @@ -913,7 +1012,8 @@ int map_vforeachinshootrange(int (*func)(struct block_list*, va_list), struct bl * @param ... Extra arguments for func * @return Sum of the values returned by func */ -int map_foreachinshootrange(int (*func)(struct block_list*, va_list), struct block_list* center, int16 range, int type, ...) { +static int map_foreachinshootrange(int (*func)(struct block_list*, va_list), struct block_list *center, int16 range, int type, ...) +{ int returnCount; va_list ap; @@ -938,7 +1038,8 @@ int map_foreachinshootrange(int (*func)(struct block_list*, va_list), struct blo * @param ap Extra arguments for func * @return Sum of the values returned by func */ -int map_vforeachinarea(int (*func)(struct block_list*, va_list), int16 m, int16 x0, int16 y0, int16 x1, int16 y1, int type, va_list ap) { +static int map_vforeachinarea(int (*func)(struct block_list*, va_list), int16 m, int16 x0, int16 y0, int16 x1, int16 y1, int type, va_list ap) +{ int returnCount = 0; int blockcount = map->bl_list_count; va_list apcopy; @@ -967,7 +1068,8 @@ int map_vforeachinarea(int (*func)(struct block_list*, va_list), int16 m, int16 * @param ... Extra arguments for func * @return Sum of the values returned by func */ -int map_foreachinarea(int (*func)(struct block_list*, va_list), int16 m, int16 x0, int16 y0, int16 x1, int16 y1, int type, ...) { +static int map_foreachinarea(int (*func)(struct block_list*, va_list), int16 m, int16 x0, int16 y0, int16 x1, int16 y1, int type, ...) +{ int returnCount; va_list ap; @@ -994,7 +1096,8 @@ int map_foreachinarea(int (*func)(struct block_list*, va_list), int16 m, int16 x * @param ap Extra arguments for func * @return Sum of the values returned by func */ -int map_vforcountinarea(int (*func)(struct block_list*,va_list), int16 m, int16 x0, int16 y0, int16 x1, int16 y1, int count, int type, va_list ap) { +static int map_vforcountinarea(int (*func)(struct block_list*, va_list), int16 m, int16 x0, int16 y0, int16 x1, int16 y1, int count, int type, va_list ap) +{ int returnCount = 0; int blockcount = map->bl_list_count; va_list apcopy; @@ -1025,7 +1128,8 @@ int map_vforcountinarea(int (*func)(struct block_list*,va_list), int16 m, int16 * @param ... Extra arguments for func * @return Sum of the values returned by func */ -int map_forcountinarea(int (*func)(struct block_list*,va_list), int16 m, int16 x0, int16 y0, int16 x1, int16 y1, int count, int type, ...) { +static int map_forcountinarea(int (*func)(struct block_list*, va_list), int16 m, int16 x0, int16 y0, int16 x1, int16 y1, int count, int type, ...) +{ int returnCount; va_list ap; @@ -1082,7 +1186,8 @@ static int bl_vgetall_inmovearea(struct block_list *bl, va_list args) * @param ap Extra arguments for func * @return Sum of the values returned by func */ -int map_vforeachinmovearea(int (*func)(struct block_list*, va_list), struct block_list* center, int16 range, int16 dx, int16 dy, int type, va_list ap) { +static int map_vforeachinmovearea(int (*func)(struct block_list*, va_list), struct block_list *center, int16 range, int16 dx, int16 dy, int type, va_list ap) +{ int returnCount = 0; int blockcount = map->bl_list_count; int m, x0, x1, y0, y1; @@ -1140,7 +1245,8 @@ int map_vforeachinmovearea(int (*func)(struct block_list*, va_list), struct bloc * @param ... Extra arguments for func * @return Sum of the values returned by func */ -int map_foreachinmovearea(int (*func)(struct block_list*, va_list), struct block_list* center, int16 range, int16 dx, int16 dy, int type, ...) { +static int map_foreachinmovearea(int (*func)(struct block_list*, va_list), struct block_list *center, int16 range, int16 dx, int16 dy, int type, ...) +{ int returnCount; va_list ap; @@ -1163,7 +1269,8 @@ int map_foreachinmovearea(int (*func)(struct block_list*, va_list), struct block * @param ap Extra arguments for func * @return Sum of the values returned by func */ -int map_vforeachincell(int (*func)(struct block_list*, va_list), int16 m, int16 x, int16 y, int type, va_list ap) { +static int map_vforeachincell(int (*func)(struct block_list*, va_list), int16 m, int16 x, int16 y, int type, va_list ap) +{ int returnCount = 0; int blockcount = map->bl_list_count; va_list apcopy; @@ -1189,7 +1296,8 @@ int map_vforeachincell(int (*func)(struct block_list*, va_list), int16 m, int16 * @param ... Extra arguments for func * @return Sum of the values returned by func */ -int map_foreachincell(int (*func)(struct block_list*, va_list), int16 m, int16 x, int16 y, int type, ...) { +static int map_foreachincell(int (*func)(struct block_list*, va_list), int16 m, int16 x, int16 y, int type, ...) +{ int returnCount; va_list ap; @@ -1268,7 +1376,8 @@ static int bl_vgetall_inpath(struct block_list *bl, va_list args) * @param ap Extra arguments for func * @return Sum of the values returned by func */ -int map_vforeachinpath(int (*func)(struct block_list*, va_list), int16 m, int16 x0, int16 y0, int16 x1, int16 y1, int16 range, int length, int type, va_list ap) { +static int map_vforeachinpath(int (*func)(struct block_list*, va_list), int16 m, int16 x0, int16 y0, int16 x1, int16 y1, int16 range, int length, int type, va_list ap) +{ // [Skotlex] // check for all targets in the square that // contains the initial and final positions (area range increased to match the @@ -1345,7 +1454,8 @@ int map_vforeachinpath(int (*func)(struct block_list*, va_list), int16 m, int16 * @param ... Extra arguments for func * @return Sum of the values returned by func */ -int map_foreachinpath(int (*func)(struct block_list*, va_list), int16 m, int16 x0, int16 y0, int16 x1, int16 y1, int16 range, int length, int type, ...) { +static int map_foreachinpath(int (*func)(struct block_list*, va_list), int16 m, int16 x0, int16 y0, int16 x1, int16 y1, int16 range, int length, int type, ...) +{ int returnCount; va_list ap; @@ -1361,7 +1471,7 @@ int map_foreachinpath(int (*func)(struct block_list*, va_list), int16 m, int16 x /// Generates a new flooritem object id from the interval [MIN_FLOORITEM, MAX_FLOORITEM). /// Used for floor items, skill units and chatroom objects. /// @return The new object id -int map_get_new_object_id(void) +static int map_get_new_object_id(void) { static int last_object_id = MIN_FLOORITEM - 1; int i; @@ -1393,7 +1503,7 @@ int map_get_new_object_id(void) * Timered function to clear the floor (remove remaining item) * Called each flooritem_lifetime ms *------------------------------------------*/ -int map_clearflooritem_timer(int tid, int64 tick, int id, intptr_t data) +static int map_clearflooritem_timer(int tid, int64 tick, int id, intptr_t data) { struct block_list *bl = idb_get(map->id_db, id); struct flooritem_data *fitem = BL_CAST(BL_ITEM, bl); @@ -1416,7 +1526,7 @@ int map_clearflooritem_timer(int tid, int64 tick, int id, intptr_t data) /* * clears a single bl item out of the bazooonga. */ -void map_clearflooritem(struct block_list *bl) +static void map_clearflooritem(struct block_list *bl) { struct flooritem_data *fitem = BL_CAST(BL_ITEM, bl); @@ -1436,7 +1546,8 @@ void map_clearflooritem(struct block_list *bl) * to place an BL_ITEM object. Scan area is 9x9, returns 1 on success. * x and y are modified with the target cell when successful. *------------------------------------------*/ -int map_searchrandfreecell(int16 m, const struct block_list *bl, int16 *x, int16 *y, int stack) { +static int map_searchrandfreecell(int16 m, const struct block_list *bl, int16 *x, int16 *y, int stack) +{ int free_cell,i,j; int free_cells[9][2]; @@ -1466,7 +1577,8 @@ int map_searchrandfreecell(int16 m, const struct block_list *bl, int16 *x, int16 return 1; } -int map_count_sub(struct block_list *bl,va_list ap) { +static int map_count_sub(struct block_list *bl, va_list ap) +{ return 1; } @@ -1482,7 +1594,7 @@ int map_count_sub(struct block_list *bl,va_list ap) { * &2 = the target should be able to walk to the target tile. * &4 = there shouldn't be any players around the target tile (use the no_spawn_on_player setting) *------------------------------------------*/ -int map_search_freecell(struct block_list *src, int16 m, int16 *x,int16 *y, int16 rx, int16 ry, int flag) +static int map_search_freecell(struct block_list *src, int16 m, int16 *x, int16 *y, int16 rx, int16 ry, int flag) { int tries, spawn=0; int bx, by; @@ -1556,9 +1668,9 @@ int map_search_freecell(struct block_list *src, int16 m, int16 *x,int16 *y, int1 * flag: * 0x1 - only count standing units *------------------------------------------*/ -bool map_closest_freecell(int16 m, const struct block_list *bl, int16 *x, int16 *y, int type, int flag) +static bool map_closest_freecell(int16 m, const struct block_list *bl, int16 *x, int16 *y, int type, int flag) { - uint8 dir = 6; + enum unit_dir dir = UNIT_DIR_EAST; int16 tx; int16 ty; int costrange = 10; @@ -1577,7 +1689,7 @@ bool map_closest_freecell(int16 m, const struct block_list *bl, int16 *x, int16 short dy = diry[dir]; //Linear search - if(dir%2 == 0 && costrange%MOVE_COST == 0) { + if (!unit_is_diagonal_dir(dir) && (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, bl, tx, ty, CELL_CHKPASS)) { @@ -1587,7 +1699,7 @@ bool map_closest_freecell(int16 m, const struct block_list *bl, int16 *x, int16 } } //Full diagonal search - else if(dir%2 == 1 && costrange%MOVE_DIAGONAL_COST == 0) { + else if (unit_is_diagonal_dir(dir) && (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, bl, tx, ty, CELL_CHKPASS)) { @@ -1597,16 +1709,24 @@ bool map_closest_freecell(int16 m, const struct block_list *bl, int16 *x, int16 } } //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); + else if (unit_is_diagonal_dir(dir) && (costrange % MOVE_COST) == 4) { + tx = *x + dx; + ty = *y + dy; + if (unit_is_dir_or_opposite(dir, UNIT_DIR_SOUTHWEST)) + tx = tx * costrange / MOVE_COST; + if (unit_is_dir_or_opposite(dir, UNIT_DIR_NORTHWEST)) + ty = ty * costrange / MOVE_COST; if (!map->count_oncell(m, tx, ty, type, flag) && map->getcell(m, bl, 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); + tx = *x + dx; + ty = *y + dy; + if (unit_is_dir_or_opposite(dir, UNIT_DIR_NORTHWEST)) + tx = tx * costrange / MOVE_COST; + if (unit_is_dir_or_opposite(dir, UNIT_DIR_SOUTHWEST)) + ty = ty * costrange / MOVE_COST; if (!map->count_oncell(m, tx, ty, type, flag) && map->getcell(m, bl, tx, ty, CELL_CHKPASS)) { *x = tx; *y = ty; @@ -1615,17 +1735,17 @@ bool map_closest_freecell(int16 m, const struct block_list *bl, int16 *x, int16 } //Get next direction - if (dir == 5) { + if (dir == UNIT_DIR_SOUTHEAST) { //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) { + dir = UNIT_DIR_EAST; + } else if (dir == UNIT_DIR_SOUTH) { //Linear search complete, switch to diagonal directions - dir = 7; + dir = UNIT_DIR_NORTHEAST; } else { - dir = (dir+2)%8; + dir = unit_get_ccw90_dir(dir); } } @@ -1640,8 +1760,9 @@ bool map_closest_freecell(int16 m, const struct block_list *bl, int16 *x, int16 * @m, @x, @y mapid,x,y * @first_charid, @second_charid, @third_charid, looting priority * @flag: &1 MVP item. &2 do stacking check. + * @showdropeffect: show effect when the item is dropped. *------------------------------------------*/ -int map_addflooritem(const struct block_list *bl, struct item *item_data, int amount, int16 m, int16 x, int16 y, int first_charid, int second_charid, int third_charid, int flags) +static int map_addflooritem(const struct block_list *bl, struct item *item_data, int amount, int16 m, int16 x, int16 y, int first_charid, int second_charid, int third_charid, int flags, bool showdropeffect) { int r; struct flooritem_data *fitem=NULL; @@ -1660,6 +1781,7 @@ int map_addflooritem(const struct block_list *bl, struct item *item_data, int am fitem->bl.x = x; fitem->bl.y = y; fitem->bl.id = map->get_new_object_id(); + fitem->showdropeffect = showdropeffect; if(fitem->bl.id==0){ ers_free(map->flooritem_ers, fitem); return 0; @@ -1688,7 +1810,7 @@ int map_addflooritem(const struct block_list *bl, struct item *item_data, int am /** * @see DBCreateData */ -struct DBData create_charid2nick(union DBKey key, va_list args) +static struct DBData create_charid2nick(union DBKey key, va_list args) { struct charid2nick *p; CREATE(p, struct charid2nick, 1); @@ -1697,7 +1819,7 @@ struct DBData create_charid2nick(union DBKey key, va_list args) /// Adds(or replaces) the nick of charid to nick_db and fullfils pending requests. /// Does nothing if the character is online. -void map_addnickdb(int charid, const char* nick) +static void map_addnickdb(int charid, const char *nick) { struct charid2nick* p; struct charid_request* req; @@ -1721,7 +1843,7 @@ void map_addnickdb(int charid, const char* nick) /// Removes the nick of charid from nick_db. /// Sends name to all pending requests on charid. -void map_delnickdb(int charid, const char* name) +static void map_delnickdb(int charid, const char *name) { struct charid2nick* p; struct charid_request* req; @@ -1745,7 +1867,7 @@ void map_delnickdb(int charid, const char* name) /// Notifies sd of the nick of charid. /// Uses the name in the character if online. /// Uses the name in nick_db if offline. -void map_reqnickdb(struct map_session_data * sd, int charid) +static void map_reqnickdb(struct map_session_data *sd, int charid) { struct charid2nick* p; struct charid_request* req; @@ -1774,7 +1896,7 @@ void map_reqnickdb(struct map_session_data * sd, int charid) /*========================================== * add bl to id_db *------------------------------------------*/ -void map_addiddb(struct block_list *bl) +static void map_addiddb(struct block_list *bl) { nullpo_retv(bl); @@ -1786,7 +1908,7 @@ void map_addiddb(struct block_list *bl) struct mob_data *md = BL_UCAST(BL_MOB, bl); idb_put(map->mobid_db,bl->id,bl); - if( md->state.boss ) + if (md->state.boss == BTYPE_MVP) idb_put(map->bossid_db, bl->id, bl); } @@ -1799,7 +1921,7 @@ void map_addiddb(struct block_list *bl) /*========================================== * remove bl from id_db *------------------------------------------*/ -void map_deliddb(struct block_list *bl) +static void map_deliddb(struct block_list *bl) { nullpo_retv(bl); @@ -1821,7 +1943,8 @@ void map_deliddb(struct block_list *bl) /*========================================== * Standard call when a player connection is closed. *------------------------------------------*/ -int map_quit(struct map_session_data *sd) { +static int map_quit(struct map_session_data *sd) +{ int i; nullpo_ret(sd); @@ -1848,6 +1971,9 @@ int map_quit(struct map_session_data *sd) { if( sd->bg_id && !sd->bg_queue.arena ) /* TODO: dump this chunk after bg_queue is fully enabled */ bg->team_leave(sd,BGTL_QUIT); + if (sd->status.clan_id) + clan->member_offline(sd); + if (sd->state.autotrade && core->runflag != MAPSERVER_ST_SHUTDOWN && !channel->config->closing) pc->autotrade_update(sd,PAUC_REMOVE); @@ -1867,6 +1993,7 @@ int map_quit(struct map_session_data *sd) { } npc->script_event(sd, NPCE_LOGOUT); + rodex->clean(sd, 0); //Unit_free handles clearing the player related data, //map->quit handles extra specific data which is related to quitting normally @@ -1882,6 +2009,7 @@ int map_quit(struct map_session_data *sd) { case SC_GDSKILL_REGENERATION: if( !sd->sc.data[i]->val4 ) break; + FALLTHROUGH default: status_change_end(&sd->bl, (sc_type)i, INVALID_TIMER); } @@ -1946,7 +2074,7 @@ int map_quit(struct map_session_data *sd) { * @return The searched map_session_data, if it exists. * @retval NULL if the ID is invalid or doesn't belong to a player unit. */ -struct map_session_data *map_id2sd(int id) +static struct map_session_data *map_id2sd(int id) { struct block_list *bl = NULL; if (id <= 0) @@ -1966,7 +2094,7 @@ struct map_session_data *map_id2sd(int id) * @return The searched npc_data, if it exists. * @retval NULL if the ID is invalid or doesn't belong to a NPC. */ -struct npc_data *map_id2nd(int id) +static struct npc_data *map_id2nd(int id) { // just a id2bl lookup because there's no npc_db struct block_list* bl = map->id2bl(id); @@ -1983,7 +2111,7 @@ struct npc_data *map_id2nd(int id) * @return The searched mob_data, if it exists. * @retval NULL if the ID is invalid or doesn't belong to a mob unit. */ -struct mob_data *map_id2md(int id) +static struct mob_data *map_id2md(int id) { struct block_list *bl = NULL; if (id <= 0) @@ -2003,7 +2131,7 @@ struct mob_data *map_id2md(int id) * @return The searched flooritem_data, if it exists. * @retval NULL if the ID is invalid or doesn't belong to a floor item. */ -struct flooritem_data *map_id2fi(int id) +static struct flooritem_data *map_id2fi(int id) { struct block_list* bl = map->id2bl(id); @@ -2017,7 +2145,7 @@ struct flooritem_data *map_id2fi(int id) * @return The searched chat_data, if it exists. * @retval NULL if the ID is invalid or doesn't belong to a chat. */ -struct chat_data *map_id2cd(int id) +static struct chat_data *map_id2cd(int id) { struct block_list* bl = map->id2bl(id); @@ -2031,7 +2159,7 @@ struct chat_data *map_id2cd(int id) * @return The searched skill_unit data, if it exists. * @retval NULL if the ID is invalid or doesn't belong to a skill unit. */ -struct skill_unit *map_id2su(int id) +static struct skill_unit *map_id2su(int id) { struct block_list* bl = map->id2bl(id); @@ -2045,7 +2173,7 @@ struct skill_unit *map_id2su(int id) * @return The searched pet_data, if it exists. * @retval NULL if the ID is invalid or doesn't belong to a pet. */ -struct pet_data *map_id2pd(int id) +static struct pet_data *map_id2pd(int id) { struct block_list* bl = map->id2bl(id); @@ -2059,7 +2187,7 @@ struct pet_data *map_id2pd(int id) * @return The searched homun_data, if it exists. * @retval NULL if the ID is invalid or doesn't belong to a homunculus. */ -struct homun_data *map_id2hd(int id) +static struct homun_data *map_id2hd(int id) { struct block_list* bl = map->id2bl(id); @@ -2073,7 +2201,7 @@ struct homun_data *map_id2hd(int id) * @return The searched mercenary_data, if it exists. * @retval NULL if the ID is invalid or doesn't belong to a mercenary. */ -struct mercenary_data *map_id2mc(int id) +static struct mercenary_data *map_id2mc(int id) { struct block_list* bl = map->id2bl(id); @@ -2087,7 +2215,7 @@ struct mercenary_data *map_id2mc(int id) * @return The searched elemental_data, if it exists. * @retval NULL if the ID is invalid or doesn't belong to an elemental. */ -struct elemental_data *map_id2ed(int id) +static struct elemental_data *map_id2ed(int id) { struct block_list* bl = map->id2bl(id); @@ -2103,7 +2231,7 @@ struct elemental_data *map_id2ed(int id) * @return The searched block_list, if it exists. * @retval NULL if the ID is invalid. */ -struct block_list *map_id2bl(int id) +static struct block_list *map_id2bl(int id) { return idb_get(map->id_db, id); } @@ -2115,13 +2243,14 @@ struct block_list *map_id2bl(int id) * @retval true if the ID exists and is valid. * @retval false otherwise. */ -bool map_blid_exists(int id) +static bool map_blid_exists(int id) { return (idb_exists(map->id_db,id)); } /// Returns the nick of the target charid or NULL if unknown (requests the nick to the char server). -const char *map_charid2nick(int charid) { +static const char *map_charid2nick(int charid) +{ struct charid2nick *p; struct map_session_data* sd; @@ -2138,7 +2267,7 @@ const char *map_charid2nick(int charid) { } /// Returns the struct map_session_data of the charid or NULL if the char is not online. -struct map_session_data* map_charid2sd(int charid) +static struct map_session_data *map_charid2sd(int charid) { struct block_list *bl = idb_get(map->charid_db, charid); if (bl) @@ -2151,30 +2280,25 @@ struct map_session_data* map_charid2sd(int charid) * (without sensitive case if necessary) * return map_session_data pointer or NULL *------------------------------------------*/ -struct map_session_data * map_nick2sd(const char *nick) +static struct map_session_data *map_nick2sd(const char *nick, bool allow_partial) { - struct map_session_data* sd; - struct map_session_data* found_sd; - struct s_mapiterator* iter; - size_t nicklen; - int qty = 0; - - if( nick == NULL ) + if (nick == NULL) return NULL; - nicklen = strlen(nick); - iter = mapit_getallusers(); + struct s_mapiterator *iter = mapit_getallusers(); + struct map_session_data *found_sd = NULL; + + if (battle_config.partial_name_scan && allow_partial) { + int nicklen = (int)strlen(nick); + int qty = 0; - found_sd = NULL; - for (sd = BL_UCAST(BL_PC, mapit->first(iter)); mapit->exists(iter); sd = BL_UCAST(BL_PC, mapit->next(iter))) { - if( battle_config.partial_name_scan ) - {// partial name search - if( strnicmp(sd->status.name, nick, nicklen) == 0 ) - { + // partial name search + for (struct map_session_data *sd = BL_UCAST(BL_PC, mapit->first(iter)); mapit->exists(iter); sd = BL_UCAST(BL_PC, mapit->next(iter))) { + if (strnicmp(sd->status.name, nick, nicklen) == 0) { found_sd = sd; - if( strcmp(sd->status.name, nick) == 0 ) - {// Perfect Match + if (strcmp(sd->status.name, nick) == 0) { + // Perfect Match qty = 1; break; } @@ -2182,24 +2306,27 @@ struct map_session_data * map_nick2sd(const char *nick) qty++; } } - else if( strcasecmp(sd->status.name, nick) == 0 ) - {// exact search only - found_sd = sd; - break; + + if (qty != 1) + found_sd = NULL; + } else { + // exact search only + for (struct map_session_data *sd = BL_UCAST(BL_PC, mapit->first(iter)); mapit->exists(iter); sd = BL_UCAST(BL_PC, mapit->next(iter))) { + if (strcasecmp(sd->status.name, nick) == 0) { + found_sd = sd; + break; + } } } mapit->free(iter); - if( battle_config.partial_name_scan && qty != 1 ) - found_sd = NULL; - return found_sd; } /*========================================== * Convext Mirror *------------------------------------------*/ -struct mob_data *map_getmob_boss(int16 m) +static struct mob_data *map_getmob_boss(int16 m) { struct DBIterator *iter; struct mob_data *md = NULL; @@ -2217,7 +2344,7 @@ struct mob_data *map_getmob_boss(int16 m) return (found)? md : NULL; } -struct mob_data *map_id2boss(int id) +static struct mob_data *map_id2boss(int id) { struct block_list *bl = NULL; if (id <= 0) @@ -2235,7 +2362,7 @@ struct mob_data *map_id2boss(int id) * * @return The equivalent race bitmask. */ -uint32 map_race_id2mask(int race) +static uint32 map_race_id2mask(int race) { if (race >= RC_FORMLESS && race < RC_MAX) return 1 << race; @@ -2263,7 +2390,7 @@ uint32 map_race_id2mask(int race) /// Applies func to all the players in the db. /// Stops iterating if func returns -1. -void map_vforeachpc(int (*func)(struct map_session_data* sd, va_list args), va_list args) +static void map_vforeachpc(int (*func)(struct map_session_data *sd, va_list args), va_list args) { struct DBIterator *iter = db_iterator(map->pc_db); struct map_session_data *sd = NULL; @@ -2285,7 +2412,8 @@ void map_vforeachpc(int (*func)(struct map_session_data* sd, va_list args), va_l /// Applies func to all the players in the db. /// Stops iterating if func returns -1. /// @see map_vforeachpc -void map_foreachpc(int (*func)(struct map_session_data* sd, va_list args), ...) { +static void map_foreachpc(int (*func)(struct map_session_data *sd, va_list args), ...) +{ va_list args; va_start(args, func); @@ -2295,7 +2423,7 @@ void map_foreachpc(int (*func)(struct map_session_data* sd, va_list args), ...) /// Applies func to all the mobs in the db. /// Stops iterating if func returns -1. -void map_vforeachmob(int (*func)(struct mob_data* md, va_list args), va_list args) +static void map_vforeachmob(int (*func)(struct mob_data *md, va_list args), va_list args) { struct DBIterator *iter = db_iterator(map->mobid_db); struct mob_data *md = NULL; @@ -2316,7 +2444,8 @@ void map_vforeachmob(int (*func)(struct mob_data* md, va_list args), va_list arg /// Applies func to all the mobs in the db. /// Stops iterating if func returns -1. /// @see map_vforeachmob -void map_foreachmob(int (*func)(struct mob_data* md, va_list args), ...) { +static void map_foreachmob(int (*func)(struct mob_data *md, va_list args), ...) +{ va_list args; va_start(args, func); @@ -2326,7 +2455,7 @@ void map_foreachmob(int (*func)(struct mob_data* md, va_list args), ...) { /// Applies func to all the npcs in the db. /// Stops iterating if func returns -1. -void map_vforeachnpc(int (*func)(struct npc_data* nd, va_list args), va_list args) +static void map_vforeachnpc(int (*func)(struct npc_data *nd, va_list args), va_list args) { struct DBIterator *iter = db_iterator(map->id_db); struct block_list *bl = NULL; @@ -2350,7 +2479,8 @@ void map_vforeachnpc(int (*func)(struct npc_data* nd, va_list args), va_list arg /// Applies func to all the npcs in the db. /// Stops iterating if func returns -1. /// @see map_vforeachnpc -void map_foreachnpc(int (*func)(struct npc_data* nd, va_list args), ...) { +static void map_foreachnpc(int (*func)(struct npc_data *nd, va_list args), ...) +{ va_list args; va_start(args, func); @@ -2360,7 +2490,7 @@ void map_foreachnpc(int (*func)(struct npc_data* nd, va_list args), ...) { /// Applies func to everything in the db. /// Stops iterating gif func returns -1. -void map_vforeachregen(int (*func)(struct block_list* bl, va_list args), va_list args) +static void map_vforeachregen(int (*func)(struct block_list *bl, va_list args), va_list args) { struct DBIterator *iter = db_iterator(map->regen_db); struct block_list *bl = NULL; @@ -2381,7 +2511,8 @@ void map_vforeachregen(int (*func)(struct block_list* bl, va_list args), va_list /// Applies func to everything in the db. /// Stops iterating gif func returns -1. /// @see map_vforeachregen -void map_foreachregen(int (*func)(struct block_list* bl, va_list args), ...) { +static void map_foreachregen(int (*func)(struct block_list *bl, va_list args), ...) +{ va_list args; va_start(args, func); @@ -2391,7 +2522,7 @@ void map_foreachregen(int (*func)(struct block_list* bl, va_list args), ...) { /// Applies func to everything in the db. /// Stops iterating if func returns -1. -void map_vforeachiddb(int (*func)(struct block_list* bl, va_list args), va_list args) +static void map_vforeachiddb(int (*func)(struct block_list *bl, va_list args), va_list args) { struct DBIterator *iter = db_iterator(map->id_db); struct block_list *bl = NULL; @@ -2412,7 +2543,8 @@ void map_vforeachiddb(int (*func)(struct block_list* bl, va_list args), va_list /// Applies func to everything in the db. /// Stops iterating if func returns -1. /// @see map_vforeachiddb -void map_foreachiddb(int (*func)(struct block_list* bl, va_list args), ...) { +static void map_foreachiddb(int (*func)(struct block_list *bl, va_list args), ...) +{ va_list args; va_start(args, func); @@ -2444,7 +2576,8 @@ struct s_mapiterator { /// @param flags Flags of the iterator /// @param type Target types /// @return Iterator -struct s_mapiterator* mapit_alloc(enum e_mapitflags flags, enum bl_type types) { +static struct s_mapiterator *mapit_alloc(enum e_mapitflags flags, enum bl_type types) +{ struct s_mapiterator* iter; iter = ers_alloc(map->iterator_ers, struct s_mapiterator); @@ -2459,7 +2592,8 @@ struct s_mapiterator* mapit_alloc(enum e_mapitflags flags, enum bl_type types) { /// Frees the iterator. /// /// @param iter Iterator -void mapit_free(struct s_mapiterator* iter) { +static void mapit_free(struct s_mapiterator *iter) +{ nullpo_retv(iter); dbi_destroy(iter->dbi); @@ -2471,7 +2605,8 @@ void mapit_free(struct s_mapiterator* iter) { /// /// @param iter Iterator /// @return first block_list or NULL -struct block_list* mapit_first(struct s_mapiterator* iter) { +static struct block_list *mapit_first(struct s_mapiterator *iter) +{ struct block_list* bl; nullpo_retr(NULL,iter); @@ -2488,7 +2623,8 @@ struct block_list* mapit_first(struct s_mapiterator* iter) { /// /// @param iter Iterator /// @return last block_list or NULL -struct block_list* mapit_last(struct s_mapiterator* iter) { +static struct block_list *mapit_last(struct s_mapiterator *iter) +{ struct block_list* bl; nullpo_retr(NULL,iter); @@ -2505,7 +2641,8 @@ struct block_list* mapit_last(struct s_mapiterator* iter) { /// /// @param iter Iterator /// @return next block_list or NULL -struct block_list* mapit_next(struct s_mapiterator* iter) { +static struct block_list *mapit_next(struct s_mapiterator *iter) +{ struct block_list* bl; nullpo_retr(NULL,iter); @@ -2526,7 +2663,8 @@ struct block_list* mapit_next(struct s_mapiterator* iter) { /// /// @param iter Iterator /// @return previous block_list or NULL -struct block_list* mapit_prev(struct s_mapiterator* iter) { +static struct block_list *mapit_prev(struct s_mapiterator *iter) +{ struct block_list* bl; nullpo_retr(NULL,iter); @@ -2546,7 +2684,8 @@ struct block_list* mapit_prev(struct s_mapiterator* iter) { /// /// @param iter Iterator /// @return true if it exists -bool mapit_exists(struct s_mapiterator* iter) { +static bool mapit_exists(struct s_mapiterator *iter) +{ nullpo_retr(false,iter); return dbi_exists(iter->dbi); @@ -2555,7 +2694,8 @@ bool mapit_exists(struct s_mapiterator* iter) { /*========================================== * Add npc-bl to id_db, basically register npc to map *------------------------------------------*/ -bool map_addnpc(int16 m,struct npc_data *nd) { +static bool map_addnpc(int16 m, struct npc_data *nd) +{ nullpo_ret(nd); if( m < 0 || m >= map->count ) @@ -2577,7 +2717,8 @@ bool map_addnpc(int16 m,struct npc_data *nd) { *-----------------------------------------*/ // Stores the spawn data entry in the mob list. // Returns the index of successful, or -1 if the list was full. -int map_addmobtolist(unsigned short m, struct spawn_data *spawn) { +static int map_addmobtolist(unsigned short m, struct spawn_data *spawn) +{ int i; nullpo_retr(-1, spawn); ARR_FIND( 0, MAX_MOB_LIST_PER_MAP, i, map->list[m].moblist[i] == NULL ); @@ -2588,7 +2729,8 @@ int map_addmobtolist(unsigned short m, struct spawn_data *spawn) { return -1; } -void map_spawnmobs(int16 m) { +static void map_spawnmobs(int16 m) +{ int i, k=0; if (map->list[m].mob_delete_timer != INVALID_TIMER) { //Mobs have not been removed yet [Skotlex] @@ -2607,7 +2749,7 @@ void map_spawnmobs(int16 m) { } } -int map_removemobs_sub(struct block_list *bl, va_list ap) +static int map_removemobs_sub(struct block_list *bl, va_list ap) { struct mob_data *md = NULL; nullpo_ret(bl); @@ -2636,7 +2778,8 @@ int map_removemobs_sub(struct block_list *bl, va_list ap) return 1; } -int map_removemobs_timer(int tid, int64 tick, int id, intptr_t data) { +static int map_removemobs_timer(int tid, int64 tick, int id, intptr_t data) +{ int count; const int16 m = id; @@ -2660,7 +2803,8 @@ int map_removemobs_timer(int tid, int64 tick, int id, intptr_t data) { return 1; } -void map_removemobs(int16 m) { +static void map_removemobs(int16 m) +{ Assert_retv(m >= 0 && m < map->count); if (map->list[m].mob_delete_timer != INVALID_TIMER) // should never happen return; //Mobs are already scheduled for removal @@ -2671,7 +2815,8 @@ void map_removemobs(int16 m) { /*========================================== * Hookup, get map_id from map_name *------------------------------------------*/ -int16 map_mapname2mapid(const char* name) { +static int16 map_mapname2mapid(const char *name) +{ unsigned short map_index; map_index = mapindex->name2id(name); if (!map_index) @@ -2682,7 +2827,8 @@ int16 map_mapname2mapid(const char* name) { /*========================================== * Returns the map of the given mapindex. [Skotlex] *------------------------------------------*/ -int16 map_mapindex2mapid(unsigned short map_index) { +static int16 map_mapindex2mapid(unsigned short map_index) +{ if (!map_index || map_index >= MAX_MAPINDEX) return -1; @@ -2693,7 +2839,8 @@ int16 map_mapindex2mapid(unsigned short map_index) { /*========================================== * Switching Ip, port ? (like changing map_server) get ip/port from map_name *------------------------------------------*/ -int map_mapname2ipport(unsigned short name, uint32* ip, uint16* port) { +static int map_mapname2ipport(unsigned short name, uint32 *ip, uint16 *port) +{ struct map_data_other_server *mdos; nullpo_retr(-1, ip); @@ -2706,63 +2853,70 @@ int map_mapname2ipport(unsigned short name, uint32* ip, uint16* port) { return 0; } -/*========================================== -* Checks if both dirs point in the same direction. -*------------------------------------------*/ -int map_check_dir(int s_dir,int t_dir) +/** + * Checks if both dirs point in the same direction. + * @param s_dir: direction source is facing + * @param t_dir: direction target is facing + * @return 0: success(both face the same direction), 1: failure + **/ +static int map_check_dir(enum unit_dir s_dir, enum unit_dir t_dir) { - if(s_dir == t_dir) + if (s_dir == t_dir || ((t_dir + UNIT_DIR_MAX - 1) % UNIT_DIR_MAX) == s_dir + || ((t_dir + UNIT_DIR_MAX + 1) % UNIT_DIR_MAX) == s_dir) return 0; - switch(s_dir) { - case 0: if(t_dir == 7 || t_dir == 1 || t_dir == 0) return 0; break; - case 1: if(t_dir == 0 || t_dir == 2 || t_dir == 1) return 0; break; - case 2: if(t_dir == 1 || t_dir == 3 || t_dir == 2) return 0; break; - case 3: if(t_dir == 2 || t_dir == 4 || t_dir == 3) return 0; break; - case 4: if(t_dir == 3 || t_dir == 5 || t_dir == 4) return 0; break; - case 5: if(t_dir == 4 || t_dir == 6 || t_dir == 5) return 0; break; - case 6: if(t_dir == 5 || t_dir == 7 || t_dir == 6) return 0; break; - case 7: if(t_dir == 6 || t_dir == 0 || t_dir == 7) return 0; break; - } return 1; } -/*========================================== +/** * Returns the direction of the given cell, relative to 'src' - *------------------------------------------*/ -uint8 map_calc_dir(struct block_list* src, int16 x, int16 y) + * @param src: object to put in relation between coordinates + * @param x: x-coordinate of cell + * @param y: y-coordinate of cell + * @return the direction of the given cell, relative to 'src' + **/ +static enum unit_dir map_calc_dir(const struct block_list *src, int16 x, int16 y) { - uint8 dir = 0; - int dx, dy; - - nullpo_ret(src); + nullpo_retr(UNIT_DIR_NORTH, src); + enum unit_dir dir = UNIT_DIR_NORTH; - dx = x-src->x; - dy = y-src->y; + int dx = x - src->x; + int dy = y - src->y; if (dx == 0 && dy == 0) { // both are standing on the same spot. // aegis-style, makes knockback default to the left. // athena-style, makes knockback default to behind 'src'. - dir = (battle_config.knockback_left ? 6 : unit->getdir(src)); - } else if (dx >= 0 && dy >=0) { - // upper-right - if( dx*2 < dy || dx == 0 ) dir = 0; // up - else if( dx > dy*2+1 || dy == 0 ) dir = 6; // right - else dir = 7; // up-right + if (battle_config.knockback_left != 0) + dir = UNIT_DIR_EAST; + else + dir = unit->getdir(src); + } else if (dx >= 0 && dy >= 0) { + if (dx * 2 < dy || dx == 0) + dir = UNIT_DIR_NORTH; + else if (dx > dy * 2 + 1 || dy == 0) + dir = UNIT_DIR_EAST; + else + dir = UNIT_DIR_NORTHEAST; } else if (dx >= 0 && dy <= 0) { - // lower-right - if( dx*2 < -dy || dx == 0 ) dir = 4; // down - else if( dx > -dy*2+1 || dy == 0 ) dir = 6; // right - else dir = 5; // down-right + if (dx * 2 < -dy || dx == 0) + dir = UNIT_DIR_SOUTH; + else if (dx > -dy * 2 + 1 || dy == 0) + dir = UNIT_DIR_EAST; + else + dir = UNIT_DIR_SOUTHEAST; } else if (dx <= 0 && dy <= 0) { - // lower-left - if( dx*2 > dy || dx == 0 ) dir = 4; // down - else if( dx < dy*2-1 || dy == 0 ) dir = 2; // left - else dir = 3; // down-left + if (dx * 2 > dy || dx == 0 ) + dir = UNIT_DIR_SOUTH; + else if (dx < dy * 2 + 1 || dy == 0) + dir = UNIT_DIR_WEST; + else + dir = UNIT_DIR_SOUTHWEST; } else { - // upper-left - if( -dx*2 < dy || dx == 0 ) dir = 0; // up - else if( -dx > dy*2+1 || dy == 0) dir = 2; // left - else dir = 1; // up-left + if (-dx * 2 < dy || dx == 0 ) + dir = UNIT_DIR_NORTH; + else if (-dx > dy * 2 + 1 || dy == 0) + dir = UNIT_DIR_WEST; + else + dir = UNIT_DIR_NORTHWEST; } return dir; } @@ -2771,7 +2925,7 @@ uint8 map_calc_dir(struct block_list* src, int16 x, int16 y) * Randomizes target cell x,y to a random walkable cell that * has the same distance from object as given coordinates do. [Skotlex] *------------------------------------------*/ -int map_random_dir(struct block_list *bl, int16 *x, int16 *y) +static int map_random_dir(struct block_list *bl, int16 *x, int16 *y) { short xi; short yi; @@ -2790,11 +2944,11 @@ int map_random_dir(struct block_list *bl, int16 *x, int16 *y) if (dist < 1) dist =1; do { - int j = 1 + 2*(rnd()%4); //Pick a random diagonal direction + enum unit_dir dir = unit_get_rnd_diagonal_dir(); short segment = 1+(rnd()%dist); //Pick a random interval from the whole vector in that direction - xi = bl->x + segment*dirx[j]; + xi = bl->x + segment * dirx[dir]; segment = (short)sqrt((float)(dist2 - segment*segment)); //The complement of the previously picked segment - yi = bl->y + segment*diry[j]; + yi = bl->y + segment * diry[dir]; } while ((map->getcell(bl->m, bl, xi, yi, CELL_CHKNOPASS) || !path->search(NULL, bl, bl->m, bl->x, bl->y, xi, yi, 1, CELL_CHKNOREACH)) && (++i)<100); @@ -2807,7 +2961,8 @@ int map_random_dir(struct block_list *bl, int16 *x, int16 *y) } // gat system -struct mapcell map_gat2cell(int gat) { +static struct mapcell map_gat2cell(int gat) +{ struct mapcell cell; memset(&cell,0,sizeof(struct mapcell)); @@ -2828,7 +2983,8 @@ struct mapcell map_gat2cell(int gat) { return cell; } -int map_cell2gat(struct mapcell cell) { +static int map_cell2gat(struct mapcell cell) +{ if( cell.walkable == 1 && cell.shootable == 1 && cell.water == 0 ) return 0; if( cell.walkable == 0 && cell.shootable == 0 && cell.water == 0 ) return 1; if( cell.walkable == 1 && cell.shootable == 1 && cell.water == 1 ) return 3; @@ -2837,21 +2993,26 @@ int map_cell2gat(struct mapcell cell) { ShowWarning("map_cell2gat: cell has no matching gat type\n"); return 1; // default to 'wall' } -void map_cellfromcache(struct map_data *m) { - struct map_cache_map_info *info; +/** + * Extracts a map's cell data from its compressed mapcache. + * + * @param[in, out] m The target map. + */ +static void map_cellfromcache(struct map_data *m) +{ nullpo_retv(m); - info = (struct map_cache_map_info *)m->cellPos; - if (info) { + if (m->cell_buf.data != NULL) { char decode_buffer[MAX_MAP_SIZE]; unsigned long size, xy; int i; - size = (unsigned long)info->xs*(unsigned long)info->ys; + size = (unsigned long)m->xs * (unsigned long)m->ys; // TO-DO: Maybe handle the scenario, if the decoded buffer isn't the same size as expected? [Shinryo] - decode_zip(decode_buffer, &size, m->cellPos+sizeof(struct map_cache_map_info), info->len); + grfio->decode_zip(decode_buffer, &size, m->cell_buf.data, m->cell_buf.len); + CREATE(m->cell, struct mapcell, size); // Set cell properties @@ -2871,11 +3032,13 @@ void map_cellfromcache(struct map_data *m) { /*========================================== * Confirm if celltype in (m,x,y) match the one given in cellchk *------------------------------------------*/ -int map_getcell(int16 m, const struct block_list *bl, int16 x, int16 y, cell_chk cellchk) { +static int map_getcell(int16 m, const struct block_list *bl, int16 x, int16 y, cell_chk cellchk) +{ return (m < 0 || m >= map->count) ? 0 : map->list[m].getcellp(&map->list[m], bl, x, y, cellchk); } -int map_getcellp(struct map_data* m, const struct block_list *bl, int16 x, int16 y, cell_chk cellchk) { +static int map_getcellp(struct map_data *m, const struct block_list *bl, int16 x, int16 y, cell_chk cellchk) +{ struct mapcell cell; nullpo_ret(m); @@ -2943,7 +3106,8 @@ int map_getcellp(struct map_data* m, const struct block_list *bl, int16 x, int16 } /* [Ind/Hercules] */ -int map_sub_getcellp(struct map_data* m, const struct block_list *bl, int16 x, int16 y, cell_chk cellchk) { +static int map_sub_getcellp(struct map_data *m, const struct block_list *bl, int16 x, int16 y, cell_chk cellchk) +{ nullpo_ret(m); map->cellfromcache(m); m->getcellp = map->getcellp; @@ -2956,7 +3120,8 @@ int map_sub_getcellp(struct map_data* m, const struct block_list *bl, int16 x, i * 'cell' - which flag to modify * 'flag' - true = on, false = off *------------------------------------------*/ -void map_setcell(int16 m, int16 x, int16 y, cell_t cell, bool flag) { +static void map_setcell(int16 m, int16 x, int16 y, cell_t cell, bool flag) +{ int j; if( m < 0 || m >= map->count || x < 0 || x >= map->list[m].xs || y < 0 || y >= map->list[m].ys ) @@ -2982,7 +3147,8 @@ void map_setcell(int16 m, int16 x, int16 y, cell_t cell, bool flag) { break; } } -void map_sub_setcell(int16 m, int16 x, int16 y, cell_t cell, bool flag) { +static void map_sub_setcell(int16 m, int16 x, int16 y, cell_t cell, bool flag) +{ if( m < 0 || m >= map->count || x < 0 || x >= map->list[m].xs || y < 0 || y >= map->list[m].ys ) return; @@ -2991,7 +3157,8 @@ void map_sub_setcell(int16 m, int16 x, int16 y, cell_t cell, bool flag) { map->list[m].getcellp = map->getcellp; map->list[m].setcell(m,x,y,cell,flag); } -void map_setgatcell(int16 m, int16 x, int16 y, int gat) { +static void map_setgatcell(int16 m, int16 x, int16 y, int gat) +{ int j; struct mapcell cell; @@ -3007,9 +3174,9 @@ void map_setgatcell(int16 m, int16 x, int16 y, int gat) { } /*========================================== -* Invisible Walls -*------------------------------------------*/ -void map_iwall_nextxy(int16 x, int16 y, int8 dir, int pos, int16 *x1, int16 *y1) + * Invisible Walls + *------------------------------------------*/ +static void map_iwall_nextxy(int16 x, int16 y, int8 dir, int pos, int16 *x1, int16 *y1) { nullpo_retv(x1); nullpo_retv(y1); @@ -3029,7 +3196,7 @@ void map_iwall_nextxy(int16 x, int16 y, int8 dir, int pos, int16 *x1, int16 *y1) *y1 = y + pos; } -bool map_iwall_set(int16 m, int16 x, int16 y, int size, int8 dir, bool shootable, const char* wall_name) +static bool map_iwall_set(int16 m, int16 x, int16 y, int size, int8 dir, bool shootable, const char *wall_name) { struct iwall_data *iwall; int i; @@ -3073,7 +3240,7 @@ bool map_iwall_set(int16 m, int16 x, int16 y, int size, int8 dir, bool shootable return true; } -void map_iwall_get(struct map_session_data *sd) +static void map_iwall_get(struct map_session_data *sd) { struct iwall_data *iwall; struct DBIterator *iter; @@ -3098,13 +3265,13 @@ void map_iwall_get(struct map_session_data *sd) dbi_destroy(iter); } -void map_iwall_remove(const char *wall_name) +static bool map_iwall_remove(const char *wall_name) { struct iwall_data *iwall; int16 i, x1, y1; if( (iwall = (struct iwall_data *)strdb_get(map->iwall_db, wall_name)) == NULL ) - return; // Nothing to do + return false; for( i = 0; i < iwall->size; i++ ) { map->iwall_nextxy(iwall->x, iwall->y, iwall->dir, i, &x1, &y1); @@ -3117,12 +3284,13 @@ void map_iwall_remove(const char *wall_name) map->list[iwall->m].iwall_num--; strdb_remove(map->iwall_db, iwall->wall_name); + return true; } /** * @see DBCreateData */ -struct DBData create_map_data_other_server(union DBKey key, va_list args) +static struct DBData create_map_data_other_server(union DBKey key, va_list args) { struct map_data_other_server *mdos; unsigned short map_index = (unsigned short)key.ui; @@ -3135,7 +3303,7 @@ struct DBData create_map_data_other_server(union DBKey key, va_list args) /*========================================== * Add mapindex to db of another map server *------------------------------------------*/ -int map_setipport(unsigned short map_index, uint32 ip, uint16 port) +static int map_setipport(unsigned short map_index, uint32 ip, uint16 port) { struct map_data_other_server *mdos; @@ -3157,7 +3325,7 @@ int map_setipport(unsigned short map_index, uint32 ip, uint16 port) * Delete all the other maps server management * @see DBApply */ -int map_eraseallipport_sub(union DBKey key, struct DBData *data, va_list va) +static int map_eraseallipport_sub(union DBKey key, struct DBData *data, va_list va) { struct map_data_other_server *mdos = DB->data2ptr(data); nullpo_ret(mdos); @@ -3168,7 +3336,8 @@ int map_eraseallipport_sub(union DBKey key, struct DBData *data, va_list va) return 0; } -int map_eraseallipport(void) { +static int map_eraseallipport(void) +{ map->map_db->foreach(map->map_db,map->eraseallipport_sub); return 1; } @@ -3176,7 +3345,8 @@ int map_eraseallipport(void) { /*========================================== * Delete mapindex from db of another map server *------------------------------------------*/ -int map_eraseipport(unsigned short map_index, uint32 ip, uint16 port) { +static int map_eraseipport(unsigned short map_index, uint32 ip, uint16 port) +{ struct map_data_other_server *mdos; mdos = (struct map_data_other_server*)uidb_get(map->map_db,(unsigned int)map_index); @@ -3191,113 +3361,163 @@ int map_eraseipport(unsigned short map_index, uint32 ip, uint16 port) { return 0; } -/*========================================== - * [Shinryo]: Init the mapcache - *------------------------------------------*/ -char *map_init_mapcache(FILE *fp) { - struct map_cache_main_header header; - size_t size = 0; - char *buffer; - - // No file open? Return.. - nullpo_ret(fp); +/** + * Reads a map's compressed cell data from its mapcache file. + * + * @param[in,out] m The target map. + * @return The loading success state. + * @retval false in case of errors. + */ +static bool map_readfromcache(struct map_data *m) +{ + unsigned int file_size; + char file_path[256]; + FILE *fp = NULL; + bool retval = false; + int16 version; - // Get file size - fseek(fp, 0, SEEK_END); - size = ftell(fp); - fseek(fp, 0, SEEK_SET); + nullpo_retr(false, m); - // Allocate enough space - CREATE(buffer, char, size); + snprintf(file_path, sizeof(file_path), "%s%s%s.%s", "maps/", DBPATH, m->name, "mcache"); + fp = fopen(file_path, "rb"); - // No memory? Return.. - nullpo_ret(buffer); + if (fp == NULL) { + ShowWarning("map_readfromcache: Could not open the mapcache file for map '%s' at path '%s'.\n", m->name, file_path); + return false; + } - // Read file into buffer.. - if(fread(buffer, sizeof(char), size, fp) != size) { - ShowError("map_init_mapcache: Could not read entire mapcache file\n"); - aFree(buffer); - return NULL; + if (fread(&version, sizeof(version), 1, fp) < 1) { + ShowError("map_readfromcache: Could not read file version for map '%s'.\n", m->name); + fclose(fp); + return false; } - rewind(fp); + fseek(fp, 0, SEEK_END); + file_size = (unsigned int)ftell(fp); + fseek(fp, 0, SEEK_SET); // Rewind file pointer before passing it to the read function. - // Get main header to verify if data is corrupted - if( fread(&header, sizeof(header), 1, fp) != 1 ) { - ShowError("map_init_mapcache: Error obtaining main header!\n"); - aFree(buffer); - return NULL; - } - if( GetULong((unsigned char *)&(header.file_size)) != size ) { - ShowError("map_init_mapcache: Map cache is corrupted!\n"); - aFree(buffer); - return NULL; + switch(version) { + case 1: + retval = map->readfromcache_v1(fp, m, file_size); + break; + default: + ShowError("map_readfromcache: Mapcache file has unknown version '%d' for map '%s'.\n", version, m->name); + break; } - return buffer; + fclose(fp); + return retval; } -/*========================================== - * Map cache reading - * [Shinryo]: Optimized some behaviour to speed this up - *==========================================*/ -int map_readfromcache(struct map_data *m, char *buffer) { - int i; - struct map_cache_main_header *header = (struct map_cache_main_header *)buffer; - struct map_cache_map_info *info = NULL; - char *p = buffer + sizeof(struct map_cache_main_header); - - nullpo_ret(m); - nullpo_ret(buffer); - - for(i = 0; i < header->map_count; i++) { - info = (struct map_cache_map_info *)p; +/** + * Reads a map's compressed cell data from its mapcache file (file format + * version 1). + * + * @param[in] fp The file pointer to read from (opened and closed by + * the caller). + * @param[in,out] m The target map. + * @param[in] file_size The size of the file to load from. + * @return The loading success state. + * @retval false in case of errors. + */ +static bool map_readfromcache_v1(FILE *fp, struct map_data *m, unsigned int file_size) +{ + struct map_cache_header mheader = { 0 }; + uint8 md5buf[16] = { 0 }; + int map_size; + nullpo_retr(false, fp); + nullpo_retr(false, m); + + if (file_size <= sizeof(mheader) || fread(&mheader, sizeof(mheader), 1, fp) < 1) { + ShowError("map_readfromcache: Failed to read cache header for map '%s'.\n", m->name); + return false; + } - if( strcmp(m->name, info->name) == 0 ) - break; // Map found + if (mheader.len <= 0) { + ShowError("map_readfromcache: A file with negative or zero compressed length passed '%d'.\n", mheader.len); + return false; + } - // Jump to next entry.. - p += sizeof(struct map_cache_map_info) + info->len; + if (file_size < sizeof(mheader) + mheader.len) { + ShowError("map_readfromcache: An incomplete file passed for map '%s'.\n", m->name); + return false; } - if( info && i < header->map_count ) { - unsigned long size; + if (mheader.ys <= 0 || mheader.xs <= 0) { + ShowError("map_readfromcache: A map with invalid size passed '%s' xs: '%d' ys: '%d'.\n", m->name, mheader.xs, mheader.ys); + return false; + } - if( info->xs <= 0 || info->ys <= 0 ) - return 0;// Invalid + m->xs = mheader.xs; + m->ys = mheader.ys; + map_size = (int)mheader.xs * (int)mheader.ys; - m->xs = info->xs; - m->ys = info->ys; - size = (unsigned long)info->xs*(unsigned long)info->ys; + if (map_size > MAX_MAP_SIZE) { + ShowWarning("map_readfromcache: %s exceeded MAX_MAP_SIZE of %d.\n", m->name, MAX_MAP_SIZE); + return false; + } - if(size > MAX_MAP_SIZE) { - ShowWarning("map_readfromcache: %s exceeded MAX_MAP_SIZE of %d\n", info->name, MAX_MAP_SIZE); - return 0; // Say not found to remove it from list.. [Shinryo] - } + CREATE(m->cell_buf.data, uint8, mheader.len); + m->cell_buf.len = mheader.len; + if (fread(m->cell_buf.data, mheader.len, 1, fp) < 1) { + ShowError("mapreadfromcache: Could not load the compressed cell data for map '%s'.\n", m->name); + aFree(m->cell_buf.data); + m->cell_buf.data = NULL; + m->cell_buf.len = 0; + return false; + } - m->cellPos = p; - m->cell = (struct mapcell *)0xdeadbeaf; + md5->binary(m->cell_buf.data, m->cell_buf.len, md5buf); - return 1; + if (memcmp(md5buf, mheader.md5_checksum, sizeof(md5buf)) != 0) { + ShowError("mapreadfromcache: md5 checksum check failed for map '%s'\n", m->name); + aFree(m->cell_buf.data); + m->cell_buf.data = NULL; + m->cell_buf.len = 0; + return false; } - return 0; // Not found + m->cell = (struct mapcell *)0xdeadbeaf; + + return true; } -int map_addmap(const char* mapname) { +/** + * Adds a new empty map to the map list. + * + * Assumes that there's enough space in the map list. + * + * @param mapname The new map's name. + * @return success state. + */ +static int map_addmap(const char *mapname) +{ map->list[map->count].instance_id = -1; mapindex->getmapname(mapname, map->list[map->count++].name); return 0; } -void map_delmapid(int id) { +/** + * Removes a map from the map list. + * + * @param id The map ID. + */ +static void map_delmapid(int id) +{ Assert_retv(id >= 0 && id < map->count); ShowNotice("Removing map [ %s ] from maplist"CL_CLL"\n",map->list[id].name); memmove(map->list+id, map->list+id+1, sizeof(map->list[0])*(map->count-id-1)); map->count--; } -int map_delmap(char* mapname) { +/** + * Removes a map fromt he map list. + * + * @param mapname The name of the map to remove. + * @return the number of removed maps. + */ +static int map_delmap(const char *mapname) +{ int i; char map_name[MAP_NAME_LENGTH]; @@ -3320,7 +3540,8 @@ int map_delmap(char* mapname) { /** * **/ -void map_zone_clear_single(struct map_zone_data *zone) { +static void map_zone_clear_single(struct map_zone_data *zone) +{ int i; nullpo_retv(zone); @@ -3362,7 +3583,7 @@ void map_zone_clear_single(struct map_zone_data *zone) { /** * **/ -void map_zone_db_clear(void) +static void map_zone_db_clear(void) { struct DBIterator *iter = db_iterator(map->zone_db); struct map_zone_data *zone = NULL; @@ -3380,24 +3601,29 @@ void map_zone_db_clear(void) /* clear the main zone stuff */ map->zone_clear_single(&map->zone_all); } -void map_clean(int i) { - int v; +static void map_clean(int i) +{ Assert_retv(i >= 0 && i < map->count); - if(map->list[i].cell && map->list[i].cell != (struct mapcell *)0xdeadbeaf) aFree(map->list[i].cell); - if(map->list[i].block) aFree(map->list[i].block); - if(map->list[i].block_mob) aFree(map->list[i].block_mob); - if(battle_config.dynamic_mobs) { //Dynamic mobs flag by [random] - int j; - if(map->list[i].mob_delete_timer != INVALID_TIMER) + if (map->list[i].cell && map->list[i].cell != (struct mapcell *)0xdeadbeaf) + aFree(map->list[i].cell); + if (map->list[i].block) + aFree(map->list[i].block); + if (map->list[i].block_mob) + aFree(map->list[i].block_mob); + + if (battle_config.dynamic_mobs != 0) { //Dynamic mobs flag by [random] + if (map->list[i].mob_delete_timer != INVALID_TIMER) timer->delete(map->list[i].mob_delete_timer, map->removemobs_timer); - for (j=0; j<MAX_MOB_LIST_PER_MAP; j++) - if (map->list[i].moblist[j]) aFree(map->list[i].moblist[j]); + for (int j = 0; j < MAX_MOB_LIST_PER_MAP; j++) { + if (map->list[i].moblist[j] != NULL) + aFree(map->list[i].moblist[j]); + } } - if( map->list[i].unit_count ) { - if( map->list[i].units ) { - for(v = 0; v < map->list[i].unit_count; v++) { + if (map->list[i].unit_count != 0) { + if (map->list[i].units != NULL) { + for (int v = 0; v < map->list[i].unit_count; v++) { aFree(map->list[i].units[v]); } aFree(map->list[i].units); @@ -3406,101 +3632,75 @@ void map_clean(int i) { map->list[i].unit_count = 0; } - if( map->list[i].skill_count ) { - if( map->list[i].skills ) { - for(v = 0; v < map->list[i].skill_count; v++) { - aFree(map->list[i].skills[v]); - } + if (map->list[i].skill_count != 0) { + if (map->list[i].skills != NULL) { + for (int v = 0; v < map->list[i].skill_count; v++) { + aFree(map->list[i].skills[v]); + } aFree(map->list[i].skills); map->list[i].skills = NULL; } map->list[i].skill_count = 0; } - if( map->list[i].zone_mf_count ) { - if( map->list[i].zone_mf ) { - for(v = 0; v < map->list[i].zone_mf_count; v++) { - aFree(map->list[i].zone_mf[v]); - } + if (map->list[i].zone_mf_count != 0) { + if (map->list[i].zone_mf != NULL) { + for (int v = 0; v < map->list[i].zone_mf_count; v++) { + aFree(map->list[i].zone_mf[v]); + } aFree(map->list[i].zone_mf); map->list[i].zone_mf = NULL; } map->list[i].zone_mf_count = 0; } - if( map->list[i].channel ) - channel->delete(map->list[i].channel); -} -void do_final_maps(void) { - int i, v = 0; - - for( i = 0; i < map->count; i++ ) { - - if(map->list[i].cell && map->list[i].cell != (struct mapcell *)0xdeadbeaf ) aFree(map->list[i].cell); - if(map->list[i].block) aFree(map->list[i].block); - if(map->list[i].block_mob) aFree(map->list[i].block_mob); + if (map->list[i].drop_list_count != 0) + map->list[i].drop_list_count = 0; + if (map->list[i].drop_list != NULL) + aFree(map->list[i].drop_list); - if(battle_config.dynamic_mobs) { //Dynamic mobs flag by [random] - int j; - if(map->list[i].mob_delete_timer != INVALID_TIMER) - timer->delete(map->list[i].mob_delete_timer, map->removemobs_timer); - for (j=0; j<MAX_MOB_LIST_PER_MAP; j++) - if (map->list[i].moblist[j]) aFree(map->list[i].moblist[j]); - } + if (map->list[i].channel != NULL) + channel->delete(map->list[i].channel); - if( map->list[i].unit_count ) { - if( map->list[i].units ) { - for(v = 0; v < map->list[i].unit_count; v++) { - aFree(map->list[i].units[v]); - } - aFree(map->list[i].units); - map->list[i].units = NULL; - } - map->list[i].unit_count = 0; - } + VECTOR_CLEAR(map->list[i].qi_list); + HPM->data_store_destroy(&map->list[i].hdata); +} +static void do_final_maps(void) +{ + for (int i = 0; i < map->count; i++) + map->clean(i); + map->zone_db_clear(); +} - if( map->list[i].skill_count ) { - if( map->list[i].skills ) { - for(v = 0; v < map->list[i].skill_count; v++) { - aFree(map->list[i].skills[v]); - } - aFree(map->list[i].skills); - map->list[i].skills = NULL; - } - map->list[i].skill_count = 0; - } +static void map_zonedb_reload(void) +{ + // first, reset maps to their initial zones: + for (int i = 0; i < map->count; i++) { + map->zone_remove_all(i); - if( map->list[i].zone_mf_count ) { - if( map->list[i].zone_mf ) { - for(v = 0; v < map->list[i].zone_mf_count; v++) { - aFree(map->list[i].zone_mf[v]); - } - aFree(map->list[i].zone_mf); - map->list[i].zone_mf = NULL; - } - map->list[i].zone_mf_count = 0; + if (battle_config.pk_mode) { + map->list[i].flag.pvp = 1; + map->list[i].zone = &map->zone_pk; + } else { + map->list[i].flag.pvp = 0; + map->list[i].zone = &map->zone_all; } - if( map->list[i].drop_list_count ) { - map->list[i].drop_list_count = 0; - } - if( map->list[i].drop_list != NULL ) - aFree(map->list[i].drop_list); - - if( map->list[i].channel ) - channel->delete(map->list[i].channel); - - if( map->list[i].qi_data ) - aFree(map->list[i].qi_data); - - HPM->data_store_destroy(&map->list[i].hdata); + map->list[i].prev_zone = map->list[i].zone; } + // now it's safe to remove the zones: map->zone_db_clear(); + // then reload everything from scratch: + map->zone_db = strdb_alloc(DB_OPT_DUP_KEY | DB_OPT_RELEASE_DATA, MAP_ZONE_NAME_LENGTH); + map->read_zone_db(); } + + /// Initializes map flags and adjusts them depending on configuration. -void map_flags_init(void) { +static void map_flags_init(void) +{ int i, v = 0; for( i = 0; i < map->count; i++ ) { @@ -3560,11 +3760,8 @@ void map_flags_init(void) { map->list[i].short_damage_rate = 100; map->list[i].long_damage_rate = 100; - if( map->list[i].qi_data ) - aFree(map->list[i].qi_data); - - map->list[i].qi_data = NULL; - map->list[i].qi_count = 0; + VECTOR_CLEAR(map->list[i].qi_list); + VECTOR_INIT(map->list[i].qi_list); } } @@ -3576,23 +3773,45 @@ void map_flags_init(void) { * Assumed path for file is data/mapname.rsw * Credits to LittleWolf */ -int map_waterheight(char* mapname) +static int map_waterheight(char *mapname) { char fn[256]; - char *rsw, *found; + char *rsw = NULL; + const char *found; nullpo_retr(NO_WATER, mapname); //Look up for the rsw snprintf(fn, sizeof(fn), "data\\%s.rsw", mapname); - if ( (found = grfio_find_file(fn)) ) + if ((found = grfio->find_file(fn))) safestrncpy(fn, found, sizeof(fn)); // replace with real name // read & convert fn - rsw = (char *) grfio_read (fn); + rsw = grfio_read(fn); if (rsw) { + if (memcmp(rsw, "GRSW", 4) != 0) { + ShowWarning("Failed to find water level for %s (%s)\n", mapname, fn); + aFree(rsw); + return NO_WATER; + } + int major_version = rsw[4]; + int minor_version = rsw[5]; + if (major_version > 2 || (major_version == 2 && minor_version > 2)) { + ShowWarning("Failed to find water level for %s (%s)\n", mapname, fn); + aFree(rsw); + return NO_WATER; + } + if (major_version < 1 || (major_version == 1 && minor_version <= 4)) { + ShowWarning("Failed to find water level for %s (%s)\n", mapname, fn); + aFree(rsw); + return NO_WATER; + } + int offset = 166; + if (major_version == 2 && minor_version >= 2) { + offset = 167; + } //Load water height from file - int wh = (int) *(float*)(rsw+166); + int wh = (int)*(float*)(rsw + offset); aFree(rsw); return wh; } @@ -3603,7 +3822,7 @@ int map_waterheight(char* mapname) /*================================== * .GAT format *----------------------------------*/ -int map_readgat (struct map_data* m) +static int map_readgat(struct map_data *m) { char filename[256]; uint8* gat; @@ -3613,7 +3832,7 @@ int map_readgat (struct map_data* m) nullpo_ret(m); sprintf(filename, "data\\%s.gat", m->name); - gat = (uint8 *) grfio_read(filename); + gat = grfio_read(filename); if (gat == NULL) return 0; @@ -3647,12 +3866,14 @@ int map_readgat (struct map_data* m) /*====================================== * Add/Remove map to the map_db *--------------------------------------*/ -void map_addmap2db(struct map_data *m) { +static void map_addmap2db(struct map_data *m) +{ nullpo_retv(m); map->index2mapid[m->index] = m->m; } -void map_removemapdb(struct map_data *m) { +static void map_removemapdb(struct map_data *m) +{ nullpo_retv(m); map->index2mapid[m->index] = -1; } @@ -3660,28 +3881,15 @@ void map_removemapdb(struct map_data *m) { /*====================================== * Initiate maps loading stage *--------------------------------------*/ -int map_readallmaps (void) { +static int map_readallmaps(void) +{ int i; - FILE* fp=NULL; int maps_removed = 0; - if( map->enable_grf ) + if (map->enable_grf) { ShowStatus("Loading maps (using GRF files)...\n"); - else { - char mapcachefilepath[254]; - sprintf(mapcachefilepath,"%s/%s%s",map->db_path,DBPATH,"map_cache.dat"); - ShowStatus("Loading maps (using %s as map cache)...\n", mapcachefilepath); - if( (fp = fopen(mapcachefilepath, "rb")) == NULL ) { - ShowFatalError("Unable to open map cache file "CL_WHITE"%s"CL_RESET"\n", mapcachefilepath); - exit(EXIT_FAILURE); //No use launching server if maps can't be read. - } - - // Init mapcache data.. [Shinryo] - map->cache_buffer = map->init_mapcache(fp); - if(!map->cache_buffer) { - ShowFatalError("Failed to initialize mapcache data (%s)..\n", mapcachefilepath); - exit(EXIT_FAILURE); - } + } else { + ShowStatus("Loading maps using map cache files...\n"); } for(i = 0; i < map->count; i++) { @@ -3695,7 +3903,7 @@ int map_readallmaps (void) { if( ! (map->enable_grf? map->readgat(&map->list[i]) - :map->readfromcache(&map->list[i], map->cache_buffer)) + :map->readfromcache(&map->list[i])) ) { map->delmapid(i); maps_removed++; @@ -3737,10 +3945,6 @@ int map_readallmaps (void) { // intialization and configuration-dependent adjustments of mapflags map->flags_init(); - if( !map->enable_grf ) { - fclose(fp); - } - // finished map loading ShowInfo("Successfully loaded '"CL_WHITE"%d"CL_RESET"' maps."CL_CLL"\n",map->count); instance->start_id = map->count; // Next Map Index will be instances @@ -3751,181 +3955,388 @@ int map_readallmaps (void) { return 0; } -/*========================================== - * Read map server configuration files (conf/map_server.conf...) - *------------------------------------------*/ -int map_config_read(char *cfgName) { - char line[1024], w1[1024], w2[1024]; - FILE *fp; +/** + * Reads 'map_configuration/console' and initializes required variables. + * + * @param filename Path to configuration file (used in error and warning messages). + * @param config The current config being parsed. + * @param imported Whether the current config is imported from another file. + * + * @retval false in case of error. + */ +static bool map_config_read_console(const char *filename, struct config_t *config, bool imported) +{ + struct config_setting_t *setting = NULL; - nullpo_retr(1, cfgName); + nullpo_retr(false, filename); + nullpo_retr(false, config); - fp = fopen(cfgName,"r"); - if( fp == NULL ) { - ShowError("Map configuration file not found at: %s\n", cfgName); - return 1; + if ((setting = libconfig->lookup(config, "map_configuration/console")) == NULL) { + if (imported) + return true; + ShowError("map_config_read: map_configuration/console was not found in %s!\n", filename); + return false; } - while (fgets(line, sizeof(line), fp)) { - char* ptr; + libconfig->setting_lookup_bool_real(setting, "stdout_with_ansisequence", &showmsg->stdout_with_ansisequence); + if (libconfig->setting_lookup_int(setting, "console_silent", &showmsg->silent) == CONFIG_TRUE) { + if (showmsg->silent) // only bother if its actually enabled + ShowInfo("Console Silent Setting: %d\n", showmsg->silent); + } + libconfig->setting_lookup_mutable_string(setting, "timestamp_format", showmsg->timestamp_format, sizeof(showmsg->timestamp_format)); + libconfig->setting_lookup_int(setting, "console_msg_log", &showmsg->console_log); - if (line[0] == '/' && line[1] == '/') - continue; - if ((ptr = strstr(line, "//")) != NULL) - *ptr = '\n'; //Strip comments - if (sscanf(line, "%1023[^:]: %1023[^\t\r\n]", w1, w2) < 2) - continue; + return true; +} - //Strip trailing spaces - ptr = w2 + strlen(w2); - while (--ptr >= w2 && *ptr == ' '); - ptr++; - *ptr = '\0'; - - if(strcmpi(w1,"timestamp_format")==0) - safestrncpy(showmsg->timestamp_format, w2, 20); - else if(strcmpi(w1,"stdout_with_ansisequence")==0) - showmsg->stdout_with_ansisequence = config_switch(w2) ? true : false; - else if(strcmpi(w1,"console_silent")==0) { - showmsg->silent = atoi(w2); - if (showmsg->silent) // only bother if its actually enabled - ShowInfo("Console Silent Setting: %d\n", atoi(w2)); - } else if (strcmpi(w1, "userid")==0) - chrif->setuserid(w2); - else if (strcmpi(w1, "passwd") == 0) - chrif->setpasswd(w2); - else if (strcmpi(w1, "char_ip") == 0) - map->char_ip_set = chrif->setip(w2); - else if (strcmpi(w1, "char_port") == 0) - chrif->setport(atoi(w2)); - else if (strcmpi(w1, "map_ip") == 0) - map->ip_set = clif->setip(w2); - else if (strcmpi(w1, "bind_ip") == 0) - clif->setbindip(w2); - else if (strcmpi(w1, "map_port") == 0) { - clif->setport(atoi(w2)); - map->port = (atoi(w2)); - } else if (strcmpi(w1, "map") == 0) - map->count++; - else if (strcmpi(w1, "delmap") == 0) - map->count--; - else if (strcmpi(w1, "npc") == 0) - npc->addsrcfile(w2); - else if (strcmpi(w1, "delnpc") == 0) - npc->delsrcfile(w2); - else if (strcmpi(w1, "autosave_time") == 0) { - map->autosave_interval = atoi(w2); - if (map->autosave_interval < 1) //Revert to default saving. - map->autosave_interval = DEFAULT_AUTOSAVE_INTERVAL; - else - map->autosave_interval *= 1000; //Pass from sec to ms - } else if (strcmpi(w1, "minsave_time") == 0) { - map->minsave_interval= atoi(w2); - if (map->minsave_interval < 1) - map->minsave_interval = 1; - } else if (strcmpi(w1, "save_settings") == 0) - map->save_settings = atoi(w2); - else if (strcmpi(w1, "help_txt") == 0) - strcpy(map->help_txt, w2); - else if (strcmpi(w1, "help2_txt") == 0) - strcpy(map->help2_txt, w2); - else if (strcmpi(w1, "charhelp_txt") == 0) - strcpy(map->charhelp_txt, w2); - else if(strcmpi(w1,"db_path") == 0) - safestrncpy(map->db_path,w2,255); - else if (strcmpi(w1, "enable_spy") == 0) - map->enable_spy = config_switch(w2); - else if (strcmpi(w1, "use_grf") == 0) - map->enable_grf = config_switch(w2); - else if (strcmpi(w1, "console_msg_log") == 0) - showmsg->console_log = atoi(w2);//[Ind] - else if (strcmpi(w1, "default_language") == 0) - safestrncpy(map->default_lang_str, w2, sizeof(map->default_lang_str)); - else if (strcmpi(w1, "import") == 0) - map->config_read(w2); +/** + * Reads 'map_configuration/sql_connection' and initializes required variables. + * + * @param filename Path to configuration file (used in error and warning messages). + * @param config The current config being parsed. + * @param imported Whether the current config is imported from another file. + * + * @retval false in case of error. + */ +static bool map_config_read_connection(const char *filename, struct config_t *config, bool imported) +{ + struct config_setting_t *setting = NULL; + + nullpo_retr(false, filename); + nullpo_retr(false, config); + + if ((setting = libconfig->lookup(config, "map_configuration/sql_connection")) == NULL) { + if (imported) + return true; + ShowError("map_config_read: map_configuration/sql_connection was not found in %s!\n", filename); + ShowWarning("map_config_read_connection: Defaulting sql_connection...\n"); + return false; + } + + libconfig->setting_lookup_int(setting, "db_port", &map->server_port); + libconfig->setting_lookup_mutable_string(setting, "db_hostname", map->server_ip, sizeof(map->server_ip)); + libconfig->setting_lookup_mutable_string(setting, "db_username", map->server_id, sizeof(map->server_id)); + libconfig->setting_lookup_mutable_string(setting, "db_password", map->server_pw, sizeof(map->server_pw)); + libconfig->setting_lookup_mutable_string(setting, "db_database", map->server_db, sizeof(map->server_db)); + libconfig->setting_lookup_mutable_string(setting, "default_codepage", map->default_codepage, sizeof(map->default_codepage)); + return true; +} + +/** + * Reads 'map_configuration/inter' and initializes required variables. + * + * @param filename Path to configuration file (used in error and warning messages). + * @param config The current config being parsed. + * @param imported Whether the current config is imported from another file. + * + * @retval false in case of error. + */ +static bool map_config_read_inter(const char *filename, struct config_t *config, bool imported) +{ + struct config_setting_t *setting = NULL; + const char *str = NULL; + char temp[24]; + uint16 port; + + nullpo_retr(false, filename); + nullpo_retr(false, config); + + if ((setting = libconfig->lookup(config, "map_configuration/inter")) == NULL) { + if (imported) + return true; + ShowError("map_config_read: map_configuration/inter was not found in %s!\n", filename); + return false; + } + + // Login information + if (libconfig->setting_lookup_mutable_string(setting, "userid", temp, sizeof(temp)) == CONFIG_TRUE) + chrif->setuserid(temp); + if (libconfig->setting_lookup_mutable_string(setting, "passwd", temp, sizeof(temp)) == CONFIG_TRUE) + chrif->setpasswd(temp); + + // Char and map-server information + if (libconfig->setting_lookup_string(setting, "char_ip", &str) == CONFIG_TRUE) + map->char_ip_set = chrif->setip(str); + if (libconfig->setting_lookup_uint16(setting, "char_port", &port) == CONFIG_TRUE) + chrif->setport(port); + + if (libconfig->setting_lookup_string(setting, "map_ip", &str) == CONFIG_TRUE) + map->ip_set = clif->setip(str); + if (libconfig->setting_lookup_uint16(setting, "map_port", &port) == CONFIG_TRUE) { + clif->setport(port); + map->port = port; + } + if (libconfig->setting_lookup_string(setting, "bind_ip", &str) == CONFIG_TRUE) + clif->setbindip(str); + + return true; +} + +/** + * Reads 'map_configuration/database' and initializes required variables + * + * @param filename Path to configuration file (used in error and warning messages). + * @param config The current config being parsed. + * @param imported Whether the current config is imported from another file. + * + * @retval false in case of error. + */ +static bool map_config_read_database(const char *filename, struct config_t *config, bool imported) +{ + struct config_setting_t *setting = NULL; + + nullpo_retr(false, filename); + nullpo_retr(false, config); + + if ((setting = libconfig->lookup(config, "map_configuration/database")) == NULL) { + if (imported) + return true; + ShowError("map_config_read: map_configuration/database was not found in %s!\n", filename); + return false; + } + libconfig->setting_lookup_mutable_string(setting, "db_path", map->db_path, sizeof(map->db_path)); + libconfig->set_db_path(map->db_path); + libconfig->setting_lookup_int(setting, "save_settings", &map->save_settings); + + if (libconfig->setting_lookup_int(setting, "autosave_time", &map->autosave_interval) == CONFIG_TRUE) { + if (map->autosave_interval < 1) // Revert to default saving + map->autosave_interval = DEFAULT_AUTOSAVE_INTERVAL; else - ShowWarning("Unknown setting '%s' in file %s\n", w1, cfgName); + map->autosave_interval *= 1000; // Pass from s to ms + } + if (libconfig->setting_lookup_int(setting, "minsave_time", &map->minsave_interval) == CONFIG_TRUE) { + if (map->minsave_interval < 1) + map->minsave_interval = 1; } - fclose(fp); - return 0; + return true; } -int map_config_read_sub(char *cfgName) { - char line[1024], w1[1024], w2[1024]; - FILE *fp; - nullpo_retr(1, cfgName); - fp = fopen(cfgName,"r"); - if (fp == NULL) { - ShowError("Map configuration file not found at: %s\n", cfgName); - return 1; +/** + * Reads 'map_configuration/map_list'/'map_configuration/map_removed' and adds + * or removes maps from map-server. + * + * @param filename Path to configuration file (used in error and warning messages). + * @param config The current config being parsed. + * @param imported Whether the current config is imported from another file. + * + * @retval false in case of error. + */ +static bool map_config_read_map_list(const char *filename, struct config_t *config, bool imported) +{ + struct config_setting_t *setting = NULL; + int i, count = 0; + struct DBMap *deleted_maps; + + nullpo_retr(false, filename); + nullpo_retr(false, config); + + deleted_maps = strdb_alloc(DB_OPT_DUP_KEY|DB_OPT_ALLOW_NULL_DATA, MAP_NAME_LENGTH); + + // Remove maps + if ((setting = libconfig->lookup(config, "map_configuration/map_removed")) != NULL) { + count = libconfig->setting_length(setting); + for (i = 0; i < count; i++) { + const char *mapname; + + if ((mapname = libconfig->setting_get_string_elem(setting, i)) == NULL || mapname[0] == '\0') + continue; + + strdb_put(deleted_maps, mapname, NULL); + + if (imported) // Map list is empty on the first run, only do this for imported files. + map->delmap(mapname); + } + } + + if ((setting = libconfig->lookup(config, "map_configuration/map_list")) == NULL) { + db_destroy(deleted_maps); + if (imported) + return true; + ShowError("map_config_read_map_list: map_configuration/map_list was not found in %s!\n", filename); + return false; } - while (fgets(line, sizeof(line), fp)) { - char* ptr; + // Add maps to map->list + count = libconfig->setting_length(setting); - if (line[0] == '/' && line[1] == '/') + if (count <= 0) { + db_destroy(deleted_maps); + if (imported) + return true; + ShowWarning("map_config_read_map_list: no maps found in %s!\n", filename); + return false; + } + + RECREATE(map->list, struct map_data, map->count + count); // TODO: VECTOR candidate + + for (i = 0; i < count; i++) { + const char *mapname; + + if ((mapname = libconfig->setting_get_string_elem(setting, i)) == NULL || mapname[0] == '\0') continue; - if ((ptr = strstr(line, "//")) != NULL) - *ptr = '\n'; //Strip comments - if (sscanf(line, "%1023[^:]: %1023[^\t\r\n]", w1, w2) < 2) + + if (strdb_exists(deleted_maps, mapname)) continue; - //Strip trailing spaces - ptr = w2 + strlen(w2); - while (--ptr >= w2 && *ptr == ' '); - ptr++; - *ptr = '\0'; + map->addmap(mapname); + } + + RECREATE(map->list, struct map_data, map->count); + + db_destroy(deleted_maps); + return true; +} + +/** + * Reads map-server configuration files (map-server.conf) and initialises + * required variables. + * + * @param filename Path to configuration file. + * @param imported Whether the current config is imported from another file. + * + * @retval false in case of error. + */ +static bool map_config_read(const char *filename, bool imported) +{ + struct config_t config; + struct config_setting_t *setting = NULL; + const char *import = NULL; + bool retval = true; + + nullpo_retr(false, filename); - if (strcmpi(w1, "map") == 0) - map->addmap(w2); - else if (strcmpi(w1, "delmap") == 0) - map->delmap(w2); - else if (strcmpi(w1, "import") == 0) - map->config_read_sub(w2); + if (!libconfig->load_file(&config, filename)) + return false; + + if ((setting = libconfig->lookup(&config, "map_configuration")) == NULL) { + libconfig->destroy(&config); + if (imported) + return true; + ShowError("map_config_read: map_configuration was not found in %s!\n", filename); + return false; } - fclose(fp); - return 0; + libconfig->setting_lookup_mutable_string(setting, "help_txt", map->help_txt, sizeof(map->help_txt)); + libconfig->setting_lookup_mutable_string(setting, "charhelp_txt", map->charhelp_txt, sizeof(map->charhelp_txt)); + libconfig->setting_lookup_bool(setting, "enable_spy", &map->enable_spy); + libconfig->setting_lookup_bool(setting, "use_grf", &map->enable_grf); + libconfig->setting_lookup_mutable_string(setting, "default_language", map->default_lang_str, sizeof(map->default_lang_str)); + + if (!map_config_read_console(filename, &config, imported)) + retval = false; + if (!map_config_read_connection(filename, &config, imported)) + retval = false; + if (!map_config_read_inter(filename, &config, imported)) + retval = false; + if (!map_config_read_database(filename, &config, imported)) + retval = false; + if (!map_config_read_map_list(filename, &config, imported)) + retval = false; + + // import should overwrite any previous configuration, so it should be called last + if (libconfig->lookup_string(&config, "import", &import) == CONFIG_TRUE) { + if (strcmp(import, filename) == 0 || strcmp(import, map->MAP_CONF_NAME) == 0) { + ShowWarning("map_config_read: Loop detected! Skipping 'import'...\n"); + } else { + if (!map->config_read(import, true)) + retval = false; + } + } + + libconfig->destroy(&config); + return retval; } -void map_reloadnpc_sub(char *cfgName) { - char line[1024], w1[1024], w2[1024]; - FILE *fp; - nullpo_retv(cfgName); - fp = fopen(cfgName,"r"); - if (fp == NULL) { - ShowError("Map configuration file not found at: %s\n", cfgName); - return; +/** + * Reads 'npc_global_list'/'npc_removed_list' and adds or removes NPC sources + * from map-server. + * + * @param filename Path to configuration file (used in error and warning messages). + * @param imported Whether the current config is imported from another file. + * + * @retval false in case of error. + */ +static bool map_read_npclist(const char *filename, bool imported) +{ + struct config_t config; + struct config_setting_t *setting = NULL; + const char *import = NULL; + bool retval = true; + bool remove_all = false; + + struct DBMap *deleted_npcs; + + nullpo_retr(false, filename); + + if (!libconfig->load_file(&config, filename)) + return false; + + deleted_npcs = strdb_alloc(DB_OPT_DUP_KEY|DB_OPT_ALLOW_NULL_DATA, 0); + + // Remove NPCs + if ((setting = libconfig->lookup(&config, "npc_removed_list")) != NULL) { + int i, del_count = libconfig->setting_length(setting); + for (i = 0; i < del_count; i++) { + const char *scriptname; + + if ((scriptname = libconfig->setting_get_string_elem(setting, i)) == NULL || scriptname[0] == '\0') + continue; + + if (strcmp(scriptname, "all") == 0) { + remove_all = true; + npc->clearsrcfile(); + } else { + strdb_put(deleted_npcs, scriptname, NULL); + npc->delsrcfile(scriptname); + } + } } - while (fgets(line, sizeof(line), fp)) { - char* ptr; + if ((setting = libconfig->lookup(&config, "npc_global_list")) != NULL) { + int i, count = libconfig->setting_length(setting); + if (count <= 0) { + if (!imported) { + ShowWarning("map_read_npclist: no NPCs found in %s!\n", filename); + retval = false; + } + } + for (i = 0; i < count; i++) { + const char *scriptname; - if (line[0] == '/' && line[1] == '/') - continue; - if ((ptr = strstr(line, "//")) != NULL) - *ptr = '\n'; //Strip comments - if (sscanf(line, "%1023[^:]: %1023[^\t\r\n]", w1, w2) < 2) - continue; + if ((scriptname = libconfig->setting_get_string_elem(setting, i)) == NULL || scriptname[0] == '\0') + continue; - //Strip trailing spaces - ptr = w2 + strlen(w2); - while (--ptr >= w2 && *ptr == ' '); - ptr++; - *ptr = '\0'; - - if (strcmpi(w1, "npc") == 0) - npc->addsrcfile(w2); - else if (strcmpi(w1, "import") == 0) - map->reloadnpc_sub(w2); - else if (strcmpi(w1, "delnpc") == 0) - npc->delsrcfile(w2); - else - ShowWarning("Unknown setting '%s' in file %s\n", w1, cfgName); + if (remove_all || strdb_exists(deleted_npcs, scriptname)) + continue; + + npc->addsrcfile(scriptname); + } + } else { + ShowError("map_read_npclist: npc_global_list was not found in %s!\n", filename); + retval = false; } - fclose(fp); + db_destroy(deleted_npcs); + + // import should overwrite any previous configuration, so it should be called last + if (libconfig->lookup_string(&config, "import", &import) == CONFIG_TRUE) { + const char *base_npclist = NULL; +#ifdef RENEWAL + base_npclist = "npc/re/scripts_main.conf"; +#else + base_npclist = "npc/pre-re/scripts_main.conf"; +#endif + if (strcmp(import, filename) == 0 || strcmp(import, base_npclist) == 0) { + ShowWarning("map_read_npclist: Loop detected! Skipping 'import'...\n"); + } else { + if (!map->read_npclist(import, true)) + retval = false; + } + } + + libconfig->destroy(&config); + return retval; } /** @@ -3933,15 +4344,16 @@ void map_reloadnpc_sub(char *cfgName) { * * @param clear whether to clear the script list before reloading. */ -void map_reloadnpc(bool clear) { +static void map_reloadnpc(bool clear) +{ int i; if (clear) - npc->addsrcfile("clear"); // this will clear the current script list + npc->clearsrcfile(); #ifdef RENEWAL - map->reloadnpc_sub("npc/re/scripts_main.conf"); + map->read_npclist("npc/re/scripts_main.conf", false); #else - map->reloadnpc_sub("npc/pre-re/scripts_main.conf"); + map->read_npclist("npc/pre-re/scripts_main.conf", false); #endif // Append extra scripts @@ -3950,69 +4362,134 @@ void map_reloadnpc(bool clear) { } } -int inter_config_read(char *cfgName) { - char line[1024],w1[1024],w2[1024]; - FILE *fp; +/** + * Reads inter-server.conf and initializes required variables. + * + * @param filename Path to configuration file + * @param imported Whether the current config is imported from another file. + * + * @retval false in case of error. + */ +static bool inter_config_read(const char *filename, bool imported) +{ + struct config_t config; + const struct config_setting_t *setting = NULL; + const char *import = NULL; + bool retval = true; - nullpo_retr(1, cfgName); - if (!(fp = fopen(cfgName,"r"))) { - ShowError("File not found: %s\n",cfgName); - return 1; + nullpo_retr(false, filename); + + if (!libconfig->load_file(&config, filename)) + return false; + + if ((setting = libconfig->lookup(&config, "inter_configuration")) == NULL) { + libconfig->destroy(&config); + if (imported) + return true; + ShowError("inter_config_read: inter_configuration was not found in %s!\n", filename); + return false; } - while (fgets(line, sizeof(line), fp)) { - if (line[0] == '/' && line[1] == '/') - continue; - if (sscanf(line,"%1023[^:]: %1023[^\r\n]", w1, w2) < 2) - continue; - /* map sql stuff */ - if(strcmpi(w1,"map_server_ip")==0) - safestrncpy(map->server_ip, w2, sizeof(map->server_ip)); - else if(strcmpi(w1,"map_server_port")==0) - map->server_port=atoi(w2); - else if(strcmpi(w1,"map_server_id")==0) - safestrncpy(map->server_id, w2, sizeof(map->server_id)); - else if(strcmpi(w1,"map_server_pw")==0) - safestrncpy(map->server_pw, w2, sizeof(map->server_pw)); - else if(strcmpi(w1,"map_server_db")==0) - safestrncpy(map->server_db, w2, sizeof(map->server_db)); - else if(strcmpi(w1,"default_codepage")==0) - safestrncpy(map->default_codepage, w2, sizeof(map->default_codepage)); - else if(strcmpi(w1,"autotrade_merchants_db")==0) - safestrncpy(map->autotrade_merchants_db, w2, sizeof(map->autotrade_merchants_db)); - else if(strcmpi(w1,"autotrade_data_db")==0) - safestrncpy(map->autotrade_data_db, w2, sizeof(map->autotrade_data_db)); - else if(strcmpi(w1,"npc_market_data_db")==0) - safestrncpy(map->npc_market_data_db, w2, sizeof(map->npc_market_data_db)); - /* sql log db */ - else if(strcmpi(w1,"log_db_ip")==0) - safestrncpy(logs->db_ip, w2, sizeof(logs->db_ip)); - else if(strcmpi(w1,"log_db_id")==0) - safestrncpy(logs->db_id, w2, sizeof(logs->db_id)); - else if(strcmpi(w1,"log_db_pw")==0) - safestrncpy(logs->db_pw, w2, sizeof(logs->db_pw)); - else if(strcmpi(w1,"log_db_port")==0) - logs->db_port = atoi(w2); - else if(strcmpi(w1,"log_db_db")==0) - safestrncpy(logs->db_name, w2, sizeof(logs->db_name)); - /* mapreg */ - else if( mapreg->config_read(w1,w2) ) - continue; - /* import */ - else if(strcmpi(w1,"import")==0) - map->inter_config_read(w2); - else - HPM->parseConf(w1, w2, HPCT_MAP_INTER); + if (!map->inter_config_read_database_names(filename, &config, imported)) + retval = false; + if (!map->inter_config_read_connection(filename, &config, imported)) + retval = false; + + if (!HPM->parse_conf(&config, filename, HPCT_MAP_INTER, imported)) + retval = false; + + // import should overwrite any previous configuration, so it should be called last + if (libconfig->lookup_string(&config, "import", &import) == CONFIG_TRUE) { + if (strcmp(import, filename) == 0 || strcmp(import, map->INTER_CONF_NAME) == 0) { + ShowWarning("inter_config_read: Loop detected in %s! Skipping 'import'...\n", filename); + } else { + if (!map->inter_config_read(import, true)) + retval = false; + } } - fclose(fp); - return 0; + libconfig->destroy(&config); + return retval; +} + +/** + * Reads the 'inter_configuration/log/sql_connection' config entry and initializes required variables. + * + * @param filename Path to configuration file (used in error and warning messages). + * @param config The current config being parsed. + * @param imported Whether the current config is imported from another file. + * + * @retval false in case of error. + */ +static bool inter_config_read_connection(const char *filename, const struct config_t *config, bool imported) +{ + const struct config_setting_t *setting = NULL; + + nullpo_retr(false, filename); + nullpo_retr(false, config); + + if ((setting = libconfig->lookup(config, "inter_configuration/log/sql_connection")) == NULL) { + if (imported) + return true; + ShowError("inter_config_read: inter_configuration/log/sql_connection was not found in %s!\n", filename); + return false; + } + + libconfig->setting_lookup_int(setting, "db_port", &logs->db_port); + libconfig->setting_lookup_mutable_string(setting, "db_hostname", logs->db_ip, sizeof(logs->db_ip)); + libconfig->setting_lookup_mutable_string(setting, "db_username", logs->db_id, sizeof(logs->db_id)); + libconfig->setting_lookup_mutable_string(setting, "db_password", logs->db_pw, sizeof(logs->db_pw)); + libconfig->setting_lookup_mutable_string(setting, "db_database", logs->db_name, sizeof(logs->db_name)); + + return true; +} + +/** + * Reads the 'inter_configuration/database_names' config entry and initializes required variables. + * + * @param filename Path to configuration file (used in error and warning messages). + * @param config The current config being parsed. + * @param imported Whether the current config is imported from another file. + * + * @retval false in case of error. + */ +static bool inter_config_read_database_names(const char *filename, const struct config_t *config, bool imported) +{ + const struct config_setting_t *setting = NULL; + bool retval = true; + + nullpo_retr(false, filename); + nullpo_retr(false, config); + + if ((setting = libconfig->lookup(config, "inter_configuration/database_names")) == NULL) { + if (imported) + return true; + ShowError("inter_config_read: inter_configuration/database_names was not found in %s!\n", filename); + return false; + } + + libconfig->setting_lookup_mutable_string(setting, "autotrade_merchants_db", map->autotrade_merchants_db, sizeof(map->autotrade_merchants_db)); + libconfig->setting_lookup_mutable_string(setting, "autotrade_data_db", map->autotrade_data_db, sizeof(map->autotrade_data_db)); + libconfig->setting_lookup_mutable_string(setting, "npc_market_data_db", map->npc_market_data_db, sizeof(map->npc_market_data_db)); + libconfig->setting_lookup_mutable_string(setting, "npc_barter_data_db", map->npc_barter_data_db, sizeof(map->npc_barter_data_db)); + libconfig->setting_lookup_mutable_string(setting, "npc_expanded_barter_data_db", map->npc_expanded_barter_data_db, sizeof(map->npc_expanded_barter_data_db)); + + if (!mapreg->config_read(filename, setting, imported)) + retval = false; + + if ((setting = libconfig->lookup(config, "inter_configuration/database_names/registry")) == NULL) { + if (imported) + return retval; + ShowError("inter_config_read: inter_configuration/database_names/registry was not found in %s!\n", filename); + return false; + } + return retval; } /*======================================= * MySQL Init *---------------------------------------*/ -int map_sql_init(void) +static int map_sql_init(void) { // main db connection map->mysql_handle = SQL->Malloc(); @@ -4029,7 +4506,7 @@ int map_sql_init(void) return 0; } -int map_sql_close(void) +static int map_sql_close(void) { ShowStatus("Close Map DB Connection....\n"); SQL->Free(map->mysql_handle); @@ -4047,7 +4524,8 @@ int map_sql_close(void) * * @return the newly created zone from merging main and other **/ -struct map_zone_data *map_merge_zone(struct map_zone_data *main, struct map_zone_data *other) { +static struct map_zone_data *map_merge_zone(struct map_zone_data *main, struct map_zone_data *other) +{ char newzone[MAP_ZONE_NAME_LENGTH]; struct map_zone_data *zone = NULL; int cursor, i, j; @@ -4055,7 +4533,7 @@ struct map_zone_data *map_merge_zone(struct map_zone_data *main, struct map_zone nullpo_retr(NULL, main); nullpo_retr(NULL, other); - sprintf(newzone, "%s+%s",main->name,other->name); + safesnprintf(newzone, MAP_ZONE_NAME_LENGTH, "%s+%s", main->name, other->name); if( (zone = strdb_get(map->zone_db, newzone)) ) return zone;/* this zone has already been merged */ @@ -4144,10 +4622,12 @@ struct map_zone_data *map_merge_zone(struct map_zone_data *main, struct map_zone return zone; } -void map_zone_change2(int m, struct map_zone_data *zone) +static void map_zone_change2(int m, struct map_zone_data *zone) { const char *empty = ""; + if (zone == NULL) + return; Assert_retv(m >= 0 && m < map->count); if( map->list[m].zone == zone ) return; @@ -4165,7 +4645,8 @@ void map_zone_change2(int m, struct map_zone_data *zone) map->zone_apply(m,zone,empty,empty,empty); } /* when changing from a mapflag to another during runtime */ -void map_zone_change(int m, struct map_zone_data *zone, const char* start, const char* buffer, const char* filepath) { +static void map_zone_change(int m, struct map_zone_data *zone, const char *start, const char *buffer, const char *filepath) +{ Assert_retv(m >= 0 && m < map->count); map->list[m].prev_zone = map->list[m].zone; @@ -4174,7 +4655,7 @@ void map_zone_change(int m, struct map_zone_data *zone, const char* start, const map->zone_apply(m,zone,start,buffer,filepath); } /* removes previous mapflags from this map */ -void map_zone_remove(int m) +static void map_zone_remove(int m) { char flag[MAP_ZONE_MAPFLAG_LENGTH], params[MAP_ZONE_MAPFLAG_LENGTH]; unsigned short k; @@ -4201,7 +4682,29 @@ void map_zone_remove(int m) map->list[m].zone_mf = NULL; map->list[m].zone_mf_count = 0; } -static inline void map_zone_mf_cache_add(int m, char *rflag) { +// this one removes every flag, even if they were previously turned on before +// the current zone was applied +static void map_zone_remove_all(int m) +{ + Assert_retv(m >= 0 && m < map->count); + + for (unsigned short k = 0; k < map->list[m].zone_mf_count; k++) { + char flag[MAP_ZONE_MAPFLAG_LENGTH]; + + memcpy(flag, map->list[m].zone_mf[k], MAP_ZONE_MAPFLAG_LENGTH); + strtok(flag, "\t"); + + npc->parse_mapflag(map->list[m].name, "", flag, "off", "", "", "", NULL); + aFree(map->list[m].zone_mf[k]); + map->list[m].zone_mf[k] = NULL; + } + + aFree(map->list[m].zone_mf); + map->list[m].zone_mf = NULL; + map->list[m].zone_mf_count = 0; +} +static inline void map_zone_mf_cache_add(int m, char *rflag) +{ Assert_retv(m >= 0 && m < map->count); RECREATE(map->list[m].zone_mf, char *, ++map->list[m].zone_mf_count); CREATE(map->list[m].zone_mf[map->list[m].zone_mf_count - 1], char, MAP_ZONE_MAPFLAG_LENGTH); @@ -4209,7 +4712,8 @@ static inline void map_zone_mf_cache_add(int m, char *rflag) { } /* TODO: introduce enumerations to each mapflag so instead of reading the string a number of times we read it only once and use its value wherever we need */ /* cache previous values to revert */ -bool map_zone_mf_cache(int m, char *flag, char *params) { +static bool map_zone_mf_cache(int m, char *flag, char *params) +{ char rflag[MAP_ZONE_MAPFLAG_LENGTH]; int state = 1; @@ -4465,6 +4969,15 @@ bool map_zone_mf_cache(int m, char *flag, char *params) { else if( map->list[m].flag.battleground ) map_zone_mf_cache_add(m,"battleground"); } + } else if (!strcmpi(flag,"cvc")) { + if (state && map->list[m].flag.cvc) { + ;/* nothing to do */ + } else { + if (state) + map_zone_mf_cache_add(m,"cvc\toff"); + else if (map->list[m].flag.cvc) + map_zone_mf_cache_add(m,"cvc"); + } } else if (!strcmpi(flag,"noexppenalty")) { if( state && map->list[m].flag.noexppenalty ) ;/* nothing to do */ @@ -4737,11 +5250,12 @@ bool map_zone_mf_cache(int m, char *flag, char *params) { } } else if (!strcmpi(flag,"adjust_unit_duration")) { int skill_id, k; - char skill_name[MAP_ZONE_MAPFLAG_LENGTH], modifier[MAP_ZONE_MAPFLAG_LENGTH]; - size_t len = strlen(params); + char skill_name[MAX_SKILL_NAME_LENGTH], modifier[MAP_ZONE_MAPFLAG_LENGTH]; + size_t len; modifier[0] = '\0'; - memcpy(skill_name, params, MAP_ZONE_MAPFLAG_LENGTH); + safestrncpy(skill_name, params, MAX_SKILL_NAME_LENGTH); + len = strlen(skill_name); for(k = 0; k < len; k++) { if( skill_name[k] == '\t' ) { @@ -4770,11 +5284,12 @@ bool map_zone_mf_cache(int m, char *flag, char *params) { } } else if (!strcmpi(flag,"adjust_skill_damage")) { int skill_id, k; - char skill_name[MAP_ZONE_MAPFLAG_LENGTH], modifier[MAP_ZONE_MAPFLAG_LENGTH]; - size_t len = strlen(params); + char skill_name[MAX_SKILL_NAME_LENGTH], modifier[MAP_ZONE_MAPFLAG_LENGTH]; + size_t len; modifier[0] = '\0'; - memcpy(skill_name, params, MAP_ZONE_MAPFLAG_LENGTH); + safestrncpy(skill_name, params, MAX_SKILL_NAME_LENGTH); + len = strlen(skill_name); for(k = 0; k < len; k++) { if( skill_name[k] == '\t' ) { @@ -4904,11 +5419,37 @@ bool map_zone_mf_cache(int m, char *flag, char *params) { else if( map->list[m].flag.nocashshop ) map_zone_mf_cache_add(m,"nocashshop"); } + } else if (strcmpi(flag, "nostorage") == 0) { + if (!state) { + if (map->list[m].flag.nostorage != 0) { + sprintf(rflag, "nostorage\t%d", map->list[m].flag.nostorage); + map_zone_mf_cache_add(m, rflag); + } + } + if (sscanf(params, "%d", &state) == 1) { + if (state != map->list[m].flag.nostorage) { + sprintf(rflag, "nostorage\t%d", state); + map_zone_mf_cache_add(m, rflag); + } + } + } else if (strcmpi(flag, "nogstorage") == 0) { + if (!state) { + if (map->list[m].flag.nogstorage != 0) { + sprintf(rflag, "nogstorage\t%d", map->list[m].flag.nogstorage); + map_zone_mf_cache_add(m, rflag); + } + } + if (sscanf(params, "%d", &state) == 1) { + if (state != map->list[m].flag.nogstorage) { + sprintf(rflag, "nogstorage\t%d", state); + map_zone_mf_cache_add(m, rflag); + } + } } return false; } -void map_zone_apply(int m, struct map_zone_data *zone, const char* start, const char* buffer, const char* filepath) +static void map_zone_apply(int m, struct map_zone_data *zone, const char *start, const char *buffer, const char *filepath) { int i; const char *empty = ""; @@ -4936,7 +5477,7 @@ void map_zone_apply(int m, struct map_zone_data *zone, const char* start, const } } /* used on npc load and reload to apply all "Normal" and "PK Mode" zones */ -void map_zone_init(void) +static void map_zone_init(void) { char flag[MAP_ZONE_MAPFLAG_LENGTH], params[MAP_ZONE_MAPFLAG_LENGTH]; struct map_zone_data *zone; @@ -4990,12 +5531,13 @@ void map_zone_init(void) } } -unsigned short map_zone_str2itemid(const char *name) { +static int map_zone_str2itemid(const char *name) +{ struct item_data *data; if( !name ) return 0; - if( name[0] == 'I' && name[1] == 'D' && strlen(name) < 8 ) { + if (name[0] == 'I' && name[1] == 'D' && strlen(name) <= 12) { if( !( data = itemdb->exists(atoi(name+2))) ) { return 0; } @@ -5006,13 +5548,14 @@ unsigned short map_zone_str2itemid(const char *name) { } return data->nameid; } -unsigned short map_zone_str2skillid(const char *name) { +static unsigned short map_zone_str2skillid(const char *name) +{ unsigned short nameid = 0; if( !name ) return 0; - if( name[0] == 'I' && name[1] == 'D' && strlen(name) < 8 ) { + if (name[0] == 'I' && name[1] == 'D' && strlen(name) <= 12) { if( !skill->get_index((nameid = atoi(name+2))) ) return 0; } else { @@ -5022,7 +5565,8 @@ unsigned short map_zone_str2skillid(const char *name) { } return nameid; } -enum bl_type map_zone_bl_type(const char *entry, enum map_zone_skill_subtype *subtype) { +static enum bl_type map_zone_bl_type(const char *entry, enum map_zone_skill_subtype *subtype) +{ char temp[200], *parse; enum bl_type bl = BL_NUL; @@ -5068,15 +5612,12 @@ enum bl_type map_zone_bl_type(const char *entry, enum map_zone_skill_subtype *su return bl; } /* [Ind/Hercules] */ -void read_map_zone_db(void) { +static void read_map_zone_db(void) +{ struct config_t map_zone_db; struct config_setting_t *zones = NULL; - /* TODO: #ifndef required for re/pre-re */ -#ifdef RENEWAL - const char *config_filename = "db/re/map_zone_db.conf"; // FIXME hardcoded name -#else - const char *config_filename = "db/pre-re/map_zone_db.conf"; // FIXME hardcoded name -#endif + char config_filename[256]; + libconfig->format_db_path(DBPATH"map_zone_db.conf", config_filename, sizeof(config_filename)); if (!libconfig->load_file(&map_zone_db, config_filename)) return; @@ -5489,45 +6030,46 @@ void read_map_zone_db(void) { zone->merge_type = MZMT_MERGEABLE; if( (zone = strdb_get(map->zone_db, MAP_ZONE_BG_NAME)) ) zone->merge_type = MZMT_MERGEABLE; + if ((zone = strdb_get(map->zone_db, MAP_ZONE_CVC_NAME))) + zone->merge_type = MZMT_MERGEABLE; } /* not supposed to go in here but in skill_final whatever */ libconfig->destroy(&map_zone_db); } -int map_get_new_bonus_id (void) { +static int map_get_new_bonus_id(void) +{ return map->bonus_id++; } -void map_add_questinfo(int m, struct questinfo *qi) { - unsigned short i; +static bool map_add_questinfo(int m, struct npc_data *nd) +{ + nullpo_retr(false, nd); + Assert_retr(false, m >= 0 && m < map->count); - nullpo_retv(qi); - Assert_retv(m >= 0 && m < map->count); - /* duplicate, override */ - for(i = 0; i < map->list[m].qi_count; i++) { - if( map->list[m].qi_data[i].nd == qi->nd ) - break; - } + int i; + ARR_FIND(0, VECTOR_LENGTH(map->list[m].qi_list), i, VECTOR_INDEX(map->list[m].qi_list, i) == nd); - if( i == map->list[m].qi_count ) - RECREATE(map->list[m].qi_data, struct questinfo, ++map->list[m].qi_count); + if (i < VECTOR_LENGTH(map->list[m].qi_list)) { + return false; + } - memcpy(&map->list[m].qi_data[i], qi, sizeof(struct questinfo)); + VECTOR_ENSURE(map->list[m].qi_list, 1, 1); + VECTOR_PUSH(map->list[m].qi_list, nd); + return true; } -bool map_remove_questinfo(int m, struct npc_data *nd) { - unsigned short i; +static bool map_remove_questinfo(int m, struct npc_data *nd) +{ + nullpo_retr(false, nd); Assert_retr(false, m >= 0 && m < map->count); - for(i = 0; i < map->list[m].qi_count; i++) { - struct questinfo *qi = &map->list[m].qi_data[i]; - if( qi->nd == nd ) { - memset(&map->list[m].qi_data[i], 0, sizeof(struct questinfo)); - if( i != --map->list[m].qi_count ) { - memmove(&map->list[m].qi_data[i],&map->list[m].qi_data[i+1],sizeof(struct questinfo)*(map->list[m].qi_count-i)); - } - return true; - } + + int i; + ARR_FIND(0, VECTOR_LENGTH(map->list[m].qi_list), i, VECTOR_INDEX(map->list[m].qi_list, i) == nd); + if (i != VECTOR_LENGTH(map->list[m].qi_list)) { + VECTOR_ERASE(map->list[m].qi_list, i); + return true; } return false; } @@ -5535,7 +6077,7 @@ bool map_remove_questinfo(int m, struct npc_data *nd) { /** * @see DBApply */ -int map_db_final(union DBKey key, struct DBData *data, va_list ap) +static int map_db_final(union DBKey key, struct DBData *data, va_list ap) { struct map_data_other_server *mdos = DB->data2ptr(data); @@ -5548,7 +6090,7 @@ int map_db_final(union DBKey key, struct DBData *data, va_list ap) /** * @see DBApply */ -int nick_db_final(union DBKey key, struct DBData *data, va_list args) +static int nick_db_final(union DBKey key, struct DBData *data, va_list args) { struct charid2nick* p = DB->data2ptr(data); struct charid_request* req; @@ -5565,7 +6107,8 @@ int nick_db_final(union DBKey key, struct DBData *data, va_list args) return 0; } -int cleanup_sub(struct block_list *bl, va_list ap) { +static int cleanup_sub(struct block_list *bl, va_list ap) +{ nullpo_ret(bl); switch(bl->type) { @@ -5573,7 +6116,7 @@ int cleanup_sub(struct block_list *bl, va_list ap) { map->quit(BL_UCAST(BL_PC, bl)); break; case BL_NPC: - npc->unload(BL_UCAST(BL_NPC, bl), false); + npc->unload(BL_UCAST(BL_NPC, bl), false, true); break; case BL_MOB: unit->free(bl,CLR_OUTSIGHT); @@ -5595,7 +6138,7 @@ int cleanup_sub(struct block_list *bl, va_list ap) { /** * @see DBApply */ -int cleanup_db_sub(union DBKey key, struct DBData *data, va_list va) +static int cleanup_db_sub(union DBKey key, struct DBData *data, va_list va) { return map->cleanup_sub(DB->data2ptr(data), va); } @@ -5603,7 +6146,8 @@ int cleanup_db_sub(union DBKey key, struct DBData *data, va_list va) /*========================================== * map destructor *------------------------------------------*/ -int do_final(void) { +int do_final(void) +{ int i; struct map_session_data* sd; struct s_mapiterator* iter; @@ -5649,6 +6193,7 @@ int do_final(void) { ircbot->final();/* before channel. */ channel->final(); chrif->final(); + clan->final(); clif->final(); npc->final(); quest->final(); @@ -5665,20 +6210,24 @@ int do_final(void) { atcommand->final_msg(); skill->final(); status->final(); + refine->final(); unit->final(); bg->final(); duel->final(); elemental->final(); map->list_final(); vending->final(); + rodex->final(); + achievement->final(); + stylist->final(); HPM_map_do_final(); map->map_db->destroy(map->map_db, map->db_final); mapindex->final(); - if(map->enable_grf) - grfio_final(); + if (map->enable_grf) + grfio->final(); db_destroy(map->id_db); db_destroy(map->pc_db); @@ -5693,6 +6242,11 @@ int do_final(void) { ers_destroy(map->iterator_ers); ers_destroy(map->flooritem_ers); + for (i = 0; i < map->count; ++i) { + if (map->list[i].cell_buf.data != NULL) + aFree(map->list[i].cell_buf.data); + map->list[i].cell_buf.len = 0; + } aFree(map->list); if( map->block_free ) @@ -5700,9 +6254,6 @@ int do_final(void) { if( map->bl_list ) aFree(map->bl_list); - if( !map->enable_grf ) - aFree(map->cache_buffer); - aFree(map->MAP_CONF_NAME); aFree(map->BATTLE_CONF_FILENAME); aFree(map->ATCOMMAND_CONF_FILENAME); @@ -5718,7 +6269,8 @@ int do_final(void) { return map->retval; } -int map_abort_sub(struct map_session_data* sd, va_list ap) { +static int map_abort_sub(struct map_session_data *sd, va_list ap) +{ chrif->save(sd,1); return 1; } @@ -5747,12 +6299,13 @@ void do_abort(void) chrif->flush(); } -void set_server_type(void) { +void set_server_type(void) +{ SERVER_TYPE = SERVER_TYPE_MAP; } /// Called when a terminate signal is received. -void do_shutdown(void) +static void do_shutdown(void) { if( core->runflag != MAPSERVER_ST_SHUTDOWN ) { @@ -5770,7 +6323,8 @@ void do_shutdown(void) } } -CPCMD(gm_position) { +static CPCMD(gm_position) +{ int x = 0, y = 0, m = 0; char map_name[25]; @@ -5793,8 +6347,10 @@ CPCMD(gm_position) { map->cpsd->bl.x = x; map->cpsd->bl.y = y; map->cpsd->bl.m = m; + map->cpsd->mapindex = map_id2index(m); } -CPCMD(gm_use) { +static CPCMD(gm_use) +{ if( line == NULL ) { ShowError("gm:use invalid syntax. use '"CL_WHITE"gm:use @command <optional params>"CL_RESET"'\n"); @@ -5811,7 +6367,8 @@ CPCMD(gm_use) { map->cpsd_active = false; } /* Hercules Console Parser */ -void map_cp_defaults(void) { +static void map_cp_defaults(void) +{ #ifdef CONSOLE_INPUT /* default HCP data */ map->cpsd = pc->get_dummy_sd(); @@ -5819,13 +6376,16 @@ void map_cp_defaults(void) { map->cpsd->bl.x = mapindex->default_x; map->cpsd->bl.y = mapindex->default_y; map->cpsd->bl.m = map->mapname2mapid(mapindex->default_map); + Assert_retv(map->cpsd->bl.m >= 0); + map->cpsd->mapindex = map_id2index(map->cpsd->bl.m); console->input->addCommand("gm:info",CPCMD_A(gm_position)); console->input->addCommand("gm:use",CPCMD_A(gm_use)); #endif } -void map_load_defaults(void) { +static void map_load_defaults(void) +{ mapindex_defaults(); map_defaults(); /* */ @@ -5834,6 +6394,7 @@ void map_load_defaults(void) { battleground_defaults(); buyingstore_defaults(); channel_defaults(); + clan_defaults(); clif_defaults(); chrif_defaults(); guild_defaults(); @@ -5866,7 +6427,11 @@ void map_load_defaults(void) { pet_defaults(); path_defaults(); quest_defaults(); + achievement_defaults(); npc_chat_defaults(); + rodex_defaults(); + stylist_defaults(); + refine_defaults(); } /** * --run-once handler @@ -6002,22 +6567,6 @@ static CMDLINEARG(loadscript) } /** - * --generate-translations - * - * Creates "./generated_translations.pot" - * @see cmdline->exec - **/ -static CMDLINEARG(generatetranslations) { - script->lang_export_file = aStrdup("./generated_translations.pot"); - - if( !(script->lang_export_fp = fopen(script->lang_export_file,"wb")) ) { - ShowError("export-dialog: failed to open '%s' for writing\n",script->lang_export_file); - } - core->runflag = CORE_ST_STOP; - return true; -} - -/** * Defines the local command line arguments */ void cmdline_args_init_local(void) @@ -6033,7 +6582,6 @@ void cmdline_args_init_local(void) CMDLINEARG_DEF2(log-config, logconfig, "Alternative logging configuration.", CMDLINE_OPT_NORMAL|CMDLINE_OPT_PARAM); CMDLINEARG_DEF2(script-check, scriptcheck, "Doesn't run the server, only tests the scripts passed through --load-script.", CMDLINE_OPT_SILENT); CMDLINEARG_DEF2(load-script, loadscript, "Loads an additional script (can be repeated).", CMDLINE_OPT_NORMAL|CMDLINE_OPT_PARAM); - CMDLINEARG_DEF2(generate-translations, generatetranslations, "Creates './generated_translations.pot' file with all translateable strings from scripts, server terminates afterwards.", CMDLINE_OPT_NORMAL); } int do_init(int argc, char *argv[]) @@ -6047,12 +6595,12 @@ int do_init(int argc, char *argv[]) map_load_defaults(); - map->INTER_CONF_NAME = aStrdup("conf/inter-server.conf"); - map->LOG_CONF_NAME = aStrdup("conf/logs.conf"); - map->MAP_CONF_NAME = aStrdup("conf/map-server.conf"); - map->BATTLE_CONF_FILENAME = aStrdup("conf/battle.conf"); + map->INTER_CONF_NAME = aStrdup("conf/common/inter-server.conf"); + map->LOG_CONF_NAME = aStrdup("conf/map/logs.conf"); + map->MAP_CONF_NAME = aStrdup("conf/map/map-server.conf"); + map->BATTLE_CONF_FILENAME = aStrdup("conf/map/battle.conf"); map->ATCOMMAND_CONF_FILENAME = aStrdup("conf/atcommand.conf"); - map->SCRIPT_CONF_NAME = aStrdup("conf/script.conf"); + map->SCRIPT_CONF_NAME = aStrdup("conf/map/script.conf"); map->MSG_CONF_NAME = aStrdup("conf/messages.conf"); map->GRF_PATH_FILENAME = aStrdup("conf/grf-files.txt"); @@ -6065,10 +6613,30 @@ int do_init(int argc, char *argv[]) cmdline->exec(argc, argv, CMDLINE_OPT_NORMAL); minimal = map->minimal;/* temp (perhaps make minimal a mask with options of what to load? e.g. plugin 1 does minimal |= mob_db; */ if (!minimal) { - map->config_read(map->MAP_CONF_NAME); - CREATE(map->list,struct map_data,map->count); - map->count = 0; - map->config_read_sub(map->MAP_CONF_NAME); + map->config_read(map->MAP_CONF_NAME, false); + + { + // TODO: Remove this when no longer needed. +#define CHECK_OLD_LOCAL_CONF(oldname, newname) do { \ + if (stat((oldname), &fileinfo) == 0 && fileinfo.st_size > 0) { \ + ShowWarning("An old configuration file \"%s\" was found.\n", (oldname)); \ + ShowWarning("If it contains settings you wish to keep, please merge them into \"%s\".\n", (newname)); \ + ShowWarning("Otherwise, just delete it.\n"); \ + ShowInfo("Resuming in 10 seconds...\n"); \ + HSleep(10); \ + } \ +} while (0) + struct stat fileinfo; + + CHECK_OLD_LOCAL_CONF("conf/import/map_conf.txt", "conf/import/map-server.conf"); + CHECK_OLD_LOCAL_CONF("conf/import/inter_conf.txt", "conf/import/inter-server.conf"); + CHECK_OLD_LOCAL_CONF("conf/import/log_conf.txt", "conf/import/logs.conf"); + CHECK_OLD_LOCAL_CONF("conf/import/script_conf.txt", "conf/import/script.conf"); + CHECK_OLD_LOCAL_CONF("conf/import/packet_conf.txt", "conf/import/socket.conf"); + CHECK_OLD_LOCAL_CONF("conf/import/battle_conf.txt", "conf/import/battle.conf"); + +#undef CHECK_OLD_LOCAL_CONF + } // loads npcs map->reloadnpc(false); @@ -6079,7 +6647,9 @@ int do_init(int argc, char *argv[]) char ip_str[16]; sockt->ip2str(sockt->addr_[0], ip_str); - ShowWarning("Not all IP addresses in /conf/map-server.conf configured, auto-detecting...\n"); +#ifndef BUILDBOT + ShowWarning("Not all IP addresses in /conf/map/map-server.conf configured, auto-detecting...\n"); +#endif if (sockt->naddr_ == 0) ShowError("Unable to determine your IP address...\n"); @@ -6094,12 +6664,12 @@ int do_init(int argc, char *argv[]) chrif->setip(ip_str); } - battle->config_read(map->BATTLE_CONF_FILENAME); + battle->config_read(map->BATTLE_CONF_FILENAME, false); atcommand->msg_read(map->MSG_CONF_NAME, false); - map->inter_config_read(map->INTER_CONF_NAME); - logs->config_read(map->LOG_CONF_NAME); + map->inter_config_read(map->INTER_CONF_NAME, false); + logs->config_read(map->LOG_CONF_NAME, false); } - script->config_read(map->SCRIPT_CONF_NAME); + script->config_read(map->SCRIPT_CONF_NAME, false); map->id_db = idb_alloc(DB_OPT_BASE); map->pc_db = idb_alloc(DB_OPT_BASE); //Added for reliable map->id2sd() use. [Skotlex] @@ -6137,8 +6707,8 @@ int do_init(int argc, char *argv[]) } } - if(map->enable_grf) - grfio_init(map->GRF_PATH_FILENAME); + if (map->enable_grf) + grfio->init(map->GRF_PATH_FILENAME); map->readallmaps(); @@ -6160,11 +6730,13 @@ int do_init(int argc, char *argv[]) ircbot->init(minimal); script->init(minimal); itemdb->init(minimal); + clan->init(minimal); skill->init(minimal); if (!minimal) map->read_zone_db();/* read after item and skill initialization */ mob->init(minimal); pc->init(minimal); + refine->init(minimal); status->init(minimal); party->init(minimal); guild->init(minimal); @@ -6174,11 +6746,14 @@ int do_init(int argc, char *argv[]) mercenary->init(minimal); elemental->init(minimal); quest->init(minimal); + achievement->init(minimal); + stylist->init(minimal); npc->init(minimal); unit->init(minimal); bg->init(minimal); duel->init(minimal); vending->init(minimal); + rodex->init(minimal); if (map->scriptcheck) { bool failed = map->extra_scripts_count > 0 ? false : true; @@ -6198,6 +6773,8 @@ int do_init(int argc, char *argv[]) npc->event_do_oninit( false ); // Init npcs (OnInit) npc->market_fromsql(); /* after OnInit */ + npc->barter_fromsql(); /* after OnInit */ + npc->expanded_barter_fromsql(); /* after OnInit */ if (battle_config.pk_mode) ShowNotice("Server is running on '"CL_WHITE"PK Mode"CL_RESET"'.\n"); @@ -6225,11 +6802,12 @@ int do_init(int argc, char *argv[]) } /*===================================== -* Default Functions : map.h -* Generated by HerculesInterfaceMaker -* created by Susu -*-------------------------------------*/ -void map_defaults(void) { + * Default Functions : map.h + * Generated by HerculesInterfaceMaker + * created by Susu + *-------------------------------------*/ +void map_defaults(void) +{ map = &map_s; /* */ @@ -6242,8 +6820,8 @@ void map_defaults(void) { map->extra_scripts_count = 0; sprintf(map->db_path ,"db"); + libconfig->set_db_path(map->db_path); sprintf(map->help_txt ,"conf/help.txt"); - sprintf(map->help2_txt ,"conf/help2.txt"); sprintf(map->charhelp_txt ,"conf/charhelp.txt"); sprintf(map->wisp_server_name ,"Server"); // can be modified in char-server configuration file @@ -6256,12 +6834,12 @@ void map_defaults(void) { map->night_flag = 0; // 0=day, 1=night [Yor] map->enable_spy = 0; //To enable/disable @spy commands, which consume too much cpu time when sending packets. [Skotlex] - map->INTER_CONF_NAME="conf/inter-server.conf"; - map->LOG_CONF_NAME="conf/logs.conf"; - map->MAP_CONF_NAME = "conf/map-server.conf"; - map->BATTLE_CONF_FILENAME = "conf/battle.conf"; + map->INTER_CONF_NAME="conf/common/inter-server.conf"; + map->LOG_CONF_NAME="conf/map/logs.conf"; + map->MAP_CONF_NAME = "conf/map/map-server.conf"; + map->BATTLE_CONF_FILENAME = "conf/map/battle.conf"; map->ATCOMMAND_CONF_FILENAME = "conf/atcommand.conf"; - map->SCRIPT_CONF_NAME = "conf/script.conf"; + map->SCRIPT_CONF_NAME = "conf/map/script.conf"; map->MSG_CONF_NAME = "conf/messages.conf"; map->GRF_PATH_FILENAME = "conf/grf-files.txt"; @@ -6304,13 +6882,15 @@ void map_defaults(void) { map->bl_list_size = 0; //all in a big chunk, respects order +PRAGMA_GCC9(GCC diagnostic push) +PRAGMA_GCC9(GCC diagnostic ignored "-Warray-bounds") memset(ZEROED_BLOCK_POS(map), 0, ZEROED_BLOCK_SIZE(map)); +PRAGMA_GCC9(GCC diagnostic pop) map->cpsd = NULL; map->list = NULL; map->iterator_ers = NULL; - map->cache_buffer = NULL; map->flooritem_ers = NULL; /* */ @@ -6318,9 +6898,11 @@ void map_defaults(void) { /* funcs */ map->zone_init = map_zone_init; map->zone_remove = map_zone_remove; + map->zone_remove_all = map_zone_remove_all; map->zone_apply = map_zone_apply; map->zone_change = map_zone_change; map->zone_change2 = map_zone_change2; + map->zone_reload = map_zonedb_reload; map->getcell = map_getcell; map->setgatcell = map_setgatcell; @@ -6390,6 +6972,7 @@ void map_defaults(void) { map->foreachinpath = map_foreachinpath; map->vforeachinmap = map_vforeachinmap; map->foreachinmap = map_foreachinmap; + map->forcountinmap = map_forcountinmap; map->vforeachininstance = map_vforeachininstance; map->foreachininstance = map_foreachininstance; @@ -6457,8 +7040,8 @@ void map_defaults(void) { map->iwall_nextxy = map_iwall_nextxy; map->create_map_data_other_server = create_map_data_other_server; map->eraseallipport_sub = map_eraseallipport_sub; - map->init_mapcache = map_init_mapcache; map->readfromcache = map_readfromcache; + map->readfromcache_v1 = map_readfromcache_v1; map->addmap = map_addmap; map->delmapid = map_delmapid; map->zone_db_clear = map_zone_db_clear; @@ -6467,9 +7050,10 @@ void map_defaults(void) { map->readgat = map_readgat; map->readallmaps = map_readallmaps; map->config_read = map_config_read; - map->config_read_sub = map_config_read_sub; - map->reloadnpc_sub = map_reloadnpc_sub; + map->read_npclist = map_read_npclist; map->inter_config_read = inter_config_read; + map->inter_config_read_database_names = inter_config_read_database_names; + map->inter_config_read_connection = inter_config_read_connection; map->sql_init = map_sql_init; map->sql_close = map_sql_close; map->zone_mf_cache = map_zone_mf_cache; |