void merc_hom_revive(struct homun_data *hd, unsigned int hp, unsigned int sp) { struct map_session_data *sd = hd->master; hd->homunculus.hp = hd->battle_status.hp; if (!sd) return; clif_send_homdata(sd,SP_ACK,0); clif_hominfo(sd,hd,1); clif_hominfo(sd,hd,0); clif_homskillinfoblock(sd); }
/** * Revive homunculus * @param hd * @param hp * @param sp */ void hom_revive(struct homun_data *hd, unsigned int hp, unsigned int sp) { struct map_session_data *sd = hd->master; hd->homunculus.hp = hd->battle_status.hp; if (!sd) return; clif_send_homdata(sd,SP_ACK,0); clif_hominfo(sd,hd,1); clif_hominfo(sd,hd,0); clif_homskillinfoblock(sd); if (hd->homunculus.class_ == 6052) //eleanor sc_start(&hd->bl,&hd->bl, SC_STYLE_CHANGE, 100, MH_MD_FIGHTING, -1); }
int merc_hom_gainexp(struct homun_data *hd,int exp) { if(hd->homunculus.vaporize) return 1; if( hd->exp_next == 0 ) { hd->homunculus.exp = 0 ; return 0; } hd->homunculus.exp += exp; if(hd->homunculus.exp < hd->exp_next) { clif_hominfo(hd->master,hd,0); return 0; } //levelup do { merc_hom_levelup(hd) ; } while(hd->homunculus.exp > hd->exp_next && hd->exp_next != 0 ); if( hd->exp_next == 0 ) hd->homunculus.exp = 0 ; clif_specialeffect(&hd->bl,568,AREA); status_calc_homunculus(hd,0); status_percent_heal(&hd->bl, 100, 100); return 0; }
void merc_hom_skillup(struct homun_data *hd,int skillnum) { int i = 0 ; nullpo_retv(hd); if(hd->homunculus.vaporize) return; i = skillnum - HM_SKILLBASE; if(hd->homunculus.skillpts > 0 && hd->homunculus.hskill[i].id && hd->homunculus.hskill[i].flag == SKILL_FLAG_PERMANENT && //Don't allow raising while you have granted skills. [Skotlex] hd->homunculus.hskill[i].lv < merc_skill_tree_get_max(skillnum, hd->homunculus.class_) ) { hd->homunculus.hskill[i].lv++; hd->homunculus.skillpts-- ; status_calc_homunculus(hd,0); if (hd->master) { clif_homskillup(hd->master, skillnum); clif_hominfo(hd->master,hd,0); clif_homskillinfoblock(hd->master); } } }
//Vaporize a character's homun. If flag, HP needs to be 80% or above. int merc_hom_vaporize(struct map_session_data *sd, int flag) { struct homun_data *hd; nullpo_retr(0, sd); hd = sd->hd; if (!hd || hd->homunculus.vaporize) return 0; if (status_isdead(&hd->bl)) return 0; //Can't vaporize a dead homun. if (flag && status_calc_life(hd->battle_status.hp, hd->battle_status.max_hp)< 80) return 0; hd->regen.state.block = 3; //Block regen while vaporized. //Delete timers when vaporized. merc_hom_hungry_timer_delete(hd); hd->homunculus.vaporize = 1; if(battle_config.hom_setting&0x40) memset(hd->blockskill, 0, sizeof(hd->blockskill)); clif_hominfo(sd, sd->hd, 0); merc_save(hd); return unit_remove_map(&hd->bl, 0); }
/** * Vaporize a character's homunculus * @param sd * @param flag 1: then HP needs to be 80% or above. 2: then set to morph state. */ int hom_vaporize(struct map_session_data *sd, int flag) { struct homun_data *hd; nullpo_ret(sd); hd = sd->hd; if (!hd || hd->homunculus.vaporize) return 0; if (status_isdead(&hd->bl)) return 0; //Can't vaporize a dead homun. if (flag == HOM_ST_REST && get_percentage(hd->battle_status.hp, hd->battle_status.max_hp) < 80) return 0; hd->regen.state.block = 3; //Block regen while vaporized. //Delete timers when vaporized. hom_hungry_timer_delete(hd); hd->homunculus.vaporize = flag ? flag : HOM_ST_REST; if (battle_config.hom_setting&HOMSET_RESET_REUSESKILL_VAPORIZED) memset(hd->blockskill, 0, sizeof(hd->blockskill)); clif_hominfo(sd, sd->hd, 0); hom_save(hd); return unit_remove_map(&hd->bl, CLR_OUTSIGHT); }
/** * Level up an homunculus skill * @param hd * @param skill_id */ void hom_skillup(struct homun_data *hd, uint16 skill_id) { short idx = 0; nullpo_retv(hd); if (hd->homunculus.vaporize) return; if ((idx = hom_skill_get_index(skill_id)) < 0) return; if (hd->homunculus.skillpts > 0 && hd->homunculus.hskill[idx].id && hd->homunculus.hskill[idx].flag == SKILL_FLAG_PERMANENT && //Don't allow raising while you have granted skills. [Skotlex] hd->homunculus.hskill[idx].lv < hom_skill_tree_get_max(skill_id, hd->homunculus.class_) ) { hd->homunculus.hskill[idx].lv++; hd->homunculus.skillpts-- ; status_calc_homunculus(hd, SCO_NONE); if (hd->master) { clif_homskillup(hd->master, skill_id); clif_hominfo(hd->master,hd,0); clif_homskillinfoblock(hd->master); } } }
/** * Receive homunculus data from char server * @param account_id : owner account_id of the homon * @param sh : homonculus data from char-serv * @param flag : does the creation in inter-serv was a success (0:no,1:yes) * @return 0:failure, 1:sucess */ int hom_recv_data(uint32 account_id, struct s_homunculus *sh, int flag) { struct map_session_data *sd; struct homun_data *hd; bool created = false; sd = map_id2sd(account_id); if(!sd) return 0; if (sd->status.char_id != sh->char_id) { if (sd->status.hom_id == sh->hom_id) sh->char_id = sd->status.char_id; //Correct char id. else return 0; } if(!flag) { // Failed to load sd->status.hom_id = 0; return 0; } if (!sd->status.hom_id) { //Hom just created. sd->status.hom_id = sh->hom_id; created = true; } if (sd->hd) //uh? Overwrite the data. memcpy(&sd->hd->homunculus, sh, sizeof(struct s_homunculus)); else hom_alloc(sd, sh); hd = sd->hd; if (created) status_percent_heal(&hd->bl, 100, 100); if(hd && hd->homunculus.hp && !hd->homunculus.vaporize && hd->bl.prev == NULL && sd->bl.prev != NULL) { if(map_addblock(&hd->bl)) return 0; clif_spawn(&hd->bl); clif_send_homdata(sd,SP_ACK,0); clif_hominfo(sd,hd,1); clif_hominfo(sd,hd,0); // send this x2. dunno why, but kRO does that [blackhole89] clif_homskillinfoblock(sd); hom_init_timers(hd); } return 1; }
int merc_call_homunculus(struct map_session_data *sd) { struct homun_data *hd; if( sd->sc.data[SC__GROOMY] ) return 0; if( map[sd->bl.m].flag.ancient ) return 0; // Cannot call homunculus on Ancient WoE if (!sd->status.hom_id) //Create a new homun. return merc_create_homunculus_request(sd, HM_CLASS_BASE + rand(0, 7)) ; // If homunc not yet loaded, load it if (!sd->hd) return intif_homunculus_requestload(sd->status.account_id, sd->status.hom_id); hd = sd->hd; if (!hd->homunculus.vaporize) return 0; //Can't use this if homun wasn't vaporized. merc_hom_init_timers(hd); hd->homunculus.vaporize = 0; if (hd->bl.prev == NULL) { //Spawn him hd->bl.x = sd->bl.x; hd->bl.y = sd->bl.y; hd->bl.m = sd->bl.m; map_addblock(&hd->bl); clif_spawn(&hd->bl); clif_send_homdata(sd,SP_ACK,0); clif_hominfo(sd,hd,1); clif_hominfo(sd,hd,0); // send this x2. dunno why, but kRO does that [blackhole89] clif_homskillinfoblock(sd); if (battle_config.slaves_inherit_speed&1) status_calc_bl(&hd->bl, SCB_SPEED); merc_save(hd); } else //Warp him to master. unit_warp(&hd->bl,sd->bl.m, sd->bl.x, sd->bl.y,CLR_OUTSIGHT); return 1; }
/** * Make a player spawn a homonculus (call) * @param sd * @return False:failure, True:sucess */ bool hom_call(struct map_session_data *sd) { struct homun_data *hd; if (!sd->status.hom_id) //Create a new homun. return hom_create_request(sd, HM_CLASS_BASE + rnd_value(0, 7)) ; // If homunc not yet loaded, load it if (!sd->hd) return intif_homunculus_requestload(sd->status.account_id, sd->status.hom_id); hd = sd->hd; if (!hd->homunculus.vaporize) return false; //Can't use this if homun wasn't vaporized. if (hd->homunculus.vaporize == HOM_ST_MORPH) return false; // Can't call homunculus (morph state). hom_init_timers(hd); hd->homunculus.vaporize = HOM_ST_ACTIVE; if (hd->bl.prev == NULL) { //Spawn him hd->bl.x = sd->bl.x; hd->bl.y = sd->bl.y; hd->bl.m = sd->bl.m; if(map_addblock(&hd->bl)) return false; clif_spawn(&hd->bl); clif_send_homdata(sd,SP_ACK,0); clif_hominfo(sd,hd,1); clif_hominfo(sd,hd,0); // send this x2. dunno why, but kRO does that [blackhole89] clif_homskillinfoblock(sd); if (battle_config.slaves_inherit_speed&1) status_calc_bl(&hd->bl, SCB_SPEED); hom_save(hd); } else //Warp him to master. unit_warp(&hd->bl,sd->bl.m, sd->bl.x, sd->bl.y,CLR_OUTSIGHT); return true; }
int merc_hom_change_name_ack(struct map_session_data *sd, char* name, int flag) { struct homun_data *hd = sd->hd; if (!merc_is_hom_active(hd)) return 0; if (!flag) { clif_displaymessage(sd->fd, msg_txt(280)); // You cannot use this name return 0; } strncpy(hd->homunculus.name,name,NAME_LENGTH); clif_charnameack (0,&hd->bl); hd->homunculus.rename_flag = 1; clif_hominfo(sd,hd,0); return 1; }
/** * Acknowledge change name request from inter-server * @param sd * @param name * @param flag */ void hom_change_name_ack(struct map_session_data *sd, char* name, int flag) { struct homun_data *hd = sd->hd; if (!hom_is_active(hd)) return; normalize_name(name," ");//bugreport:3032 if (!flag || name[0] == '\0') { clif_displaymessage(sd->fd, msg_txt(sd,280)); // You cannot use this name return; } safestrncpy(hd->homunculus.name,name,NAME_LENGTH); clif_charnameack (0,&hd->bl); hd->homunculus.rename_flag = 1; clif_hominfo(sd,hd,0); }
/** * Add homunculus exp * @param hd * @param exp Added EXP */ void hom_gainexp(struct homun_data *hd,int exp) { int m_class; nullpo_retv(hd); if(hd->homunculus.vaporize) return; if((m_class = hom_class2mapid(hd->homunculus.class_)) == -1) { ShowError("hom_gainexp: Invalid class %d. \n", hd->homunculus.class_); return; } if( hd->exp_next == 0 || ((m_class&HOM_REG) && hd->homunculus.level >= battle_config.hom_max_level) || ((m_class&HOM_S) && hd->homunculus.level >= battle_config.hom_S_max_level) ) { hd->homunculus.exp = 0; return; } hd->homunculus.exp += exp; if (hd->homunculus.exp < hd->exp_next) { clif_hominfo(hd->master,hd,0); return; } // Do the levelup(s) while( hd->homunculus.exp > hd->exp_next ){ // Max level reached or error if( !hom_levelup(hd) ){ break; } } if( hd->exp_next == 0 ) hd->homunculus.exp = 0 ; clif_specialeffect(&hd->bl,568,AREA); status_calc_homunculus(hd, SCO_NONE); status_percent_heal(&hd->bl, 100, 100); }
/** * Delete a homunculus, completely "killing it". * Emote is the emotion the master should use, send negative to disable. * @param hd * @param emote */ int hom_delete(struct homun_data *hd, int emote) { struct map_session_data *sd; nullpo_ret(hd); sd = hd->master; if (!sd) return unit_free(&hd->bl,CLR_DEAD); if (emote >= 0) clif_emotion(&sd->bl, emote); //This makes it be deleted right away. hd->homunculus.intimacy = 0; // Send homunculus_dead to client hd->homunculus.hp = 0; clif_hominfo(sd, hd, 0); return unit_remove_map(&hd->bl,CLR_OUTSIGHT); }
int merc_hom_gainexp(struct homun_data *hd,int exp) { int m_class; if(hd->homunculus.vaporize) return 1; if((m_class = hom_class2mapid(hd->homunculus.class_)) == -1) { ShowError("merc_hom_gainexp: Invalid class %d. \n", hd->homunculus.class_); return 0; } if( hd->exp_next == 0 || ((m_class&HOM_REG) && hd->homunculus.level >= battle_config.hom_max_level) || ((m_class&HOM_S) && hd->homunculus.level >= battle_config.hom_S_max_level) ) { hd->homunculus.exp = 0; return 0; } hd->homunculus.exp += exp; if(hd->homunculus.exp < hd->exp_next) { clif_hominfo(hd->master,hd,0); return 0; } //levelup do { merc_hom_levelup(hd) ; } while(hd->homunculus.exp > hd->exp_next && hd->exp_next != 0 ); if( hd->exp_next == 0 ) hd->homunculus.exp = 0 ; clif_specialeffect(&hd->bl,568,AREA); status_calc_homunculus(hd,0); status_percent_heal(&hd->bl, 100, 100); return 0; }
int merc_hom_gainexp(struct homun_data *hd,int exp) { struct map_session_data *sd; struct s_homunculus *hom; hom = &hd->homunculus; sd = hd->master; if(hd->homunculus.vaporize) return 1; if( hd->exp_next == 0 ) { hd->homunculus.exp = 0 ; return 0; } if (sd->sc.data[SC_EXPBOOST]) exp += exp*((sd->sc.data[SC_EXPBOOST]->val1)/100); hd->homunculus.exp += exp; if(hd->homunculus.exp < hd->exp_next) { clif_hominfo(hd->master,hd,0); return 0; } //levelup do { merc_hom_levelup(hd) ; } while(hd->homunculus.exp > hd->exp_next && hd->exp_next != 0 && hom->evomoment == 0 ); if( hd->exp_next == 0 ) hd->homunculus.exp = 0 ; clif_specialeffect(&hd->bl,705,AREA); status_calc_homunculus(hd,0); status_percent_heal(&hd->bl, 100, 100); return 0; }
/** * Update homunculus info to master after healing * @param hd */ void hom_heal(struct homun_data *hd) { clif_hominfo(hd->master,hd,0); }
/** * Homunculus leveled up * @param hd */ int hom_levelup(struct homun_data *hd) { struct s_homunculus *hom; struct h_stats *min = NULL, *max = NULL; int growth_str, growth_agi, growth_vit, growth_int, growth_dex, growth_luk ; int growth_max_hp, growth_max_sp ; int m_class; if ((m_class = hom_class2mapid(hd->homunculus.class_)) == -1) { ShowError("hom_levelup: Invalid class %d. \n", hd->homunculus.class_); return 0; } /// When homunculus is homunculus S, we check to see if we need to apply previous class stats if(m_class&HOM_S && hd->homunculus.level < battle_config.hom_S_growth_level) { int i; if (!hd->homunculus.prev_class) { /// We also need to be sure that the previous class exists, otherwise give it something to work with hd->homunculus.prev_class = 6001; } // Give the homunculus the level up stats database it needs i = hom_search(hd->homunculus.prev_class,HOMUNCULUS_CLASS); if (i < 0) // Nothing should go wrong here, but check anyways return 0; max = &homunculus_db[i].gmax; min = &homunculus_db[i].gmin; } if (((m_class&HOM_REG) && hd->homunculus.level >= battle_config.hom_max_level) || ((m_class&HOM_S) && hd->homunculus.level >= battle_config.hom_S_max_level) || !hd->exp_next || hd->homunculus.exp < hd->exp_next) return 0; hom = &hd->homunculus; hom->level++ ; if (!(hom->level % 3)) hom->skillpts++ ; //1 skillpoint each 3 base level hom->exp -= hd->exp_next ; hd->exp_next = hexptbl[hom->level - 1] ; if (!max) { max = &hd->homunculusDB->gmax; min = &hd->homunculusDB->gmin; } growth_max_hp = rnd_value(min->HP, max->HP); growth_max_sp = rnd_value(min->SP, max->SP); growth_str = rnd_value(min->str, max->str); growth_agi = rnd_value(min->agi, max->agi); growth_vit = rnd_value(min->vit, max->vit); growth_dex = rnd_value(min->dex, max->dex); growth_int = rnd_value(min->int_,max->int_); growth_luk = rnd_value(min->luk, max->luk); //Aegis discards the decimals in the stat growth values! growth_str-=growth_str%10; growth_agi-=growth_agi%10; growth_vit-=growth_vit%10; growth_dex-=growth_dex%10; growth_int-=growth_int%10; growth_luk-=growth_luk%10; hom->max_hp += growth_max_hp; hom->max_sp += growth_max_sp; hom->str += growth_str; hom->agi += growth_agi; hom->vit += growth_vit; hom->dex += growth_dex; hom->int_+= growth_int; hom->luk += growth_luk; APPLY_HOMUN_LEVEL_STATWEIGHT(); // Needed to update skill list for mutated homunculus so unlocked skills will appear when the needed level is reached. status_calc_homunculus(hd,SCO_NONE); clif_hominfo(hd->master,hd,0); clif_homskillinfoblock(hd->master); if ( hd->master && battle_config.homunculus_show_growth ) { char output[256] ; sprintf(output, "Growth: hp:%d sp:%d str(%.2f) agi(%.2f) vit(%.2f) int(%.2f) dex(%.2f) luk(%.2f) ", growth_max_hp, growth_max_sp, growth_str/10.0, growth_agi/10.0, growth_vit/10.0, growth_int/10.0, growth_dex/10.0, growth_luk/10.0); clif_messagecolor(&hd->master->bl, color_table[COLOR_LIGHT_GREEN], output, false, SELF); } return 1; }
void merc_damage(struct homun_data *hd) { clif_hominfo(hd->master,hd,0); }
void merc_hom_heal(struct homun_data *hd,int hp,int sp) { clif_hominfo(hd->master,hd,0); }
void merc_damage(struct homun_data *hd,struct block_list *src,int hp,int sp) { clif_hominfo(hd->master,hd,0); }
/** * Update homunculus info to its master after receiving damage * @param hd */ void hom_damage(struct homun_data *hd) { if (hd->master) clif_hominfo(hd->master,hd,0); }