// Copyright (c) Copyright (c) Hercules Dev Team, licensed under GNU GPL. // Copyright (c) 2014 - 2015 Evol developers #include "common/hercules.h" #include #include #include #include "common/conf.h" #include "common/db.h" #include "common/HPMi.h" #include "common/memmgr.h" #include "common/mmo.h" #include "common/nullpo.h" #include "common/socket.h" #include "common/strlib.h" #include "common/timer.h" #include "map/pc.h" #include "map/npc.h" #include "map/homunculus.h" #include "map/script.h" #include "map/skill.h" #include "emap/skill.h" #include "emap/skill_const.h" #include "emap/skill_ground.h" #include "emap/skill_targeted.h" #include "emap/status.h" #include "emap/data/skilld.h" #include "emap/struct/skilldext.h" #include "plugins/HPMHooking.h" int eskill_get_index_post(int retVal, int skill_id) { if (skill_id >= EVOL_FIRST_SKILL && skill_id < EVOL_FIRST_SKILL + MAX_EVOL_SKILLS) { // 1478 + skill_id - 20000 skill_id = OLD_MAX_SKILL_DB + skill_id - EVOL_FIRST_SKILL; return skill_id; } return retVal; } int eskill_check_condition_castend_post(int retVal, TBL_PC* sd, uint16 skill_id, uint16 skill_lv) { // TMW2: Disabled (see below) if (0 && retVal && sd) { struct linkdb_node **label_linkdb = strdb_get(npc->ev_label_db, "OnSkillInvoke"); if (label_linkdb == NULL) return retVal; struct linkdb_node *node = *label_linkdb; while (node) { struct event_data* ev = node->data; if (ev) { pc->setreg(sd, script->add_variable("@skillId"), skill_id); pc->setreg(sd, script->add_variable("@skillLv"), skill_lv); script->run(ev->nd->u.scr.script, ev->pos, sd->bl.id, ev->nd->bl.id); } node = node->next; } } return retVal; } // TODO: eskill_castend_damage_id_unknown / Unused but now broken bool eskill_castend_nodamage_id_unknown(struct block_list *src, struct block_list *bl, uint16 *skill_id, uint16 *skill_lv, int64 *tick __attribute__ ((unused)), int *flag __attribute__ ((unused))) { //ShowDebug("Cast end nodamage id unknown!\n"); switch (*skill_id) { case EVOL_PHYSICAL_SHIELD: eskill_physical_shield(src, bl, *skill_id, *skill_lv); break; default: clif->skill_nodamage(src, bl, *skill_id, *skill_lv, 1); break; } //ShowDebug("Operation start!\n"); // 1: Check if src can become a sd; If not, ABORT struct map_session_data *sd = NULL; if (src->type == BL_HOM) { struct homun_data *hd = NULL; hd = BL_CAST(BL_HOM, src); sd = hd->master; } else { sd = BL_CAST(BL_PC, src); } if (!sd) return true; //ShowDebug("Source found!\n"); // 2: Add skill target info pc->setreg(sd, script->add_variable("@skillTarget"), bl->id); pc->setreg(sd, script->add_variable("@skillTargetX"), bl->x); pc->setreg(sd, script->add_variable("@skillTargetY"), bl->y); pc->setreg(sd, script->add_variable("@skillCaster"), src->id); //ShowDebug("Data filled! Targed was %d\n", bl->id); if (sd) { struct linkdb_node **label_linkdb = strdb_get(npc->ev_label_db, "OnSkillInvoke"); if (label_linkdb == NULL) return true; struct linkdb_node *node = *label_linkdb; while (node) { struct event_data* ev = node->data; if (ev) { pc->setreg(sd, script->add_variable("@skillId"), *skill_id); pc->setreg(sd, script->add_variable("@skillLv"), *skill_lv); script->run(ev->nd->u.scr.script, ev->pos, sd->bl.id, ev->nd->bl.id); } node = node->next; } } map->freeblock_unlock(); return true; } void eskill_additional_effect_unknown(struct block_list* src __attribute__ ((unused)), struct block_list *bl __attribute__ ((unused)), uint16 *skill_id __attribute__ ((unused)), uint16 *skill_lv __attribute__ ((unused)), int *attack_type __attribute__ ((unused)), int *dmg_lv __attribute__ ((unused)), int64 *tick __attribute__ ((unused))) { } void eskill_counter_additional_effect_unknown(struct block_list *src __attribute__ ((unused)), struct block_list *bl __attribute__ ((unused)), uint16 *skill_id __attribute__ ((unused)), uint16 *skill_lv __attribute__ ((unused)), int *attack_type __attribute__ ((unused)), int64 *tick __attribute__ ((unused))) { } void eskill_attack_combo2_unknown(int *attack_type __attribute__ ((unused)), struct block_list *src __attribute__ ((unused)), struct block_list *dsrc __attribute__ ((unused)), struct block_list *bl __attribute__ ((unused)), uint16 *skill_id __attribute__ ((unused)), uint16 *skill_lv __attribute__ ((unused)), int64 *tick __attribute__ ((unused)), int *flag __attribute__ ((unused)), int *combo __attribute__ ((unused))) { } void eskill_attack_post_unknown(int *attack_type __attribute__ ((unused)), struct block_list *src __attribute__ ((unused)), struct block_list *dsrc __attribute__ ((unused)), struct block_list *bl __attribute__ ((unused)), uint16 *skill_id __attribute__ ((unused)), uint16 *skill_lv __attribute__ ((unused)), int64 *tick __attribute__ ((unused)), int *flag __attribute__ ((unused))) { } void eskill_timerskill_notarget_unknown(int tid __attribute__ ((unused)), int64 tick __attribute__ ((unused)), struct block_list *src __attribute__ ((unused)), struct unit_data *ud __attribute__ ((unused)), struct skill_timerskill *skl __attribute__ ((unused))) { } void eskill_unitsetting1_unknown(struct block_list *src __attribute__ ((unused)), uint16 *skill_id __attribute__ ((unused)), uint16 *skill_lv __attribute__ ((unused)), int16 *x __attribute__ ((unused)), int16 *y __attribute__ ((unused)), int *flag __attribute__ ((unused)), int *val1 __attribute__ ((unused)), int *val2 __attribute__ ((unused)), int *val3 __attribute__ ((unused))) { } void eskill_unit_onplace_unknown(struct skill_unit *src __attribute__ ((unused)), struct block_list *bl __attribute__ ((unused)), int64 *tick __attribute__ ((unused))) { } bool eskill_check_condition_castend_unknown(struct map_session_data *sd __attribute__ ((unused)), uint16 *skill_id __attribute__ ((unused)), uint16 *skill_lv __attribute__ ((unused))) { return false; } void eskill_get_requirement_unknown(struct status_change *sc __attribute__ ((unused)), struct map_session_data *sd __attribute__ ((unused)), uint16 *skill_id __attribute__ ((unused)), uint16 *skill_lv __attribute__ ((unused)), struct skill_condition *req __attribute__ ((unused))) { } bool eskill_castend_pos2_unknown(struct block_list* src, int *x, int *y, uint16 *skill_id, uint16 *skill_lv, int64 *tick, int *flag) { switch (*skill_id) { case EVOL_MASS_PROVOKE: return eskill_massprovoke_castend(src, x, y, skill_id, skill_lv, tick, flag); default: ShowWarning("skill_castend_pos2: Unknown skill used:%d\n", *skill_id); return true; } } // probably this function must be implimented in server bool eskill_lookup_const(const struct config_setting_t *it, const char *name, int *value) { nullpo_retr(false, name); nullpo_retr(false, value); if (libconfig->setting_lookup_int(it, name, value)) { return true; } else { const char *str = NULL; if (libconfig->setting_lookup_string(it, name, &str)) { if (*str && script->get_constant(str, value)) return true; } } return false; } void eskill_validate_additional_fields(struct config_setting_t *conf, struct s_skill_db *sk) { nullpo_retv(conf); nullpo_retv(sk); Assert_retv(sk->nameid < MAX_SKILL_ID); int i32 = 0; struct config_setting_t *t = NULL; struct SkilldExt *skilld = skilld_get_id(sk->nameid); nullpo_retv(skilld); if ((t = libconfig->setting_get_member(conf, "MiscEffects"))) { if (config_setting_is_array(t)) { for (int i = 0; i < libconfig->setting_length(t) && i < SKILLD_MAXMISCEFFECTS; i++) { skilld->miscEffects[i] = libconfig->setting_get_int_elem(t, i); } } else { if (eskill_lookup_const(conf, "MiscEffects", &i32) && i32 >= 0) { for (int i = 0; i < SKILLD_MAXMISCEFFECTS; i++) { skilld->miscEffects[i] = i32; } } } } if (eskill_lookup_const(conf, "TargetMiscEffect", &i32) && i32 >= 0) { skilld->miscEffects[0] = i32; } else if (eskill_lookup_const(conf, "TargetMiscEffect1", &i32) && i32 >= 0) { skilld->miscEffects[0] = i32; } if (eskill_lookup_const(conf, "TargetMiscEffect2", &i32) && i32 >= 0) { skilld->miscEffects[1] = i32; } } int eskill_calc_heal_post(int retVal, struct block_list *src, struct block_list *target, uint16 skill_id, uint16 skill_lv __attribute__ ((unused)), bool heal __attribute__ ((unused))) { // Rebuild some data I need int hp = 0; int skill2_lv, tmp, tmp1; struct map_session_data *sd = BL_CAST(BL_PC, src); struct map_session_data *tsd = BL_CAST(BL_PC, target); // Only affects healing if (sd && tsd && skill_id == AL_HEAL) { //ShowDebug("Skill is healing and SD is set. ACC ID %d.\n", sd->login_id2); // Only if self-target if (sd->login_id2 == tsd->login_id2) { // Recalculate everything with VIT instead hp = (status->get_lv(src) + status_get_vit(src)) / 5 * 30 * skill_lv / 10; // Skill bonuses if (sd && (skill2_lv = pc->skillheal_bonus(sd, skill_id)) != 0) hp += hp*skill2_lv/100; if (tsd && (skill2_lv = pc->skillheal2_bonus(tsd, skill_id)) != 0) hp += hp*skill2_lv/100; // Preprare the possible healing bonus tmp = status->get_total_def(src)*2; tmp1 = status->get_matk(src, 3); // Use the highest from both if (tmp > tmp1) hp+=tmp; else hp+=tmp1; //ShowDebug("Redefined (idx=%d original %d)\n", hp, retVal); //ShowDebug("TMP %d TMP1 %d Won %d)\n", tmp, tmp1, hp); } } if (hp) return hp; else return retVal; } int eskill_consume_requirement_post(int retVal, struct map_session_data *sd, uint16 skill_id, uint16 skill_lv, short type) { int i, n; struct skill_condition req; if (!sd) return retVal; //ShowInfo("crpost, Skill %d Level %d and type %d\n", skill_id, skill_lv, type); req = skill->get_requirement(sd,skill_id,skill_lv); // TODO We need more checks than only this if (type == 1 && skill_id > EVOL_FIRST_SKILL) { // Delete the items for( i = 0; i < MAX_SKILL_ITEM_REQUIRE; ++i ) { if( !req.itemid[i] ) continue; if ((n = pc->search_inventory(sd,req.itemid[i])) != INDEX_NOT_FOUND) pc->delitem(sd, n, req.amount[i], 0, DELITEM_SKILLUSE, LOG_TYPE_CONSUME); } } return retVal; } /* void eskill_castend_type_post(int *type __attribute__ ((unused)), struct block_list *src, struct block_list *bl, uint16 skill_id __attribute__ ((unused)), uint16 skill_lv __attribute__ ((unused)), int64 tick __attribute__ ((unused)), int flag __attribute__ ((unused))) { ShowDebug("Cast end type POST!\n"); // 1: Check if src can become a sd; If not, ABORT struct map_session_data *sd = NULL; sd = BL_CAST(BL_PC, src); if (!sd) return; ShowDebug("Source found!\n"); // 2: Add skill target info pc->setreg(sd, script->add_variable("@skillTarget"), bl->id); pc->setreg(sd, script->add_variable("@skillTargetX"), bl->x); pc->setreg(sd, script->add_variable("@skillTargetY"), bl->y); ShowDebug("Data filled! Targed was %d\n", bl->id); } void eskill_castend_type_pre(int *type __attribute__ ((unused)), struct block_list **src, struct block_list **blPtr, uint16 *skill_id __attribute__ ((unused)), uint16 *skill_lv __attribute__ ((unused)), int64 *tick __attribute__ ((unused)), int *flag __attribute__ ((unused))) { ShowDebug("Cast end type PRE!\n"); // 1: Check if src can become a sd; If not, ABORT struct map_session_data *sd = NULL; sd = BL_CAST(BL_PC, *src); if (!sd) return; ShowDebug("Source found!\n"); struct block_list *bl = *blPtr; // 2: Add skill target info pc->setreg(sd, script->add_variable("@skillTarget"), bl->id); pc->setreg(sd, script->add_variable("@skillTargetX"), bl->x); pc->setreg(sd, script->add_variable("@skillTargetY"), bl->y); ShowDebug("Data filled! Targed was %d\n", bl->id); } */