summaryrefslogtreecommitdiff
path: root/src/emap/skill.c
blob: 38fb2650d5bc58563d96c80cc2d2770df62dabcc (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
// 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/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;
	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);
    //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);
}
*/