Browse Source

Instance map fixes (#3539)

* Fixed #3517, new map from instance doesn't use unused map slots
* Fixed #3528, crashed on reloadscript if there is instance map
* Cleared map flags on reloadscript
Cydh Ramdh 6 years ago
parent
commit
e66dc4f62e
3 changed files with 88 additions and 23 deletions
  1. 85 23
      src/map/map.cpp
  2. 2 0
      src/map/map.hpp
  3. 1 0
      src/map/npc.cpp

+ 85 - 23
src/map/map.cpp

@@ -2639,11 +2639,6 @@ int map_addinstancemap(const char *name, unsigned short instance_id)
 	}
 
 	struct map_data *src_map = map_getmapdata(src_m);
-
-	// Copy the map
-	memcpy(&map[dst_m], src_map, sizeof(struct map_data));
-
-	// Retrieve new map data
 	struct map_data *dst_map = map_getmapdata(dst_m);
 
 	strcpy(iname, name);
@@ -2658,17 +2653,15 @@ int map_addinstancemap(const char *name, unsigned short instance_id)
 		snprintf(dst_map->name, sizeof(dst_map->name),"%.3hu%s", instance_id, iname);
 	dst_map->name[MAP_NAME_LENGTH-1] = '\0';
 
-	// Mimic questinfo
-	if( src_map->qi_count ) {
-		dst_map->qi_count = src_map->qi_count;
-		CREATE( dst_map->qi_data, struct questinfo, dst_map->qi_count );
-		memcpy( dst_map->qi_data, src_map->qi_data, dst_map->qi_count * sizeof(struct questinfo) );
-	}
-
 	dst_map->m = dst_m;
 	dst_map->instance_id = instance_id;
 	dst_map->instance_src_map = src_m;
 	dst_map->users = 0;
+	dst_map->xs = src_map->xs;
+	dst_map->ys = src_map->ys;
+	dst_map->bxs = src_map->bxs;
+	dst_map->bys = src_map->bys;
+	dst_map->iwall_num = src_map->iwall_num;
 
 	memset(dst_map->npc, 0, sizeof(dst_map->npc));
 	dst_map->npc_num = 0;
@@ -2686,6 +2679,10 @@ int map_addinstancemap(const char *name, unsigned short instance_id)
 	dst_map->channel = NULL;
 	dst_map->mob_delete_timer = INVALID_TIMER;
 
+	map_data_copy(dst_map, src_map);
+
+	ShowInfo("[Instance] Created map '%s' ('%d') from map '%s' ('%d')\n", dst_map->name, dst_map->m, name, src_map->m);
+
 	map_addmap2db(dst_map);
 
 	return dst_m;
@@ -2734,7 +2731,7 @@ static int map_instancemap_clean(struct block_list *bl, va_list ap)
 	return 1;
 }
 
-static void map_free_questinfo(int m);
+static void map_free_questinfo(struct map_data *mapdata);
 
 /*==========================================
  * Deleting an instance map
@@ -2754,16 +2751,28 @@ int map_delinstancemap(int m)
 
 	if( mapdata->mob_delete_timer != INVALID_TIMER )
 		delete_timer(mapdata->mob_delete_timer, map_removemobs_timer);
+	mapdata->mob_delete_timer = INVALID_TIMER;
 
 	// Free memory
-	aFree(mapdata->cell);
-	aFree(mapdata->block);
-	aFree(mapdata->block_mob);
-	map_free_questinfo(m);
+	if (mapdata->cell)
+		aFree(mapdata->cell);
+	mapdata->cell = NULL;
+	if (mapdata->block)
+		aFree(mapdata->block);
+	mapdata->block = NULL;
+	if (mapdata->block_mob)
+		aFree(mapdata->block_mob);
+	mapdata->block_mob = NULL;
+
+	map_free_questinfo(mapdata);
 	mapdata->damage_adjust = {};
+	mapdata->flag.clear();
+	mapdata->skill_damage.clear();
 
-	mapindex_removemap( mapdata->index );
+	mapindex_removemap(mapdata->index);
 	map_removemapdb(mapdata);
+
+	memset(&mapdata->name, '\0', sizeof(map[0].name)); // just remove the name
 	return 1;
 }
 
@@ -3546,6 +3555,7 @@ void map_flags_init(void){
 		struct map_data *mapdata = &map[i];
 		union u_mapflag_args args = {};
 
+		mapdata->flag.clear();
 		mapdata->flag.reserve(MF_MAX); // Reserve the bucket size
 		args.flag_val = 100;
 
@@ -3555,14 +3565,59 @@ void map_flags_init(void){
 		map_setmapflag_sub(i, MF_BEXP, true, &args); // per map base exp multiplicator
 		map_setmapflag_sub(i, MF_JEXP, true, &args); // per map job exp multiplicator
 
-		// skill damage
+		// Clear adjustment data, will be reset after loading NPC
 		mapdata->damage_adjust = {};
+		mapdata->skill_damage.clear();
+		map_free_questinfo(mapdata);
+
+		if (instance_start && i >= instance_start)
+			continue;
 
 		// adjustments
 		if( battle_config.pk_mode && !mapdata->flag[MF_PVP] )
 			mapdata->flag[MF_PVP] = true; // make all maps pvp for pk_mode [Valaris]
+	}
+}
+
+/**
+* Copying map data from parent map for instance map
+* @param dst_map Mapdata will be copied to
+* @param src_map Copying data from
+*/
+void map_data_copy(struct map_data *dst_map, struct map_data *src_map) {
+	nullpo_retv(dst_map);
+	nullpo_retv(src_map);
+
+	memcpy(&dst_map->save, &src_map->save, sizeof(struct point));
+	memcpy(&dst_map->damage_adjust, &src_map->damage_adjust, sizeof(struct s_skill_damage));
 
-		map_free_questinfo(i);
+	dst_map->flag.insert(src_map->flag.begin(), src_map->flag.end());
+	dst_map->skill_damage.insert(dst_map->skill_damage.begin(), src_map->skill_damage.begin(), src_map->skill_damage.end());
+
+	dst_map->zone = src_map->zone;
+	dst_map->qi_count = 0;
+	dst_map->qi_data = NULL;
+
+	// Mimic questinfo
+	if (src_map->qi_count) {
+		dst_map->qi_count = src_map->qi_count;
+		CREATE(dst_map->qi_data, struct questinfo, dst_map->qi_count);
+		memcpy(dst_map->qi_data, src_map->qi_data, dst_map->qi_count * sizeof(struct questinfo));
+	}
+}
+
+/**
+* Copy map data for instance maps from its parents
+* that were cleared in map_flags_init() after reloadscript
+*/
+void map_data_copyall (void) {
+	if (!instance_start)
+		return;
+	for (int i = instance_start; i < map_num; i++) {
+		struct map_data *mapdata = &map[i];
+		if (!mapdata || mapdata->name[0] == '\0' || !mapdata->instance_src_map)
+			continue;
+		map_data_copy(mapdata, &map[mapdata->instance_src_map]);
 	}
 }
 
@@ -3760,6 +3815,12 @@ int map_readallmaps (void)
 		size = mapdata->bxs * mapdata->bys * sizeof(struct block_list*);
 		mapdata->block = (struct block_list**)aCalloc(size, 1);
 		mapdata->block_mob = (struct block_list**)aCalloc(size, 1);
+
+		memset(&mapdata->save, 0, sizeof(struct point));
+		mapdata->damage_adjust = {};
+		mapdata->qi_count = 0;
+		mapdata->qi_data = NULL;
+		mapdata->channel = NULL;
 	}
 
 	// intialization and configuration-dependent adjustments of mapflags
@@ -4275,9 +4336,10 @@ bool map_remove_questinfo(int m, struct npc_data *nd) {
 	return true;
 }
 
-static void map_free_questinfo(int m) {
+static void map_free_questinfo(struct map_data *mapdata) {
 	unsigned short i;
-	struct map_data *mapdata = map_getmapdata(m);
+	if (!mapdata)
+		return;
 
 	for(i = 0; i < mapdata->qi_count; i++) {
 		if (mapdata->qi_data[i].jobid)
@@ -4871,7 +4933,7 @@ void do_final(void){
 			for (int j=0; j<MAX_MOB_LIST_PER_MAP; j++)
 				if (mapdata->moblist[j]) aFree(mapdata->moblist[j]);
 		}
-		map_free_questinfo(i);
+		map_free_questinfo(mapdata);
 		mapdata->damage_adjust = {};
 	}
 

+ 2 - 0
src/map/map.hpp

@@ -1024,6 +1024,8 @@ int map_addflooritem(struct item *item, int amount, int16 m, int16 x, int16 y, i
 // instances
 int map_addinstancemap(const char *name, unsigned short instance_id);
 int map_delinstancemap(int m);
+void map_data_copyall(void);
+void map_data_copy(struct map_data *dst_map, struct map_data *src_map);
 
 // player to map session
 void map_addnickdb(int charid, const char* nick);

+ 1 - 0
src/map/npc.cpp

@@ -4537,6 +4537,7 @@ int npc_reload(void) {
 	//Execute the OnInit event for freshly loaded npcs. [Skotlex]
 	npc_event_runall(script_config.init_event_name);
 
+	map_data_copyall();
 	do_reload_instance();
 
 	// Execute rest of the startup events if connected to char-server. [Lance]