diff --git a/Changelog-Trunk.txt b/Changelog-Trunk.txt index 1438d349f9..8d0bd5d266 100644 --- a/Changelog-Trunk.txt +++ b/Changelog-Trunk.txt @@ -4,6 +4,8 @@ AS OF SVN REV. 5091, WE ARE NOW USING TRUNK. ALL UNTESTED BUGFIXES/FEATURES GO IF YOU HAVE A WORKING AND TESTED BUGFIX PUT IT INTO STABLE AS WELL AS TRUNK. 2006/08/10 + * Code cleanup on homunc, they stay in memory until player disconnect or + homunc destruction [Toms] * Corrected Advanced Jobs HP bonus from 30% -> 25% [Skotlex] * Hopefully fixed family-party-even-share not breaking when a member logs out. [Skotlex] diff --git a/src/map/map.c b/src/map/map.c index 71af455301..1f4a2ec4b6 100644 --- a/src/map/map.c +++ b/src/map/map.c @@ -1669,7 +1669,7 @@ int map_quit(struct map_session_data *sd) { sd->state.waitingdisconnect = 1; if (sd->pd) unit_free(&sd->pd->bl); if(sd->status.hom_id > 0 && sd->hd) //[orn] - merc_hom_delete(sd->hd, 0) ; + merc_hom_delete(sd->hd, 2) ; unit_free(&sd->bl); chrif_save(sd,1); } else { //Try to free some data, without saving anything (this could be invoked on map server change. [Skotlex] diff --git a/src/map/mercenary.c b/src/map/mercenary.c index 47c2ca686f..6304f7f7db 100644 --- a/src/map/mercenary.c +++ b/src/map/mercenary.c @@ -113,7 +113,7 @@ void merc_damage(struct homun_data *hd,struct block_list *src,int hp,int sp) int merc_hom_dead(struct homun_data *hd, struct block_list *src) { - hd->master->homunculus.hp = 0 ; + hd->battle_status.hp = hd->master->homunculus.hp = 0 ; clif_hominfo(hd->master,hd,0); // Send dead flag if(!merc_hom_decrease_intimacy(hd, 100)) { // Intimacy was < 100 merc_stop_walking(hd, 1); @@ -122,16 +122,24 @@ int merc_hom_dead(struct homun_data *hd, struct block_list *src) merc_hom_delete(hd,1) ; return 1 ; } + clif_send_homdata(hd->master,SP_INTIMATE,hd->master->homunculus.intimacy / 100); clif_emotion(&hd->bl, 16) ; //wah clif_emotion(&hd->master->bl, 28) ; //sob merc_hom_delete(hd, 0); - return 3; //Remove it from map. + return 1; // Removing is handled by merc_hom_delete } int merc_hom_delete(struct homun_data *hd, int flag) { nullpo_retr(0, hd); + + if ((flag & 2) && hd->bl.prev == NULL) + { + // Homunc was already removed from map, so just free the bl + return unit_free(&hd->bl); + } + // Delete homunculus if ( flag&1 ) { //sabbath intif_homunculus_requestdelete(hd->master->homunculus.hom_id) ; @@ -140,9 +148,9 @@ int merc_hom_delete(struct homun_data *hd, int flag) hd->master->homunculus.hom_id = 0; chrif_save(hd->master,0); } else - merc_save(hd) ; + merc_save(hd); - return unit_free(&hd->bl); + return unit_remove_map(&hd->bl, 0); } int merc_hom_calc_skilltree(struct map_session_data *sd) @@ -456,23 +464,32 @@ static int merc_natural_heal_sub(struct homun_data *hd,int tick) { int merc_natural_heal(int tid,unsigned int tick,int id,int data) { struct map_session_data *sd; + struct homun_data * hd; sd=map_id2sd(id); - - nullpo_retr(0, sd); - - sd->hd->natural_heal_timer = -1; - - if(sd->homunculus.vaporize) + if(!sd) return 1; - if(sd && sd->hd) { - natural_heal_diff_tick = DIFF_TICK(tick,natural_heal_prev_tick); - merc_natural_heal_sub(sd->hd, tick); - - natural_heal_prev_tick = tick; - sd->hd->natural_heal_timer = add_timer(gettick()+battle_config.natural_healhp_interval, merc_natural_heal,sd->bl.id,0); + if(!sd->status.hom_id || !(hd = sd->hd)) + return 1; + + if(hd->natural_heal_timer != tid){ + if(battle_config.error_log) + ShowError("merc_natural_heal %d != %d\n",hd->natural_heal_timer,tid); + return 1; } + + hd->natural_heal_timer = -1; + + if(sd->homunculus.vaporize || sd->homunculus.hp == 0) + return 1; + + natural_heal_diff_tick = DIFF_TICK(tick,natural_heal_prev_tick); + merc_natural_heal_sub(hd, tick); + + natural_heal_prev_tick = tick; + sd->hd->natural_heal_timer = add_timer(gettick()+battle_config.natural_healhp_interval, merc_natural_heal,sd->bl.id,0); + return 0; } @@ -721,7 +738,8 @@ int search_homunculusDB_index(int key,int type) return -1; } -int merc_hom_data_init(struct map_session_data *sd) +// Create homunc structure +int merc_hom_create(struct map_session_data *sd) { struct homun_data *hd; int i = 0 ; @@ -737,12 +755,16 @@ int merc_hom_data_init(struct map_session_data *sd) } sd->hd = hd = (struct homun_data *)aCalloc(1,sizeof(struct homun_data)); hd->homunculusDB = &homunculus_db[i]; - merc_calc_pos(hd,sd->bl.x,sd->bl.y,sd->ud.dir); - hd->bl.x = hd->ud.to_x; - hd->bl.y = hd->ud.to_y; hd->master = sd; + return merc_hom_data_init(sd); +} - sd->status.hom_id = sd->homunculus.hom_id ; +int merc_hom_data_init(struct map_session_data *sd) +{ + struct homun_data * hd = sd->hd; + int i; + + nullpo_retr(1, hd); hd->bl.m=sd->bl.m; hd->bl.x=sd->bl.x; @@ -782,48 +804,56 @@ int merc_hom_data_init(struct map_session_data *sd) map_addiddb(&hd->bl); status_calc_homunculus(hd,1); - //timer - hd->hungry_timer = add_timer(gettick()+hd->homunculusDB->hungryDelay,merc_hom_hungry,sd->bl.id,0); - natural_heal_prev_tick = gettick(); - hd->natural_heal_timer = add_timer(gettick()+battle_config.natural_healhp_interval, merc_natural_heal,sd->bl.id,0); - + + // Timers + hd->hungry_timer = add_timer(gettick()+hd->homunculusDB->hungryDelay,merc_hom_hungry,hd->master->bl.id,0); + natural_heal_prev_tick = gettick(); + hd->natural_heal_timer = add_timer(gettick()+battle_config.natural_healhp_interval, merc_natural_heal,hd->master->bl.id,0); return 0; } + // FIX call_homunculus [albator] int merc_call_homunculus(struct map_session_data *sd) { int class_ = 0 ; nullpo_retr(0, sd); - // call vaporized homunculus [albator] - if(sd->homunculus.vaporize == 1) + if (!sd->status.hom_id) { - sd->homunculus.vaporize = 0; - merc_hom_data_init(sd); - - if ( sd->homunculus.hp && sd->hd && sd->bl.prev != NULL) { - map_addblock(&sd->hd->bl); - clif_spawn(&sd->hd->bl); - clif_send_homdata(sd,SP_ACK,0); - clif_hominfo(sd,sd->hd,1); - clif_hominfo(sd,sd->hd,0); // send this x2. dunno why, but kRO does that [blackhole89] - clif_homskillinfoblock(sd); - } - // save - merc_save(sd->hd); - return 1; - - } - - if ( sd->status.hom_id ) { - return merc_hom_recv_data(sd->status.account_id, &sd->homunculus, 1 ) ; - } else { class_ = 6000 + rand(1, 8) ; return merc_create_homunculus(sd, class_) ; } - + // If homunc not yet loaded, load it, else just activate it + if (!sd->hd) + merc_hom_create(sd); + else + merc_hom_data_init(sd); + + // call vaporized homunculus [albator] + if(sd->homunculus.vaporize == 1) + { + sd->homunculus.vaporize = 0; + } + else + { + // Homunc was dead, set hp to 1 + sd->homunculus.hp = 1 ; + } + + if ( sd->homunculus.hp && sd->hd && sd->bl.prev != NULL) { + map_addblock(&sd->hd->bl); + clif_spawn(&sd->hd->bl); + clif_send_homdata(sd,SP_ACK,0); + clif_hominfo(sd,sd->hd,1); + clif_hominfo(sd,sd->hd,0); // send this x2. dunno why, but kRO does that [blackhole89] + clif_homskillinfoblock(sd); + } + // save + merc_save(sd->hd); + return 1; } + // Albator // Recv data of an homunculus after it loading int merc_hom_recv_data(int account_id, struct s_homunculus *sh, int flag) @@ -840,13 +870,9 @@ int merc_hom_recv_data(int account_id, struct s_homunculus *sh, int flag) } memcpy(&sd->homunculus, sh, sizeof(struct s_homunculus)); - if ( flag == 2 ) { - sh->hp = 1 ; - sd->homunculus.hp = 1 ; - } - if(sd->homunculus.hp && sh->vaporize!=1) + if(sd->homunculus.hp && sd->homunculus.vaporize!=1) { - merc_hom_data_init(sd); + merc_hom_create(sd); if ( sd->hd && sd->bl.prev != NULL) { map_addblock(&sd->hd->bl); @@ -907,19 +933,23 @@ int merc_hom_revive(struct map_session_data *sd, int per) { nullpo_retr(0, sd); - merc_hom_data_init(sd); + // Homunc not already loaded, load it, else just init timers + if (!sd->hd) + merc_hom_create(sd); + else + merc_hom_data_init(sd); - if ( sd->hd && sd->bl.prev != NULL) { - sd->homunculus.hp = sd->hd->base_status.hp = sd->hd->battle_status.hp = 1 ; - status_heal(&sd->hd->bl, sd->homunculus.max_hp*per/100, 0, 1) ; - map_addblock(&sd->hd->bl); - clif_spawn(&sd->hd->bl); - clif_send_homdata(sd,SP_ACK,0); - clif_hominfo(sd,sd->hd,1); - clif_hominfo(sd,sd->hd,0); - clif_homskillinfoblock(sd); - clif_specialeffect(&sd->hd->bl,77,AREA) ; //resurrection angel - } + if ( sd->hd && sd->bl.prev != NULL) { + sd->homunculus.hp = sd->hd->base_status.hp = sd->hd->battle_status.hp = 1 ; + status_heal(&sd->hd->bl, sd->homunculus.max_hp*per/100, 0, 1) ; + map_addblock(&sd->hd->bl); + clif_spawn(&sd->hd->bl); + clif_send_homdata(sd,SP_ACK,0); + clif_hominfo(sd,sd->hd,1); + clif_hominfo(sd,sd->hd,0); + clif_homskillinfoblock(sd); + clif_specialeffect(&sd->hd->bl,77,AREA) ; //resurrection angel + } return 1 ; } diff --git a/src/map/mercenary.h b/src/map/mercenary.h index d81cb9be77..aa07538ff7 100644 --- a/src/map/mercenary.h +++ b/src/map/mercenary.h @@ -46,7 +46,8 @@ enum { SP_INTIMATE = 0x100, SP_HUNGRY = 0x200 }; - +// merc_is_hom_alive(struct homun_data *) +#define merc_is_hom_active(x) (x && x->master && x->master->homunculus.vaporize != 1 && x->battle_status.hp != 0) int do_init_merc(void); int merc_hom_recv_data(int account_id, struct s_homunculus *sh, int flag); //albator void merc_load_sub(struct homun_data *hd, struct map_session_data *sd); @@ -79,3 +80,4 @@ int read_homunculusdb(void); int merc_hom_increase_intimacy(struct homun_data * hd, unsigned int value); int merc_hom_decrease_intimacy(struct homun_data * hd, unsigned int value); int merc_skill_tree_get_max(int id, int b_class); +int merc_hom_data_init(struct map_session_data *sd); diff --git a/src/map/skill.c b/src/map/skill.c index 8691aaff01..0e90ee1894 100644 --- a/src/map/skill.c +++ b/src/map/skill.c @@ -5489,7 +5489,7 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, in case AM_CALLHOMUN: //[orn] if (sd) { - if ((sd->status.hom_id == 0 || sd->homunculus.vaporize == 1)) { + if (sd->status.hom_id == 0 || sd->homunculus.vaporize == 1) { if (sd->status.hom_id == 0) { i = pc_search_inventory(sd,7142); if(i < 0) { @@ -5509,12 +5509,12 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, in { if (sd) { - if (sd->hd && ( sd->hd->battle_status.hp >= (sd->hd->battle_status.max_hp * 80 / 100 ) ) ) { + if (sd->hd && !sd->homunculus.vaporize && ( sd->hd->battle_status.hp >= (sd->hd->battle_status.max_hp * 80 / 100 ) ) ) { sd->homunculus.vaporize = 1; clif_hominfo(sd, sd->hd, 0); merc_hom_delete(sd->hd, 0) ; - } - clif_skill_fail(sd,skillid,0,0); + } else + clif_skill_fail(sd,skillid,0,0); } break; } diff --git a/src/map/unit.c b/src/map/unit.c index c9a7c5176d..d7c512714d 100644 --- a/src/map/unit.c +++ b/src/map/unit.c @@ -1605,6 +1605,30 @@ int unit_remove_map(struct block_list *bl, int clrtype) { map_freeblock_unlock(); return 0; } + } else if (bl->type == BL_HOM) { + struct homun_data *hd = (struct homun_data *) bl; + struct map_session_data *sd = hd->master; + + // Desactive timers + merc_hom_hungry_timer_delete(hd); + merc_natural_heal_timer_delete(hd); + + if(!sd) { + map_delblock(bl); + unit_free(bl); + map_freeblock_unlock(); + return 0; + } + + // Homunc was deleted or player is leaving the server, remove it from memory + if (sd->homunculus.hom_id == 0 || sd->state.waitingdisconnect) + { //Remove pet. + map_delblock(bl); + unit_free(bl); + sd->hd = NULL; + map_freeblock_unlock(); + return 1; + } } map_delblock(bl); map_freeblock_unlock(); @@ -1770,16 +1794,6 @@ int unit_free(struct block_list *bl) { } if(mob_is_clone(md->class_)) mob_clone_delete(md->class_); - } else if( bl->type == BL_HOM ) { //[orn] - struct homun_data *hd = (struct homun_data*)bl; - struct map_session_data *sd = hd->master; - merc_hom_hungry_timer_delete(hd); - merc_natural_heal_timer_delete(hd) ; - if (sd) { -// if(hd->intimacy > 0) -// intif_save_mercdata(sd->status.account_id,&sd->hom); - sd->hd = NULL; - } } skill_clear_unitgroup(bl);