Parcourir la source

Clean-up sc_display
* Statuses can now also be saved for monsters
* Updated the status.txt docs
* Added missing BL_NPC to BL_SCEFFECT
* Corrected conditions for saving statuses depending on the unit type affected
* Corrected conditions for displaying status depending on the unit type affected when the status is given

Atemo il y a 1 an
Parent
commit
89327d2b67
12 fichiers modifiés avec 118 ajouts et 170 suppressions
  1. 9 6
      doc/status.txt
  2. 39 22
      src/map/clif.cpp
  3. 1 1
      src/map/clif.hpp
  4. 2 0
      src/map/mob.hpp
  5. 1 15
      src/map/npc.cpp
  6. 2 6
      src/map/npc.hpp
  7. 0 8
      src/map/pc.cpp
  8. 1 4
      src/map/pc.hpp
  9. 1 0
      src/map/script_constants.hpp
  10. 59 98
      src/map/status.cpp
  11. 2 1
      src/map/status.hpp
  12. 1 9
      src/map/unit.cpp

+ 9 - 6
doc/status.txt

@@ -196,9 +196,12 @@ Options: Special option/client effect state when status is active.
 Flags: Various status flags for specific status change events.
 
 	None                  - No special flag. (Default)
-	BlEffect              - Status should have BL_SCEFFECT as relevant effect, must have an EFST (displays on BL_PC, BL_HOM, BL_MER, BL_MOB, BL_ELEM). BL_PC is the default value.
-	DisplayPc             - Displays status effect when player logs in.
-	DislpayNpc            - Displays status effect on a NPC.
+	BlEffect              - Flag to send a visual effect to clients around if the affected unit is BL_PC, BL_HOM, BL_MER, BL_MOB, BL_ELEM or BL_NPC when the status is given.
+	                        The status must have an EFST defined in Icon - other than EFST_BLANK.
+	                        When not defined (default) the status is displayed to clients around when the affected unit is BL_PC (player) only.
+	DisplayPc             - Whether the status is displayed (again) to client around when the affected unit (player) appears in the client's range.
+	DisplayNpc            - Whether the status is displayed (again) to client around when the affected unit (NPC) appears in the client's range.
+	DisplayMob            - Whether the status is displayed (again) to client around when the affected unit (monster) appears in the client's range.
 	Debuff                - Status is considered a debuff. Used in combination with 'battle_config.debuff_on_logout'.
 	SetStand              - Sets player to standing state.
 	OverlapIgnoreLevel    - The status will successfully activate for any level if the status is already active.
@@ -208,9 +211,9 @@ Flags: Various status flags for specific status change events.
 	MobLoseTarget         - When active on a monster it will lose the target.
 	RestartOnMapWarp      - Restarts the timer of a status when warping to another map.
 	SpreadEffect          - Passes the status onto a target when SC_DEADLYINFECT is active.
-	SendVal1              - Notifies the client of a status change (val1).
-	SendVal2              - Notifies the client of a status change (val2).
-	SendVal3              - Notifies the client of a status change (val3).
+	SendVal1              - Whether val1 must be saved for DisplayPc, DisplayNpc, DisplayMob. If false, the value is ignored when the status is displayed again.
+	SendVal2              - Whether val2 must be saved for DisplayPc, DisplayNpc, DisplayMob. If false, the value is ignored when the status is displayed again.
+	SendVal3              - Whether val3 must be saved for DisplayPc, DisplayNpc, DisplayMob. If false, the value is ignored when the status is displayed again.
 
 	NoClearbuff           - Cannot be removed by 'status_change_clear_buffs()', 'sc_end SC_ALL', 'status_change_clear(3)', etc.
 	NoForcedEnd           - Cannot be removed by sc_end.

+ 39 - 22
src/map/clif.cpp

@@ -1721,7 +1721,7 @@ int clif_spawn( struct block_list *bl, bool walking ){
 				clif_spiritcharm(sd);
 			if (sd->status.robe)
 				clif_refreshlook(bl,bl->id,LOOK_ROBE,sd->status.robe,AREA);
-			clif_efst_status_change_sub(bl, bl, AREA);
+			clif_efst_status_change_sub( *bl, *bl, AREA );
 			clif_hat_effects( *sd, sd->bl, AREA );
 		}
 		break;
@@ -1734,6 +1734,7 @@ int clif_spawn( struct block_list *bl, bool walking ){
 				clif_specialeffect(&md->bl,EF_BABYBODY2,AREA);
 			if ( md->special_state.ai == AI_ABR || md->special_state.ai == AI_BIONIC )
 				clif_summon_init(*md);
+			clif_efst_status_change_sub( *bl, *bl, AREA );
 		}
 		break;
 	case BL_NPC:
@@ -1743,7 +1744,7 @@ int clif_spawn( struct block_list *bl, bool walking ){
 				clif_specialeffect(&nd->bl,EF_GIANTBODY2,AREA);
 			else if( nd->size == SZ_MEDIUM )
 				clif_specialeffect(&nd->bl,EF_BABYBODY2,AREA);
-			clif_efst_status_change_sub(bl, bl, AREA);
+			clif_efst_status_change_sub( *bl, *bl, AREA );
 			clif_progressbar_npc_area(nd);
 		}
 		break;
@@ -5062,7 +5063,7 @@ void clif_getareachar_unit( map_session_data* sd,struct block_list *bl ){
 				clif_sendbgemblem_single(sd->fd,tsd);
 			if ( tsd->status.robe )
 				clif_refreshlook(&sd->bl,bl->id,LOOK_ROBE,tsd->status.robe,SELF);
-			clif_efst_status_change_sub(&sd->bl, bl, SELF);
+			clif_efst_status_change_sub( sd->bl, *bl, SELF );
 			clif_hat_effects( *sd, tsd->bl, SELF );
 		}
 		break;
@@ -5079,7 +5080,7 @@ void clif_getareachar_unit( map_session_data* sd,struct block_list *bl ){
 				clif_specialeffect_single(bl,EF_GIANTBODY2,sd->fd);
 			else if( nd->size == SZ_MEDIUM )
 				clif_specialeffect_single(bl,EF_BABYBODY2,sd->fd);
-			clif_efst_status_change_sub(&sd->bl, bl, SELF);
+			clif_efst_status_change_sub( sd->bl, *bl, SELF );
 			clif_progressbar_npc(nd, sd);
 		}
 		break;
@@ -5098,6 +5099,7 @@ void clif_getareachar_unit( map_session_data* sd,struct block_list *bl ){
 						clif_monster_hp_bar(md, sd->fd);
 			}
 #endif
+			clif_efst_status_change_sub( *bl, *bl, AREA );
 		}
 		break;
 	case BL_PET:
@@ -6553,28 +6555,41 @@ void clif_status_change(struct block_list *bl, int type, int flag, t_tick tick,
  * @param bl: Objects walking into view
  * @param target: Client send type
  */
-void clif_efst_status_change_sub(struct block_list *tbl, struct block_list *bl, enum send_target target) {
-	unsigned char i;
-	struct sc_display_entry **sc_display;
-	unsigned char sc_display_count;
+void clif_efst_status_change_sub( block_list& tbl, block_list& bl, enum send_target target ){
 	bool spheres_sent;
+	std::unordered_map<sc_type, std::shared_ptr<sc_display_entry>> sc_display;
 
-	nullpo_retv(bl);
-
-	switch( bl->type ){
+	switch( bl.type ){
 		case BL_PC: {
-			map_session_data* sd = (map_session_data*)bl;
+			map_session_data* sd = BL_CAST(BL_PC, &bl);
+
+			if (sd == nullptr)
+				return;
 
 			sc_display = sd->sc_display;
-			sc_display_count = sd->sc_display_count;
+
 			spheres_sent = !sd->state.connect_new;
 			}
 			break;
 		case BL_NPC: {
-			struct npc_data* nd = (struct npc_data*)bl;
+			npc_data* nd = BL_CAST(BL_NPC, &bl);
+
+			if (nd == nullptr)
+				return;
 
 			sc_display = nd->sc_display;
-			sc_display_count = nd->sc_display_count;
+
+			spheres_sent = true;
+			}
+			break;
+		case BL_MOB: {
+			mob_data* md = BL_CAST(BL_MOB, &bl);
+
+			if (md == nullptr)
+				return;
+
+			sc_display = md->sc_display;
+
 			spheres_sent = true;
 			}
 			break;
@@ -6582,13 +6597,15 @@ void clif_efst_status_change_sub(struct block_list *tbl, struct block_list *bl,
 			return;
 	}
 
-	for (i = 0; i < sc_display_count; i++) {
-		enum sc_type type = sc_display[i]->type;
-		status_change *sc = status_get_sc(bl);
+	for ( const auto &it : sc_display ) {
+		std::shared_ptr<sc_display_entry> entry = it.second;
+
+		enum sc_type type = entry->type;
+		status_change *sc = status_get_sc( &bl );
 		const struct TimerData *td = (sc && sc->getSCE(type) ? get_timer(sc->getSCE(type)->timer) : nullptr);
 		t_tick tick = 0;
 
-		if (td)
+		if (td != nullptr)
 			tick = DIFF_TICK(td->tick, gettick());
 
 		// Status changes that need special handling
@@ -6610,9 +6627,9 @@ void clif_efst_status_change_sub(struct block_list *tbl, struct block_list *bl,
 		}
 
 #if PACKETVER > 20120418
-		clif_efst_status_change(tbl, bl->id, target, status_db.getIcon(type), tick, sc_display[i]->val1, sc_display[i]->val2, sc_display[i]->val3);
+		clif_efst_status_change( &tbl, bl.id, target, status_db.getIcon(type), tick, entry->val1, entry->val2, entry->val3 );
 #else
-		clif_status_change_sub(tbl, bl->id, status_db.getIcon(type), 1, tick, sc_display[i]->val1, sc_display[i]->val2, sc_display[i]->val3, target);
+		clif_status_change_sub( &tbl, bl.id, status_db.getIcon(type), 1, tick, entry->val1, entry->val2, entry->val3, target );
 #endif
 	}
 }
@@ -9882,7 +9899,7 @@ void clif_refresh(map_session_data *sd)
 		clif_clearunit_single( sd->bl.id, CLR_DEAD, *sd );
 	else
 		clif_changed_dir(&sd->bl, SELF);
-	clif_efst_status_change_sub(&sd->bl,&sd->bl,SELF);
+	clif_efst_status_change_sub( sd->bl, sd->bl, SELF );
 
 	//Issue #2143
 	//Cancel Trading State 

+ 1 - 1
src/map/clif.hpp

@@ -947,7 +947,7 @@ void clif_changemapcell(int fd, int16 m, int x, int y, int type, enum send_targe
 #define clif_status_load(bl, type, flag) clif_status_change((bl), (type), (flag), 0, 0, 0, 0)
 void clif_status_change(struct block_list *bl, int type, int flag, t_tick tick, int val1, int val2, int val3);
 void clif_efst_status_change(struct block_list *bl, int tid, enum send_target target, int type, t_tick tick, int val1, int val2, int val3);
-void clif_efst_status_change_sub(struct block_list *tbl, struct block_list *bl, enum send_target target);
+void clif_efst_status_change_sub( block_list& tbl, block_list& bl, enum send_target target );
 
 void clif_wis_message(map_session_data* sd, const char* nick, const char* mes, size_t mes_len, int gmlvl);
 void clif_wis_end( map_session_data& sd, e_ack_whisper result );

+ 2 - 0
src/map/mob.hpp

@@ -388,6 +388,8 @@ struct mob_data {
 	uint16 damagetaken;
 
 	e_mob_bosstype get_bosstype();
+
+	std::unordered_map<sc_type, std::shared_ptr<sc_display_entry>> sc_display;
 };
 
 class MobAvailDatabase : public YamlDatabase {

+ 1 - 15
src/map/npc.cpp

@@ -50,8 +50,6 @@ static int npc_mob=0;
 static int npc_delay_mob=0;
 static int npc_cache_mob=0;
 
-struct eri *npc_sc_display_ers;
-
 // Market Shop
 #if PACKETVER >= 20131223
 struct s_npc_market {
@@ -3527,18 +3525,10 @@ int npc_unload(struct npc_data* nd, bool single) {
 		}
 		if( nd->u.scr.guild_id )
 			guild_flag_remove(nd);
-		if( nd->sc_display_count ){
-			unsigned char i;
-
-			for( i = 0; i < nd->sc_display_count; i++ )
-				ers_free(npc_sc_display_ers, nd->sc_display[i]);
-			nd->sc_display_count = 0;
-			aFree(nd->sc_display);
-			nd->sc_display = nullptr;
-		}
 	}
 
 	nd->qi_data.clear();
+	nd->sc_display.clear();
 
 	script_stop_sleeptimers(nd->bl.id);
 
@@ -3772,8 +3762,6 @@ struct npc_data *npc_create_npc(int16 m, int16 x, int16 y){
 	nd->bl.m = m;
 	nd->bl.x = x;
 	nd->bl.y = y;
-	nd->sc_display = nullptr;
-	nd->sc_display_count = 0;
 	nd->progressbar.timeout = 0;
 	nd->vd = npc_viewdb[0]; // Default to JT_INVISIBLE
 	nd->dynamicnpc.owner_char_id = 0;
@@ -6146,7 +6134,6 @@ void do_final_npc(void) {
 	stylist_db.clear();
 	barter_db.clear();
 	ers_destroy(timer_event_ers);
-	ers_destroy(npc_sc_display_ers);
 	npc_src_files.clear();
 }
 
@@ -6212,7 +6199,6 @@ void do_init_npc(void){
 #endif
 
 	timer_event_ers = ers_new(sizeof(struct timer_event_data),"npc.cpp::timer_event_ers",ERS_OPT_NONE);
-	npc_sc_display_ers = ers_new(sizeof(struct sc_display_entry), "npc.cpp:npc_sc_display_ers", ERS_OPT_NONE);
 
 	npc_loadsrcfiles();
 

+ 2 - 6
src/map/npc.hpp

@@ -216,11 +216,10 @@ struct npc_data {
 		} barter;
 	} u;
 
-	struct sc_display_entry **sc_display;
-	unsigned char sc_display_count;
-
 	std::vector<std::shared_ptr<s_questinfo>> qi_data;
 
+	std::unordered_map<sc_type, std::shared_ptr<sc_display_entry>> sc_display;
+
 	struct {
 		t_tick timeout;
 		unsigned long color;
@@ -239,9 +238,6 @@ struct npc_data {
 	bool is_invisible;
 };
 
-struct eri;
-extern struct eri *npc_sc_display_ers;
-
 #define START_NPC_NUM 110000000
 
 enum e_job_types

+ 0 - 8
src/map/pc.cpp

@@ -84,7 +84,6 @@ SkillTreeDatabase skill_tree_db;
 int day_timer_tid = INVALID_TIMER;
 int night_timer_tid = INVALID_TIMER;
 
-struct eri *pc_sc_display_ers = nullptr;
 struct eri *num_reg_ers;
 struct eri *str_reg_ers;
 int pc_expiration_tid = INVALID_TIMER;
@@ -2209,10 +2208,6 @@ bool pc_authok(map_session_data *sd, uint32 login_id2, time_t expiration_time, i
 
 	pc_validate_skill(sd);
 
-	/* [Ind] */
-	sd->sc_display = nullptr;
-	sd->sc_display_count = 0;
-
 	// Player has not yet received the CashShop list
 	sd->status.cashshop_sent = false;
 
@@ -15847,7 +15842,6 @@ void do_final_pc(void) {
 	db_destroy(itemcd_db);
 	do_final_pc_groups();
 
-	ers_destroy(pc_sc_display_ers);
 	ers_destroy(num_reg_ers);
 	ers_destroy(str_reg_ers);
 
@@ -15906,11 +15900,9 @@ void do_init_pc(void) {
 
 	do_init_pc_groups();
 
-	pc_sc_display_ers = ers_new(sizeof(struct sc_display_entry), "pc.cpp:pc_sc_display_ers", ERS_OPT_FLEX_CHUNK);
 	num_reg_ers = ers_new(sizeof(struct script_reg_num), "pc.cpp:num_reg_ers", (ERSOptions)(ERS_OPT_CLEAN|ERS_OPT_FLEX_CHUNK));
 	str_reg_ers = ers_new(sizeof(struct script_reg_str), "pc.cpp:str_reg_ers", (ERSOptions)(ERS_OPT_CLEAN|ERS_OPT_FLEX_CHUNK));
 
-	ers_chunk_size(pc_sc_display_ers, 150);
 	ers_chunk_size(num_reg_ers, 300);
 	ers_chunk_size(str_reg_ers, 50);
 }

+ 1 - 4
src/map/pc.hpp

@@ -863,9 +863,7 @@ public:
 	unsigned char fontcolor;
 	t_tick *channel_tick;
 
-	/* [Ind] */
-	struct sc_display_entry **sc_display;
-	unsigned char sc_display_count;
+	std::unordered_map<enum sc_type, std::shared_ptr<sc_display_entry>> sc_display;
 
 	unsigned char delayed_damage; //[Ind]
 
@@ -944,7 +942,6 @@ public:
 	std::vector<uint32> party_booking_requests;
 };
 
-extern struct eri *pc_sc_display_ers; /// Player's SC display table
 
 /**
  * ERS for the bulk of pc vars

+ 1 - 0
src/map/script_constants.hpp

@@ -11230,6 +11230,7 @@
 	export_constant(SCF_REMOVEONUNEQUIPARMOR);
 	export_constant(SCF_REMOVEONHERMODE);
 	export_constant(SCF_REQUIRENOWEAPON);
+	export_constant(SCF_DISPLAYMOB);
 
 	/* enchantgrades */
 	export_constant(ENCHANTGRADE_NONE);

+ 59 - 98
src/map/status.cpp

@@ -9828,61 +9828,45 @@ t_tick status_get_sc_def(struct block_list *src, struct block_list *bl, enum sc_
  * @param dval1~3: Depends on type of status change
  * Author: Ind
  */
-void status_display_add(struct block_list *bl, enum sc_type type, int dval1, int dval2, int dval3) {
-	struct eri *eri;
-	struct sc_display_entry **sc_display;
-	struct sc_display_entry ***sc_display_ptr;
-	struct sc_display_entry *entry;
-	int i;
-	unsigned char sc_display_count;
-	unsigned char *sc_display_count_ptr;
+void status_display_add( block_list& bl, enum sc_type type, int val1, int val2, int val3 ){
+	std::shared_ptr<sc_display_entry> entry = std::make_shared<sc_display_entry>();
 
-	nullpo_retv(bl);
+	entry->type = type;
+	entry->val1 = val1;
+	entry->val2 = val2;
+	entry->val3 = val3;
 
-	switch( bl->type ){
+	switch( bl.type ){
 		case BL_PC: {
-			map_session_data* sd = (map_session_data*)bl;
+			map_session_data* sd = BL_CAST(BL_PC, &bl);
 
-			sc_display_ptr = &sd->sc_display;
-			sc_display_count_ptr = &sd->sc_display_count;
-			eri = pc_sc_display_ers;
+			if (sd == nullptr)
+				return;
+
+			sd->sc_display[type] = entry;
 			}
 			break;
 		case BL_NPC: {
-			struct npc_data* nd = (struct npc_data*)bl;
+			npc_data* nd = BL_CAST(BL_NPC, &bl);
+
+			if (nd == nullptr)
+				return;
 
-			sc_display_ptr = &nd->sc_display;
-			sc_display_count_ptr = &nd->sc_display_count;
-			eri = npc_sc_display_ers;
+			nd->sc_display[type] = entry;
 			}
 			break;
-		default:
-			return;
-	}
-
-	sc_display = *sc_display_ptr;
-	sc_display_count = *sc_display_count_ptr;
+		case BL_MOB: {
+			mob_data* md = BL_CAST(BL_MOB, &bl);
 
-	ARR_FIND(0, sc_display_count, i, sc_display[i]->type == type);
+			if (md == nullptr)
+				return;
 
-	if( i != sc_display_count ) {
-		sc_display[i]->val1 = dval1;
-		sc_display[i]->val2 = dval2;
-		sc_display[i]->val3 = dval3;
-		return;
+			md->sc_display[type] = entry;
+			}
+			break;
+		default:
+			return;
 	}
-
-	entry = ers_alloc(eri, struct sc_display_entry);
-
-	entry->type = type;
-	entry->val1 = dval1;
-	entry->val2 = dval2;
-	entry->val3 = dval3;
-
-	RECREATE(sc_display, struct sc_display_entry *, ++sc_display_count);
-	sc_display[sc_display_count - 1] = entry;
-	*sc_display_ptr = sc_display;
-	*sc_display_count_ptr = sc_display_count;
 }
 
 /**
@@ -9891,66 +9875,43 @@ void status_display_add(struct block_list *bl, enum sc_type type, int dval1, int
  * @param type: Status change (SC_*)
  * Author: Ind
  */
-void status_display_remove(struct block_list *bl, enum sc_type type) {
-	struct eri *eri;
-	struct sc_display_entry **sc_display;
-	struct sc_display_entry ***sc_display_ptr;
-	int i;
-	unsigned char sc_display_count;
-	unsigned char *sc_display_count_ptr;
-
-	nullpo_retv(bl);
-
-	switch( bl->type ){
+void status_display_remove( block_list& bl, enum sc_type type ){
+	switch( bl.type ){
 		case BL_PC: {
-			map_session_data* sd = (map_session_data*)bl;
+			map_session_data* sd = BL_CAST(BL_PC, &bl);
 
-			sc_display_ptr = &sd->sc_display;
-			sc_display_count_ptr = &sd->sc_display_count;
-			eri = pc_sc_display_ers;
+			if (sd == nullptr)
+				return;
+
+			if (util::umap_find( sd->sc_display, type ) != nullptr) {
+				sd->sc_display.erase( type );
+			}
 			}
 			break;
 		case BL_NPC: {
-			struct npc_data* nd = (struct npc_data*)bl;
+			npc_data* nd = BL_CAST(BL_NPC, &bl);
 
-			sc_display_ptr = &nd->sc_display;
-			sc_display_count_ptr = &nd->sc_display_count;
-			eri = npc_sc_display_ers;
+			if (nd == nullptr)
+				return;
+
+			if (util::umap_find( nd->sc_display, type ) != nullptr) {
+				nd->sc_display.erase( type );
+			}
 			}
 			break;
-		default:
-			return;
-	}
-
-	sc_display = *sc_display_ptr;
-	sc_display_count = *sc_display_count_ptr;
-
-	ARR_FIND(0, sc_display_count, i, sc_display[i]->type == type);
-
-	if( i != sc_display_count ) {
-		int cursor;
-
-		ers_free(eri, sc_display[i]);
-		sc_display[i] = nullptr;
-
-		/* The all-mighty compact-o-matic */
-		for( i = 0, cursor = 0; i < sc_display_count; i++ ) {
-			if( sc_display[i] == nullptr )
-				continue;
-
-			if( i != cursor )
-				sc_display[cursor] = sc_display[i];
-
-			cursor++;
-		}
+		case BL_MOB: {
+			mob_data* md = BL_CAST(BL_MOB, &bl);
 
-		if( !(sc_display_count = cursor) ) {
-			aFree(sc_display);
-			sc_display = nullptr;
-		}
+			if (md == nullptr)
+				return;
 
-		*sc_display_ptr = sc_display;
-		*sc_display_count_ptr = sc_display_count;
+			if (util::umap_find( md->sc_display, type ) != nullptr) {
+				md->sc_display.erase( type );
+			}
+			}
+			break;
+		default:
+			return;
 	}
 }
 
@@ -12831,8 +12792,8 @@ int status_change_start(struct block_list* src, struct block_list* bl,enum sc_ty
 		return 0;
 	}
 
-	/* [Ind] */
-	if (scdb->flag[SCF_DISPLAYPC] || scdb->flag[SCF_DISPLAYNPC]) {
+	// Save sc to display it again later
+	if (scdb->flag[SCF_DISPLAYPC] && bl->type == BL_PC || scdb->flag[SCF_DISPLAYNPC] && bl->type == BL_NPC || scdb->flag[SCF_DISPLAYMOB] && bl->type == BL_MOB) {
 		int dval1 = 0, dval2 = 0, dval3 = 0;
 
 		switch (type) {
@@ -12848,7 +12809,7 @@ int status_change_start(struct block_list* src, struct block_list* bl,enum sc_ty
 				dval1 = val1;
 				break;
 		}
-		status_display_add(bl,type,dval1,dval2,dval3);
+		status_display_add( *bl, type, dval1, dval2, dval3 );
 	}
 
 	//SC that force player to stand if is sitting
@@ -12935,7 +12896,7 @@ int status_change_start(struct block_list* src, struct block_list* bl,enum sc_ty
 		calc_flag.reset(SCB_BODY);
 	}*/
 
-	if (!(flag&SCSTART_NOICON) && !(flag&SCSTART_LOADED && scdb->flag[SCF_DISPLAYPC] || scdb->flag[SCF_DISPLAYNPC])) {
+	if (!(flag&SCSTART_NOICON) && !(flag&SCSTART_LOADED)) {
 		int status_icon = scdb->icon;
 
 #if PACKETVER < 20151104
@@ -13252,8 +13213,8 @@ int status_change_end(struct block_list* bl, enum sc_type type, int tid)
 
 	sc->clearSCE(type);
 
-	if (scdb->flag[SCF_DISPLAYPC] || scdb->flag[SCF_DISPLAYNPC])
-		status_display_remove(bl,type);
+	if (scdb->flag[SCF_DISPLAYPC] && bl->type == BL_PC || scdb->flag[SCF_DISPLAYNPC] && bl->type == BL_NPC || scdb->flag[SCF_DISPLAYMOB] && bl->type == BL_MOB)
+		status_display_remove( *bl, type );
 
 	vd = status_get_viewdata(bl);
 	std::bitset<SCB_MAX> calc_flag = scdb->calc_flag;

+ 2 - 1
src/map/status.hpp

@@ -3057,6 +3057,7 @@ enum e_status_change_flag : uint16 {
 	SCF_REMOVEONUNEQUIPARMOR,
 	SCF_REMOVEONHERMODE,
 	SCF_REQUIRENOWEAPON,
+	SCF_DISPLAYMOB,
 	SCF_MAX
 };
 
@@ -3140,7 +3141,7 @@ enum e_refine_chance_type {
 ///Define to determine who has regen
 #define BL_REGEN (BL_PC|BL_HOM|BL_MER|BL_ELEM)
 ///Define to determine who will receive a clif_status_change packet for effects that require one to display correctly
-#define BL_SCEFFECT (BL_PC|BL_HOM|BL_MER|BL_MOB|BL_ELEM)
+#define BL_SCEFFECT (BL_PC|BL_HOM|BL_MER|BL_MOB|BL_ELEM|BL_NPC)
 
 /** Basic damage info of a weapon
 * Required because players have two of these, one in status_data

+ 1 - 9
src/map/unit.cpp

@@ -3439,7 +3439,6 @@ int unit_free(struct block_list *bl, clr_type clrtype)
 	switch( bl->type ) {
 		case BL_PC: {
 			map_session_data *sd = (map_session_data*)bl;
-			int i;
 
 			if( status_isdead(bl) )
 				pc_setrestartvalue(sd,2);
@@ -3495,14 +3494,7 @@ int unit_free(struct block_list *bl, clr_type clrtype)
 
 			sd->combos.clear();
 
-			if( sd->sc_display_count ) { /* [Ind] */
-				for( i = 0; i < sd->sc_display_count; i++ )
-					ers_free(pc_sc_display_ers, sd->sc_display[i]);
-
-				sd->sc_display_count = 0;
-				aFree(sd->sc_display);
-				sd->sc_display = nullptr;
-			}
+			sd->sc_display.clear();
 
 			if( sd->quest_log != nullptr ) {
 				aFree(sd->quest_log);