Spellforce-Spell-framework
Loading...
Searching...
No Matches
sf_ai_spell_handlers.cpp
Go to the documentation of this file.
3
4#include <stdio.h>
5
7 uint16_t target_index,
8 uint16_t spell_line,
9 SF_CGdResourceSpell *spell_data)
10{
11 uint32_t rank = 1;
12 if (!toolboxAPI.hasSpellOnIt((_this->battleData).CGdFigureToolBox,
13 target_index, kGdSpellLinePoison))
14 {
15 rank = 0;
16 }
17 return rank;
18}
19
20// Ice, Fire, Thorn shield, Conservation, Dexterity
22 uint16_t target_index,
23 uint16_t spell_line,
24 SF_CGdResourceSpell *spell_data)
25{
26 uint32_t rank = 1;
27 if (_this->battleData.enemy_figures.entityCount == 0)
28 {
29 rank = 0;
30 }
31 else
32 {
33 if (toolboxAPI.isUnitMelee(_this->battleData.CGdFigureToolBox, target_index))
34 {
35 rank = rank << 2;
36 }
37 else
38 {
39 rank = rank << 1;
40 }
41
42 if (figureAPI.getCurrentStat(_this->battleData.CGdFigure, target_index, HEALTH) <
43 figureAPI.getMaxStat(_this->battleData.CGdFigure, target_index, HEALTH))
44 {
45 rank = rank << 1;
46 }
47 }
48 return rank;
49}
50
52 uint16_t target_index,
53 uint16_t spell_line,
54 SF_CGdResourceSpell *spell_data)
55{
56 uint32_t rank = 1;
57 if (!toolboxAPI.hasSpellOnIt((_this->battleData).CGdFigureToolBox, target_index, kGdSpellLinePestilence))
58 {
59 rank = 0;
60 }
61 return rank;
62}
63
65 uint16_t target_index,
66 uint16_t spell_line,
67 SF_CGdResourceSpell *spell_data)
68{
69 uint32_t rank = 1;
70 if (figureAPI.getCurrentHealthPercent(_this->battleData.CGdFigure, target_index) < 50)
71 {
72 rank = rank * 10;
73 }
74 else
75 {
76 rank = 0;
77 }
78
79 return rank;
80}
81
82// weakness, suffocation, lifetap
83// slow fighting, inflexibility, slow walking
84// inability, hypnotization, manatap
86 uint16_t target_index,
87 uint16_t spell_line,
88 SF_CGdResourceSpell *spell_data)
89{
90 uint32_t rank = 1;
91 if (_this->battleData.current_figure == target_index)
92 {
93 if (_this->battleData.enemy_figures.entityCount == 0)
94 {
95 rank = 0;
96 }
97 else
98 {
99 uint16_t manacost = (spell_data->mana_cost * 7) / 2;
100 if (figureAPI.getCurrentStat(_this->battleData.CGdFigure, target_index, MANA) < manacost)
101 {
102 rank = 0;
103 }
104 if ((spellAPI.hasSpellTag(spell_line, SpellTag::BLACK_AURA_SPELL)) &&
105 (toolboxAPI.hasSpellOnIt(_this->battleData.CGdFigureToolBox, target_index,
107 {
108 rank = 0;
109 }
110 }
111 }
112 else
113 {
114 rank = 0;
115 }
116 return rank;
117}
118
120 uint16_t target_index,
121 uint16_t spell_line,
122 SF_CGdResourceSpell *spell_data)
123{
124 uint32_t rank = 4;
125 if (_this->battleData.current_figure != target_index)
126 {
127 rank = 0;
128 }
129 if (_this->battleData.enemy_figures.entityCount == 0)
130 {
131 rank = 0;
132 }
133 SF_Coord caster_pos = _this->battleData.CGdFigure->figures[target_index].position;
134 SF_Coord initial_offset = {1,10};
135 SF_Coord figure_pos = {0,0};
136 uint16_t sector = _this->battleData.CGdWorld->cells[caster_pos.Y * 400 + caster_pos.X].sector;
137
138 if (!toolboxAPI.findClosestFreePosition(_this->battleData.CGdWorldToolBox, &caster_pos, &initial_offset, sector,
139 &figure_pos))
140 {
141 rank = 0;
142 }
143 return rank;
144}
145
146// kGdSpellLineAuraStrength
147// kGdSpellLineAuraEndurance
148// kGdSpellLineAuraFastFighting
149// kGdSpellLineAuraFlexibility
150// kGdSpellLineAuraFastWalking
151// kGdSpellLineAuraDexterity
152// kGdSpellLineAuraBrilliance
154 uint16_t target_index,
155 uint16_t spell_line,
156 SF_CGdResourceSpell *spell_data)
157{
158 uint32_t rank = 1;
159 if (_this->battleData.current_figure == target_index)
160 {
161 if ((_this->battleData.enemy_figures.entityCount == 0) ||
162 (_this->battleData.ally_figures.entityCount == 0))
163 {
164 rank = 0;
165 }
166 else
167 {
168 uint16_t manacost = (spell_data->mana_cost * 7) / 2;
169 if (figureAPI.getCurrentStat(_this->battleData.CGdFigure, target_index, MANA) < manacost)
170 {
171 rank = 0;
172 }
173 if ((spellAPI.hasSpellTag(spell_line, SpellTag::WHITE_AURA_SPELL)) &&
174 (toolboxAPI.hasSpellOnIt(_this->battleData.CGdFigureToolBox, target_index,
176 {
177 rank = 0;
178 }
179 }
180 }
181 else
182 {
183 rank = 0;
184 }
185 return rank;
186}
187
188// Regeneration and Healing
190 uint16_t target_index,
191 uint16_t spell_line,
192 SF_CGdResourceSpell *spell_data)
193{
194 uint32_t rank = 1;
195 if (_this->battleData.current_figure == target_index)
196 {
197 if ((_this->battleData.enemy_figures.entityCount == 0) &&
198 (_this->battleData.ally_figures.entityCount == 0))
199 {
200 rank = 0;
201 }
202 else
203 {
204 if (_this->battleData.figures_missing_hp == 0)
205 {
206 rank = 0;
207 }
208 else
209 {
210 uint16_t manacost = (spell_data->mana_cost * 7) / 2;
211 if (figureAPI.getCurrentStat(_this->battleData.CGdFigure, target_index, MANA) < manacost)
212 {
213 rank = 0;
214 }
215 uint16_t best_target = 0;
216 uint16_t subspell_id = spell_data->params[6];
217 SF_CGdResourceSpell sub_spell_data;
218 spellAPI.getResourceSpellData(_this->battleData.CGdResource, &sub_spell_data, subspell_id);
219 uint16_t healing_amount = sub_spell_data.params[0];
220 for (int i = 0; i < _this->battleData.ally_figures.entityCount; i++)
221 {
222 uint16_t figure_id = _this->battleData.ally_figures.data[i].entity_index;
223 if (_this->battleData.CGdFigure->figures[figure_id].health.missing_val >= healing_amount)
224 {
225 best_target = figure_id;
226 break;
227 }
228 }
229 if (best_target == 0)
230 {
231 rank = 0;
232 }
233 }
234 }
235 }
236 else
237 {
238 rank = 0;
239 }
240 return rank;
241}
242
244 uint16_t target_index,
245 uint16_t spell_line,
246 SF_CGdResourceSpell *spell_data)
247{
248 uint32_t rank = 1;
249 if (_this->battleData.current_figure == target_index)
250 {
251 if (_this->battleData.enemy_figures.entityCount == 0)
252 {
253 rank = 0;
254 }
255 else
256 {
257 rank = 0;
258 // Vanilla Bug Fix
259 for (uint16_t i = 0; i < _this->battleData.enemy_figures.entityCount; i++)
260 {
261 uint16_t enemy_index = _this->battleData.enemy_figures.data[i].entity_index;
262 if (_this->battleData.CGdFigure->figures[enemy_index].flags & UNDEAD)
263 {
264 rank = 1;
265 break;
266 }
267 }
268 if (rank)
269 {
270 uint16_t manacost = (spell_data->mana_cost * 7) / 2;
271 if (figureAPI.getCurrentStat(_this->battleData.CGdFigure, target_index, MANA) < manacost)
272 {
273 rank = 0;
274 }
275 }
276 }
277 }
278 else
279 {
280 rank = 0;
281 }
282 return rank;
283}
284
285// kGdSpellLineAbilityWarCry
286// kGdSpellLineAbilityPatronize
287// kGdSpellLineAbilityEndurance
289 uint16_t target_index,
290 uint16_t spell_line,
291 SF_CGdResourceSpell *spell_data)
292{
293 uint32_t rank = 1;
294 if ((_this->battleData.current_figure != target_index) ||
295 (_this->battleData.ally_figures.entityCount < 4) ||
297 {
298 rank = 0;
299 }
300 else
301 {
302 uint8_t figure_count = 0;
303 for (uint16_t i = 0; i < _this->battleData.ally_figures.entityCount;
304 i++)
305 {
306 uint16_t ally_index =
308 if ((figureAPI.isAlive(_this->battleData.CGdFigure, ally_index)) &&
309 (figureAPI.isWarrior(_this->battleData.CGdFigure, ally_index)) &&
310 (!toolboxAPI.hasSpellOnIt(_this->battleData.CGdFigureToolBox, ally_index, spell_line)))
311 {
312 figure_count++;
313 }
314 if (figure_count > 3)
315 {
316 break;
317 }
318 }
319 if (figure_count < 3)
320 {
321 rank = 0;
322 }
323 }
324 return rank;
325}
326
327// kGdSpellLineAbilityShelter
328// kGdSpellLineAbilityTrueShot
329// kGdSpellLineAbilitySteelSkin
330// kGdSpellLineAbilitySalvo
332 uint16_t target_index,
333 uint16_t spell_line,
334 SF_CGdResourceSpell *spell_data)
335{
336 uint32_t rank = 1;
337 if ((_this->battleData.current_figure != target_index) ||
339 {
340 rank = 0;
341 }
342 return rank;
343}
344
345// kGdSpellLineAbilityDurability
346// kGdSpellLineAbilityRiposte
348 uint16_t target_index,
349 uint16_t spell_line,
350 SF_CGdResourceSpell *spell_data)
351{
352 uint32_t rank = 1;
353 if ((_this->battleData.current_figure != target_index) ||
355 {
356 rank = 0;
357 }
358 else
359 {
360 if (figureAPI.getCurrentHealthPercent(_this->battleData.CGdFigure, target_index) > 80)
361 {
362 rank = 0;
363 }
364 }
365 return rank;
366}
367
368// kGdSpellLineSummonGoblin
369// kGdSpellLineSummonSkeleton
370// kGdSpellLineSummonDemon
371// kGdSpellLineSummonChanneler
372// kGdSpellLineSummonSpectre
373// kGdSpellLineSummonWolf
374// kGdSpellLineSummonBear
375// kGdSpellLineFireElemental
376// kGdSpellLineIceElemental
377// kGdSpellLineEarthElemental
378// kGdSpellLineSummonTreeWraith
379// kGdSpellLineSummonBlade
380// kGdSpellLineSummonFireGolem
381// kGdSpellLineSummonIceGolem
382// kGdSpellLineSummonEarthGolem
383// kGdSpellLineMirrorImage
385 uint16_t target_index,
386 uint16_t spell_line,
387 SF_CGdResourceSpell *spell_data)
388{
389 uint32_t rank = 1;
390 if ((_this->battleData.current_figure != target_index) ||
392 {
393 rank = 0;
394 }
395 else
396 {
397 uint16_t manacost = (spell_data->mana_cost * 3) / 2;
398 if (figureAPI.getCurrentStat(_this->battleData.CGdFigure, target_index, MANA) < manacost)
399 {
400 rank = 0;
401 }
402 }
403 return rank;
404}
405
406// kGdSpellLineDistract
407// kGdSpellLineShockwave
408// kGdSpellLineWaveOfFire
409// kGdSpellLineWaveOfIce
410// kGdSpellLineWaveOfRocks
411uint32_t __thiscall wave_ai_handler(SF_CGdBattleDevelopment *_this,
412 uint16_t target_index, uint16_t spell_line,
413 SF_CGdResourceSpell *spell_data)
414{
415 uint32_t rank = 1;
416 if ((_this->battleData.current_figure != target_index) ||
418 {
419 rank = 0;
420 }
421 else
422 {
423 uint8_t figure_count = 0;
424 for (uint16_t i = 0; i < _this->battleData.enemy_figures.entityCount; i++)
425 {
426 uint16_t enemy_index = _this->battleData.enemy_figures.data[i].entity_index;
427 if (figureAPI.isAlive(_this->battleData.CGdFigure, enemy_index))
428 {
429 SF_Coord enemy_pos = _this->battleData.CGdFigure->figures[enemy_index].position;
430 SF_Coord caster_pos = _this->battleData.current_figure_pos;
431 if (getDistance(&enemy_pos, &caster_pos) < 10)
432 {
433 figure_count++;
434 }
435 }
436 if (figure_count > 2)
437 {
438 break;
439 }
440 }
441 if (figure_count < 2)
442 {
443 rank = 0;
444 }
445 }
446 return rank;
447}
448
450 uint16_t target_index,
451 uint16_t spell_line,
452 SF_CGdResourceSpell *spell_data)
453{
454 uint32_t rank = 1;
455 if ((_this->battleData.current_figure != target_index) ||
457 {
458 rank = 0;
459 }
460 else
461 {
462 // Berserk level 101 is special case for trolls
463 if (spell_data->skill_requirements[2] > 100)
464 {
465 if (figureAPI.getCurrentHealthPercent(_this->battleData.CGdFigure, target_index) > 25)
466 {
467 rank = 0;
468 }
469 }
470 }
471 return rank;
472}
473
475 uint16_t target_index,
476 uint16_t spell_line,
477 SF_CGdResourceSpell *spell_data)
478{
479 uint32_t rank = 1;
480 if ((_this->battleData.current_figure != target_index) ||
482 {
483 rank = 0;
484 }
485 else
486 {
487 if (figureAPI.getCurrentHealthPercent(_this->battleData.CGdFigure,
488 target_index) > (100 - spell_data->params[0]))
489 {
490 rank = 0;
491 }
492 }
493 return rank;
494}
495
497 uint16_t target_index,
498 uint16_t spell_line,
499 SF_CGdResourceSpell *spell_data)
500{
501 uint32_t rank = 1;
502 if ((_this->battleData.current_figure != target_index) ||
503 (_this->battleData.enemy_figures.entityCount == 0) ||
504 (_this->battleData.ally_figures.entityCount < 4) ||
505 (_this->battleData.figures_missing_hp == 0))
506 {
507 rank = 0;
508 }
509 else
510 {
511 uint16_t figures_count = 0;
512 for (uint16_t i = 0; i < _this->battleData.ally_figures.entityCount;
513 i++)
514 {
515 uint16_t ally_index =
517 if (figureAPI.isAlive(_this->battleData.CGdFigure, ally_index))
518 {
519 if (!toolboxAPI.hasSpellOnIt(_this->battleData.CGdFigureToolBox, ally_index, spell_line))
520 {
521 if (figureAPI.isWarrior(_this->battleData.CGdFigure, ally_index))
522 {
523 if (figureAPI.getCurrentHealthPercent(
524 _this->battleData.CGdFigure, ally_index) < (100 - spell_data->params[0]))
525 {
526 figures_count++;
527 }
528 }
529 }
530 else
531 {
532 rank = 0;
533 break;
534 }
535 }
536 }
537 if (figures_count < 3)
538 {
539 rank = 0;
540 }
541 }
542 return rank;
543}
544
546 uint16_t target_index,
547 uint16_t spell_line,
548 SF_CGdResourceSpell *spell_data)
549{
550 uint32_t rank = 1;
551 if ((_this->battleData.current_figure != target_index) ||
552 (_this->battleData.enemy_figures.entityCount == 0) ||
553 (_this->battleData.ally_figures.entityCount == 0))
554 {
555 rank = 0;
556 }
557 else
558 {
559 uint16_t percent = figureAPI.getCurrentHealthPercent(_this->battleData.CGdFigure, target_index);
560 // hardcode value is 75% gamedata value is 50%, i go with gamedata value
561 if (percent > (100 - spell_data->params[1]))
562 {
563 rank = 0;
564 }
565 }
566 return rank;
567}
568
570 uint16_t target_index,
571 uint16_t spell_line,
572 SF_CGdResourceSpell *spell_data)
573{
574 uint32_t rank = 1;
575 if ((_this->battleData.current_figure != target_index) ||
577 {
578 rank = 0;
579 }
580 else
581 {
583 SF_Coord pos;
584 iteratorAPI.figureIteratorInit(&iter, 0, 0, 0x3ff, 0x3ff);
585 iteratorAPI.figureIteratorSetPointers(&iter,
586 _this->battleData.CGdFigure,
587 _this->battleData.autoclass22,
588 _this->battleData.CGdWorld);
589 figureAPI.getPosition(_this->battleData.CGdFigure, &pos, target_index);
590 if (toolboxAPI.isUnitMelee(_this->battleData.CGdFigureToolBox, target_index))
591 {
592 iteratorAPI.iteratorSetArea(&iter, &pos, 2);
593 }
594 else
595 {
596 iteratorAPI.iteratorSetArea(&iter, &pos, 8);
597 }
598 bool should_use = false;
599 uint16_t figure_id = iteratorAPI.getNextFigure(&iter);
600 while (figure_id != 0)
601 {
602 if (_this->battleData.CGdFigure->figures[figure_id].owner != (uint16_t)-1)
603 {
604 if (toolboxAPI.figuresCheckHostile( _this->battleData.CGdFigureToolBox, target_index, figure_id))
605 {
606 if (figureAPI.isAlive(_this->battleData.CGdFigure, figure_id))
607 {
608 if (figureAPI.getCurrentHealthPercent(_this->battleData.CGdFigure, figure_id) < 50)
609 {
610 should_use = true;
611 break;
612 }
613 }
614 }
615 }
616 figure_id = iteratorAPI.getNextFigure(&iter);
617 }
618 if (!should_use)
619 {
620 rank = 0;
621 }
622 iteratorAPI.disposeFigureIterator(&iter);
623 }
624 return rank;
625}
626
627// kGdSpellLineProtectionBlack
628// kGdSpellLineFakeSpellOneFigure
630 uint16_t target_index,
631 uint16_t spell_line,
632 SF_CGdResourceSpell *spell_data)
633{
634 return 0;
635}
636
638 uint16_t target_index,
639 uint16_t spell_line,
640 SF_CGdResourceSpell *spell_data)
641{
642 return 2;
643}
644
645// Weird shit, might need fix?
647 uint16_t target_index,
648 uint16_t spell_line,
649 SF_CGdResourceSpell *spell_data)
650{
651 uint32_t rank = 5;
652 uint16_t current_mp = figureAPI.getCurrentStat(_this->battleData.CGdFigure, _this->battleData.current_figure, MANA);
653 uint16_t max_mana = figureAPI.getMaxStat(_this->battleData.CGdFigure, _this->battleData.current_figure, MANA);
654 uint16_t current_health = figureAPI.getCurrentStat(_this->battleData.CGdFigure, target_index, HEALTH);
655 uint16_t max_health = figureAPI.getMaxStat(_this->battleData.CGdFigure, target_index, HEALTH);
656 if ((max_mana / 2 < current_mp) && (current_health < max_health))
657 {
658 if (current_health == 0)
659 {
660 rank = 0;
661 }
662 else
663 {
664 if (max_health == 0)
665 {
666 rank = 0;
667 }
668 else
669 {
670 rank = (current_health * 2 - max_health) / (max_health * max_health);
671 }
672 }
673 }
674 else
675 {
676 rank = 0;
677 }
678 return rank;
679}
680
682 uint16_t target_index,
683 uint16_t spell_line,
684 SF_CGdResourceSpell *spell_data)
685{
686 uint32_t rank = 1;
688 uint16_t list_length = ((uint32_t)node.data - (uint32_t)node.first) >> 1;
689 if ((_this->battleData.enemy_figures.entityCount == 0) ||
690 (list_length == 0))
691 {
692 rank = 0;
693 }
694 else
695 {
700 }
701 return rank;
702}
703
705 uint16_t target_index,
706 uint16_t spell_line,
707 SF_CGdResourceSpell *spell_data)
708{
709 uint32_t rank = 1;
710 if (target_index == _this->battleData.current_figure)
711 {
712 uint16_t threshold = spell_data->params[0];
713 uint16_t count = 0;
714 for (int i = 0; i < _this->battleData.enemy_figures.entityCount; i++)
715 {
716 uint16_t figure_index = _this->battleData.enemy_figures.data[i].entity_index;
717 if (figureAPI.isAlive(_this->battleData.CGdFigure, figure_index))
718 {
719 if (figureAPI.getCurrentStat(_this->battleData.CGdFigure, figure_index, HEALTH) < threshold)
720 {
721 SF_Coord position;
722 figureAPI.getPosition(_this->battleData.CGdFigure, &position, figure_index);
723 uint16_t distance = getDistance(&position, &(_this->battleData.current_figure_pos));
724 if (distance < 10)
725 {
726 count++;
727 break;
728 }
729 }
730 }
731 }
732 if (!count)
733 {
734 rank = 0;
735 }
736 }
737 else
738 {
739 rank = 0;
740 }
741 return rank;
742}
743
745 uint16_t target_index,
746 uint16_t spell_line,
747 SF_CGdResourceSpell *spell_data)
748{
749 uint32_t rank = 1;
750 uint16_t current_health = figureAPI.getCurrentStat(_this->battleData.CGdFigure, target_index, HEALTH);
751 uint16_t max_health = figureAPI.getMaxStat(_this->battleData.CGdFigure, target_index, HEALTH);
752 if (toolboxAPI.hasSpellOnIt(_this->battleData.CGdFigureToolBox, target_index, kGdSpellLineRemediless))
753 {
754 return 0;
755 }
756 uint16_t healing_amount = 0;
757 struct
758 {
759 uint32_t *first;
760 uint32_t *data;
761 uint32_t *post_last;
762 } some_list;
763 uint32_t *list_first;
764 uint32_t *list_current;
765 figureAPI.getHealersList(_this->battleData.CGdFigure, &some_list, target_index);
766 uint32_t list_length = ((uint32_t)some_list.data - (uint32_t)some_list.first) >> 2;
767 if (list_length != 0)
768 {
769 list_first = some_list.first;
770 list_current = some_list.data;
771 while (list_current != list_first)
772 {
773 healing_amount += spell_data->params[0];
774 list_first++;
775 }
776 }
777 if (current_health + healing_amount < max_health)
778 {
779 if (current_health == 0)
780 {
781 rank = 0;
782 figureAPI.disposeHealerList(&some_list);
783 return rank;
784 }
785 if (((max_health * 9) / 10 < current_health + healing_amount) ||
786 (current_health + healing_amount < max_health / 10))
787 {
788 rank = rank << 1;
789 }
790 }
791 else
792 {
793 rank = 0;
794 }
795 return rank;
796}
797
798uint32_t __thiscall amok_ai_handler(SF_CGdBattleDevelopment *_this,
799 uint16_t target_index, uint16_t spell_line,
800 SF_CGdResourceSpell *spell_data)
801{
802 uint32_t rank = 2;
803 if ((_this->battleData.enemy_figures.entityCount < 2) ||
804 (spell_data->params[2] < _this->battleData.current_target_level_possibly))
805 {
806 rank = 0;
807 }
808 return rank;
809}
810
811// kGdSpellLineHypnotizeTower
812// kGdSpellLineHypnotizeTwo
813// kGdSpellLineHypnotizeArea
814// kGdSpellLineHypnotize
816 uint16_t target_index,
817 uint16_t spell_line,
818 SF_CGdResourceSpell *spell_data)
819{
820 uint32_t rank = 2;
821
822 if (spell_data->params[2] < _this->battleData.current_target_level_possibly)
823 {
824 rank = 0;
825 }
826 else
827 {
828 if (toolboxAPI.isUnitMelee(_this->battleData.CGdFigureToolBox, target_index))
829 {
830 rank = 4;
831 }
832 }
833 return rank;
834}
835
837 uint16_t target_index,
838 uint16_t spell_line,
839 SF_CGdResourceSpell *spell_data)
840{
841 uint32_t rank = 2;
842 uint16_t max_health = figureAPI.getMaxStat(_this->battleData.CGdFigure, target_index, HEALTH);
843 uint16_t current_health = figureAPI.getCurrentStat(_this->battleData.CGdFigure, target_index, HEALTH);
844 if (current_health < max_health)
845 {
846 rank = 4;
847 }
848 return rank;
849}
850
851// Stackable:
852// kGdSpellLineFireBurst
853// Icestrike
854// Non-stackable:
855// kGdSpellLinePoison
856// kGdSpellLinePestilence
858 uint16_t target_index,
859 uint16_t spell_line,
860 SF_CGdResourceSpell *spell_data)
861{
862 uint32_t rank = 2;
864 {
865 rank = 4;
866 }
867 return rank;
868}
869
870// Death and Pain
871uint32_t __thiscall death_ai_handler(SF_CGdBattleDevelopment *_this,
872 uint16_t target_index, uint16_t spell_line,
873 SF_CGdResourceSpell *spell_data)
874{
875 uint32_t rank = 2;
877 {
878 rank = ((uint16_t)_this->battleData.current_target_level_possibly / 5 +
879 1) * 2;
880 }
881 return rank;
882}
883
885 uint16_t target_index,
886 uint16_t spell_line,
887 SF_CGdResourceSpell *spell_data)
888{
889 uint32_t rank = 2;
890 uint16_t percent = figureAPI.getCurrentHealthPercent(_this->battleData.CGdFigure, _this->battleData.current_figure);
891 if (percent > 95)
892 {
893 rank = 0;
894 }
895 percent = figureAPI.getCurrentHealthPercent(_this->battleData.CGdFigure, target_index);
896 if (percent > 10)
897 {
898 rank = 0;
899 }
900 return rank;
901}
902
904 uint16_t target_index,
905 uint16_t spell_line,
906 SF_CGdResourceSpell *spell_data)
907{
908 uint32_t rank = 2;
909
910 if (spell_data->params[2] < _this->battleData.current_target_level_possibly)
911 {
912 rank = 0;
913 }
914 return rank;
915}
916
917// charm
918// charm animal
919uint32_t __thiscall charm_ai_handler(SF_CGdBattleDevelopment *_this,
920 uint16_t target_index, uint16_t spell_line,
921 SF_CGdResourceSpell *spell_data)
922{
923 uint32_t rank = 2;
924 if ((figureAPI.isFlagSet(_this->battleData.CGdFigure, target_index, UNKILLABLE)) ||
925 (spell_data->params[6] < _this->battleData.current_target_level_possibly))
926 {
927 rank = 0;
928 }
929 return rank;
930}
931
933 uint16_t target_index,
934 uint16_t spell_line,
935 SF_CGdResourceSpell *spell_data)
936{
937 uint32_t rank = 2;
938 if ((_this->battleData.CGdFigure->figures[target_index].flags & GdFigureFlags::UNDEAD) == 0)
939 {
940 rank = 0;
941 }
942 return rank;
943}
944
946 uint16_t target_index,
947 uint16_t spell_line,
948 SF_CGdResourceSpell *spell_data)
949{
950 uint32_t rank = 2;
951 uint16_t current_mp = figureAPI.getCurrentStat(_this->battleData.CGdFigure, _this->battleData.current_figure, MANA);
952 uint16_t max_mana = figureAPI.getMaxStat(_this->battleData.CGdFigure, _this->battleData.current_figure, MANA);
953
954 if (current_mp <= (uint16_t)((max_mana * 95) / 100))
955 {
956 uint16_t target_mana = figureAPI.getCurrentStat(_this->battleData.CGdFigure, target_index, MANA);
957 uint16_t target_max_mana = figureAPI.getMaxStat(_this->battleData.CGdFigure, target_index, MANA);
958 if ((target_max_mana / 10) > target_mana)
959 {
960 rank = 0;
961 }
962 }
963 else
964 {
965 rank = 0;
966 }
967 return rank;
968}
969
971 uint16_t target_index,
972 uint16_t spell_line,
973 SF_CGdResourceSpell *spell_data)
974{
975 uint32_t rank = 2;
976 if (toolboxAPI.isUnitMelee(_this->battleData.CGdFigureToolBox, target_index))
977 {
978 rank = 0;
979 }
980 return rank;
981}
982
984 uint16_t target_index,
985 uint16_t spell_line,
986 SF_CGdResourceSpell *spell_data)
987{
988 uint32_t rank = 2;
989 if (spell_data->params[1] < _this->battleData.current_target_level_possibly)
990 {
991 rank = 0;
992 }
993 return rank;
994}
995
996// befriend
997// disenchant
999 uint16_t target_index,
1000 uint16_t spell_line,
1001 SF_CGdResourceSpell *spell_data)
1002{
1003 uint32_t rank = 2;
1004 if (spell_data->params[0] < _this->battleData.current_target_level_possibly)
1005 {
1006 rank = 0;
1007 }
1008 return rank;
1009}
1010
1012 uint16_t target_index,
1013 uint16_t spell_line,
1014 SF_CGdResourceSpell *spell_data)
1015{
1016 uint32_t rank = 2;
1017 if (spell_data->params[0] < _this->battleData.current_target_level_possibly)
1018 {
1019 rank = 0;
1020 }
1021 if (_this->battleData.CGdFigure->figures[target_index].current_job.task != TASK_PET)
1022 {
1023 rank = 0;
1024 }
1025 return rank;
1026}
1028 uint16_t target_index,
1029 uint16_t spell_line,
1030 SF_CGdResourceSpell *spell_data)
1031{
1032 uint32_t rank = 2;
1033 bool hasAura = false;
1034 if (toolboxAPI.hasAuraActive(_this->battleData.CGdFigureToolBox, target_index))
1035 {
1036 for (uint16_t node_id = figureAPI.getSpellJobStartNode(_this->battleData.CGdFigure, target_index);
1037 node_id != 0;
1038 node_id = toolboxAPI.getNextNode((uint32_t *)_this->battleData.CGdDoubleLinkList, node_id))
1039 {
1040 uint16_t spell_index = toolboxAPI.getSpellIndexFromDLL((uint32_t *) _this->battleData.CGdDoubleLinkList,
1041 node_id);
1042 uint16_t spell_line = spellAPI.getSpellLine(_this->battleData.CGdSpell, spell_index);
1043 if (spellAPI.hasSpellTag(spell_line, SpellTag::WHITE_AURA_SPELL))
1044 {
1045 hasAura = true;
1046 break;
1047 }
1048 }
1049 }
1050 if (!hasAura)
1051 {
1052 rank = 0;
1053 }
1054 return rank;
1055}
1056
1058 uint16_t target_index,
1059 uint16_t spell_line,
1060 SF_CGdResourceSpell *spell_data)
1061{
1062 uint32_t rank = 2;
1063 bool hasAura = false;
1064 if (toolboxAPI.hasAuraActive(_this->battleData.CGdFigureToolBox,
1065 target_index))
1066 {
1067 for (uint16_t node_id = figureAPI.getSpellJobStartNode(_this->battleData.CGdFigure, target_index);
1068 node_id != 0;
1069 node_id = toolboxAPI.getNextNode((uint32_t *) _this->battleData.CGdDoubleLinkList, node_id))
1070 {
1071 uint16_t spell_index = toolboxAPI.getSpellIndexFromDLL((uint32_t *) _this->battleData.CGdDoubleLinkList,
1072 node_id);
1073 uint16_t spell_line = spellAPI.getSpellLine(_this->battleData.CGdSpell, spell_index);
1074 if (spellAPI.hasSpellTag(spell_line, SpellTag::BLACK_AURA_SPELL))
1075 {
1076 hasAura = true;
1077 break;
1078 }
1079 }
1080 }
1081 if (!hasAura)
1082 {
1083 rank = 0;
1084 }
1085 return rank;
1086}
1087
1089 uint16_t target_index,
1090 uint16_t spell_line,
1091 SF_CGdResourceSpell *spell_data)
1092{
1093 return 4;
1094}
1095
1097 uint16_t target_index,
1098 uint16_t spell_line,
1099 SF_CGdResourceSpell *spell_data)
1100{
1101 uint32_t rank = 2;
1102 if ((spell_data->params[2] < _this->battleData.current_target_level_possibly) ||
1103 (figureAPI.isFlagSet(_this->battleData.CGdFigure, target_index, UNKILLABLE)))
1104 {
1105 rank = 0;
1106 }
1107 return rank;
1108}
1109
1111 uint16_t target_index,
1112 uint16_t spell_line,
1113 SF_CGdResourceSpell *spell_data)
1114{
1115 uint32_t rank = 2;
1116 if ((spell_data->params[2] < _this->battleData.current_target_level_possibly) ||
1117 (figureAPI.isFlagSet(_this->battleData.CGdFigure, target_index, UNKILLABLE)))
1118 {
1119 rank = 0;
1120 }
1121 uint8_t race = _this->battleData.CGdFigure->figures[target_index].race;
1122 //TODO CGdResource::isRaceAnimal passthrough
1123 if (false)
1124 {
1125 rank = 0;
1126 }
1127 return rank;
1128}
1129
1130
1132 uint16_t target_index,
1133 uint16_t spell_line,
1134 SF_CGdResourceSpell *spell_data)
1135{
1136 uint32_t rank = 2;
1137 if ((spell_data->params[2] < _this->battleData.current_target_level_possibly) ||
1138 (figureAPI.isFlagSet(_this->battleData.CGdFigure, target_index, UNKILLABLE)))
1139 {
1140 rank = 0;
1141 }
1142 if (!figureAPI.isFlagSet(_this->battleData.CGdFigure, target_index, UNDEAD))
1143 {
1144 rank = 0;
1145 }
1146 return rank;
1147}
SpellFunctions * spellAPI
Definition TestMod.cpp:11
FigureFunctions * figureAPI
Definition TestMod.cpp:13
ToolboxFunctions * toolboxAPI
Definition TestMod.cpp:12
IteratorFunctions iteratorAPI
Definition sf_hooks.c:49
uint32_t __thiscall getDistance(SF_Coord *pointA, SF_Coord *pointB)
Definition sf_wrappers.c:41
uint32_t __thiscall cure_disease_ai_handler(SF_CGdBattleDevelopment *_this, uint16_t target_index, uint16_t spell_line, SF_CGdResourceSpell *spell_data)
uint32_t __thiscall hallow_ai_handler(SF_CGdBattleDevelopment *_this, uint16_t target_index, uint16_t spell_line, SF_CGdResourceSpell *spell_data)
uint32_t __thiscall berserk_ai_handler(SF_CGdBattleDevelopment *_this, uint16_t target_index, uint16_t spell_line, SF_CGdResourceSpell *spell_data)
uint32_t __thiscall shields_ai_handler(SF_CGdBattleDevelopment *_this, uint16_t target_index, uint16_t spell_line, SF_CGdResourceSpell *spell_data)
uint32_t __thiscall death_ai_handler(SF_CGdBattleDevelopment *_this, uint16_t target_index, uint16_t spell_line, SF_CGdResourceSpell *spell_data)
uint32_t __thiscall fireburst_ai_handler(SF_CGdBattleDevelopment *_this, uint16_t target_index, uint16_t spell_line, SF_CGdResourceSpell *spell_data)
uint32_t __thiscall disenchant_ai_handler(SF_CGdBattleDevelopment *_this, uint16_t target_index, uint16_t spell_line, SF_CGdResourceSpell *spell_data)
uint32_t __thiscall manatap_ai_handler(SF_CGdBattleDevelopment *_this, uint16_t target_index, uint16_t spell_line, SF_CGdResourceSpell *spell_data)
uint32_t __thiscall RCA_ability_ai_handler(SF_CGdBattleDevelopment *_this, uint16_t target_index, uint16_t spell_line, SF_CGdResourceSpell *spell_data)
uint32_t __thiscall amok_ai_handler(SF_CGdBattleDevelopment *_this, uint16_t target_index, uint16_t spell_line, SF_CGdResourceSpell *spell_data)
uint32_t __thiscall dominate_animal_ai_handler(SF_CGdBattleDevelopment *_this, uint16_t target_index, uint16_t spell_line, SF_CGdResourceSpell *spell_data)
uint32_t __thiscall hypnotize_ai_handler(SF_CGdBattleDevelopment *_this, uint16_t target_index, uint16_t spell_line, SF_CGdResourceSpell *spell_data)
uint32_t __thiscall lifetap_ai_handler(SF_CGdBattleDevelopment *_this, uint16_t target_index, uint16_t spell_line, SF_CGdResourceSpell *spell_data)
uint32_t __thiscall do_not_cast_ai_handler(SF_CGdBattleDevelopment *_this, uint16_t target_index, uint16_t spell_line, SF_CGdResourceSpell *spell_data)
uint32_t __thiscall dispel_white_aura_ai_handler(SF_CGdBattleDevelopment *_this, uint16_t target_index, uint16_t spell_line, SF_CGdResourceSpell *spell_data)
uint32_t __thiscall befriend_ai_handler(SF_CGdBattleDevelopment *_this, uint16_t target_index, uint16_t spell_line, SF_CGdResourceSpell *spell_data)
uint32_t __thiscall healing_ai_handler(SF_CGdBattleDevelopment *_this, uint16_t target_index, uint16_t spell_line, SF_CGdResourceSpell *spell_data)
uint32_t __thiscall tower_extinct_ai_handler(SF_CGdBattleDevelopment *_this, uint16_t target_index, uint16_t spell_line, SF_CGdResourceSpell *spell_data)
uint32_t __thiscall shift_life_ai_handler(SF_CGdBattleDevelopment *_this, uint16_t target_index, uint16_t spell_line, SF_CGdResourceSpell *spell_data)
uint32_t __thiscall death_grasp_ai_handler(SF_CGdBattleDevelopment *_this, uint16_t target_index, uint16_t spell_line, SF_CGdResourceSpell *spell_data)
uint32_t __thiscall demoralization_ai_handler(SF_CGdBattleDevelopment *_this, uint16_t target_index, uint16_t spell_line, SF_CGdResourceSpell *spell_data)
uint32_t __thiscall charm_ai_handler(SF_CGdBattleDevelopment *_this, uint16_t target_index, uint16_t spell_line, SF_CGdResourceSpell *spell_data)
uint32_t __thiscall freeze_ai_handler(SF_CGdBattleDevelopment *_this, uint16_t target_index, uint16_t spell_line, SF_CGdResourceSpell *spell_data)
uint32_t __thiscall summon_ai_handler(SF_CGdBattleDevelopment *_this, uint16_t target_index, uint16_t spell_line, SF_CGdResourceSpell *spell_data)
uint32_t __thiscall riposte_ability_ai_handler(SF_CGdBattleDevelopment *_this, uint16_t target_index, uint16_t spell_line, SF_CGdResourceSpell *spell_data)
uint32_t __thiscall default_support_ai_handler(SF_CGdBattleDevelopment *_this, uint16_t target_index, uint16_t spell_line, SF_CGdResourceSpell *spell_data)
uint32_t __thiscall dominate_undead_ai_handler(SF_CGdBattleDevelopment *_this, uint16_t target_index, uint16_t spell_line, SF_CGdResourceSpell *spell_data)
uint32_t __thiscall cure_poison_ai_handler(SF_CGdBattleDevelopment *_this, uint16_t target_index, uint16_t spell_line, SF_CGdResourceSpell *spell_data)
uint32_t __thiscall dispel_black_aura_ai_handler(SF_CGdBattleDevelopment *_this, uint16_t target_index, uint16_t spell_line, SF_CGdResourceSpell *spell_data)
uint32_t __thiscall sacrifice_mana_ai_handler(SF_CGdBattleDevelopment *_this, uint16_t target_index, uint16_t spell_line, SF_CGdResourceSpell *spell_data)
uint32_t __thiscall offensive_aura_ai_handler(SF_CGdBattleDevelopment *_this, uint16_t target_index, uint16_t spell_line, SF_CGdResourceSpell *spell_data)
uint32_t __thiscall HCA_ability_ai_handler(SF_CGdBattleDevelopment *_this, uint16_t target_index, uint16_t spell_line, SF_CGdResourceSpell *spell_data)
uint32_t __thiscall illusion_ai_handler(SF_CGdBattleDevelopment *_this, uint16_t target_index, uint16_t spell_line, SF_CGdResourceSpell *spell_data)
uint32_t __thiscall critical_hits_ai_handler(SF_CGdBattleDevelopment *_this, uint16_t target_index, uint16_t spell_line, SF_CGdResourceSpell *spell_data)
uint32_t __thiscall wave_ai_handler(SF_CGdBattleDevelopment *_this, uint16_t target_index, uint16_t spell_line, SF_CGdResourceSpell *spell_data)
uint32_t __thiscall dominate_ai_handler(SF_CGdBattleDevelopment *_this, uint16_t target_index, uint16_t spell_line, SF_CGdResourceSpell *spell_data)
uint32_t __thiscall petrify_ai_handler(SF_CGdBattleDevelopment *_this, uint16_t target_index, uint16_t spell_line, SF_CGdResourceSpell *spell_data)
uint32_t __thiscall defensive_aura_ai_handler(SF_CGdBattleDevelopment *_this, uint16_t target_index, uint16_t spell_line, SF_CGdResourceSpell *spell_data)
uint32_t __thiscall blessing_ai_handler(SF_CGdBattleDevelopment *_this, uint16_t target_index, uint16_t spell_line, SF_CGdResourceSpell *spell_data)
uint32_t __thiscall healing_aura_ai_handler(SF_CGdBattleDevelopment *_this, uint16_t target_index, uint16_t spell_line, SF_CGdResourceSpell *spell_data)
uint32_t __thiscall extinct_ai_handler(SF_CGdBattleDevelopment *_this, uint16_t target_index, uint16_t spell_line, SF_CGdResourceSpell *spell_data)
uint32_t __thiscall benefactions_ai_handler(SF_CGdBattleDevelopment *_this, uint16_t target_index, uint16_t spell_line, SF_CGdResourceSpell *spell_data)
uint32_t __thiscall default_offensive_ai_handler(SF_CGdBattleDevelopment *_this, uint16_t target_index, uint16_t spell_line, SF_CGdResourceSpell *spell_data)
uint32_t __thiscall confuse_ai_handler(SF_CGdBattleDevelopment *_this, uint16_t target_index, uint16_t spell_line, SF_CGdResourceSpell *spell_data)
uint32_t __thiscall aura_light_ai_handler(SF_CGdBattleDevelopment *_this, uint16_t target_index, uint16_t spell_line, SF_CGdResourceSpell *spell_data)
@ WHITE_AURA_SPELL
@ BLACK_AURA_SPELL
@ kGdSpellLineDispelWhiteAura
@ kGdSpellLinePoison
@ kGdSpellLinePestilence
@ kGdSpellLineRemediless
@ kGdSpellLineDispelBlackAura
EntityPriorityList ally_figures
uint32_t figures_missing_hp
SF_CGdTargetData current_source_maybe
uint32_t current_target_level_possibly
SF_Coord current_figure_pos
EntityPriorityList enemy_figures
SF_CGdFigureToolbox * CGdFigureToolBox
SF_CGdFigure * CGdFigure
SF_CGdSpell * CGdSpell
ushort_list_node another_figure_list[2000]
SF_CGdWorld * CGdWorld
SF_CGdWorldToolBox * CGdWorldToolBox
EntityPriorityList_data data[500]
FigureJobData current_job
FigureStatisticExt health
High-level structure managing AI battle development.
GdFigure figures[2000]
SF_world_unkn_2 cells[1048576]
Represents a node in a list of unsigned short values.