Spellforce-Spell-framework
Loading...
Searching...
No Matches
sf_onhit_hook.c
Go to the documentation of this file.
1#include "sf_onhit_hook.h"
2
3
4// getFigureJobData_ptr getFigureJobData;
5// FUN_006f8c06_ptr FUN_006f8c06;
6// FUN_006fa3ce_ptr FUN_006fa3ce;
7// setFigureAction_ptr setFigureAction;
8
9// uint32_t __thiscall onSpellCastHook(SF_CGdFigureToolbox *_this, uint16_t figure_id, uint16_t spell_id,
10// uint16_t target_id, uint8_t target_type, SF_Coord position, uint32_t param6,
11// uint32_t param7)
12// {
13// FigureJobData *ac24 = getFigureJobData(_this->CGdFigure, figure_id);
14// if (!FUN_006f8c06(_this, figure_id, spell_id, target_id, target_type, position, param6, param7, 0))
15// {
16// return 0;
17// }
18// else
19// {
20// FUN_006fa3ce(_this, figure_id, 0);
21// ac24->flags |= MANUAL_JOB_CHANGE;
22// ac24->GdJobId = kGdJobManualWalkToTarget;
23// ac24->target.entity_index = target_id;
24// ac24->target.entity_type = target_type;
25// ac24->target.position.X = position.X;
26// ac24->target.position.Y = position.Y;
27// SF_CGdResourceSpell spell_data;
28// spellAPI->getResourceSpellData(_this->CGdResource, &spell_data, spell_id);
29
30// SF_SGtFigureAction action;
31// action.type = spell_data.spell_line_id;
32// action.subtype = spell_id;
33// action.unkn2 = 0;
34// action.unkn3 = 0;
35// action.unkn4 = 0;
36// action.unkn5 = 0;
37
38// setFigureAction(ac24, &action);
39// return 1;
40// }
41// return 0;
42// }
43
44typedef uint16_t (__thiscall *get_reduced_damage_ptr)(void *AutoClass34,
45 uint16_t source_index,
46 uint16_t target_index,
47 uint16_t unkn);
48typedef uint16_t (__thiscall *get_reduced_building_damage_ptr)(
49 void *AutoClass32, uint16_t source_index, uint16_t target_index,
50 uint16_t damage);
51typedef uint16_t (__thiscall *get_hit_chance_ptr)(void *AutoClass34,
52 uint16_t source_index,
53 uint16_t target_index);
54typedef void (__thiscall *FUN_006c3a60_ptr)(void *AutoClass30,
55 uint16_t source_index,
56 uint16_t target_index, uint8_t unkn,
57 uint32_t unkn2);
58typedef uint32_t (__thiscall *FUN_0071d7b0_ptr)(void *CGdObject,
59 uint16_t object_index);
60typedef uint32_t (__thiscall *FUN_00755180_ptr)(uint32_t param1);
61typedef uint32_t (__thiscall *objectDealDamage_ptr)(void *CGdObjectToolBox,
62 uint16_t source_index,
63 uint16_t target_index,
64 uint16_t damage,
65 uint32_t unknown);
66typedef uint32_t (__thiscall *getWeaponEffects_ptr)(void *CGdResource,
67 uint32_t *param1,
68 uint16_t weapon_id);
69
78
79// TODO PassThrough GET CURRENT STAT
80
81uint16_t __thiscall getCurrentDex(SF_CGdFigure *_this, uint16_t figure_index)
82{
83 uint16_t base_val = _this->figures[figure_index].dexterity.base_val;
84 uint16_t bonus_val = _this->figures[figure_index].dexterity.bonus_val;
85 uint16_t multiplier =
86 _this->figures[figure_index].dexterity.bonus_multiplier + 100;
87 if (base_val + bonus_val > 0)
88 {
89 return ((base_val + bonus_val) * multiplier) / 100;
90 }
91 return 0;
92}
93
94uint16_t __thiscall getCurrentInt(SF_CGdFigure *_this, uint16_t figure_index)
95{
96 uint16_t base_val = _this->figures[figure_index].intelligence.base_val;
97 uint16_t bonus_val = _this->figures[figure_index].intelligence.bonus_val;
98 uint16_t multiplier =
99 _this->figures[figure_index].intelligence.bonus_multiplier + 100;
100 if (base_val + bonus_val > 0)
101 {
102 return ((base_val + bonus_val) * multiplier) / 100;
103 }
104 return 0;
105}
106// End TODO
107
108uint16_t get_effect_chance(uint16_t dex_val, uint16_t int_val,
109 uint16_t spell_line)
110{
111 if (spell_line != kGdSpellLinePoison)
112 {
113 return (dex_val + int_val + 100) * 5;
114 }
115 return dex_val * 8 + int_val * 5 + 0x578;
116}
117
130
131void __thiscall getTargetData(FigureJobData *_this, SF_CGdTargetData *target)
132{
133 target->entity_type = _this->target.entity_type;
134 target->entity_index = _this->target.entity_index;
135 target->position = _this->target.position;
136}
137
138bool isJobDoNothing(uint16_t job_id)
139{
140 if ((job_id == kGdJobGroupNothing) || (job_id == kGdJobWarriorNothing) ||
141 (job_id == kGdJobCheckBattleSleep) || (job_id == kGdJobPetIdle))
142 {
143 return 1;
144 }
145 return 0;
146}
147
148bool __thiscall isFigureJobSpell(SF_CGdFigureJobs *_this, uint16_t figure_id)
149{
150 uint16_t job_id = figureAPI.getJob(_this->CGdFigure, figure_id);
151 if ((job_id == kGdJobCast) || (job_id == kGdJobPreCast) ||
152 (job_id == kGdJobCastResolve) || (job_id == kGdJobCastPreResolve))
153 {
154 return 1;
155 }
156 if (job_id == kGdJobWalkToTarget)
157 {
158 SF_SGtFigureAction action;
159 aiAPI.getTargetAction(_this->CGdFigure, &action, figure_id);
160 if ((action.type != 0) && (action.type < 10000))
161 {
162 return 1;
163 }
164 }
165 return 0;
166}
167
168bool __thiscall canJobBeInterrupted(FigureJobs job_id)
169{
170 if ((((job_id != kGdJobCastPreResolve) && (job_id != kGdJobCastResolve)) &&
171 (job_id != kGdJobHitTargetRange2)) &&
172 (((job_id != kGdJobEnterBuilding && (job_id != kGdJobExitBuilding)) &&
173 ((job_id != kGdJobMeleeAbility &&
174 (job_id != kGdJobStartWorkAtBuilding))))))
175 {
176 return 1;
177 }
178 return 0;
179}
180
181uint16_t __thiscall getAttackInterruptionChance(SF_CGdFigure *_this,
182 uint16_t source_index,
183 uint16_t target_index)
184{
185 uint8_t source_level = _this->figures[source_index].level;
186 uint8_t target_level = _this->figures[target_index].level;
187 if (target_level < source_level)
188 {
189 uint16_t precalc_chance = (source_level - target_level) * 5 + 15;
190 if (precalc_chance > 100)
191 {
192 return 100;
193 }
194 return precalc_chance;
195 }
196 if (target_level == source_level)
197 {
198 return 15;
199 }
200 if ( 15 < ((target_level - source_level) * 2))
201 {
202 return 0;
203 }
204 return 15 - (target_level - source_level) * 2;
205}
206
207uint16_t __thiscall handle_riposte_set(SF_CGdFigureJobs *_this,
208 uint16_t source_index,
209 uint16_t target_index,
210 uint16_t weapon_damage)
211{
212 bool apply_set = false;
213 if (_this->CGdFigure->figures[target_index].set_type == 0x03)
214 {
215 uint16_t counter = spellAPI.getRandom(_this->OpaqueClass, 100);
216 apply_set = (counter < 0x0b);
217 }
218 if (apply_set)
219 {
220 uint16_t damage = g_get_reduced_damage(_this->AutoClass34, source_index, source_index, weapon_damage);
221 toolboxAPI.dealDamage(_this->CGdFigureToolBox, source_index, source_index, damage, 0, 0, 0);
222 return 0;
223 }
224 // TODO: fix enchatments on weapon applying with reflected hit
225 return weapon_damage;
226}
227
228uint16_t __thiscall handle_berserk_set(SF_CGdFigureJobs *_this,
229 uint16_t source_index,
230 uint16_t target_index,
231 uint16_t weapon_damage)
232{
233 bool apply_set = false;
234 if (_this->CGdFigure->figures[source_index].set_type == 0x04)
235 {
236 uint16_t counter = spellAPI.getRandom(_this->OpaqueClass, 100);
237 apply_set = (counter < 0x0b);
238 }
239 // 7FFF is one-shot magic number
240 if ((apply_set) && (weapon_damage != 0x7FFF))
241 {
242 uint16_t damage = weapon_damage * 3;
243 return damage;
244 }
245 return weapon_damage;
246}
247
248uint16_t __thiscall handle_trueshot_set(SF_CGdFigureJobs *_this,
249 uint16_t source_index,
250 uint16_t target_index,
251 uint16_t weapon_damage)
252{
253 bool apply_set = false;
254 if (_this->CGdFigure->figures[source_index].set_type == 0x05)
255 {
256 uint16_t counter = spellAPI.getRandom(_this->OpaqueClass, 100);
257 apply_set = (counter < 0x0b);
258 }
259 // 7FFF is one-shot magic number
260 if ((apply_set) && (weapon_damage != 0x7FFF))
261 {
262 uint16_t damage = weapon_damage * 4;
263 return damage;
264 }
265 return weapon_damage;
266}
267
268void __thiscall sf_onhit_hook(SF_CGdFigureJobs *_this, uint16_t source_index,
269 uint32_t param_2, uint8_t param_3)
270{
271 if ((_this->CGdFigure->figures[source_index].owner == -1) || (_this->CGdFigure->figures[source_index].flags & 10))
272 {
273 return;
274 }
275
276 SF_CGdFigureWeaponStats weapon_stats;
277 SF_CGdTargetData target;
278 SF_SGtFigureAction action;
279 figureAPI.getWeaponStats(_this->CGdFigure, &weapon_stats, source_index);
280 uint16_t weapon_damage_rng = spellAPI.getRandom(_this->OpaqueClass, weapon_stats.max_dmg - weapon_stats.min_dmg);
281 uint16_t weapon_damage = weapon_damage_rng + weapon_stats.min_dmg;
282 getTargetData(&_this->CGdFigure->figures[source_index].current_job, &target);
283 aiAPI.getTargetAction(_this->CGdFigure, &action, source_index);
284
285 if (target.entity_type == 1)
286 {
287 // NB Parenthis matters in flags check. I mean it
288 if ((_this->CGdFigure->figures[target.entity_index].owner == -1) ||
289 ((_this->CGdFigure->figures[target.entity_index].flags & (RESESRVED_ONLY | IS_DEAD)) != 0) ||
290 (!toolboxAPI.isTargetable(_this->CGdFigureToolBox, target.entity_index)))
291 {
292 return;
293 }
294
295 uint16_t hit_chance = g_get_hit_chance(_this->AutoClass34, source_index, target.entity_index);
296
297 // miss handling
298 if ((hit_chance < spellAPI.getRandom(_this->OpaqueClass, 100)) && (param_2 == 0))
299 {
300 g_FUN_006c3a60(_this->AutoClass30, source_index, target.entity_index, 1, 0);
301 uint16_t aggro = figureAPI.getAggroValue(_this->CGdFigure, target.entity_index, source_index);
302 if (aggro < 10000)
303 {
304 figureAPI.setAggroValue(_this->CGdFigure, target.entity_index, source_index, 12000, 0);
305 }
306 uint16_t job_id = figureAPI.getJob(_this->CGdFigure, target.entity_index);
307
308 if (isJobDoNothing(job_id))
309 {
310 _this->CGdFigure->figures[target.entity_index].to_do_count = 1;
311 return;
312 }
313 }
314 /*
315 target_index = get_reduced_hit_damage
316 (this->field11_0x2c,uVar3,(ushort)local_12c._1_4_,(ushort)local_160);
317 target_index = ((target_index & 0xffff) * (uint)param_3 + 0x32) / 100;
318 damage = target_index & 0xffff;
319 */
320
321
322 uint16_t damage = g_get_reduced_damage(_this->AutoClass34, source_index, target.entity_index, weapon_damage);
323 damage = ((damage & 0xffff) * ((uint8_t) param_3) + 0x32) / 100;
324 damage = damage & 0xffff;
325 // glanced hit
326 if (damage == 0)
327 {
328#if _DEBUG_
329 log_info("Damage IS 0");
330#endif
331 uint16_t aggro = figureAPI.getAggroValue(_this->CGdFigure, target.entity_index, source_index);
332 if (aggro < 10000)
333 {
334 figureAPI.setAggroValue(_this->CGdFigure, target.entity_index, source_index, 12000, 0);
335 }
336 }
337 else
338 {
339 if (isFigureJobSpell(_this, target.entity_index))
340 {
341 uint16_t job_id = figureAPI.getJob(_this->CGdFigure, target.entity_index);
342 if (canJobBeInterrupted((FigureJobs) job_id))
343 {
344 uint16_t chance = getAttackInterruptionChance(_this->CGdFigure, source_index, target.entity_index);
345 if (spellAPI.getRandom(_this->OpaqueClass, 100) <= chance)
346 {
347 toolboxAPI.figureSetNewJob(_this, target.entity_index, kGdJobOfferMe, 0, 0, 0);
348 }
349 }
350 }
351 for (int i = PHASE_0; i < OnHitEnd; ++i)
352 {
353 if (i == PHASE_0)
354 {
355 if (isActionMelee(&action))
356 {
357 damage = handle_berserk_set(_this, source_index, target.entity_index, damage);
358 damage = handle_riposte_set(_this, source_index, target.entity_index, damage);
359 }
360 else
361 {
362 damage = handle_trueshot_set(_this, source_index, target.entity_index, damage);
363 }
364 }
365 std::list<std::pair<uint16_t, onhit_handler_ptr>> onhit_list =
366 get_onhit_phase(static_cast<OnHitPhase>(i));
367 for (auto it = onhit_list.crbegin(); it != onhit_list.crend(); ++it)
368 {
369 std::pair<uint16_t, onhit_handler_ptr> entry = *it;
370
371 uint16_t spell_line_id = entry.first;
372
373 if (hasSpellTag(spell_line_id, TARGET_ONHIT_SPELL))
374 {
375 //Target on-hits for ranged spells should be handled in phys effect hook, not here
376 if (isActionMelee(&action))
377 {
378 if ((_this->CGdFigure->figures[target.entity_index].flags & F_CHECK_SPELLS_BEFORE_JOB) != 0)
379 {
380 if (toolboxAPI.hasSpellOnIt(_this->CGdFigureToolBox, target.entity_index,
381 spell_line_id))
382 {
383 onhit_handler_ptr onhit_func = entry.second;
384 damage = onhit_func(_this, source_index, target.entity_index, damage);
385 }
386 }
387 }
388 }
389 else
390 {
391 if ((_this->CGdFigure->figures[source_index].flags & F_CHECK_SPELLS_BEFORE_JOB) != 0)
392 {
393 if (toolboxAPI.hasSpellOnIt(_this->CGdFigureToolBox, source_index, spell_line_id))
394 {
395 onhit_handler_ptr onhit_func = entry.second;
396 damage = onhit_func(_this, source_index, target.entity_index, damage);
397 }
398 }
399 }
400 }
401 }
402 // donnoe wtf is it, looks like shooting?
403 if (action.type == 0x2712)
404 {
405 uint16_t maxY = (_this->CGdFigure->figures[source_index].position.Y <=
406 _this->CGdFigure->figures[target.entity_index].position.Y)
407 ? (_this->CGdFigure->figures[target.entity_index].position.Y)
408 : (_this->CGdFigure->figures[source_index].position.Y);
409
410 uint16_t maxX = (_this->CGdFigure->figures[source_index].position.X <=
411 _this->CGdFigure->figures[target.entity_index].position.X)
412 ? (_this->CGdFigure->figures[target.entity_index].position.X)
413 : (_this->CGdFigure->figures[source_index].position.X);
414
415 uint16_t minY = (_this->CGdFigure->figures[source_index].position.Y >
416 _this->CGdFigure->figures[target.entity_index].position.Y)
417 ? (_this->CGdFigure->figures[target.entity_index].position.Y)
418 : (_this->CGdFigure->figures[source_index].position.Y);
419
420 uint16_t minX = (_this->CGdFigure->figures[source_index].position.X >
421 _this->CGdFigure->figures[target.entity_index].position.X)
422 ? (_this->CGdFigure->figures[target.entity_index].position.X)
423 : (_this->CGdFigure->figures[source_index].position.X);
424 SF_Coord p1;
425 SF_Coord p2;
426 SF_Rectangle vector;
427 p1.X = maxX;
428 if (minX < maxX)
429 {
430 p1.X = minX;
431 }
432 p1.Y = maxY;
433 if (minY < maxY)
434 {
435 p1.Y = minY;
436 }
437
438 p2.X = maxX;
439 if (maxX <= minX)
440 {
441 p2.X = minX;
442 }
443 p2.Y = maxY;
444 if (maxY <= minY)
445 {
446 p2.Y = minY;
447 }
448 vector.partA = p1.Y << 0x10 | p1.X;
449 vector.partB = p2.Y << 0x10 | p2.X;
450
451 uint32_t distance = getDistance(&_this->CGdFigure->figures[source_index].position,
452 &_this->CGdFigure->figures[target.entity_index].position);
453 distance = ((distance & 0xffff) * 1400) / 3000;
454 SF_CGdTargetData source = {1, source_index, {0, 0}};
455 uint16_t effect_id = effectAPI.addEffect(_this->CGdEffect, kGdEffectProjectile, &source, &target,
457 ((distance != 0) ? distance : 1), &vector);
458 log_debug(DEBUG_LOW, "Effect %d Distance %d", effect_id, distance);
459
460 effectAPI.setEffectXData(_this->CGdEffect, effect_id, EFFECT_ENTITY_TYPE, 1);
461 effectAPI.setEffectXData(_this->CGdEffect, effect_id, EFFECT_ENTITY_TYPE2, 1);
462 effectAPI.setEffectXData(_this->CGdEffect, effect_id, EFFECT_ENTITY_INDEX, source_index);
463 effectAPI.setEffectXData(_this->CGdEffect, effect_id, EFFECT_ENTITY_INDEX2, target.entity_index);
464 effectAPI.setEffectXData(_this->CGdEffect, effect_id, EFFECT_ADD_SUBSPELL, 1);
465 effectAPI.setEffectXData(_this->CGdEffect, effect_id, EFFECT_PHYSICAL_DAMAGE, damage);
466
467 uint16_t subspell_id = 0;
468 // troll fire thrower
469 if (_this->CGdFigure->figures[source_index].unit_data_id == 0x508)
470 {
471 subspell_id = 0x6de;
472 }
473 // troll ice thrower
474 if (_this->CGdFigure->figures[source_index].unit_data_id == 0x505)
475 {
476 subspell_id = 0x6ea;
477 }
478 // windarcher
479 if (_this->CGdFigure->figures[source_index].unit_data_id == 0x4cd)
480 {
481 subspell_id = 0x6d2;
482 }
483 if (subspell_id != 0)
484 {
485 uint16_t spell_lvl = _this->CGdFigure->figures[source_index].level;
486 uint16_t spell_id =spellAPI.getLeveledSpellID(_this->CGdResource, subspell_id, spell_lvl);
487 if (spell_id != 0)
488 {
489 effectAPI.setEffectXData(_this->CGdEffect, effect_id, EFFECT_SUBSPELL_ID, spell_id);
490 }
491 }
492 }
493 else
494 {
495 // Havoc & DeathKnight upgrade
496 if ((_this->CGdFigure->figures[target.entity_index].unit_data_id == 0x510) ||
497 (_this->CGdFigure->figures[target.entity_index].unit_data_id == 0x513))
498 {
499 // NOT a bug, but feature. The higher the level of enemy, the stronger curse gets.
500 uint16_t spell_id = spellAPI.getLeveledSpellID(_this->CGdResource, 0x167,
501 _this->CGdFigure->figures[source_index].level);
502 if (spell_id != 0)
503 {
504 SF_CGdTargetData t_data;
505 t_data.entity_index = source_index;
506 t_data.entity_type = 1;
507 t_data.position = {0, 0};
508 spellAPI.addSpell(_this->CGdSpell, spell_id, _this->OpaqueClass->current_step, &target, &t_data,
509 0);
510 }
511 }
512 if(damage != 0)
513 {
514 toolboxAPI.dealDamage(_this->CGdFigureToolBox, source_index, target.entity_index, damage, 0, 0, 0);
515 }
516 }
517
518 if (figureAPI.isAlive(_this->CGdFigure, target.entity_index))
519 {
520 uint16_t weapon_id = _this->CGdFigure->figures[source_index].equipment[(action.type != 10000) * 2 + 1];
521 // can't make heads or tails here
522 uint32_t puVar15[2];
523 g_getWeaponEffects(_this->CGdResource, puVar15, weapon_id);
524 if (puVar15[0] != 0)
525 {
526 for (int i = 0; i < 3; i++)
527 {
528 uint16_t enchant_id = *(uint16_t *)((uint32_t)(&puVar15[0]) + i * 2 + 2);
529
530 if (enchant_id == 0)
531 break;
532 SF_CGdResourceSpell spell_data;
533 spellAPI.getResourceSpellData(_this->CGdResource, &spell_data, enchant_id);
534
535/*
536 uint16_t curr_dex = getCurrentDex(_this->CGdFigure, source_index);
537 uint16_t curr_int = getCurrentInt(_this->CGdFigure, source_index);
538 uint16_t chance = get_effect_chance(curr_dex, curr_int, spell_data.spell_line_id);
539 */
540
541 enchant_handler_ptr chance_handler = get_enchant_handler(spell_data.spell_line_id);
542 uint32_t chance = chance_handler(_this->CGdFigure, source_index);
543 if (spellAPI.getRandom(_this->OpaqueClass, 10000) < chance)
544 {
545 if ((_this->CGdFigure->figures[source_index].race != 0) &&
546 (_this->CGdFigure->figures[source_index].race < 7))
547 {
548 if (_this->CGdFigure->figures[source_index].owner != 0)
549 {
550 enchant_id = spellAPI.getLeveledSpellID(_this->CGdResource, enchant_id,
551 _this->CGdFigure->figures[source_index].
552 level);
553 }
554 }
555 if (enchant_id != 0)
556 {
557 // FIXME reflect enchants as well in riposte set handler;
558 SF_CGdTargetData source;
559 source.entity_type = 1;
560 source.entity_index = source_index;
561 source.position = {0, 0};
562 spellAPI.addSpell(_this->CGdSpell, enchant_id, _this->OpaqueClass->current_step,
563 &source, &target, 0);
564 }
565 }
566 }
567 }
568 }
569 }
570 }
571 if (target.entity_type == 2)
572 {
573 uint16_t damage = g_get_reduced_building_damage(_this->AutoClass34, source_index, target.entity_index,
574 weapon_damage);
575 if ((target.entity_index != 0) && (_this->CGdBuilding->buildings[target.entity_index].health_current != 0))
576 {
577 buildingAPI.buildingDealDamage(_this->CGdBuildingToolBox, source_index, target.entity_index, damage, 0);
578 }
579 }
580 if (target.entity_type == 3)
581 {
582 if (target.entity_index != 0)
583 {
584 uint32_t value_1 = g_FUN_0071d7b0(_this->CGdObject, target.entity_index);
585 if ((value_1 != 0) && (g_FUN_00755180(value_1) != 0))
586 {
587 g_objectDealDamage(_this->CGdObjectToolBox, source_index, target.entity_index, weapon_damage, 0);
588 }
589 }
590 }
591}
592
SpellFunctions * spellAPI
Definition TestMod.cpp:11
FigureFunctions * figureAPI
Definition TestMod.cpp:13
ToolboxFunctions * toolboxAPI
Definition TestMod.cpp:12
EffectFunctions effectAPI
Definition sf_hooks.c:45
BuildingFunctions buildingAPI
Definition sf_hooks.c:47
AiFunctions aiAPI
Definition sf_hooks.c:51
uint32_t __thiscall getDistance(SF_Coord *pointA, SF_Coord *pointB)
Definition sf_wrappers.c:41
void log_debug(DebugLevel level, const char *format,...)
bool __thiscall hasSpellTag(uint16_t spell_id, SpellTag tag)
void log_info(const char *format,...)
bool __thiscall isActionMelee(SF_SGtFigureAction *_this)
int AddrOf(int offset)
returns "real" virtual address of given memory offset
Definition sf_asi.h:135
enchant_handler_ptr get_enchant_handler(uint16_t spell_line)
@ kGdEffectProjectile
@ TARGET_ONHIT_SPELL
@ kGdJobHitTargetRange2
@ kGdJobStartWorkAtBuilding
@ kGdJobEnterBuilding
@ kGdJobWarriorNothing
@ kGdJobCastPreResolve
@ kGdJobExitBuilding
@ kGdJobCheckBattleSleep
@ kGdJobCastResolve
@ kGdJobGroupNothing
@ kGdJobMeleeAbility
@ kGdJobWalkToTarget
@ EFFECT_ENTITY_TYPE2
@ EFFECT_ENTITY_INDEX2
@ EFFECT_SUBSPELL_ID
@ EFFECT_ENTITY_TYPE
@ EFFECT_ADD_SUBSPELL
@ EFFECT_ENTITY_INDEX
@ EFFECT_PHYSICAL_DAMAGE
@ kGdSpellLinePoison
@ F_CHECK_SPELLS_BEFORE_JOB
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)
void __thiscall getTargetData(FigureJobData *_this, SF_CGdTargetData *target)
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)
std::list< std::pair< uint16_t, onhit_handler_ptr > > get_onhit_phase(OnHitPhase phase)
uint16_t(__thiscall * enchant_handler_ptr)(SF_CGdFigure *_this, uint16_t figure_id)
uint16_t(__thiscall * onhit_handler_ptr)(SF_CGdFigureJobs *, uint16_t source, uint16_t target, uint16_t damage)
SF_CGdTargetData target
uint16_t to_do_count
uint16_t equipment[16]
FigureStatistic dexterity
FigureJobData current_job
uint16_t unit_data_id
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
SF_CGdBuildingToolbox * CGdBuildingToolBox