Spellforce-Spell-framework
Loading...
Searching...
No Matches
sf_worker_logic_hook.c
Go to the documentation of this file.
2#include "../sf_hooks.h"
3#include "sf_endspell_hook.h"
4#include "../sf_wrappers.h"
5
12extern AiFunctions aiAPI;
14
15void terminate_job_spells(SF_CGdFigureJobs *_this, uint16_t figure_id)
16{
17 uint16_t spell_index = toolboxAPI.getSpellIndexOfType(_this->CGdFigureToolBox, figure_id,
19 if (spell_index == 0)
20 {
21 spell_index = toolboxAPI.getSpellIndexOfType(_this->CGdFigureToolBox, figure_id,
23 }
24 if (spell_index != 0)
25 {
26 sf_endspell_hook(_this->CGdSpell, spell_index);
27 }
28}
29
30//TODO - use registry instead of hardcode
31static uint8_t getRacialSmallHQ(uint8_t race)
32{
33 uint8_t result = 0;
34 switch (race)
35 {
36 case 1:
37 result = 2;
38 break;
39 case 2:
40 result = 41;
41 break;
42 case 3:
43 result = 20;
44 break;
45 case 4:
46 result = 73;
47 break;
48 case 5:
49 result = 58;
50 break;
51 case 6:
52 result = 85;
53 break;
54 default:
55 break;
56 }
57 return result;
58}
59//NOTE SF_Coord here is used as two uint16_t
60typedef void (__thiscall *startWalkingTo_ptr)(SF_CGdFigureJobs *_this, uint16_t figure_id, SF_CGdTargetData *target,
61 SF_Coord *ranges, uint8_t walk_mode, uint32_t param5);
62typedef uint32_t *(__thiscall *getObjectQueue_ptr)(void *CGdObject, uint16_t object_index);
63typedef void (__thiscall *addToObjectQueue_ptr)(uint32_t *_this, uint16_t figure_index);
64
65typedef void (__thiscall *doArtisanAnimation_ptr)(SF_CGdFigureJobs *_this, uint16_t figure_id);
66typedef uint32_t (__thiscall *addResource_ptr)(SF_CGdPlayer *_this, uint16_t player_id, bool isLight,
67 uint8_t resource_type,
68 uint32_t amount);
69
70typedef void (__thiscall *AC65_FUN_0074caf0_ptr)(void *autoclass65, uint16_t owner, uint16_t resource, uint16_t amount);
71typedef void (__thiscall *AC30_FUN_006c3880_ptr)(void *autoclass30, uint16_t figure_id, uint8_t resource,
72 uint16_t amount);
73typedef uint32_t *(*getGlobalAC65_ptr)(void);
74
75
76
85
86
101static void setupWalkToMonument(SF_CGdFigureJobs *_this, uint16_t figure_id, uint16_t monument_id)
102{
103 SF_Coord ranges = {1,1};
104 SF_CGdTargetData t_data;
105 t_data.entity_index = monument_id;
106 t_data.entity_type = 3;
107 t_data.position = {0,0};
108 toolboxAPI.setFigureXData(_this->CGdFigureToolBox, figure_id, EFFECT_ENTITY_INDEX2, monument_id);
109 startWalkingTo(_this, figure_id, &t_data, &ranges, 0, 1);
110 uint32_t *unknown_list = getObjectQueue(_this->CGdObject, monument_id);
111 addToObjectQueue(unknown_list, figure_id);
112}
113
114bool __thiscall onWoodcutterFinishJob(SF_CGdFigureJobs *_this, uint16_t figure_id)
115{
116 uint16_t job_id = _this->CGdFigure->figures[figure_id].current_job.GdJobId;
117 uint8_t figure_task = _this->CGdFigure->figures[figure_id].current_job.task;
118 uint8_t target_building_type = 0;
119 uint16_t target_building = 0;
120 uint32_t target_job = kGdJobWoodCutterWalkHome;
121 if (figure_task == CGdFigureTask::TASK_WORKER)
122 {
123 uint8_t race = _this->CGdFigure->figures[figure_id].race;
124 target_building_type = getRacialSmallHQ(race);
125 if (target_building_type != 0)
126 {
127 target_building = buildingAPI.findClosestBuilding(_this->CGdBuildingToolBox,
128 _this->CGdFigure->figures[figure_id].position,
129 target_building_type,
130 _this->CGdFigure->figures[figure_id].owner, 0x19);
131 }
132 }
133 else
134 {
135 uint8_t race = _this->CGdFigure->figures[figure_id].race;
136 target_building_type = buildingAPI.getRacialSawmill(race);
137 if (target_building_type != 0)
138 {
139 uint16_t building_index = _this->CGdFigure->figures[figure_id].building;
140 //NO, there's no invariant here!
141 target_building = buildingAPI.findClosestBuilding(_this->CGdBuildingToolBox,
142 _this->CGdBuilding->buildings[building_index].position,
143 target_building_type,
144 _this->CGdFigure->figures[figure_id].owner, 0x19);
145 }
146 }
147 if (target_building != 0)
148 {
150 }
151 else
152 {
153 if (figure_task == CGdFigureTask::TASK_WORKER)
154 {
155 uint16_t monument_id, unused;
156 monument_id = toolboxAPI.findClosestMonument(_this->CGdObjectToolBox, figure_id, &unused);
157 if (monument_id == 0)
158 {
159 figureAPI.setJob(_this, figure_id, job_id);
160 return false;
161 }
162 figureAPI.prepareJobTransition(_this, figure_id, job_id, target_job);
163 terminate_job_spells(_this, figure_id);
164 figureAPI.onStartJob(_this, figure_id, target_job);
165 setupWalkToMonument(_this, figure_id, monument_id);
166 return true;
167 }
168 else
169 {
170 target_building = _this->CGdFigure->figures[figure_id].building;
171 }
172 }
173 figureAPI.prepareJobTransition(_this, figure_id, job_id, target_job);
174 terminate_job_spells(_this, figure_id);
175 figureAPI.onStartJob(_this, figure_id, target_job);
176 if (target_job == kGdJobWoodCutterWalkToDeliverGood)
177 {
178 buildingAPI.addFigureToBuilding(_this->CGdBuildingToolBox, target_building, figure_id, 0);
179 }
180 toolboxAPI.setFigureXData(_this->CGdFigureToolBox, figure_id, WORKER_DELIVERY_BUILDING, target_building);
181 toolboxAPI.setFigureXData(_this->CGdFigureToolBox, figure_id, EFFECT_ENTITY_INDEX2, 0);
182 SF_Coord walk_pos = _this->CGdBuilding->buildings[target_building].position;
183 figureAPI.setFigureWalkPos(_this, figure_id, &walk_pos, 0, 1);
184
185 return true;
186}
187
188bool __thiscall onMinerFinishJob(SF_CGdFigureJobs *_this, uint16_t figure_id)
189{
190 uint16_t job_id = _this->CGdFigure->figures[figure_id].current_job.GdJobId;
191 uint8_t figure_task = _this->CGdFigure->figures[figure_id].current_job.task;
192 uint8_t target_building_type = 0;
193 uint16_t target_building = 0;
194 uint32_t target_job = kGdJobMinerWalkHome;
195 if (figure_task == CGdFigureTask::TASK_WORKER)
196 {
197 uint8_t race = _this->CGdFigure->figures[figure_id].race;
198 target_building_type = getRacialSmallHQ(race);
199 if (target_building_type != 0)
200 {
201 target_building = buildingAPI.findClosestBuilding(_this->CGdBuildingToolBox,
202 _this->CGdFigure->figures[figure_id].position,
203 target_building_type,
204 _this->CGdFigure->figures[figure_id].owner, 0x19);
205 }
206 }
207 else
208 {
209 uint8_t race = _this->CGdFigure->figures[figure_id].race;
210 uint16_t building_index = _this->CGdFigure->figures[figure_id].building;
211 if (buildingAPI.buildingIsMoonsilverMine(_this->CGdBuilding, building_index))
212 {
213 target_building = 0;
214 }
215 else
216 {
217 target_building_type = buildingAPI.getRacialSmelter(race);
218 if (target_building_type != 0)
219 {
220 SF_Coord pos;
221 pos.X = toolboxAPI.getFigureXData(_this->CGdFigureToolBox, figure_id, WORKER_HOST_BUILDING_POS_X);
222 pos.Y = toolboxAPI.getFigureXData(_this->CGdFigureToolBox, figure_id, WORKER_HOST_BUILDING_POS_Y);
223
224 //NO, there's no invariant here!
225 target_building = buildingAPI.findClosestBuilding(_this->CGdBuildingToolBox,
226 pos, target_building_type,
227 _this->CGdFigure->figures[figure_id].owner, 0x19);
228 }
229 }
230 }
231 if (target_building != 0)
232 {
233 target_job = kGdJobMinerWalkToDeliverGood;
234 }
235 else
236 {
237 if (figure_task == CGdFigureTask::TASK_WORKER)
238 {
239 uint16_t monument_id, unused;
240 monument_id = toolboxAPI.findClosestMonument(_this->CGdObjectToolBox, figure_id, &unused);
241 if (monument_id == 0)
242 {
243 figureAPI.setJob(_this, figure_id, job_id);
244 return false;
245 }
246 figureAPI.prepareJobTransition(_this, figure_id, job_id, target_job);
247 terminate_job_spells(_this, figure_id);
248 figureAPI.onStartJob(_this, figure_id, target_job);
249 setupWalkToMonument(_this, figure_id, monument_id);
250 return true;
251 }
252 else
253 {
254 target_building = _this->CGdFigure->figures[figure_id].building;
255 }
256 }
257 figureAPI.prepareJobTransition(_this, figure_id, job_id, target_job);
258 terminate_job_spells(_this, figure_id);
259 figureAPI.onStartJob(_this, figure_id, target_job);
260 if (target_job == kGdJobMinerWalkToDeliverGood)
261 {
262 buildingAPI.addFigureToBuilding(_this->CGdBuildingToolBox, target_building, figure_id, 0);
263 }
264 toolboxAPI.setFigureXData(_this->CGdFigureToolBox, figure_id, WORKER_DELIVERY_BUILDING, target_building);
265 toolboxAPI.setFigureXData(_this->CGdFigureToolBox, figure_id, EFFECT_ENTITY_INDEX2, 0);
266 SF_Coord walk_pos = _this->CGdBuilding->buildings[target_building].position;
267 figureAPI.setFigureWalkPos(_this, figure_id, &walk_pos, 0, 1);
268
269 return true;
270}
271
272bool __thiscall onStoneMinerFinishJob(SF_CGdFigureJobs *_this, uint16_t figure_id)
273{
274 uint16_t job_id = _this->CGdFigure->figures[figure_id].current_job.GdJobId;
275 uint8_t figure_task = _this->CGdFigure->figures[figure_id].current_job.task;
276 uint8_t target_building_type = 0;
277 uint16_t target_building = 0;
278 uint32_t target_job = kGdJobStoneMinerWalkHome;
279 if (figure_task == CGdFigureTask::TASK_WORKER)
280 {
281 uint8_t race = _this->CGdFigure->figures[figure_id].race;
282 target_building_type = getRacialSmallHQ(race);
283 if (target_building_type != 0)
284 {
285 target_building = buildingAPI.findClosestBuilding(_this->CGdBuildingToolBox,
286 _this->CGdFigure->figures[figure_id].position,
287 target_building_type,
288 _this->CGdFigure->figures[figure_id].owner, 0x19);
289 }
290 }
291 else
292 {
293 uint8_t race = _this->CGdFigure->figures[figure_id].race;
294 target_building_type = buildingAPI.getRacialStonecutter(race);
295 if (target_building_type != 0)
296 {
297 uint16_t building_index = _this->CGdFigure->figures[figure_id].building;
298 //NO, there's no invariant here!
299 target_building = buildingAPI.findClosestBuilding(_this->CGdBuildingToolBox,
300 _this->CGdBuilding->buildings[building_index].position,
301 target_building_type,
302 _this->CGdFigure->figures[figure_id].owner, 0x19);
303 }
304 }
305 if (target_building != 0)
306 {
308 }
309 else
310 {
311 if (figure_task == CGdFigureTask::TASK_WORKER)
312 {
313 uint16_t monument_id, unused;
314 monument_id = toolboxAPI.findClosestMonument(_this->CGdObjectToolBox, figure_id, &unused);
315 if (monument_id == 0)
316 {
317 figureAPI.setJob(_this, figure_id, job_id);
318 return false;
319 }
320 figureAPI.prepareJobTransition(_this, figure_id, job_id, target_job);
321 terminate_job_spells(_this, figure_id);
322 figureAPI.onStartJob(_this, figure_id, target_job);
323 setupWalkToMonument(_this, figure_id, monument_id);
324 return true;
325 }
326 else
327 {
328 target_building = _this->CGdFigure->figures[figure_id].building;
329 }
330 }
331 figureAPI.prepareJobTransition(_this, figure_id, job_id, target_job);
332 terminate_job_spells(_this, figure_id);
333 figureAPI.onStartJob(_this, figure_id, target_job);
334 if (target_job == kGdJobStoneMinerWalkToDeliverGood)
335 {
336 buildingAPI.addFigureToBuilding(_this->CGdBuildingToolBox, target_building, figure_id, 0);
337 }
338 toolboxAPI.setFigureXData(_this->CGdFigureToolBox, figure_id, WORKER_DELIVERY_BUILDING, target_building);
339 toolboxAPI.setFigureXData(_this->CGdFigureToolBox, figure_id, EFFECT_ENTITY_INDEX2, 0);
340 SF_Coord walk_pos = _this->CGdBuilding->buildings[target_building].position;
341 figureAPI.setFigureWalkPos(_this, figure_id, &walk_pos, 0, 1);
342
343 return true;
344}
345
346void __thiscall update_owner_resources(SF_CGdFigureJobs *_this, uint16_t owner, uint16_t figure_id,
347 uint8_t resource_type, uint8_t amount)
348{
349 uint32_t *AC65 = getGlobalAC65();
350 AC65_FUN_0074caf0(AC65, owner, 0, amount);
351 AC30_FUN_006c3880(_this->AutoClass30, figure_id, resource_type, amount);
352}
353
354void __thiscall onCarpenterFinishJob(SF_CGdFigureJobs *_this, uint16_t figure_id)
355{
356 uint16_t building_id = _this->CGdFigure->figures[figure_id].building;
357 uint8_t resource_type = 0;
358 if ((_this->CGdBuilding->buildings[building_id].flags >> 1)&1)
359 {
360 int32_t tick_count = toolboxAPI.getFigureXData(_this->CGdFigureToolBox, figure_id, SPELL_TICK_COUNT_AUX);
361 tick_count++;
362 toolboxAPI.setFigureXData(_this->CGdFigureToolBox, figure_id, SPELL_TICK_COUNT, tick_count);
363 if (tick_count == 0)
364 {
365 doArtisanAnimation(_this, figure_id);
366 buildingAPI.setBuildingXData(_this->CGdBuildingToolBox, building_id, BUILDING_ANIM_START,
367 _this->OpaqueClass->current_step);
368 buildingAPI.setBuildingXData(_this->CGdBuildingToolBox, building_id, BUILDING_ANIM_LENGTH,
369 _this->CGdFigure->figures[figure_id].to_do_count);
370 return;
371 }
372
373 uint32_t queue_count = buildingAPI.getBuildingXData(_this->CGdBuildingToolBox, building_id,
375 queue_count--;
376 buildingAPI.setBuildingXData(_this->CGdBuildingToolBox, building_id, BUILDING_QUEUE_COUNT, queue_count);
377
378 if (buildingAPI.buildingIsSawmill(_this->CGdBuilding, building_id))
379 {
380 resource_type = 1;
381 }
382 if (buildingAPI.buildingIsStonecutter(_this->CGdBuilding, building_id))
383 {
384 resource_type = 2;
385 }
386 uint8_t race = _this->CGdFigure->figures[figure_id].race;
387 uint16_t owner = _this->CGdFigure->figures[figure_id].owner;
388 bool side = ((race != 3) && (race != 2) && (race != 1));
389 addResource(_this->CGdPlayer, owner, side, resource_type, 10);
390 update_owner_resources(_this, owner, figure_id, resource_type, 10);
391 }
392 figureAPI.prepareJobTransition(_this, figure_id, _this->CGdFigure->figures[figure_id].current_job.GdJobId,
394 figureAPI.onStartJob(_this, figure_id, kGdJobCarpenterSearchForWork);
395 terminate_job_spells(_this, figure_id);
396 _this->CGdBuilding->buildings[building_id].flags &= (~4);
397}
RegistrationFunctions * registrationAPI
Definition TestMod.cpp:14
SpellFunctions * spellAPI
Definition TestMod.cpp:11
FigureFunctions * figureAPI
Definition TestMod.cpp:13
ToolboxFunctions * toolboxAPI
Definition TestMod.cpp:12
void __thiscall sf_endspell_hook(SF_CGdSpell *_this, uint16_t spell_index)
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
getGlobalAC65_ptr getGlobalAC65
uint32_t *(* getGlobalAC65_ptr)(void)
@ kGdJobMinerWalkHome
@ kGdJobWoodCutterWalkHome
@ kGdJobStoneMinerWalkHome
@ kGdJobWoodCutterWalkToDeliverGood
@ kGdJobCarpenterSearchForWork
@ kGdJobStoneMinerWalkToDeliverGood
@ kGdJobMinerWalkToDeliverGood
@ WORKER_HOST_BUILDING_POS_Y
@ BUILDING_ANIM_START
@ EFFECT_ENTITY_INDEX2
@ BUILDING_QUEUE_COUNT
@ SPELL_TICK_COUNT_AUX
@ SPELL_TICK_COUNT
@ WORKER_HOST_BUILDING_POS_X
@ BUILDING_ANIM_LENGTH
@ WORKER_DELIVERY_BUILDING
@ kGdSpellLineInvisibility
@ kGdSpellLineFeignDeath
getObjectQueue_ptr getObjectQueue
bool __thiscall onWoodcutterFinishJob(SF_CGdFigureJobs *_this, uint16_t figure_id)
getGlobalAC65_ptr getGlobalAC65
bool __thiscall onMinerFinishJob(SF_CGdFigureJobs *_this, uint16_t figure_id)
void __thiscall onCarpenterFinishJob(SF_CGdFigureJobs *_this, uint16_t figure_id)
void terminate_job_spells(SF_CGdFigureJobs *_this, uint16_t figure_id)
void initialize_worker_logic_data_hooks()
void(__thiscall * startWalkingTo_ptr)(SF_CGdFigureJobs *_this, uint16_t figure_id, SF_CGdTargetData *target, SF_Coord *ranges, uint8_t walk_mode, uint32_t param5)
void(__thiscall * AC65_FUN_0074caf0_ptr)(void *autoclass65, uint16_t owner, uint16_t resource, uint16_t amount)
addResource_ptr addResource
AC65_FUN_0074caf0_ptr AC65_FUN_0074caf0
void(__thiscall * doArtisanAnimation_ptr)(SF_CGdFigureJobs *_this, uint16_t figure_id)
doArtisanAnimation_ptr doArtisanAnimation
void(__thiscall * AC30_FUN_006c3880_ptr)(void *autoclass30, uint16_t figure_id, uint8_t resource, uint16_t amount)
bool __thiscall onStoneMinerFinishJob(SF_CGdFigureJobs *_this, uint16_t figure_id)
startWalkingTo_ptr startWalkingTo
addToObjectQueue_ptr addToObjectQueue
void __thiscall update_owner_resources(SF_CGdFigureJobs *_this, uint16_t owner, uint16_t figure_id, uint8_t resource_type, uint8_t amount)
AC30_FUN_006c3880_ptr AC30_FUN_006c3880
uint32_t(__thiscall * addResource_ptr)(SF_CGdPlayer *_this, uint16_t player_id, bool isLight, uint8_t resource_type, uint32_t amount)
void(__thiscall * addToObjectQueue_ptr)(uint32_t *_this, uint16_t figure_index)
uint32_t *(__thiscall * getObjectQueue_ptr)(void *CGdObject, uint16_t object_index)
Group of functions related to AI manipulation.
Group of functions related to Effect manipulation.
Group of functions to manipulate the behavior and statistics of the game figures (units).
uint16_t to_do_count
FigureJobData current_job
Group of functions related to Iteration, Often used for AOE or Chain Like Spells.
A structure dedicated to the registration of spells This structure holds functions that are used to c...
GdBuilding buildings[1000]
GdFigure figures[2000]
SF_CGdBuilding * CGdBuilding
SF_CGdFigureToolbox * CGdFigureToolBox
SF_CGdBuildingToolbox * CGdBuildingToolBox
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...