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!
This commit is contained in:
Lemongrass3110 2017-08-11 19:27:33 +02:00 committed by GitHub
parent 9c6a89076d
commit abfd1980de
5 changed files with 107 additions and 5 deletions

View File

@ -336,9 +336,49 @@ int mobdb_checkid(const int id)
struct view_data * mob_get_viewdata(int mob_id) struct view_data * mob_get_viewdata(int mob_id)
{ {
if (mob_db(mob_id) == mob_dummy) if (mob_db(mob_id) == mob_dummy)
return 0; return NULL;
return &mob_db(mob_id)->vd; 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" * Cleans up mob-spawn data to make it "valid"
*------------------------------------------*/ *------------------------------------------*/
@ -5189,6 +5229,9 @@ static void mob_load(void)
mob_skill_db_set(); mob_skill_db_set();
} }
/**
* Initialize monster data
*/
void mob_db_load(void){ void mob_db_load(void){
memset(mob_db_data,0,sizeof(mob_db_data)); //Clear the array 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 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(); 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) { void mob_reload(void) {
do_final_mob(); do_final_mob();
mob_db_load(); mob_db_load();
map_foreachmob(mob_reload_sub);
} }
/**
* Clear spawn data for all monsters
*/
void mob_clear_spawninfo() void mob_clear_spawninfo()
{ //Clears spawn related information for a script reload. { //Clears spawn related information for a script reload.
int i; int i;

View File

@ -173,6 +173,7 @@ struct mob_data {
struct block_list bl; struct block_list bl;
struct unit_data ud; struct unit_data ud;
struct view_data *vd; 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_data status, *base_status; //Second one is in case of leveling up mobs, or tiny/large mobs.
struct status_change sc; struct status_change sc;
struct mob_db *db; //For quick data access (saves doing mob_db(md->mob_id) all the time) [Skotlex] 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_searchname_array(struct mob_db** data, int size, const char *str);
int mobdb_checkid(const int id); int mobdb_checkid(const int id);
struct view_data* mob_get_viewdata(int mob_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); 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);

View File

@ -17769,6 +17769,23 @@ BUILDIN_FUNC(setunitdata)
md->base_status = (struct status_data*)aCalloc(1, sizeof(struct status_data)); md->base_status = (struct status_data*)aCalloc(1, sizeof(struct status_data));
memcpy(md->base_status, &md->db->status, 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) { switch (type) {
case UMOB_SIZE: md->base_status->size = (unsigned char)value; calc_status = true; break; case UMOB_SIZE: md->base_status->size = (unsigned char)value; calc_status = true; break;
case UMOB_LEVEL: md->level = (unsigned short)value; 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_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_AI: md->special_state.ai = (enum mob_ai)value; break;
case UMOB_SCOPTION: md->sc.option = (unsigned short)value; break; case UMOB_SCOPTION: md->sc.option = (unsigned short)value; break;
case UMOB_SEX: md->vd->sex = (char)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); 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_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_HAIRCOLOR: clif_changelook(bl, LOOK_HAIR_COLOR, (unsigned short)value); break;
case UMOB_HEADBOTTOM: clif_changelook(bl, LOOK_HEAD_BOTTOM, (unsigned short)value); break; case UMOB_HEADBOTTOM: clif_changelook(bl, LOOK_HEAD_BOTTOM, (unsigned short)value); break;

View File

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

View File

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