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); } } }
/** * 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); } } }
int merc_hom_calc_skilltree(struct homun_data *hd, int flag_evolve) { int i, id = 0; int j, f = 1; int c = 0; nullpo_ret(hd); /* load previous homunculus form skills first. */ if( hd->homunculus.prev_class != 0 ) { c = hd->homunculus.prev_class - HM_CLASS_BASE; for( i = 0; i < MAX_SKILL_TREE && ( id = hskill_tree[c][i].id ) > 0; i++ ) { if( hd->homunculus.hskill[ id - HM_SKILLBASE ].id ) continue; //Skill already known. if(!battle_config.skillfree) { for( j = 0; j < MAX_PC_SKILL_REQUIRE; j++ ) { if( hskill_tree[c][i].need[j].id && merc_hom_checkskill(hd,hskill_tree[c][i].need[j].id) < hskill_tree[c][i].need[j].lv ) { f = 0; break; } } } if ( f ) hd->homunculus.hskill[id-HM_SKILLBASE].id = id; } f = 1; } c = hd->homunculus.class_ - HM_CLASS_BASE; for( i = 0; i < MAX_SKILL_TREE && ( id = hskill_tree[c][i].id ) > 0; i++ ) { if( hd->homunculus.hskill[ id - HM_SKILLBASE ].id ) continue; //Skill already known. j = ( flag_evolve ) ? 10 : hd->homunculus.intimacy; if( j < hskill_tree[c][i].intimacylv ) continue; if(!battle_config.skillfree) { for( j = 0; j < MAX_PC_SKILL_REQUIRE; j++ ) { if( hskill_tree[c][i].need[j].id && merc_hom_checkskill(hd,hskill_tree[c][i].need[j].id) < hskill_tree[c][i].need[j].lv ) { f = 0; break; } } } if ( f ) hd->homunculus.hskill[id-HM_SKILLBASE].id = id; } if( hd->master ) clif_homskillinfoblock(hd->master); return 0; }
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); }
/** * Shuffle homunculus status * @param hd */ int hom_shuffle(struct homun_data *hd) { struct map_session_data *sd; int lv, i, skillpts; unsigned int exp; struct s_skill b_skill[MAX_HOMUNSKILL]; if (!hom_is_active(hd)) return 0; sd = hd->master; lv = hd->homunculus.level; exp = hd->homunculus.exp; memcpy(&b_skill, &hd->homunculus.hskill, sizeof(b_skill)); skillpts = hd->homunculus.skillpts; //Reset values to level 1. hom_reset_stats(hd); //Level it back up for (i = 1; i < lv && hd->exp_next; i++){ hd->homunculus.exp += hd->exp_next; // Should never happen, but who knows if( !hom_levelup(hd) ) { break; } } if(hd->homunculus.class_ == hd->homunculusDB->evo_class) { //Evolved bonuses struct s_homunculus *hom = &hd->homunculus; struct h_stats *max = &hd->homunculusDB->emax, *min = &hd->homunculusDB->emin; hom->max_hp += rnd_value(min->HP, max->HP); hom->max_sp += rnd_value(min->SP, max->SP); hom->str += 10*rnd_value(min->str, max->str); hom->agi += 10*rnd_value(min->agi, max->agi); hom->vit += 10*rnd_value(min->vit, max->vit); hom->int_+= 10*rnd_value(min->int_,max->int_); hom->dex += 10*rnd_value(min->dex, max->dex); hom->luk += 10*rnd_value(min->luk, max->luk); } hd->homunculus.exp = exp; memcpy(&hd->homunculus.hskill, &b_skill, sizeof(b_skill)); hd->homunculus.skillpts = skillpts; clif_homskillinfoblock(sd); status_calc_homunculus(hd, SCO_NONE); status_percent_heal(&hd->bl, 100, 100); clif_specialeffect(&hd->bl,568,AREA); return 1; }
/** * 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; }
/** * Calculates homunculus skill tree * @param hd * @param flag_envolve */ void hom_calc_skilltree(struct homun_data *hd, int flag_evolve) { int i, skill_id = 0; int f = 1; short c = 0; nullpo_retv(hd); /* load previous homunculus form skills first. */ if (hd->homunculus.prev_class != 0 && (c = hom_class2index(hd->homunculus.prev_class)) >= 0) { for (i = 0; i < MAX_SKILL_TREE && (skill_id = hskill_tree[c][i].id) > 0; i++) { int idx = hom_skill_get_index(skill_id); if (idx < 0) continue; if (hd->homunculus.hskill[idx].id) continue; //Skill already known. if (!battle_config.skillfree) { int j; for (j = 0; j < MAX_HOM_SKILL_REQUIRE; j++) { if (hskill_tree[c][i].need[j].id && hom_checkskill(hd,hskill_tree[c][i].need[j].id) < hskill_tree[c][i].need[j].lv) { f = 0; break; } } } if (f) hd->homunculus.hskill[idx].id = skill_id; } f = 1; } if ((c = hom_class2index(hd->homunculus.class_)) < 0) return; for (i = 0; i < MAX_SKILL_TREE && (skill_id = hskill_tree[c][i].id) > 0; i++) { int intimacy; int idx = hom_skill_get_index(skill_id); if (idx < 0) continue; if (hd->homunculus.hskill[idx].id) continue; //Skill already known. intimacy = (flag_evolve) ? 10 : hd->homunculus.intimacy; if (intimacy < hskill_tree[c][i].intimacylv) continue; if (!battle_config.skillfree) { int j; for (j = 0; j < MAX_HOM_SKILL_REQUIRE; j++) { if (hskill_tree[c][i].need[j].id && hom_checkskill(hd,hskill_tree[c][i].need[j].id) < hskill_tree[c][i].need[j].lv) { f = 0; break; } } } if (f) hd->homunculus.hskill[idx].id = skill_id; } if (hd->master) clif_homskillinfoblock(hd->master); }
/** * 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; }
/** * Calculates homunculus skill tree * @param hd * @param flag_envolve */ void hom_calc_skilltree(struct homun_data *hd, bool flag_evolve) { uint8 i; short c = 0; nullpo_retv(hd); /* load previous homunculus form skills first. */ if (hd->homunculus.prev_class != 0 && (c = hom_class2index(hd->homunculus.prev_class)) >= 0) { for (i = 0; i < MAX_HOM_SKILL_TREE; i++) { uint16 skill_id; short idx = -1; bool fail = false; if (!(skill_id = hskill_tree[c][i].id) || (idx = hom_skill_get_index(skill_id)) == -1) continue; if (hd->homunculus.hskill[idx].id) continue; //Skill already known. if (!battle_config.skillfree) { uint8 j; if (hskill_tree[c][i].need_level > hd->homunculus.level) continue; for (j = 0; j < MAX_HOM_SKILL_REQUIRE; j++) { if (hskill_tree[c][i].need[j].id && hom_checkskill(hd,hskill_tree[c][i].need[j].id) < hskill_tree[c][i].need[j].lv) { fail = true; break; } } } if (!fail) hd->homunculus.hskill[idx].id = skill_id; } } if ((c = hom_class2index(hd->homunculus.class_)) < 0) return; for (i = 0; i < MAX_HOM_SKILL_TREE; i++) { unsigned int intimacy = 0; uint16 skill_id; short idx = -1; bool fail = false; if (!(skill_id = hskill_tree[c][i].id) || (idx = hom_skill_get_index(skill_id)) == -1) continue; if (hd->homunculus.hskill[idx].id) continue; //Skill already known. intimacy = (flag_evolve) ? 10 : hd->homunculus.intimacy; if (intimacy < hskill_tree[c][i].intimacy * 100) continue; if (!battle_config.skillfree) { uint8 j; if (hskill_tree[c][i].need_level > hd->homunculus.level) continue; for (j = 0; j < MAX_HOM_SKILL_REQUIRE; j++) { if (hskill_tree[c][i].need[j].id && hom_checkskill(hd,hskill_tree[c][i].need[j].id) < hskill_tree[c][i].need[j].lv) { fail = true; break; } } } if (!fail) hd->homunculus.hskill[idx].id = skill_id; } if (hd->master) clif_homskillinfoblock(hd->master); }
int merc_hom_levelup(struct homun_data *hd) { struct s_homunculus *hom; struct h_stats *min, *max; int growth_str, growth_agi, growth_vit, growth_int, growth_dex, growth_luk ; int growth_max_hp, growth_max_sp ; char output[256] ; if (hd->homunculus.level == hd->homunculusDB->maxlevel || !hd->exp_next || hd->homunculus.exp < hd->exp_next) return 0 ; hom = &hd->homunculus; hom->level++ ; if ( hom->level > 99 ) { if (!(hom->level % 2)) hom->skillpts++ ; //1 skill point for each 2 levels for mutated homunculus. } else { if (!(hom->level % 3)) hom->skillpts++ ; //1 skill point each 3 levels when below 100. } hom->exp -= hd->exp_next ; hd->exp_next = hexptbl[hom->level - 1] ; max = &hd->homunculusDB->gmax; min = &hd->homunculusDB->gmin; growth_max_hp = rand(min->HP, max->HP); growth_max_sp = rand(min->SP, max->SP); growth_str = rand(min->str, max->str); growth_agi = rand(min->agi, max->agi); growth_vit = rand(min->vit, max->vit); growth_dex = rand(min->dex, max->dex); growth_int = rand(min->int_,max->int_); growth_luk = rand(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; // Needed to update skill list for mutated homunculus so unlocked skills will appear when the needed level is reached. clif_homskillinfoblock(hd->master); if ( battle_config.homunculus_show_growth ) { 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_disp_onlyself(hd->master,output,strlen(output)); } return 1 ; }