summaryrefslogblamecommitdiff
path: root/src/emap/skill.c
blob: 3bfb1adedd9835e9e1ee9f5d867ab7c2639a3b6d (plain) (tree)
1
2
3
4
5
6
7
8
9
                                                                         
                                            
 

                            



                   
                        

                        
                          
                       
                          




                          
                           
                       
                      
 


                              

                                

                                  
 

                               
                                     
                                       









                                                                                      
                                                   
                                                   

                                                        
 

                                 










                                                                                         

                                                                           






                                                                                     
 
                                                                 






                                                                             
                                                   









                                                                   

                                                     







                                       







                                                                  
                                                                   



















                                                                                         



                            



































































                                                                                              
                                                                                                 


                                                                                      
                 








                                                                                         










                                                        
                               





                                                                                         




























                                                                     
                                           






































                                                                                               















                                                                   
                                                                                   


















                                                                                                   

                                                                        







                      



























                                                                                                         
 















































                                                                      
 
// Copyright (c) Copyright (c) Hercules Dev Team, licensed under GNU GPL.
// Copyright (c) 2014 - 2015 Evol developers

#include "common/hercules.h"

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#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);
}
*/