Selaa lähdekoodia

I'm still here!
Rewrote fame ranking lists- changed MAP_NAME_LENGTH to 12, now there's MAP_NAME_LENGTH_EXT at 16 for
uses where there is / may be the .gat extension, code adjusted accordingly
- moved map_normalize_name to mapindex_normalize_name so that everything
handling map names uses the same extension-removing function
- greatly enhanced the map cache generator, complete documentation on the
tool and the map cache format can be found in doc/
- the map cache format changed a bit as a consequence, but of course a new
valid one is included (contains latest Nameless Island maps)
- fixed a duplicate entry in map index


git-svn-id: https://svn.code.sf.net/p/rathena/svn/trunk@10167 54d463be-8e91-2dee-dedb-b68131a5f0ec

DracoRPG 18 vuotta sitten
vanhempi
commit
7c8f12ccd5

+ 11 - 0
Changelog-Trunk.txt

@@ -5,6 +5,17 @@ IF YOU HAVE A WORKING AND TESTED BUGFIX PUT IT INTO STABLE AS WELL AS TRUNK.
 
 
 2007/04/07
+	* Final touches to the whole map crap [DracoRPG]
+	- changed MAP_NAME_LENGTH to 12, now there's MAP_NAME_LENGTH_EXT at 16 for
+	  uses where there is / may be the .gat extension, code adjusted accordingly
+	- moved map_normalize_name to mapindex_normalize_name so that everything
+	  handling map names uses the same extension-removing function
+	- greatly enhanced the map cache generator, complete documentation on the
+	  tool and the map cache format can be found in doc/
+	- the map cache format changed a bit as a consequence, but of course a new
+	  valid one is included (contains latest Nameless Island maps)
+	- and I'm sorry for the number of times I've moved around and renamed files,
+	  now the final structure should have been reached
 	* Capped clif_heal's heal field (the argument received is int, but the
 	  packet field is short, meaning that if the heal is high enough, the client
 	  would receive a negative heal amount). [Skotlex]

+ 11 - 1
conf-tmpl/maps_athena.conf

@@ -744,7 +744,6 @@ map: ice_dun04
 
 // --- Veins & Thor Dungeon ---
 // -- 2006-12-19sdata_k.gpf --
-
 map: que_thor
 map: thor_camp
 map: thor_v01
@@ -760,6 +759,17 @@ map: ve_fild05
 map: ve_fild06
 map: ve_fild07
 
+// --- Unknown Island & Abbey Dungeon ---
+// -- 2007-04-02sdata_k.gpf
+map: nameless_i
+map: nameless_n
+map: nameless_in
+map: abbey01
+map: abbey02
+map: abbey03
+map: poring_w01
+map: poring_w02
+
 //------------------------- Clone Maps ---------------------------
 //------------------------- Extra Maps ---------------------------
 

+ 2 - 0
db/Changelog.txt

@@ -21,6 +21,8 @@
 ========================
 
 04/07
+	* Updated map index and map cache with Nameless Island maps [DracoRPG]
+	- also removed the duplicate g_room2 entry from map index, read the note
 	* Corrected Aliza card's item_db line. [Skotlex]
 04/05
 	* Fixed some items that should heal percentual hp/sp [Playtester]

+ 0 - 15
db/grf_files.txt

@@ -1,15 +0,0 @@
-//-----------------------------------------
-// GRF List
-//-----------------------------------------
-
-grf: C:\Program Files\Gravity\RO\data.grf
-grf: C:\Program Files\Gravity\RO\sdata.grf
-
-// You may add more in this format
-// grf: <data file path>
-
-//------ Others ---------------------------
-
-//Path to directory that contains the data dir 
-//NOTE: Path must include trailing backslash, only one data_dir entry is supported.
-//data_dir: C:\Program Files\Gravity\RO\

BIN
db/map_cache.dat


+ 15 - 2
db/map_list.txt → db/map_index.txt

@@ -9,6 +9,11 @@
 //mapname <- map will use index of previous map +1
 //Note that map index 0 is special and reserved for "error" status. 
 
+// NOTE TO DEVELOPERS
+// Due to a removed duplicate, index 591 is free, if you have to add a single map,
+// please add it there instead of the end. Then remove the 592 on next line (rachel)
+// and remove all those comments.  ~DracoRPG
+
 alb_ship 1
 alb2trea
 alberta
@@ -599,8 +604,8 @@ job_hunter
 job_knight
 job_priest
 job_wizard
-g_room2
-rachel
+// INDEX 591 IS FREE, PLEASE USE IT
+rachel 592
 ra_in01
 ra_fild01
 ra_fild02
@@ -645,6 +650,14 @@ ve_fild07
 poring_c01
 poring_c02
 que_ng
+nameless_i
+nameless_n
+nameless_in
+abbey01
+abbey02
+abbey03
+poring_w01
+poring_w02
 
 
 // Only add maps under this line if they are not standard maps!

+ 60 - 11
doc/map_cache.txt

@@ -1,18 +1,67 @@
-"How to use the mapcache builder"
-DracoRPG
+//===== Athena Doc ========================================
+//= Map Cache Builder and Format Documentation
+//===== By ================================================
+//= DracoRPG
+//===== Version ===========================================
+//= 1.0
+//=========================================================
+//= 0.1 - Short howto for the initial builder version
+//= 1.0 - Complete manual covering the improved version
+//===== Description =======================================
+//= A complete manual for eAthena's map cache generator
+//= as well as a reference on the map cache format used
+//=========================================================
 
+Preface:
+-------------------------------------------------------------------------------
 
-This is only useful if you have custom maps, as eAthena is provided with an updated mapcache containing every map
-from kRO Sakray's data.
+Since SVN revision ~10000, the map-server does not know how to read RO client files anymore. It reads maps from a
+"map cache" file that contains all and only the useful data about the maps. A map cache containing every official
+kRO Sakray map currently supported by eAthena is provided as a default.
+If you have custom maps or want to minimize the size of your map cache because your server does not load all of them
+(multi-map-server or light test server), you can use the map cache builder to generate a new one fitting your needs.
 
-1. First add the path to the directory / GRF containing your maps to db/grf_files.txt
-/!\ Please note you must also have the official maps as the whole mapcache will be rebuilt from scratch
+Map cache builder manual:
+-------------------------------------------------------------------------------
 
-2. Then add those custom maps at the end of db/map_list.txt, carefully chosing their index
+The source code for the map cache builder is located in src/tool/. It can be built using "make tools" if you use the Makefile
+or using the "mapcache" project under Visual Studio. Named "mapcache", the executable will be in your eAthena main folder.
+The map cache builder needs 3 file paths : one is a list of GRFs and/or data directory containing the maps, the second
+is the list of maps to add to the map cache, and the last one is the path of the map cache to generate. Default values for
+those paths are "tools/mapcache/grf_files.txt", "db/map_index.txt" and "db/map_cache.dat".
+The list of GRF and/or data directory must follow the format and indication of the default file: as many "grf:" entries as
+you wish and optionally one only "data_dir:" entry with trailing backslash included. // comments are supported as usual.
+In fact, any file with one map name per line can be used as a map list, that's why the map index list is used as a default:
+we are sure it contains every map supported by the server. Anything after the map name is ignored, // comments are supported
+and if the first word on the line is "map:" then the second word is used as the map name instead: that allows using
+maps_athena.conf as your map list, which is handy if you want to generate a minimal map cache for each of your multiple
+map-servers.
+The map cache file path can point to an already existing file, as the builder adds a map only if it's not already cached.
+This way, you can add custom maps to the base map cache without even needing kRO Sakray maps. If you wish to rebuild the
+entire map cache, though, you can either provide a path to a non-existing file, or force the rebuild mode.
 
-3. Now just run the mapcache builder and it'll build a new one at db/map_cache.dat
+Here are the command-line arguments you can provide to the map cache builder to customize its behavior:
+ -grf path/to/grf/list
+   Allows to specify the file containing the list of GRFs and/or data directory
+ -list path/to/map/list
+   Allows to specify the file containing the list of maps to add to the map cache
+ -cache path/to/map/cache
+   Allows to specify the path to the generated map cache
+ - rebuild
+   Allows to force the rebuild mode (map cache will be overwritten even if it already exists)
 
 
-NOTE:
-You can override those default paths by providing your own ones as command-line arguments to the mapcache builder:
-$> mapcache [grf_files_path [map_list_path [map_cache_path]]]
+Map cache format reference:
+-------------------------------------------------------------------------------
+
+The file is written as little-endian, even on big-endian systems, for cross-compatibility reasons. Appropriate conversions
+are done when generating it, so don't worry about it.
+The first 6 bytes are a main header:
+<unsigned long> file size
+<unsigned short> number of maps
+Then maps are stored one right after another:
+<12-characters-long string> map name
+<short> X size
+<short> Y size
+<long> compressed cell data length
+<variable> compressed cell data

+ 3 - 7
src/char/char.c

@@ -1605,10 +1605,6 @@ void create_online_files(void) {
 				if (online_display_option & 24) { // 8 or 16
 					// prepare map name
 					memcpy(temp, mapindex_id2name(char_dat[j].status.last_point.map), MAP_NAME_LENGTH);
-					temp[MAP_NAME_LENGTH] = '\0';
-					if (strstr(temp, ".gat") != NULL) {
-						temp[strstr(temp, ".gat") - temp] = 0; // suppress the '.gat'
-					}
 					// write map name
 					if (online_display_option & 16) { // map-name AND coordinates
 						fprintf(fp2, "        <td>%s (%d, %d)</td>\n", temp, char_dat[j].status.last_point.x, char_dat[j].status.last_point.y);
@@ -3532,13 +3528,13 @@ int parse_char(int fd)
 			{
 				//Send player to map
 				uint32 subnet_map_ip;
-				char map_name[MAP_NAME_LENGTH];
-				snprintf(map_name, MAP_NAME_LENGTH, "%s.gat", mapindex_id2name(cd->last_point.map));
+				char map_name[MAP_NAME_LENGTH_EXT];
+				snprintf(map_name, MAP_NAME_LENGTH_EXT, "%s.gat", mapindex_id2name(cd->last_point.map));
 
 				WFIFOHEAD(fd,28);
 				WFIFOW(fd,0) = 0x71;
 				WFIFOL(fd,2) = cd->char_id;
-				memcpy(WFIFOP(fd,6), map_name, MAP_NAME_LENGTH);
+				memcpy(WFIFOP(fd,6), map_name, MAP_NAME_LENGTH_EXT);
 			
 				// Advanced subnet check [LuzZza]
 				subnet_map_ip = lan_subnetcheck(ipl);

+ 9 - 12
src/char_sql/char.c

@@ -3340,13 +3340,12 @@ int parse_char(int fd)
 			{
 				//Send player to map.
 				uint32 subnet_map_ip;
-				char map_name[MAP_NAME_LENGTH];
-				snprintf(map_name, MAP_NAME_LENGTH, "%s.gat", mapindex_id2name(char_dat.last_point.map));
-
+				char map_name[MAP_NAME_LENGTH_EXT];
+				snprintf(map_name, MAP_NAME_LENGTH_EXT, "%s.gat", mapindex_id2name(char_dat.last_point.map));	
 				WFIFOHEAD(fd,28);
 				WFIFOW(fd,0) = 0x71;
 				WFIFOL(fd,2) = char_dat.char_id;
-				memcpy(WFIFOP(fd,6), map_name, MAP_NAME_LENGTH);
+				memcpy(WFIFOP(fd,6), map_name, MAP_NAME_LENGTH_EXT);
 
 				// Advanced subnet check [LuzZza]
 				subnet_map_ip = lan_subnetcheck(ipl);
@@ -4024,17 +4023,15 @@ int char_config_read(const char *cfgName) {
 		} else if (strcmpi(w1, "save_log") == 0) {
 			save_log = config_switch(w2);
 		} else if (strcmpi(w1, "start_point") == 0) {
-			char map[MAP_NAME_LENGTH];
+			char map[MAP_NAME_LENGTH_EXT];
 			int x, y;
 			if (sscanf(w2, "%16[^,],%d,%d", map, &x, &y) < 3)
 				continue;
-			if (strstr(map, ".gat") != NULL) { // Verify at least if '.gat' is in the map name
-				start_point.map = mapindex_name2id(map);
-				if (!start_point.map)
-					ShowError("Specified start_point %s not found in map-index cache.\n", map);
-				start_point.x = x;
-				start_point.y = y;
-			}
+			start_point.map = mapindex_name2id(map);
+			if (!start_point.map)
+				ShowError("Specified start_point %s not found in map-index cache.\n", map);
+			start_point.x = x;
+			start_point.y = y;
 		} else if (strcmpi(w1, "start_zeny") == 0) {
 			start_zeny = atoi(w2);
 			if (start_zeny < 0)

+ 32 - 20
src/common/mapindex.c

@@ -15,42 +15,53 @@
 //Leave an extra char of space to hold the terminator, in case for the strncpy(mapindex_id2name()) calls.
 struct indexes {
 	char name[MAP_NAME_LENGTH+1]; //Stores map name
-	int length; //Stores string length WITHOUT the extension for quick lookup.
+	char exists; //Set to 1 if index exists
 } indexes[MAX_MAPINDEX];
 
 static unsigned short max_index = 0;
 
-char mapindex_cfgfile[80] = "db/map_list.txt";
+char mapindex_cfgfile[80] = "db/map_index.txt";
+
+// Removes the extension from a map name
+char *mapindex_normalize_name(char *mapname)
+{
+	char *ptr, *ptr2;
+	ptr = strchr(mapname, '.');
+	if (ptr) { //Check and remove extension.
+		while (ptr[1] && (ptr2 = strchr(ptr+1, '.')))
+			ptr = ptr2; //Skip to the last dot.
+		if(stricmp(ptr,".gat") == 0 ||
+			stricmp(ptr,".afm") == 0 ||
+			stricmp(ptr,".af2") == 0)
+			*ptr = '\0'; //Remove extension.
+	}
+	return mapname;
+}
 
 /// Adds a map to the specified index
 /// Returns 1 if successful, 0 oherwise
 int mapindex_addmap(int index, const char *name)
 {
 	char map_name[1024];
-	char *ext;
-	int length;
 
 	if (index < 0 || index >= MAX_MAPINDEX) {
 		ShowError("(mapindex_add) Map index (%d) for \"%s\" out of range (max is %d)\n", index, name, MAX_MAPINDEX);
 		return 0;
 	}
+
 	snprintf(map_name, 1024, "%s", name);
-	map_name[1023] = 0;
-	length = strlen(map_name);
-	if (length > MAP_NAME_LENGTH) {
+	mapindex_normalize_name(map_name);
+
+	if (strlen(map_name) > MAP_NAME_LENGTH-1) {
 		ShowError("(mapindex_add) Map name %s is too long. Maps are limited to %d characters.\n", map_name, MAP_NAME_LENGTH);
 		return 0;
 	}
-	if ((ext = strstr(map_name, ".")) != NULL) { // Remove extension
-		length = ext-map_name;
-		*ext = '\0';
-	}
 
-	if (indexes[index].length)
+	if (indexes[index].exists)
 		ShowWarning("(mapindex_add) Overriding index %d: map \"%s\" -> \"%s\"\n", index, indexes[index].name, map_name);
 
 	strncpy(indexes[index].name, map_name, MAP_NAME_LENGTH);
-	indexes[index].length = length;
+	indexes[index].exists = 1;
 	if (max_index <= index)
 		max_index = index+1;
 	return 1;
@@ -59,17 +70,18 @@ int mapindex_addmap(int index, const char *name)
 unsigned short mapindex_name2id(const char* name) {
 	//TODO: Perhaps use a db to speed this up? [Skotlex]
 	int i;
-	int length = strlen(name);
-	char *ext = strstr(name, ".");
-	if (ext)
-		length = ext-name; //Base map-name length without the extension.
+	char map_name[1024];
+
+	snprintf(map_name, 1024, "%s", name);
+	mapindex_normalize_name(map_name);
+
 	for (i = 1; i < max_index; i++)
 	{
-		if (strncmp(indexes[i].name,name,length)==0)
+		if (strcmp(indexes[i].name,map_name)==0)
 			return i;
 	}
 #ifdef MAPINDEX_AUTOADD
-	if( mapindex_addmap(i,name) )
+	if( mapindex_addmap(i,map_name) )
 	{
 		ShowDebug("mapindex_name2id: Auto-added map \"%s\" to position %d\n", indexes[i], i);
 		return i;
@@ -83,7 +95,7 @@ unsigned short mapindex_name2id(const char* name) {
 }
 
 const char* mapindex_id2name(unsigned short id) {
-	if (id > MAX_MAPINDEX || !indexes[id].length) {
+	if (id > MAX_MAPINDEX || !indexes[id].exists) {
 		ShowDebug("mapindex_id2name: Requested name for non-existant map index [%d] in cache.\n", id);
 		return indexes[0].name; //Theorically this should never happen, hence we return this string to prevent null pointer crashes.
 	}

+ 1 - 0
src/common/mapindex.h

@@ -37,6 +37,7 @@ extern char mapindex_cfgfile[80];
 #define MAP_VEINS "veins"
 #define MAP_JAIL "sec_pri"
 #define MAP_NOVICE "new_zone01"
+char *mapindex_normalize_name(char *mapname);
 int mapindex_addmap(int index, const char *name);
 unsigned short mapindex_name2id(const char*);
 const char* mapindex_id2name(unsigned short);

+ 3 - 2
src/common/mmo.h

@@ -77,8 +77,9 @@
 #define NAME_LENGTH 24
 //For item names, which tend to have much longer names.
 #define ITEM_NAME_LENGTH 50
-//For Map Names, which the client considers to be 16 in length
-#define MAP_NAME_LENGTH 16
+//For Map Names, which the client considers to be 16 in length including the .gat extension
+#define MAP_NAME_LENGTH 12
+#define MAP_NAME_LENGTH_EXT 16
 
 #define MAX_FRIENDS 40
 #define MAX_MEMOPOINTS 10

+ 10 - 10
src/map/atcommand.c

@@ -1310,7 +1310,7 @@ int atcommand_send(const int fd, struct map_session_data* sd, const char* comman
  */
 int atcommand_rura( const int fd, struct map_session_data* sd, const char* command, const char* message)
 {
-	char map_name[MAP_NAME_LENGTH];
+	char map_name[MAP_NAME_LENGTH_EXT];
 	unsigned short mapindex;
 	int x = 0, y = 0;
 	int m = -1;
@@ -1698,7 +1698,7 @@ int atcommand_whomap3(const int fd, struct map_session_data* sd, const char* com
 	int i, count, users;
 	int pl_GM_level, GM_level;
 	int map_id;
-	char map_name[MAP_NAME_LENGTH];
+	char map_name[MAP_NAME_LENGTH_EXT];
 
 	memset(atcmd_output, '\0', sizeof(atcmd_output));
 	memset(map_name, '\0', sizeof(map_name));
@@ -1752,7 +1752,7 @@ int atcommand_whomap2(const int fd, struct map_session_data* sd, const char* com
 	int i, count, users;
 	int pl_GM_level, GM_level;
 	int map_id = 0;
-	char map_name[MAP_NAME_LENGTH];
+	char map_name[MAP_NAME_LENGTH_EXT];
 
 	nullpo_retr(-1, sd);
 
@@ -1810,7 +1810,7 @@ int atcommand_whomap(const int fd, struct map_session_data* sd, const char* comm
 	int i, count, users;
 	int pl_GM_level, GM_level;
 	int map_id = 0;
-	char map_name[MAP_NAME_LENGTH];
+	char map_name[MAP_NAME_LENGTH_EXT];
 	struct guild *g;
 	struct party_data *p;
 
@@ -3190,10 +3190,10 @@ int atcommand_go(const int fd, struct map_session_data* sd, const char* command,
 {
 	int i;
 	int town;
-	char map_name[MAP_NAME_LENGTH];
+	char map_name[MAP_NAME_LENGTH_EXT];
 	int m;
  
-	const struct { char map[MAP_NAME_LENGTH]; int x,   y; } data[] = {
+	const struct { char map[MAP_NAME_LENGTH_EXT]; int x,   y; } data[] = {
 		{ MAP_PRONTERA,	156, 191  },		//	 0=Prontera
 		{ MAP_MORROC,		156, 93  },			//	 1=Morroc
 		{ MAP_GEFFEN,		119, 59  },			//	 2=Geffen
@@ -3250,7 +3250,7 @@ int atcommand_go(const int fd, struct map_session_data* sd, const char* command,
 		return -1;
 	} else {
 		// get possible name of the city
-		map_name[MAP_NAME_LENGTH-1] = '\0';
+		map_name[MAP_NAME_LENGTH_EXT-1] = '\0';
 		for (i = 0; map_name[i]; i++)
 			map_name[i] = TOLOWER(map_name[i]);
 		// try to see if it's a name, and not a number (try a lot of possibilities, write errors and abbreviations too)
@@ -3636,7 +3636,7 @@ static int atkillmonster_sub(struct block_list *bl, va_list ap)
 void atcommand_killmonster_sub(const int fd, struct map_session_data* sd, const char* message, const int drop)
 {
 	int map_id;
-	char map_name[MAP_NAME_LENGTH];
+	char map_name[MAP_NAME_LENGTH_EXT];
 
 	if (!sd) return;
 
@@ -5432,8 +5432,8 @@ int atcommand_mapinfo(const int fd, struct map_session_data* sd, const char* com
 	}
 
 	if (atcmd_player_name[0] == '\0') {
-		memcpy(atcmd_player_name, mapindex_id2name(sd->mapindex), MAP_NAME_LENGTH);
-		atcmd_player_name[MAP_NAME_LENGTH] = '\0';
+		memcpy(atcmd_player_name, mapindex_id2name(sd->mapindex), MAP_NAME_LENGTH_EXT);
+		atcmd_player_name[MAP_NAME_LENGTH_EXT] = '\0';
 		m_id =  map_mapindex2mapid(sd->mapindex);
 	} else {
 		m_id = map_mapname2mapid(atcmd_player_name);

+ 2 - 2
src/map/charcommand.c

@@ -617,7 +617,7 @@ int charcommand_save(
 	const int fd, struct map_session_data* sd,
 	const char* command, const char* message)
 {
-	char map_name[MAP_NAME_LENGTH];
+	char map_name[MAP_NAME_LENGTH_EXT];
 	char character[NAME_LENGTH];
 	struct map_session_data* pl_sd;
 	int x = 0, y = 0;
@@ -1130,7 +1130,7 @@ int charcommand_warp(
 	const int fd, struct map_session_data* sd,
 	const char* command, const char* message)
 {
-	char map_name[MAP_NAME_LENGTH];
+	char map_name[MAP_NAME_LENGTH_EXT];
 	char character[NAME_LENGTH];
 	int x = 0, y = 0;
 	struct map_session_data *pl_sd;

+ 1 - 1
src/map/chrif.c

@@ -328,7 +328,7 @@ int chrif_changemapserver(struct map_session_data *sd, short map, int x, int y,
 int chrif_changemapserverack(int fd)
 {
 	struct map_session_data *sd;
-	char mapname[MAP_NAME_LENGTH+1];
+	char mapname[MAP_NAME_LENGTH_EXT];
 	RFIFOHEAD(fd);
 	sd = map_id2sd(RFIFOL(fd,2));
 

+ 34 - 27
src/map/clif.c

@@ -1208,12 +1208,16 @@ static void clif_spiritball_single(int fd, struct map_session_data *sd)
  *------------------------------------------
  */
 static int clif_set0192(int fd, int m, int x, int y, int type) {
+	char map_name[MAP_NAME_LENGTH_EXT];
+
+	sprintf(map_name, "%s.gat", map[m].name);
+
 	WFIFOHEAD(fd, packet_len(0x192));
 	WFIFOW(fd,0) = 0x192;
 	WFIFOW(fd,2) = x;
 	WFIFOW(fd,4) = y;
 	WFIFOW(fd,6) = type;
-	memcpy(WFIFOP(fd,8),map[m].name,MAP_NAME_LENGTH);
+	memcpy(WFIFOP(fd,8),map_name,MAP_NAME_LENGTH_EXT);
 	WFIFOSET(fd,packet_len(0x192));
 
 	return 0;
@@ -1600,17 +1604,17 @@ void clif_setwaitclose(int fd) {
  */
 int clif_changemap(struct map_session_data *sd, short map, int x, int y) {
 	int fd;
-	char map_name[MAP_NAME_LENGTH];
-	
+	char map_name[MAP_NAME_LENGTH_EXT];
+
 	nullpo_retr(0, sd);
 
 	fd = sd->fd;
 
-	snprintf(map_name, MAP_NAME_LENGTH, "%s.gat", mapindex_id2name(map));
+	sprintf(map_name, "%s.gat", mapindex_id2name(map));
 
 	WFIFOHEAD(fd, packet_len(0x91));
 	WFIFOW(fd,0) = 0x91;
-	memcpy(WFIFOP(fd,2), map_name, MAP_NAME_LENGTH);
+	memcpy(WFIFOP(fd,2), map_name, MAP_NAME_LENGTH_EXT);
 	WFIFOW(fd,18) = x;
 	WFIFOW(fd,20) = y;
 	WFIFOSET(fd, packet_len(0x91));
@@ -1631,7 +1635,7 @@ int clif_changemapserver(struct map_session_data* sd, const char* mapname, int x
 	WFIFOHEAD(fd, packet_len(0x92));
 	WFIFOW(fd,0) = 0x92;
 	//Better not trust the null-terminator is there. [Skotlex]
-	memcpy(WFIFOP(fd,2), mapname, MAP_NAME_LENGTH);
+	memcpy(WFIFOP(fd,2), mapname, MAP_NAME_LENGTH_EXT);
 	WFIFOB(fd,17) = 0;	//Null terminator for mapname
 	WFIFOW(fd,18) = x;
 	WFIFOW(fd,20) = y;
@@ -4661,10 +4665,10 @@ int clif_skill_warppoint(struct map_session_data *sd,int skill_num,int skill_lv,
 	WFIFOHEAD(fd,packet_len(0x11c));
 	WFIFOW(fd,0)=0x11c;
 	WFIFOW(fd,2)=skill_num;
-	strncpy((char*)WFIFOP(fd, 4),map1,MAP_NAME_LENGTH);
-	strncpy((char*)WFIFOP(fd,20),map2,MAP_NAME_LENGTH);
-	strncpy((char*)WFIFOP(fd,36),map3,MAP_NAME_LENGTH);
-	strncpy((char*)WFIFOP(fd,52),map4,MAP_NAME_LENGTH);
+	strncpy((char*)WFIFOP(fd, 4),map1,MAP_NAME_LENGTH_EXT);
+	strncpy((char*)WFIFOP(fd,20),map2,MAP_NAME_LENGTH_EXT);
+	strncpy((char*)WFIFOP(fd,36),map3,MAP_NAME_LENGTH_EXT);
+	strncpy((char*)WFIFOP(fd,52),map4,MAP_NAME_LENGTH_EXT);
 	WFIFOSET(fd,packet_len(0x11c));
 	sd->menuskill_id = skill_num;
 	if (skill_num == AL_WARP)
@@ -5660,7 +5664,7 @@ int clif_party_created(struct map_session_data *sd,int flag)
 int clif_party_member_info(struct party_data *p, struct map_session_data *sd)
 {
 	unsigned char buf[96];
-	char map_name[MAP_NAME_LENGTH];
+	char map_name[MAP_NAME_LENGTH_EXT];
 
 	if (!sd) { //Pick any party member (this call is used when changing item share rules)
 		int i;
@@ -5669,7 +5673,7 @@ int clif_party_member_info(struct party_data *p, struct map_session_data *sd)
 		sd = p->data[i].sd;
 	}
 
-	snprintf(map_name, MAP_NAME_LENGTH, "%s.gat", mapindex_id2name(sd->mapindex));
+	snprintf(map_name, MAP_NAME_LENGTH_EXT, "%s.gat", mapindex_id2name(sd->mapindex));
 
 	WBUFW(buf,0)=0x1e9;
 	WBUFL(buf,2)= sd->status.account_id;
@@ -5679,7 +5683,7 @@ int clif_party_member_info(struct party_data *p, struct map_session_data *sd)
 	WBUFB(buf,14)=0; //Unconfirmed byte, could be online/offline.
 	memcpy(WBUFP(buf,15), p->party.name, NAME_LENGTH);
 	memcpy(WBUFP(buf,39), sd->status.name, NAME_LENGTH);
-	memcpy(WBUFP(buf,63), map_name, MAP_NAME_LENGTH);
+	memcpy(WBUFP(buf,63), map_name, MAP_NAME_LENGTH_EXT);
 	WBUFB(buf,79) = (p->party.item&1)?1:0;
 	WBUFB(buf,80) = (p->party.item&2)?1:0;
 	clif_send(buf,packet_len(0x1e9),&sd->bl,PARTY);
@@ -5693,7 +5697,7 @@ int clif_party_member_info(struct party_data *p, struct map_session_data *sd)
  *------------------------------------------*/
 int clif_party_info(struct party_data* p, struct map_session_data *sd)
 {
-	unsigned char buf[2+2+NAME_LENGTH+(4+NAME_LENGTH+MAP_NAME_LENGTH+1+1)*MAX_PARTY];
+	unsigned char buf[2+2+NAME_LENGTH+(4+NAME_LENGTH+MAP_NAME_LENGTH_EXT+1+1)*MAX_PARTY];
 	struct map_session_data* party_sd = NULL;
 	int i, c;
 
@@ -5704,17 +5708,17 @@ int clif_party_info(struct party_data* p, struct map_session_data *sd)
 	for(i = 0, c = 0; i < MAX_PARTY; i++)
 	{
 		struct party_member* m = &p->party.member[i];
-		char map_name[MAP_NAME_LENGTH];
+		char map_name[MAP_NAME_LENGTH_EXT];
 
 		if(!m->account_id) continue;
 
 		if(party_sd == NULL) party_sd = p->data[i].sd;
 
-		snprintf(map_name, MAP_NAME_LENGTH, "%s.gat", mapindex_id2name(m->map));
+		snprintf(map_name, MAP_NAME_LENGTH_EXT, "%s.gat", mapindex_id2name(m->map));
 
 		WBUFL(buf,28+c*46) = m->account_id;
 		memcpy(WBUFP(buf,28+c*46+4), m->name, NAME_LENGTH);
-		memcpy(WBUFP(buf,28+c*46+28), map_name, MAP_NAME_LENGTH);
+		memcpy(WBUFP(buf,28+c*46+28), map_name, MAP_NAME_LENGTH_EXT);
 		WBUFB(buf,28+c*46+44) = (m->leader) ? 0 : 1;
 		WBUFB(buf,28+c*46+45) = (m->online) ? 0 : 1;
 		c++;
@@ -5993,12 +5997,12 @@ int clif_hpmeter(struct map_session_data *sd)
 int clif_party_move(struct party *p,struct map_session_data *sd,int online)
 {
 	unsigned char buf[128];
-	char map_name[MAP_NAME_LENGTH];
+	char map_name[MAP_NAME_LENGTH_EXT];
 
 	nullpo_retr(0, sd);
 	nullpo_retr(0, p);
 
-	snprintf(map_name, MAP_NAME_LENGTH, "%s.gat", map[sd->bl.m].name);
+	snprintf(map_name, MAP_NAME_LENGTH_EXT, "%s.gat", map[sd->bl.m].name);
 
 	WBUFW(buf, 0)=0x104;
 	WBUFL(buf, 2)=sd->status.account_id;
@@ -6008,7 +6012,7 @@ int clif_party_move(struct party *p,struct map_session_data *sd,int online)
 	WBUFB(buf,14)=!online;
 	memcpy(WBUFP(buf,15),p->name, NAME_LENGTH);
 	memcpy(WBUFP(buf,39),sd->status.name, NAME_LENGTH);
-	memcpy(WBUFP(buf,63),map_name, MAP_NAME_LENGTH);
+	memcpy(WBUFP(buf,63),map_name, MAP_NAME_LENGTH_EXT);
 	clif_send(buf,packet_len(0x104),&sd->bl,PARTY);
 	return 0;
 }
@@ -6415,6 +6419,9 @@ int clif_changemapcell(int m,int x,int y,int cell_type,int type)
 {
 	struct block_list bl;
 	unsigned char buf[32];
+	char map_name[MAP_NAME_LENGTH_EXT];
+
+	snprintf(map_name, MAP_NAME_LENGTH_EXT, "%s.gat", map[m].name);
 
 	bl.type = BL_NUL;
 	bl.m = m;
@@ -6424,7 +6431,7 @@ int clif_changemapcell(int m,int x,int y,int cell_type,int type)
 	WBUFW(buf,2) = x;
 	WBUFW(buf,4) = y;
 	WBUFW(buf,6) = cell_type;
-	memcpy(WBUFP(buf,8),map[m].name,MAP_NAME_LENGTH);
+	memcpy(WBUFP(buf,8),map_name,MAP_NAME_LENGTH_EXT);
 	if(!type)
 		clif_send(buf,packet_len(0x192),&bl,AREA);
 	else
@@ -7850,13 +7857,13 @@ void clif_gospel_info(struct map_session_data *sd, int type)
 void clif_feel_info(struct map_session_data *sd, unsigned char feel_level, unsigned char type)
 {
 	int fd=sd->fd;
-	char map_name[MAP_NAME_LENGTH];
+	char map_name[MAP_NAME_LENGTH_EXT];
 
-	snprintf(map_name, MAP_NAME_LENGTH, "%s.gat", mapindex_id2name(sd->feel_map[feel_level].index));
+	snprintf(map_name, MAP_NAME_LENGTH_EXT, "%s.gat", mapindex_id2name(sd->feel_map[feel_level].index));
 
 	WFIFOHEAD(fd,packet_len(0x20e));
 	WFIFOW(fd,0)=0x20e;
-	memcpy(WFIFOP(fd,2),map_name, MAP_NAME_LENGTH);
+	memcpy(WFIFOP(fd,2),map_name, MAP_NAME_LENGTH_EXT);
 	WFIFOL(fd,26)=sd->bl.id;
 	WFIFOB(fd,30)=feel_level;
 	WFIFOB(fd,31)=type?1:0;
@@ -8636,8 +8643,8 @@ int clif_message(struct block_list *bl, const char* msg)
  */
 void clif_parse_MapMove(int fd, struct map_session_data *sd) {
 // /m /mapmove (as @rura GM command)
-	char output[MAP_NAME_LENGTH+15]; // Max length of a short: ' -6XXXX' -> 7 digits
-	char message[MAP_NAME_LENGTH+15+5]; // "/mm "+output
+	char output[MAP_NAME_LENGTH_EXT+15]; // Max length of a short: ' -6XXXX' -> 7 digits
+	char message[MAP_NAME_LENGTH_EXT+15+5]; // "/mm "+output
 	char *map_name;
 	RFIFOHEAD(fd);
 
@@ -8647,7 +8654,7 @@ void clif_parse_MapMove(int fd, struct map_session_data *sd) {
 		return;
 
 	map_name = RFIFOP(fd,2);
-	map_name[MAP_NAME_LENGTH-1]='\0';
+	map_name[MAP_NAME_LENGTH_EXT-1]='\0';
 	sprintf(output, "%s %d %d", map_name, RFIFOW(fd,18), RFIFOW(fd,20));
 	atcommand_rura(fd, sd, "@rura", output);
 	if(log_config.gm && get_atcommand_level(AtCommand_MapMove) >= log_config.gm)

+ 3 - 2
src/map/guild.c

@@ -9,6 +9,7 @@
 #include "../common/timer.h"
 #include "../common/nullpo.h"
 #include "../common/malloc.h"
+#include "../common/mapindex.h"
 #include "../common/showmsg.h"
 #include "../common/ers.h"
 
@@ -183,7 +184,7 @@ static int guild_read_castledb(void)
 
 		gc=(struct guild_castle *)aCalloc(1,sizeof(struct guild_castle));
 		gc->castle_id=atoi(str[0]);
-		memcpy(gc->map_name,map_normalize_name(str[1]),MAP_NAME_LENGTH-1);
+		memcpy(gc->map_name,mapindex_normalize_name(str[1]),MAP_NAME_LENGTH-1);
 		memcpy(gc->castle_name,str[2],NAME_LENGTH-1);
 		memcpy(gc->castle_event,str[3],NAME_LENGTH-1);
 
@@ -254,7 +255,7 @@ struct guild_castle *guild_mapname2gc(char *mapname)
 	int i;
 	struct guild_castle *gc=NULL;
 
-	map_normalize_name(mapname);
+	mapindex_normalize_name(mapname);
 
 	for(i=0;i<MAX_GUILDCASTLE;i++){
 		gc=guild_castle_search(i);

+ 30 - 40
src/map/map.c

@@ -145,6 +145,20 @@ struct charid2nick {
 	int req_id;
 };
 
+// This is the main header found at the very beginning of the map cache
+struct map_cache_main_header {
+	unsigned long file_size;
+	unsigned short map_count;
+};
+
+// This is the header appended before every compressed map cells info in the map cache
+struct map_cache_map_info {
+	char name[MAP_NAME_LENGTH];
+	short xs;
+	short ys;
+	long len;
+};
+
 char map_cache_file[256]="db/map_cache.dat";
 char db_path[256] = "db";
 char motd_txt[256] = "conf/motd.txt";
@@ -2410,61 +2424,34 @@ int map_eraseipport(unsigned short mapindex, uint32 ip, uint16 port)
 * Map cache reading
 *===========================================*/
 
-// This is the header appended before every compressed map cells info
-struct map_cache_info {
-	char name[MAP_NAME_LENGTH];
-	unsigned short index;
-	short xs;
-	short ys;
-	long len;
-};
-
-FILE *map_cache_fp;
-
-// Removes the extension from a map name
-char *map_normalize_name(char *mapname)
-{
-	char *ptr, *ptr2;
-	ptr = strchr(mapname, '.');
-	if (ptr) { //Check and remove extension.
-		while (ptr[1] && (ptr2 = strchr(ptr+1, '.')))
-			ptr = ptr2; //Skip to the last dot.
-		if(stricmp(ptr,".gat") == 0 ||
-			stricmp(ptr,".afm") == 0 ||
-			stricmp(ptr,".af2") == 0)
-			*ptr = '\0'; //Remove extension.
-	}
-	return mapname;
-}
-
-int map_readmap(struct map_data *m)
+int map_readfromcache(struct map_data *m, FILE *fp)
 {
 	int i;
-	unsigned short map_count;
-	struct map_cache_info info;
+	struct map_cache_main_header header;
+	struct map_cache_map_info info;
 	unsigned long size;
 	unsigned char *buf;
 
-	if(!map_cache_fp)
+	if(!fp)
 		return 0;
 
-	fseek(map_cache_fp, 0, SEEK_SET);
-	fread(&map_count, sizeof(map_count), 1, map_cache_fp);
+	fseek(fp, 0, SEEK_SET);
+	fread(&header, sizeof(struct map_cache_main_header), 1, fp);
 
-	for(i = 0; i < map_count; i++) {
-		fread(&info, sizeof(info), 1, map_cache_fp);
+	for(i = 0; i < header.map_count; i++) {
+		fread(&info, sizeof(struct map_cache_map_info), 1, fp);
 		if(strcmp(m->name, info.name) == 0) { // Map found
 			m->xs = info.xs;
 			m->ys = info.ys;
 			m->gat = (unsigned char *)aMalloc(m->xs*m->ys); // Allocate room for map cells data
 			buf = aMalloc(info.len); // Allocate a temp buffer to read the zipped map
-			fread(buf, info.len, 1, map_cache_fp);
+			fread(buf, info.len, 1, fp);
 			size = m->xs*m->ys;
 			decode_zip(m->gat, &size, buf, info.len); // Unzip the map from the buffer
 			aFree(buf);
 			return 1;
 		} else // Map not found, jump to the beginning of the next map info header
-			fseek(map_cache_fp, info.len, SEEK_CUR);
+			fseek(fp, info.len, SEEK_CUR);
 	}
 
 	return 0;
@@ -2482,7 +2469,7 @@ int map_addmap(char *mapname) {
 		return 1;
 	}
 
-	memcpy(map[map_num].name, map_normalize_name(mapname), MAP_NAME_LENGTH-1);
+	memcpy(map[map_num].name, mapindex_normalize_name(mapname), MAP_NAME_LENGTH-1);
 	map_num++;
 	return 0;
 }
@@ -2520,8 +2507,9 @@ int map_readallmaps (void)
 {
 	int i;
 	int maps_removed = 0;
+	FILE *fp;
 
-	if(!(map_cache_fp = fopen(map_cache_file, "rb")))
+	if(!(fp = fopen(map_cache_file, "rb")))
 	{
 		ShowFatalError("Unable to open map cache file "CL_WHITE"%s"CL_RESET"\n", map_cache_file);
 		exit(1); //No use launching server if maps can't be read.
@@ -2559,7 +2547,7 @@ int map_readallmaps (void)
 			fflush(stdout);
 		}
 
-		if(!map_readmap(&map[i])) {
+		if(!map_readfromcache(&map[i], fp)) {
 			map_delmapid(i);
 			maps_removed++;
 			i--;
@@ -2609,6 +2597,8 @@ int map_readallmaps (void)
 		map[i].block_mob_count = (int*)aCallocA(size, 1);
 	}
 
+	fclose(fp);
+
 	// finished map loading
 	printf("\r");
 	ShowInfo("Successfully loaded '"CL_WHITE"%d"CL_RESET"' maps.%30s\n",map_num,"");

+ 1 - 2
src/map/map.h

@@ -1030,7 +1030,7 @@ enum { ATK_LUCKY=1,ATK_FLEE,ATK_DEF};	// 
 struct map_data {
 	char name[MAP_NAME_LENGTH];
 	unsigned short index; //Index is the map index used by the mapindex* functions.
-	unsigned char *gat;	// NULL‚Ȃ牺‚Ìmap_data_other_server‚Æ‚µ‚Ĉµ‚¤
+	unsigned char *gat;	// If this is NULL‚ the map is not on this map-server
 	unsigned char *cell; //Contains temporary cell data that is set/unset on tiles.
 #ifdef CELL_NOSTACK
 	unsigned char *cell_bl; //Holds amount of bls in any given cell.
@@ -1350,7 +1350,6 @@ void map_foreachpc(int (*func)(DBKey,void*,va_list),...);
 int map_foreachiddb(int (*)(DBKey,void*,va_list),...);
 void map_addnickdb(struct map_session_data *);
 struct map_session_data * map_nick2sd(const char*);
-char *map_normalize_name(char *mapname);
 
 // ‚»‚Ì‘¼
 int map_check_dir(int s_dir,int t_dir);

+ 7 - 7
src/map/npc.c

@@ -1659,7 +1659,7 @@ int npc_parse_warp (char *w1,char *w2,char *w3,char *w4)
 {
 	int x, y, xs, ys, to_x, to_y, m;
 	int i;
-	char mapname[MAP_NAME_LENGTH], to_mapname[MAP_NAME_LENGTH];
+	char mapname[MAP_NAME_LENGTH_EXT], to_mapname[MAP_NAME_LENGTH_EXT];
 	struct npc_data *nd;
 
 	// 引数の個数チェック
@@ -1723,7 +1723,7 @@ static int npc_parse_shop (char *w1, char *w2, char *w3, char *w4)
 	#define MAX_SHOPITEM 100
 	char *p;
 	int x, y, dir, m, pos = 0;
-	char mapname[MAP_NAME_LENGTH];
+	char mapname[MAP_NAME_LENGTH_EXT];
 	struct npc_data *nd;
 
 	if (strcmp(w1, "-") == 0) {
@@ -1953,7 +1953,7 @@ static int npc_skip_script (char *w1,char *w2,char *w3,char *w4,char *first_line
 static int npc_parse_script(char *w1,char *w2,char *w3,char *w4,char *first_line,FILE *fp,int *lines,const char* file)
 {
 	int x, y, dir = 0, m, xs = 0, ys = 0, class_ = 0;	// [Valaris] thanks to fov
-	char mapname[MAP_NAME_LENGTH];
+	char mapname[MAP_NAME_LENGTH_EXT];
 	unsigned char *srcbuf = NULL;
 	struct script_code *script;
 	int srcsize = 65536;
@@ -2380,7 +2380,7 @@ int npc_parse_mob2 (struct spawn_data *mob, int index)
 int npc_parse_mob (char *w1, char *w2, char *w3, char *w4)
 {
 	int level, num, class_, mode, x,y,xs,ys;
-	char mapname[MAP_NAME_LENGTH];
+	char mapname[MAP_NAME_LENGTH_EXT];
 	char mobname[NAME_LENGTH];
 	struct spawn_data mob, *data;
 
@@ -2515,7 +2515,7 @@ int npc_parse_mob (char *w1, char *w2, char *w3, char *w4)
 static int npc_parse_mapflag (char *w1, char *w2, char *w3, char *w4)
 {
 	int m;
-	char mapname[MAP_NAME_LENGTH];
+	char mapname[MAP_NAME_LENGTH_EXT];
 	int state = 1;
 
 	// 引数の個数チェック
@@ -2530,7 +2530,7 @@ static int npc_parse_mapflag (char *w1, char *w2, char *w3, char *w4)
 	
 //マップフラグ
 	if (strcmpi(w3, "nosave") == 0) {
-		char savemap[MAP_NAME_LENGTH];
+		char savemap[MAP_NAME_LENGTH_EXT];
 		int savex, savey;
 		if (state == 0)
 			; //Map flag disabled.
@@ -2764,7 +2764,7 @@ static int npc_parse_mapflag (char *w1, char *w2, char *w3, char *w4)
 static int npc_parse_mapcell (char *w1, char *w2, char *w3, char *w4)
 {
 	int m, cell, x, y, x0, y0, x1, y1;
-	char type[24], mapname[MAP_NAME_LENGTH];
+	char type[24], mapname[MAP_NAME_LENGTH_EXT];
 
 	if (sscanf(w1, "%15[^,]", mapname) != 1)
 		return 1;

+ 9 - 9
src/map/script.c

@@ -9119,10 +9119,10 @@ BUILDIN_FUNC(flagemblem)
 
 BUILDIN_FUNC(getcastlename)
 {
-	char mapname[MAP_NAME_LENGTH];
+	char mapname[MAP_NAME_LENGTH_EXT];
 	struct guild_castle *gc;
 
-	strncpy(mapname, script_getstr(st,2), MAP_NAME_LENGTH);
+	strncpy(mapname, script_getstr(st,2), MAP_NAME_LENGTH_EXT);
 	gc = guild_mapname2gc(mapname);
 
 	if(gc)
@@ -9134,13 +9134,13 @@ BUILDIN_FUNC(getcastlename)
 
 BUILDIN_FUNC(getcastledata)
 {
-	char mapname[MAP_NAME_LENGTH];
+	char mapname[MAP_NAME_LENGTH_EXT];
 	int index=script_getnum(st,3);
 	const char *event=NULL;
 	struct guild_castle *gc;
 	int i;
 
-	strncpy(mapname, script_getstr(st,2), MAP_NAME_LENGTH);
+	strncpy(mapname, script_getstr(st,2), MAP_NAME_LENGTH_EXT);
 	gc = guild_mapname2gc(mapname);
 
 	if(script_hasdata(st,4) && index==0 && gc) {
@@ -9202,12 +9202,12 @@ BUILDIN_FUNC(getcastledata)
 
 BUILDIN_FUNC(setcastledata)
 {
-	char mapname[MAP_NAME_LENGTH];
+	char mapname[MAP_NAME_LENGTH_EXT];
 	int index=script_getnum(st,3);
 	int value=script_getnum(st,4);
 	struct guild_castle *gc;
 
-	strncpy(mapname, script_getstr(st,2), MAP_NAME_LENGTH);
+	strncpy(mapname, script_getstr(st,2), MAP_NAME_LENGTH_EXT);
 	gc = guild_mapname2gc(mapname);
 
 	if(gc) {
@@ -11084,9 +11084,9 @@ BUILDIN_FUNC(getsavepoint)
 	y=sd->status.save_point.y;
 	switch(type){
 		case 0:
-			mapname=(char *) aMallocA((MAP_NAME_LENGTH+1)*sizeof(char));
+			mapname=(char *) aMallocA((MAP_NAME_LENGTH)*sizeof(char));
 			memcpy(mapname, mapindex_id2name(sd->status.save_point.map), MAP_NAME_LENGTH);
-			mapname[MAP_NAME_LENGTH]='\0';
+			mapname[MAP_NAME_LENGTH-1]='\0';
 			script_pushstr(st,mapname);
 		break;
 		case 1:
@@ -11133,7 +11133,7 @@ BUILDIN_FUNC(getmapxy)
 	char prefix;
 
 	int x,y,type;
-	char mapname[MAP_NAME_LENGTH+1];
+	char mapname[MAP_NAME_LENGTH];
 	memset(mapname, 0, sizeof(mapname));
 
 	if( !data_isreference(script_getdata(st,2)) ){

+ 7 - 7
src/map/skill.c

@@ -4445,8 +4445,8 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, in
 			} else {
 				if (sd->skillitem != AL_TELEPORT)
 				{
-					char save_map[MAP_NAME_LENGTH];
-					snprintf(save_map, MAP_NAME_LENGTH, "%s.gat", mapindex_id2name(sd->status.save_point.map));
+					char save_map[MAP_NAME_LENGTH_EXT];
+					snprintf(save_map, MAP_NAME_LENGTH_EXT, "%s.gat", mapindex_id2name(sd->status.save_point.map));
 					clif_skill_warppoint(sd,skillid,skilllv,"Random",save_map,"","");
 				}
 				else //Autocasted Teleport level 2??
@@ -6086,14 +6086,14 @@ int skill_castend_pos2 (struct block_list *src, int x, int y, int skillid, int s
 
 	case AL_WARP:
 		if(sd) {
-			char memo[4][MAP_NAME_LENGTH] = {"", "", "", ""};
-			snprintf(memo[0], MAP_NAME_LENGTH, "%s.gat", mapindex_id2name(sd->status.save_point.map));
+			char memo[4][MAP_NAME_LENGTH_EXT] = {"", "", "", ""};
+			snprintf(memo[0], MAP_NAME_LENGTH_EXT, "%s.gat", mapindex_id2name(sd->status.save_point.map));
 			if (skilllv>1 && sd->status.memo_point[0].map)
-				snprintf(memo[1], MAP_NAME_LENGTH, "%s.gat", mapindex_id2name(sd->status.memo_point[0].map));
+				snprintf(memo[1], MAP_NAME_LENGTH_EXT, "%s.gat", mapindex_id2name(sd->status.memo_point[0].map));
 			if (skilllv>2 && sd->status.memo_point[1].map)
-				snprintf(memo[2], MAP_NAME_LENGTH, "%s.gat", mapindex_id2name(sd->status.memo_point[1].map));
+				snprintf(memo[2], MAP_NAME_LENGTH_EXT, "%s.gat", mapindex_id2name(sd->status.memo_point[1].map));
 			if (skilllv>3 && sd->status.memo_point[2].map)
-				snprintf(memo[3], MAP_NAME_LENGTH, "%s.gat", mapindex_id2name(sd->status.memo_point[2].map));
+				snprintf(memo[3], MAP_NAME_LENGTH_EXT, "%s.gat", mapindex_id2name(sd->status.memo_point[2].map));
 
 			clif_skill_warppoint(sd,skillid,skilllv,
 				memo[0],memo[1],memo[2],memo[3]);

+ 0 - 1
src/tool/grfio.c

@@ -578,7 +578,6 @@ void* grfio_reads(char *fname, int *size)
 			if (entry != NULL && entry->gentry < 0) {
 				entry->gentry = -entry->gentry;	// local file checked
 			} else {
-				printf("%s not found (grfio_reads - local file %s)\n", fname, lfname);
 				return NULL;
 			}
 		}

+ 154 - 60
src/tool/mapcache.c

@@ -4,6 +4,7 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
+#include <malloc.h>
 
 #ifndef _WIN32
 #include <unistd.h>
@@ -11,12 +12,18 @@
 
 #include "grfio.h"
 
-char grf_list_file[256] = "db/grf_files.txt";
-char map_list_file[256] = "db/map_list.txt";
+#define MAP_NAME_LENGTH 12
+#define MAP_NAME_LENGTH_EXT 16
+#define NO_WATER 1000000
+
+char grf_list_file[256] = "tools/mapcache/grf_files.txt";
+char map_list_file[256] = "db/map_index.txt";
 char map_cache_file[256] = "db/map_cache.dat";
+int rebuild = 0;
 
-#define MAP_NAME_LENGTH 16
-#define NO_WATER 1000000
+FILE *map_cache_fp;
+
+unsigned long file_size;
 
 // Used internally, this structure contains the physical map cells
 struct map_data {
@@ -26,31 +33,25 @@ struct map_data {
 };
 
 // This is the main header found at the very beginning of the file
-unsigned short map_count;
+struct main_header {
+	unsigned long file_size;
+	unsigned short map_count;
+} header;
 
 // This is the header appended before every compressed map cells info
-struct map_cache_info {
+struct map_info {
 	char name[MAP_NAME_LENGTH];
-	unsigned short index;
 	short xs;
 	short ys;
 	long len;
 };
 
-FILE *map_cache_fp;
-
-int filesize;
 
-/// Converts an unsigned short (16 bits) from current machine order to little-endian
-unsigned short MakeUShortLE(unsigned short val)
-{
-	unsigned char buf[2];
-	buf[0] = (unsigned char)( (val & 0x00FF)         );
-	buf[1] = (unsigned char)( (val & 0xFF00) >> 0x08 );
-	return *((unsigned short*)buf);
-}
+/*************************************
+* Big-endian compatibility functions *
+*************************************/
 
-/// Converts a short (16 bits) from current machine order to little-endian
+// Converts a short (16 bits) from current machine order to little-endian
 short MakeShortLE(short val)
 {
 	unsigned char buf[2];
@@ -59,7 +60,7 @@ short MakeShortLE(short val)
 	return *((short*)buf);
 }
 
-/// Converts a long (32 bits) from current machine order to little-endian
+// Converts a long (32 bits) from current machine order to little-endian
 long MakeLongLE(long val)
 {
 	unsigned char buf[4];
@@ -70,7 +71,23 @@ long MakeLongLE(long val)
 	return *((long*)buf);
 }
 
-/// Reads an unsigned long (32 bits) in little-endian from the buffer
+// Reads an unsigned short (16 bits) in little-endian from the buffer
+unsigned short GetUShort(const unsigned char *buf)
+{
+	return	 ( ((unsigned short)(buf[0]))         )
+			|( ((unsigned short)(buf[1])) << 0x08 );
+}
+
+// Reads a long (32 bits) in little-endian from the buffer
+long GetLong(const unsigned char *buf)
+{
+	return	 ( ((long)(buf[0]))         )
+			|( ((long)(buf[1])) << 0x08 )
+			|( ((long)(buf[2])) << 0x10 )
+			|( ((long)(buf[3])) << 0x18 );
+}
+
+// Reads an unsigned long (32 bits) in little-endian from the buffer
 unsigned long GetULong(const unsigned char *buf)
 {
 	return	 ( ((unsigned long)(buf[0]))         )
@@ -87,7 +104,7 @@ float GetFloat(const unsigned char *buf)
 }
 
 
-// Read map from GRF's GAT and RSW files
+// Reads a map from GRF's GAT and RSW files
 int read_map(char *name, struct map_data *m)
 {
 	char filename[256];
@@ -143,31 +160,31 @@ int read_map(char *name, struct map_data *m)
 	return 1;
 }
 
-void cache_map(char *name, unsigned short index, struct map_data *m)
+// Adds a map to the cache
+void cache_map(char *name, struct map_data *m)
 {
-	struct map_cache_info info;
-	unsigned long len;
-	char *write_buf;
+	struct map_info info;
+	long len;
+	unsigned char *write_buf;
 
 	// Create an output buffer twice as big as the uncompressed map... this way we're sure it fits
 	len = m->xs*m->ys*2;
-	write_buf = (char *)malloc(len);
+	write_buf = (unsigned char *)malloc(len);
 	// Compress the cells and get the compressed length
-	encode_zip((unsigned char *)write_buf, &len, m->cells, m->xs*m->ys);
+	encode_zip(write_buf, &len, m->cells, m->xs*m->ys);
 
 	// Fill the map header
 	strncpy(info.name, name, MAP_NAME_LENGTH);
-	info.index = MakeUShortLE(index);
 	info.xs = MakeShortLE(m->xs);
 	info.ys = MakeShortLE(m->ys);
-	info.len = MakeLongLE((long)len);
+	info.len = MakeLongLE(len);
 
 	// Append map header then compressed cells at the end of the file
-	fseek(map_cache_fp, filesize, SEEK_SET);
-	fwrite(&info, sizeof(struct map_cache_info), 1, map_cache_fp);
+	fseek(map_cache_fp, header.file_size, SEEK_SET);
+	fwrite(&info, sizeof(struct map_info), 1, map_cache_fp);
 	fwrite(write_buf, 1, len, map_cache_fp);
-	map_count++;
-	filesize += sizeof(struct map_cache_info) + len;
+	header.file_size += sizeof(struct map_info) + len;
+	header.map_count++;
 
 	free(write_buf);
 	free(m->cells);
@@ -175,41 +192,111 @@ void cache_map(char *name, unsigned short index, struct map_data *m)
 	return;
 }
 
+// Checks whether a map is already is the cache
+int find_map(char *name)
+{
+	int i;
+	struct map_info info;
+
+	fseek(map_cache_fp, sizeof(struct main_header), SEEK_SET);
+
+	for(i = 0; i < header.map_count; i++) {
+		fread(&info, sizeof(info), 1, map_cache_fp);
+		if(strcmp(name, info.name) == 0) // Map found
+			return 1;
+		else // Map not found, jump to the beginning of the next map info header
+			fseek(map_cache_fp, GetLong((unsigned char *)&(info.len)), SEEK_CUR);
+	}
+
+	return 0;
+}
+
+// Cuts the extension from a map name
+char *remove_extension(char *mapname)
+{
+	char *ptr, *ptr2;
+	ptr = strchr(mapname, '.');
+	if (ptr) { //Check and remove extension.
+		while (ptr[1] && (ptr2 = strchr(ptr+1, '.')))
+			ptr = ptr2; //Skip to the last dot.
+		if(stricmp(ptr,".gat") == 0 ||
+			stricmp(ptr,".afm") == 0 ||
+			stricmp(ptr,".af2") == 0)
+			*ptr = '\0'; //Remove extension.
+	}
+	return mapname;
+}
+
+// Processes command-line arguments
+void process_args(int argc, char *argv[])
+{
+	int i;
+
+	for(i = 0; i < argc; i++) {
+		if(strcmp(argv[i], "-grf") == 0) {
+			if(++i < argc)
+				strcpy(grf_list_file, argv[i]);
+		} else if(strcmp(argv[i], "-list") == 0) {
+			if(++i < argc)
+				strcpy(map_list_file, argv[i]);
+		} else if(strcmp(argv[i], "-cache") == 0) {
+			if(++i < argc)
+				strcpy(map_cache_file, argv[i]);
+		} else if(strcmp(argv[i], "-rebuild") == 0)
+			rebuild = 1;
+	}
+
+}
+
 int main(int argc, char *argv[])
 {
 	FILE *list;
 	char line[1024];
 	struct map_data map;
-	char name[MAP_NAME_LENGTH];
-	unsigned short index = 1;
+	char name[MAP_NAME_LENGTH_EXT];
 
-	if(argc > 1)
-		strcpy(grf_list_file, argv[1]);
-	if(argc > 2)
-		strcpy(map_list_file, argv[2]);
-	if(argc > 3)
-		strcpy(map_cache_file, argv[3]);
+	// Process the command-line arguments
+	process_args(argc, argv);
 
 	printf("Initializing grfio with %s\n", grf_list_file);
 	grfio_init(grf_list_file);
 
+	// Attempt to open the map cache file and force rebuild if not found
 	printf("Opening map cache: %s\n", map_cache_file);
-	map_cache_fp = fopen(map_cache_file, "wb");
-	if( map_cache_fp == NULL ) {
+	if(!rebuild) {
+		map_cache_fp = fopen(map_cache_file, "rb");
+		if(map_cache_fp == NULL) {
+			printf("Existing map cache not found, forcing rebuild mode\n");
+			rebuild = 1;
+		} else
+			fclose(map_cache_fp);
+	}
+	if(rebuild)
+		map_cache_fp = fopen(map_cache_file, "w+b");
+	else
+		map_cache_fp = fopen(map_cache_file, "r+b");
+	if(map_cache_fp == NULL) {
 		printf("Failure when opening map cache file %s\n", map_cache_file);
 		exit(1);
 	}
 
+	// Open the map list
 	printf("Opening map list: %s\n", map_list_file);
 	list = fopen(map_list_file, "r");
-	if( list == NULL ) {
+	if(list == NULL) {
 		printf("Failure when opening maps list file %s\n", map_list_file);
-		exit(1);
+		exit(2);
 	}
 
 	// Initialize the main header
-	map_count = 0;
-	filesize = sizeof(map_count);
+	if(rebuild) {
+		header.file_size = sizeof(struct main_header);
+		header.map_count = 0;
+	} else {
+		fread(&header, sizeof(struct main_header), 1, map_cache_fp);
+		header.file_size = GetULong((unsigned char *)&(header.file_size));
+		header.map_count = GetUShort((unsigned char *)&(header.map_count));
+	}
 
 	// Read and process the map list
 	while(fgets(line, 1020, list)){
@@ -217,30 +304,37 @@ int main(int argc, char *argv[])
 		if(line[0] == '/' && line[1] == '/')
 			continue;
 
-		if(sscanf(line, "%16s %hu", name, &index) > 0) { // No defines in strings, 16 is hardcoded here
-				printf("Index %d : %s\n", index, name);
-				if(read_map(name, &map))
-					cache_map(name, index, &map);
-				else
-					printf("Map file not found in GRF\n");
-				// If the 2nd argument is omitted at next line, we'll keep last used index + 1
-				index++;
-		}
+		if(sscanf(line, "%15s", name) < 1)
+			continue;
+
+		if(strcmp("map:", name) == 0 && sscanf(line, "%*s %15s", name) < 1)
+			continue;
+
+		remove_extension(name);
+		printf("%s", name);
+		if(find_map(name))
+			printf(" already in cache!\n");
+		else if(read_map(name, &map)) {
+			cache_map(name, &map);
+			printf(" successfully cached\n");
+		} else
+			printf(" not found in GRF!\n");
+
 	}
 
 	printf("Closing map list: %s\n", map_list_file);
 	fclose(list);
 
-	printf("Closing map cache: %s\n", map_cache_file);
 	// Write the main header and close the map cache
+	printf("Closing map cache: %s\n", map_cache_file);
 	fseek(map_cache_fp, 0, SEEK_SET);
-	fwrite(&map_count, sizeof(map_count), 1, map_cache_fp);
+	fwrite(&header, sizeof(struct main_header), 1, map_cache_fp);
 	fclose(map_cache_fp);
 
 	printf("Finalizing grfio\n");
 	grfio_final();
 
-	printf("%d maps cached\n", map_count);
+	printf("%d maps now in cache\n", header.map_count);
 
 	return 0;
 }

+ 15 - 0
tools/mapcache/grf_files.txt

@@ -0,0 +1,15 @@
+//-----------------------------------------
+// GRF List
+//  Add as many entries as you wish
+//-----------------------------------------
+
+//grf: C:\Program Files\Gravity\RO\data.grf
+grf: C:\Program Files\Gravity\RO\sdata.grf
+
+//-----------------------------------------
+// Data Directory
+//  Path must include trailing backslash
+//  Only one entry supported!
+//-----------------------------------------
+
+//data_dir: C:\Program Files\Gravity\RO\