浏览代码

Multiple dynamic npc (#7486)

* Vectorize npc_id_dynamic to support multiple dynamic npc with different ids

Co-authored-by: Lemongrass3110 <lemongrass@kstp.at>

Thanks to @dimasshotta and @eppc0330 !
Atemo 2 年之前
父节点
当前提交
ef602d98cb
共有 3 个文件被更改,包括 29 次插入16 次删除
  1. 14 6
      src/map/npc.cpp
  2. 1 1
      src/map/pc.hpp
  3. 14 9
      src/map/unit.cpp

+ 14 - 6
src/map/npc.cpp

@@ -3528,7 +3528,7 @@ int npc_unload(struct npc_data* nd, bool single) {
 		map_session_data* owner = map_charid2sd( nd->dynamicnpc.owner_char_id );
 
 		if( owner != nullptr ){
-			owner->npc_id_dynamic = 0;
+			util::vector_erase_if_exists(owner->npc_id_dynamic, nd->bl.id);
 		}
 	}
 
@@ -4515,7 +4515,7 @@ const char* npc_parse_duplicate( char* w1, char* w2, char* w3, char* w4, const c
 
 	if( owner != nullptr ){
 		nd->dynamicnpc.owner_char_id = owner->status.char_id;
-		owner->npc_id_dynamic = nd->bl.id;
+		owner->npc_id_dynamic.push_back(nd->bl.id);
 	}
 
 	switch( type ) {
@@ -5796,7 +5796,7 @@ TIMER_FUNC(npc_dynamicnpc_removal_timer){
 			return 0;
 		}
 
-		sd->npc_id_dynamic = 0;
+		// npc id from sd->npc_id_dynamic is removed in npc_unload
 	}
 
 	// Delete the NPC
@@ -5808,9 +5808,17 @@ TIMER_FUNC(npc_dynamicnpc_removal_timer){
 }
 
 struct npc_data* npc_duplicate_npc_for_player( struct npc_data& nd, map_session_data& sd ){
-	if( sd.npc_id_dynamic != 0 ){
-		clif_msg_color( &sd, C_DYNAMICNPC_TWICE, color_table[COLOR_LIGHT_YELLOW] );
-		return nullptr;
+	// A duplicate of a duplicate is still a duplicate of the same NPC
+	int src_id = nd.src_id > 0 ? nd.src_id : nd.bl.id;
+
+	for (const auto &it : sd.npc_id_dynamic) {
+		struct npc_data* src_nd = map_id2nd( it );
+
+		// Check if the source NPC id of currently active duplicates already exists.
+		if( src_nd != nullptr && src_nd->src_id == src_id ){
+			clif_msg_color( &sd, C_DYNAMICNPC_TWICE, color_table[COLOR_LIGHT_YELLOW] );
+			return nullptr;
+		}
 	}
 
 	if( map_getmapflag( sd.bl.m, MF_NODYNAMICNPC ) ){

+ 1 - 1
src/map/pc.hpp

@@ -492,7 +492,7 @@ public:
 	unsigned char head_dir; //0: Look forward. 1: Look right, 2: Look left.
 	t_tick client_tick;
 	int npc_id,npc_shopid; //for script follow scriptoid;   ,npcid
-	int npc_id_dynamic;
+	std::vector<int> npc_id_dynamic;
 	std::vector<int> areanpc, npc_ontouch_;	///< Array of OnTouch and OnTouch_ NPC ID
 	int npc_item_flag; //Marks the npc_id with which you can use items during interactions with said npc (see script command enable_itemuse)
 	int npc_menu; // internal variable, used in npc menu handling

+ 14 - 9
src/map/unit.cpp

@@ -3423,17 +3423,22 @@ int unit_free(struct block_list *bl, clr_type clrtype)
 				sd->npc_id = 0;
 			}
 
-			if( sd->npc_id_dynamic != 0 ){
-				struct npc_data* nd = map_id2nd( sd->npc_id_dynamic );
-
-				if( nd != nullptr ){
-					// Delete the NPC
-					npc_unload( nd, true );
-					// Update NPC event database
-					npc_read_event_script();
+			if( !sd->npc_id_dynamic.empty() ){
+				for (const auto &it : sd->npc_id_dynamic) {
+					struct npc_data* nd = map_id2nd( it );
+
+					if( nd != nullptr ){
+						// Erase the owner first to prevent loops from npc_unload
+						nd->dynamicnpc.owner_char_id = 0;
+
+						// Delete the NPC
+						npc_unload( nd, true );
+					}
 				}
+				// Update NPC event database
+				npc_read_event_script();
 
-				sd->npc_id_dynamic = 0;
+				sd->npc_id_dynamic.clear();
 			}
 
 			sd->combos.clear();