Bläddra i källkod

Made view_data for mob unit changes persistent (#2316)

Made view_data for mobs changes persistent

Fixes #2269

Thanks to @Yuchinin
---
Fixed reloadmobdb breaking the view ids

Fixes #2326

Thanks to @karlseven
---
Allowed updating mob's class to a pc class
Fixed sex change so that the client is automatically refreshed
Respawn the monster on clientside if the class is changed

Thanks to @Jeybla and @aleos89 for helping!
Lemongrass3110 7 år sedan
förälder
incheckning
abfd1980de
5 ändrade filer med 107 tillägg och 5 borttagningar
  1. 75 1
      src/map/mob.c
  2. 3 0
      src/map/mob.h
  3. 19 2
      src/map/script.c
  4. 8 2
      src/map/status.c
  5. 2 0
      src/map/unit.c

+ 75 - 1
src/map/mob.c

@@ -336,9 +336,49 @@ int mobdb_checkid(const int id)
 struct view_data * mob_get_viewdata(int mob_id)
 {
 	if (mob_db(mob_id) == mob_dummy)
-		return 0;
+		return NULL;
 	return &mob_db(mob_id)->vd;
 }
+
+/**
+ * Create unique view data associated to a spawned monster.
+ * @param md: Mob to adjust
+ */
+void mob_set_dynamic_viewdata( struct mob_data* md ){
+	// If it is a valid monster and it has not already been created
+	if( md && !md->vd_changed ){
+		// Allocate a dynamic entry
+		struct view_data* vd = (struct view_data*)aMalloc( sizeof( struct view_data ) );
+
+		// Copy the current values
+		memcpy( vd, md->vd, sizeof( struct view_data ) );
+
+		// Update the pointer to the new entry
+		md->vd = vd;
+
+		// Flag it as changed so it is freed later on
+		md->vd_changed = true;
+	}
+}
+
+/**
+ * Free any view data associated to a spawned monster.
+ * @param md: Mob to free
+ */
+void mob_free_dynamic_viewdata( struct mob_data* md ){
+	// If it is a valid monster and it has already been allocated
+	if( md && md->vd_changed ){
+		// Free it
+		aFree( md->vd );
+
+		// Remove the reference
+		md->vd = NULL;
+
+		// Unflag it as changed
+		md->vd_changed = false;
+	}
+}
+
 /*==========================================
  * Cleans up mob-spawn data to make it "valid"
  *------------------------------------------*/
@@ -5189,6 +5229,9 @@ static void mob_load(void)
 	mob_skill_db_set();
 }
 
+/**
+ * Initialize monster data
+ */
 void mob_db_load(void){
 	memset(mob_db_data,0,sizeof(mob_db_data)); //Clear the array
 	mob_db_data[0] = (struct mob_db*)aCalloc(1, sizeof (struct mob_db));	//This mob is used for random spawns
@@ -5201,11 +5244,42 @@ void mob_db_load(void){
 	mob_load();
 }
 
+/**
+ * Apply the proper view data on monsters during mob_db reload.
+ * @param md: Mob to adjust
+ * @param args: va_list of arguments
+ * @return 0
+ */
+static int mob_reload_sub( struct mob_data *md, va_list args ){
+	if( md->bl.prev == NULL ){
+		return 0;
+	}
+
+	// If the view data was not overwritten manually
+	if( !md->vd_changed ){
+		// Get the new view data from the mob database
+		md->vd = mob_get_viewdata(md->mob_id);
+
+		// Respawn all mobs on client side so that they are displayed correctly(if their view id changed)
+		clif_clearunit_area(&md->bl, CLR_OUTSIGHT);
+		clif_spawn(&md->bl);
+	}
+
+	return 0;
+}
+
+/**
+ * Reload monster data
+ */
 void mob_reload(void) {
 	do_final_mob();
 	mob_db_load();
+	map_foreachmob(mob_reload_sub);
 }
 
+/**
+ * Clear spawn data for all monsters
+ */
 void mob_clear_spawninfo()
 {	//Clears spawn related information for a script reload.
 	int i;

+ 3 - 0
src/map/mob.h

@@ -173,6 +173,7 @@ struct mob_data {
 	struct block_list bl;
 	struct unit_data  ud;
 	struct view_data *vd;
+	bool vd_changed;
 	struct status_data status, *base_status; //Second one is in case of leveling up mobs, or tiny/large mobs.
 	struct status_change sc;
 	struct mob_db *db;	//For quick data access (saves doing mob_db(md->mob_id) all the time) [Skotlex]
@@ -298,6 +299,8 @@ int mobdb_searchname(const char *str);
 int mobdb_searchname_array(struct mob_db** data, int size, const char *str);
 int mobdb_checkid(const int id);
 struct view_data* mob_get_viewdata(int mob_id);
+void mob_set_dynamic_viewdata( struct mob_data* md );
+void mob_free_dynamic_viewdata( struct mob_data* md );
 
 struct mob_data *mob_once_spawn_sub(struct block_list *bl, int16 m, int16 x, int16 y, const char *mobname, int mob_id, const char *event, unsigned int size, unsigned int ai);
 

+ 19 - 2
src/map/script.c

@@ -17769,6 +17769,23 @@ BUILDIN_FUNC(setunitdata)
 			md->base_status = (struct status_data*)aCalloc(1, sizeof(struct status_data));
 			memcpy(md->base_status, &md->db->status, sizeof(struct status_data));
 		}
+
+		// Check if the view data will be modified
+		switch( type ){
+			case UMOB_SEX:
+			//case UMOB_CLASS: // Called by status_set_viewdata
+			case UMOB_HAIRSTYLE:
+			case UMOB_HAIRCOLOR:
+			case UMOB_HEADBOTTOM:
+			case UMOB_HEADMIDDLE:
+			case UMOB_HEADTOP:
+			case UMOB_CLOTHCOLOR:
+			case UMOB_SHIELD:
+			case UMOB_WEAPON:
+				mob_set_dynamic_viewdata( md );
+				break;
+		}
+
 		switch (type) {
 			case UMOB_SIZE: md->base_status->size = (unsigned char)value; calc_status = true; break;
 			case UMOB_LEVEL: md->level = (unsigned short)value; break;
@@ -17782,8 +17799,8 @@ BUILDIN_FUNC(setunitdata)
 			case UMOB_MODE: md->base_status->mode = (enum e_mode)value; calc_status = true; break;
 			case UMOB_AI: md->special_state.ai = (enum mob_ai)value; break;
 			case UMOB_SCOPTION: md->sc.option = (unsigned short)value; break;
-			case UMOB_SEX: md->vd->sex = (char)value; break;
-			case UMOB_CLASS: status_set_viewdata(bl, (unsigned short)value); break;
+			case UMOB_SEX: md->vd->sex = (char)value; clif_clearunit_area(bl, CLR_OUTSIGHT); clif_spawn(bl); break;
+			case UMOB_CLASS: status_set_viewdata(bl, (unsigned short)value); clif_clearunit_area(bl, CLR_OUTSIGHT); clif_spawn(bl); break;
 			case UMOB_HAIRSTYLE: clif_changelook(bl, LOOK_HAIR, (unsigned short)value); break;
 			case UMOB_HAIRCOLOR: clif_changelook(bl, LOOK_HAIR_COLOR, (unsigned short)value); break;
 			case UMOB_HEADBOTTOM: clif_changelook(bl, LOOK_HEAD_BOTTOM, (unsigned short)value); break;

+ 8 - 2
src/map/status.c

@@ -7680,9 +7680,15 @@ void status_set_viewdata(struct block_list *bl, int class_)
 	case BL_MOB:
 		{
 			TBL_MOB* md = (TBL_MOB*)bl;
-			if (vd)
+			if (vd){
+				mob_free_dynamic_viewdata( md );
+
 				md->vd = vd;
-			else
+			}else if( pcdb_checkid( class_ ) ){
+				mob_set_dynamic_viewdata( md );
+
+				md->vd->class_ = class_;
+			}else
 				ShowError("status_set_viewdata (MOB): No view data for class %d\n", class_);
 		}
 	break;

+ 2 - 0
src/map/unit.c

@@ -3305,6 +3305,8 @@ int unit_free(struct block_list *bl, clr_type clrtype)
 		case BL_MOB: {
 			struct mob_data *md = (struct mob_data*)bl;
 
+			mob_free_dynamic_viewdata( md );
+
 			if( md->spawn_timer != INVALID_TIMER ) {
 				delete_timer(md->spawn_timer,mob_delayspawn);
 				md->spawn_timer = INVALID_TIMER;