Spellforce-Spell-framework
Loading...
Searching...
No Matches
sf_spelleffect_handlers.cpp
Go to the documentation of this file.
4#include <cstdio>
5#include <vector>
6#include <algorithm>
7
173
174
181extern AiFunctions aiAPI;
182
183typedef uint16_t (__thiscall *reserveFigure_ptr)(SF_CGdFigureToolbox *_this, uint16_t x, uint16_t y, uint16_t owner,
184 CGdResourceUnitStats *stats, CGdFigureTask task, uint16_t param6);
186
187void __thiscall apply_aura_effect(SF_CGdSpell *_this, uint16_t spell_index, uint16_t sub_spell_index,
188 uint16_t source_index,
189 uint16_t target_index)
190{
191 SF_GdSpell *spell = &_this->active_spell_list[spell_index];
192 SF_Rectangle rect;
193 SF_Coord center = {0,0};
194 spellAPI.getTargetsRectangle(_this, &rect, spell_index, 0, &center);
195 SF_CGdTargetData target_data;
196 target_data.entity_index = target_index;
197 target_data.entity_type = 1;
198 target_data.position = {0,0};
199
200 SF_CGdTargetData source_data;
201 source_data.entity_index = source_index;
202 source_data.entity_type = 1;
203 source_data.position = {0,0};
204 SF_Coord caster_pos = _this->SF_CGdFigure->figures[source_index].position;
205 SF_Coord target_pos = _this->SF_CGdFigure->figures[target_index].position;
206 uint32_t distance = toolboxAPI.getDistance(&caster_pos, &target_pos);
207 distance = (distance * 1400) / 4000;
208 if (distance == 0)
209 {
210 distance = 1;
211 }
212 uint16_t effect_index = effectAPI.addEffect(_this->SF_CGdEffect, kGdEffectAuraResolve,
213 &source_data, &target_data,
214 _this->OpaqueClass->current_step, distance,
215 &rect);
216 effectAPI.setEffectXData(_this->SF_CGdEffect, effect_index, EFFECT_SPELL_INDEX, spell_index);
217 effectAPI.setEffectXData(_this->SF_CGdEffect, effect_index, EFFECT_SPELL_ID, spell->spell_id);
218 effectAPI.setEffectXData(_this->SF_CGdEffect, effect_index, EFFECT_SUBSPELL_ID, sub_spell_index);
219 effectAPI.setEffectXData(_this->SF_CGdEffect, effect_index, EFFECT_ENTITY_TYPE, 1);
220 effectAPI.setEffectXData(_this->SF_CGdEffect, effect_index, EFFECT_ENTITY_INDEX, source_index);
221 effectAPI.setEffectXData(_this->SF_CGdEffect, effect_index, EFFECT_ENTITY_TYPE2, 1);
222 effectAPI.setEffectXData(_this->SF_CGdEffect, effect_index, EFFECT_ENTITY_INDEX2, target_index);
223}
224
225void __thiscall effect_conservation(SF_CGdSpell *_this, uint16_t spell_index)
226{
227 SF_GdSpell *spell = &_this->active_spell_list[spell_index];
228 uint16_t source_index = spell->source.entity_index;
229 uint16_t target_index = spell->target.entity_index;
230
231
232 if ((_this->SF_CGdFigure->figures[target_index].owner != (uint16_t)(-1)) &&
233 ((_this->SF_CGdFigure->figures[target_index].flags & (IS_DEAD|RESESRVED_ONLY)) == 0))
234 {
235 if (spellAPI.addToXData(_this, spell_index, SPELL_TICK_COUNT_AUX, 1) == 1)
236 {
237 if (spellAPI.checkCanApply(_this, spell_index))
238 {
239 SF_CGdResourceSpell spell_data;
240 spellAPI.getResourceSpellData(_this->SF_CGdResource, &spell_data, spell->spell_id);
241 spellAPI.setXData(_this, spell_index, SPELL_CONSERVATION_SHIELD, spell_data.params[0]);
243 _this->SF_CGdFigure->figures[target_index].flags |= F_CHECK_SPELLS_BEFORE_JOB;
246 spell->to_do_count = 20;
247 uint32_t unused;
248 SF_Rectangle rect = {0,0};
249 SF_CGdTargetData target;
250 target.position = {0,0};
251 target.entity_index = target_index;
252 target.entity_type = 1;
253 spellAPI.addVisualEffect(_this, spell_index, kGdEffectSpellHitTarget, &unused, &target,
254 _this->OpaqueClass->current_step, 0, &rect);
255 return;
256 }
257 }
258 else
259 {
260 uint32_t shield = spellAPI.getXData(_this, spell_index, SPELL_CONSERVATION_SHIELD);
261 if (shield != 0)
262 {
263 SF_CGdResourceSpell spell_data;
264 spellAPI.getResourceSpellData(_this->SF_CGdResource, &spell_data, spell->spell_id);
265 uint32_t total_ticks = (spell_data.params[1] * 10) / 20000 - 1;
266 if (spellAPI.getXData(_this, spell_index, SPELL_TICK_COUNT_AUX) <= total_ticks)
267 {
268 spell->to_do_count = 20;
269 return;
270 }
271 }
272 spellAPI.figTryClrCHkSPlBfrJob2(_this, spell_index);
273 spellAPI.figClrChkSplBfrChkBattle(_this, spell_index, 0);
274 spellAPI.removeDLLNode(_this, spell_index);
275 }
276 }
277 spellAPI.setEffectDone(_this, spell_index, 0);
278}
279
280void __thiscall effect_ability_warcry(SF_CGdSpell *_this, uint16_t spell_index)
281{
282 SF_GdSpell *spell = &_this->active_spell_list[spell_index];
283 uint16_t source_index = spell->source.entity_index;
284
285 if (spell->target.entity_type == 1)
286 {
287 uint32_t tick_count = spellAPI.addToXData(_this, spell_index, SPELL_TICK_COUNT_AUX, 1);
288 if (tick_count == 1)
289 {
290 SF_CGdResourceSpell spell_data;
291 spellAPI.getResourceSpellData(_this->SF_CGdResource, &spell_data, spell->spell_id);
292
293 _this->active_spell_list[spell_index].to_do_count = (spell_data.params[0] * 10) / 1000;
294
295 SF_Rectangle rect = {0,0};
296 SF_Coord caster_pos = _this->SF_CGdFigure->figures[source_index].position;
297 //spellAPI.getTargetsRectangle(_this, &rect, spell_index, spell_data.params[3], &caster_pos);
298
299 SF_CGdTargetData source_data;
300 source_data.entity_index = source_index;
301 source_data.entity_type = 1;
302 source_data.position = {0,0};
303
304 spellAPI.addVisualEffect(_this, spell_index, kGdEffectSpellHitTarget, &rect, &source_data,
305 _this->OpaqueClass->current_step, 100, &rect);
306
307 _this->SF_CGdFigure->figures[source_index].flags |= F_CHECK_SPELLS_BEFORE_JOB;
309
311 iteratorAPI.setupFigureIterator(&iter, _this);
312 iteratorAPI.iteratorSetArea(&iter, &caster_pos, spell_data.params[3]);
313 std::vector<uint16_t> targets;
314 std::vector<uint16_t> meh_targets;
315 uint16_t next_figure = iteratorAPI.getNextFigure(&iter);
316 while (next_figure != 0)
317 {
318 if ((_this->SF_CGdFigure->figures[next_figure].owner != (uint16_t)(-1)) &&
319 ((_this->SF_CGdFigure->figures[next_figure].flags & (IS_DEAD|RESESRVED_ONLY)) == 0))
320 {
321 if ((next_figure != source_index) &&
322 (toolboxAPI.figuresCheckFriendly(_this->SF_CGdFigureToolBox, source_index, next_figure)) &&
323 (toolboxAPI.isTargetable(_this->SF_CGdFigureToolBox, next_figure)) &&
324 (!toolboxAPI.hasSpellOnIt(_this->SF_CGdFigureToolBox, next_figure, kGdSpellLineAbilityWarCry)))
325 {
326 if (toolboxAPI.isUnitMelee(_this->SF_CGdFigureToolBox, next_figure))
327 {
328 targets.push_back(next_figure);
329 }
330 else
331 {
332 meh_targets.push_back(next_figure);
333 }
334
335 }
336 }
337 if (targets.size() < spell_data.params[2])
338 {
339 next_figure = iteratorAPI.getNextFigure(&iter);
340 }
341 else
342 {
343 break;
344 }
345 }
346 iteratorAPI.disposeFigureIterator(&iter);
347 if (targets.size() < spell_data.params[2])
348 {
349 uint16_t count = spell_data.params[2] - targets.size();
350 while (meh_targets.size() > 0 && count > 0)
351 {
352 uint16_t add_target = meh_targets.back();
353 targets.push_back(add_target);
354 meh_targets.pop_back();
355 count--;
356 }
357 }
358 while (targets.size() > 0)
359 {
360 uint16_t target_index = targets.back();
361
362 _this->SF_CGdFigure->figures[target_index].flags |= F_CHECK_SPELLS_BEFORE_JOB;
363
364 SF_CGdTargetData target_data;
365 target_data.entity_index = target_index;
366 target_data.entity_type = 1;
367 target_data.position = {0,0};
368 spellAPI.addVisualEffect(_this, spell_index, kGdEffectSpellHitTarget, &rect, &target_data,
369 _this->OpaqueClass->current_step, 100, &rect);
370 toolboxAPI.addSpellToFigure(_this->SF_CGdFigureToolBox, target_index, spell_index);
371 targets.pop_back();
372 }
373 return;
374 }
375 for (int i = 0; i<_this->SF_CGdFigure->max_used; i++)
376 {
377 if ((_this->SF_CGdFigure->figures[i].owner != (uint16_t)(-1)) &&
378 ((_this->SF_CGdFigure->figures[i].flags & (IS_DEAD|RESESRVED_ONLY)) == 0))
379 {
380 if (toolboxAPI.removeSpellFromList(_this->SF_CGdFigureToolBox, i, spell_index))
381 {
382 spellAPI.figTryClrCHkSPlBfrJob2(_this, spell_index);
383 }
384 }
385 }
386 spellAPI.setEffectDone(_this, spell_index, 0);
387 }
388
389}
390
391void __thiscall effect_aura (SF_CGdSpell *_this, uint16_t spell_index)
392{
393 SF_GdSpell *spell = &_this->active_spell_list[spell_index];
394 SF_CGdResourceSpell spell_data;
395 uint16_t source_index = spell->source.entity_index;
396 spellAPI.getResourceSpellData(_this->SF_CGdResource, &spell_data, spell->spell_id);
397 uint16_t sub_effect_id = spell_data.params[6];
398 SF_CGdResourceSpell sub_spell_data;
399 spellAPI.getResourceSpellData(_this->SF_CGdResource, &sub_spell_data, sub_effect_id);
400 _this->active_spell_list[spell_index].to_do_count = (spell_data.params[0] * 10) / 1000;
401
402 SF_CGdTargetData source_data;
403 source_data.entity_index = source_index;
404 source_data.entity_type = 1;
405 source_data.position = {0,0};
406 if (spell->source.entity_type == 1)
407 {
408 if ((_this->SF_CGdFigure->figures[source_index].owner != (uint16_t)(-1)) &&
409 ((*(uint8_t *)(&_this->SF_CGdFigure->figures[source_index].flags) & 0xa) == 0))
410 {
411
412 uint32_t tick = spellAPI.addToXData(_this, spell_index, SPELL_TICK_COUNT_AUX, 1);
413 if (tick == 1)
414 {
415 _this->SF_CGdFigure->figures[source_index].flags |= AURA_RUNNING;
416 SF_Rectangle rect = {0, 0};
417 uint16_t effect_index = effectAPI.addEffect(_this->SF_CGdEffect, kGdEffectSpellHitTarget, &source_data,
418 &source_data,
419 _this->OpaqueClass->current_step, 0, &rect);
420
421 spellAPI.setXData(_this, spell_index, EFFECT_EFFECT_INDEX, effect_index);
422 effectAPI.setEffectXData(_this->SF_CGdEffect, effect_index, EFFECT_SPELL_INDEX, spell_index);
423 effectAPI.setEffectXData(_this->SF_CGdEffect, effect_index, EFFECT_SPELL_ID, spell->spell_id);
424 }
425 }
426
427 uint16_t current_mp = figureAPI.getCurrentStat(_this->SF_CGdFigure, source_index, MANA);
428 uint16_t aura_target_type = spell_data.params[5];
429 uint16_t manacost = spell_data.params[8];
430 if (_this->SF_CGdFigure->figures[source_index].set_type == 7)
431 {
432 manacost -= ((manacost * 33) / 100);
433 }
434 if (current_mp >= manacost)
435 {
436 SF_Coord caster_pos = _this->SF_CGdFigure->figures[source_index].position;
438 iteratorAPI.setupFigureIterator(&iter, _this);
439 iteratorAPI.iteratorSetArea(&iter, &caster_pos, spell_data.params[2]);
440 std::vector<uint16_t> targets;
441 uint16_t target_index = iteratorAPI.getNextFigure(&iter);
442 while (target_index != 0)
443 {
444 if ((_this->SF_CGdFigure->figures[target_index].owner != (uint16_t)(-1)) &&
445 ((*(uint8_t *)(&_this->SF_CGdFigure->figures[target_index].flags) & 0xa) == 0))
446 {
447 //allied auras
448 if (aura_target_type == 1)
449 {
450 if (!toolboxAPI.figuresCheckHostile(_this->SF_CGdFigureToolBox, source_index, target_index))
451 {
452 if (_this->SF_CGdFigure->figures[target_index].owner ==
453 _this->SF_CGdFigure->figures[source_index].owner)
454 {
455 //special logic here
457 {
458 uint16_t missing_hp = _this->SF_CGdFigure->figures[target_index].health.missing_val;
459 if ((missing_hp >sub_spell_data.params[0]) &&
460 (!toolboxAPI.hasSpellOnIt(_this->SF_CGdFigureToolBox, target_index,
462 {
463 targets.push_back(target_index);
464 }
465 target_index = iteratorAPI.getNextFigure(&iter);
466 continue;
467 }
468
470 {
471 uint16_t missing_hp = _this->SF_CGdFigure->figures[target_index].health.missing_val;
472 if ((missing_hp != 0) &&
473 (!toolboxAPI.hasSpellOnIt(_this->SF_CGdFigureToolBox, target_index,
474 sub_spell_data.spell_line_id)))
475 {
476 targets.push_back(target_index);
477 }
478 target_index = iteratorAPI.getNextFigure(&iter);
479 continue;
480 }
481
482 if (!toolboxAPI.hasSpellOnIt(_this->SF_CGdFigureToolBox, target_index,
483 sub_spell_data.spell_line_id))
484 {
485 if (figureAPI.isWarrior(_this->SF_CGdFigure, target_index))
486 {
487 targets.push_back(target_index);
488 }
489 }
490 }
491 }
492 }
493 //hostile auras
494 if (aura_target_type == 2)
495 {
496 if (toolboxAPI.figuresCheckHostile(_this->SF_CGdFigureToolBox, source_index, target_index))
497 {
498 if (toolboxAPI.isTargetable(_this->SF_CGdFigureToolBox, target_index))
499 {
500 if (!toolboxAPI.hasSpellOnIt(_this->SF_CGdFigureToolBox, target_index,
501 sub_spell_data.spell_line_id))
502 {
503 targets.push_back(target_index);
504 }
505 }
506 }
507 }
508
509 }
510 target_index = iteratorAPI.getNextFigure(&iter);
511 }
512 if (!targets.empty())
513 {
514 uint16_t aura_target = 0;
515 uint16_t prio = 0;
517 {
518 for (uint32_t j = 0; j < targets.size(); j++)
519 {
520 target_index = targets.at(j);
521 SF_Coord target_pos = _this->SF_CGdFigure->figures[target_index].position;
522 uint16_t dx = 7;
523 uint16_t sec_prio = 0;
524 for (int i = 8; i> 0; i--)
525 {
526 //some serious bitfuckery
527 uint16_t near_x = *(uint16_t *)((uint32_t)&_this->SF_CGdWorld->unknown1[0].uknwn1 + dx) +
528 target_pos.X;
529 uint16_t near_y = *(uint16_t *)((uint32_t)&_this->SF_CGdWorld->unknown1[0].uknwn2 + dx) +
530 target_pos.Y;
531 if (((*(uint8_t *)&_this->SF_CGdWorld->cells[near_y*0x400 + near_x].world_cell_flags) &
532 0x10) !=
533 0)
534 {
535 uint16_t sec_target = toolboxAPI.getFigureFromWorld(_this->SF_CGdWorldToolBox, near_x,
536 near_y, 1);
537
538 if ((sec_target != 0) && (toolboxAPI.figuresCheckHostile(_this->SF_CGdFigureToolBox,
539 target_index, sec_target)))
540 {
541 sec_prio++;
542 }
543 }
544 dx += 7;
545 }
546 sec_prio *= (100 - figureAPI.getCurrentHealthPercent(_this->SF_CGdFigure, target_index));
547 if (sec_prio > prio)
548 {
549 prio = sec_prio;
550 aura_target = targets[j];
551 }
552 }
553 }
555 {
556 uint16_t sec_prio = 0;
557 uint16_t prio = 0;
558
559 for (uint32_t j = 0; j < targets.size(); j++)
560 {
561 target_index = targets.at(j);
562 sec_prio = (100 - figureAPI.getCurrentHealthPercent(_this->SF_CGdFigure, target_index));
563 if (sec_prio > prio)
564 {
565 prio = sec_prio;
566 aura_target = target_index;
567 }
568 }
569 }
570 if (aura_target == 0)
571 {
572 uint16_t value = spellAPI.getRandom(_this->OpaqueClass, targets.size()-1);
573 aura_target = targets.at(value);
574 }
575 apply_aura_effect(_this, spell_index, sub_effect_id, source_index, aura_target);
576 figureAPI.subMana(_this->SF_CGdFigure, source_index, manacost);
577 }
578 iteratorAPI.disposeFigureIterator(&iter);
579 return;
580 }
581 else
582 {
583 return;
584 }
585 if (source_index != 0)
586 {
587 _this->SF_CGdFigure->figures[source_index].flags &= ~AURA_RUNNING;
588 }
589 uint16_t effect_index = spellAPI.getXData(_this, spell_index, EFFECT_EFFECT_INDEX);
590 effectAPI.tryEndEffect(_this->SF_CGdEffect, effect_index);
591 }
592 spellAPI.setXData(_this, spell_index, EFFECT_EFFECT_INDEX, 0);
593 spellAPI.setEffectDone(_this, spell_index, 0);
594 return;
595}
596
597//fix for aura set
598void __thiscall effect_siege_aura (SF_CGdSpell *_this, uint16_t spell_index)
599{
600 SF_GdSpell *spell = &_this->active_spell_list[spell_index];
601 SF_CGdResourceSpell spell_data;
602 uint16_t source_index = spell->source.entity_index;
603 spellAPI.getResourceSpellData(_this->SF_CGdResource, &spell_data, spell->spell_id);
604 SF_CGdTargetData source_data;
605 source_data.entity_index = source_index;
606 source_data.entity_type = 1;
607 source_data.position = {0,0};
608 _this->active_spell_list[spell_index].to_do_count = (spell_data.params[0] * 10) / 1000;
609 if (spell->source.entity_type == 1)
610 {
611 if ((_this->SF_CGdFigure->figures[source_index].owner != (uint16_t)(-1)) &&
612 ((*(uint8_t *)(&_this->SF_CGdFigure->figures[source_index].flags) & 0xa) == 0))
613 {
614 uint32_t tick = spellAPI.addToXData(_this, spell_index, SPELL_TICK_COUNT_AUX, 1);
615 if (tick == 1)
616 {
617 _this->SF_CGdFigure->figures[source_index].flags |= AURA_RUNNING;
618 SF_Rectangle rect = {0, 0};
619 uint16_t effect_index = effectAPI.addEffect(_this->SF_CGdEffect, kGdEffectSpellHitTarget, &source_data,
620 &source_data,
621 _this->OpaqueClass->current_step, 0, &rect);
622
623 spellAPI.setXData(_this, spell_index, EFFECT_EFFECT_INDEX, effect_index);
624 effectAPI.setEffectXData(_this->SF_CGdEffect, effect_index, EFFECT_SPELL_INDEX, spell_index);
625 effectAPI.setEffectXData(_this->SF_CGdEffect, effect_index, EFFECT_SPELL_ID, spell->spell_id);
626 }
627
628 }
629 }
630 uint16_t current_mp = figureAPI.getCurrentStat(_this->SF_CGdFigure, source_index, MANA);
631 uint16_t aura_target_type = spell_data.params[5];
632 //Aura target type is either 1 or 2 for valid auras! IDK wtf is 3, but that's valid too? ~UnSchtalch
633 if ((aura_target_type > 0) && (aura_target_type <= 3) && (current_mp >= spell_data.params[8]))
634 {
635 SF_Coord caster_pos;
636 caster_pos.X = _this->SF_CGdFigure->figures[source_index].position.X;
637 caster_pos.Y = _this->SF_CGdFigure->figures[source_index].position.Y;
639 iteratorAPI.buildingIteratorInit(&iter, 0, 0, 0x3ff, 0x3ff);
640 iteratorAPI.buildingIteratorSetPointers(&iter, _this->CGdBuilding, _this->SF_CGdTile, _this->SF_CGdWorld);
641 //Types are similar, to a point, but I do need to cast it
642
643 iteratorAPI.iteratorSetArea((CGdFigureIterator *)&iter, &caster_pos, spell_data.params[2]+10);
644 uint16_t building_index = iteratorAPI.getNextBuilding(&iter);
645 uint16_t min_distance = 0xffff;
646 uint16_t target_building = 0;
647 while (building_index != 0)
648 {
649 //Since it's siege auras, they won't have allied buildings as targets. So I DO skip section with 1
650 if (_this->CGdBuilding->buildings[building_index].owner !=
651 _this->SF_CGdFigure->figures[source_index].owner)
652 {
653 if (buildingAPI.buildingCheckHostile(_this->SF_CGdBuildingToolbox, source_index, building_index))
654 {
655 if (_this->CGdBuilding->buildings[building_index].health_current != 0)
656 {
657 SF_Rectangle building_rect;
658 buildingAPI.getBuildingClosestVertex(_this->SF_CGdBuildingToolbox, (SF_Coord *) &building_rect,
659 building_index,
660 source_index, 1);
661 SF_Coord building_pos = *(SF_Coord *)&building_rect.partA;
662 uint16_t current_distance = toolboxAPI.getDistance(&caster_pos,&building_pos);
663 if ((current_distance < min_distance) && (current_distance <= spell_data.params[2]))
664 {
665 min_distance = current_distance;
666 target_building = building_index;
667 }
668 }
669 }
670 }
671 building_index = iteratorAPI.getNextBuilding(&iter);
672 }
673 if (target_building != 0)
674 {
675 SF_CGdTargetData building_data;
676 building_data.entity_index = target_building;
677 building_data.entity_type = 2;
678 building_data.position = {0,0};
679 SF_Rectangle rect = {0,0};
680 uint16_t effect_index = effectAPI.addEffect(_this->SF_CGdEffect, kGdEffectSpellHitTarget,
681 &source_data, &building_data,
682 _this->OpaqueClass->current_step, 0x14, &rect);
683 effectAPI.setEffectXData(_this->SF_CGdEffect, effect_index, EFFECT_SPELL_INDEX, spell_index);
684 effectAPI.setEffectXData(_this->SF_CGdEffect, effect_index, EFFECT_SPELL_ID, spell->spell_id);
685 effectAPI.setEffectXData(_this->SF_CGdEffect, effect_index, EFFECT_PHYSICAL_DAMAGE,
686 spell_data.params[7]);
687 effectAPI.setEffectXData(_this->SF_CGdEffect, effect_index, EFFECT_ADD_SUBSPELL, 1);
688 effectAPI.setEffectXData(_this->SF_CGdEffect, effect_index, EFFECT_ENTITY_TYPE, 1);
689 effectAPI.setEffectXData(_this->SF_CGdEffect, effect_index, EFFECT_ENTITY_INDEX, source_index);
690 effectAPI.setEffectXData(_this->SF_CGdEffect, effect_index, EFFECT_ENTITY_TYPE2, 2);
691 effectAPI.setEffectXData(_this->SF_CGdEffect, effect_index, EFFECT_ENTITY_INDEX2, target_building);
692 }
693 iteratorAPI.disposeFigureIterator((CGdFigureIterator *)&iter);
694 return;
695 }
696 if (source_index != 0)
697 {
698 _this->SF_CGdFigure->figures[source_index].flags &= ~AURA_RUNNING;
699 }
700 uint16_t effect_index = spellAPI.getXData(_this, spell_index, EFFECT_EFFECT_INDEX);
701 effectAPI.tryEndEffect(_this->SF_CGdEffect, effect_index);
702 spellAPI.setXData(_this, spell_index, EFFECT_EFFECT_INDEX, 0);
703 spellAPI.setEffectDone(_this, spell_index, 0);
704 return;
705}
706
707void __thiscall setWeaponStats(SF_CGdFigure *_this, uint16_t figure_id, uint8_t slot, SF_CGdFigureWeaponStats *stats)
708{
709 if (slot < 2)
710 {
711 _this->figures[figure_id].weapon_stats[slot].max_dmg = stats->max_dmg;
712 _this->figures[figure_id].weapon_stats[slot].min_dmg = stats->min_dmg;
713 _this->figures[figure_id].weapon_stats[slot].max_rng = stats->max_rng;
714 _this->figures[figure_id].weapon_stats[slot].min_rng = stats->min_rng;
715
716 _this->figures[figure_id].weapon_stats[slot].wpn_mat = stats->wpn_mat;
717 _this->figures[figure_id].weapon_stats[slot].wpn_spd = stats->wpn_spd;
718 _this->figures[figure_id].weapon_stats[slot].wpn_type = stats->wpn_type;
719
720 }
721}
722
723void __thiscall getWeaponStats(SF_CGdFigure *_this, uint16_t figure_id, uint8_t slot, SF_CGdFigureWeaponStats *stats)
724{
725 if (slot < 2)
726 {
727 stats->max_dmg = _this->figures[figure_id].weapon_stats[slot].max_dmg;
728 stats->min_dmg = _this->figures[figure_id].weapon_stats[slot].min_dmg;
729 stats->max_rng = _this->figures[figure_id].weapon_stats[slot].max_rng;
730 stats->min_rng = _this->figures[figure_id].weapon_stats[slot].min_rng;
731 stats->wpn_mat = _this->figures[figure_id].weapon_stats[slot].wpn_mat;
732 stats->wpn_spd = _this->figures[figure_id].weapon_stats[slot].wpn_spd;
733 stats->wpn_type = _this->figures[figure_id].weapon_stats[slot].wpn_type;
734
735 }
736}
737
738
739void __thiscall effect_self_illusion(SF_CGdSpell *_this, uint16_t spell_index)
740{
741 SF_GdSpell *spell = &_this->active_spell_list[spell_index];
742 if (spell->target.entity_type == 1)
743 {
744 SF_CGdResourceSpell spell_data;
745 spellAPI.getResourceSpellData(_this->SF_CGdResource, &spell_data, spell->spell_id);
746
747 uint16_t source_index = spell->source.entity_index;
748 uint16_t existing_clones = 0;
749 for (int i = 1; i < _this->SF_CGdFigure->max_used; i++)
750 {
751 GdFigure *figure = &_this->SF_CGdFigure->figures[i];
752 if (((figure->flags & ILLUSION) != 0) &&
753 (toolboxAPI.hasSpellOnIt(_this->SF_CGdFigureToolBox, i, kGdSpellLineSelfIllusion)) &&
754 (figure->master_figure == source_index))
755 {
756 existing_clones++;
757 }
758 }
759 uint16_t current_tick = spellAPI.addToXData(_this, spell_index, SPELL_TICK_COUNT_AUX, 1);
760 if (current_tick == 1)
761 {
763 memset(&stats, 0, sizeof(CGdResourceUnitStats));
764
765 uint16_t scale_factor = spell_data.params[1];
766 uint16_t summon_count = spell_data.params[0];
767
768 stats.level = _this->SF_CGdFigure->figures[source_index].level;
769 stats.race = _this->SF_CGdFigure->figures[source_index].race;
770 stats.head = _this->SF_CGdFigure->figures[source_index].head;
771
772 for (int i = 0; i< 10; i++)
773 {
774 stats.abilities[i].id = 0xff;
775 stats.abilities[i].spec = 0xff;
776 stats.abilities[i].level = 0xff;
777 }
778 if ((_this->SF_CGdFigure->figures[source_index].flags & FEMALE) != 0)
779 {
780 stats.unit_flags |= 1;
781 }
782
783 stats.agility = _this->SF_CGdFigure->figures[source_index].agility.base_val;
784 stats.dexterity = _this->SF_CGdFigure->figures[source_index].dexterity.base_val;
785 stats.charisma = _this->SF_CGdFigure->figures[source_index].charisma.base_val;
786 stats.strength = _this->SF_CGdFigure->figures[source_index].strength.base_val;
787 stats.stamina = (_this->SF_CGdFigure->figures[source_index].stamina.base_val * scale_factor) / 100;
788 stats.intelligence = _this->SF_CGdFigure->figures[source_index].intelligence.base_val;
789 stats.wisdom = _this->SF_CGdFigure->figures[source_index].wisdom.base_val;
790
791 stats.ires = _this->SF_CGdFigure->figures[source_index].resistance_ice.base_val;
792 stats.fres = _this->SF_CGdFigure->figures[source_index].resistance_fire.base_val;
793 stats.bres = _this->SF_CGdFigure->figures[source_index].resistance_black.base_val;
794 stats.mres = _this->SF_CGdFigure->figures[source_index].resistance_mental.base_val;
795
796 stats.fspeed = _this->SF_CGdFigure->figures[source_index].fight_speed.base_val;
797 stats.wspeed = _this->SF_CGdFigure->figures[source_index].walk_speed.base_val;
798 stats.cspeed = _this->SF_CGdFigure->figures[source_index].cast_speed.base_val;
799 stats.scaling = _this->SF_CGdFigure->figures[source_index].scaling;
800
801 for (int i = 0; i< summon_count - existing_clones; i++)
802 {
803 SF_Coord caster_pos = _this->SF_CGdFigure->figures[source_index].position;
804 SF_Coord initial_offset = {1,10};
805 SF_Coord figure_pos = {0,0};
806 uint16_t sector = _this->SF_CGdWorld->cells[caster_pos.Y * 400 + caster_pos.X].sector;
807
808 if (toolboxAPI.findClosestFreePosition(_this->SF_CGdWorldToolBox, &caster_pos, &initial_offset, sector,
809 &figure_pos))
810 {
811 uint16_t figure_index = reserveFigure(_this->SF_CGdFigureToolBox, figure_pos.X, figure_pos.Y,
812 _this->SF_CGdFigure->figures[source_index].owner, &stats,
813 TASK_NPC, 0x1c);
814 if (figure_index != 0)
815 {
816 GdFigure *figure = &_this->SF_CGdFigure->figures[figure_index];
817 figure->flags |= ILLUSION;
818 figure->master_figure = source_index;
819 figureAPI.setJob(_this->SF_CGdFigureJobs, figure_index, kGdJobPetIdle);
820 figureAPI.setTask(_this->SF_CGdFigure,figure_index, TASK_PET);
821 SF_CGdFigureWeaponStats weapon_stats;
822
823 getWeaponStats(_this->SF_CGdFigure, source_index, 0, &weapon_stats);
824 weapon_stats.min_dmg = 0;
825 weapon_stats.max_dmg = 0;
826 setWeaponStats(_this->SF_CGdFigure, figure_index, 0, &weapon_stats);
827
828 getWeaponStats(_this->SF_CGdFigure, source_index, 1, &weapon_stats);
829 weapon_stats.min_dmg = 0;
830 weapon_stats.max_dmg = 0;
831 setWeaponStats(_this->SF_CGdFigure, figure_index, 1, &weapon_stats);
832
833 for (int j = 0; j < 15; j++)
834 {
835 SF_SGtFigureAction action;
836 aiAPI.getFigureAction(_this->SF_CGdFigure, &action, source_index, j);
837 if ((action.type != 0xFFFF) && (action.type >= 10000))
838 {
839 figureAPI.addAction(_this->SF_CGdFigure, figure_index, &action);
840 }
841 }
842 for (int j = 0; j < 16; j++)
843 {
844 uint16_t eq_id = _this->SF_CGdFigure->figures[source_index].equipment[j];
845 figure->equipment[j] = eq_id;
846 }
847 uint16_t armour = figureAPI.getCurrentStat(_this->SF_CGdFigure, source_index, ARMOR);
848 figure->armor.base_val = (armour * scale_factor) / 100;
849
850 SF_CGdTargetData source;
851 source.entity_index = source_index;
852 source.entity_type = 1;
853 source.position = {0,0};
854
855 SF_CGdTargetData target;
856 target.entity_index = figure_index;
857 target.entity_type = 1;
858 target.position = {0,0};
859
860 SF_Rectangle rect = {0,0};
861
862 uint16_t effect_index = effectAPI.addEffect(_this->SF_CGdEffect, kGdEffectSpellHitTarget,
863 &source,
864 &target, _this->OpaqueClass->current_step, 0,
865 &rect);
866 if (effect_index !=0 )
867 {
868 effectAPI.setEffectXData(_this->SF_CGdEffect, effect_index, EFFECT_SPELL_ID,
869 spell->spell_id);
870 }
871 toolboxAPI.addSpellToFigure(_this->SF_CGdFigureToolBox, figure_index, spell_index);
872 }
873 }
874 }
875 spell->to_do_count = (spell_data.params[2] * 10) / 1000;
876 return;
877 }
878 if (existing_clones != 0)
879 {
880 uint16_t current_mana = figureAPI.getCurrentStat(_this->SF_CGdFigure, source_index, MANA);
881 if (current_mana < spell_data.params[3])
882 {
883 for (int i = 1; i < _this->SF_CGdFigure->max_used; i++)
884 {
885 GdFigure *figure = &_this->SF_CGdFigure->figures[i];
886 if (((figure->flags & ILLUSION) != 0) &&
887 (toolboxAPI.hasSpellOnIt(_this->SF_CGdFigureToolBox, i, kGdSpellLineSelfIllusion)) &&
888 (figure->master_figure == source_index))
889 {
890
891
892 SF_CGdTargetData target;
893 target.entity_index = i;
894 target.entity_type = 1;
895 target.position = {0,0};
896
897 SF_Rectangle rect = {0,0};
898 uint32_t unused;
899 spellAPI.addVisualEffect(_this, spell_index, kGdEffectSpellHitTarget, &unused,
900 &target, _this->OpaqueClass->current_step, 0, &rect);
901 toolboxAPI.dealDamage(_this->SF_CGdFigureToolBox, source_index, i, 0x7FFF, 1, 0, 0);
902 }
903
904 }
905 }
906 else
907 {
908 figureAPI.subMana(_this->SF_CGdFigure, source_index, spell_data.params[3]);
909 spell->to_do_count = (spell_data.params[2] * 10) / 1000;
910 return;
911 }
912 }
913 }
914 spellAPI.setEffectDone(_this, spell_index, 0);
915}
916
917typedef struct
918{
919 uint16_t figure_id;
920 uint32_t missing_hp;
922
923void __thiscall effect_ability_benefactions(SF_CGdSpell *_this, uint16_t spell_index)
924{
925 SF_GdSpell *spell = &_this->active_spell_list[spell_index];
926 uint16_t target_index = spell->target.entity_index;
927 if ((spell->target.entity_type == 1) && (target_index != 0))
928 {
929 SF_CGdResourceSpell spell_data;
930 spellAPI.getResourceSpellData(_this->SF_CGdResource, &spell_data, spell->spell_id);
931 uint16_t heal = spell_data.params[0];
932 uint16_t unit_count = spell_data.params[1];
933 uint16_t radius = spell_data.params[2];
934
935 if (!toolboxAPI.hasSpellOnIt(_this->SF_CGdFigureToolBox, target_index, kGdSpellLineRemediless))
936 {
937 uint16_t current_hp = figureAPI.getCurrentStat(_this->SF_CGdFigure, target_index, HEALTH);
938 uint16_t max_hp = figureAPI.getMaxStat(_this->SF_CGdFigure, target_index, HEALTH);
939
940 if (current_hp <= max_hp)
941 {
942 int16_t heal_amount = (heal * max_hp) / 100;
943 if (max_hp - current_hp < heal_amount)
944 {
945 heal_amount = max_hp - current_hp;
946 }
947 SF_CGdTargetData target_data;
948 target_data.entity_index = target_index;
949 target_data.entity_type = 1;
950 target_data.position = {0, 0};
951 SF_Rectangle rect = {0,0};
952 uint32_t unused;
953 spellAPI.addVisualEffect(_this, spell_index, kGdEffectSpellHitTarget, &unused, &target_data,
954 _this->OpaqueClass->current_step, 10, &rect);
955 figureAPI.subHealth(_this->SF_CGdFigure, target_index, -heal_amount);
956 }
957 }
958
960 iteratorAPI.figureIteratorInit(&iter, 0, 0, 0x3ff,0x3ff );
961 iteratorAPI.figureIteratorSetPointers(&iter, _this->SF_CGdFigure, _this->SF_CGdTile, _this->SF_CGdWorld);
962
963 iteratorAPI.iteratorSetArea(&iter, &_this->SF_CGdFigure->figures[target_index].position, radius);
964
965 std::vector<healing_entry> healing_targets;
966 uint16_t next_figure = iteratorAPI.getNextFigure(&iter);
967 while (next_figure != 0)
968 {
969 if ((figureAPI.isAlive(_this->SF_CGdFigure, next_figure)) &&
970 (toolboxAPI.figuresCheckFriendly(_this->SF_CGdFigureToolBox, target_index, next_figure)))
971 {
972 uint16_t current_hp = figureAPI.getCurrentStat(_this->SF_CGdFigure, next_figure, HEALTH);
973 uint16_t max_hp = figureAPI.getMaxStat(_this->SF_CGdFigure, next_figure, HEALTH);
974 if (current_hp < max_hp)
975 {
976 healing_entry entry = {next_figure, max_hp - current_hp};
977 healing_targets.push_back(entry);
978 }
979 }
980 next_figure = iteratorAPI.getNextFigure(&iter);
981 }
982 std::sort(healing_targets.begin(), healing_targets.end(), [](const healing_entry& a, const healing_entry& b)
983 {
984 return a.missing_hp > b.missing_hp;
985 });
986 iteratorAPI.disposeFigureIterator(&iter);
987 for (uint32_t i = 0; i < healing_targets.size(); i++)
988 {
989 if (i > unit_count)
990 {
991 break;
992 }
993 if (toolboxAPI.hasSpellOnIt(_this->SF_CGdFigureToolBox, healing_targets[i].figure_id,
995 {
996 continue;
997 }
998 uint16_t current_hp = figureAPI.getCurrentStat(_this->SF_CGdFigure, healing_targets[i].figure_id, HEALTH);
999 uint16_t max_hp = figureAPI.getMaxStat(_this->SF_CGdFigure, healing_targets[i].figure_id, HEALTH);
1000
1001 uint16_t heal_amount = (heal * max_hp) / 100;
1002 if (max_hp - current_hp < heal_amount)
1003 {
1004 heal_amount = max_hp - current_hp;
1005 }
1006
1007 SF_CGdTargetData target_data;
1008 target_data.entity_index = healing_targets[i].figure_id;
1009 target_data.entity_type = 1;
1010 target_data.position = {0, 0};
1011 SF_Rectangle rect = {0,0};
1012 uint32_t unused;
1013 spellAPI.addVisualEffect(_this, spell_index, kGdEffectSpellHitTarget, &unused, &target_data,
1014 _this->OpaqueClass->current_step, 10, &rect);
1015 figureAPI.subHealth(_this->SF_CGdFigure, healing_targets[i].figure_id, -heal_amount);
1016 }
1017 }
1018 spellAPI.setEffectDone(_this, spell_index, 0);
1019}
1020
1021//hotfix for firebane
1022//TODO: fix some stuff about hasSpellOnIt
1023void __thiscall effect_fire_resistance (SF_CGdSpell *_this, uint16_t spell_index)
1024{
1025 SF_GdSpell *spell = &_this->active_spell_list[spell_index];
1026 SF_CGdResourceSpell spell_data;
1027 spellAPI.getResourceSpellData(_this->SF_CGdResource, &spell_data, spell->spell_id);
1028 uint16_t source_index = spell->source.entity_index;
1029 if (spell->target.entity_type == 5)
1030 {
1031 uint32_t tick = spellAPI.getXData(_this, spell_index, SPELL_TICK_COUNT_AUX);
1032
1033 if (tick == 0)
1034 {
1035 _this->active_spell_list[spell_index].to_do_count = (spell_data.params[1] * 10) / 1000;
1036 spellAPI.addToXData(_this, spell_index, SPELL_TICK_COUNT_AUX, 1);
1037 int16_t multiplier = spell_data.params[0];
1038 (multiplier >= 127) ? (multiplier = 127) : (multiplier);
1039 for (int i = 1; i <= _this->SF_CGdFigure->max_used; i++)
1040 {
1041 if ((_this->SF_CGdFigure->figures[i].owner != (uint16_t)(-1)) &&
1042 (_this->SF_CGdFigure->figures[i].owner == _this->SF_CGdFigure->figures[source_index].owner) &&
1043 ((*(uint8_t *)(&_this->SF_CGdFigure->figures[i].flags) & 0xa) == 0))
1044 {
1045 SF_CGdTargetData target_data;
1046 target_data.entity_index = i;
1047 target_data.entity_type = 1;
1048 target_data.position = {0,0};
1049 SF_Rectangle rect = {0,0};
1050 figureAPI.addBonusMultToStatistic(_this->SF_CGdFigure, RESISTANCE_FIRE, i, multiplier);
1051 spellAPI.addVisualEffect(_this, spell_index, kGdEffectSpellHitTarget, 0, &target_data,
1052 _this->OpaqueClass->current_step,
1053 0x14, &rect);
1054 }
1055 }
1056 return;
1057 }
1058 else
1059 {
1060 int16_t multiplier = spell_data.params[0];
1061 (multiplier >= 127) ? (multiplier = 127) : (multiplier);
1062 for (int i = 1; i <= _this->SF_CGdFigure->max_used; i++)
1063 {
1064 if ((_this->SF_CGdFigure->figures[i].owner != (uint16_t)(-1)) &&
1065 (_this->SF_CGdFigure->figures[i].owner == _this->SF_CGdFigure->figures[source_index].owner) &&
1066 ((*(uint8_t *)(&_this->SF_CGdFigure->figures[i].flags) & 0xa) == 0))
1067 {
1068 figureAPI.addBonusMultToStatistic(_this->SF_CGdFigure, RESISTANCE_FIRE, i, -multiplier);
1069 }
1070 }
1071 }
1072 }
1073 spellAPI.setEffectDone(_this, spell_index, 0);
1074 return;
1075
1076}
1077
1078void __thiscall effect_pain_area (SF_CGdSpell *_this, uint16_t spell_index)
1079{
1080 SF_GdSpell *spell = &_this->active_spell_list[spell_index];
1081 uint16_t source_index = spell->source.entity_index;
1082 if (spell->target.entity_type == 5)
1083 {
1084 SF_CGdResourceSpell spell_data;
1085 spellAPI.getResourceSpellData(_this->SF_CGdResource, &spell_data, spell->spell_id);
1086 uint16_t damage = spell_data.params[0];
1087 uint16_t total_area = spell_data.params[1];
1088 uint16_t area = spellAPI.addToXData(_this, spell_index, SPELL_TICK_COUNT_AUX, 1);
1089 if (area == 1)
1090 {
1091 SF_Rectangle area_rect;
1092 uint32_t unused;
1093 SF_CGdTargetData target_data;
1094 target_data.entity_index = 0;
1095 target_data.entity_type = 5;
1096 target_data.position = spell->target.position;
1097 spellAPI.getTargetsRectangle(_this, &area_rect, spell_index, total_area, &spell->target.position);
1098 spellAPI.addVisualEffect(_this, spell_index, kGdEffectSpellHitTarget, &unused,
1099 &target_data, _this->OpaqueClass->current_step, 0x19, &area_rect);
1100 }
1101 if (area <= total_area)
1102 {
1103 spell->to_do_count = 1;
1104
1105 CGdFigureIterator iter;
1106 iteratorAPI.setupFigureIterator(&iter, _this);
1107 iteratorAPI.iteratorSetArea(&iter,&spell->target.position, area);
1108 std::vector<uint16_t> targets;
1109 std::vector<uint16_t> old_targets;
1110 std::vector<uint16_t> final_targets;
1111 uint16_t target_index = iteratorAPI.getNextFigure(&iter);
1112 while (target_index != 0)
1113 {
1114 targets.push_back(target_index);
1115 target_index = iteratorAPI.getNextFigure(&iter);
1116 }
1117 iteratorAPI.disposeFigureIterator(&iter);
1118 std::sort(targets.begin(), targets.end());
1119 if (area > 1)
1120 {
1121 CGdFigureIterator iter;
1122 iteratorAPI.setupFigureIterator(&iter, _this);
1123 iteratorAPI.iteratorSetArea(&iter,&spell->target.position, area-1);
1124 uint16_t target_index = iteratorAPI.getNextFigure(&iter);
1125 while (target_index != 0)
1126 {
1127 old_targets.push_back(target_index);
1128 target_index = iteratorAPI.getNextFigure(&iter);
1129 }
1130 iteratorAPI.disposeFigureIterator(&iter);
1131 std::sort(old_targets.begin(), old_targets.end());
1132 }
1133 if (!old_targets.empty())
1134 {
1135 for (uint32_t i = 0; i < targets.size(); i++)
1136 {
1137 if (!std::binary_search(old_targets.begin(), old_targets.end(),targets[i]))
1138 {
1139 final_targets.push_back(targets[i]);
1140 }
1141 }
1142 }
1143 else
1144 {
1145 for (uint32_t i = 0; i < targets.size(); i++)
1146 {
1147 final_targets.push_back(targets[i]);
1148 }
1149 }
1150 for (uint32_t i = 0; i < final_targets.size(); i++)
1151 {
1152 if (((_this->SF_CGdFigure->figures[final_targets[i]].flags & (IS_DEAD | RESESRVED_ONLY)) == 0) &&
1153 (_this->SF_CGdFigure->figures[final_targets[i]].owner != (uint16_t)(-1)) &&
1154 (toolboxAPI.figuresCheckHostile(_this->SF_CGdFigureToolBox, source_index, final_targets[i])) &&
1155 (toolboxAPI.isTargetable(_this->SF_CGdFigureToolBox, final_targets[i])))
1156 {
1157 uint32_t chance = spellAPI.getChanceToResistSpell(_this->AutoClass34, source_index,
1158 final_targets[i], spell->spell_id);
1159 uint32_t random = spellAPI.getRandom(_this->OpaqueClass, 100);
1160 if (chance < random)
1161 {
1162 uint32_t unused;
1163 SF_CGdTargetData target_data;
1164 target_data.entity_index = final_targets[i];
1165 target_data.entity_type = 1;
1166 target_data.position = {0, 0};
1167 SF_Rectangle rect = {0, 0};
1168 spellAPI.addVisualEffect(_this, spell_index, kGdEffectSpellHitTarget, &unused,
1169 &target_data, _this->OpaqueClass->current_step, 0x19, &rect);
1170
1171 if (((_this->SF_CGdFigure->figures[source_index].flags & (IS_DEAD | RESESRVED_ONLY)) == 0) &&
1172 (_this->SF_CGdFigure->figures[source_index].owner != (uint16_t)(-1)) &&
1173 (_this->SF_CGdFigure->figures[source_index].set_type == 8))
1174 {
1175 uint32_t random = spellAPI.getRandom(_this->OpaqueClass, 100);
1176 if (random < 26)
1177 {
1178 damage *=2;
1179 }
1180 }
1181 toolboxAPI.dealDamage(_this->SF_CGdFigureToolBox, source_index, final_targets[i], damage,1,0,0);
1182 }
1183 else
1184 {
1185 uint32_t unused;
1186 SF_CGdTargetData target_data;
1187 target_data.entity_index = final_targets[i];
1188 target_data.entity_type = 1;
1189 target_data.position = {0, 0};
1190 SF_Rectangle rect = {0, 0};
1191 spellAPI.addVisualEffect(_this, spell_index, kGdEffectSpellTargetResisted, &unused,
1192 &target_data, _this->OpaqueClass->current_step, 0x19, &rect);
1193
1194 spellAPI.figureAggro(_this, spell_index, final_targets[i]);
1195 }
1196 }
1197 }
1198 return;
1199 }
1200 }
1201 spellAPI.setEffectDone(_this, spell_index, 0);
1202 return;
1203}
1204
1205void __thiscall effect_detect_metal(SF_CGdSpell *_this, uint16_t spell_index)
1206{
1207 SF_GdSpell *spell = &_this->active_spell_list[spell_index];
1208 uint16_t source_index = spell->source.entity_index;
1209 GdFigure *source_figure = &_this->SF_CGdFigure->figures[source_index];
1210 if (spell->target.entity_type == 1)
1211 {
1212 SF_CGdResourceSpell spell_data;
1213 spellAPI.getResourceSpellData(_this->SF_CGdResource, &spell_data, spell->spell_id);
1214 SF_Rectangle t_rect;
1215 SF_Coord center = {0,0};
1216 spellAPI.getTargetsRectangle(_this, &t_rect, spell_index, spell_data.params[0], &center);
1217 SF_CGdTargetData target_data;
1218 target_data.entity_type = 4;
1219 target_data.entity_index = 0;
1220 target_data.position = source_figure->position;
1221 spellAPI.addVisualEffect(_this, spell_index, kGdEffectSpellHitTarget, &t_rect, &target_data,
1222 _this->OpaqueClass->current_step, 20, &t_rect);
1223 CGdObjectIterator iter;
1224 iteratorAPI.objectIteratorInit(&iter, 0, 0, 0x3ff, 0x3ff);
1225 iteratorAPI.objectIteratorSetPointers(&iter, _this->SF_CGdObject, _this->SF_CGdTile, _this->SF_CGdWorld);
1226 iteratorAPI.iteratorSetArea((CGdFigureIterator *)&iter, &source_figure->position, spell_data.params[0]);
1227 for (uint16_t i = iteratorAPI.getNextObject(&iter); i != 0; i = iteratorAPI.getNextObject(&iter))
1228 {
1229 uint16_t data_id = _this->SF_CGdObject->objects[i].object_data_id;
1230 uint16_t out_type = 0;
1231 if ((uint16_t)(data_id - 1536) < 128)
1232 {
1233 out_type = 41;
1234 }
1235 else
1236 {
1237 if ((uint16_t)(data_id - 1664) < 128)
1238 {
1239 out_type = 42;
1240 }
1241 }
1242 if (out_type != 0)
1243 {
1244 uint16_t pos_x = _this->SF_CGdObject->objects[i].pos.X;
1245 uint16_t pos_y = _this->SF_CGdObject->objects[i].pos.Y;
1246 uint16_t owner = source_figure->owner;
1247 toolboxAPI.doMapOutCry(_this->AC30, out_type, owner, 4, 0, pos_x, pos_y);
1248 }
1249 }
1250 iteratorAPI.disposeFigureIterator((CGdFigureIterator *)&iter);
1251 }
1252 spellAPI.setEffectDone(_this, spell_index, 0);
1253}
1254
1255void __thiscall effect_assistance(SF_CGdSpell *_this, uint16_t spell_index)
1256{
1257 SF_GdSpell *spell = &_this->active_spell_list[spell_index];
1258 uint16_t target_index = spell->target.entity_index;
1259 GdFigure *target_figure = &_this->SF_CGdFigure->figures[target_index];
1260
1261 if (spell->target.entity_type == 1)
1262 {
1263 uint32_t tick = spellAPI.addToXData(_this, spell_index, SPELL_TICK_COUNT_AUX, 1);
1264 bool canApply = spellAPI.checkCanApply(_this, spell_index);
1265 if ((tick == 1) && (canApply))
1266 {
1267 SF_CGdResourceSpell spell_data;
1268 spellAPI.getResourceSpellData(_this->SF_CGdResource, &spell_data, spell->spell_id);
1269 if (((target_figure->flags & (IS_DEAD | RESESRVED_ONLY)) == 0) &&
1270 (target_figure->owner != (uint16_t)(-1)))
1271 {
1272 target_figure->flags |= F_CHECK_SPELLS_BEFORE_JOB;
1273 uint32_t tick_count = (spell_data.params[2] * 10) / 1000;
1274 spell->to_do_count = tick_count;
1276 uint32_t unused;
1277 SF_CGdTargetData target;
1278 target.entity_index = target_index;
1279 target.entity_type = 1;
1280 target.position = {0,0};
1281
1282 SF_Rectangle rect = {0,0};
1283 spellAPI.addVisualEffect(_this, spell_index, kGdEffectSpellHitTarget, &unused, &target,
1284 _this->OpaqueClass->current_step,tick_count, &rect);
1285 return;
1286 }
1287 }
1288 spellAPI.figTryClrCHkSPlBfrJob2(_this, spell_index);
1289 }
1290 spellAPI.setEffectDone(_this, spell_index, 0);
1291 return;
1292}
1293
1301{
1303
1304 effect_ability_benefactions_handler = &effect_ability_benefactions;// (handler_ptr)(ASI::AddrOf(0x32c090));
1317 effect_ability_warcry_handler = &effect_ability_warcry;// (handler_ptr)(ASI::AddrOf(0x32df90));
1326 effect_assistance_handler = &effect_assistance; //(handler_ptr)(ASI::AddrOf(0x32fbc0));
1327 //effect_aura_handler = (handler_ptr)(ASI::AddrOf(0x32fd40));
1328 effect_aura_handler = &effect_aura; // hotfix lives here
1342 effect_conservation_handler = &effect_conservation;// (handler_ptr)(ASI::AddrOf(0x333130));
1353 effect_detect_metal_handler = effect_detect_metal;//(handler_ptr)(ASI::AddrOf(0x334cb0));
1424 effect_pain_area_handler = &effect_pain_area; //(handler_ptr)(ASI::AddrOf(0x341af0));
1445 effect_self_illusion_handler = &effect_self_illusion;// (handler_ptr)(ASI::AddrOf(0x3463c0));
1470}
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
IteratorFunctions iteratorAPI
Definition sf_hooks.c:49
BuildingFunctions buildingAPI
Definition sf_hooks.c:47
AiFunctions aiAPI
Definition sf_hooks.c:51
int AddrOf(int offset)
returns "real" virtual address of given memory offset
Definition sf_asi.h:135
@ kGdEffectSpellHitTarget
@ kGdEffectSpellTargetResisted
@ kGdEffectAuraResolve
@ RESISTANCE_FIRE
@ EFFECT_ENTITY_TYPE2
@ EFFECT_SPELL_ID
@ EFFECT_ENTITY_INDEX2
@ EFFECT_SUBSPELL_ID
@ SPELL_CONSERVATION_SHIELD
@ EFFECT_ENTITY_TYPE
@ SPELL_TICK_COUNT_AUX
@ EFFECT_ADD_SUBSPELL
@ EFFECT_ENTITY_INDEX
@ EFFECT_PHYSICAL_DAMAGE
@ EFFECT_SPELL_INDEX
@ EFFECT_EFFECT_INDEX
@ kGdSpellLineAuraRegeneration
@ kGdSpellLineAuraHealing
@ kGdSpellLineRemediless
@ kGdSpellLineAbilityWarCry
@ kGdSpellLineSelfIllusion
@ CHECK_SPELLS_BEFORE_JOB2
@ CHECK_SPELLS_BEFORE_CHECK_BATTLE
@ F_CHECK_SPELLS_BEFORE_JOB
@ F_CHECK_SPELLS_BEFORE_CHECK_BATTLE
handler_ptr effect_enlightement_handler
void __thiscall effect_conservation(SF_CGdSpell *_this, uint16_t spell_index)
handler_ptr effect_decay2_handler
handler_ptr effect_ability_critical_hits_handler
handler_ptr effect_dispel_black_aura_handler
handler_ptr effect_shockwave_handler
handler_ptr effect_freeze_area_handler
handler_ptr effect_sentinel_healing_handler
handler_ptr effect_fire_resistance_handler
handler_ptr effect_endurance_handler
handler_ptr effect_ability_endurance_handler
void __thiscall effect_aura(SF_CGdSpell *_this, uint16_t spell_index)
handler_ptr effect_healing_area_handler
handler_ptr effect_confuse_handler
handler_ptr effect_cannibalize_handler
handler_ptr effect_sacrifice_mana_handler
handler_ptr effect_almightiness_black_handler
handler_ptr effect_aura_handler
handler_ptr effect_self_illusion_handler
handler_ptr effect_healing_handler
handler_ptr effect_chill_resistance_handler
handler_ptr effect_invisibility_handler
handler_ptr effect_confuse_area_handler
handler_ptr effect_death_handler
handler_ptr effect_feet_of_clay_handler
handler_ptr effect_icestrike2_handler
handler_ptr effect_torture_handler
handler_ptr effect_suffocation_handler
handler_ptr effect_remove_curse_handler
handler_ptr effect_thornshield_handler
handler_ptr effect_quickness_area_handler
handler_ptr effect_befriend_handler
handler_ptr effect_fireshield1_handler
handler_ptr effect_essence_mental_handler
handler_ptr effect_strength_area_handler
handler_ptr effect_shock_handler
handler_ptr effect_iceshield_handler
handler_ptr effect_roots_area_handler
handler_ptr effect_illuminate_handler
handler_ptr effect_eternity_handler
handler_ptr effect_thorns_handler
handler_ptr effect_almightiness_white_handler
handler_ptr effect_chain_handler
handler_ptr effect_invulnerability_handler
handler_ptr effect_firebullet_handler
handler_ptr effect_tower_pain_handler
void __thiscall effect_pain_area(SF_CGdSpell *_this, uint16_t spell_index)
handler_ptr effect_feedback_handler
handler_ptr effect_guard_handler
handler_ptr effect_hallow_handler
handler_ptr effect_summon_handler
handler_ptr effect_roots_handler
handler_ptr effect_ability_trueshot_handler
handler_ptr effect_hypnotize_handler
handler_ptr effect_amok_handler
handler_ptr effect_quickness_handler
handler_ptr effect_fireball1_handler
handler_ptr effect_pestilence_handler
handler_ptr effect_manadrain_handler
handler_ptr effect_slowness_area_handler
handler_ptr effect_detect_magic_handler
handler_ptr effect_poison_handler
handler_ptr effect_weaken_handler
handler_ptr effect_ability_salvo_handler
handler_ptr effect_decay_handler
handler_ptr effect_tower_arrow_handler
handler_ptr effect_essence_black_handler
handler_ptr effect_tower_extinct_handler
handler_ptr effect_manashield_handler
handler_ptr effect_inflexibility_handler
handler_ptr effect_cure_disease_handler
void __thiscall getWeaponStats(SF_CGdFigure *_this, uint16_t figure_id, uint8_t slot, SF_CGdFigureWeaponStats *stats)
handler_ptr effect_ability_durability_handler
handler_ptr effect_icestrike1_handler
void __thiscall effect_ability_benefactions(SF_CGdSpell *_this, uint16_t spell_index)
handler_ptr effect_extinct_handler
handler_ptr effect_detect_metal_handler
handler_ptr effect_essence_white_handler
handler_ptr effect_almightiness_elemental2_handler
handler_ptr effect_ability_riposte_handler
handler_ptr effect_dominate_handler
handler_ptr effect_remediless_handler
handler_ptr effect_mutation_handler
handler_ptr effect_siege_aura_handler
handler_ptr effect_manatap_aura_handler
handler_ptr effect_strength_handler
handler_ptr effect_almightiness_elemental_handler
handler_ptr effect_freeze_handler
handler_ptr effect_holy_touch_handler
void __thiscall effect_detect_metal(SF_CGdSpell *_this, uint16_t spell_index)
handler_ptr effect_essence_elemental2_handler
handler_ptr effect_blizzard_handler
handler_ptr effect_wave_handler
void __thiscall apply_aura_effect(SF_CGdSpell *_this, uint16_t spell_index, uint16_t sub_spell_index, uint16_t source_index, uint16_t target_index)
handler_ptr effect_slow_fighting_handler
handler_ptr effect_fog_handler
handler_ptr effect_manatap_handler
handler_ptr effect_ability_shelter_handler
handler_ptr effect_cloak_of_nor_handler
handler_ptr effect_lifetap_aura_handler
handler_ptr effect_darkness_area_handler
void __thiscall effect_siege_aura(SF_CGdSpell *_this, uint16_t spell_index)
handler_ptr effect_brilliance_handler
handler_ptr effect_conservation_handler
handler_ptr effect_spark_handler
handler_ptr effect_slowness_handler
handler_ptr effect_inability_handler
handler_ptr effect_ability_benefactions_handler
handler_ptr effect_pain_area_handler
void __thiscall effect_fire_resistance(SF_CGdSpell *_this, uint16_t spell_index)
void __thiscall effect_ability_warcry(SF_CGdSpell *_this, uint16_t spell_index)
handler_ptr effect_essence_elemental_handler
handler_ptr effect_dominate_break_handler
handler_ptr effect_lifetap_handler
handler_ptr effect_dominate_undead_handler
handler_ptr effect_suicide_heal_handler
handler_ptr effect_tower_stone_handler
handler_ptr effect_charisma_handler
handler_ptr effect_disenchant_handler
handler_ptr effect_charm_animal_handler
handler_ptr effect_dark_banishing_handler
handler_ptr effect_assistance_handler
handler_ptr effect_inflexibility_area_handler
handler_ptr effect_rain_of_stone_handler
void initialize_vanilla_effect_handler_hooks()
handler_ptr effect_iceshield3_handler
handler_ptr effect_distract_handler
handler_ptr effect_revenge_handler
handler_ptr effect_iceshield2_handler
handler_ptr effect_ice2_handler
handler_ptr effect_cure_poison_handler
handler_ptr effect_ability_patronize_handler
handler_ptr effect_retention_handler
handler_ptr effect_dominate_animal_handler
handler_ptr effect_suicide_death_handler
handler_ptr effect_plague_area_handler
handler_ptr effect_forget_handler
handler_ptr effect_acid_cloud_handler
handler_ptr effect_death_grasp_handler
handler_ptr effect_fake_spell_one_figure_handler
handler_ptr effect_ability_boons_handler
handler_ptr effect_stone_handler
handler_ptr effect_flexibility_area_handler
handler_ptr effect_unknown1_handler
handler_ptr effect_raise_dead_handler
handler_ptr effect_rock_bullet_handler
handler_ptr effect_fireball2_handler
handler_ptr effect_ability_shift_life_handler
handler_ptr effect_flexibility_handler
handler_ptr effect_ability_warcry_handler
handler_ptr effect_fireburst_handler
handler_ptr effect_almightiness_mental_handler
handler_ptr effect_ice1_handler
handler_ptr effect_unknown2_handler
handler_ptr effect_demoralization_handler
uint16_t(__thiscall * reserveFigure_ptr)(SF_CGdFigureToolbox *_this, uint16_t x, uint16_t y, uint16_t owner, CGdResourceUnitStats *stats, CGdFigureTask task, uint16_t param6)
handler_ptr effect_charm_handler
void __thiscall effect_self_illusion(SF_CGdSpell *_this, uint16_t spell_index)
handler_ptr effect_weaken_area_handler
handler_ptr effect_meditation_handler
handler_ptr effect_pain_handler
handler_ptr effect_dispel_white_aura_handler
handler_ptr effect_shift_mana_handler
handler_ptr effect_ability_berserk_handler
void __thiscall setWeaponStats(SF_CGdFigure *_this, uint16_t figure_id, uint8_t slot, SF_CGdFigureWeaponStats *stats)
handler_ptr effect_reinforcement_handler
handler_ptr effect_petrify_handler
handler_ptr effect_hypnotize_area_handler
handler_ptr effect_disrupt_handler
handler_ptr effect_regenerate_handler
handler_ptr effect_fireshield2_handler
reserveFigure_ptr reserveFigure
handler_ptr effect_fast_fighting_handler
void __thiscall effect_assistance(SF_CGdSpell *_this, uint16_t spell_index)
handler_ptr effect_rain_of_fire_handler
handler_ptr effect_melt_resistance_handler
handler_ptr effect_dexterity_handler
handler_ptr effect_mirage_handler
handler_ptr effect_feign_death_handler
handler_ptr effect_healing_aura_handler
handler_ptr effect_ability_steelskin_handler
void(__thiscall * handler_ptr)(SF_CGdSpell *, uint16_t)
Definition sfsf.h:30
Group of functions related to AI manipulation.
GdFigureAbility abilities[10]
Group of functions related to Effect manipulation.
Group of functions to manipulate the behavior and statistics of the game figures (units).
FigureStatisticExt stamina
uint16_t equipment[16]
FigureStatistic strength
uint16_t master_figure
SF_CGdFigureWeaponStats weapon_stats[2]
FigureStatistic dexterity
FigureStatistic resistance_mental
FigureStatistic charisma
FigureStatistic resistance_fire
FigureStatistic cast_speed
FigureStatisticExt health
FigureStatistic wisdom
FigureStatistic fight_speed
FigureStatistic resistance_ice
FigureStatistic agility
FigureStatistic resistance_black
FigureStatistic walk_speed
FigureStatistic armor
FigureStatistic intelligence
Group of functions related to Iteration, Often used for AOE or Chain Like Spells.
GdBuilding buildings[1000]
A structure for the global list of figures and related statistics for them.
GdFigure figures[2000]
GdObject objects[16384]
SF_CGdFigureJobs * SF_CGdFigureJobs
SF_CGdFigure * SF_CGdFigure
SF_CGdWorldToolBox * SF_CGdWorldToolBox
SF_CGdWorld * SF_CGdWorld
AutoClass14 * OpaqueClass
SF_CGdObject * SF_CGdObject
SF_CGdFigureToolbox * SF_CGdFigureToolBox
SF_CGdBuilding * CGdBuilding
SF_GdSpell active_spell_list[800]
SF_CGdEffect * SF_CGdEffect
SF_CGdBuildingToolbox * SF_CGdBuildingToolbox
SF_world_unkn_1 unknown1[10001]
SF_world_unkn_2 cells[1048576]
SF_CGdTargetData source
SF_CGdTargetData target
Represents a collection of function pointers for managing spell-related operations.
Holds most of the Toolbox Functions relevent for custom spells. Includes functions for the manipulati...
uint16_t figure_id
uint32_t missing_hp