Spellforce-Spell-framework
Loading...
Searching...
No Matches
sf_onhit_hook.c
Go to the documentation of this file.
1
9#include "sf_onhit_hook.h"
10#include "../sf_wrappers.h"
11#include "../sf_hooks.h"
12#include "../sf_modloader.h"
15
16#include <stdint.h>
17#include <stdlib.h>
18#include <stdio.h>
19#include <string.h>
20#include <list>
21#include <utility>
22
23typedef uint16_t (__thiscall *get_reduced_damage_ptr)(void *AutoClass34,
24 uint16_t source_index,
25 uint16_t target_index,
26 uint16_t unkn);
27typedef uint16_t (__thiscall *get_reduced_building_damage_ptr)(
28 void *AutoClass32, uint16_t source_index, uint16_t target_index,
29 uint16_t damage);
30typedef uint16_t (__thiscall *get_hit_chance_ptr)(void *AutoClass34,
31 uint16_t source_index,
32 uint16_t target_index);
33typedef void (__thiscall *FUN_006c3a60_ptr)(void *AutoClass30,
34 uint16_t source_index,
35 uint16_t target_index, uint8_t unkn,
36 uint32_t unkn2);
37typedef uint32_t (__thiscall *FUN_0071d7b0_ptr)(void *CGdObject,
38 uint16_t object_index);
39typedef uint32_t (__thiscall *FUN_00755180_ptr)(uint32_t param1);
40typedef uint32_t (__thiscall *objectDealDamage_ptr)(void *CGdObjectToolBox,
41 uint16_t source_index,
42 uint16_t target_index,
43 uint16_t damage,
44 uint32_t unknown);
45typedef uint32_t (__thiscall *getWeaponEffects_ptr)(void *CGdResource,
46 uint32_t *param1,
47 uint16_t weapon_id);
48
57
58// TODO PassThrough GET CURRENT STAT
59
60uint16_t __thiscall getCurrentDex(SF_CGdFigure *_this, uint16_t figure_index)
61{
62 uint16_t base_val = _this->figures[figure_index].dexterity.base_val;
63 uint16_t bonus_val = _this->figures[figure_index].dexterity.bonus_val;
64 uint16_t multiplier =
65 _this->figures[figure_index].dexterity.bonus_multiplier + 100;
66 if (base_val + bonus_val > 0)
67 {
68 return ((base_val + bonus_val) * multiplier) / 100;
69 }
70 return 0;
71}
72
73uint16_t __thiscall getCurrentInt(SF_CGdFigure *_this, uint16_t figure_index)
74{
75 uint16_t base_val = _this->figures[figure_index].intelligence.base_val;
76 uint16_t bonus_val = _this->figures[figure_index].intelligence.bonus_val;
77 uint16_t multiplier =
78 _this->figures[figure_index].intelligence.bonus_multiplier + 100;
79 if (base_val + bonus_val > 0)
80 {
81 return ((base_val + bonus_val) * multiplier) / 100;
82 }
83 return 0;
84}
85// End TODO
86
87uint16_t get_effect_chance(uint16_t dex_val, uint16_t int_val,
88 uint16_t spell_line)
89{
90 if (spell_line != kGdSpellLinePoison)
91 {
92 return (dex_val + int_val + 100) * 5;
93 }
94 return dex_val * 8 + int_val * 5 + 0x578;
95}
108
109void __thiscall getTargetData(AutoClass24 *_this, SF_CGdTargetData *target)
110{
111 target->entity_type = _this->target.entity_type;
112 target->entity_index = _this->target.entity_index;
113 target->position = _this->target.position;
114}
115
116bool isJobDoNothing(uint16_t job_id)
117{
118 if ((job_id == kGdJobGroupNothing) || (job_id == kGdJobWarriorNothing) ||
119 (job_id == kGdJobCheckBattleSleep) || (job_id == kGdJobPetIdle))
120 {
121 return 1;
122 }
123 return 0;
124}
125
126bool __thiscall isFigureJobSpell(SF_CGdFigureJobs *_this, uint16_t figure_id)
127{
128 uint16_t job_id = figureAPI.getJob(_this->CGdFigure, figure_id);
129 if ((job_id == kGdJobCast) || (job_id == kGdJobPreCast) ||
130 (job_id == kGdJobCastResolve) || (job_id == kGdJobCastPreResolve))
131 {
132 return 1;
133 }
134 if (job_id == kGdJobWalkToTarget)
135 {
136 SF_SGtFigureAction action;
137 aiAPI.getTargetAction(_this->CGdFigure, &action, figure_id);
138 if ((action.type != 0) && (action.type < 10000))
139 {
140 return 1;
141 }
142 }
143 return 0;
144}
145
146bool __thiscall canJobBeInterrupted(FigureJobs job_id)
147
148{
149 if ((((job_id != kGdJobCastPreResolve) && (job_id != kGdJobCastResolve)) &&
150 (job_id != kGdJobHitTargetRange2)) &&
151 (((job_id != kGdJobEnterBuilding && (job_id != kGdJobExitBuilding)) &&
152 ((job_id != kGdJobMeleeAbility &&
153 (job_id != kGdJobStartWorkAtBuilding))))))
154 {
155 return 1;
156 }
157 return 0;
158}
159
160uint16_t __thiscall getAttackInterruptionChance(SF_CGdFigure *_this,
161 uint16_t source_index,
162 uint16_t target_index)
163{
164 uint8_t source_level = _this->figures[source_index].level;
165 uint8_t target_level = _this->figures[target_index].level;
166 if (target_level < source_level)
167 {
168 uint16_t precalc_chance = (source_level - target_level) * 5 + 0xf;
169 if (precalc_chance > 100)
170 {
171 return 100;
172 }
173 return precalc_chance;
174 }
175 if (target_level == source_level)
176 {
177 return 0xf;
178 }
179 if (0xf < ((target_level - source_level) * 2))
180 {
181 return 0;
182 }
183 return (target_index - source_index) * -2 + 0xf;
184}
185
186uint16_t __thiscall handle_riposte_set(SF_CGdFigureJobs *_this,
187 uint16_t source_index,
188 uint16_t target_index,
189 uint16_t weapon_damage)
190{
191 bool apply_set = false;
192 if (_this->CGdFigure->figures[target_index].set_type == 0x03)
193 {
194 uint16_t counter = spellAPI.getRandom(_this->OpaqueClass, 100);
195 apply_set = (counter < 0x0b);
196 }
197 if (apply_set)
198 {
199 uint16_t damage = g_get_reduced_damage(_this->AutoClass34, source_index,
200 source_index, weapon_damage);
201 toolboxAPI.dealDamage(_this->CGdFigureToolBox, source_index,
202 source_index, damage, 0, 0, 0);
203 return 0;
204 }
205 // TODO: fix enchatments on weapon applying with reflected hit
206 return weapon_damage;
207}
208
209uint16_t __thiscall handle_berserk_set(SF_CGdFigureJobs *_this,
210 uint16_t source_index,
211 uint16_t target_index,
212 uint16_t weapon_damage)
213{
214 bool apply_set = false;
215 if (_this->CGdFigure->figures[source_index].set_type == 0x04)
216 {
217 uint16_t counter = spellAPI.getRandom(_this->OpaqueClass, 100);
218 apply_set = (counter < 0x0b);
219 }
220 // 7FFF is one-shot magic number
221 if ((apply_set) && (weapon_damage != 0x7FFF))
222 {
223 uint16_t damage = weapon_damage * 3;
224 return damage;
225 }
226 return weapon_damage;
227}
228
229uint16_t __thiscall handle_trueshot_set(SF_CGdFigureJobs *_this,
230 uint16_t source_index,
231 uint16_t target_index,
232 uint16_t weapon_damage)
233{
234 bool apply_set = false;
235 if (_this->CGdFigure->figures[source_index].set_type == 0x05)
236 {
237 uint16_t counter = spellAPI.getRandom(_this->OpaqueClass, 100);
238 apply_set = (counter < 0x0b);
239 }
240 // 7FFF is one-shot magic number
241 if ((apply_set) && (weapon_damage != 0x7FFF))
242 {
243 uint16_t damage = weapon_damage * 4;
244 return damage;
245 }
246 return weapon_damage;
247}
248
249void __thiscall sf_onhit_hook(SF_CGdFigureJobs *_this, uint16_t source_index,
250 uint32_t param_2, uint8_t param_3)
251{
252 if ((_this->CGdFigure->figures[source_index].owner == -1) ||
253 (_this->CGdFigure->figures[source_index].flags & 10))
254 {
255 return;
256 }
257
258 SF_CGdFigureWeaponStats weapon_stats;
259 SF_CGdTargetData target;
260 SF_SGtFigureAction action;
261 figureAPI.getWeaponStats(_this->CGdFigure, &weapon_stats, source_index);
262 uint16_t weapon_damage_rng = spellAPI.getRandom(_this->OpaqueClass,
263 weapon_stats.max_dmg -
264 weapon_stats.min_dmg);
265 uint16_t weapon_damage = weapon_damage_rng + weapon_stats.min_dmg;
266 getTargetData(&_this->CGdFigure->figures[source_index].ac_1, &target);
267 aiAPI.getTargetAction(_this->CGdFigure, &action, source_index);
268
269 if (target.entity_type == 1)
270 {
271 // NB Parenthis matters in flags check. I mean it
272 if ((_this->CGdFigure->figures[target.entity_index].owner == -1) ||
273 ((_this->CGdFigure->figures[target.entity_index].flags &
274 (REDO | IS_DEAD)) != 0) ||
276 target.entity_index)))
277 {
278 return;
279 }
280
281 uint16_t hit_chance = g_get_hit_chance(_this->AutoClass34, source_index,
282 target.entity_index);
283
284 // miss handling
285 if ((hit_chance < spellAPI.getRandom(_this->OpaqueClass,
286 100)) && (param_2 == 0))
287 {
288 g_FUN_006c3a60(_this->AutoClass30, source_index,
289 target.entity_index, 1, 0);
290 uint16_t aggro = figureAPI.getAggroValue(_this->CGdFigure,
291 target.entity_index,
292 source_index);
293 if (aggro < 10000)
294 {
296 source_index, 12000, 0);
297 }
298 uint16_t job_id = figureAPI.getJob(_this->CGdFigure,
299 target.entity_index);
300
301 if (isJobDoNothing(job_id))
302 {
303 _this->CGdFigure->figures[target.entity_index].to_do_count = 1;
304 return;
305 }
306 }
307 /*
308 target_index = get_reduced_hit_damage
309 (this->field11_0x2c,uVar3,(ushort)local_12c._1_4_,(ushort)local_160);
310 target_index = ((target_index & 0xffff) * (uint)param_3 + 0x32) / 100;
311 damage = target_index & 0xffff;
312 */
313
314
315 uint16_t damage = g_get_reduced_damage(_this->AutoClass34, source_index,
316 target.entity_index,
317 weapon_damage);
318 damage = ((damage & 0xffff) * ((uint8_t) param_3) + 0x32) / 100;
319 damage = damage & 0xffff;
320 // glanced hit
321 if (damage == 0)
322 {
323 log_info("Damage IS 0");
324 uint16_t aggro = figureAPI.getAggroValue(_this->CGdFigure,
325 target.entity_index,
326 source_index);
327 if (aggro < 10000)
328 {
330 source_index, 12000, 0);
331 }
332 }
333 else
334 {
335 if (isFigureJobSpell(_this, target.entity_index))
336 {
337 uint16_t job_id = figureAPI.getJob(_this->CGdFigure,
338 target.entity_index);
339 if (canJobBeInterrupted((FigureJobs) job_id))
340 {
341 uint16_t chance =
343 source_index,
344 target.entity_index);
345 if (spellAPI.getRandom(_this->OpaqueClass, 100) <= chance)
346 {
348 kGdJobOfferMe, 0, 0, 0);
349 }
350 }
351 }
352 for (int i = PHASE_0; i < OnHitEnd; ++i)
353 {
354 if (i == PHASE_0)
355 {
356 if (isActionMelee(&action))
357 {
358 damage = handle_berserk_set(_this, source_index,
359 target.entity_index,
360 damage);
361 damage = handle_riposte_set(_this, source_index,
362 target.entity_index,
363 damage);
364 }
365 else
366 {
367 damage = handle_trueshot_set(_this, source_index,
368 target.entity_index,
369 damage);
370 }
371 }
372 std::list<std::pair<uint16_t,
373 onhit_handler_ptr>> onhit_list = get_onhit_phase(static_cast<
375 (i));
376
377 uint16_t list_size = onhit_list.size();
378
379 int return_damage = weapon_damage;
380
381 for (auto it = onhit_list.crbegin(); it != onhit_list.crend();
382 ++it)
383 {
384 std::pair<uint16_t, onhit_handler_ptr> entry = *it;
385
386 uint16_t spell_line_id = entry.first;
387
388 if (hasSpellTag(spell_line_id, TARGET_ONHIT_SPELL))
389 {
390 if ((_this->CGdFigure->figures[target.entity_index].
391 flags & F_CHECK_SPELLS_BEFORE_JOB) != 0)
392 {
394 target.entity_index,
395 spell_line_id))
396 {
397 onhit_handler_ptr onhit_func = entry.second;
398 damage = onhit_func(_this, source_index,
399 target.entity_index,
400 damage);
401 }
402 }
403 }
404 else
405 {
406 if ((_this->CGdFigure->figures[source_index].flags &
408 {
410 source_index,
411 spell_line_id))
412 {
413 onhit_handler_ptr onhit_func = entry.second;
414 damage = onhit_func(_this, source_index,
415 target.entity_index,
416 damage);
417 }
418 }
419 }
420 }
421 }
422 // donnoe wtf is it, looks like shooting?
423 if (action.type == 0x2712)
424 {
425 uint16_t maxY =
426 (_this->CGdFigure->figures[source_index].position.Y <=
427 _this->CGdFigure->figures[target.entity_index].position.Y)
428 ? (_this->CGdFigure->figures[target.
429 entity_index].
430 position.Y)
431 : (_this->CGdFigure->figures[source_index].
432 position.Y);
433
434 uint16_t maxX =
435 (_this->CGdFigure->figures[source_index].position.X <=
436 _this->CGdFigure->figures[target.entity_index].position.X)
437 ? (_this->CGdFigure->figures[target.
438 entity_index].
439 position.X)
440 : (_this->CGdFigure->figures[source_index].
441 position.X);
442
443 uint16_t minY =
444 (_this->CGdFigure->figures[source_index].position.Y >
445 _this->CGdFigure->figures[target.entity_index].position.Y)
446 ? (_this->CGdFigure->figures[target.
447 entity_index].
448 position.Y)
449 : (_this->CGdFigure->figures[source_index].
450 position.Y);
451
452 uint16_t minX =
453 (_this->CGdFigure->figures[source_index].position.X >
454 _this->CGdFigure->figures[target.entity_index].position.X)
455 ? (_this->CGdFigure->figures[target.
456 entity_index].
457 position.X)
458 : (_this->CGdFigure->figures[source_index].
459 position.X);
460 SF_Coord p1;
461 SF_Coord p2;
462 SF_Rectangle vector;
463 p1.X = maxX;
464 if (minX < maxX)
465 {
466 p1.X = minX;
467 }
468 p1.Y = maxY;
469 if (minY < maxY)
470 {
471 p1.Y = minY;
472 }
473
474 p2.X = maxX;
475 if (maxX <= minX)
476 {
477 p2.X = minX;
478 }
479 p2.Y = maxY;
480 if (maxY <= minY)
481 {
482 p2.Y = minY;
483 }
484 vector.partA = p1.Y << 0x10 | p1.X;
485 vector.partB = p2.Y << 0x10 | p2.X;
486
487 uint32_t distance =
489 &_this->CGdFigure->figures[source_index].position,
490 &_this->CGdFigure->figures[target.entity_index].position);
491 distance = ((distance & 0xffff) * 0x578) / 3000;
492 SF_CGdTargetData source = {1, source_index, {0, 0}};
493 uint16_t effect_id = effectAPI.addEffect(_this->CGdEffect,
495 &source, &target,
496 _this->OpaqueClass->
497 current_step,
498 ((distance !=
499 0) ? distance : 1),
500 &vector);
501 effectAPI.setEffectXData(_this->CGdEffect, effect_id,
503 effectAPI.setEffectXData(_this->CGdEffect, effect_id,
505 effectAPI.setEffectXData(_this->CGdEffect, effect_id,
506 EFFECT_ENTITY_INDEX, source_index);
507 effectAPI.setEffectXData(_this->CGdEffect, effect_id,
509 target.entity_index);
510 effectAPI.setEffectXData(_this->CGdEffect, effect_id,
512 effectAPI.setEffectXData(_this->CGdEffect, effect_id,
513 EFFECT_PHYSICAL_DAMAGE, damage);
514
515 uint16_t subspell_id = 0;
516 // troll fire thrower
517 if (_this->CGdFigure->figures[source_index].unit_data_id ==
518 0x508)
519 {
520 subspell_id = 0x6de;
521 }
522 // troll ice thrower
523 if (_this->CGdFigure->figures[source_index].unit_data_id ==
524 0x505)
525 {
526 subspell_id = 0x6ea;
527 }
528 // windarcher
529 if (_this->CGdFigure->figures[source_index].unit_data_id ==
530 0x4cd)
531 {
532 subspell_id = 0x6d2;
533 }
534 if (subspell_id != 0)
535 {
536 uint16_t spell_lvl =
537 _this->CGdFigure->figures[source_index].level;
538 uint16_t spell_id =spellAPI.getLeveledSpellID(_this->CGdResource, subspell_id, spell_lvl);
539 if (spell_id != 0)
540 {
541 effectAPI.setEffectXData(_this->CGdEffect, effect_id,
542 EFFECT_SUBSPELL_ID, spell_id);
543 }
544 }
545 }
546 else
547 {
548 uint16_t subspell_id = 0;
549 // Havoc & DeathKnight upgrade
550 if ((_this->CGdFigure->figures[target.entity_index].unit_data_id
551 == 0x510) ||
553 == 0x513))
554 {
555 // NOT a bug, but feature. The higher the level of enemy, the stronger curse gets.
556 uint16_t spell_id = spellAPI.getLeveledSpellID(_this->CGdResource, 0x167,
557 _this->CGdFigure->figures[source_index].level);
558 if (spell_id != 0)
559 {
560 SF_CGdTargetData t_data;
561 t_data.entity_index = source_index;
562 t_data.entity_type = 1;
563 t_data.position = {0, 0};
564 spellAPI.addSpell(_this->CGdSpell, spell_id,
566 &target, &t_data, 0);
567 }
568 }
569 if(damage != 0)
570 toolboxAPI.dealDamage(_this->CGdFigureToolBox, source_index,
571 target.entity_index, damage, 0, 0, 0);
572 }
573
574 if (figureAPI.isAlive(_this->CGdFigure, target.entity_index))
575 {
576 uint16_t weapon_id =
577 _this->CGdFigure->figures[source_index].equipment[(action.
578 type !=
579 10000) *
580 2 + 1];
581 // can't make heads or tails here
582 uint32_t puVar15[2];
583 g_getWeaponEffects(_this->CGdResource, puVar15, weapon_id);
584 if (puVar15[0] != 0)
585 {
586 for (int i = 0; i < 3; i++)
587 {
588 uint16_t enchant_id =
589 *(uint16_t *)((uint32_t)(&puVar15[0]) + i * 2 + 2);
590
591 if (enchant_id == 0)
592 break;
593 SF_CGdResourceSpell spell_data;
595 &spell_data, enchant_id);
596 uint16_t curr_dex = getCurrentDex(_this->CGdFigure,
597 source_index);
598 uint16_t curr_int = getCurrentInt(_this->CGdFigure,
599 source_index);
600 uint16_t chance = get_effect_chance(curr_dex, curr_int,
601 spell_data.
602 spell_line_id);
603 if (spellAPI.getRandom(_this->OpaqueClass,
604 10000) < chance)
605 {
606 if ((_this->CGdFigure->figures[source_index].race != 0) &&
607 (_this->CGdFigure->figures[source_index].race < 7))
608 {
609 if (_this->CGdFigure->figures[source_index].
610 owner != 0)
611 {
612 enchant_id = spellAPI.getLeveledSpellID(_this->CGdResource, enchant_id,
613 _this->CGdFigure->figures[source_index].
614 level);
615 }
616 }
617 if (enchant_id != 0)
618 {
619 // FIXME reflect enchants as well in riposte set handler;
620 SF_CGdTargetData source;
621 source.entity_type = 1;
622 source.entity_index = source_index;
623 source.position = {0, 0};
624 spellAPI.addSpell(_this->CGdSpell, enchant_id,
625 _this->OpaqueClass->
626 current_step, &source,
627 &target, 0);
628 }
629 }
630 }
631 }
632 }
633 }
634 }
635 if (target.entity_type == 2)
636 {
637 uint16_t damage = g_get_reduced_building_damage(_this->AutoClass34,
638 source_index,
639 target.entity_index,
640 weapon_damage);
641 if ((target.entity_index != 0) &&
643 != 0))
644 {
646 source_index, target.entity_index,
647 damage, 0);
648 }
649 }
650 if (target.entity_type == 3)
651 {
652 if (target.entity_index != 0)
653 {
654 uint32_t value_1 = g_FUN_0071d7b0(_this->CGdObject,
655 target.entity_index);
656 if ((value_1 != 0) && (g_FUN_00755180(value_1) != 0))
657 {
658 g_objectDealDamage(_this->CGdObjectToolBox, source_index,
659 target.entity_index, weapon_damage, 0);
660 }
661 }
662 }
663}
664
SpellFunctions * spellAPI
Definition TestMod.cpp:11
FigureFunctions * figureAPI
Definition TestMod.cpp:13
ToolboxFunctions * toolboxAPI
Definition TestMod.cpp:12
EffectFunctions effectAPI
Definition sf_hooks.c:37
AiFunctions aiAPI
Definition sf_hooks.c:41
bool isJobDoNothing(uint16_t job_id)
void(__thiscall * FUN_006c3a60_ptr)(void *AutoClass30, uint16_t source_index, uint16_t target_index, uint8_t unkn, uint32_t unkn2)
FUN_0071d7b0_ptr g_FUN_0071d7b0
bool __thiscall isFigureJobSpell(SF_CGdFigureJobs *_this, uint16_t figure_id)
uint16_t __thiscall handle_berserk_set(SF_CGdFigureJobs *_this, uint16_t source_index, uint16_t target_index, uint16_t weapon_damage)
get_hit_chance_ptr g_get_hit_chance
uint16_t get_effect_chance(uint16_t dex_val, uint16_t int_val, uint16_t spell_line)
objectDealDamage_ptr g_objectDealDamage
uint16_t(__thiscall * get_reduced_damage_ptr)(void *AutoClass34, uint16_t source_index, uint16_t target_index, uint16_t unkn)
uint16_t(__thiscall * get_hit_chance_ptr)(void *AutoClass34, uint16_t source_index, uint16_t target_index)
uint32_t(__thiscall * getWeaponEffects_ptr)(void *CGdResource, uint32_t *param1, uint16_t weapon_id)
FUN_00755180_ptr g_FUN_00755180
getWeaponEffects_ptr g_getWeaponEffects
get_reduced_building_damage_ptr g_get_reduced_building_damage
uint16_t __thiscall getCurrentDex(SF_CGdFigure *_this, uint16_t figure_index)
bool __thiscall canJobBeInterrupted(FigureJobs job_id)
uint32_t(__thiscall * objectDealDamage_ptr)(void *CGdObjectToolBox, uint16_t source_index, uint16_t target_index, uint16_t damage, uint32_t unknown)
FUN_006c3a60_ptr g_FUN_006c3a60
uint16_t __thiscall getAttackInterruptionChance(SF_CGdFigure *_this, uint16_t source_index, uint16_t target_index)
void initialize_onhit_data_hooks()
uint32_t(__thiscall * FUN_00755180_ptr)(uint32_t param1)
uint16_t __thiscall handle_trueshot_set(SF_CGdFigureJobs *_this, uint16_t source_index, uint16_t target_index, uint16_t weapon_damage)
get_reduced_damage_ptr g_get_reduced_damage
uint16_t __thiscall handle_riposte_set(SF_CGdFigureJobs *_this, uint16_t source_index, uint16_t target_index, uint16_t weapon_damage)
uint32_t(__thiscall * FUN_0071d7b0_ptr)(void *CGdObject, uint16_t object_index)
uint16_t(__thiscall * get_reduced_building_damage_ptr)(void *AutoClass32, uint16_t source_index, uint16_t target_index, uint16_t damage)
uint16_t __thiscall getCurrentInt(SF_CGdFigure *_this, uint16_t figure_index)
void __thiscall sf_onhit_hook(SF_CGdFigureJobs *_this, uint16_t source_index, uint32_t param_2, uint8_t param_3)
void __thiscall getTargetData(AutoClass24 *_this, SF_CGdTargetData *target)
uint32_t getDistance(SF_Coord *pointA, SF_Coord *pointB)
void log_info(const char *message)
Definition sf_wrappers.c:89
bool __thiscall hasSpellTag(uint16_t spell_id, SpellTag tag)
bool __thiscall isActionMelee(SF_SGtFigureAction *_this)
int AddrOf(int offset)
returns "real" virtual address of given memory offset
Definition sf_asi.h:135
@ kGdJobHitTargetRange2
@ kGdJobPetIdle
@ kGdJobOfferMe
@ kGdJobStartWorkAtBuilding
@ kGdJobEnterBuilding
@ kGdJobWarriorNothing
@ kGdJobCastPreResolve
@ kGdJobCast
@ kGdJobExitBuilding
@ kGdJobCheckBattleSleep
@ kGdJobCastResolve
@ kGdJobGroupNothing
@ kGdJobMeleeAbility
@ kGdJobPreCast
@ kGdJobWalkToTarget
@ TARGET_ONHIT_SPELL
@ EFFECT_ENTITY_TYPE2
@ EFFECT_DO_NOT_ADD_SUBSPELL
@ EFFECT_ENTITY_INDEX2
@ EFFECT_SUBSPELL_ID
@ EFFECT_ENTITY_TYPE
@ EFFECT_ENTITY_INDEX
@ EFFECT_PHYSICAL_DAMAGE
@ kGdEffectProjectile
@ F_CHECK_SPELLS_BEFORE_JOB
std::list< std::pair< uint16_t, onhit_handler_ptr > > get_onhit_phase(OnHitPhase phase)
uint16_t(__thiscall * onhit_handler_ptr)(SF_CGdFigureJobs *, uint16_t source, uint16_t target, uint16_t damage)
@ kGdSpellLinePoison
getTargetAction_ptr getTargetAction
SF_CGdTargetData target
addEffect_ptr addEffect
setEffectXData_ptr setEffectXData
getWeaponStats_ptr getWeaponStats
setAggroValue_ptr setAggroValue
getAggroValue_ptr getAggroValue
uint16_t equipment[16]
FigureStatistic dexterity
GdFigureFlags flags
FigureStatistic intelligence
GdBuilding buildings[1000]
A structure for the global list of figures and related statistics for them.
GdFigure figures[2000]
SF_CGdBuilding * CGdBuilding
SF_CGdFigureToolbox * CGdFigureToolBox
getRandom_ptr getRandom
Generates a random value up to the specified maximum value.
getResourceSpellData_ptr getResourceSpellData
addSpell_ptr addSpell
Creates a new spell of a given spell type.
getLeveledSpellID_ptr getLeveledSpellID
dealDamage_ptr dealDamage
hasSpellOnIt_ptr hasSpellOnIt
figureSetNewJob_ptr figureSetNewJob
isTargetable_ptr isTargetable
buildingDealDamage_ptr buildingDealDamage