1 /*
2 * Open Fodder
3 * ---------------
4 *
5 * Copyright (C) 2008-2018 Open Fodder
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 3 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License along
18 * with this program; if not, write to the Free Software Foundation, Inc.,
19 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 */
22
23 #include "stdafx.hpp"
24 #include "Map/Random.hpp"
25
26 #ifdef WIN32
27 #include <windows.h>
28 #endif
29
30 const int32 CAMERA_PAN_TO_START_ACCELARATION = 0x80000; // Dos: Original 0x80000
31 const int32 CAMERA_PAN_TO_SQUAD_ACCELERATION = 0x20000; // Dos: Original 0x20000
32 const int32 CAMERA_TOWARD_SQUAD_SPEED = 0x14; // Dos: Original 0x14
33
34 const int16 MOUSE_POSITION_X_ADJUST = -32;
35 const int16 MOUSE_POSITION_Y_ADJUST = 4;
36
37 const int16 SIDEBAR_WIDTH = 48;
38
39 const int16 mBriefing_Helicopter_Offsets[] =
40 {
41 0x0180, 0x0040, 0x0004, 0x01A0,
42 0x0040, 0x000F, 0x01C0, 0x0040,
43 0x0007, 0x01E0, 0x0020, 0x0007,
44 0x0000, 0x0010, 0x000A, 0x0080,
45 0x0010, 0x001E, 0x0100, 0x0010,
46 0x000A, 0x01A0, 0x0008, 0x0019,
47 0x0170, 0x0064, 0x000A, -1,
48 -1, -1
49 };
50
cFodder(std::shared_ptr<cWindow> pWindow)51 cFodder::cFodder(std::shared_ptr<cWindow> pWindow) {
52
53 mVersions = std::make_shared<cVersions>();
54 mVersionCurrent = 0;
55 mVersionDefault = 0;
56
57 mParams = std::make_shared<sFodderParameters>();
58 mStartParams = std::make_shared<sFodderParameters>();
59
60 mOpenFodder_Intro_Done = false;
61 mCustom_Mode = eCustomMode_None;
62 mGraphics = 0;
63 mSound = 0;
64 mWindow = pWindow;
65
66 mGUI_Select_File_ShownItems = 4;
67 mTicksDiff = 0;
68 mTicks = 0;
69
70 mMouseX = 0;
71 mMouseY = 0;
72 mMouseX_Offset = 0;
73 mMouseY_Offset = 0;
74
75 mIntroDone = false;
76
77 mMouse_EventLastButtonsPressed = 0;
78
79 mMouseButtonStatus = 0;
80 mInputMouseX = 0;
81 mInputMouseY = 0;
82
83 mButtonPressLeft = mButtonPressRight = 0;
84 mMouse_Button_Left_Toggle = 0;
85 mMouse_Button_Right_Toggle = 0;
86 mMouse_Button_LeftRight_Toggle = mSquad_Member_Fire_CoolDown_Override = false;
87 mMouse_Button_LeftRight_Toggle2 = false;
88
89 mMouse_Exit_Loop = false;
90
91 mSprite_Frame_1 = 0;
92 mSprite_Frame_Modifier_Update_Countdown = 0;
93 mSprite_Frame_2 = 0;
94 mSprite_Frame3_ChangeCount = 0;
95 mSprite_Frame_3 = 0;
96
97 mEnemy_BuildingCount = 0;
98 mPhase_Aborted = false;
99 mPhase_EscapeKeyAbort = false;
100
101 mSprite_SpareUsed = 0;
102 mSprite_SpareUsed2 = 0;
103 mSquad_WalkTargetX = 0;
104 mSquad_WalkTargetY = 0;
105 mSprite_Bullet_Destroy = 0;
106 mSprite_Helicopter_DestroyLight = 0;
107 mSprite_DistanceTo_Squad0 = 0;
108 mSprite_Tank_SpriteX = 0;
109 mSprite_Tank_SpriteY = 0;
110 mSprite_Tank_Squad0_X = 0;
111 mSprite_Tank_DistanceTo_Squad0 = 0;
112 mSprite_Missile_LaunchDistance_X = 0;
113 mSprite_Missile_LaunchDistance_Y = 0;
114 mMapTile_ColumnOffset = 0;
115 mMapTile_RowOffset = 0;
116 mGUI_Select_File_String_Input_Callback = 0;
117
118 mMapTile_Ptr = 0;
119
120 mSoundEffectToPlay = 0;
121 mBriefing_Aborted = 0;
122 mGUI_Mouse_Modifier_X = 0;
123 mGUI_Mouse_Modifier_Y = 0;
124 mBriefing_Render_1_Mode = 0;
125
126 mMouseSpriteCurrent = 0;
127 mService_ExitLoop = 0;
128 mVideo_Draw_FrameDataPtr = 0;
129 mVideo_Draw_PosX = 0;
130 mVideo_Draw_PosY = 0;
131 mVideo_Draw_Columns = 0;
132 mVideo_Draw_Rows = 0;
133 mVideo_Draw_PaletteIndex = 0;
134 mDraw_Source_SkipPixelsPerRow = 0;
135 mDraw_Dest_SkipPixelsPerRow = 0;
136 mKeyCode = 0;
137
138 mCameraX = 0;
139 mCameraY = 0;
140
141 mMapTile_TargetX = 0;
142 mMapTile_TargetY = 0;
143 mMapTile_SpeedX = 0;
144 mMapTile_SpeedY = 0;
145
146 mSurfaceMapOverview = 0;
147
148 mMap = 0;
149
150 mVersionPlatformSwitchDisabled = false;
151 mGame_Data.mGamePhase_Data.mIsComplete = false;
152 mSidebar_Draw_Y = 0;
153 word_3A3BF = 0;
154
155 mDebug_PhaseSkip = 0;
156
157 mGame_InputTicks = 0;
158 mKeyControlPressed = 0;
159 mVersionReturnAfterPhase = false;
160
161 mInput_LastKey = 0;
162 mCustom_ExitMenu = 0;
163
164 word_428D8 = 0;
165 word_3A05F = 0;
166 byte_44AC0 = 0;
167 mSoundDisabled = false;
168 Squad_Walk_Target_SetAll(0);
169 mPhase_Completed_Timer = 0;
170 mVideo_Draw_ColumnsMax = 0;
171 word_428B6 = 0;
172 word_428B8 = 0;
173 word_428BA = 0;
174 mHelicopterPosX = 0;
175 mHelicopterPosY = 0;
176 mBriefing_Helicopter_Off1 = 0;
177 mBriefing_Helicopter_Off2 = 0;
178 mBriefing_Helicopter_Off3 = 0;
179 mBriefing_Helicopter_Off4 = 0;
180 mBriefing_ParaHeli_Frame = 0;
181 mBriefing_Helicopter_Moving = 0;
182 mTroop_InRange_Callpad = 0;
183
184 for (unsigned int x = 0; x < 0x18; ++x) {
185 mMission_Save_Blocked[x] = 0;
186 }
187
188 mService_Promotion_Exit_Loop = 0;
189
190 // Field_0, X, Width, Y, Height, mMouseInsideFuncPtr
191 mSidebar_OverlayButtons[0] = {
192 &cFodder::GUI_Button_NoAction,
193 0, // X
194 47, // Width
195 0, // Y
196 225, // Height
197 &cFodder::GUI_Button_NoAction2 };
198
199 mSidebar_OverlayButtons[1] = { 0, 0, 0, 0, 0, 0 };
200
201 mGUI_Handle_Button_SelectSquad_Array[0] = &cFodder::GUI_Handle_Button_SelectSquad_0;
202 mGUI_Handle_Button_SelectSquad_Array[1] = &cFodder::GUI_Handle_Button_SelectSquad_1;
203 mGUI_Handle_Button_SelectSquad_Array[2] = &cFodder::GUI_Handle_Button_SelectSquad_2;
204
205 mDemo_ExitMenu = 0;
206
207 mSurfaceMapTop = 0;
208 mSurfaceMapLeft = 0;
209
210 mSprite_SheetPtr = 0;
211
212 Sprite_Clear_All();
213
214 Phase_EngineReset();
215
216 Sprite_Table_Setup();
217
218 }
219
~cFodder()220 cFodder::~cFodder() {
221
222 delete mSurfaceMapOverview;
223 }
224
Squad_Walk_Target_SetAll(int16 pValue)225 void cFodder::Squad_Walk_Target_SetAll(int16 pValue) {
226
227 for (unsigned int x = 0; x < 10; ++x) {
228
229 for (unsigned int y = 0; y < 30; ++y) {
230
231 mSquad_WalkTargets[x][y].asInt = pValue;
232 mSquad_WalkTargets[x][y].asInt = pValue;
233 mSquad_WalkTargets[x][y].asInt = pValue;
234 mSquad_WalkTargets[x][y].asInt = pValue;
235 mSquad_WalkTargets[x][y].asInt = pValue;
236 mSquad_WalkTargets[x][y].asInt = pValue;
237 mSquad_WalkTargets[x][y].asInt = pValue;
238 mSquad_WalkTargets[x][y].asInt = pValue;
239 mSquad_WalkTargets[x][y].asInt = pValue;
240 mSquad_WalkTargets[x][y].asInt = pValue;
241 }
242 }
243
244 }
245
246 /**
247 * Execute one cycle of the current phase
248 *
249 * -1 = Phase Try Again
250 * 0 = Phase Won
251 * 1 = Phase Running
252 */
Phase_Cycle()253 int16 cFodder::Phase_Cycle() {
254
255 // If demo playback is enabled, and a record resume cycle is set
256 if (mStartParams->mDemoPlayback && mStartParams->mDemoRecordResumeCycle) {
257 // See if we hit the tick count
258 if (mGame_Data.mDemoRecorded.mTick >= mStartParams->mDemoRecordResumeCycle) {
259 // Then resume recording
260 mStartParams->mDemoPlayback = false;
261 mStartParams->mDemoRecord = true;
262 mStartParams->mDemoRecordResumeCycle = 0;
263 mParams->mSleepDelta = 2;
264 mParams->mDemoRecord = mStartParams->mDemoRecord;
265 mParams->mDemoPlayback = mStartParams->mDemoPlayback;
266 mStartParams->mDisableVideo = false;
267 mStartParams->mDisableSound = false;
268 Mouse_Setup();
269 }
270 }
271
272 MapTile_UpdateFromCamera();
273 MapTile_Update_Position();
274
275 Game_Handle();
276 ++mMission_EngineTicks;
277
278 if (mCamera_Start_Adjust) {
279 Camera_SetTargetToStartPosition();
280 mCamera_Start_Adjust = false;
281 return 1;
282 }
283
284 //loc_1074E
285 if (mGUI_Sidebar_Setup >= 0 && !mPhase_TryAgain)
286 GUI_Sidebar_Setup();
287 else {
288 GUI_Sidebar_Draw();
289 }
290
291 //loc_10768
292 Phase_Progress_Check();
293 mHelicopterCallPadPressedCount = 0;
294 if (word_3A9B8 >= 0)
295 --word_3A9B8;
296
297 Sprite_Find_HumanVehicles();
298
299 // Cheat
300 if (mDebug_PhaseSkip == -1) {
301 mDebug_PhaseSkip = 0;
302 mPhase_Complete = true;
303 }
304 else
305 Phase_Goals_Check();
306
307 //loc_1079C
308 Squad_Walk_Steps_Decrease();
309 Squad_Troops_Count();
310
311 Mission_Sprites_Handle();
312 Squad_Switch_Timer();
313 if (!mStartParams->mDisableVideo)
314 mGraphics->Sidebar_Copy_To_Surface();
315
316 // Game Paused
317 if (mPhase_Paused) {
318 Phase_Paused();
319
320 mSurface->Save();
321
322 // Fade the background out, and the 'mission paused' message in
323 mSurface->palette_FadeTowardNew();
324 mSurface->palette_FadeTowardNew();
325 mSurface->palette_FadeTowardNew();
326
327 while (mPhase_Paused) {
328
329 // Update mouse
330 Mouse_Inputs_Get();
331 Mouse_DrawCursor();
332 // Draw surface
333 mSurface->draw();
334
335 // Copy the rendered surface of the 'mission paused' message over the top of the main surface
336 mSurface->mergeSurfaceBuffer(mSurface2);
337
338 mWindow->RenderAt(mSurface);
339 mWindow->FrameEnd();
340 Cycle_End();
341
342 mSurface->Restore();
343 }
344
345 mGraphics->PaletteSet();
346 mSurface->palette_SetFromNew();
347 mSurface->surfaceSetToPalette();
348
349 mPhase_Aborted = false;
350
351 // Redraw the screen
352 mGraphics->MapTiles_Draw();
353 Sprites_Draw();
354 mGraphics->Sidebar_Copy_To_Surface();
355 }
356
357 Mouse_DrawCursor();
358
359 if (mSurface->isPaletteAdjusting())
360 mSurface->palette_FadeTowardNew();
361
362 Camera_Update_Mouse_Position_For_Pan();
363
364 if (mPhase_ShowMapOverview && mSurfaceMapOverview) {
365
366 // Dont show the map while recording
367 if (!mParams->mDemoRecord)
368 Phase_Map_Overview_Show();
369
370 mPhase_ShowMapOverview = 0;
371 }
372
373 if (mGame_Data.mGamePhase_Data.mIsComplete) {
374
375 if (mPhase_Aborted)
376 Sprite_Handle_Player_Destroy_Unk();
377 else {
378 if (!mPhase_TryAgain)
379 return 0;
380
381 Sprite_Handle_Player_DestroyAll();
382 }
383 return -1;
384 }
385
386 //loc_10841
387 Sprite_Bullet_SetData();
388 Squad_EnteredVehicle_TimerTick();
389 Squad_Set_CurrentVehicle();
390
391 // No squad is selected, so set count down timer
392 if (mSquad_Selected < 0 && !mSquad_Select_Timer)
393 mSquad_Select_Timer = 0x14;
394
395 Sprite_HelicopterCallPad_Check();
396 Mission_Final_Timer();
397
398 Video_SurfaceRender();
399 return 1;
400 }
401
Phase_Prepare()402 void cFodder::Phase_Prepare() {
403
404 Map_Load();
405 Map_Load_Sprites();
406 Map_Overview_Prepare();
407
408 // Prepare Squads
409 Phase_Soldiers_Count();
410 mGame_Data.Soldier_Sort();
411 Phase_Soldiers_Prepare(false);
412 Phase_Soldiers_AttachToSprites();
413
414 mPhase_Aborted = false;
415
416 Map_Load();
417 mGraphics->SetActiveSpriteSheet(eGFX_IN_GAME);
418
419 MapTiles_Draw();
420 Camera_Reset();
421
422 Mouse_Inputs_Get();
423 Sprite_Frame_Modifier_Update();
424
425 mSound->Stop();
426 Sprite_Aggression_Set();
427
428 //seg000:05D1
429
430 Phase_Goals_Set();
431
432 Sprite_Bullet_SetData();
433 Sprite_Handle_Loop();
434 Sprite_Create_Rank();
435
436 mCamera_Start_Adjust = true;
437 mCamera_StartPosition_X = mSprites[0].field_0;
438 mCamera_StartPosition_Y = mSprites[0].field_4;
439
440 // Is map 17 x 12
441 {
442 if (mMapLoaded->getWidth() == 17) {
443 if (mMapLoaded->getHeight() == 12)
444 mPhase_MapIs17x12 = -1;
445 }
446 }
447
448 GUI_Element_Reset();
449 mInput_Enabled = true;
450 Camera_Prepare();
451
452 mGUI_Mouse_Modifier_X = 0;
453 mGUI_Mouse_Modifier_Y = 4;
454 mCamera_Start_Adjust = true;
455
456 Squad_Prepare_GrenadesAndRockets();
457
458 mGraphics->PaletteSet();
459
460 GUI_Sidebar_Prepare_Squads();
461 Squad_Select_Grenades();
462 mMap_Destroy_Tiles.clear();
463 Sprite_Count_HelicopterCallPads();
464 Mission_Set_Final_TimeRemaining();
465
466 mMouseSpriteNew = eSprite_pStuff_Mouse_Cursor;
467
468 mPhase_Aborted = false;
469 mPhase_Paused = false;
470 mPhase_In_Progress = true;
471 mPhase_EscapeKeyAbort = false;
472
473 mPhase_Finished = false;
474 mPhase_ShowMapOverview = 0;
475
476 Window_UpdateScreenSize();
477
478 mSurface->Save();
479 }
480
Phase_Loop()481 int16 cFodder::Phase_Loop() {
482 int16 result = 1;
483
484 // -1 = Phase Try Again
485 // 0 = Phase Won
486 // 1 = Phase Running
487 for (result = 1; result == 1; result = Phase_Cycle()) {
488
489 Cycle_End();
490 }
491
492 return result;
493 }
494
Game_Handle()495 void cFodder::Game_Handle() {
496
497 // Input disabled or Mission not paused?
498 if (!mInput_Enabled || !mPhase_Paused) {
499
500 ++mGame_InputTicks;
501
502 Mouse_Inputs_Get();
503
504 if (mInput_Enabled) {
505 Camera_Handle();
506 Camera_Handle();
507 Camera_Handle();
508
509 if (!mPhase_Finished)
510 Mouse_Inputs_Check();
511 }
512 }
513
514 //loc_108AE
515 if (mSquad_SwitchWeapon) {
516 --mSquad_SwitchWeapon;
517 Squad_Switch_Weapon();
518 }
519
520 if (mMouseCursor_Enabled)
521 Mouse_DrawCursor();
522
523 if (!mInput_Enabled)
524 return;
525
526 if (!mPhase_In_Progress)
527 return;
528
529 if (mPhase_Completed_Timer || mPhase_Complete || mPhase_TryAgain || mPhase_Aborted) {
530 mPhase_Finished = true;
531 return;
532 }
533
534 if (!mSoundEffectToPlay)
535 return;
536
537 Sound_Play(mSquad_Leader, mSoundEffectToPlay, 0);
538 mSoundEffectToPlay = 0;
539 }
540
Camera_Handle()541 void cFodder::Camera_Handle() {
542
543 if (mPhase_In_Progress) {
544 Camera_Speed_Reset();
545 Camera_Speed_MaxSet();
546 Camera_Speed_Calculate();
547 Camera_TileSpeedX_Set();
548 Camera_Speed_Update_From_PanTarget();
549 Camera_PanTarget_AdjustToward_SquadLeader();
550 Camera_Acceleration_Set();
551 }
552 }
553
Camera_PanTarget_AdjustToward_SquadLeader()554 void cFodder::Camera_PanTarget_AdjustToward_SquadLeader() {
555 if (mSquad_Leader == INVALID_SPRITE_PTR || mSquad_Leader == 0)
556 return;
557
558 int16 SquadLeaderX = mSquad_Leader->field_0 + 0x18;
559 int16 SquadLeaderY = mSquad_Leader->field_4;
560 int16 Data18 = SquadLeaderX;
561 int16 Data1C = SquadLeaderY;
562
563
564 mCamera_Scroll_Speed = CAMERA_TOWARD_SQUAD_SPEED;
565
566 // Mouse near sidebar?
567 if (mMouseX <= 0x0F) {
568
569 if (mCamera_Panning_ToTarget) {
570
571 if ((SquadLeaderX - mCamera_SquadLeaderX) > 0 ||
572 (SquadLeaderY - mCamera_SquadLeaderY) > 0) {
573 mCamera_PanTargetX = SquadLeaderX;
574 mCamera_PanTargetY = SquadLeaderY;
575 }
576
577 // Original Logic
578 //mCamera_PanTargetX += (SquadLeaderX - mCamera_SquadLeaderX);
579 //mCamera_PanTargetY += (SquadLeaderY - mCamera_SquadLeaderY);
580
581 mCamera_SquadLeaderX = SquadLeaderX;
582 mCamera_SquadLeaderY = SquadLeaderY;
583 } else {
584 //loc_10A11
585 mCamera_Panning_ToTarget = true;
586
587 mCamera_PanTargetX = (mCameraX >> 16) + (getCameraWidth() / 2) - 8;
588 mCamera_PanTargetY = (mCameraY >> 16) + (getCameraHeight() - 8) / 2;
589 }
590 //loc_10A3A
591 mMouse_Locked = false;
592 return;
593 }
594
595 mCamera_Panning_ToTarget = false;
596 mCamera_SquadLeaderX = SquadLeaderX;
597 mCamera_SquadLeaderY = SquadLeaderY;
598 int16 Data0 = mMouseX + (mCameraX >> 16);
599 int16 Data4 = mMouseY + (mCameraY >> 16);
600
601 int16 Data0_Saved = Data0;
602 int16 Data4_Saved = Data4;
603 int16 Data8_Saved = SquadLeaderX;
604 int16 DataC_Saved = SquadLeaderY;
605
606 Map_Get_Distance_BetweenPoints_Within_Window(Data0, Data4, SquadLeaderX, SquadLeaderY);
607
608 if (mSquad_CurrentVehicle) {
609 if (Data0 >= 0x64)
610 Data0 = 0x64;
611 } else {
612 if (Data0 >= 0x8C)
613 Data0 = 0x8C;
614 }
615 //loc_10AAA
616 int16 word_3ABFD = Data0;
617
618 SquadLeaderX = Data8_Saved;
619 SquadLeaderY = DataC_Saved;
620 Data4 = Data4_Saved; // MouseY
621 Data0 = Data0_Saved; // MouseX
622
623 if (Direction_Between_Points(Data0, Data4, SquadLeaderX, SquadLeaderY) < 0)
624 return;
625
626 int32 DirectionX = mMap_Direction_Calculations[Data4 / 2];
627 Data4 += 0x80;
628 Data4 &= 0X1FE;
629
630 int32 DirectionY = mMap_Direction_Calculations[Data4 / 2];
631
632 DirectionX = (DirectionX * word_3ABFD) >> 16;
633 DirectionY = (DirectionY * word_3ABFD) >> 16;
634
635 Data18 += DirectionX;
636 Data1C += DirectionY;
637 Data18 -= 0x18;
638
639 if (Data18 < 0)
640 Data18 = 0;
641
642 mCamera_PanTargetX = Data18;
643 mCamera_PanTargetY = Data1C;
644 mMouse_Locked = false;
645 }
646
GameData_Reset()647 void cFodder::GameData_Reset() {
648 mDebug_PhaseSkip = 0;
649 mInput_Enabled = false;
650 mGame_InputTicks = 0;
651 mMission_EngineTicks = 0;
652 mRecruit_Mission_Restarting = false;
653
654 for (unsigned int x = 0; x < 9; ++x) {
655 mMission_Troops_SpritePtrs[x] = 0;
656 }
657
658 mPhase_TryingAgain = false;
659 mGame_Data.Clear();
660 mGame_Data.mGamePhase_Data.Clear();
661 }
662
GameData_Backup()663 void cFodder::GameData_Backup() {
664 mGame_Data_Backup = mGame_Data;
665 }
666
GameData_Restore()667 void cFodder::GameData_Restore() {
668 mGame_Data = mGame_Data_Backup;
669
670 // Reset grave pointers
671 mGame_Data.mGamePhase_Data.mHeroesCount = mGame_Data.mHeroes.size();
672 }
673
Phase_EngineReset()674 void cFodder::Phase_EngineReset() {
675 // Clear memory 2454 to 3B58
676 mPhase_EscapeKeyAbort = false;
677 mPhase_Aborted2 = false;
678 mButtonPressLeft = 0;
679 mButtonPressRight = 0;
680 mMouse_Button_Left_Toggle = 0;
681 mMouse_Button_Right_Toggle = 0;
682 mMouse_Button_LeftRight_Toggle = false;
683 mMouse_Button_LeftRight_Toggle2 = false;
684
685 mVehicle_Input_Disabled = false;
686 mMouse_Exit_Loop = false;
687 mSquad_Member_Fire_CoolDown_Override = false;
688
689 mCameraX = 0;
690 mCameraY = 0;
691 dword_39F36 = 0;
692 mCamera_Scroll_Speed = 0;
693 mCamera_SquadLeaderX = 0;
694 mCamera_SquadLeaderY = 0;
695 mCamera_Panning_ToTarget = false;
696
697 mCamera_Speed_X = 0;
698 mCamera_Speed_Y = 0;
699 mCamera_AccelerationX = 0;
700
701 mCamera_AccelerationY = 0;
702 mCamera_Speed_Reset_X = 0;
703 mCamera_Speed_Reset_Y = 0;
704 mCamera_TileSpeed_Overflow = 0;
705 mCamera_TileX = 0;
706 mCamera_TileY = 0;
707 mCamera_TileSpeedX = 0;
708 mCamera_TileSpeedY = 0;
709
710 mKeyCodeAscii = 0;
711 mMapTile_TargetX = 0;
712 mMapTile_TargetY = 0;
713 mMapTile_SpeedX = 0;
714 mMapTile_SpeedY = 0;
715
716 mMapTile_MoveDirectionX_Previous = 0;
717 mMapTile_MoveDirectionY_Previous = 0;
718 mMapTile_DrawX = 0;
719 mMapTile_DrawY = 0;
720 mMapTile_SpeedX_Previous = 0;
721 mMapTile_SpeedY_Previous = 0;
722 mMapTile_MovedHorizontal = 0;
723 mMapTile_MovedVertical = 0;
724 mMapTile_ColumnOffset = 0;
725 mMapTile_RowOffset = 0;
726
727 mSquad_Leader = 0;
728 mMapTile_MoveDirectionX = 0;
729 mMapTile_MoveDirectionY = 0;
730 mCamera_MoveDirectionX = 0;
731 mCamera_MoveDirectionY = 0;
732 mCamera_MovePauseX = 0;
733 mCamera_MovePauseY = 0;
734 mSquad_Selected = 0;
735 mSquad_JoiningTo = 0;
736
737 mSprite_Frame_1 = 0;
738 mSprite_Frame_Modifier_Update_Countdown = 0;
739 mSprite_Frame_2 = 0;
740 mSprite_Frame3_ChangeCount = 0;
741 mSprite_Frame_3 = 0;
742
743 mTroop_Weapon_Grenade_Disabled = false;
744 mTroop_Weapon_Bullet_Disabled = false;
745 mTroop_Weapon_Rocket_Disabled = false;
746 mSidebar_SmallMode = 0;
747 dword_3A030 = 0;
748 mCamera_PanTargetX = 0;
749 mCamera_PanTargetY = 0;
750 mCamera_StartPosition_X = 0;
751
752 mStoredSpriteX = 0;
753 mStoredSpriteY = 0;
754 mTmp_FrameNumber = 0;
755
756 mGame_Data.mGamePhase_Data.mIsComplete = false;
757 mSidebar_Draw_Y = 0;
758 word_3A3BF = 0;
759 mDirectionMod = 0;
760 mPhase_Aborted = false;
761 mPhase_Aborted2 = false;
762 mSquad_SwitchWeapon = 0;
763 word_3A9B8 = 0;
764 for (uint8 x = 0; x < 3; ++x) {
765 mSquad_Walk_Target_Indexes[x] = 0;
766 mSquad_Walk_Target_Steps[x] = 0;
767 }
768
769 mSprite_Bumped_Into_SquadMember = 0;
770 mSprite_Player_CheckWeapon = 0;
771 mPhase_Paused = false;
772 for (uint8 x = 0; x < 4; ++x) {
773 mSprite_Projectile_Counters[x] = 0;
774 mSprite_Missile_Projectile_Counters[x] = 0;
775 }
776
777 mMouseX_Offset = 0;
778 mMouseY_Offset = 0;
779 mMouseSpriteNew = 0;
780
781 mCamera_Speed_Max = 0;
782
783 mMouseSetToCursor = 0;
784 mSprites_Found_Count = 0;
785
786 for (uint16 x = 0; x < 3; ++x) {
787 mSquad_Grenades[x] = 0;
788 mSquad_Rockets[x] = 0;
789 mGUI_Squad_Icon[x] = 0;
790 }
791
792 mTroops_Enemy_Count = 0;
793 mHostage_Count = 0;
794 mEnemy_BuildingCount = 0;
795
796 mCamera_Start_Adjust = false;
797 word_3AA1D = 0;
798 mCamera_Reached_Target = 0;
799 word_3AA21 = 0;
800 mSprite_FaceWeaponTarget = 0;
801 word_3AA45 = 0;
802 mSquad_Select_Timer = 0;
803 mSprite_Find_Distance = 0;
804 mMouseCursor_Enabled = 0;
805 mRecruit_Sidebar_Draw_Y_Start = 0;
806 mRecruit_Render_Name_SmallGap = 0;
807 mRecruit_Truck_Frame = 0;
808 mRecruit_Truck_FrameAnimBufferPtr = 0;
809 mRecruit_Screen_Active = false;
810
811 word_3ABB1 = 0;
812 mSquad_Member_Fire_CoolDown = 0;
813 mTroop_Rotate_Next = 0;
814 mPhase_MapIs17x12 = 0;
815 mSprite_Weapon_Data.mSpeed = 0;
816 mSprite_Weapon_Data.mAliveTime = 0;
817 mSprite_Weapon_Data.mCooldown = 0;
818 mSprite_Weapon_Data.mDeviatePotential = 0;
819 mSprite_Weapon_Data.field_8 = 0;
820
821 mSprite_Reached_Target = 0;
822 mStoredSpriteFrame = 0;
823 mSprite_Bullet_Time_Modifier = 0;
824 mSprite_Bullet_Fire_Speed_Modifier = 0;
825 mSquad_Member_Clicked_TroopInSameSquad = 0;
826 mSquad_Member_Clicked_TroopPtr = 0;
827
828 mString_GapCharID = 0;
829 mGUI_Loop_Squad_Current = 0;
830 mGUI_Loop_Draw_Y = 0;
831 word_3AC2D[0] = 0;
832 word_3AC2D[1] = 0;
833 word_3AC2D[2] = 0;
834
835 mGUI_Print_String_To_Sidebar = 0;
836 mGUI_Squad_NextDraw_Y = 0;
837 mGUI_Sidebar_Setup = 0;
838 mGUI_RefreshSquadGrenades[0] = 0;
839 mGUI_RefreshSquadGrenades[1] = 0;
840 mGUI_RefreshSquadGrenades[2] = 0;
841 mGUI_RefreshSquadRockets[0] = 0;
842 mGUI_RefreshSquadRockets[1] = 0;
843 mGUI_RefreshSquadRockets[2] = 0;
844
845 mSquad_CurrentWeapon[0] = eWeapon_None;
846 mSquad_CurrentWeapon[1] = eWeapon_None;
847 mSquad_CurrentWeapon[2] = eWeapon_None;
848
849 mMouseDisabled = 0;
850 mGUI_Loop_Is_CurrentSquad = 0;
851
852 word_3AC4B = 0;
853 word_3AC4D = 0;
854 word_3AC51 = 0;
855
856 mMap_Destroy_Tile_LastTile = 0;
857 mMap_Destroy_Tile_X = 0;
858 mMap_Destroy_Tile_Y = 0;
859
860 mMap_Destroy_Tiles.clear();
861
862 mMap_Destroy_Tiles_Countdown = 0;
863
864 for (uint16 x = 0; x < 42; ++x) {
865 mGUI_Elements[x].field_0 = 0;
866 mGUI_Elements[x].mX = 0;
867 mGUI_Elements[x].mWidth = 0;
868 mGUI_Elements[x].mY = 0;
869 mGUI_Elements[x].mHeight = 0;
870 mGUI_Elements[x].mMouseInsideFuncPtr = 0;
871 }
872
873 mGUI_NextFreeElement = 0;
874 mGUI_TroopName_DrawOffset = 0;
875
876 mSprite_SpareUsed = 0;
877 mSquad_WalkTargetX = 0;
878 mSquad_WalkTargetY = 0;
879 mSprite_Bullet_Destroy = 0;
880 mSprite_Helicopter_DestroyLight = 0;
881 mSprite_Bullet_Deviate_Counter = 0;
882 dword_3B1CB = 0;
883
884 for (uint16 x = 0; x < 0x0F; ++x)
885 mRecruit_Hill_Positions_Use[x] = 0;
886
887 mRecruit_Truck_Animation_Play = 0;
888 mRecruit_Truck_Troops_ToEnter_Count = 0;
889
890 mSquad_CurrentVehicle = 0;
891 mPhase_In_Progress = false;
892 mSprite_HumanVehicles_Found = false;
893 mSprites_HumanVehicles.clear();
894 dword_3B24B = 0;
895
896 for (uint16 x = 0; x < 3; ++x) {
897 mSquad_CurrentVehicles[x] = 0;
898 }
899
900 word_3B25B = 0;
901 word_3B25D = 0;
902 mGUI_SaveLoadAction = 0;
903 word_3B2CF = 0;
904 for (uint16 x = 0; x < 6; ++x)
905 word_3B2D1[x] = 0;
906
907 mSprite_Find_Types[0] = 0;
908 mSprite_Find_Types[1] = 0;
909 mSprite_Find_Types[2] = 0;
910 mSprite_Find_Types[3] = 0;
911 mSprite_Find_Types[4] = 0;
912 word_3B2ED = 0;
913 mSpawnSpriteType = 0;
914 word_3B2F1 = 0;
915 word_3B2F3 = 0;
916 mSprite_Field10_Saved = 0;
917 word_3B2F7 = 0;
918 mRecruit_Button_Load_Pressed = 0;
919 mRecruit_Button_Save_Pressed = 0;
920
921 mGUI_Temp_X = 0;
922 mGUI_Temp_Width = 0;
923 mGUI_Temp_Y = 0;
924 mGUI_Draw_LastHeight = 0;
925 mInput.clear();
926 mGUI_Select_File_CurrentIndex = 0;
927 mGUI_Select_File_Count = 0;
928 mGUI_Select_File_SelectedFileIndex = 0;
929 mIntro_PlayTextDuration = 0;
930 mSoundEffectToPlay_Set = 0;
931
932 for (uint16 x = 0; x < 3; ++x)
933 mSquad_EnteredVehicleTimer[x] = 0;
934
935 mSprite_OpenCloseDoor_Ptr = 0;
936 mSprite_Civilian_GotHome = 0;
937 mSwitchesActivated = false;
938 mSprite_Civilian_Tmp_X = 0;
939 mSprite_Civilian_Tmp_Y = 0;
940 word_3B481 = 0;
941 word_3B483 = 0;
942 mHelicopterCallPadCount = 0;
943 mHelicopterCallPadPressedCount = 0;
944
945 for (uint16 x = 0; x < 16; ++x) {
946 mSprite_TroopsAlive[x] = 0;
947 }
948 mHelicopterCall_X = 0;
949 mHelicopterCall_Y = 0;
950 mMission_Final_TimeToDie_Ticker = 0;
951 mMission_Final_TimeRemain = 0;
952 mMission_Final_TimeToAbort = 0;
953 mGUI_Sidebar_MapButton_Prepared = 0;
954 mPhase_ShowMapOverview = 0;
955
956 mTurretFires_HomingMissile = 0;
957 word_3B4ED[0] = 0;
958 word_3B4ED[1] = 0;
959 mPhase_Finished = false;
960 mImage_Aborted = 0;
961 mBriefing_Aborted = 0;
962 mHostage_Rescue_Tent = 0;
963
964 mSprite_Missile_LaunchDistance_X = 0;
965 mSprite_Missile_LaunchDistance_Y = 0;
966 mKeyControlPressed = 0;
967
968 mVideo_Draw_PosX = 0;
969 mVideo_Draw_PosY = 0;
970
971 mMapTile_Column_CurrentScreen = 0;
972 mMapTile_Row_CurrentScreen = 0;
973
974 mTroop_InRange_Callpad = 0;
975 }
976
Phase_SquadPrepare()977 void cFodder::Phase_SquadPrepare() {
978 mSquad_Grenade_SplitMode = eSquad_Weapon_Split_Half;
979 mSquad_Rocket_SplitMode = eSquad_Weapon_Split_Half;
980 mGUI_Sidebar_TroopList_Name_BreakOnSpace = 5;
981 // -1
982 mSquads[0] = mSquad_0_Sprites;
983 mSquads[1] = mSquad_1_Sprites;
984 mSquads[2] = mSquad_2_Sprites;
985 mSquads[3] = mSquad_3_Sprites;
986 mSquads[4] = mSquad_4_Sprites;
987
988 for (unsigned int x = 0; x < 9; ++x)
989 mSquad_0_Sprites[x] = INVALID_SPRITE_PTR;
990
991 for (unsigned int x = 0; x < 9; ++x)
992 mSquad_1_Sprites[x] = INVALID_SPRITE_PTR;
993
994 for (unsigned int x = 0; x < 9; ++x)
995 mSquad_2_Sprites[x] = INVALID_SPRITE_PTR;
996
997 for (unsigned int x = 0; x < 9; ++x)
998 mSquad_3_Sprites[x] = INVALID_SPRITE_PTR;
999
1000 for (unsigned int x = 0; x < 9; ++x)
1001 mSquad_4_Sprites[x] = INVALID_SPRITE_PTR;
1002
1003 mSprite_Frame1_Modifier = 1;
1004 mSprite_Frame2_Modifier = 1;
1005 mSprite_Frame_3_Modifier = 1;
1006 mGUI_Mouse_Modifier_X = 0x1A;
1007 mGUI_Mouse_Modifier_Y = 0x12;
1008
1009 word_3BED5[0] = 2;
1010 word_3BED5[1] = 2;
1011 word_3BED5[2] = 2;
1012 word_3BED5[3] = 2;
1013 word_3BED5[4] = 2;
1014
1015 mSquad_Join_TargetSquad[0] = -1;
1016 mSquad_Join_TargetSquad[1] = -1;
1017 mSquad_Join_TargetSquad[2] = -1;
1018
1019 mSquad_Join_TargetSprite[0] = 0;
1020 mSquad_Join_TargetSprite[1] = 0;
1021 mSquad_Join_TargetSprite[2] = 0;
1022 mSquad_Join_TargetSprite[3] = 0;
1023 mSquad_Join_TargetSprite[4] = 0;
1024 mSquad_Join_TargetSprite[5] = 0;
1025
1026 mMouse_Locked = false;
1027
1028 mSquad_Selected = 0;
1029 mPhase_TryAgain = false;
1030 mPhase_Complete = false;
1031 mPhase_Completed_Timer = 0;
1032
1033 mMouseSpriteNew = eSprite_pStuff_Mouse_Cursor;
1034
1035 mSquads_TroopCount[0] = 0;
1036 mSquads_TroopCount[1] = 0;
1037 mSquads_TroopCount[2] = 0;
1038 mSquads_TroopCount[3] = 0;
1039
1040 mCheckPattern_Position.mX = 0;
1041 mCheckPattern_Position.mY = 0;
1042
1043 mCamera_StartPosition_X = 0;
1044 mCamera_StartPosition_Y = 0;
1045
1046 Squad_Walk_Target_SetAll(-1);
1047 }
1048
Squad_Set_Squad_Leader()1049 void cFodder::Squad_Set_Squad_Leader() {
1050
1051 mSquad_Leader = &mSprites[0];
1052 }
1053
Sprite_Clear_All()1054 void cFodder::Sprite_Clear_All() {
1055 mSprites.resize(mParams->mSpritesMax);
1056 Squad_Set_Squad_Leader();
1057
1058 for (auto& Sprite : mSprites) {
1059 Sprite.Clear();
1060 }
1061 mSprite_Spare.Clear();
1062
1063 mSprites[mSprites.size() - 1].field_0 = -1;
1064 mSprite_SpareUsed = 0;
1065 }
1066
Tile_FindType(eTerrainFeature pType)1067 int16 cFodder::Tile_FindType(eTerrainFeature pType) {
1068
1069 for (int16 TileID = 0; TileID < sizeof(mTile_Hit) / sizeof(int16); ++TileID) {
1070
1071 int16 TerrainType = mTile_Hit[TileID];
1072
1073 // Single Type Tile
1074 if (TerrainType >= 0) {
1075
1076 // Match?
1077 if ((TerrainType & 0x0F) == pType) {
1078
1079 return TileID;
1080 }
1081 }
1082 else {
1083
1084 if (TerrainType < 0) {
1085 //loc_2A8D9
1086 // X
1087 /*pData10 >>= 1;
1088 pData10 &= 0x07;
1089
1090 int16 TilePixel = 7;
1091 TilePixel -= pData10;
1092
1093 // Y
1094 pData14 >>= 1;
1095 pData14 &= 0x07;
1096
1097 int8 RowTerrainType = mTile_BHit[TileID][pData14];
1098
1099 // If the bit for this X position is set, we use the UpperBits for the terrain type
1100 if (RowTerrainType & (1 << TilePixel))
1101 TerrainType >>= 4;*/
1102 }
1103 }
1104 }
1105
1106 return -1;
1107 }
1108
Tile_FindType(const eTerrainFeature pType,const eTerrainFeature pType2)1109 std::vector<int16> cFodder::Tile_FindType(const eTerrainFeature pType, const eTerrainFeature pType2) {
1110 std::vector<int16> Results;
1111
1112 for (int16 TileID = 0; TileID < sizeof(mTile_Hit) / sizeof(int16); ++TileID) {
1113
1114 int16 TerrainType = mTile_Hit[TileID];
1115
1116 // Second Type?
1117 if (TerrainType < 0) {
1118 auto Type1 = (TerrainType & 0x0F);
1119 auto Type2 = (TerrainType >> 4) & 0x0F;
1120
1121 if ((Type1 == pType && Type2 == pType2) || (Type1 == pType2 || Type2 == pType)) {
1122
1123 Results.push_back(TileID);
1124 }
1125
1126 }
1127 }
1128
1129 return Results;
1130 }
1131
Map_Add_Structure(const sStructure & pStructure,int16 pTileX,int16 pTileY)1132 void cFodder::Map_Add_Structure(const sStructure& pStructure, int16 pTileX, int16 pTileY) {
1133
1134 for (const auto& Piece : pStructure.mTiles) {
1135
1136 MapTile_Set(pTileX + Piece.mX, pTileY + Piece.mY, Piece.mTileID);
1137 }
1138
1139 // Add the sprites
1140 for (const auto& Sprite : pStructure.mSprites) {
1141
1142 auto Sheet = Sprite_Get_Sheet(Sprite.mSpriteID, 0);
1143
1144 // - 0x40 because no sidebar
1145 Sprite_Add(Sprite.mSpriteID, ((pTileX) * 16) + (Sprite.mX - Sheet->mModX) - 0x40,
1146 ((pTileY) * 16) + (Sprite.mY - Sheet->mModY));
1147 }
1148 }
1149
Map_Load_Sprites()1150 void cFodder::Map_Load_Sprites() {
1151
1152 Sprite_Clear_All();
1153
1154 mSprites = mMapLoaded->getSprites();
1155
1156 if (mSprites.size() < mParams->mSpritesMax) {
1157 size_t start = mSprites.size();
1158 mSprites.resize(mParams->mSpritesMax);
1159
1160 for (; start < mSprites.size(); ++start) {
1161 mSprites[start].Clear();
1162 }
1163 }
1164
1165 Squad_Set_Squad_Leader();
1166 Map_Load_Sprites_Count();
1167 }
1168
Map_Load_Sprites_Count()1169 void cFodder::Map_Load_Sprites_Count() {
1170 uint16 HumanCount = 0;
1171 int16 dword_37ABC = 0x0A;
1172
1173 mTroops_Enemy_Count = 0;
1174 mHostage_Count = 0;
1175
1176 for (auto& Sprite : mSprites) {
1177
1178 if (Sprite.field_0 == -1 || Sprite.field_0 == -32768)
1179 continue;
1180
1181 Sprite.field_8 = 0x7C;
1182 Sprite.field_32 = (HumanCount / 8);
1183
1184 if (Sprite.field_18 == eSprite_Enemy_Leader || Sprite.field_18 == eSprite_Hostage) {
1185
1186 ++mHostage_Count;
1187 }
1188
1189 if (Sprite.field_18 == eSprite_Player) {
1190
1191 ++HumanCount;
1192 Sprite.field_4A = 0;
1193 }
1194 else {
1195
1196 if (Sprite.field_18 == eSprite_Enemy_Rocket) {
1197 Sprite.field_22 = eSprite_PersonType_AI;
1198 ++mTroops_Enemy_Count;
1199
1200 }
1201 else {
1202 if (Sprite.field_18 == eSprite_Enemy)
1203 ++mTroops_Enemy_Count;
1204 }
1205
1206 dword_37ABC += 0x0A;
1207 if (Sprite.field_62 > 4)
1208 dword_37ABC = 0;
1209
1210 Sprite.field_4A = dword_37ABC;
1211 }
1212 }
1213 }
1214
Phase_Soldiers_Count()1215 void cFodder::Phase_Soldiers_Count() {
1216 mGame_Data.mGamePhase_Data.mSoldiers_Required = 0;
1217 sSprite* Sprite = mSprites.data();
1218
1219 // TODO: This counter needs fixing
1220 // How many player sprites are on this map
1221 for (int16 mTmpCount = 0x1D; mTmpCount > 0; --mTmpCount, ++Sprite) {
1222 if (Sprite->field_0 != -32768) {
1223
1224 if (Sprite->field_18 == eSprite_Player)
1225 ++mGame_Data.mGamePhase_Data.mSoldiers_Required;
1226 }
1227 }
1228
1229 // How many recruits have already been allocated to the mission
1230 mGame_Data.mGamePhase_Data.mSoldiers_Allocated_Count = 0;
1231
1232 for( auto& Troop : mGame_Data.mSoldiers_Allocated) {
1233
1234 if (Troop.mRecruitID != -1) {
1235 --mGame_Data.mGamePhase_Data.mSoldiers_Required;
1236 ++mGame_Data.mGamePhase_Data.mSoldiers_Allocated_Count;
1237 }
1238 }
1239
1240 // Do we still require troops?
1241 int16 ax = mGame_Data.mGamePhase_Data.mSoldiers_Required;
1242 if (mGame_Data.mGamePhase_Data.mSoldiers_Required >= 0) {
1243
1244 // Do we need more than available?
1245 if (ax > mGame_Data.mRecruits_Available_Count)
1246 ax = mGame_Data.mRecruits_Available_Count;
1247
1248 // Set the Required amount
1249 mGame_Data.mGamePhase_Data.mSoldiers_Required = ax;
1250
1251 // Reduce the available recruits by the number taken by the mission
1252 mGame_Data.mRecruits_Available_Count -= ax;
1253 }
1254
1255 mGame_Data.mGamePhase_Data.mSoldiers_Available = mGame_Data.mGamePhase_Data.mSoldiers_Allocated_Count + ax;
1256 }
1257
Phase_Soldiers_Prepare(const bool pPrebriefing)1258 void cFodder::Phase_Soldiers_Prepare(const bool pPrebriefing) {
1259 Mission_Troops_Clear_Selected();
1260
1261 if (!pPrebriefing) {
1262
1263 // Set the sMission_Troop Sprites from mMission_Troops_SpritePtrs
1264 if (mGame_Data.mGamePhase_Data.mSoldiers_Prepare_SetFromSpritePtrs) {
1265 sSprite** Data24 = mMission_Troops_SpritePtrs;
1266
1267 for (auto& Troop : mGame_Data.mSoldiers_Allocated) {
1268 Troop.mSprite = *Data24++;
1269 }
1270 }
1271
1272 mGame_Data.mGamePhase_Data.mSoldiers_Prepare_SetFromSpritePtrs = true;
1273
1274 sSprite** Data24 = mMission_Troops_SpritePtrs;
1275 for (auto& Troop : mGame_Data.mSoldiers_Allocated) {
1276 *Data24++ = Troop.mSprite;
1277 }
1278
1279 }
1280
1281 // Join recruits into the squad
1282 int16 Data1C = mGame_Data.mGamePhase_Data.mSoldiers_Required - 1;
1283 while (Data1C >= 0) {
1284 Mission_Troop_Prepare_Next_Recruits();
1285 --Data1C;
1286 }
1287
1288 if (pPrebriefing)
1289 return;
1290
1291 // Remove recruits which arn't needed for the map
1292 Data1C = mGame_Data.mGamePhase_Data.mSoldiers_Available;
1293 for (auto& Troop : mGame_Data.mSoldiers_Allocated) {
1294
1295 if (Troop.mSprite == INVALID_SPRITE_PTR)
1296 continue;
1297
1298 if (Data1C)
1299 --Data1C;
1300 else
1301 Troop.mSprite = INVALID_SPRITE_PTR;
1302 }
1303
1304 }
1305
Mission_Troop_Prepare_Next_Recruits()1306 void cFodder::Mission_Troop_Prepare_Next_Recruits() {
1307
1308 // Loop each troop
1309 for (auto& Troop : mGame_Data.mSoldiers_Allocated) {
1310
1311 // Does troop member have a recruit id?
1312 if (Troop.mRecruitID == -1) {
1313
1314 if (mGame_Data.mRecruit_NextID >= 360)
1315 return;
1316
1317 Troop.mRecruitID = mGame_Data.mRecruit_NextID;
1318
1319 // All troops are equal during unit testing
1320 if (mParams->mUnitTesting) {
1321 Troop.mRank = 0;
1322 } else {
1323 // Demo sets static ranks
1324 if (mVersionCurrent->isDemo() && mCustom_Mode != eCustomMode_Set) {
1325
1326 Troop.mRank = (mGame_Data.mMission_Number - 1) >> 1;
1327
1328 // Jops
1329 if (Troop.mRecruitID == 1)
1330 Troop.mRank = 2;
1331
1332 // Jools
1333 if (Troop.mRecruitID == 0)
1334 Troop.mRank = 4;
1335
1336 }
1337 else {
1338 Troop.mRank = (mGame_Data.mMission_Number - 1) / 3;
1339 }
1340 }
1341
1342 Troop.field_6 = 3;
1343 ++mGame_Data.mRecruit_NextID;
1344
1345 return;
1346 }
1347 }
1348 }
1349
Phase_Soldiers_AttachToSprites()1350 void cFodder::Phase_Soldiers_AttachToSprites() {
1351
1352 int16 TroopsRemaining = mGame_Data.mGamePhase_Data.mSoldiers_Available;
1353 sSprite* Sprite = mSprites.data();
1354 sMission_Troop* Troop = mGame_Data.mSoldiers_Allocated;
1355
1356 // TODO: This counter needs fixing
1357 // Loop the game sprites looking for 'player' sprite
1358 for (int16 Data18 = 0x1D; Data18 >= 0; --Data18, ++Sprite) {
1359
1360 if (Sprite->field_0 == -32768)
1361 continue;
1362
1363 if (Sprite->field_18 != eSprite_Player)
1364 continue;
1365
1366 //
1367 if (--TroopsRemaining < 0) {
1368 Troop->mSprite = INVALID_SPRITE_PTR;
1369 Sprite->field_0 = -32768;
1370 Sprite->field_18 = eSprite_Null;
1371 Sprite->field_8 = 0x7C;
1372 ++Troop;
1373 }
1374 else {
1375 // loc_1166B
1376
1377 // Attach a Mission Troop to the sprite
1378 Sprite->field_46_mission_troop = Troop;
1379
1380 Troop->mSprite = Sprite;
1381 Sprite->field_10 = 0x40;
1382 Sprite->field_22 = eSprite_PersonType_Human;
1383
1384 ++Troop;
1385 }
1386 }
1387 }
1388
Camera_Speed_Update_From_PanTarget()1389 void cFodder::Camera_Speed_Update_From_PanTarget() {
1390 int16 Data4 = mCamera_PanTargetY - (getCameraHeight() - 8) / 2;
1391 if (Data4 < 0)
1392 Data4 = 0;
1393
1394 int16 Data0 = mCamera_PanTargetX - (getCameraWidth() / 2) + 8;
1395 if (Data0 < 0)
1396 Data0 = 0;
1397
1398 int16 Data8 = mCameraX >> 16;
1399 int16 DataC = mCameraY >> 16;
1400
1401 int16 PanTargetX = Data0;
1402 int16 PanTargetY = Data4;
1403 int16 CameraX = Data8;
1404 int16 CameraY = DataC;
1405
1406 Map_Get_Distance_BetweenPoints_Within_Window(Data0, Data4, Data8, DataC);
1407 if (Data0 > 0x10) {
1408 Data4 = mCamera_Scroll_Speed;
1409
1410 if (Data4 <= (dword_39F36 >> 16)) {
1411 dword_39F36 = (Data4 << 16) | (dword_39F36 & 0xFFFF);
1412 }
1413 else {
1414 dword_39F36 += 0x8000;
1415 }
1416 }
1417 else {
1418 dword_39F36 = Data0 << 16;
1419 }
1420
1421 DataC = CameraY;
1422 Data8 = CameraX;
1423 Data4 = PanTargetY;
1424 Data0 = PanTargetX;
1425
1426 if (sub_119E1(Data0, Data4, Data8, DataC) >= 0) {
1427
1428 Data0 &= 0x1FE;
1429 if (!dword_39F36)
1430 return;
1431 Data4 = Data0;
1432
1433 Data8 = mMap_Direction_Calculations[Data4 / 2];
1434 Data4 += 0x80;
1435 Data4 &= 0x1FE;
1436
1437 DataC = mMap_Direction_Calculations[Data4 / 2];
1438 Data8 >>= 2;
1439 DataC >>= 2;
1440
1441 //seg000:197D
1442 int32 Dataa8 = (int32)Data8;
1443 int32 DataaC = (int32)DataC;
1444
1445 Data4 = (dword_39F36 >> 16);
1446 Dataa8 *= Data4;
1447 DataaC *= Data4;
1448
1449 mCamera_Speed_X = Dataa8;
1450 mCamera_Speed_Y = DataaC;
1451
1452 }
1453 else {
1454
1455 //loc_119C6
1456 dword_39F36 -= 0x8000;
1457 if (dword_39F36 < 0) {
1458 dword_39F36 = 0;
1459 mMouse_Locked = true;
1460 }
1461 }
1462
1463 }
1464
sub_119E1(int16 & pX1,int16 & pY1,int16 pX2,int16 pY2)1465 int16 cFodder::sub_119E1(int16& pX1, int16& pY1, int16 pX2, int16 pY2) {
1466
1467 int16 Data10 = 0, Data14 = 0;
1468
1469 pX1 -= pX2;
1470 pY1 -= pY2;
1471
1472 if (pX1 < 0)
1473 Data10 = 1;
1474
1475 Data10 = -Data10;
1476 if (pX1 < 0)
1477 pX1 = -pX1;
1478
1479
1480 if (pY1 < 0)
1481 Data14 = 1;
1482
1483 Data14 = -Data14;
1484 if (pY1 < 0)
1485 pY1 = -pY1;
1486
1487 int16 count = 0;
1488 for (count = 0x0E; count >= 0; --count) {
1489 if (pX1 & (1 << count))
1490 break;
1491 if (pY1 & (1 << count))
1492 break;
1493 }
1494
1495 count -= 4;
1496 if (count >= 0) {
1497 pX1 >>= count;
1498 pY1 >>= count;
1499 }
1500 pY1 <<= 5;
1501 pY1 |= pX1;
1502
1503 pY1 = mMap_DirectionsBetweenPoints[pY1];
1504 if (pY1 < 0)
1505 return -1;
1506
1507 pY1 <<= 1;
1508 if (Data10 < 0) {
1509 //loc_11AD2
1510 if (Data14 >= 0) {
1511 pX1 = 0x180;
1512 pX1 += pY1;
1513 pY1 = 0;
1514 return 0;
1515 }
1516 //loc_11AEF
1517 pX1 = 0x180;
1518 pX1 -= pY1;
1519 pY1 = 0;
1520 return 0;
1521 }
1522
1523 if (Data14 < 0) {
1524 //loc_11ABC
1525 pX1 = 0x80;
1526 pX1 += pY1;
1527 pY1 = 0;
1528 return 0;
1529 }
1530
1531 pX1 = 0x80;
1532 pX1 -= pY1;
1533 pY1 = 0;
1534 return 0;
1535
1536
1537 }
1538
Camera_Speed_Calculate()1539 void cFodder::Camera_Speed_Calculate() {
1540
1541 mCamera_Speed_X += mCamera_AccelerationX;
1542 mCamera_Speed_Y += mCamera_AccelerationY;
1543
1544 int32 Data0 = 1;
1545
1546 if (mCamera_Speed_X < 0)
1547 Data0 = -1;
1548
1549 if (Data0 != mCamera_MoveDirectionX) {
1550 mCamera_MoveDirectionX = Data0;
1551 mCamera_MovePauseX = 9;
1552 }
1553
1554 if (mCamera_MovePauseX)
1555 mCamera_Speed_X = 0;
1556
1557 Data0 = 1;
1558 if (mCamera_Speed_Y < 0)
1559 Data0 = -1;
1560
1561 if (Data0 != mCamera_MoveDirectionY) {
1562 mCamera_MoveDirectionY = Data0;
1563 mCamera_MovePauseY = 9;
1564 }
1565
1566 if (mCamera_MovePauseY)
1567 mCamera_Speed_Y = 0;
1568
1569 //loc_11B9C
1570 // Calculate maximum right position of camera
1571 Data0 = mMapLoaded->getWidthPixels() - getCameraWidth();
1572 Data0 = (Data0 << 16) | (Data0 >> 16);
1573
1574 int32 Data4 = mCameraX + mCamera_Speed_X;
1575 if (Data4 > Data0) {
1576 Data0 -= mCameraX;
1577 mCamera_Speed_X = Data0;
1578 }
1579 //loc_11BE8
1580 Data0 = mMapLoaded->getHeightPixels() - getCameraHeight();
1581 Data0 = (Data0 << 16) | (Data0 >> 16);
1582
1583 Data4 = mCameraY + mCamera_Speed_Y;
1584
1585 if (Data4 > Data0) {
1586 Data0 -= mCameraY;
1587 mCamera_Speed_Y = Data0;
1588 }
1589
1590 Data0 = mCamera_Speed_X;
1591 if (Data0 < 0)
1592 Data0 = -Data0;
1593
1594 if (Data0 > mCamera_Speed_Max) {
1595 Data0 = mCamera_Speed_Max;
1596
1597 if ((mCamera_Speed_X >> 16) < 0)
1598 Data0 = -Data0;
1599
1600 mCamera_Speed_X = Data0;
1601 }
1602 //loc_11C6D
1603 Data0 = mCamera_Speed_Y;
1604 if (Data0 < 0)
1605 Data0 = -Data0;
1606
1607 if (Data0 <= mCamera_Speed_Max)
1608 return;
1609
1610 Data0 = mCamera_Speed_Max;
1611 if ((mCamera_Speed_Y >> 16) < 0)
1612 Data0 = -Data0;
1613
1614 mCamera_Speed_Y = Data0;
1615 }
1616
Camera_Prepare()1617 void cFodder::Camera_Prepare() {
1618
1619 mCamera_TileX = mCameraX >> 16;
1620 mCamera_TileY = mCameraY >> 16;
1621 mCamera_Speed_Reset_X = false;
1622 mCamera_Speed_Reset_Y = false;
1623 mCamera_AccelerationX &= 0x0000FFFF;
1624 mCamera_AccelerationY &= 0x0000FFFF;
1625 }
1626
Camera_SetTargetToStartPosition()1627 void cFodder::Camera_SetTargetToStartPosition() {
1628 int16 Data0 = mCameraX >> 16;
1629 int16 Data4 = mCameraY >> 16;
1630
1631 int16 Data8 = mCamera_StartPosition_X;
1632 Data8 -= (getCameraWidth() / 2) - 8;
1633 if (Data8 < 0)
1634 Data8 = 0;
1635
1636 int16 Data10 = mMapLoaded->getWidthPixels();
1637 Data10 -= (getCameraWidth() / 2) - 8;
1638 if (Data8 >= Data10)
1639 Data8 = Data10;
1640
1641 int16 DataC = mCamera_StartPosition_Y;
1642 DataC -= (getCameraHeight() - 8) / 2;
1643 if (DataC < 0)
1644 DataC = 0;
1645
1646 Data10 = mMapLoaded->getHeightPixels();
1647 Data10 -= (getCameraHeight() - 8) / 2;
1648 if (DataC >= Data10)
1649 DataC = Data10;
1650
1651 if (!mPhase_MapIs17x12) {
1652 Map_Get_Distance_BetweenPoints_Within_Window(Data0, Data4, Data8, DataC);
1653
1654 if (Data0 >= 0x8C)
1655 goto loc_11D8A;
1656 }
1657 //loc_11D62
1658 mCamera_PanTargetX = mCamera_StartPosition_X;
1659 mCamera_PanTargetY = mCamera_StartPosition_Y;
1660
1661 Music_Play_Tileset();
1662 return;
1663
1664 loc_11D8A:;
1665
1666 if (mPhase_Completed_Timer)
1667 goto loc_11E5B;
1668
1669 mCamera_MovePauseX = 6;
1670 mCamera_MovePauseY = 6;
1671 mInput_Enabled = false;
1672
1673 mCamera_PanTargetX = mCamera_StartPosition_X;
1674 mCamera_PanTargetY = mCamera_StartPosition_Y;
1675 mCamera_Speed_Reset_X = false;
1676 mCamera_AccelerationX &= 0x0000FFFF;
1677 mCamera_Speed_Reset_Y = false;
1678 mCamera_AccelerationY &= 0x0000FFFF;
1679
1680 Image_FadeOut();
1681
1682 if (mMap_Destroy_Tiles_Countdown)
1683 Map_Destroy_Tiles();
1684
1685 // THis count is really meant as a backup to stop it looping forever
1686 for (int count = 0; count < 10000000; ++count) {
1687 Camera_Pan_To_Target();
1688 Camera_Pan_To_Target();
1689
1690 if (!mCamera_Reached_Target)
1691 break;
1692 }
1693
1694 if (mCamera_Reached_Target) {
1695 g_Debugger->Notice("Camera didnt reach target");
1696 }
1697 Mission_Sprites_Handle();
1698 mGraphics->Sidebar_Copy_To_Surface();
1699 Mouse_DrawCursor();
1700 Camera_Prepare();
1701
1702 mInput_Enabled = true;
1703
1704 mGraphics->PaletteSet();
1705
1706 loc_11E5B:;
1707 Music_Play_Tileset();
1708 }
1709
Campaign_Load(std::string pName)1710 bool cFodder::Campaign_Load(std::string pName) {
1711
1712 // If no campaign name was provided, use the default for the current version
1713 if (!pName.size()) {
1714
1715 if (!mVersionCurrent->isCustom()) {
1716 pName = mVersionCurrent->mName;
1717 }
1718 }
1719
1720 VersionSwitch(mVersions->GetForCampaign(pName, mParams->mDefaultPlatform));
1721 if (!mGame_Data.mCampaign.LoadCampaign(pName, pName != mVersionCurrent->mName)) {
1722 // TODO: But what?
1723
1724 return false;
1725 }
1726
1727 return true;
1728 }
1729
Map_Create(sMapParams pParams)1730 void cFodder::Map_Create(sMapParams pParams) {
1731 uint8 TileID = (pParams.mTileType == eTileTypes_Int) ? 4
1732 : (pParams.mTileType == eTileTypes_AFX) ? 20
1733 : 16;
1734
1735 if (mVersionCurrent->isAmigaPower())
1736 pParams.mTileSub = eTileSub_1;
1737
1738 // In OF, this will only ever get called from the campaign selection screen,
1739 // so we pick a tile thats easy to read text on
1740 #ifndef _OFED
1741 if (mVersionCurrent->isAmigaXmas())
1742 TileID = 100;
1743 #endif
1744
1745 mMapLoaded = std::make_shared<cRandomMap>(pParams);
1746
1747 mMap = mMapLoaded->getData();
1748
1749 mMapTile_Ptr = (int32)((0x60 - 8) - (mMapLoaded->getWidth() * 2));
1750 mMapTile_DrawX = 0;
1751 mMapTile_DrawY = 0;
1752
1753 // Clear current sprites
1754 Sprite_Clear_All();
1755
1756 // Load the map specific resources
1757 Map_Load_Resources();
1758
1759 #ifdef _OFED
1760 // Editor needs to render the surface now
1761 // Draw the tiles
1762 MapTiles_Draw();
1763
1764 Mission_Sprites_Handle();
1765
1766 // Refresh the palette
1767 mGraphics->PaletteSet(mSurface);
1768 mSurface->surfaceSetToPaletteNew();
1769 #endif
1770
1771 }
1772
Map_Load()1773 void cFodder::Map_Load() {
1774 mMapLoaded = mGame_Data.mCampaign.getCMap(mGame_Data.mPhase_Current);
1775 mMap = mMapLoaded->getData();
1776
1777 if (!mMap->size())
1778 return;
1779
1780 Map_Load_Resources();
1781 }
1782
1783 /**
1784 * Load the Base and Sub Tile BLK Files
1785 *
1786 * @return true if both files are loaded
1787 */
Tiles_Load_Data()1788 bool cFodder::Tiles_Load_Data() {
1789 std::string BaseName, SubName;
1790
1791 // junbase.blk
1792 BaseName.append(mMap->data(), mMap->data() + 11);
1793
1794 // junsub0.blk
1795 SubName.append(mMap->data() + 0x10, mMap->data() + 0x10 + 11);
1796
1797 mTile_BaseBlk = mResources->fileGet(BaseName);
1798 mTile_SubBlk = mResources->fileGet(SubName);
1799
1800 if (!mTile_BaseBlk->size() || !mTile_SubBlk->size())
1801 return false;
1802
1803 return true;
1804 }
1805
Map_Load_Resources()1806 void cFodder::Map_Load_Resources() {
1807 std::string BaseBase, BaseSub, BaseBaseSet, BaseSubSet;
1808
1809 // Is the tileset available?
1810 if (!Tiles_Load_Data()) {
1811
1812 // Load the default version
1813 VersionSwitch(mVersionDefault);
1814
1815 // Check the default version for the tileset
1816 if (!Tiles_Load_Data()) {
1817
1818 // Not found, so lets go find it
1819 auto Version = mVersions->GetForTileset(mMapLoaded->getTileType(), mMapLoaded->getTileSub());
1820
1821 // Load it
1822 if (Version) {
1823 VersionSwitch(Version);
1824 Tiles_Load_Data();
1825 }
1826 else {
1827 DataNotFound();
1828 return;
1829 }
1830 }
1831
1832 mVersionReturnAfterPhase = true;
1833 }
1834
1835 // jun
1836 BaseBaseSet.append(mMap->data(), mMap->data() + 3);
1837
1838 // jun
1839 BaseSubSet.append(mMap->data() + 0x10, mMap->data() + 0x10 + 3);
1840
1841 // junbase
1842 BaseBase.append(mMap->data(), mMap->data() + 7);
1843
1844 // junsub0
1845 BaseSub.append(mMap->data() + 0x10, mMap->data() + 0x10 + 7);
1846
1847
1848 mFilenameCopt = BaseBaseSet + "copt";
1849 mFilenameArmy = BaseSubSet + "army";
1850
1851 mFilenameBaseSwp = BaseBase + ".swp";
1852 mFilenameBaseHit = BaseBase + ".hit";
1853 mFilenameBaseBht = BaseBase + ".bht";
1854 mFilenameSubSwp = BaseSub + ".swp";
1855 mFilenameSubHit = BaseSub + ".hit";
1856 mFilenameSubBht = BaseSub + ".bht";
1857 mFilenameBasePal = BaseBase + ".pal";
1858
1859
1860 size_t Size = mResources->fileLoadTo(mFilenameBaseSwp, (uint8*)&mTile_Destroy_Swap[0]);
1861 tool_EndianSwap((uint8*)&mTile_Destroy_Swap[0], Size);
1862
1863 Size = mResources->fileLoadTo(mFilenameSubSwp, (uint8*)&mTile_Destroy_Swap[240]);
1864 tool_EndianSwap((uint8*)&mTile_Destroy_Swap[240], Size);
1865
1866 memset(mTile_Hit, 0, 512);
1867
1868 for (int x = 0; x < 512; ++x)
1869 for (int y = 0; y < 8; ++y)
1870 mTile_BHit[x][y] = 0;
1871
1872 Size = mResources->fileLoadTo(mFilenameBaseHit, (uint8*)&mTile_Hit[0]);
1873 tool_EndianSwap((uint8*)&mTile_Hit[0], Size);
1874
1875 Size = mResources->fileLoadTo(mFilenameSubHit, (uint8*)&mTile_Hit[240]);
1876 tool_EndianSwap((uint8*)&mTile_Hit[240], Size);
1877
1878 Size = mResources->fileLoadTo(mFilenameBaseBht, (uint8*)&mTile_BHit[0][0]);
1879 Size = mResources->fileLoadTo(mFilenameSubBht, (uint8*)&mTile_BHit[240][0]);
1880
1881 mGraphics->Tile_Prepare_Gfx();
1882 mGraphics->Map_Load_Resources();
1883 mGraphics->PaletteSet();
1884 }
1885
Music_Play_Tileset()1886 void cFodder::Music_Play_Tileset() {
1887 if (!mStartParams->mDisableSound)
1888 mSound->Music_Play(mMapLoaded->getTileType() + 0x32);
1889 }
1890
Camera_Pan_To_Target()1891 void cFodder::Camera_Pan_To_Target() {
1892 Camera_Pan_Set_Speed();
1893
1894 int32 Saved_dword_3A9FD = mCamera_Speed_Max;
1895 mCamera_Speed_Max = 0x100000;
1896 Camera_Speed_Calculate();
1897 mCamera_Speed_Max = Saved_dword_3A9FD;
1898
1899 Camera_TileSpeedX_Set();
1900
1901 MapTile_UpdateFromCamera();
1902 MapTile_Update_Position();
1903 }
1904
Camera_Pan_Set_Speed()1905 void cFodder::Camera_Pan_Set_Speed() {
1906 mCamera_Reached_Target = 2;
1907 mCamera_Speed_X = 0;
1908 mCamera_Speed_Y = 0;
1909
1910 int16 Data0 = mCamera_PanTargetX;
1911 Data0 -= getCameraWidth() / 2;
1912 if (Data0 < 0)
1913 Data0 = 0;
1914
1915 Data0 >>= 4;
1916 int16 Data4 = mCamera_PanTargetY;
1917 Data4 -= (getCameraHeight() - 8) / 2;
1918 if (Data4 < 0)
1919 Data4 = 0;
1920
1921 Data4 >>= 4;
1922
1923 int16 Data8 = mMapLoaded->getWidth();
1924 Data8 -= (getCameraWidth() >> 4) + 1;
1925
1926 if (Data8 < 0)
1927 Data8 = 0;
1928
1929 if (Data0 >= Data8)
1930 Data0 = Data8;
1931
1932 Data8 = mMapLoaded->getHeight();
1933 Data8 -= (getCameraHeight() + 32) >> 4;
1934 if (Data8 < 0)
1935 Data8 = 0;
1936
1937 if (Data4 >= Data8)
1938 Data4 = Data8;
1939
1940 Data8 = mCameraX >> 16;
1941 Data8 >>= 4;
1942 int16 DataC = mCameraY >> 16;
1943 DataC >>= 4;
1944
1945 if (Data8 == Data0) {
1946 --mCamera_Reached_Target;
1947 }
1948 else if (Data8 > Data0) {
1949 mCamera_Speed_X = (mCamera_Speed_X & 0xFFFF) | -CAMERA_PAN_TO_START_ACCELARATION; // (-8 << 16);
1950 }
1951 else
1952 mCamera_Speed_X = (mCamera_Speed_X & 0xFFFF) | CAMERA_PAN_TO_START_ACCELARATION; // (8 << 16);
1953
1954 //loc_11FAC
1955 if (DataC == Data4) {
1956 --mCamera_Reached_Target;
1957 }
1958 else if (DataC > Data4) {
1959 mCamera_Speed_Y = (mCamera_Speed_Y & 0xFFFF) | -CAMERA_PAN_TO_START_ACCELARATION; // (-8 << 16);
1960 }
1961 else
1962 mCamera_Speed_Y = (mCamera_Speed_Y & 0xFFFF) | CAMERA_PAN_TO_START_ACCELARATION; // (8 << 16);
1963 }
1964
1965 /**
1966 * Move the mouse position to follow the terrain as the camere pans
1967 */
Camera_Update_Mouse_Position_For_Pan()1968 void cFodder::Camera_Update_Mouse_Position_For_Pan() {
1969
1970 if (!mMouse_Locked) {
1971
1972 // Mouse in playfield?
1973 if (mMouseX > 0x0F) {
1974 mMouseX -= (mCameraX >> 16) - mCamera_TileX;
1975 mMouseY -= (mCameraY >> 16) - mCamera_TileY;
1976 }
1977 }
1978
1979 //loc_12007
1980 mCamera_TileX = (mCameraX >> 16);
1981 mCamera_TileY = (mCameraY >> 16);
1982 }
1983
MapTile_UpdateFromCamera()1984 void cFodder::MapTile_UpdateFromCamera() {
1985 mMapTile_SpeedX = mCamera_TileSpeedX;
1986 mMapTile_SpeedY = mCamera_TileSpeedY;
1987 mMapTile_TargetX = mCameraX;
1988 mMapTile_TargetY = mCameraY;
1989 mMapTile_MoveDirectionX = mCamera_MoveDirectionX;
1990 mMapTile_MoveDirectionY = mCamera_MoveDirectionY;
1991 }
1992
Camera_Reset()1993 void cFodder::Camera_Reset() {
1994
1995 mCamera_TileSpeedX = 0;
1996 mCamera_TileSpeedY = 0;
1997 mCameraX = 0;
1998 mCameraY = 0;
1999 dword_39F36 &= 0x0000FFFF;
2000 mCamera_AccelerationX &= 0x0000FFFF;
2001 mCamera_AccelerationY &= 0x0000FFFF;
2002 mCamera_Speed_Reset_X = false;
2003 mCamera_Speed_Reset_Y = false;
2004 mCamera_TileX = 0;
2005 mCamera_TileY = 0;
2006 mCamera_Speed_X = 0;
2007 mCamera_Speed_Y = 0;
2008 mCamera_TileSpeed_Overflow = 0;
2009 }
2010
Camera_TileSpeedX_Set()2011 void cFodder::Camera_TileSpeedX_Set() {
2012 mCamera_TileSpeed_Overflow = 0;
2013
2014 int32 dword_39F5A = mCameraX;
2015
2016 mCameraX += mCamera_Speed_X;
2017 if (mCameraX < 0) {
2018 mCamera_Speed_X = dword_39F5A;
2019 if (mCamera_Speed_X)
2020 mCamera_Speed_X = -mCamera_Speed_X;
2021
2022 mCameraX = 0;
2023 }
2024 //loc_12147
2025 mCamera_TileSpeedX += mCamera_Speed_X;
2026
2027 if ((mCamera_Speed_X >> 16) < 0) {
2028
2029 if ((mCamera_TileSpeedX >> 16) < 0) {
2030
2031 mCamera_TileSpeedX += (getWindowWidth() << 16);
2032 mCamera_TileSpeed_Overflow = (0xFFFF << 16) | (mCamera_TileSpeed_Overflow & 0xFFFF);
2033 }
2034 }
2035 else {
2036 //loc_12181
2037 if ((mCamera_TileSpeedX >> 16) >= getWindowWidth()) {
2038 mCamera_TileSpeedX -= (getWindowWidth() << 16);
2039 mCamera_TileSpeed_Overflow = (1 << 16) | (mCamera_TileSpeed_Overflow & 0xFFFF);
2040 }
2041 }
2042 //loc_1219F
2043 Camera_TileSpeedY_Set();
2044 mCamera_Speed_X = 0;
2045 mCamera_Speed_Y = 0;
2046 }
2047
Camera_TileSpeedY_Set()2048 void cFodder::Camera_TileSpeedY_Set() {
2049
2050 int32 dword_39F5A = mCameraY;
2051
2052 mCameraY += mCamera_Speed_Y;
2053 if (mCameraY < 0) {
2054 mCamera_Speed_Y = dword_39F5A;
2055
2056 if (mCamera_Speed_Y)
2057 mCamera_Speed_Y = -mCamera_Speed_Y;
2058
2059 mCameraY = 0;
2060 }
2061
2062 //loc_121F2
2063
2064 mCamera_TileSpeedY += (mCamera_Speed_Y + mCamera_TileSpeed_Overflow);
2065 mCamera_TileSpeedY &= (0x00FF << 16) | 0xFFFF;
2066 }
2067
Camera_Speed_MaxSet()2068 void cFodder::Camera_Speed_MaxSet() {
2069
2070 mCamera_Speed_Max = 0x20000;
2071 if (!mPhase_Aborted && !mPhase_TryAgain && !mPhase_Complete)
2072 return;
2073
2074 int16 Data0 = 0;
2075
2076 mCamera_AccelerationX = (mCamera_AccelerationX & 0xFFFF) + (Data0 << 16);
2077 mCamera_AccelerationY = (mCamera_AccelerationY & 0xFFFF) + (Data0 << 16);
2078 mCamera_Speed_X = Data0;
2079 mCamera_Speed_Y = Data0;
2080 mCamera_Speed_Max = 0;
2081 }
2082
Camera_Speed_Reset()2083 void cFodder::Camera_Speed_Reset() {
2084
2085 if (mCamera_Speed_Reset_X)
2086 mCamera_Speed_X = 0;
2087
2088 if (mCamera_Speed_Reset_Y)
2089 mCamera_Speed_Y = 0;
2090 }
2091
Camera_Acceleration_Set()2092 void cFodder::Camera_Acceleration_Set() {
2093
2094 if (mSquad_Leader == INVALID_SPRITE_PTR || mSquad_Leader == 0)
2095 return;
2096
2097 int16 DistanceX = mSquad_Leader->field_0 + 0x40;
2098 int16 DistanceY = mSquad_Leader->field_4 + 0x10;
2099
2100 DistanceX -= mCameraX >> 16;
2101 DistanceY -= mCameraY >> 16;
2102
2103 if (mCamera_Speed_Reset_X && DistanceX > 0x90 && DistanceX < 0xCF) { // 90 / A2 = Amiga
2104 mCamera_Speed_Reset_X = false;
2105 mCamera_AccelerationX = 0;
2106 }
2107
2108 if (mCamera_Speed_Reset_Y && DistanceY > 0x60 && DistanceY < 0x87) { // 64 / 8F = Amiga
2109 mCamera_Speed_Reset_Y = false;
2110 mCamera_AccelerationY = 0;
2111 }
2112 //loc_1234F
2113 if (DistanceX <= 0x40) {
2114 mCamera_AccelerationX = (mCamera_AccelerationX & 0xFFFF) | -CAMERA_PAN_TO_SQUAD_ACCELERATION; // (-2 << 16);
2115 mCamera_Speed_Reset_X = true;
2116 }
2117 //loc_12362
2118 if (DistanceX >= getCameraWidth() + 64) {
2119 mCamera_AccelerationX = (mCamera_AccelerationX & 0xFFFF) | CAMERA_PAN_TO_SQUAD_ACCELERATION; // (2 << 16);
2120 mCamera_Speed_Reset_X = true;
2121 }
2122
2123 if (DistanceY <= 0x10) {
2124 mCamera_AccelerationY = (mCamera_AccelerationY & 0xFFFF) | -CAMERA_PAN_TO_SQUAD_ACCELERATION; // (-2 << 16);
2125 mCamera_Speed_Reset_Y = true;
2126 }
2127
2128 if (DistanceY >= (getCameraHeight() - 9)) {
2129 mCamera_AccelerationY = (mCamera_AccelerationY & 0xFFFF) | CAMERA_PAN_TO_SQUAD_ACCELERATION; // (2 << 16);
2130 mCamera_Speed_Reset_Y = true;
2131 }
2132 }
2133
Mission_Sprites_Handle()2134 void cFodder::Mission_Sprites_Handle() {
2135
2136 #ifndef _OFED
2137 Sprite_Frame_Modifier_Update();
2138 Sprite_Handle_Loop();
2139 #endif
2140
2141 Sprite_Sort_DrawList();
2142
2143 MapTile_UpdateFromCamera();
2144
2145 Map_Destroy_Tiles();
2146 Sprites_Draw();
2147 }
2148
Sprite_Sort_DrawList()2149 void cFodder::Sprite_Sort_DrawList() {
2150
2151 mSprite_DrawList_First.clear();
2152 mSprite_DrawList_Second.clear();
2153 mSprite_DrawList_Third.clear();
2154 for(sSprite& sprite : mSprites) {
2155
2156 if (sprite.field_0 == -32768)
2157 continue;
2158
2159 if (sprite.field_2C == eSprite_Draw_First) {
2160 mSprite_DrawList_First.push_back(&sprite);
2161 continue;
2162 }
2163
2164 if (sprite.field_2C == eSprite_Draw_Second) {
2165 mSprite_DrawList_Second.push_back(&sprite);
2166 continue;
2167 }
2168
2169 mSprite_DrawList_Third.push_back(&sprite);
2170 }
2171
2172 std::sort(mSprite_DrawList_Second.begin(), mSprite_DrawList_Second.end(), [](sSprite*& pLeft, sSprite*& pRight) {
2173 return pLeft->field_4 < pRight->field_4;
2174 });
2175
2176 //loc_124AF
2177 mSprite_DrawList_Final.clear();
2178 for (auto spriteptr : mSprite_DrawList_First) {
2179 mSprite_DrawList_Final.push_back(spriteptr);
2180 }
2181 for (auto spriteptr : mSprite_DrawList_Second) {
2182 mSprite_DrawList_Final.push_back(spriteptr);
2183 }
2184 for (auto spriteptr : mSprite_DrawList_Third) {
2185 mSprite_DrawList_Final.push_back(spriteptr);
2186 }
2187 }
2188
Sprite_Bullet_SetData()2189 void cFodder::Sprite_Bullet_SetData() {
2190 if (mSprite_TroopsAlive[0] == INVALID_SPRITE_PTR || mSprite_TroopsAlive[0] == 0)
2191 return;
2192
2193 sSprite* Data20 = mSprite_TroopsAlive[0];
2194 int16 Data0 = 0;
2195
2196 if (Data20->field_46_mission_troop) {
2197 Data0 = Data20->field_46_mission_troop->mRank;
2198 Data0 += 8;
2199 if (Data0 > 0x0F)
2200 Data0 = 0x0F;
2201 }
2202
2203 mSprite_Weapon_Data = mSprite_Bullet_UnitData[Data0];
2204 }
2205
Phase_Goals_Check()2206 void cFodder::Phase_Goals_Check() {
2207
2208 int16 Enemys = 0;
2209 int16 Buildings = 0;
2210
2211 for (auto& Sprite : mSprites) {
2212 sSprite* Data20 = &Sprite;
2213
2214 if (Data20->field_0 == -32768)
2215 continue;
2216
2217 int16 Data10 = Data20->field_18;
2218 if (Data10 == eSprite_Computer_1 || Data10 == eSprite_Computer_2 || Data10 == eSprite_Computer_3 || Data10 == eSprite_BuildingDoor3 || Data10 == eSprite_BuildingDoor_Reinforced)
2219 goto loc_12620;
2220
2221 if (Data10 == eSprite_BuildingDoor2 || Data10 == eSprite_BuildingDoor) {
2222 if (Data20->field_38 == eSprite_Anim_Die1)
2223 continue;
2224
2225 loc_12620:;
2226 if (Data20->field_38 == eSprite_Anim_Die3)
2227 continue;
2228
2229 ++Buildings;
2230 continue;
2231 }
2232
2233 const int16* Data24 = mEnemy_Unit_Types;
2234 for (; *Data24 >= 0; ++Data24) {
2235 if (Data10 != *Data24)
2236 continue;
2237
2238 ++Enemys;
2239 }
2240 }
2241
2242 // The one demo just has two objectives for each map
2243 if (mVersionCurrent->isAmigaTheOne()) {
2244
2245 if (Buildings || Enemys)
2246 return;
2247
2248 mPhase_Complete = true;
2249 return;
2250 }
2251
2252 mEnemy_BuildingCount = Buildings;
2253 if (mGame_Data.mGamePhase_Data.mGoals_Remaining[eObjective_Destroy_Enemy_Buildings - 1]) {
2254 if (Buildings)
2255 return;
2256 }
2257
2258 if (mGame_Data.mGamePhase_Data.mGoals_Remaining[eObjective_Kill_All_Enemy - 1]) {
2259 if (Enemys)
2260 return;
2261 }
2262
2263 if (!mGame_Data.mGamePhase_Data.mGoals_Remaining[eObjective_Kidnap_Leader - 1]) {
2264 if (!mGame_Data.mGamePhase_Data.mGoals_Remaining[eObjective_Rescue_Hostages - 1])
2265 if (!mGame_Data.mGamePhase_Data.mGoals_Remaining[eObjective_Rescue_Hostage - 1])
2266 goto loc_126A6;
2267 }
2268
2269 if (mHostage_Count)
2270 return;
2271
2272 loc_126A6:;
2273
2274 if (mGame_Data.mGamePhase_Data.mGoals_Remaining[eObjective_Get_Civilian_Home - 1]) {
2275 if (!mSprite_Civilian_GotHome)
2276 return;
2277 }
2278
2279 if (mGame_Data.mGamePhase_Data.mGoals_Remaining[eObjective_Activate_All_Switches - 1]) {
2280 if (!mSwitchesActivated)
2281 return;
2282 }
2283
2284 mPhase_Complete = true;
2285 }
2286
Phase_Goals_Set()2287 void cFodder::Phase_Goals_Set() {
2288
2289 for (auto& Goal : mGame_Data.mGamePhase_Data.mGoals_Remaining)
2290 Goal = false;
2291
2292 for (auto Goal : mGame_Data.mPhase_Current->mGoals) {
2293
2294 mGame_Data.mGamePhase_Data.mGoals_Remaining[Goal - 1] = true;
2295 }
2296 }
2297
Phase_Progress_Check()2298 void cFodder::Phase_Progress_Check() {
2299
2300 if (!mPhase_Complete)
2301 if (!mPhase_Aborted)
2302 if (!mPhase_TryAgain)
2303 return;
2304
2305 if (mPhase_Completed_Timer < 0)
2306 return;
2307
2308 if (mPhase_Completed_Timer)
2309 goto loc_1280A;
2310
2311 mPhase_Completed_Timer = 0x64;
2312
2313 if (mPhase_Aborted) {
2314 mPhase_Completed_Timer = 0x32;
2315 goto MissionTryAgain;
2316 }
2317
2318 if (mPhase_Complete) {
2319 if (mPhase_TryAgain)
2320 goto MissionTryAgain;
2321
2322 Phase_Show_Complete();
2323 goto loc_1280A;
2324 }
2325 //loc_127E1
2326 if (mGame_Data.mRecruits_Available_Count) {
2327 MissionTryAgain:;
2328
2329 // Try Again sprites not availabe in 'The One'
2330 if(!mVersionCurrent->isAmigaTheOne())
2331 Phase_Show_TryAgain();
2332
2333 }
2334 else {
2335 //loc_127FA
2336 Phase_GameOver();
2337 }
2338 loc_1280A:;
2339
2340 if (mPhase_Completed_Timer == 0x19) {
2341 mSurface->paletteNew_SetToBlack();
2342 }
2343 --mPhase_Completed_Timer;
2344 if (mPhase_Completed_Timer && !mParams->mUnitTesting)
2345 return;
2346
2347 mPhase_Completed_Timer = -1;
2348 mGame_Data.mGamePhase_Data.mIsComplete = true;
2349 }
2350
Phase_Show_Complete()2351 void cFodder::Phase_Show_Complete() {
2352 Sprite_Destroy(&mSprites[40]);
2353
2354 if (mGame_Data.mMission_Phases_Remaining == 1)
2355 Phase_TextSprite_Create_Mission(&mSprites[41]);
2356 else
2357 Phase_TextSprite_Create_Phase(&mSprites[41]);
2358
2359 Phase_TextSprite_Create_Complete(&mSprites[42]);
2360 }
2361
Phase_TextSprite_Create_Mission(sSprite * pData2C)2362 void cFodder::Phase_TextSprite_Create_Mission(sSprite* pData2C) {
2363 Phase_TextSprite_Prepare(pData2C);
2364
2365 pData2C->field_4 -= 0x14;
2366 pData2C->field_0 += 0x12;
2367 pData2C->field_8 = 0xA2;
2368 pData2C->field_18 = eSprite_Text_Mission;
2369 if (!mStartParams->mDisableSound)
2370 mSound->Music_Play(6);
2371 }
2372
Phase_TextSprite_Create_Phase(sSprite * pData2C)2373 void cFodder::Phase_TextSprite_Create_Phase(sSprite* pData2C) {
2374 Phase_TextSprite_Prepare(pData2C);
2375
2376 pData2C->field_4 -= 0x14;
2377 pData2C->field_0 += 0x1B;
2378 pData2C->field_8 = 0xA1;
2379 pData2C->field_18 = eSprite_Text_Phase;
2380
2381 if (!mStartParams->mDisableSound)
2382 mSound->Music_Play(0x0C);
2383 }
2384
Phase_TextSprite_Create_Complete(sSprite * pData2C)2385 void cFodder::Phase_TextSprite_Create_Complete(sSprite* pData2C) {
2386 Phase_TextSprite_Prepare(pData2C);
2387
2388 pData2C->field_8 = 0xA0;
2389 pData2C->field_18 = eSprite_Text_Complete;
2390 }
2391
Phase_TextSprite_Prepare(sSprite * pData2C)2392 void cFodder::Phase_TextSprite_Prepare(sSprite* pData2C) {
2393
2394 pData2C->field_0 = mMapTile_TargetX >> 16;
2395 pData2C->field_0 += (getCameraWidth() / 2) - 52;
2396
2397 pData2C->field_4 = mMapTile_TargetY >> 16;
2398 pData2C->field_4 += getCameraHeight() + 10;
2399
2400 pData2C->field_A = 0;
2401 pData2C->field_20 = 0;
2402 pData2C->field_52 = 0;
2403 pData2C->field_32 = -1;
2404 pData2C->field_2C = eSprite_Draw_OnTop;
2405 }
2406
Phase_Show_TryAgain()2407 void cFodder::Phase_Show_TryAgain() {
2408
2409 Sprite_Destroy(&mSprites[40]);
2410
2411 Phase_TextSprite_Create_Try(&mSprites[41]);
2412 Phase_TextSprite_Create_Again(&mSprites[42]);
2413
2414 if (!mStartParams->mDisableSound)
2415 mSound->Music_Play(0x0F);
2416 }
2417
Phase_TextSprite_Create_Try(sSprite * pData2C)2418 void cFodder::Phase_TextSprite_Create_Try(sSprite* pData2C) {
2419 Phase_TextSprite_Prepare(pData2C);
2420 pData2C->field_4 -= 0x14;
2421 pData2C->field_0 += 0x12;
2422 pData2C->field_8 = 0xCA;
2423 pData2C->field_18 = eSprite_Text_Try;
2424 }
2425
Phase_TextSprite_Create_Again(sSprite * pData2C)2426 void cFodder::Phase_TextSprite_Create_Again(sSprite* pData2C) {
2427 Phase_TextSprite_Prepare(pData2C);
2428
2429 pData2C->field_8 = 0xCB;
2430 pData2C->field_18 = eSprite_Text_Again;
2431 }
2432
Squad_Member_PhaseCount()2433 void cFodder::Squad_Member_PhaseCount() {
2434
2435 for( auto& Troop : mGame_Data.mSoldiers_Allocated ) {
2436 if (Troop.mSprite == INVALID_SPRITE_PTR || Troop.mSprite == 0)
2437 continue;
2438
2439 ++Troop.mPhaseCount;
2440 }
2441 }
2442
Sprite_Find_HumanVehicles()2443 void cFodder::Sprite_Find_HumanVehicles() {
2444
2445 if (mSprite_HumanVehicles_Found)
2446 return;
2447
2448 mSprite_HumanVehicles_Found = true;
2449
2450 for(auto& Sprite : mSprites) {
2451
2452 if (Sprite.field_0 == -32768)
2453 continue;
2454
2455 // Is not Human?
2456 if (Sprite.field_22 != eSprite_PersonType_Human)
2457 continue;
2458
2459 // Not Enabled?
2460 if (!Sprite.field_65)
2461 continue;
2462
2463 mSprites_HumanVehicles.push_back(&Sprite);
2464 }
2465 }
2466
Squad_Set_CurrentVehicle()2467 void cFodder::Squad_Set_CurrentVehicle() {
2468
2469 if (mSquad_Selected >= 0) {
2470 sSprite** Data20 = mSquads[mSquad_Selected];
2471
2472 mSquad_CurrentVehicles[mSquad_Selected] = 0;
2473
2474 int16 Data0 = 0;
2475
2476 for (;;) {
2477 if (*Data20 != INVALID_SPRITE_PTR && *Data20 != 0) {
2478 sSprite* Data24 = *Data20++;
2479
2480 // Sprite not in vehicle?
2481 if (!Data24->field_6E)
2482 break;
2483
2484 mSquad_CurrentVehicle = Data24->field_6A_sprite;
2485 Data0 = -1;
2486 continue;
2487
2488 }
2489 else {
2490 //loc_12C2B
2491 if (Data0 == 0)
2492 break;
2493
2494 mSquad_CurrentVehicles[mSquad_Selected] = mSquad_CurrentVehicle;
2495 mSquad_Leader = mSquad_CurrentVehicle;
2496 return;
2497 }
2498 }
2499
2500 }
2501
2502 mSquad_CurrentVehicle = 0;
2503 }
2504
Squad_EnteredVehicle_TimerTick()2505 void cFodder::Squad_EnteredVehicle_TimerTick() {
2506
2507 for (int16 Data0 = 0; Data0 < 3; ++Data0) {
2508 if (!mSquad_EnteredVehicleTimer[Data0])
2509 continue;
2510
2511 mSquad_EnteredVehicleTimer[Data0]--;
2512 if (mSquad_EnteredVehicleTimer[Data0])
2513 continue;
2514
2515 sSprite** Data2C = mSquads[Data0];
2516
2517 for (;;) {
2518 if (*Data2C == INVALID_SPRITE_PTR)
2519 break;
2520
2521 sSprite* Data30 = *Data2C++;
2522 Data30->field_38 = eSprite_Anim_Vehicle_Enter;
2523 }
2524 }
2525 }
2526
Phase_Map_Overview_Show()2527 void cFodder::Phase_Map_Overview_Show() {
2528
2529 // We allow the overview map to be shown on all versions in debug mode
2530 #ifndef _DEBUG
2531 // Overview map is disabled for demos
2532 if (mVersionCurrent->isDemo() && !mVersionCurrent->isCustom())
2533 return;
2534 #endif
2535
2536 int16 word_3A016 = 0;
2537 mVideo_Draw_PosX = (mSquad_Leader->field_0) + (mSurfaceMapLeft * 16);
2538 mVideo_Draw_PosY = (mSquad_Leader->field_4 - 0x10) + (mSurfaceMapTop * 16);
2539
2540 if (mVideo_Draw_PosX < 0)
2541 mVideo_Draw_PosX = 0;
2542
2543 if (mVideo_Draw_PosY < 0)
2544 mVideo_Draw_PosY = 0;
2545
2546 mVideo_Draw_PaletteIndex = 0xF0;
2547
2548 mGraphics->PaletteSetOverview();
2549 mSurfaceMapOverview->Save();
2550 mGraphics->SetImage(mSurfaceMapOverview);
2551
2552 do {
2553 if (mSquad_Leader != INVALID_SPRITE_PTR) {
2554 ++word_3A016;
2555 word_3A016 &= 0x1F; // Original Value: 0x3F;
2556
2557 if (word_3A016 < 0x10) {
2558 mVideo_Draw_FrameDataPtr = mGraphics->GetSpriteData(eGFX_PSTUFF);
2559 mVideo_Draw_Rows = 0x10;
2560
2561 mVideo_Draw_FrameDataPtr += PLATFORM_BASED(0x46B8, ((113 * 40) + 6));
2562 mVideo_Draw_Columns = PLATFORM_BASED(0x10, 0x02);
2563
2564 mGraphics->Video_Draw_8();
2565 }
2566 else
2567 mSurfaceMapOverview->Restore();
2568 }
2569
2570 Mouse_Inputs_Get();
2571 if (!mStartParams->mDisableVideo) {
2572 mWindow->RenderShrunk(mSurfaceMapOverview);
2573 mWindow->FrameEnd();
2574 }
2575 if (mPhase_Aborted)
2576 break;
2577 Cycle_End();
2578
2579 } while (Mouse_Button_Left_Toggled() < 0);
2580
2581 mSurfaceMapOverview->Restore();
2582 mGraphics->SetImageOriginal();
2583
2584 mPhase_Aborted = false;
2585 }
2586
Map_Overview_Prepare()2587 void cFodder::Map_Overview_Prepare() {
2588
2589 if (mParams->mUnitTesting)
2590 return;
2591
2592 delete mSurfaceMapOverview;
2593 size_t Size = mMapLoaded->getWidth() < mMapLoaded->getHeight() ? mMapLoaded->getHeight() : mMapLoaded->getWidth();
2594 if ((Size * 16) * (Size * 16) >= 0x7FFFFFFF)
2595 return;
2596
2597 mSurfaceMapOverview = new cSurface(Size * 16, Size * 16);
2598 mSurfaceMapOverview->clearBuffer();
2599
2600 int16* MapPtr = (int16*)(mMap->data() + 0x60);
2601
2602 mSurfaceMapTop = mSurfaceMapLeft = 0;
2603
2604 if (mMapLoaded->getHeight() < mMapLoaded->getWidth()) {
2605 mSurfaceMapTop = (mMapLoaded->getWidth() / 2) - (mMapLoaded->getHeight() / 2);
2606 if (mSurfaceMapTop < 0)
2607 mSurfaceMapTop = 0;
2608 }
2609
2610 if (mMapLoaded->getWidth() < mMapLoaded->getHeight()) {
2611 mSurfaceMapLeft = (mMapLoaded->getHeight() / 2) - (mMapLoaded->getWidth() / 2);
2612 if (mSurfaceMapLeft < 0)
2613 mSurfaceMapLeft = 0;
2614 }
2615
2616 for (uint16 dx = 0; dx < mMapLoaded->getHeight(); ++dx) {
2617
2618 for (uint16 cx = 0; cx < mMapLoaded->getWidth(); ++cx, ++MapPtr) {
2619
2620 if (MapPtr < (int16*) mMap->data() || MapPtr >= (int16*) (mMap->data() + mMap->size()))
2621 continue;
2622
2623 mGraphics->MapOverview_Render_Tiles(*MapPtr & 0x1FF, cx + mSurfaceMapLeft, dx + mSurfaceMapTop);
2624 }
2625 }
2626
2627 }
2628
eventProcess(const cEvent & pEvent)2629 void cFodder::eventProcess(const cEvent& pEvent) {
2630 switch (pEvent.mType) {
2631
2632 case eEvent_KeyDown:
2633 keyProcess(pEvent.mButton, false);
2634 break;
2635
2636 case eEvent_KeyUp:
2637 keyProcess(pEvent.mButton, true);
2638 break;
2639
2640 case eEvent_MouseLeftDown:
2641 mMouse_EventLastPosition = pEvent.mPosition;
2642 mMouse_EventLastButtonsPressed |= 1;
2643 break;
2644
2645 case eEvent_MouseRightDown:
2646 mMouse_EventLastPosition = pEvent.mPosition;
2647 mMouse_EventLastButtonsPressed |= 2;
2648 break;
2649
2650 case eEvent_MouseLeftUp:
2651 mMouse_EventLastPosition = pEvent.mPosition;
2652 mMouse_EventLastButtonsPressed &= ~1;
2653 break;
2654
2655 case eEvent_MouseRightUp:
2656 mMouse_EventLastPosition = pEvent.mPosition;
2657 mMouse_EventLastButtonsPressed &= ~2;
2658 break;
2659
2660 case eEvent_MouseMove:
2661 mMouse_EventLastPosition = pEvent.mPosition;
2662 break;
2663
2664 case eEvent_MouseWheel:
2665 mMouse_EventLastWheel = pEvent.mPosition;
2666 break;
2667
2668 case eEvent_None:
2669 break;
2670
2671 case eEvent_Quit:
2672 Exit(0);
2673 break;
2674 }
2675 }
2676
eventsProcess()2677 void cFodder::eventsProcess() {
2678
2679 mMouse_EventLastWheel.Clear();
2680
2681 if (mParams->mDemoPlayback) {
2682 for (auto Event : mGame_Data.mDemoRecorded.GetEvents(mGame_Data.mDemoRecorded.mTick))
2683 eventProcess(Event);
2684
2685 } else {
2686 for (auto Event : *mWindow->EventGet()) {
2687 if (mParams->mDemoRecord) {
2688 if(Event.mType != eEventType::eEvent_MouseMove)
2689 mGame_Data.mDemoRecorded.AddEvent(mGame_Data.mDemoRecorded.mTick, Event);
2690 }
2691 eventProcess(Event);
2692 }
2693 }
2694
2695 mWindow->EventGet()->clear();
2696
2697 mGame_Data.mDemoRecorded.Tick();
2698 }
2699
keyProcess(uint8 pKeyCode,bool pPressed)2700 void cFodder::keyProcess(uint8 pKeyCode, bool pPressed) {
2701 if (pPressed)
2702 mKeyCode = pKeyCode;
2703 else
2704 mKeyCode = 0;
2705
2706 // Switch between platforms
2707 if (!mVersionPlatformSwitchDisabled) {
2708 mVersionPlatformSwitchDisabled = true;
2709 if ((mVersionDefault && mVersionDefault->isRetail()) || (mVersionCurrent && mVersionCurrent->isRetail())) {
2710
2711 if (pKeyCode == SDL_SCANCODE_F1 && pPressed) {
2712 mVersionDefault = mVersions->GetForCampaign(mVersionCurrent->mName, ePlatform::Amiga);
2713 mParams->mDefaultPlatform = ePlatform::Amiga;
2714 VersionSwitch(mVersionDefault);
2715 }
2716 if (pKeyCode == SDL_SCANCODE_F2 && pPressed) {
2717 mVersionDefault = mVersions->GetForCampaign(mVersionCurrent->mName, ePlatform::PC);
2718 mParams->mDefaultPlatform = ePlatform::PC;
2719 VersionSwitch(mVersionDefault);
2720 }
2721 }
2722 mVersionPlatformSwitchDisabled = false;
2723 }
2724
2725 if (pKeyCode == SDL_SCANCODE_F3 && pPressed) {
2726 if (mParams->mDemoRecord) {
2727 mStartParams->mDemoRecordResumeCycle = mGame_Data.mDemoRecorded.mTick - 80;
2728 mGame_Data.mGamePhase_Data.mIsComplete = true;
2729 mPhase_TryAgain = true;
2730 }
2731 }
2732
2733 if ((pKeyCode == SDL_SCANCODE_EQUALS && pPressed) || (pKeyCode == SDL_SCANCODE_KP_PLUS && pPressed))
2734 mWindow->WindowIncrease();
2735
2736 if ((pKeyCode == SDL_SCANCODE_MINUS && pPressed) || (pKeyCode == SDL_SCANCODE_KP_MINUS && pPressed))
2737 mWindow->WindowDecrease();
2738
2739 if (pKeyCode == SDL_SCANCODE_F11 && pPressed)
2740 mWindow->ToggleFullscreen();
2741
2742 if (pKeyCode == SDL_SCANCODE_ESCAPE && pPressed && mPhase_Aborted)
2743 mPhase_Aborted2 = true;
2744
2745 if (pKeyCode == SDL_SCANCODE_ESCAPE && pPressed) {
2746 mPhase_Aborted = true;
2747 mPhase_EscapeKeyAbort = true;
2748 }
2749 // In Mission and not on map overview
2750 if (mPhase_In_Progress && !mPhase_ShowMapOverview) {
2751
2752 if (pKeyCode == SDL_SCANCODE_LCTRL || pKeyCode == SDL_SCANCODE_RCTRL) {
2753 if (pPressed)
2754 mKeyControlPressed = -1;
2755 else
2756 mKeyControlPressed = 0;
2757 }
2758
2759 if (pKeyCode == SDL_SCANCODE_P && pPressed)
2760 mPhase_Paused = !mPhase_Paused;
2761
2762 if (pKeyCode == SDL_SCANCODE_SPACE && pPressed)
2763 ++mSquad_SwitchWeapon;
2764
2765 if (pKeyCode == SDL_SCANCODE_M && pPressed) {
2766 if (mPhase_Finished == false)
2767 mPhase_ShowMapOverview = -1;
2768 }
2769
2770 if (pKeyCode == SDL_SCANCODE_1 && pPressed) {
2771 if(mSquads_TroopCount[0])
2772 Squad_Select(0, false);
2773 }
2774
2775 if (pKeyCode == SDL_SCANCODE_2 && pPressed) {
2776 if(mSquads_TroopCount[1])
2777 Squad_Select(1, false);
2778 }
2779 if (pKeyCode == SDL_SCANCODE_3 && pPressed) {
2780 if(mSquads_TroopCount[2])
2781 Squad_Select(2, false);
2782 }
2783
2784 if (mParams->mCheatsEnabled) {
2785
2786 // Debug: Mission Complete
2787 if (pKeyCode == SDL_SCANCODE_F10 && pPressed) {
2788 mDebug_PhaseSkip = -1;
2789 }
2790
2791 // Debug: Make current squad invincible
2792 if (pKeyCode == SDL_SCANCODE_F9 && pPressed) {
2793 if (mSquad_Selected >= 0) {
2794 sSprite** Data28 = mSquads[mSquad_Selected];
2795 for (; *Data28 != INVALID_SPRITE_PTR;) {
2796
2797 sSprite* Data2C = *Data28++;
2798 Data2C->field_75 |= eSprite_Flag_Invincibility;
2799 }
2800 }
2801 }
2802 }
2803 }
2804 }
2805
Mouse_Setup()2806 void cFodder::Mouse_Setup() {
2807
2808 mMouse_EventLastButtonsPressed = 0;
2809 mButtonPressLeft = 0;
2810 mButtonPressRight = 0;
2811 mMouseButtonStatus = 0;
2812
2813 mMouseX = (getCameraWidth() / 2) - 9;
2814 mMouseY = (getCameraHeight() / 2) - 9;
2815 }
2816
Mouse_Cursor_Handle()2817 void cFodder::Mouse_Cursor_Handle() {
2818 static bool WasClicked = false;
2819 static bool CursorGrabbed = false;
2820 const cPosition WindowPos = mWindow->GetWindowPosition();
2821 const cDimension ScreenSize = mWindow->GetScreenSize();
2822 const cDimension WindowSize = mWindow->GetWindowSize();
2823 const cDimension scale = mWindow->GetScale();
2824
2825 mMouseButtonStatus = mMouse_EventLastButtonsPressed;
2826
2827 if (!mWindow->hasFocusEvent() && CursorGrabbed)
2828 CursorGrabbed = false;
2829
2830 if (mStartParams->mMouseAlternative) {
2831 mInputMouseX = (mMouse_EventLastPosition.mX / scale.getWidth()) + MOUSE_POSITION_X_ADJUST;
2832 mInputMouseY = (mMouse_EventLastPosition.mY / scale.getHeight()) + MOUSE_POSITION_Y_ADJUST;
2833 return;
2834 }
2835
2836 // Check if the system mouse is grabbed
2837 if (!CursorGrabbed) {
2838
2839 if (!mWindow->hasFocusEvent() || mWindow->isMouseInside()) {
2840 // Register mouse position even when not focused but cursor on window
2841 mInputMouseX = (mMouse_EventLastPosition.mX / scale.getWidth()) + MOUSE_POSITION_X_ADJUST;
2842 mInputMouseY = (mMouse_EventLastPosition.mY / scale.getHeight()) + MOUSE_POSITION_Y_ADJUST;
2843 }
2844
2845 // Check if the system cursor x/y is inside our window
2846 // and ensure the mouse button has been released before we focus
2847 if (mWindow->hasFocusEvent() && mWindow->isMouseInside() && !mWindow->isMouseButtonPressed_Global()) {
2848 WasClicked = true;
2849 CursorGrabbed = true;
2850
2851 if (!mWindow->isFullscreen()) {
2852 // Ensure X not too close to a border
2853 if (mInputMouseX <= MOUSE_POSITION_X_ADJUST)
2854 mInputMouseX = MOUSE_POSITION_X_ADJUST + 1;
2855 else if (mInputMouseX >= ScreenSize.getWidth() + MOUSE_POSITION_X_ADJUST - 1)
2856 mInputMouseX = ScreenSize.getWidth() + MOUSE_POSITION_X_ADJUST - 2;
2857
2858 // Ensure Y not too close to a border
2859 if (mInputMouseY <= MOUSE_POSITION_Y_ADJUST)
2860 mInputMouseY = MOUSE_POSITION_Y_ADJUST + 1;
2861 else if (mInputMouseY >= ScreenSize.getHeight() + MOUSE_POSITION_Y_ADJUST - 1)
2862 mInputMouseY = ScreenSize.getHeight() + MOUSE_POSITION_Y_ADJUST - 2;
2863 }
2864 }
2865 } else {
2866 cPosition BorderMouse;
2867
2868 if (!mWindow->isFullscreen()) {
2869 // Need to check if the game cursor is near an edge: top-left / top-right / bottom-left / bottom-right
2870 if ((mMouseX <= MOUSE_POSITION_X_ADJUST && mMouseY <= MOUSE_POSITION_Y_ADJUST) ||
2871 (mMouseX >= ScreenSize.getWidth() + MOUSE_POSITION_X_ADJUST - 1 && mMouseY <= MOUSE_POSITION_Y_ADJUST) ||
2872 (mMouseX <= MOUSE_POSITION_X_ADJUST && mMouseY >= ScreenSize.getHeight() + MOUSE_POSITION_Y_ADJUST - 1) ||
2873 (mMouseX >= ScreenSize.getWidth() + MOUSE_POSITION_X_ADJUST - 1 && mMouseY >= ScreenSize.getHeight() + MOUSE_POSITION_Y_ADJUST - 1)) {
2874 BorderMouse.mX = mMouseX <= MOUSE_POSITION_X_ADJUST ? WindowPos.mX - 1 : WindowPos.mX + WindowSize.getWidth() + 1;
2875 BorderMouse.mY = mMouseY <= MOUSE_POSITION_Y_ADJUST ? WindowPos.mY - 1 : WindowPos.mY + WindowSize.getHeight() + 1;
2876 }
2877 // Need to check if the game cursor is near a border on X axis
2878 else if (mMouseX <= MOUSE_POSITION_X_ADJUST || mMouseX >= ScreenSize.getWidth() + MOUSE_POSITION_X_ADJUST - 1) {
2879 BorderMouse.mX = mMouseX <= MOUSE_POSITION_X_ADJUST ? WindowPos.mX - 1 : WindowPos.mX + WindowSize.getWidth() + 1;
2880 BorderMouse.mY = WindowPos.mY + (mMouseY - MOUSE_POSITION_Y_ADJUST) * scale.getHeight();
2881 } // Need to check if the game cursor is near a border Y axis
2882 else if (mMouseY <= MOUSE_POSITION_Y_ADJUST || mMouseY >= ScreenSize.getHeight() + MOUSE_POSITION_Y_ADJUST - 1) {
2883 BorderMouse.mX = WindowPos.mX + (mMouseX - MOUSE_POSITION_X_ADJUST) * scale.getWidth();
2884 BorderMouse.mY = mMouseY <= MOUSE_POSITION_Y_ADJUST ? WindowPos.mY - 1 : WindowPos.mY + WindowSize.getHeight() + 1;
2885 }
2886
2887 // if yes set system cursor outside the border
2888 // if yes set system cursor outside the border
2889 if (BorderMouse.mX || BorderMouse.mY) {
2890 CursorGrabbed = false;
2891 mWindow->SetMousePosition(BorderMouse);
2892 return;
2893 }
2894 }
2895
2896 // hack to avoid moving cursor on window resizing
2897 if (mWindow->isResized()) {
2898 mWindow->ClearResized();
2899 } else {
2900 if (WasClicked) {
2901 if (!mWindow->isMouseButtonPressed_Global())
2902 WasClicked = false;
2903 } else {
2904 // Calc the distance from the cursor to the centre of the window
2905 const cPosition Diff = (mMouse_EventLastPosition - WindowSize.getCentre());
2906
2907 mInputMouseX = mMouseX + static_cast<int16>((Diff.mX / scale.getWidth()) * 1.5);
2908 mInputMouseY = mMouseY + static_cast<int16>((Diff.mY / scale.getHeight()) * 1.5);
2909 }
2910 }
2911
2912 // Set system cursor back to centre of window
2913 mWindow->SetMousePosition(WindowSize.getCentre() + WindowPos);
2914 }
2915 }
2916
Mouse_Inputs_Get()2917 void cFodder::Mouse_Inputs_Get() {
2918
2919
2920 if (mParams->mDemoPlayback) {
2921
2922 // Window_UpdateScreenSize();
2923
2924 auto State = mGame_Data.mDemoRecorded.GetState(mGame_Data.mDemoRecorded.mTick);
2925 if (State) {
2926 mInputMouseX = State->mInputMouseX;
2927 mInputMouseY = State->mInputMouseY;
2928
2929 mMouseButtonStatus = State->mMouseButtonStatus;
2930 }
2931 else {
2932 if(mGame_Data.mDemoRecorded.mTick > mGame_Data.mDemoRecorded.GetTotalTicks() + 100 )
2933 mPhase_Aborted = true;
2934 }
2935 }
2936 else {
2937 Mouse_Cursor_Handle();
2938 }
2939
2940 if (mParams->mDemoRecord)
2941
2942 mGame_Data.mDemoRecorded.AddState(mGame_Data.mDemoRecorded.mTick, cStateRecorded{ mInputMouseX, mInputMouseY, mMouseButtonStatus });
2943
2944 Mouse_ButtonCheck();
2945
2946 int16 Data4 = mInputMouseX;
2947
2948 if (mSidebar_SmallMode == 0)
2949 goto loc_13B3A;
2950
2951 if (Data4 >= MOUSE_POSITION_X_ADJUST + 16)
2952 goto loc_13B58;
2953
2954 goto loc_13B41;
2955
2956 loc_13B3A:;
2957 if (Data4 >= MOUSE_POSITION_X_ADJUST)
2958 goto loc_13B58;
2959
2960 loc_13B41:;
2961 if (mSidebar_SmallMode)
2962 Data4 = MOUSE_POSITION_X_ADJUST + 16;
2963 else
2964 Data4 = MOUSE_POSITION_X_ADJUST;
2965
2966 goto loc_13B66;
2967
2968 loc_13B58:;
2969
2970 if (Data4 > (int16)mWindow->GetScreenSize().getWidth() + MOUSE_POSITION_X_ADJUST - 1)
2971 Data4 = (int16)mWindow->GetScreenSize().getWidth() + MOUSE_POSITION_X_ADJUST - 1;
2972
2973 loc_13B66:;
2974 mMouseX = Data4;
2975
2976 int16 Data0 = mInputMouseY;
2977
2978 if (Data0 < MOUSE_POSITION_Y_ADJUST)
2979 Data0 = MOUSE_POSITION_Y_ADJUST;
2980 else {
2981
2982 if (Data0 > (int16)mWindow->GetScreenSize().getHeight() + MOUSE_POSITION_Y_ADJUST - 1)
2983 Data0 = (int16)mWindow->GetScreenSize().getHeight() + MOUSE_POSITION_Y_ADJUST - 1;
2984 }
2985
2986 mMouseY = Data0;
2987 }
2988
Mouse_ButtonCheck()2989 void cFodder::Mouse_ButtonCheck() {
2990
2991 mButtonPressLeft = 0;
2992 if (mMouseButtonStatus & 1) {
2993 mButtonPressLeft -= 1;
2994 if (mMouse_Button_Left_Toggle == 0) {
2995 mMouse_Button_Left_Toggle = -1;
2996 mMouse_Exit_Loop = true;
2997
2998 if (mButtonPressRight) {
2999 mMouse_Button_LeftRight_Toggle = true;
3000 mMouse_Button_LeftRight_Toggle2 = true;
3001 }
3002 }
3003
3004 }
3005 else {
3006 mMouse_Button_LeftRight_Toggle2 = false;
3007 mMouse_Button_Left_Toggle = 0;
3008 }
3009
3010 mButtonPressRight = 0;
3011 if (mMouseButtonStatus & 2) {
3012 mButtonPressRight -= 1;
3013 if (mMouse_Button_Right_Toggle == 0) {
3014 mSquad_Member_Fire_CoolDown_Override = true;
3015 mMouse_Button_Right_Toggle = -1;
3016 }
3017 }
3018 else {
3019 mMouse_Button_Right_Toggle = 0;
3020 }
3021
3022 }
3023
WindowTitleSet(bool pInMission)3024 void cFodder::WindowTitleSet(bool pInMission) {
3025 std::stringstream Title;
3026 Title << mWindowTitle.str();
3027
3028 if (pInMission && mGame_Data.mPhase_Current && mGame_Data.mMission_Current) {
3029 if (mVersionCurrent->isDemo() && mCustom_Mode != eCustomMode_Set ) {
3030 Title << " ( Mission: ";
3031 Title << mGame_Data.mPhase_Current->mName;
3032 }
3033 else {
3034 Title << " ( Mission: " << mGame_Data.mMission_Number;
3035 Title << " " << mGame_Data.mMission_Current->mName;
3036
3037 Title << " Phase: " << (mGame_Data.mMission_Phase) << " ";
3038
3039 if (mGame_Data.mMission_Current->NumberOfPhases() > 1) {
3040 Title << "of " << mGame_Data.mMission_Current->NumberOfPhases();
3041 Title << " " << mGame_Data.mPhase_Current->mName;
3042 }
3043 else
3044 Title << mGame_Data.mPhase_Current->mName;
3045 }
3046
3047 Title << " )";
3048 }
3049
3050 mWindow->SetWindowTitle(Title.str());
3051 }
3052
WindowTitleBaseSetup()3053 void cFodder::WindowTitleBaseSetup() {
3054
3055 mWindowTitle.str("");
3056 mWindowTitle << "Open Fodder";
3057
3058 if (mVersionCurrent) {
3059
3060 // Ensure we have a campaign
3061 if (mGame_Data.mCampaign.getName().size()) {
3062 if (mGame_Data.mCampaign.isCustom()) {
3063 mWindowTitle << ": Custom (" << mGame_Data.mCampaign.getName() << ")";
3064 } else {
3065 mWindowTitle << ": " << mGame_Data.mCampaign.getName();
3066 }
3067 }
3068 }
3069
3070 WindowTitleSet(mPhase_In_Progress);
3071 }
3072
3073 /**
3074 * This function loads a new version of the game, and is generally called on startup,
3075 * or AFTER a button on the campaign select screen is pushed
3076 *
3077 */
VersionSwitch(const sGameVersion * pVersion)3078 void cFodder::VersionSwitch(const sGameVersion* pVersion) {
3079 const sGameVersion* VersionPrevious = mVersionCurrent;
3080
3081 if (!pVersion)
3082 return;
3083
3084 if (mVersionCurrent == pVersion)
3085 return;
3086
3087 Image_FadeOut();
3088
3089 mVersionCurrent = pVersion;
3090
3091 WindowTitleBaseSetup();
3092
3093 // Sound must be released first, to unlock the audio device
3094 // But only if we actually have to change the sound object
3095 if (mVersionCurrent && VersionPrevious && !(mVersionCurrent->CanUseAmigaSound() && VersionPrevious->CanUseAmigaSound()))
3096 mSound = 0;
3097
3098 mResources = g_Resource = mVersionCurrent->GetResources();
3099 mGraphics = mVersionCurrent->GetGraphics();
3100
3101 if(!mSound)
3102 mSound = mVersionCurrent->GetSound();
3103
3104 if(!mResources) {
3105 std::cout << "Unknown Platform";
3106 exit(1);
3107 }
3108
3109 mGUI_Select_File_ShownItems = PLATFORM_BASED(4, 5);
3110
3111 Window_UpdateScreenSize();
3112
3113 mGraphics->Load_Sprite_Font();
3114 mGraphics->Load_Hill_Data();
3115 mGraphics->Load_pStuff();
3116
3117 if (mPhase_In_Progress) {
3118 mGraphics->SetActiveSpriteSheet(eGFX_IN_GAME);
3119
3120 // Reload Map Data
3121 Map_Load_Resources();
3122 Map_Overview_Prepare();
3123 mGraphics->MapTiles_Draw();
3124
3125 // Redraw sidebar
3126 mGUI_Sidebar_Setup = 0;
3127 while(mGUI_Sidebar_Setup>=0)
3128 GUI_Sidebar_Setup();
3129
3130 mSurface->palette_FadeTowardNew();
3131 Music_Play_Tileset();
3132 }
3133
3134 if(mRecruit_Screen_Active && mVersionCurrent->hasGfx(eGFX_HILL)) {
3135 Recruit_Prepare();
3136
3137 mRecruit_RenderedNext = mRecruit_Rendereds.begin();
3138 for (int i = 0; i < mGame_Data.mGamePhase_Data.mSoldiers_Required - mRecruit_Truck_Troops_ToEnter_Count; ++i) {
3139 Recruit_Sidebar_Render_SquadName();
3140 }
3141
3142 if (!mStartParams->mDisableSound)
3143 mSound->Music_Play(0);
3144 }
3145
3146 }
3147
getWindowWidth() const3148 int16 cFodder::getWindowWidth() const {
3149 if (!mParams->mWindowColumns) {
3150 if (mVersionCurrent)
3151 return 320;
3152
3153 return 352;
3154 }
3155
3156 return (int16) mParams->mWindowColumns * 16;
3157 }
3158
getSurfaceSize() const3159 cDimension cFodder::getSurfaceSize() const {
3160 if (!mParams->mWindowColumns || !mParams->mWindowRows) {
3161 if (mVersionCurrent)
3162 return mVersionCurrent->GetScreenSize();
3163
3164 return { 352, 364 };
3165 }
3166
3167 return { (unsigned int)(mParams->mWindowColumns + 2) * 16, (unsigned int)(mParams->mWindowRows + 2) * 16 };
3168 }
3169
getWindowSize() const3170 cDimension cFodder::getWindowSize() const {
3171
3172 if (!mParams->mWindowColumns || !mParams->mWindowRows) {
3173 if (mVersionCurrent)
3174 return mVersionCurrent->GetScreenSize();
3175
3176 return { 336, 348 };
3177 }
3178
3179 return { (unsigned int) mParams->mWindowColumns * 16, (unsigned int) mParams->mWindowRows * 16 };
3180 }
3181
getWindowRows() const3182 int16 cFodder::getWindowRows() const {
3183 if (!mParams->mWindowRows) {
3184 return 16;
3185 }
3186 return (int16) mParams->mWindowRows;
3187 }
3188
getWindowColumns() const3189 int16 cFodder::getWindowColumns() const {
3190 if (!mParams->mWindowColumns) {
3191 if (mVersionCurrent->isAmiga())
3192 return 21;
3193
3194 return 22;
3195 }
3196 return (int16) mParams->mWindowColumns;
3197 }
3198
getCameraWidth() const3199 int16 cFodder::getCameraWidth() const {
3200
3201 return ((getWindowWidth() - SIDEBAR_WIDTH));
3202 }
3203
getCameraHeight() const3204 int16 cFodder::getCameraHeight() const {
3205 if (!mParams->mWindowRows) {
3206 if (mVersionCurrent)
3207 return mVersionCurrent->GetScreenSize().mHeight;
3208
3209 return 364;
3210 }
3211
3212 return (int16) mParams->mWindowRows * 16;
3213 }
3214
DataNotFound()3215 void cFodder::DataNotFound() {
3216 g_Debugger->Error("No game data could be found, including the demos, have you installed the data pack?");
3217
3218 g_Debugger->Error("We are looking for the 'Data' directory in: ");
3219 for (auto path : g_ResourceMan->getAllPaths()) {
3220 g_Debugger->Error(path);
3221 }
3222
3223 g_Debugger->Error("Press enter to quit");
3224 std::cin.get();
3225 exit(1);
3226 }
3227
Prepare(std::shared_ptr<sFodderParameters> pParams)3228 void cFodder::Prepare(std::shared_ptr<sFodderParameters> pParams) {
3229 mParams = std::make_shared<sFodderParameters>(*pParams);
3230 mStartParams = std::make_shared<sFodderParameters>(*pParams);
3231
3232 g_ResourceMan->refresh();
3233
3234 if (!g_ResourceMan->isDataAvailable())
3235 DataNotFound();
3236
3237
3238 mWindow->InitWindow("Open Fodder");
3239 mWindow->SetWindowSize((int)mParams->mWindowScale);
3240
3241 mTile_BaseBlk = tSharedBuffer();
3242 mTile_SubBlk = tSharedBuffer();
3243
3244 mMap = tSharedBuffer();
3245
3246 mSidebar_Buffer_Size = 0x30 * getCameraHeight();
3247
3248 mSidebar_Back_Buffer = (uint16*) new uint8[mSidebar_Buffer_Size];
3249 mSidebar_Screen_Buffer = (uint16*) new uint8[mSidebar_Buffer_Size];
3250 mSidebar_Screen_BufferPtr = mSidebar_Screen_Buffer;
3251
3252 mBriefing_Render_1_Mode = -1;
3253
3254 mSurface = new cSurface( getSurfaceSize() );
3255 mSurface2 = new cSurface(getSurfaceSize() );
3256
3257 Sprite_Clear_All();
3258
3259 g_ScriptingEngine = std::make_shared<cScriptingEngine>();
3260 }
3261
Sprite_Count_HelicopterCallPads()3262 void cFodder::Sprite_Count_HelicopterCallPads() {
3263
3264 int16 Data0 = 0;
3265 for(auto& Sprite : mSprites) {
3266
3267 if (Sprite.field_18 == eSprite_Helicopter_CallPad)
3268 ++Data0;
3269 }
3270
3271 mHelicopterCallPadCount = Data0;
3272 mHelicopterCall_X = -1;
3273 }
3274
Mission_Set_Final_TimeRemaining()3275 void cFodder::Mission_Set_Final_TimeRemaining() {
3276 mMission_Final_TimeRemain = 0x64;
3277 mMission_Final_TimeToDie_Ticker = 0x28;
3278 }
3279
Sprite_HelicopterCallPad_Check()3280 void cFodder::Sprite_HelicopterCallPad_Check() {
3281 if (!mHelicopterCallPadCount)
3282 return;
3283
3284 if (mHelicopterCallPadCount != mHelicopterCallPadPressedCount)
3285 return;
3286
3287 if (mHelicopterCall_X >= 0)
3288 return;
3289
3290 if (!mTroop_InRange_Callpad || mTroop_InRange_Callpad == INVALID_SPRITE_PTR)
3291 return;
3292
3293 mHelicopterCall_X = mTroop_InRange_Callpad->field_0;
3294 mHelicopterCall_Y = mTroop_InRange_Callpad->field_4;
3295
3296 mHelicopterCall_Y += 0x28;
3297 }
3298
Mission_Final_Timer()3299 void cFodder::Mission_Final_Timer() {
3300
3301 if (mVersionCurrent->isRetail() && mVersionCurrent->isCannonFodder1()) {
3302
3303 if (!(mGame_Data.mMission_Number == 24 && mGame_Data.mMission_Phase == 6))
3304 return;
3305
3306 if (mMission_Final_TimeRemain)
3307 return;
3308
3309 if (!mMission_Final_TimeToAbort)
3310 mMission_Final_TimeToAbort = 0x28;
3311
3312 --mMission_Final_TimeToAbort;
3313 if (!mMission_Final_TimeToAbort)
3314 mPhase_Aborted = true;
3315
3316 if (!(mMission_EngineTicks & 3))
3317 Sprite_Create_RandomExplosion();
3318 }
3319 }
3320
Sprite_Create_RandomExplosion()3321 int16 cFodder::Sprite_Create_RandomExplosion() {
3322 int16 Data0 = 1;
3323 sSprite* Data2C = 0, *Data30 = 0;
3324
3325 if (Sprite_Get_Free_Max42(Data0, Data2C, Data30)) {
3326 Data0 = -1;
3327 return -1;
3328 }
3329
3330 Data2C->field_0 = mMapTile_TargetX >> 16;
3331 Data0 = tool_RandomGet() & 0xFF;
3332 Data0 += 0x0A;
3333
3334 Data2C->field_0 += Data0;
3335 Data2C->field_4 = mMapTile_TargetY >> 16;
3336
3337 Data0 = tool_RandomGet() & 0xFF;
3338 Data0 -= 0x14;
3339
3340 Data2C->field_4 += Data0;
3341 Data2C->field_18 = eSprite_Explosion;
3342 return Data0;
3343 }
3344
Phase_Paused()3345 void cFodder::Phase_Paused() {
3346 mSurface2->clearBuffer();
3347
3348 mGraphics->PaletteSet(mSurface2);
3349 mSurface2->surfaceSetToPaletteNew();
3350
3351 // Dim the current surface
3352 mSurface->paletteNew_SetToBlack();
3353
3354 // Draw to the secondary surface
3355 {
3356 mGraphics->SetImage(mSurface2);
3357
3358 mGraphics->SetActiveSpriteSheet(eGFX_BRIEFING);
3359 mString_GapCharID = 0x25;
3360
3361 String_CalculateWidth(320 + SIDEBAR_WIDTH, mFont_Underlined_Width, "GAME PAUSED");
3362 String_Print(mFont_Underlined_Width, 1, mGUI_Temp_X, 0x54, "GAME PAUSED");
3363
3364 mSurface2->draw();
3365 mString_GapCharID = 0;
3366 mGraphics->SetActiveSpriteSheet(eGFX_IN_GAME);
3367 mGraphics->SetImageOriginal();
3368 }
3369 }
3370
Phase_GameOver()3371 void cFodder::Phase_GameOver() {
3372 sSprite* Data24 = &mSprites[40];
3373 Sprite_Destroy(Data24);
3374
3375 sSprite* Data2C = &mSprites[41];
3376 Phase_TextSprite_Create_GameOver(Data2C);
3377 }
3378
Phase_TextSprite_Create_GameOver(sSprite * pData2C)3379 void cFodder::Phase_TextSprite_Create_GameOver(sSprite* pData2C) {
3380 Phase_TextSprite_Prepare(pData2C);
3381 pData2C->field_8 = 0xC1;
3382 pData2C->field_18 = eSprite_Text_GameOver;
3383
3384 if (!mStartParams->mDisableSound)
3385 mSound->Music_Play(8);
3386 }
3387
Mouse_DrawCursor()3388 void cFodder::Mouse_DrawCursor() {
3389 if (mParams->mDisableVideo)
3390 return;
3391
3392 mVideo_Draw_PosX = (mMouseX + mMouseX_Offset) + SIDEBAR_WIDTH;
3393 mVideo_Draw_PosY = (mMouseY + mMouseY_Offset) + 12;
3394
3395 if (mMouseSpriteNew >= 0) {
3396 mMouseSpriteCurrent = mMouseSpriteNew;
3397 mMouseSpriteNew = -1;
3398 }
3399
3400 if (mGraphics)
3401 mGraphics->Mouse_DrawCursor();
3402 }
3403
Sprite_Draw_Frame(sSprite * pDi,int16 pSpriteType,int16 pFrame,cSurface * pDestination)3404 void cFodder::Sprite_Draw_Frame(sSprite* pDi, int16 pSpriteType, int16 pFrame, cSurface *pDestination) {
3405 auto SheetData = Sprite_Get_Sheet(pSpriteType, pFrame);
3406
3407 mVideo_Draw_PaletteIndex = SheetData->mPalleteIndex & 0xFF;
3408 mVideo_Draw_FrameDataPtr = SheetData->GetGraphicsPtr();
3409
3410 mVideo_Draw_Columns = SheetData->mColCount;
3411 mVideo_Draw_Rows = SheetData->mRowCount - pDi->field_52;
3412
3413 #if defined(_OFED) || defined(_OFBOT)
3414 mMapTile_DrawY = (mMapTile_MovedVertical * 16) + mMapTile_RowOffset;
3415 mMapTile_DrawX = (mMapTile_MovedHorizontal * 16) + mMapTile_ColumnOffset;
3416
3417 mVideo_Draw_PosX = (int16)((SheetData->mModX + pDi->field_0) - mMapTile_DrawX);
3418 #else
3419 mVideo_Draw_PosX = (int16)((SheetData->mModX + pDi->field_0) - mMapTile_DrawX + 0x40);
3420 #endif
3421
3422 mVideo_Draw_PosY = (int16)((SheetData->mModY + pDi->field_4) - mVideo_Draw_Rows - pDi->field_20 - mMapTile_DrawY);
3423 mVideo_Draw_PosY += 0x10;
3424
3425 if (Sprite_OnScreen_Check()) {
3426 pDi->field_5C = 1;
3427 if(!mStartParams->mDisableVideo)
3428 mGraphics->Video_Draw_8(pDestination);
3429 }
3430 else
3431 pDi->field_5C = 0;
3432 }
3433
Sprite_OnScreen_Check()3434 bool cFodder::Sprite_OnScreen_Check() {
3435
3436 return mGraphics->Sprite_OnScreen_Check();
3437 }
3438
Sprites_Draw()3439 void cFodder::Sprites_Draw() {
3440
3441 for( auto& Sprite : mSprite_DrawList_Final) {
3442
3443 if (Sprite->field_24) {
3444 Sprite->field_24 = 0;
3445 Sprite->field_0 = -32768;
3446 mSprite_SpareUsed = 0;
3447 mSprite_SpareUsed2 = 0;
3448 }
3449 else {
3450 int16 Data0 = Sprite->field_8;
3451 int16 Data4 = Sprite->field_A;
3452 Sprite_Draw_Frame(Sprite, Data0, Data4);
3453 }
3454 }
3455 }
3456
Sprite_Map_Sound_Play(int16 & pData0)3457 void cFodder::Sprite_Map_Sound_Play(int16 &pData0) {
3458
3459 mSoundEffectToPlay_Set = pData0;
3460
3461 if (mSquad_Leader == INVALID_SPRITE_PTR)
3462 return;
3463
3464 goto loc_14D66;
3465 //seg002:05B0
3466 // UNUSED BLOCK
3467
3468 loc_14D66:;
3469 mSoundEffectToPlay = mSoundEffectToPlay_Set;
3470 }
3471
Sound_Play(sSprite * pSprite,int16 pSoundEffect,int16 pData8)3472 void cFodder::Sound_Play(sSprite* pSprite, int16 pSoundEffect, int16 pData8) {
3473
3474 if (mSoundDisabled)
3475 return;
3476
3477 //loc_14BD4
3478 pData8 = mCameraX >> 16;
3479 pData8 += (getCameraWidth() / 2) - 8;
3480
3481 if (pSprite != INVALID_SPRITE_PTR)
3482 pData8 -= pSprite->field_0;
3483
3484 int16 DataC = mCameraY >> 16;
3485 DataC += (getCameraHeight() - 8) / 2;
3486
3487 if (pSprite != INVALID_SPRITE_PTR)
3488 DataC -= pSprite->field_4;
3489
3490 int16 X = 0;
3491 int16 Y = 0;
3492
3493 Map_Get_Distance_BetweenPoints_Within_640(X, Y, pData8, DataC);
3494
3495 int Volume = 40;
3496 Volume -= (X / 16);
3497
3498 if (Volume <= 0)
3499 return;
3500
3501 if (!mStartParams->mDisableSound)
3502 mSound->Sound_Play(mMapLoaded->getTileType(), pSoundEffect, Volume);
3503 }
3504
Mission_Intro_Helicopter_Start()3505 void cFodder::Mission_Intro_Helicopter_Start() {
3506 mHelicopterPosX = 0x01500000;
3507 if (mVersionCurrent->isPC())
3508 mHelicopterPosY = 0x00260000;
3509 else
3510 mHelicopterPosY = 0x00300000;
3511
3512 mBriefing_Helicopter_Off1 = mBriefing_Helicopter_Offsets[0];
3513 mBriefing_Helicopter_Off2 = mBriefing_Helicopter_Offsets[1];
3514 mBriefing_Helicopter_Off3 = mBriefing_Helicopter_Offsets[2];
3515 mBriefing_Helicopter_Off4 = &mBriefing_Helicopter_Offsets[3];
3516 mBriefing_ParaHeli_Frame = 0;
3517 mBriefing_Helicopter_Moving = -1;
3518 word_428D8 = -1;
3519
3520 sub_1594F();
3521 }
3522
Briefing_Update_Helicopter()3523 void cFodder::Briefing_Update_Helicopter() {
3524 word_428B6 &= 0x1FE;
3525 uint16 bx = word_428B6;
3526
3527 int32 ax = mMap_Direction_Calculations[(bx / 2) & 0xFF];
3528
3529 ax >>= 2;
3530
3531 mHelicopterPosX += ax * word_428B8;
3532
3533 bx += 0x80;
3534 bx &= 0x1FE;
3535
3536 ax = mMap_Direction_Calculations[(bx / 2) & 0xFF];
3537 ax >>= 2;
3538 mHelicopterPosY += ax * word_428B8;
3539
3540 bx = mBriefing_Helicopter_Off1 - word_428B6;
3541 bx >>= 5;
3542 --bx;
3543 bx ^= 0x0F;
3544 bx &= 0x0F;
3545
3546 int16 al = mSprite_Direction_Frame_Unk[bx];
3547 al <<= 2;
3548 word_428B6 += al;
3549 word_428B6 &= 0x1FE;
3550
3551 if (mBriefing_Helicopter_Off2 != word_428B8) {
3552 if (word_428B8 >= mBriefing_Helicopter_Off2)
3553 word_428B8 -= 4;
3554 else
3555 word_428B8 += 4;
3556 }
3557
3558 if (mVersionCurrent->isCannonFodder1() && mVersionCurrent->isPC())
3559 mBriefing_ParaHeli_Frame += 1;
3560
3561 if (mBriefing_ParaHeli_Frame == 4)
3562 mBriefing_ParaHeli_Frame = 0;
3563
3564 --word_428BA;
3565 if (word_428BA <= 0)
3566 sub_1594F();
3567
3568 }
3569
sub_1594F()3570 void cFodder::sub_1594F() {
3571
3572 word_428B6 = mBriefing_Helicopter_Off1;
3573 word_428B8 = mBriefing_Helicopter_Off2;
3574 word_428BA = mBriefing_Helicopter_Off3;
3575 mBriefing_Helicopter_Off1 = *mBriefing_Helicopter_Off4++;
3576 mBriefing_Helicopter_Off2 = *mBriefing_Helicopter_Off4++;
3577 mBriefing_Helicopter_Off3 = *mBriefing_Helicopter_Off4++;
3578
3579 if (word_428B6 == -1) {
3580 mBriefing_Helicopter_Moving = 0;
3581 word_428D8 = 0;
3582
3583 mGraphics->mImageMissionIntro.CopyPalette(mGraphics->mPalette, 0x100, 0);
3584 mSurface->paletteNew_SetToBlack();
3585 }
3586
3587 }
3588
Mission_Intro_Draw_OpenFodder()3589 void cFodder::Mission_Intro_Draw_OpenFodder() {
3590 // Draw OPEN FODDER
3591 {
3592 mString_GapCharID = 0x25;
3593 String_Print_Large("OPEN FODDER", true, 0x01);
3594 }
3595
3596 // Draw Mission Name, or Map
3597 {
3598 int16 DrawY = 0xB5;
3599
3600 DrawY += PLATFORM_BASED(0, 0x16);
3601 //String_Print_Large("CAMPAIGNS", false, DrawY);
3602 }
3603 }
3604
Mission_Intro_Draw_Mission_Name()3605 void cFodder::Mission_Intro_Draw_Mission_Name() {
3606
3607 if (mGame_Data.mMission_Number == 0)
3608 Mission_Intro_Draw_OpenFodder();
3609 else
3610 Briefing_Draw_Mission_Title(0xB5);
3611 }
3612
3613 /**
3614 * Draw the Mission Name or the Map Name
3615 * Drawing at 0xB5 will cause the Mission Name to be drawn.
3616 *
3617 * @param pDrawAtY
3618 */
Briefing_Draw_Mission_Title(int16 pDrawAtY)3619 void cFodder::Briefing_Draw_Mission_Title(int16 pDrawAtY) {
3620
3621 // Draw MISSION xx
3622 {
3623 std::stringstream Mission;
3624 Mission << "MISSION ";
3625 mString_GapCharID = 0x25;
3626 Mission << tool_StripLeadingZero(std::to_string(mGame_Data.mMission_Number));
3627
3628 String_Print_Large(Mission.str(), true, 0);
3629 }
3630
3631 // Draw Mission Name, or Map
3632 {
3633 std::string Title;
3634
3635 if (pDrawAtY == 0xB5) {
3636 Title = mGame_Data.mMission_Current->GetName();
3637
3638 pDrawAtY += PLATFORM_BASED(0, 0x16);
3639
3640 }
3641 else {
3642 Title = mGame_Data.mPhase_Current->GetName();
3643 }
3644
3645 String_Print_Large(Title, true, pDrawAtY);
3646 }
3647 }
3648
Campaign_Select_DrawMenu(const char * pTitle,const char * pSubTitle)3649 void cFodder::Campaign_Select_DrawMenu(const char* pTitle, const char* pSubTitle) {
3650 size_t YOffset = PLATFORM_BASED(0, 25);
3651
3652 mGraphics->SetActiveSpriteSheet(eGFX_BRIEFING);
3653
3654 GUI_Element_Reset();
3655
3656 mString_GapCharID = 0x25;
3657 String_Print_Large(pTitle, true, 0x01);
3658 mString_GapCharID = 0x00;
3659
3660 String_Print_Large(pSubTitle, false, 0x18);
3661
3662 if (mGUI_Select_File_Count != mGUI_Select_File_ShownItems) {
3663 GUI_Button_Draw_Small("UP", 0x30);
3664 GUI_Button_Setup_Small(&cFodder::GUI_Button_Load_Up);
3665
3666 GUI_Button_Draw_Small("DOWN", 0x99 + YOffset);
3667 GUI_Button_Setup_Small(&cFodder::GUI_Button_Load_Down);
3668 }
3669
3670 GUI_Button_Draw_Small("EXIT", 0xB3 + YOffset);
3671 GUI_Button_Setup_Small(&cFodder::GUI_Button_Load_Exit);
3672
3673 GUI_Button_Draw_SmallAt("ABOUT", 0xA, 0xB3 + YOffset);
3674 GUI_Button_Setup_Small(&cFodder::GUI_Button_Show_About);
3675
3676
3677 int16 ItemCount = 0;
3678
3679 auto FileIT = mCampaignList.begin() + mGUI_Select_File_CurrentIndex;
3680
3681 for (; ItemCount < mGUI_Select_File_ShownItems && FileIT != mCampaignList.end(); ++ItemCount) {
3682
3683 GUI_Button_Draw_Small(FileIT->c_str(), 0x44 + (ItemCount * 0x15), 0xB2, 0xB3);
3684 GUI_Button_Setup_Small(&cFodder::GUI_Button_Filename);
3685 ++FileIT;
3686 }
3687 }
3688
3689 // Campaign Selection screen tile data
3690 static std::vector<unsigned char> mCampaignSelectMap_Jungle = {
3691 0x18, 0x01, 0x8b, 0x01, 0x8b, 0x01, 0x8b, 0x01, 0x8b, 0x01, 0x8b, 0x01, 0x8b, 0x01, 0x8b, 0x01, 0x8b, 0x01, 0x8b, 0x01, 0x8b, 0x01, 0x6c, 0x01, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7c, 0x00, 0x7c, 0x00, 0x7b, 0x00, 0x7c, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0xd1, 0x00, 0x6a, 0x01, 0x30, 0x01, 0x6b, 0x01, 0x8b,
3692 0x01, 0x8b, 0x01, 0x8b, 0x01, 0x8b, 0x01, 0x5a, 0x01, 0x8b, 0x01, 0x8b, 0x01, 0x08, 0x01, 0x7c, 0x00, 0x7b, 0x00, 0x7c, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x4d, 0x01, 0x4e, 0x01, 0x7c, 0x00, 0x19, 0x01, 0x8b, 0x01, 0x8b, 0x01, 0x8b, 0x01, 0x8b, 0x01,
3693 0x8b, 0x01, 0x8b, 0x01, 0x8b, 0x01, 0x1b, 0x01, 0x7b, 0x00, 0x7b, 0x00, 0x7c, 0x00, 0x10, 0x10, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x60, 0x01, 0x61, 0x01, 0x62, 0x01, 0x7b, 0x00, 0x7b, 0x00, 0xf3, 0x00, 0x5a, 0x01, 0x46, 0x01, 0x8b, 0x01, 0x8b, 0x01, 0x8b, 0x01, 0x8b, 0x01, 0x8b, 0x01, 0x1b,
3694 0x01, 0x7b, 0x00, 0x7c, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x74, 0x01, 0x75, 0x01, 0x76, 0x01, 0x77, 0x01, 0x7b, 0x00, 0x0a, 0x01, 0x5a, 0x01, 0x46, 0x01, 0x8b, 0x01, 0x5a, 0x01, 0x8b, 0x01, 0x5a, 0x01, 0x8b, 0x01, 0x8b, 0x01, 0x1a, 0x01, 0x7b, 0x00, 0x7c, 0x00, 0x7b, 0x00,
3695 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x88, 0x01, 0x89, 0x01, 0x8a, 0x01, 0x10, 0x10, 0x00, 0x00, 0x32, 0x01, 0x8b, 0x01, 0x46, 0x01, 0x8b, 0x01, 0x8b, 0x01, 0x8b, 0x01, 0x5a, 0x01, 0x8b, 0x01, 0x8b, 0x01, 0x8b, 0x01, 0xf4, 0x00, 0x7b, 0x00, 0x7c, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b,
3696 0x00, 0x7b, 0x00, 0x7b, 0x00, 0xf0, 0x00, 0x05, 0x01, 0x8b, 0x01, 0x46, 0x01, 0x46, 0x01, 0x46, 0x01, 0x8b, 0x01, 0x8b, 0x01, 0x8b, 0x01, 0x8b, 0x01, 0x8b, 0x01, 0x06, 0x01, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7c, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0xf1, 0x00, 0x8b, 0x01,
3697 0x8b, 0x01, 0x46, 0x01, 0x8b, 0x01, 0x8b, 0x01, 0x8b, 0x01, 0x46, 0x01, 0x8b, 0x01, 0x8b, 0x01, 0xf2, 0x00, 0x7c, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7c, 0x00, 0x7b, 0x00, 0x7c, 0x00, 0x05, 0x01, 0x8b, 0x01, 0x5a, 0x01, 0x5a, 0x01, 0x8b, 0x01, 0x8b, 0x01, 0x8b,
3698 0x01, 0x8b, 0x01, 0x8b, 0x01, 0x8b, 0x01, 0x6c, 0x01, 0x7c, 0x00, 0x7c, 0x00, 0x7b, 0x00, 0xf6, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x10, 0x10, 0xf1, 0x00, 0x8b, 0x01, 0x8b, 0x01, 0x8b, 0x01, 0x46, 0x01, 0x8b, 0x01, 0x8b, 0x01, 0x8b, 0x01, 0x8b, 0x01, 0x8b, 0x01, 0x8b, 0x01, 0x06, 0x01,
3699 0x7c, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x8c, 0x00, 0x0a, 0x01, 0x8b, 0x01, 0x8b, 0x01, 0x46, 0x01, 0x8b, 0x01, 0x46, 0x01, 0x46, 0x01, 0x8b, 0x01, 0x8b, 0x01, 0x8b, 0x01, 0x1c, 0x01, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b,
3700 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x6f, 0x01, 0x0a, 0x01, 0x8b, 0x01, 0x8b, 0x01, 0x8b, 0x01, 0x46, 0x01, 0x8b, 0x01, 0x46, 0x01, 0x8b, 0x01, 0x8b, 0x01, 0x1d, 0x01, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x10, 0x10, 0x7b, 0x00, 0xf0, 0x00,
3701 0x05, 0x01, 0x8b, 0x01, 0x8b, 0x01, 0x8b, 0x01, 0x8b, 0x01, 0x46, 0x01, 0x8b, 0x01, 0x8b, 0x01, 0xf2, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x36, 0x01, 0x37, 0x01, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x68, 0x01, 0x69, 0x01, 0x8b, 0x01, 0x8b, 0x01, 0x8b, 0x01, 0x46, 0x01, 0x46,
3702 0x01, 0x8b, 0x01, 0x8b, 0x01, 0x8b, 0x01, 0x6c, 0x01, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x69, 0x01, 0x8b, 0x01, 0x8b, 0x01, 0x8b, 0x01, 0x5a, 0x01, 0x8b, 0x01, 0x46, 0x01, 0x8b, 0x01, 0x8b, 0x01, 0x8b, 0x01, 0x8b, 0x01, 0x08, 0x01,
3703 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00
3704 };
3705
3706 static std::vector<unsigned char> mCampaignSelectMap_AF = {
3707 0x14, 0x00, 0x14, 0x00, 0x50, 0x00, 0x72, 0x00, 0x72, 0x00, 0x72, 0x00, 0x72, 0x00, 0x72, 0x00, 0x72, 0x00, 0x72, 0x00, 0x72, 0x00, 0x5b, 0x00, 0x14, 0x00, 0x14, 0x00, 0x14, 0x00, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x00, 0x3d, 0x00, 0x14, 0x00, 0x14, 0x00, 0x50, 0x00, 0x72, 0x00, 0x72, 0x00, 0x72,
3708 0x00, 0x72, 0x00, 0x73, 0x00, 0x72, 0x00, 0x72, 0x00, 0x72, 0x00, 0x72, 0x00, 0x81, 0x00, 0x29, 0x00, 0x14, 0x00, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x00, 0x14, 0x00, 0x14, 0x00, 0x83, 0x00, 0x72, 0x00, 0x72, 0x00, 0x72, 0x00, 0x72, 0x00, 0x72, 0x00, 0x72, 0x00, 0x72, 0x00, 0x72, 0x00,
3709 0x72, 0x00, 0x72, 0x00, 0x71, 0x00, 0x14, 0x00, 0x14, 0x00, 0x9a, 0x00, 0x9b, 0x00, 0x00, 0x00, 0x14, 0x00, 0x14, 0x00, 0x14, 0x00, 0x14, 0x00, 0x5d, 0x00, 0x72, 0x00, 0x72, 0x00, 0x72, 0x00, 0x72, 0x00, 0x72, 0x00, 0x72, 0x00, 0x72, 0x00, 0x72, 0x00, 0x72, 0x00, 0x72, 0x00, 0x5a, 0x00, 0x14, 0x00, 0x0c,
3710 0x00, 0xae, 0x00, 0xaf, 0x00, 0x00, 0x00, 0x14, 0x00, 0x14, 0x00, 0x14, 0x00, 0x14, 0x00, 0x14, 0x00, 0x5c, 0x00, 0x72, 0x00, 0x72, 0x00, 0x72, 0x00, 0x72, 0x00, 0x72, 0x00, 0x72, 0x00, 0x72, 0x00, 0x72, 0x00, 0x5a, 0x00, 0x14, 0x00, 0x14, 0x00, 0x0b, 0x00, 0xc2, 0x00, 0xc3, 0x00, 0x00, 0x00, 0x00, 0x00,
3711 0x14, 0x00, 0x14, 0x00, 0x14, 0x00, 0x14, 0x00, 0x14, 0x00, 0x5c, 0x00, 0x72, 0x00, 0x72, 0x00, 0x72, 0x00, 0x72, 0x00, 0x72, 0x00, 0x72, 0x00, 0x72, 0x00, 0x81, 0x00, 0x28, 0x00, 0x14, 0x00, 0x14, 0x00, 0x07, 0x00, 0x07, 0x00, 0x04, 0x00, 0x14, 0x00, 0x14, 0x00, 0x14, 0x00, 0x14, 0x00, 0x14, 0x00, 0x14,
3712 0x00, 0x14, 0x00, 0x70, 0x00, 0x72, 0x00, 0x72, 0x00, 0x72, 0x00, 0x72, 0x00, 0x72, 0x00, 0x72, 0x00, 0x94, 0x00, 0x14, 0x00, 0x14, 0x00, 0x14, 0x00, 0x14, 0x00, 0x14, 0x00, 0x14, 0x00, 0x14, 0x00, 0x14, 0x00, 0x14, 0x00, 0x14, 0x00, 0x14, 0x00, 0x14, 0x00, 0x14, 0x00, 0x97, 0x00, 0x72, 0x00, 0x72, 0x00,
3713 0x72, 0x00, 0x72, 0x00, 0x72, 0x00, 0x72, 0x00, 0x56, 0x00, 0x3d, 0x00, 0x14, 0x00, 0x14, 0x00, 0x14, 0x00, 0x14, 0x00, 0x14, 0x00, 0x14, 0x00, 0x14, 0x00, 0x14, 0x00, 0x14, 0x00, 0x14, 0x00, 0x52, 0x00, 0x53, 0x00, 0x72, 0x00, 0x72, 0x00, 0x72, 0x00, 0x72, 0x00, 0x72, 0x00, 0x72, 0x00, 0x72, 0x00, 0x72,
3714 0x00, 0x59, 0x00, 0x14, 0x10, 0x14, 0x00, 0x14, 0x00, 0x14, 0x00, 0x14, 0x00, 0x14, 0x00, 0x14, 0x00, 0x14, 0x00, 0x14, 0x00, 0x50, 0x00, 0x72, 0x00, 0x72, 0x00, 0x72, 0x00, 0x72, 0x00, 0x72, 0x00, 0x72, 0x00, 0x73, 0x00, 0x72, 0x00, 0x72, 0x00, 0x72, 0x00, 0x72, 0x00, 0x81, 0x00, 0x14, 0x10, 0x14, 0x00,
3715 0x14, 0x00, 0x14, 0x00, 0x14, 0x00, 0x14, 0x00, 0x14, 0x00, 0x50, 0x00, 0x72, 0x00, 0x72, 0x00, 0x72, 0x00, 0x72, 0x00, 0x72, 0x00, 0x72, 0x00, 0x72, 0x00, 0x72, 0x00, 0x72, 0x00, 0x72, 0x00, 0x72, 0x00, 0x72, 0x00, 0x5a, 0x00, 0x14, 0x00, 0x14, 0x00, 0x14, 0x00, 0x14, 0x00, 0x14, 0x00, 0x14, 0x00, 0x50,
3716 0x00, 0x72, 0x00, 0x72, 0x00, 0x72, 0x00, 0x72, 0x00, 0x72, 0x00, 0x73, 0x00, 0x73, 0x00, 0x73, 0x00, 0x73, 0x00, 0x72, 0x00, 0x72, 0x00, 0x72, 0x00, 0x80, 0x00, 0x14, 0x00, 0x0c, 0x00, 0x11, 0x00, 0x11, 0x00, 0x0e, 0x00, 0x14, 0x00, 0x14, 0x00, 0x82, 0x00, 0x72, 0x00, 0x72, 0x00, 0x72, 0x00, 0x72, 0x00,
3717 0x72, 0x00, 0x73, 0x00, 0x72, 0x00, 0x72, 0x00, 0x72, 0x00, 0x72, 0x00, 0x72, 0x00, 0x72, 0x00, 0x71, 0x00, 0x14, 0x00, 0x18, 0x00, 0x23, 0x00, 0x24, 0x00, 0x16, 0x00, 0x14, 0x00, 0x14, 0x00, 0x96, 0x00, 0x72, 0x00, 0x72, 0x00, 0x72, 0x00, 0x72, 0x00, 0x72, 0x00, 0x72, 0x00, 0x72, 0x00, 0x72, 0x00, 0x72,
3718 0x00, 0x72, 0x00, 0x72, 0x00, 0x72, 0x00, 0x94, 0x00, 0x14, 0x00, 0x0b, 0x00, 0x07, 0x00, 0x07, 0x00, 0x04, 0x00, 0x14, 0x00, 0x14, 0x00, 0x14, 0x00, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x64, 0x00, 0x64, 0x00, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10,
3719 0x10, 0x10, 0x0b, 0x00, 0x10, 0x10, 0x07, 0x00, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10
3720 };
3721
Campaign_Select_Setup()3722 void cFodder::Campaign_Select_Setup() {
3723 mCampaignList.clear();
3724
3725 mPhase_In_Progress = true;
3726 mPhase_Aborted = false;
3727 mGUI_SaveLoadAction = 0;
3728
3729 {
3730 for (auto& Name : mVersions->GetCampaignNames()) {
3731
3732 if (g_ResourceMan->isCampaignAvailable(Name) || Name == "Single Map" || Name == "Random Map")
3733 mCampaignList.push_back(Name);
3734 }
3735 }
3736
3737 {
3738 auto Files = g_ResourceMan->GetCampaigns();
3739
3740 // Append all custom campaigns to the list
3741 for (auto& File : Files) {
3742 size_t Pos = File.find_first_of(".");
3743 std::string FileName = File.substr(0, Pos);
3744
3745 // Don't add known campaigns
3746 if (mVersions->isCampaignKnown(FileName))
3747 continue;
3748
3749 mCampaignList.push_back(FileName);
3750 }
3751 }
3752
3753 mGUI_Select_File_CurrentIndex = 0;
3754 mGUI_Select_File_Count = (int16)mCampaignList.size();
3755
3756
3757
3758 // Create the title screen depending on which data is loaded
3759 if (mVersionCurrent->isRetail()) {
3760 sMapParams Params(0x15, 0x0F, eTileTypes_Jungle, eTileSub_0);
3761 Map_Create(Params);
3762 std::memcpy(mMap->data() + 0x60, mCampaignSelectMap_Jungle.data(), mMap->size() - 0x60);
3763 }
3764 else {
3765 sMapParams Params(0x15, 0x0F, eTileTypes_AFX, eTileSub_0);
3766 Map_Create(Params);
3767 std::memcpy(mMap->data() + 0x60, mCampaignSelectMap_AF.data(), mMap->size() - 0x60);
3768 }
3769
3770 Campaign_Select_Sprite_Prepare();
3771
3772 if (mGUI_SaveLoadAction != 3) {
3773 mSurface->palette_FadeTowardNew();
3774 Mouse_Setup();
3775 }
3776 mGUI_SaveLoadAction = 0;
3777
3778 mGraphics->PaletteSet();
3779 mSurface->Save();
3780
3781 mMouseSpriteNew = eSprite_pStuff_Mouse_Target;
3782 mDemo_ExitMenu = 0;
3783
3784 Camera_Reset();
3785 }
3786
Campaign_Select_File(const char * pTitle,const char * pSubTitle,const char * pPath,const char * pType,eDataType pData)3787 std::string cFodder::Campaign_Select_File(const char* pTitle, const char* pSubTitle, const char* pPath, const char* pType, eDataType pData) {
3788
3789 Campaign_Select_Setup();
3790
3791 do {
3792
3793 Campaign_Select_File_Loop(pTitle, pSubTitle);
3794
3795 } while (mGUI_SaveLoadAction == 3);
3796
3797 mPhase_In_Progress = false;
3798
3799 if (mGUI_SaveLoadAction == 1)
3800 return "";
3801
3802 return mCampaignList[mGUI_Select_File_CurrentIndex + mGUI_Select_File_SelectedFileIndex];
3803 }
3804
3805
3806
Campaign_Selection()3807 void cFodder::Campaign_Selection() {
3808 mPhase_Complete = false;
3809
3810 Phase_EngineReset();
3811 GameData_Reset();
3812 mMap_Destroy_Tiles.clear();
3813
3814 Image_FadeOut();
3815
3816 mGraphics->PaletteSet();
3817
3818 mMouseSpriteNew = eSprite_pStuff_Mouse_Target;
3819 mMouseX_Offset = -8;
3820 mMouseY_Offset = -8;
3821
3822 mGraphics->SetActiveSpriteSheet(eGFX_BRIEFING);
3823
3824 mCustom_Mode = eCustomMode_None;
3825
3826 std::string CampaignFile = Campaign_Select_File("OPEN FODDER", "SELECT CAMPAIGN", "", "*.ofc", eDataType::eCampaign);
3827
3828 // Exit Pressed?
3829 if (mGUI_SaveLoadAction == 1 || mGUI_SaveLoadAction == 4 || !CampaignFile.size()) {
3830
3831 // Return to custom menu
3832 mDemo_ExitMenu = 1;
3833 mCustom_Mode = eCustomMode_None;
3834
3835 return;
3836 }
3837
3838 // Find a data version to use with this campaign
3839 // If no version is found, we use the currently loaded one
3840 {
3841 const sGameVersion* Version = mVersions->GetForCampaign(CampaignFile, mVersionCurrent->mPlatform);
3842
3843 if (!Version) {
3844 Version = mVersions->GetForCampaign(CampaignFile);
3845 }
3846
3847 // Load a new version?
3848 if (Version && Version != mVersionCurrent) {
3849 VersionSwitch(Version);
3850 }
3851
3852 // Set the default/starting version
3853 mVersionDefault = mVersionCurrent;
3854
3855 // Single Map Mode?
3856 if (CampaignFile == "Single Map" || CampaignFile == "Random Map") {
3857
3858 mGame_Data.mCampaign.SetSingleMapCampaign();
3859 mCustom_Mode = eCustomMode_Map;
3860 return;
3861
3862 // If no version, it must be a custom campaign
3863 }
3864 else if (!Version) {
3865
3866 // If version is currently XMAS, it means no retail is available
3867 if (mVersionCurrent->isAmigaXmas()) {
3868
3869 VersionSwitch(mVersions->GetForCampaign("Amiga Action"));
3870
3871 // Set the default/starting version
3872 mVersionDefault = mVersions->GetForCampaign("Amiga Action");
3873 }
3874
3875 mCustom_Mode = eCustomMode_Set;
3876 }
3877 }
3878
3879 // Load the campaign
3880 if (Campaign_Load(CampaignFile) == true) {
3881
3882 //
3883 if (mVersionCurrent->isCustom()) {
3884 mDemo_ExitMenu = 1;
3885 mCustom_ExitMenu = 1;
3886 }
3887
3888 WindowTitleBaseSetup();
3889 return;
3890 }
3891
3892 mDemo_ExitMenu = 1;
3893 mCustom_Mode = eCustomMode_None;
3894 }
3895
Campaign_Select_Sprite_Prepare()3896 void cFodder::Campaign_Select_Sprite_Prepare() {
3897
3898 int16 x = 0;
3899
3900 Sprite_Clear_All();
3901
3902 Phase_SquadPrepare();
3903
3904 mSquad_CurrentVehicle = &mSprites[x];
3905 mSprites[x].field_0 = 0xe6;
3906 mSprites[x].field_4 = 0xcd;
3907 mSprites[x].field_8 = 0xD2;
3908 mSprites[x].field_A = 5;
3909 mSprites[x].field_52 = 0;
3910 mSprites[x].field_20 = 0;
3911 mSprites[x].field_18 = eSprite_Turret_Missile_Human;
3912 mSprites[x++].field_6F = eVehicle_Turret_Missile;
3913
3914 mSprites[x].field_0 = tool_RandomGet() & 0xFF;
3915 mSprites[x].field_4 = tool_RandomGet() & 0xff;
3916 mSprites[x].field_8 = 6;
3917 mSprites[x].field_A = 0;
3918 mSprites[x].field_52 = 0;
3919 mSprites[x].field_20 = 0;
3920 mSprites[x++].field_18 = eSprite_Civilian_Spear;
3921
3922 mSprites[x].field_0 = 0xff;
3923 mSprites[x].field_4 = 16 + (tool_RandomGet() % 0x60);
3924 mSprites[x].field_8 = 2;
3925 mSprites[x].field_A = 0;
3926 mSprites[x].field_52 = 0;
3927 mSprites[x].field_20 = 0;
3928 mSprites[x++].field_18 = eSprite_Bird_Left;
3929
3930 mSprites[x].field_0 = 0;
3931 mSprites[x].field_4 = 16 + (tool_RandomGet() % 0xc0);
3932 mSprites[x].field_8 = 2;
3933 mSprites[x].field_A = 0;
3934 mSprites[x].field_52 = 0;
3935 mSprites[x].field_20 = 0;
3936 mSprites[x++].field_18 = eSprite_Bird_Left;
3937
3938 mSprites[x].field_0 = 185;
3939 mSprites[x].field_4 = 19;
3940 mSprites[x].field_8 = 2;
3941 mSprites[x].field_A = 0;
3942 mSprites[x].field_52 = 0;
3943 mSprites[x].field_20 = 0;
3944 mSprites[x++].field_18 = eSprite_Hostage;
3945
3946 mSprites[x].field_0 = 100;
3947 mSprites[x].field_4 = 0xd0;
3948 mSprites[x].field_8 = 2;
3949 mSprites[x].field_A = 0;
3950 mSprites[x].field_52 = 0;
3951 mSprites[x].field_20 = 0;
3952 mSprites[x++].field_18 = eSprite_Floating_Dead_Soldier;
3953
3954 mSprites[x].field_0 = 220;
3955 mSprites[x].field_4 = 60;
3956 mSprites[x].field_8 = 2;
3957 mSprites[x].field_A = 0;
3958 mSprites[x].field_52 = 0;
3959 mSprites[x].field_20 = 0;
3960 mSprites[x++].field_18 = eSprite_BoilingPot;
3961
3962 mSprites[x].field_0 = 220;
3963 mSprites[x].field_4 = 60;
3964 mSprites[x].field_8 = 2;
3965 mSprites[x].field_A = 0;
3966 mSprites[x].field_52 = 0;
3967 mSprites[x].field_20 = 0;
3968 mSprites[x++].field_18 = eSprite_Null;
3969
3970 mSquad_Leader = mSquad_CurrentVehicle;
3971
3972 word_3AA1D = word_3BED5[0];
3973
3974 if(mMapLoaded->getTileType() == eTileTypes_Jungle)
3975 Map_Add_Structure(mStructuresBarracksWithSoldier[mMapLoaded->getTileType()], 4, 2);
3976
3977 if(mMapLoaded->getTileType() == eTileTypes_AFX)
3978 Map_Add_Structure(mStructuresBarracksWithSoldier[mMapLoaded->getTileType()], 2, 5);
3979 }
3980
Campaign_Select_File_Cycle(const char * pTitle,const char * pSubTitle)3981 void cFodder::Campaign_Select_File_Cycle(const char* pTitle, const char* pSubTitle) {
3982 static int16 Timedown = 0;
3983
3984 mGraphics->SetActiveSpriteSheet(eGFX_IN_GAME);
3985 Sprite_Frame_Modifier_Update();
3986 Mission_Sprites_Handle();
3987
3988 mSurface->clearBuffer();
3989 MapTiles_Draw();
3990 Sprites_Draw();
3991
3992 Campaign_Select_DrawMenu(pTitle, pSubTitle);
3993
3994
3995 if (mSurface->isPaletteAdjusting())
3996 mSurface->palette_FadeTowardNew();
3997
3998 Mouse_Inputs_Get();
3999 Mouse_DrawCursor();
4000
4001 if (Timedown)
4002 --Timedown;
4003
4004 if (mMouse_Button_Left_Toggle && !Timedown) {
4005 Vehicle_Input_Handle();
4006
4007 mMouse_Button_Left_Toggle = 0;
4008 mSprites[0].field_57 = -1;
4009 mSprites[0].field_2E = mSquad_Leader->field_26 + 10;
4010 mSprites[0].field_30 = mSquad_Leader->field_28 - 18;
4011
4012 Timedown = 10;
4013 }
4014
4015 if (mPhase_Aborted)
4016 GUI_Button_Load_Exit();
4017
4018 if (mMouse_Button_Left_Toggle)
4019 GUI_Handle_Element_Mouse_Check(mGUI_Elements);
4020
4021 GUI_Button_Load_MouseWheel();
4022 Video_SurfaceRender();
4023 Cycle_End();
4024 }
4025
Campaign_Select_File_Loop(const char * pTitle,const char * pSubTitle)4026 void cFodder::Campaign_Select_File_Loop(const char* pTitle, const char* pSubTitle) {
4027
4028
4029 do {
4030 Campaign_Select_File_Cycle(pTitle, pSubTitle);
4031
4032 } while (mGUI_SaveLoadAction <= 0);
4033
4034 mPhase_Aborted = false;
4035
4036 if (mGUI_SaveLoadAction == 3)
4037 return;
4038
4039 Image_FadeOut();
4040 }
4041
4042 /**
4043 * Display a list of custom maps
4044 */
Custom_ShowMapSelection()4045 void cFodder::Custom_ShowMapSelection() {
4046 // If demo data is loaded, we need to enture a retail release is loaded for the menu draw data
4047 if (mVersionCurrent->isDemo())
4048 VersionSwitch(mVersionDefault);
4049
4050 Image_FadeOut();
4051 mGraphics->PaletteSet();
4052
4053 std::string File = mParams->mSingleMap;
4054
4055 if (!File.size()) {
4056 auto Maps = g_ResourceMan->GetMaps();
4057 File = GUI_Select_File("SELECT MAP", {}, Maps);
4058 // Exit Pressed?
4059 if (mGUI_SaveLoadAction == 1 || !File.size()) {
4060
4061 // Return to custom menu
4062 mDemo_ExitMenu = 1;
4063 mCustom_Mode = eCustomMode_None;
4064
4065 return;
4066 }
4067 }
4068
4069 mGame_Data.mCampaign.LoadCustomMapFromPath(g_ResourceMan->GetMapPath(File));
4070
4071 mGame_Data.mMission_Phases_Remaining = 1;
4072 mGame_Data.mMission_Number = 0;
4073 mGame_Data.mMission_Phase = 0;
4074 mGame_Data.Phase_Next();
4075
4076 mDemo_ExitMenu = 1;
4077 mCustom_ExitMenu = 1;
4078 mCustom_Mode = eCustomMode_Map;
4079 }
4080
Demo_Amiga_ShowMenu()4081 bool cFodder::Demo_Amiga_ShowMenu() {
4082 mSound->Music_Stop();
4083
4084 if(mVersionCurrent->isAmigaNotVeryFestive() || mVersionCurrent->isAmigaAlienLevels())
4085 mGraphics->Load_And_Draw_Image("VMENU", 32);
4086 else
4087 mGraphics->Load_And_Draw_Image("apmenu.lbm", 32);
4088
4089 // Amiga Demos have a different cursor palette
4090 GetGraphics<cGraphics_Amiga>()->SetCursorPalette(0x10);
4091 mWindow->SetScreenSize(mVersionCurrent->GetSecondScreenSize());
4092
4093 mGUI_Mouse_Modifier_Y = 4;
4094
4095 Menu_Loop(
4096 [this]() {
4097 if (mButtonPressLeft) {
4098 if (mVersionCurrent->isAmigaXmas())
4099 GUI_Element_Mouse_Over(mAfx_Buttons);
4100
4101 if (mVersionCurrent->isAmigaPower())
4102 GUI_Element_Mouse_Over(mPlus_Buttons);
4103
4104 if (mVersionCurrent->isAmigaAction() || mVersionCurrent->isAmigaNotVeryFestive() || mVersionCurrent->isAmigaAlienLevels())
4105 GUI_Element_Mouse_Over(mAmigaAction_Buttons);
4106
4107
4108 }
4109 });
4110
4111 GetGraphics<cGraphics_Amiga>()->SetCursorPalette(0xE0);
4112 mWindow->SetScreenSize(mVersionCurrent->GetScreenSize());
4113 return mPhase_Aborted;
4114 }
4115
Sprite_Handle_Player_Enter_Vehicle(sSprite * pSprite)4116 void cFodder::Sprite_Handle_Player_Enter_Vehicle(sSprite* pSprite) {
4117 // Have a target vehicle?
4118 if (!pSprite->field_66)
4119 return;
4120
4121 sSprite* Vehicle = pSprite->field_66;
4122
4123 int16 VehicleX = Vehicle->field_0 + 0x10;
4124
4125 if (Vehicle->field_6F == eVehicle_Turret_Cannon || Vehicle->field_6F == eVehicle_Turret_Missile)
4126 VehicleX -= 0x0C;
4127
4128 int16 VehicleY = Vehicle->field_4 - 9;
4129 int16 SoldierX = pSprite->field_0 + 4;
4130 int16 SoldierY = pSprite->field_4;
4131
4132 // Is the sprite close enough to enter the vehicle?
4133 int16 Distance = 0x1F;
4134 if (Map_Get_Distance_BetweenPoints(VehicleX, VehicleY, SoldierX, Distance, SoldierY) >= 0x0D)
4135 return;
4136
4137 // Enter the vehicle
4138 pSprite->field_6A_sprite = Vehicle;
4139 pSprite->field_6E = -1;
4140 sSprite* Data20 = 0;
4141
4142 sub_305D5(Data20);
4143
4144 // First member of current player squad
4145 sSprite* eax = mSquads[pSprite->field_32][0];
4146
4147 // Is this the first member of the squad
4148 if (eax != pSprite)
4149 return;
4150
4151 mSquad_EnteredVehicleTimer[pSprite->field_32] = 0x190;
4152 }
4153
Mouse_Cursor_Update()4154 void cFodder::Mouse_Cursor_Update() {
4155 int16 Data0, Data4, Data8;
4156
4157 // Sidebar
4158 if (mMouseX < 0x10) {
4159 mMouseSpriteNew = eSprite_pStuff_Mouse_Cursor;
4160 mMouseX_Offset = 0;
4161 mMouseY_Offset = 0;
4162 return;
4163 }
4164
4165 if (!mButtonPressRight) {
4166
4167 Data0 = mMouseX + (mCameraX >> 16);
4168 Data4 = mMouseY + (mCameraY >> 16);
4169
4170 Data0 -= 0x0F;
4171 Data4 -= 3;
4172
4173 //loc_30B36
4174 for (auto& Vehicle : mSprites_HumanVehicles) {
4175
4176 if (Vehicle->field_0 < 0)
4177 continue;
4178
4179 if (!Vehicle->field_65)
4180 continue;
4181
4182 // If not human
4183 if (Vehicle->field_22 != eSprite_PersonType_Human)
4184 continue;
4185
4186 Data8 = Vehicle->field_0;
4187 if (Vehicle->field_6F == eVehicle_Turret_Cannon)
4188 goto loc_30BB9;
4189 if (Vehicle->field_6F == eVehicle_Turret_Missile)
4190 goto loc_30BBE;
4191
4192 loc_30BB9:;
4193 Data8 -= 8;
4194 loc_30BBE:;
4195
4196 if (Data0 < Data8)
4197 continue;
4198
4199 Data8 += mSprite_Width[Vehicle->field_18];
4200 if (Data0 > Data8)
4201 continue;
4202
4203 Data8 = Vehicle->field_4;
4204 Data8 -= Vehicle->field_20;
4205 Data8 -= mSprite_Height_Top[Vehicle->field_18];
4206 Data8 -= 0x14;
4207
4208 if (Data4 < Data8)
4209 continue;
4210
4211 Data8 = Vehicle->field_4;
4212 Data8 -= Vehicle->field_20;
4213 if (Data4 > Data8)
4214 continue;
4215
4216 mMouseSetToCursor = -1;
4217
4218 // Is vehicle off ground
4219 if (Vehicle->field_20) {
4220
4221 // And is current
4222 if (Vehicle != mSquad_CurrentVehicle)
4223 return;
4224
4225 if (Vehicle->field_8 == 0xA5)
4226 return;
4227
4228 // Show the helicopter land icon
4229 mMouseSpriteNew = eSprite_pStuff_Mouse_Helicopter;
4230 mMouseX_Offset = 0;
4231 mMouseY_Offset = 0;
4232 return;
4233 }
4234
4235 // Is this the vehicle the current squad is in
4236 if (Vehicle == mSquad_CurrentVehicle)
4237 mMouseSpriteNew = eSprite_pStuff_Mouse_Arrow_DownRight;
4238 else
4239 mMouseSpriteNew = eSprite_pStuff_Mouse_Arrow_UpLeft;
4240
4241 mMouseX_Offset = 0;
4242 mMouseY_Offset = 0;
4243 return;
4244 }
4245 }
4246
4247 if (mMouseSetToCursor) {
4248 mMouseSetToCursor = 0;
4249 mMouseSpriteNew = eSprite_pStuff_Mouse_Cursor;
4250 mMouseX_Offset = 0;
4251 mMouseY_Offset = 0;
4252 }
4253 }
4254
sub_22C87(sSprite * pSprite)4255 void cFodder::sub_22C87(sSprite* pSprite) {
4256
4257 int32 Data0 = pSprite->field_1A;
4258
4259 pSprite->field_1E_Big += Data0;
4260
4261 if (pSprite->field_1E_Big < 0) {
4262 pSprite->field_1E_Big = 0;
4263 Data0 = -Data0;
4264 Data0 >>= 1;
4265 }
4266
4267 Data0 -= 0x20000;
4268 pSprite->field_1A = (int32)Data0;
4269 }
4270
sub_22CD7(sSprite * pSprite,int16 & pData0,int16 & pData4)4271 void cFodder::sub_22CD7(sSprite* pSprite, int16& pData0, int16& pData4) {
4272
4273 int16 Data1C;
4274
4275 pSprite->field_3C = pSprite->field_10;
4276
4277 Sprite_Direction_Between_Points(pSprite, pData0, pData4);
4278
4279 mSprite_Field10_Saved = pSprite->field_10;
4280 pSprite->field_3E = 0;
4281
4282 Sprite_SetDirectionMod(pSprite);
4283
4284 pSprite->field_10 = pSprite->field_3C;
4285
4286 pData0 = word_3B2F7;
4287 pData0 -= pSprite->field_36;
4288
4289 pData0 *= mDirectionMod;
4290 int16 Data8 = 0;
4291
4292 pData4 = pData0;
4293 if (pData4 < 0) {
4294 Data8 = -1;
4295 pData4 = -pData4;
4296 }
4297
4298 if (pData4 > word_3B25D) {
4299 pData0 = word_3B25D;
4300
4301 if (Data8 < 0)
4302 pData0 = -pData0;
4303 }
4304 //loc_22D7A
4305 pSprite->field_10 += pData0;
4306 pSprite->field_10 &= 0x1FE;
4307
4308 if (pSprite->field_6F == eVehicle_Jeep)
4309 goto loc_22DC4;
4310
4311 if (pSprite->field_6F == eVehicle_JeepRocket)
4312 goto loc_22DC4;
4313
4314 if (pSprite->field_6F == eVehicle_Tank)
4315 goto loc_22DCF;
4316
4317 if (pSprite->field_36 <= 6)
4318 return;
4319
4320 if (!(mMission_EngineTicks & 1))
4321 return;
4322
4323 loc_22DC4:;
4324 if (pSprite->field_36 <= 8)
4325 return;
4326
4327 loc_22DCF:;
4328 pData0 = -pData0;
4329 if (!pData0) {
4330 Data1C = 0;
4331 }
4332 else if (pData0 >= 0) {
4333 Data1C = 1;
4334 }
4335 else {
4336 Data1C = -1;
4337 }
4338
4339 Sprite_Vehicle_Direction_Update(pSprite, Data1C);
4340 }
4341
Sprite_Handle_Vehicle_Terrain_Check(sSprite * pSprite)4342 void cFodder::Sprite_Handle_Vehicle_Terrain_Check(sSprite* pSprite) {
4343 int16 Data4, Data0;
4344 int32 Dataa0;
4345
4346 pSprite->field_50 = pSprite->field_52;
4347 if (!pSprite->field_50)
4348 pSprite->field_52 = 0;
4349
4350 if (Map_Sprite_Check_Around_Position(pSprite))
4351 goto Computer_Vehicle_SoftTerrain;
4352
4353 Data4 = 0x0F;
4354 Data0 = -10;
4355 Map_Terrain_Get_Type_And_Walkable(pSprite, Data0, Data4);
4356
4357 pSprite->field_60 = static_cast<int8>(Data4);
4358 if (Data4 == eTerrainFeature_Rocky || Data4 == eTerrainFeature_Rocky2)
4359 goto loc_23056;
4360
4361 if (Data4 == eTerrainFeature_Jump)
4362 goto loc_23100;
4363
4364 if (Data4 == eTerrainFeature_Block)
4365 goto Computer_Vehicle_SoftTerrain;
4366
4367 if (Data4 == eTerrainFeature_Drop || Data4 == 0x0A)
4368 goto loc_22F06;
4369
4370 if (pSprite->field_56)
4371 pSprite->field_38 = eSprite_Anim_Die1;
4372
4373 if (Data4 == eTerrainFeature_Snow)
4374 goto loc_22FA3;
4375
4376 if (pSprite->field_22 == eSprite_PersonType_Human)
4377 goto Human_Vehicle;
4378
4379 if (Data4 == eTerrainFeature_QuickSand || Data4 == eTerrainFeature_WaterEdge
4380 || Data4 == eTerrainFeature_Water || Data4 == eTerrainFeature_Sink)
4381 goto Computer_Vehicle_SoftTerrain;
4382
4383 goto loc_22EEB;
4384
4385 Human_Vehicle:;
4386
4387 if (Data4 == eTerrainFeature_QuickSand)
4388 goto Human_Vehicle_Quicksand;
4389
4390 if (Data4 == eTerrainFeature_WaterEdge)
4391 goto Human_Vehicle_WaterEdge;
4392
4393 if (Data4 == eTerrainFeature_Water || Data4 == eTerrainFeature_Sink)
4394 goto AnimDie3;
4395
4396 loc_22EEB:;
4397 pSprite->field_52 = 0;
4398 if (pSprite->field_50)
4399 goto loc_23056;
4400
4401 return;
4402
4403 loc_22F06:;
4404 pSprite->field_56 += 4;
4405 Data0 = pSprite->field_56;
4406 pSprite->field_4 += Data0;
4407 return;
4408
4409 Computer_Vehicle_SoftTerrain:;
4410
4411 if (pSprite->field_22 != eSprite_PersonType_Human) {
4412 pSprite->field_26 = pSprite->field_0;
4413 pSprite->field_28 = pSprite->field_4;
4414 }
4415 //loc_22F5F
4416 pSprite->field_36 = -pSprite->field_36;
4417 pSprite->field_36 >>= 1;
4418 Sprite_XY_Restore(pSprite);
4419
4420 Data4 = 0x0F;
4421 Data0 = -10;
4422 Map_Terrain_Get_Type_And_Walkable(pSprite, Data0, Data4);
4423 if (Data4 == eTerrainFeature_Block)
4424 pSprite->field_38 = eSprite_Anim_Die1;
4425
4426 Sprite_Animation_SlideOrDie(pSprite);
4427 return;
4428
4429 loc_22FA3:;
4430
4431 if (!pSprite->field_36)
4432 return;
4433
4434 pSprite->field_20 ^= 1;
4435 if (!pSprite->field_20)
4436 return;
4437
4438 if (pSprite->field_36 <= 0x10)
4439 return;
4440
4441 pSprite->field_36 -= 2;
4442 return;
4443
4444 Human_Vehicle_Quicksand:;
4445 pSprite->field_52 = 1;
4446 return;
4447
4448 Human_Vehicle_WaterEdge:;
4449 pSprite->field_52 = 3;
4450 return;
4451
4452 AnimDie3:;
4453 if (pSprite->field_56)
4454 pSprite->field_38 = eSprite_Anim_None;
4455 dword_3B24B = -1;
4456
4457 Sprite_Handle_Vehicle_Sinking(pSprite);
4458 if (pSprite->field_52 < 0x50)
4459 goto loc_23033;
4460
4461 pSprite->field_52 = 0x1E;
4462 pSprite->field_38 = eSprite_Anim_Die3;
4463 return;
4464
4465 loc_23033:;
4466 pSprite->field_52 += 1;
4467 pSprite->field_36 -= 0x0C;
4468 if (pSprite->field_36 >= 0)
4469 return;
4470
4471 pSprite->field_36 = 0;
4472 return;
4473
4474 loc_23056:;
4475 if (pSprite->field_20)
4476 return;
4477
4478 if (pSprite->field_36 >= 0x14)
4479 goto loc_230B0;
4480
4481 if (!pSprite->field_36)
4482 return;
4483
4484 Data0 = mGame_InputTicks;
4485 Data0 &= 1;
4486 Data0 += 3;
4487 pSprite->field_20 = Data0;
4488 Data0 = -Data0;
4489 pSprite->field_1A = (((int64)pSprite->field_1A & 0xFFFF) | Data0 << 16);
4490 return;
4491
4492 loc_230B0:;
4493 // Not Moving?
4494 if (!pSprite->field_36)
4495 return;
4496
4497 pSprite->field_20 = 1;
4498 Dataa0 = pSprite->field_36 << 16;
4499 Dataa0 >>= 3;
4500 pSprite->field_1A = Dataa0;
4501 return;
4502
4503 loc_23100:;
4504 if (!pSprite->field_36)
4505 return;
4506
4507 pSprite->field_20 = 1;
4508 Dataa0 = pSprite->field_36 << 16;
4509 Dataa0 >>= 2;
4510 pSprite->field_1A = Dataa0;
4511 pSprite->field_36 <<= 1;
4512 pSprite->field_36 <<= 1;
4513
4514 }
4515
Sprite_Under_Vehicle(sSprite * pSprite,int16 pData8,int16 pDataC,int16 pData10,int16 pData14,int16 pData18,int16 pData1C)4516 void cFodder::Sprite_Under_Vehicle(sSprite* pSprite, int16 pData8, int16 pDataC, int16 pData10, int16 pData14, int16 pData18, int16 pData1C) {
4517
4518 if (mPhase_Finished)
4519 return;
4520
4521 sSprite* Sprite = mSprites.data();
4522
4523 // TODO: Fix counter
4524 for (int16 Count = 0x1D; Count >= 0; --Count, ++Sprite) {
4525 if (Sprite->field_0 == -32768)
4526 continue;
4527
4528 if (Sprite == pSprite)
4529 continue;
4530
4531 if (!mSprite_Can_Be_RunOver[Sprite->field_18])
4532 continue;
4533
4534 if (pSprite->field_22 == Sprite->field_22)
4535 continue;
4536
4537 if (Sprite->field_18 == eSprite_Hostage)
4538 continue;
4539
4540 if (Sprite->field_18 == eSprite_Enemy_Leader)
4541 continue;
4542
4543 if (pData8 > Sprite->field_0)
4544 continue;
4545
4546 if (pDataC < Sprite->field_0)
4547 continue;
4548
4549 if (pData10 > Sprite->field_4)
4550 continue;
4551
4552 if (pData14 < Sprite->field_4)
4553 continue;
4554
4555 int16 Data0 = Sprite->field_20;
4556 if (pData1C < Data0)
4557 continue;
4558 Data0 += 0x0E;
4559 if (pData18 > Data0)
4560 continue;
4561
4562 if (Sprite->field_18 != eSprite_Player) {
4563 if (Sprite->field_6E)
4564 continue;
4565 }
4566
4567 // Run Over
4568 Sprite->field_38 = eSprite_Anim_Die1;
4569 if (!Sprite->field_65)
4570 return;
4571
4572 pSprite->field_38 = eSprite_Anim_Die1;
4573 return;
4574 }
4575 }
4576
Sprite_Animation_SlideOrDie(sSprite * pSprite)4577 int16 cFodder::Sprite_Animation_SlideOrDie(sSprite* pSprite) {
4578 sSprite* Data24 = 0;
4579
4580 // Die animation running?
4581 if (pSprite->field_38 == eSprite_Anim_Die1 || pSprite->field_38 == eSprite_Anim_Die3) {
4582 pSprite->field_18 = eSprite_Explosion;
4583 pSprite->field_26 = 0x1F56;
4584 pSprite->field_28 = -9;
4585 Data24 = pSprite + 1;
4586
4587 Sprite_Destroy(Data24);
4588 if (pSprite->field_22 == eSprite_PersonType_Human)
4589 return -1;
4590
4591 Data24 = pSprite + 2;
4592 Sprite_Destroy(Data24);
4593 return -1;
4594 }
4595
4596 // Slide animation running?
4597 if (pSprite->field_38 == eSprite_Anim_Slide1) {
4598
4599 pSprite->field_36 = -pSprite->field_36;
4600 pSprite->field_38 = eSprite_Anim_Slide2;
4601
4602 }
4603 else if (pSprite->field_38 == eSprite_Anim_Slide2) {
4604 pSprite->field_36 += 6;
4605
4606 if (pSprite->field_36 >= 0) {
4607 pSprite->field_38 = eSprite_Anim_None;
4608 pSprite->field_36 = 0;
4609 }
4610
4611 }
4612 else {
4613 return 0;
4614 }
4615
4616 Sprite_Movement_Calculate(pSprite);
4617 sub_243E9(pSprite);
4618 return -1;
4619 }
4620
Map_Sprite_Check_Around_Position(sSprite * pSprite)4621 int16 cFodder::Map_Sprite_Check_Around_Position(sSprite* pSprite) {
4622 int16 Data4 = 0x0A;
4623 int16 Data0 = -13;
4624
4625 int16 ax = Map_Terrain_Get_Type_And_Walkable(pSprite, Data0, Data4);
4626 if (ax)
4627 return ax;
4628
4629 Data4 = 0x14;
4630 Data0 = -13;
4631 ax = Map_Terrain_Get_Type_And_Walkable(pSprite, Data0, Data4);
4632 if (ax)
4633 return ax;
4634
4635 Data4 = 0x0A;
4636 Data0 = -7;
4637 ax = Map_Terrain_Get_Type_And_Walkable(pSprite, Data0, Data4);
4638 if (ax)
4639 return ax;
4640
4641 Data4 = 0x14;
4642 Data0 = -7;
4643 ax = Map_Terrain_Get_Type_And_Walkable(pSprite, Data0, Data4);
4644 if (ax)
4645 return ax;
4646
4647 return 0;
4648 }
4649
Sprite_Handle_Vehicle_Human(sSprite * pSprite)4650 void cFodder::Sprite_Handle_Vehicle_Human(sSprite* pSprite) {
4651
4652 if (pSprite->field_38) {
4653
4654 pSprite->field_22 = eSprite_PersonType_Human;
4655 Sprite_Handle_Vehicle(pSprite);
4656 pSprite->field_22 = eSprite_PersonType_Human;
4657 return;
4658 }
4659
4660 if (pSprite->field_6F == eVehicle_JeepRocket)
4661 sub_245BF(pSprite);
4662
4663 mSprite_Helicopter_DestroyLight = 0;
4664 pSprite->field_22 = eSprite_PersonType_Human;
4665 Sprite_Handle_Vehicle(pSprite);
4666 pSprite->field_22 = eSprite_PersonType_Human;
4667 mSprite_Helicopter_DestroyLight = 0;
4668
4669 sSprite* Data24 = pSprite + 1;
4670 Data24->field_18 = eSprite_Null;
4671 }
4672
Sprite_Create_Smoke(sSprite * pSprite,sSprite * & pData2C)4673 int16 cFodder::Sprite_Create_Smoke(sSprite* pSprite, sSprite*& pData2C) {
4674 if (!pSprite->field_5C)
4675 return -1;
4676
4677 int16 Data0 = 1;
4678 sSprite* Data30 = 0;
4679
4680 if (Sprite_Get_Free_Max42(Data0, pData2C, Data30))
4681 return -1;
4682
4683 pData2C->field_0 = pSprite->field_0;
4684 pData2C->field_2 = pSprite->field_2;
4685 pData2C->field_4 = pSprite->field_4;
4686 pData2C->field_6 = pSprite->field_6;
4687
4688 if (dword_3B24B) {
4689 Data0 = tool_RandomGet() & 0x1F;
4690 Data0 -= 8;
4691 pData2C->field_0 += Data0;
4692 Data0 >>= 4;
4693 Data0 &= 0x0F;
4694 Data0 -= 8;
4695 pData2C->field_4 -= Data0;
4696 dword_3B24B = 0;
4697 }
4698
4699 pData2C->field_20 = pSprite->field_20;
4700 pData2C->field_52 = 0;
4701 pData2C->field_8 = 0xCC;
4702 pData2C->field_A = 4;
4703 pData2C->field_2C = eSprite_Draw_OnTop;
4704 pData2C->field_18 = eSprite_Smoke;
4705 return 0;
4706 }
4707
sub_23525(sSprite * pSprite)4708 void cFodder::sub_23525(sSprite* pSprite) {
4709 int16 Data0 = 2;
4710 int16 Data4 = pSprite->field_36;
4711 int16 Data8, DataC, Data10, Data14, Data18, Data1C;
4712 sSprite* Data2C = 0;
4713
4714 if (!Data4) {
4715 if (pSprite->field_22 == eSprite_PersonType_Human) {
4716 if (pSprite != mSquad_CurrentVehicle)
4717 goto loc_2356B;
4718 }
4719 }
4720
4721 Data4 += 0x10;
4722 if (Data4 > 0x20)
4723 Data4 = 0x20;
4724
4725 Sprite_Map_Sound_Play(Data0);
4726
4727 loc_2356B:;
4728 pSprite->field_6F = eVehicle_Tank;
4729 pSprite->field_65 = -1;
4730 if (Sprite_Animation_SlideOrDie(pSprite))
4731 return;
4732
4733 pSprite->field_8 = 0xD1;
4734 word_3B2F7 = pSprite->field_36 + 0x20;
4735
4736 Data0 = pSprite->field_26;
4737 Data4 = pSprite->field_28;
4738
4739 sub_22CD7(pSprite, Data0, Data4);
4740 Data0 = pSprite->field_26;
4741 Data4 = pSprite->field_28;
4742
4743 Data8 = pSprite->field_0;
4744 DataC = pSprite->field_4;
4745
4746 Map_Get_Distance_BetweenPoints_Within_Window(Data0, Data4, Data8, DataC);
4747 if (Data0 >= 0x1E)
4748 goto loc_2361A;
4749
4750 if (Data0 >= pSprite->field_36)
4751 goto loc_23680;
4752
4753 pSprite->field_36 = Data0;
4754 goto loc_23680;
4755
4756 loc_2361A:;
4757 dword_3B24B = -1;
4758 if (!Sprite_Create_Smoke(pSprite, Data2C))
4759 Data2C->field_2C = eSprite_Draw_First;
4760
4761 if (!pSprite->field_36) {
4762 if (mDirectionMod) {
4763 pSprite->field_36 -= 4;
4764 goto loc_23680;
4765 }
4766 }
4767
4768 pSprite->field_2A += 1;
4769 pSprite->field_2A &= 1;
4770 if (!pSprite->field_2A) {
4771 ++pSprite->field_36;
4772
4773 if (pSprite->field_36 >= 0x18)
4774 pSprite->field_36 = 0x18;
4775 }
4776
4777 loc_23680:;
4778
4779 Sprite_XY_Store(pSprite);
4780 Sprite_Movement_Calculate(pSprite);
4781 Sprite_Handle_Vehicle_Terrain_Check(pSprite);
4782
4783 pSprite->field_20 = 0;
4784 sub_236F7(pSprite);
4785
4786 Data8 = pSprite->field_0;
4787 DataC = pSprite->field_0 + 0x1E;
4788 Data10 = pSprite->field_4 - 0x14;
4789 Data14 = pSprite->field_4;
4790 Data18 = pSprite->field_20;
4791 Data1C = Data18 + 0x0E;
4792
4793 Sprite_Under_Vehicle(pSprite, Data8, DataC, Data10, Data14, Data18, Data1C);
4794 }
4795
sub_236F7(sSprite * pSprite)4796 void cFodder::sub_236F7(sSprite* pSprite) {
4797 sSprite* Data24 = pSprite + 1;
4798 int16 Data0, Data4, Data8, DataC;
4799
4800 Data24->field_8 = 0xD2;
4801 Data24->field_0 = pSprite->field_0 + 0x0A;
4802 Data24->field_4 = pSprite->field_4 + 1;
4803
4804 Data0 = pSprite->field_52;
4805 Data24->field_4 += Data0;
4806 Data24->field_20 = pSprite->field_20;
4807 Data24->field_20 += 9;
4808 Data0 = Data24->field_0 + 8;
4809 Data4 = Data24->field_4 - 5;
4810
4811 Data4 -= Data24->field_20;
4812 Data24->field_52 = pSprite->field_52;
4813
4814 if (pSprite->field_22 == eSprite_PersonType_Human)
4815 goto loc_23815;
4816
4817 Data8 = pSprite->field_2E;
4818 if (Data8 >= 0)
4819 goto loc_23806;
4820
4821 Data0 = mMission_EngineTicks & 0x0F;
4822 if (Data0)
4823 return;
4824
4825 Data0 = tool_RandomGet() & 1;
4826 if (!Data0)
4827 Data0 -= 1;
4828
4829 Data24->field_A += Data0;
4830 Data24->field_A &= 0x0F;
4831 return;
4832
4833 loc_23806:;
4834 DataC = pSprite->field_30;
4835 goto loc_23843;
4836
4837 loc_23815:;
4838 if (pSprite != mSquad_CurrentVehicle)
4839 return;
4840
4841 Data8 = mMouseX + (mCameraX >> 16);
4842 Data8 -= 0x10;
4843
4844 DataC = mMouseY + (mCameraY >> 16);
4845 loc_23843:;
4846 Direction_Between_Points(Data0, Data4, Data8, DataC);
4847
4848 Data4 -= 0x10;
4849 Data4 >>= 5;
4850 Data4 += 8;
4851 Data4 ^= 0x0F;
4852 Data4 &= 0x0F;
4853 Data24->field_A = Data4;
4854 }
4855
Sprite_Handle_Tank_FireMissile(sSprite * pSprite)4856 void cFodder::Sprite_Handle_Tank_FireMissile(sSprite* pSprite) {
4857 if (!pSprite->field_57)
4858 if (!pSprite->field_54)
4859 return;
4860
4861 pSprite->field_54 = 0;
4862 sSprite* Data24 = pSprite + 1;
4863
4864 Data24->field_2E = pSprite->field_2E;
4865 Data24->field_30 = pSprite->field_30;
4866
4867 int16 Data24_Field_0 = Data24->field_0;
4868 int16 Data24_Field_4 = Data24->field_4;
4869 int16 Data0 = Data24->field_A << 1;
4870
4871 Data24->field_0 += mSprite_Turret_Positions[Data0];
4872 Data24->field_4 += mSprite_Turret_Positions[Data0 + 1];
4873
4874 mSprite_Missile_LaunchDistance_X = 0;
4875 mSprite_Missile_LaunchDistance_Y = 0;
4876 sSprite* Data2C = 0;
4877
4878 if (!Sprite_Create_Missile(Data24, Data2C)) {
4879 Data24->field_4 = Data24_Field_4;
4880 Data24->field_0 = Data24_Field_0;
4881 pSprite->field_57 = -1;
4882 return;
4883 }
4884
4885 Data2C->field_20 += 0x11;
4886 Data2C->field_36 = 0x3C;
4887 Sound_Play(Data24, 5, 0x1E);
4888 Sprite_Create_Smoke(Data24, Data2C);
4889
4890 Data24->field_4 = Data24_Field_4;
4891 Data24->field_0 = Data24_Field_0;
4892 pSprite->field_57 = 0;
4893 }
4894
Sprite_Create_Missile(sSprite * pSprite,sSprite * & pData2C)4895 int16 cFodder::Sprite_Create_Missile(sSprite* pSprite, sSprite*& pData2C) {
4896 if (mPhase_Completed_Timer)
4897 return 0;
4898
4899 if (mSprite_Missile_Projectile_Counters[pSprite->field_22] == 2)
4900 return 0;
4901
4902 if (!pSprite->field_2E)
4903 return 0;
4904
4905 int16 Data0 = 2;
4906 sSprite* Data30 = 0;
4907 if (Sprite_Get_Free_Max42(Data0, pData2C, Data30))
4908 return 0;
4909
4910 ++mSprite_Missile_Projectile_Counters[pSprite->field_22];
4911 Data30 = pData2C + 1;
4912
4913 pData2C->field_0 = pSprite->field_0;
4914 pData2C->field_2 = pSprite->field_2;
4915 pData2C->field_4 = pSprite->field_4;
4916 pData2C->field_6 = pSprite->field_6;
4917
4918 Data30->field_0 = pSprite->field_0;
4919 Data30->field_2 = pSprite->field_2;
4920 Data30->field_4 = pSprite->field_4;
4921 Data30->field_6 = pSprite->field_6;
4922
4923 pData2C->field_0 += mSprite_Missile_LaunchDistance_X;
4924 Data30->field_0 += mSprite_Missile_LaunchDistance_X;
4925 if (Data30->field_0 < 0)
4926 return 0;
4927
4928 pData2C->field_4 += mSprite_Missile_LaunchDistance_Y;
4929 Data30->field_4 += mSprite_Missile_LaunchDistance_Y;
4930
4931 if (Data30->field_4 < 0)
4932 return 0;
4933
4934 pData2C->field_32 = 0;
4935 if (pSprite->field_6F == eVehicle_Turret_Cannon)
4936 pData2C->field_32 = -1;
4937
4938 pData2C->field_1E = pSprite->field_1E;
4939 pData2C->field_20 = pSprite->field_20;
4940 pData2C->field_20 -= 0x0D;
4941 pData2C->field_26 = pSprite->field_2E;
4942 pData2C->field_28 = pSprite->field_30;
4943 pData2C->field_28 += 0x10;
4944
4945 if (pSprite->field_22 != eSprite_PersonType_Human) {
4946 Sprite_Enemy_Set_Target(pData2C);
4947 }
4948 else {
4949 pData2C->field_26 -= 1;
4950 pData2C->field_28 += 3;
4951 }
4952
4953 pData2C->field_8 = 0xA3;
4954 Data30->field_8 = 0x7E;
4955 pData2C->field_A = 0;
4956 Data30->field_A = 1;
4957 pData2C->field_36 = pSprite->field_36;
4958 Data30->field_36 = pSprite->field_36;
4959 pData2C->field_3A = 1;
4960 Data30->field_1E = 0;
4961 Data30->field_20 = 0;
4962 pData2C->field_4 += 1;
4963 pData2C->field_0 += 3;
4964 pData2C->field_18 = eSprite_Missile;
4965 Data30->field_18 = eSprite_ShadowSmall;
4966 pData2C->field_52 = 0;
4967 Data30->field_52 = 0;
4968 pData2C->field_22 = pSprite->field_22;
4969 Data30->field_22 = pSprite->field_22;
4970 pData2C->field_2C = eSprite_Draw_Second;
4971 Data30->field_2C = eSprite_Draw_First;
4972 pData2C->field_38 = eSprite_Anim_None;
4973
4974 // HACK: Disable sound for Amiga Coverdisks (it crashes)
4975 if (!mVersionCurrent->isCoverDisk())
4976 Sound_Play(pSprite, eSound_Effect_Missile_Launch, 0x0F);
4977
4978 return -1;
4979 }
4980
Sprite_Enemy_Set_Target(sSprite * pData2C)4981 void cFodder::Sprite_Enemy_Set_Target(sSprite* pData2C) {
4982
4983 int16 Data0 = tool_RandomGet();
4984 int16 Data4 = Data0;
4985
4986 // Bigger X movement range for low aggression
4987 if (mGame_Data.mGamePhase_Data.mSprite_Enemy_AggressionAverage < 5)
4988 Data0 &= 0x3F;
4989 else
4990 Data0 &= 0x1F;
4991
4992 if (Data4 < 0)
4993 Data0 = -Data0;
4994
4995 pData2C->field_26 += Data0;
4996
4997 Data0 = tool_RandomGet();
4998 Data4 = Data0;
4999
5000 // Bigger Y movement range for low aggression
5001 if (mGame_Data.mGamePhase_Data.mSprite_Enemy_AggressionAverage < 5)
5002 Data0 &= 0x3F;
5003 else
5004 Data0 &= 0x1F;
5005 if (Data4 < 0)
5006 Data0 = -Data0;
5007
5008 pData2C->field_28 += Data0;
5009 }
5010
Sprite_Handle_Helicopter_Human(sSprite * pSprite)5011 void cFodder::Sprite_Handle_Helicopter_Human(sSprite* pSprite) {
5012
5013 if (pSprite->field_38) {
5014
5015 pSprite->field_22 = eSprite_PersonType_Human;
5016 Sprite_Handle_Helicopter(pSprite);
5017 pSprite->field_22 = eSprite_PersonType_Human;
5018
5019 return;
5020 }
5021
5022 Sprite_Handle_Helicopter_Human_Deploy_Weapon(pSprite);
5023
5024 mSprite_Helicopter_DestroyLight = 0;
5025 pSprite->field_22 = eSprite_PersonType_Human;
5026 Sprite_Handle_Helicopter(pSprite);
5027 pSprite->field_22 = eSprite_PersonType_Human;
5028 mSprite_Helicopter_DestroyLight = 0;
5029
5030 sSprite* Data24 = pSprite + 1;
5031 Data24->field_18 = eSprite_Null;
5032 Data24 = pSprite + 2;
5033 Data24->field_18 = eSprite_Null;
5034 }
5035
Sprite_Handle_Helicopter_Terrain_Check(sSprite * pSprite)5036 int16 cFodder::Sprite_Handle_Helicopter_Terrain_Check(sSprite* pSprite) {
5037 int16 Data4 = 0x0F;
5038 int16 Data0 = -10;
5039
5040 Map_Terrain_Get_Type_And_Walkable(pSprite, Data0, Data4);
5041 switch (Data4) {
5042 case eTerrainFeature_Rocky:
5043 case eTerrainFeature_QuickSand:
5044 case eTerrainFeature_WaterEdge:
5045 case eTerrainFeature_Water:
5046 case eTerrainFeature_Sink:
5047 Data0 = 0x0C;
5048 break;
5049
5050 case eTerrainFeature_Block:
5051 Data0 = 0x14;
5052 break;
5053 case eTerrainFeature_Rocky2:
5054 case eTerrainFeature_Drop:
5055 case eTerrainFeature_Drop2:
5056 Data0 = 0x0E;
5057 break;
5058
5059 default:
5060 return 0; // Correct?
5061 }
5062
5063 Data4 = pSprite->field_20;
5064 if (Data4 >= Data0)
5065 return 0;
5066
5067 ++pSprite->field_20;
5068 return -1;
5069 }
5070
sub_23E01(sSprite * pSprite,int16 & pData0,int16 & pData4)5071 void cFodder::sub_23E01(sSprite* pSprite, int16& pData0, int16& pData4) {
5072 if (pSprite->field_44) {
5073 pSprite->field_44 -= 1;
5074
5075 if (pSprite->field_44)
5076 goto loc_23E2F;
5077 }
5078
5079 pSprite->field_3C = pSprite->field_10;
5080 Sprite_Direction_Between_Points(pSprite, pData0, pData4);
5081
5082 loc_23E2F:;
5083 Sprite_SetDirectionMod(pSprite);
5084
5085 pSprite->field_10 = pSprite->field_3C;
5086 pData0 = mDirectionMod;
5087 pData0 <<= 3;
5088
5089 if (pSprite->field_36 > 0x18)
5090 pData0 <<= 1;
5091 pSprite->field_10 = pData0;
5092 pSprite->field_10 &= 0x1FE;
5093
5094 Sprite_Set_Direction_To_Next(pSprite);
5095
5096 int16 Data8 = pSprite->field_3C;
5097 if (!pSprite->field_36)
5098 return;
5099
5100 pSprite->field_A = Data8 >> 1;
5101 }
5102
Sprites_HumanVehicles_Remove(sSprite * pSprite)5103 void cFodder::Sprites_HumanVehicles_Remove(sSprite* pSprite) {
5104
5105 auto it = remove_if(mSprites_HumanVehicles.begin(), mSprites_HumanVehicles.end(),
5106 [pSprite](sSprite* pSpriteFind) {
5107 return pSprite == pSpriteFind;
5108 });
5109
5110 mSprites_HumanVehicles.erase(it, mSprites_HumanVehicles.end());
5111 }
5112
Sprite_Handle_Turret(sSprite * pSprite)5113 void cFodder::Sprite_Handle_Turret(sSprite* pSprite) {
5114 sSprite* Data28 = 0;
5115 sSprite* Data34 = 0;
5116 int16 Data0, Data4, Data8, DataC, Data10;
5117
5118 // Turrets in Moors / Interior can't be destroyed
5119 if (mVersionCurrent->isCannonFodder1()) {
5120 if (mMapLoaded->getTileType() == eTileTypes_Moors || mMapLoaded->getTileType() == eTileTypes_Int) {
5121
5122 if (pSprite->field_38 == eSprite_Anim_Die1)
5123 pSprite->field_38 = eSprite_Anim_None;
5124 }
5125 }
5126
5127 if (pSprite->field_38 == eSprite_Anim_Die3 || pSprite->field_38 == eSprite_Anim_Die1) {
5128
5129 pSprite->field_18 = eSprite_Explosion;
5130 pSprite->field_26 = 0x1F45;
5131 pSprite->field_28 = -2;
5132 if (pSprite->field_22 == eSprite_PersonType_Human)
5133 return;
5134
5135 Sprite_Destroy(pSprite + 1);
5136 return;
5137 }
5138
5139 //loc_23F70
5140 pSprite->field_8 = 0xD2;
5141 pSprite->field_65 = -1;
5142 if (pSprite->field_22 == eSprite_PersonType_Human)
5143 goto loc_24075;
5144
5145 mTurretFires_HomingMissile = 0;
5146 Data0 = eSprite_Player;
5147 Data4 = -1;
5148 Data8 = -1;
5149 DataC = -1;
5150 Data10 = -1;
5151
5152 if (mGame_Data.mGamePhase_Data.mGoals_Remaining[eObjective_Get_Civilian_Home - 1]) {
5153 Data4 = eSprite_Civilian;
5154 Data8 = eSprite_Civilian2;
5155 DataC = eSprite_Civilian_Spear;
5156 Data10 = -1;
5157 }
5158
5159 if (Sprite_Find_By_Types(pSprite, Data0, Data4, Data8, DataC, Data10, Data28))
5160 goto loc_240F3;
5161
5162 if (mSprite_Find_Distance >= 0x28) {
5163
5164 Data0 = tool_RandomGet();
5165 if (mGame_Data.mGamePhase_Data.mSprite_Enemy_AggressionAverage < 5)
5166 Data0 &= 0x3F;
5167 else
5168 Data0 &= 0x1F;
5169
5170 if (Data0 == 4)
5171 pSprite->field_54 = -1;
5172 }
5173
5174 // Fire a homing missile
5175 mTurretFires_HomingMissile = -1;
5176 Data34 = Data28;
5177
5178 Data0 = pSprite->field_0 + 8;
5179 Data4 = pSprite->field_4 - 5;
5180 Data8 = Data28->field_0;
5181 DataC = Data28->field_4;
5182
5183 pSprite->field_2E = Data8;
5184 pSprite->field_30 = DataC;
5185
5186 word_3B4ED[1] = Data28->field_20;
5187 goto loc_240C8;
5188
5189 loc_24075:;
5190 if (pSprite != mSquad_CurrentVehicle)
5191 return;
5192
5193 Data0 = pSprite->field_0 + 8;
5194 Data4 = pSprite->field_4 - 5;
5195 Data8 = mMouseX + (mCameraX >> 16);
5196 Data8 -= 0x10;
5197 DataC = mMouseY + (mCameraY >> 16);
5198
5199 loc_240C8:;
5200 Direction_Between_Points(Data0, Data4, Data8, DataC);
5201 Data4 -= 0x10;
5202 Data4 >>= 5;
5203 Data4 += 8;
5204 Data4 ^= 0x0F;
5205 Data4 &= 0x0F;
5206
5207 pSprite->field_A = Data4;
5208 loc_240F3:;
5209
5210 Sprite_Handle_Turret_Fire(pSprite, Data34);
5211
5212 if (pSprite->field_22 == eSprite_PersonType_Human)
5213 return;
5214
5215 sSprite* Data24 = pSprite + 1;
5216
5217 Data24->field_18 = eSprite_Flashing_Light;
5218 Data4 = pSprite->field_0;
5219 Data4 += 5;
5220 Data24->field_0 = Data4;
5221 Data4 = pSprite->field_4;
5222 Data4 -= 0x0F;
5223 Data4 -= pSprite->field_52;
5224 Data24->field_4 = Data4;
5225 Data24->field_20 = pSprite->field_20;
5226 }
5227
Sprite_Handle_Turret_Fire(sSprite * pSprite,sSprite * pData34)5228 void cFodder::Sprite_Handle_Turret_Fire(sSprite* pSprite, sSprite* pData34) {
5229 int16 ax;
5230
5231 sSprite* Data2C = 0;
5232
5233 if (!pSprite->field_57) {
5234 if (!pSprite->field_54)
5235 return;
5236 }
5237
5238 pSprite->field_54 = 0;
5239 int16 Field_0 = pSprite->field_0;
5240 int16 Field_4 = pSprite->field_4;
5241
5242 int16 Data0 = pSprite->field_A;
5243 Data0 <<= 1;
5244
5245 int16 Data4 = mSprite_Turret_Positions[Data0];
5246 pSprite->field_0 += Data4;
5247
5248 Data4 = mSprite_Turret_Positions[Data0 + 1];
5249 pSprite->field_4 += Data4;
5250
5251 mSprite_Missile_LaunchDistance_X = 0;
5252 mSprite_Missile_LaunchDistance_Y = 0;
5253
5254 if (pSprite->field_6F != eVehicle_Turret_Homing)
5255 goto loc_2421D;
5256
5257 if (!mTurretFires_HomingMissile)
5258 goto loc_2421D;
5259
5260 ax = Sprite_Create_MissileHoming(pSprite, Data2C, pData34);
5261 goto loc_24234;
5262
5263 loc_2421D:;
5264
5265 if (pSprite->field_22 != eSprite_PersonType_Human)
5266 if (word_3B4ED[1] > 9)
5267 goto loc_24275;
5268
5269 ax = Sprite_Create_Missile(pSprite, Data2C);
5270
5271 loc_24234:;
5272 if (!ax)
5273 goto loc_2426C;
5274
5275 Data2C->field_20 += 0x11;
5276 Data2C->field_36 = 0x3C;
5277 Sound_Play(pSprite, eSound_Effect_Turret_Fire, 0x1E);
5278 Sprite_Create_Smoke(pSprite, Data2C);
5279 pSprite->field_57 = 0;
5280 goto loc_24275;
5281
5282 loc_2426C:;
5283 pSprite->field_57 = -1;
5284
5285 loc_24275:;
5286 pSprite->field_4 = Field_4;
5287 pSprite->field_0 = Field_0;
5288 }
5289
Sprite_Find_By_Types(sSprite * pSprite,int16 & pData0,int16 & pData4,int16 & pData8,int16 & pDataC,int16 & pData10,sSprite * & pData28)5290 int16 cFodder::Sprite_Find_By_Types(sSprite* pSprite, int16& pData0, int16& pData4, int16& pData8, int16& pDataC, int16& pData10, sSprite*& pData28) {
5291 int16* Data2C = mSprite_Find_Types;
5292
5293 mSprite_Find_Types[0] = pData0;
5294 mSprite_Find_Types[1] = pData4;
5295 mSprite_Find_Types[2] = pData8;
5296 mSprite_Find_Types[3] = pDataC;
5297 mSprite_Find_Types[4] = pData10;
5298
5299 // Check if Sprite @ field_5E sprite is one of the types
5300 pData28 = &mSprites[pSprite->field_5E];
5301
5302 // The original engine checks 1 sprite per cycle, and we have a max of 43 sprites to check
5303 // Meaning it takes 43 cycles to check all sprites, including empty sprite slots
5304 // this becomes problematic when you increase maxsprites, especially insane high values like
5305 // 1,000,000
5306 if (!mParams->isOriginalSpriteMax()) {
5307 bool Looped = false;
5308
5309 // So if we arnt using default max sprites,
5310 // We counter the problem by searching all sprites in a single loop (we can do this, as we have faster CPUs than in 1993)
5311 //
5312 do {
5313 NextSprite2:;
5314 pData28 = &mSprites[pSprite->field_5E];
5315
5316 if (pSprite->field_5E >= (mParams->mSpritesMax - 2)) {
5317 pSprite->field_5E = 0;
5318 if (Looped == true)
5319 return -1;
5320
5321 Looped = true;
5322 continue;
5323 }
5324
5325 if (pData28->field_0 == -32768) {
5326 ++pSprite->field_5E;
5327 continue;
5328 }
5329
5330 Data2C = mSprite_Find_Types;
5331 do {
5332 pData0 = *Data2C++;
5333 if (pData0 < 0) {
5334 ++pSprite->field_5E;
5335 goto NextSprite2;
5336 }
5337 } while (pData0 != pData28->field_18);
5338 } while (pData28->field_0 == -32768);
5339
5340 } else {
5341 if (pData28->field_0 == -32768)
5342 goto NextSprite;
5343
5344 do {
5345 pData0 = *Data2C++;
5346 if (pData0 < 0)
5347 goto NextSprite;
5348 } while (pData0 != pData28->field_18);
5349 }
5350
5351 // Found a type match
5352 pData0 = pSprite->field_0;
5353 pData4 = pSprite->field_4;
5354 pData8 = pData28->field_0;
5355 pDataC = pData28->field_4;
5356
5357 Map_Get_Distance_BetweenPoints_Within_Window(pData0, pData4, pData8, pDataC);
5358 mSprite_Find_Distance = pData0;
5359
5360 if (pData0 >= 0xD2)
5361 goto NextSprite;
5362
5363 if (pData0 <= 0x28)
5364 goto FoundSprite;
5365
5366 pData0 = pSprite->field_0;
5367 pData4 = pSprite->field_4;
5368 pData8 = pData28->field_0;
5369 pDataC = pData28->field_4;
5370
5371 if (Map_PathCheck_CalculateTo(pData0, pData4, pData8, pDataC))
5372 goto loc_2439F;
5373
5374 pData0 = mSprite_Find_Distance;
5375 goto FoundSprite;
5376
5377 loc_2439F:;
5378 if (mSprite_Find_Distance < 0x40)
5379 goto FoundSprite;
5380
5381 NextSprite:;
5382 pSprite->field_5E++;
5383 if (pSprite->field_5E >= (mParams->mSpritesMax - 2))
5384 pSprite->field_5E = 0;
5385
5386 goto loc_243DD;
5387 FoundSprite:;
5388 pData4 = pData28->field_18;
5389 return 0;
5390
5391 loc_243DD:;
5392 return -1;
5393 }
5394
sub_243E9(sSprite * pSprite)5395 void cFodder::sub_243E9(sSprite* pSprite) {
5396 sSprite* Data24 = pSprite + 1;
5397
5398 Data24->field_8 = 0x8D;
5399 int16 Data0 = pSprite->field_20;
5400 Data0 >>= 4;
5401 if (Data0 > 2)
5402 Data0 = 2;
5403
5404 Data24->field_A = Data0;
5405 Data0 = pSprite->field_20;
5406 Data0 >>= 1;
5407
5408 int16 Data4 = Data0;
5409 Data0 += 9;
5410 Data0 += pSprite->field_0;
5411 Data24->field_0 = Data0;
5412 Data4 -= 1;
5413 Data4 += pSprite->field_4;
5414 Data24->field_4 = Data4;
5415 if (!pSprite->field_52)
5416 return;
5417
5418 Data24->field_A = 0;
5419 Data24->field_8 = 0x7C;
5420 }
5421
Sprite_Handle_Vehicle_Sinking(sSprite * pSprite)5422 int16 cFodder::Sprite_Handle_Vehicle_Sinking(sSprite* pSprite) {
5423
5424 Sound_Play(pSprite, eSound_Effect_Vehicle_Sinking, 0x0F);
5425 if (!pSprite->field_5C)
5426 return -1;
5427
5428 int16 Data0 = 1;
5429 sSprite* Data2C = 0, *Data30 = 0;
5430
5431 if (Sprite_Get_Free_Max42(Data0, Data2C, Data30))
5432 return -1;
5433
5434 Data2C->field_0 = pSprite->field_0;
5435 Data2C->field_2 = pSprite->field_2;
5436 Data2C->field_4 = pSprite->field_4;
5437 Data2C->field_6 = pSprite->field_6;
5438
5439 if (dword_3B24B) {
5440 Data0 = tool_RandomGet() & 0x1F;
5441 Data0 -= 5;
5442 Data2C->field_0 += Data0;
5443 Data0 >>= 4;
5444 Data0 &= 0x0F;
5445 Data0 -= 0x0A;
5446 Data2C->field_4 -= Data0;
5447 dword_3B24B = 0;
5448 }
5449 //loc_24546
5450 Data2C->field_20 = pSprite->field_20;
5451 Data2C->field_52 = 0;
5452 Data2C->field_2C = eSprite_Draw_OnTop;
5453
5454 Data0 = tool_RandomGet() & 1;
5455 if (!Data0) {
5456 Data2C->field_8 = 0xDE;
5457 Data2C->field_A = 4;
5458 Data2C->field_18 = eSprite_Vehicle_Sinking_1;
5459 }
5460 else {
5461 Data2C->field_8 = 0xDF;
5462 Data2C->field_A = 0;
5463 Data2C->field_18 = eSprite_Vehicle_Sinking_2;
5464 }
5465 return 0;
5466 }
5467
sub_245BF(sSprite * pSprite)5468 void cFodder::sub_245BF(sSprite* pSprite) {
5469
5470 if (pSprite->field_22 == eSprite_PersonType_Human)
5471 goto loc_245DA;
5472
5473 if (pSprite->field_54)
5474 goto loc_24617;
5475
5476 return;
5477
5478 loc_245DA:;
5479 if (pSprite != mSquad_CurrentVehicle)
5480 return;
5481
5482 if (!mButtonPressRight)
5483 return;
5484
5485 if (pSprite->field_54)
5486 goto loc_24617;
5487 pSprite->field_54 = 0;
5488 pSprite->field_55 = ~pSprite->field_55;
5489 if (pSprite->field_55)
5490 return;
5491
5492 loc_24617:;
5493 pSprite->field_54 = 0;
5494
5495 int16 Field_0 = pSprite->field_0;
5496 int16 Field_4 = pSprite->field_4;
5497
5498 int16 Data0 = pSprite->field_A;
5499
5500 // seg005:4F58
5501 Data0 <<= 1;
5502
5503 if (pSprite->field_5B < 0)
5504 Data0 += 2;
5505
5506 int16 Data4 = mSprite_VehiclePosition_Mod[Data0];
5507 pSprite->field_0 += Data4;
5508 Data4 = mSprite_VehiclePosition_Mod[Data0 + 1];
5509 pSprite->field_4 += Data4;
5510
5511 if (!Sprite_Create_Cannon(pSprite)) {
5512 pSprite->field_5B = ~pSprite->field_5B;
5513 Sound_Play(pSprite, 0x10, 0x1E);
5514 }
5515
5516 //loc_246BC
5517 pSprite->field_4 = Field_4;
5518 pSprite->field_0 = Field_0;
5519 }
5520
Sprite_Create_Cannon(sSprite * pSprite)5521 int16 cFodder::Sprite_Create_Cannon(sSprite* pSprite) {
5522 if (mPhase_Completed_Timer)
5523 return -1;
5524
5525 int16 Data0 = 1;
5526 sSprite* Data2C = 0, *Data30 = 0;
5527
5528 if (Sprite_Get_Free_Max42(Data0, Data2C, Data30))
5529 return -1;
5530
5531 if (mSprite_Projectile_Counters[2] == 0x14)
5532 return -1;
5533
5534 ++mSprite_Projectile_Counters[2];
5535 Data2C->field_0 = pSprite->field_0;
5536 Data2C->field_2 = pSprite->field_2;
5537 Data2C->field_4 = pSprite->field_4;
5538 Data2C->field_6 = pSprite->field_6;
5539 Data2C->field_8 = 0x7F;
5540 Data2C->field_A = 3;
5541 Data2C->field_12 = 9;
5542 Data2C->field_18 = eSprite_Cannon;
5543
5544 Data2C->field_1E_Big += 0x60000;
5545
5546 Data2C->field_52 = pSprite->field_52;
5547 Data2C->field_22 = pSprite->field_22;
5548 Data2C->field_2C = eSprite_Draw_Second;
5549 Data0 = 0x321;
5550
5551 Data0 += pSprite->field_62;
5552 Data2C->field_4A = Data0;
5553 Data0 = pSprite->field_36;
5554 Data0 += 0x50;
5555 Data2C->field_36 = Data0;
5556 Data2C->field_43 = 0;
5557 Data2C->field_44 = 0;
5558 Data0 = pSprite->field_A;
5559 Data0 -= 1;
5560 Data0 ^= 0x0F;
5561 Data0 &= 0x0F;
5562 Data0 <<= 5;
5563 Data2C->field_10 = Data0;
5564 Data2C->field_3A = 0;
5565 Data2C->field_1A_sprite = pSprite;
5566 Data2C->field_2A = 2;
5567 Data2C->field_16 = 0;
5568 Data2C->field_14 = 2;
5569 Data2C->field_34 = -1;
5570 Data2C->field_50 = 0;
5571 Data2C->field_59 = 0;
5572
5573 int16 Data8 = 7;
5574 Data0 = tool_RandomGet();
5575 int16 Data4 = Data0;
5576
5577 Data0 &= Data8;
5578 if (Data4 < 0)
5579 Data0 = -Data0;
5580
5581 Data2C->field_10 += Data0;
5582 Data2C->field_64 = 0;
5583 return 0;
5584 }
5585
Sprite_Handle_Helicopter_Human_Deploy_Weapon(sSprite * pSprite)5586 void cFodder::Sprite_Handle_Helicopter_Human_Deploy_Weapon(sSprite* pSprite) {
5587 sSprite* Data2C = 0, *Data34 = 0;
5588
5589 if (!pSprite->field_57)
5590 if (!pSprite->field_54)
5591 return;
5592
5593 pSprite->field_54 = 0;
5594
5595 if (pSprite->field_20 <= 0x1F)
5596 return;
5597
5598 if (pSprite->field_6F == eVehicle_Helicopter_Grenade)
5599 goto loc_24905;
5600
5601 if (pSprite->field_6F == eVehicle_Helicopter_Missile)
5602 goto loc_24917;
5603
5604 if (pSprite->field_6F == eVehicle_Helicopter_Homing)
5605 goto loc_24917;
5606
5607 loc_24905:;
5608 if (!Sprite_Create_Grenade2(pSprite))
5609 goto loc_2490D;
5610 goto loc_24942;
5611
5612 loc_2490D:;
5613 pSprite->field_57 = -1;
5614 return;
5615
5616 loc_24917:;
5617 mSprite_Missile_LaunchDistance_X = 0x0E;
5618 mSprite_Missile_LaunchDistance_Y = -12;
5619
5620 // Homing Missle and can get lock on a target?
5621 if (pSprite->field_6F == eVehicle_Helicopter_Homing &&
5622 Sprite_Homing_LockInRange(pSprite, Data34)) {
5623
5624 // Launch a homing missile
5625 if (!Sprite_Create_MissileHoming(pSprite, Data2C, Data34))
5626 goto loc_2490D;
5627
5628 }
5629 else {
5630 // Launch a missile
5631 if (!Sprite_Create_Missile(pSprite, Data2C))
5632 goto loc_2490D;
5633 }
5634
5635 loc_24942:;
5636 pSprite->field_57 = 0;
5637 }
5638
Sprite_Create_Grenade2(sSprite * pSprite)5639 int16 cFodder::Sprite_Create_Grenade2(sSprite* pSprite) {
5640 int16 Data0, Data4, Data8, DataC;
5641
5642 if (mPhase_Completed_Timer)
5643 return 0;
5644
5645 if (mSprite_Projectile_Counters[pSprite->field_22] == 2)
5646 return 0;
5647
5648 if (!pSprite->field_2E)
5649 return 0;
5650
5651 Data0 = 2;
5652 sSprite* Data2C, *Data30;
5653 if (Sprite_Get_Free_Max42(Data0, Data2C, Data30))
5654 return 0;
5655
5656 ++mSprite_Projectile_Counters[pSprite->field_22];
5657 Data30 = Data2C + 1;
5658 Data2C->field_0 = pSprite->field_0;
5659 Data30->field_0 = pSprite->field_0;
5660 Data2C->field_4 = pSprite->field_4;
5661 Data30->field_4 = pSprite->field_4;
5662 Data2C->field_8 = 0x7D;
5663 Data30->field_8 = 0x7E;
5664 Data2C->field_A = 0;
5665 Data30->field_A = 0;
5666
5667 Data8 = pSprite->field_2E;
5668 DataC = pSprite->field_30;
5669 DataC += 6;
5670
5671 Data2C->field_26 = Data8;
5672 Data2C->field_28 = DataC;
5673
5674 if (pSprite->field_22 != eSprite_PersonType_Human)
5675 Sprite_Enemy_Set_Target(Data2C);
5676
5677 Data0 = pSprite->field_0;
5678 Data4 = pSprite->field_4;
5679
5680 Map_Get_Distance_BetweenPoints_Within_Window(Data0, Data4, Data8, DataC);
5681 if (Data0 < 0x28)
5682 Data0 = 0x28;
5683
5684 Data0 = Data0 / 5;
5685 if (Data0 > 0x64)
5686 Data0 = 0x64;
5687
5688 Data2C->field_12 = Data0;
5689 Data2C->field_36 = 0x32;
5690 Data30->field_36 = 0x32;
5691 Data0 = pSprite->field_20;
5692 Data0 += 2;
5693
5694 Data2C->field_1E = 0;
5695 Data2C->field_20 = Data0;
5696 Data30->field_1E = 0;
5697 Data30->field_20 = 0;
5698
5699 Data2C->field_4 += 1;
5700 Data2C->field_0 += 3;
5701
5702 int32 Dataa0 = Data2C->field_12 << 16;
5703 Dataa0 >>= 1;
5704 if (Dataa0 > 0xE0000)
5705 Dataa0 = 0xE0000;
5706
5707 Data2C->field_1A = Dataa0;
5708 Data2C->field_1A = 0;
5709 Data2C->field_18 = eSprite_Grenade;
5710 Data30->field_18 = eSprite_ShadowSmall;
5711
5712 Data2C->field_52 = 0;
5713 Data30->field_52 = 0;
5714 Data2C->field_50 = 0;
5715
5716 Data2C->field_22 = pSprite->field_22;
5717 Data30->field_22 = pSprite->field_22;
5718
5719 Data2C->field_2C = eSprite_Draw_Second;
5720 Data30->field_2C = eSprite_Draw_First;
5721 Data2C->field_38 = eSprite_Anim_None;
5722
5723 if (pSprite->field_22 != eSprite_PersonType_Human)
5724 Data2C->field_12 += 0x0A;
5725
5726 return -1;
5727 }
5728
Sprite_Create_MissileHoming(sSprite * pSprite,sSprite * & pData2C,sSprite * & pData34)5729 int16 cFodder::Sprite_Create_MissileHoming(sSprite* pSprite, sSprite*& pData2C, sSprite*& pData34) {
5730
5731 if (mPhase_Completed_Timer)
5732 return 0;
5733
5734 if (mSprite_Missile_Projectile_Counters[pSprite->field_22] == 2)
5735 return 0;
5736
5737 if (!pSprite->field_2E)
5738 return 0;
5739
5740 int16 Data0 = 2;
5741 sSprite *Data30 = 0;
5742 if (Sprite_Get_Free_Max42(Data0, pData2C, Data30))
5743 return 0;
5744
5745 ++mSprite_Missile_Projectile_Counters[pSprite->field_22];
5746
5747 Data30 = pData2C;
5748 ++Data30;
5749
5750 //seg005:55E0
5751 pData2C->field_0 = pSprite->field_0;
5752 pData2C->field_2 = pSprite->field_2;
5753 pData2C->field_4 = pSprite->field_4;
5754 pData2C->field_6 = pSprite->field_6;
5755
5756 Data30->field_0 = pSprite->field_0;
5757 Data30->field_2 = pSprite->field_2;
5758 Data30->field_4 = pSprite->field_4;
5759 Data30->field_6 = pSprite->field_6;
5760
5761 pData2C->field_0 += mSprite_Missile_LaunchDistance_X;
5762 Data30->field_0 += mSprite_Missile_LaunchDistance_X;
5763 if (Data30->field_0 < 0)
5764 return 0;
5765
5766 pData2C->field_4 += mSprite_Missile_LaunchDistance_Y;
5767 Data30->field_4 += mSprite_Missile_LaunchDistance_Y;
5768
5769 if (Data30->field_0 < 0)
5770 return 0;
5771
5772 //seg005:5672
5773 pData2C->field_1A_sprite = pData34;
5774 pData2C->field_1E = pSprite->field_1E;
5775 pData2C->field_20 = pSprite->field_20;
5776 pData2C->field_26 = pSprite->field_2E;
5777 pData2C->field_28 = pSprite->field_30;
5778 pData2C->field_28 += 0x10;
5779 pData2C->field_8 = 0xA3;
5780 Data30->field_8 = 0x7E;
5781 pData2C->field_A = 0;
5782 Data30->field_A = 1;
5783 pData2C->field_36 = 0;
5784 Data30->field_36 = 0;
5785 pData2C->field_6A = 0x10000;
5786 if (pSprite->field_22 != eSprite_PersonType_Human)
5787 pData2C->field_6A = 0x400;
5788
5789 Data30->field_1E = 0;
5790 Data30->field_20 = 0;
5791 pData2C->field_4 += 1;
5792 pData2C->field_0 += 3;
5793 pData2C->field_18 = eSprite_MissileHoming2;
5794 if (pSprite->field_22 != eSprite_PersonType_Human)
5795 pData2C->field_18 = eSprite_MissileHoming;
5796 Data30->field_18 = eSprite_ShadowSmall;
5797 pData2C->field_52 = 0;
5798 Data30->field_52 = 0;
5799 pData2C->field_22 = pSprite->field_22;
5800 Data30->field_22 = pSprite->field_22;
5801 pData2C->field_2C = eSprite_Draw_Second;
5802 Data30->field_2C = eSprite_Draw_First;
5803 pData2C->field_38 = eSprite_Anim_None;
5804
5805 if (mVersionCurrent->isCoverDisk())
5806 Sound_Play(pSprite, 0x10, 0x0F);
5807 else
5808 Sound_Play(pSprite, eSound_Effect_Turret_Fire, 0x0F);
5809 return -1;
5810 }
5811
Sprite_Handle_Helicopter_Enemy_Weapon(sSprite * pSprite,sSprite * & pData30)5812 int16 cFodder::Sprite_Handle_Helicopter_Enemy_Weapon(sSprite* pSprite, sSprite*& pData30) {
5813 int16 Data0;
5814 sSprite* Data2C = 0, *Data34 = 0;
5815
5816 if (pSprite->field_6F == eVehicle_Helicopter_Grenade)
5817 goto loc_25344;
5818
5819 if (pSprite->field_6F == eVehicle_Helicopter_Missile)
5820 goto loc_253E7;
5821
5822 if (pSprite->field_6F == eVehicle_Helicopter_Homing)
5823 goto loc_253E7;
5824
5825 loc_25344:;
5826 pSprite->field_26 = pData30->field_0;
5827 pSprite->field_26 += 0x14;
5828 pSprite->field_28 = pData30->field_4;
5829 pSprite->field_26 -= 0x1E;
5830 if (pSprite->field_26 < 0)
5831 pSprite->field_26 = 0;
5832
5833 pSprite->field_2E = pData30->field_0;
5834 pSprite->field_30 = pData30->field_4;
5835 if (pSprite->field_20 <= 0x1F)
5836 goto loc_253D2;
5837
5838 if (mMission_EngineTicks & 0x0F)
5839 goto loc_253D2;
5840
5841 Sprite_Create_Grenade2(pSprite);
5842 Data0 = tool_RandomGet() & 0x0F;
5843 if (!Data0)
5844 goto loc_253DE;
5845
5846 loc_253D2:;
5847 return -1;
5848
5849 loc_253DE:;
5850 return 0;
5851
5852 loc_253E7:;
5853 pSprite->field_26 = pData30->field_0;
5854 pSprite->field_28 = pData30->field_4;
5855 pSprite->field_2E = pData30->field_0;
5856 pSprite->field_30 = pData30->field_4;
5857
5858 Data0 = mSprite_DistanceTo_Squad0;
5859 if (Data0 <= 0x3C)
5860 goto loc_254C7;
5861 if (Data0 >= 0x8C)
5862 goto loc_254E7;
5863
5864 if (pSprite->field_20 >= 0x19) {
5865 if (!(mMission_EngineTicks & 0x0F)) {
5866 mSprite_Missile_LaunchDistance_X = 0x0E;
5867 mSprite_Missile_LaunchDistance_Y = -12;
5868 if (pSprite->field_6F == eVehicle_Helicopter_Homing) {
5869
5870 Data34 = pData30;
5871 if (Sprite_Create_MissileHoming(pSprite, Data2C, Data34)) {
5872 Data2C->field_6A = 0x2000;
5873 Data2C->field_36 = 0x14;
5874 }
5875 }
5876 else {
5877 Sprite_Create_Missile(pSprite, Data2C);
5878 }
5879 }
5880 }
5881
5882 if (pSprite->field_36 < 0)
5883 goto loc_254E7;
5884
5885 pSprite->field_36 -= 4;
5886 if (pSprite->field_36 < 0)
5887 pSprite->field_36 = 0;
5888 goto loc_254E7;
5889
5890 loc_254C7:;
5891
5892 if (pSprite->field_36 >= 0)
5893 goto loc_254DE;
5894
5895 if (pSprite->field_36 < -34)
5896 goto loc_254E7;
5897 loc_254DE:;
5898 pSprite->field_36 -= 3;
5899
5900 loc_254E7:;
5901 Data0 = tool_RandomGet() & 0x0F;
5902 if (!Data0)
5903 return 0;
5904
5905 return -1;
5906 }
5907
Sprite_Handle_Vehicle_Enemy(sSprite * pSprite)5908 void cFodder::Sprite_Handle_Vehicle_Enemy(sSprite* pSprite) {
5909 int16 Data0, Data4, Data8, DataC, Data10;
5910 sSprite* Data28 = 0;
5911
5912 if (pSprite->field_38) {
5913 pSprite->field_22 = eSprite_PersonType_AI;
5914 Sprite_Handle_Vehicle(pSprite);
5915 pSprite->field_22 = eSprite_PersonType_AI;
5916 return;
5917 }
5918
5919 if (pSprite->field_6F == eVehicle_DontTargetPlayer)
5920 goto loc_255DA;
5921
5922 Data0 = eSprite_Player;
5923 Data4 = eSprite_Civilian;
5924 Data8 = 0x3E;
5925 DataC = 0x46;
5926 Data10 = -1;
5927 if (Sprite_Find_By_Types(pSprite, Data0, Data4, Data8, DataC, Data10, Data28))
5928 goto loc_255DA;
5929
5930 Data0 = tool_RandomGet() & 3;
5931 if (!Data0)
5932 pSprite->field_54 = -1;
5933
5934 Data0 = pSprite->field_0;
5935 Data0 += 8;
5936 Data4 = pSprite->field_4;
5937 Data4 -= 5;
5938 Data8 = Data28->field_0;
5939 pSprite->field_2E = Data8;
5940 pSprite->field_26 = Data8;
5941 DataC = Data28->field_4;
5942 pSprite->field_30 = DataC;
5943 pSprite->field_28 = DataC;
5944
5945 loc_255DA:;
5946 pSprite->field_22 = eSprite_PersonType_AI;
5947 Sprite_Handle_Vehicle(pSprite);
5948
5949 if (pSprite->field_6F == eVehicle_JeepRocket)
5950 sub_245BF(pSprite);
5951
5952 sSprite* Data24 = pSprite + 1;
5953 Data24->field_18 = eSprite_Null;
5954
5955 Data24 = pSprite + 2;
5956 Data24->field_18 = eSprite_Flashing_Light;
5957 Data4 = pSprite->field_0;
5958 Data4 += 0x0D;
5959 Data24->field_0 = Data4;
5960
5961 Data4 = pSprite->field_4;
5962 Data4 -= 0x13;
5963
5964 Data4 += pSprite->field_52;
5965 Data24->field_4 = Data4;
5966 Data24->field_20 = pSprite->field_20;
5967 }
5968
Sprite_Handle_Helicopter_Enemy(sSprite * pSprite)5969 void cFodder::Sprite_Handle_Helicopter_Enemy(sSprite* pSprite) {
5970 int16 Data0;
5971 int16 Data4;
5972 int16 Data8;
5973 int16 DataC;
5974 int16 Data10, Data14, Data1C;
5975 sSprite* Data24 = 0, *Data30 = 0;
5976
5977 // Bullets don't hit choppers
5978 if (pSprite->field_38 == eSprite_Anim_Hit)
5979 pSprite->field_38 = eSprite_Anim_None;
5980
5981 if (pSprite->field_38) {
5982 mSprite_Helicopter_DestroyLight = -1;
5983
5984 pSprite->field_22 = eSprite_PersonType_AI;
5985 Sprite_Handle_Helicopter(pSprite);
5986 pSprite->field_22 = eSprite_PersonType_AI;
5987
5988 mSprite_Helicopter_DestroyLight = 0;
5989 goto loc_25288;
5990 }
5991
5992 if (!pSprite->field_43) {
5993 pSprite->field_46 = (pSprite->field_0 << 16) | (pSprite->field_4 & 0xFFFF);
5994 pSprite->field_43 = -1;
5995 }
5996
5997 if (pSprite->field_4C)
5998 --pSprite->field_4C;
5999
6000 if (pSprite->field_20)
6001 goto loc_250D2;
6002
6003 Data0 = pSprite->field_0;
6004 Data4 = pSprite->field_4;
6005 Data8 = ((int64)pSprite->field_46) >> 16;
6006 DataC = ((int64)pSprite->field_46) & 0xFFFF;
6007
6008 Map_Get_Distance_BetweenPoints_Within_Window(Data0, Data4, Data8, DataC);
6009 if (Data0 > 0x14)
6010 goto loc_250D2;
6011
6012 Data8 = pSprite->field_62;
6013 if ((uint16)Data8 >= 0x1F4) {
6014 if (pSprite->field_18 == eSprite_Helicopter_Homing_Enemy2)
6015 if (mHelicopterCall_X < 0)
6016 goto loc_24FF1;
6017
6018 if (!(tool_RandomGet() & 1))
6019 goto loc_2500F;
6020 }
6021
6022 loc_24FF1:;
6023 if (mVersionCurrent->isDemo()) {
6024 Data8 += 0x20;
6025 if (Data8)
6026 pSprite->field_62 = Data8;
6027
6028 }
6029 else {
6030 Data8 += 1;
6031 Data8 += mGame_Data.mGamePhase_Data.mSprite_Enemy_AggressionAverage;
6032
6033 if (Data8 >= 0)
6034 pSprite->field_62 = Data8;
6035 }
6036
6037 goto loc_25239;
6038
6039 loc_2500F:;
6040 if (pSprite->field_4C)
6041 goto loc_25239;
6042
6043 Data0 = map_GetRandomX();
6044 Data0 += 4;
6045 if (Data0 > mMapLoaded->getWidth())
6046 goto loc_25239;
6047
6048 Data8 = Data0;
6049 Data0 = map_GetRandomY();
6050 Data0 += 4;
6051
6052 if (Data0 > mMapLoaded->getHeight())
6053 goto loc_25239;
6054
6055 DataC = Data0;
6056
6057 Data8 <<= 4;
6058 Data0 = tool_RandomGet() & 0x0F;
6059 Data8 += Data0;
6060
6061 DataC <<= 4;
6062 Data0 = tool_RandomGet() & 0x0F;
6063 DataC += Data0;
6064
6065 if (Map_Terrain_Get_Moveable_Wrapper(mTiles_NotFlyable, Data8, DataC, Data10, Data14))
6066 goto loc_25239;
6067
6068 pSprite->field_26 = Data10;
6069 pSprite->field_28 = Data14;
6070 pSprite->field_4C = 0x5A;
6071 goto loc_25239;
6072
6073 loc_250D2:;
6074
6075 if (pSprite->field_6F == eVehicle_Helicopter)
6076 goto loc_251D2;
6077
6078 Data1C = pSprite->field_5E_Squad;
6079
6080 if (mSquads[Data1C / 9] == (sSprite**)INVALID_SPRITE_PTR)
6081 goto loc_251B4;
6082
6083 Data30 = mSquads[Data1C / 9][Data1C % 9];
6084 if (Data30 == INVALID_SPRITE_PTR)
6085 goto loc_251B4;
6086
6087 if (Data30->field_52)
6088 goto loc_251B4;
6089
6090 Data8 = Data30->field_0;
6091 Data8 += 8;
6092 DataC = Data30->field_4;
6093 DataC += -5;
6094
6095 if (Map_Terrain_Get_Moveable_Wrapper(mTiles_NotDriveable, Data8, DataC, Data10, Data14))
6096 goto loc_251B4;
6097
6098 Data0 = Data30->field_0;
6099 Data4 = Data30->field_4;
6100 Data8 = pSprite->field_0;
6101 DataC = pSprite->field_4;
6102 Map_Get_Distance_BetweenPoints_Within_Window(Data0, Data4, Data8, DataC);
6103
6104 mSprite_DistanceTo_Squad0 = Data0;
6105 if (Data0 < 0xFA)
6106 if (Sprite_Handle_Helicopter_Enemy_Weapon(pSprite, Data30))
6107 goto loc_251D2;
6108
6109 loc_251B4:;
6110 pSprite->field_5E_Squad += 1;
6111 if (pSprite->field_5E_Squad >= 0x1E)
6112 pSprite->field_5E_Squad = 0;
6113
6114 loc_251D2:;
6115 if (pSprite->field_62) {
6116 --pSprite->field_62;
6117 }
6118 else {
6119 pSprite->field_26 = ((int64)pSprite->field_46) >> 16;
6120 pSprite->field_28 = ((int64)pSprite->field_46) & 0xFFFF;
6121 goto loc_25239;
6122 }
6123
6124 Data0 = tool_RandomGet() & 0x1F;
6125 if (!Data0)
6126 goto loc_2500F;
6127
6128 if (!pSprite->field_20) {
6129 Data0 = tool_RandomGet() & 0x0F;
6130 if (!Data0) {
6131 sSprite* Data2C;
6132 Sprite_Create_Enemy(pSprite, Data2C);
6133 }
6134 }
6135
6136 loc_25239:;
6137 mSprite_Helicopter_DestroyLight = -1;
6138 pSprite->field_22 = eSprite_PersonType_AI;
6139 Sprite_Handle_Helicopter(pSprite);
6140
6141 pSprite->field_22 = eSprite_PersonType_AI;
6142 mSprite_Helicopter_DestroyLight = 0;
6143 Data24 = pSprite + 1;
6144 Data24->field_18 = eSprite_Null;
6145
6146 ++Data24;
6147 Data24->field_18 = eSprite_Null;
6148
6149 loc_25288:;
6150
6151 Data24 = pSprite + 3;
6152 Data24->field_18 = eSprite_Flashing_Light;
6153 Data0 = pSprite->field_A << 1;
6154
6155 Data4 = pSprite->field_0;
6156 Data4 += mSprite_Helicopter_Light_Positions[Data0];
6157 Data24->field_0 = Data4;
6158
6159 Data4 = pSprite->field_4;
6160 Data4 += mSprite_Helicopter_Light_Positions[Data0 + 1];
6161 Data24->field_4 = Data4;
6162
6163 Data24->field_20 = pSprite->field_20;
6164 }
6165
Sprite_Handle_Civilian_Unk(sSprite * pSprite)6166 void cFodder::Sprite_Handle_Civilian_Unk(sSprite* pSprite) {
6167 if (!pSprite->field_5C)
6168 return;
6169
6170 if ((tool_RandomGet() & 0x3F) != 9)
6171 return;
6172
6173 if (mSquad_Leader == INVALID_SPRITE_PTR)
6174 return;
6175
6176 pSprite->field_2E = mSquad_Leader->field_0;
6177 pSprite->field_30 = mSquad_Leader->field_4;
6178
6179 Sprite_Create_Civilian_Spear2(pSprite);
6180 }
6181
Sprite_Handle_Civilian_Movement(sSprite * pSprite)6182 void cFodder::Sprite_Handle_Civilian_Movement(sSprite* pSprite) {
6183
6184 // Destination change cool down
6185 if (pSprite->field_4C) {
6186 pSprite->field_4C -= 1;
6187 if (pSprite->field_4C)
6188 return;
6189 }
6190
6191 if (pSprite->field_18 == eSprite_Hostage || pSprite->field_18 == eSprite_Enemy_Leader) {
6192 pSprite->field_26 = pSprite->field_0;
6193 pSprite->field_28 = pSprite->field_4;
6194 }
6195 else {
6196 if (Sprite_Handle_Civilian_RandomMovement(pSprite) < 0)
6197 return;
6198 }
6199
6200 // Random time until destination change
6201 int16 Data0 = tool_RandomGet() & 0x3F;
6202 Data0 += 0x14;
6203 pSprite->field_4C = static_cast<int8>(Data0);
6204 }
6205
Sprite_Handle_Civilian_Within_Range_OpenCloseDoor(sSprite * pSprite)6206 int16 cFodder::Sprite_Handle_Civilian_Within_Range_OpenCloseDoor(sSprite* pSprite) {
6207
6208 if (!mSprite_OpenCloseDoor_Ptr)
6209 return -1;
6210
6211 if (pSprite->field_4C) {
6212 --pSprite->field_4C;
6213 return 0;
6214 }
6215
6216 sSprite* Data28 = mSprite_OpenCloseDoor_Ptr;
6217
6218 int16 Data0 = pSprite->field_0;
6219 int16 Data4 = pSprite->field_4;
6220 int16 Data8 = Data28->field_0;
6221 int16 DataC = Data28->field_4;
6222
6223 pSprite->field_26 = Data8;
6224 pSprite->field_28 = DataC;
6225
6226 mSprite_Civilian_Tmp_X = Data0;
6227 mSprite_Civilian_Tmp_Y = Data4;
6228 word_3B481 = Data8;
6229 word_3B483 = DataC;
6230 int16 Data10 = 0x20;
6231
6232 Map_Get_Distance_BetweenPoints(Data0, Data4, Data8, Data10, DataC);
6233 if (Data0 <= 3) {
6234 Sprite_Destroy_Wrapper(pSprite);
6235 mSprite_Civilian_GotHome = -1;
6236 return 1;
6237 }
6238
6239 if (Data0 < 6) {
6240 Data28->field_2A = 0x0A;
6241 return 0;
6242 }
6243
6244 Data0 = mSprite_Civilian_Tmp_X;
6245 Data4 = mSprite_Civilian_Tmp_Y;
6246 Data8 = word_3B481;
6247 DataC = word_3B483;
6248
6249 if (!Map_PathCheck_CalculateTo(Data0, Data4, Data8, DataC))
6250 return 0;
6251
6252 // Move toward top left
6253 Data0 = tool_RandomGet() & 0x3F;
6254 if (Data0)
6255 return 0;
6256
6257 pSprite->field_26 = pSprite->field_0;
6258 pSprite->field_28 = pSprite->field_4;
6259 pSprite->field_26 -= 0x10;
6260 pSprite->field_28 -= 0x20;
6261 pSprite->field_4C = 0x1E;
6262
6263 return 0;
6264 }
6265
Sprite_Handle_Civilian_Death(sSprite * pSprite)6266 void cFodder::Sprite_Handle_Civilian_Death(sSprite* pSprite) {
6267
6268 if (pSprite->field_8 != 0xD6) {
6269 word_3B2D1[2] = -1;
6270
6271 if (mGame_Data.mGamePhase_Data.mGoals_Remaining[eObjective_Protect_Civilians - 1])
6272 mPhase_Aborted = true;
6273
6274 if (mGame_Data.mGamePhase_Data.mGoals_Remaining[eObjective_Get_Civilian_Home - 1])
6275 mPhase_Aborted = true;
6276
6277 pSprite->field_8 = 0xD6;
6278 pSprite->field_A = 0;
6279
6280 int16 Data0 = tool_RandomGet() & 7;
6281 int16 Data4 = mSprite_Civilian_Sound_Death[Data0];
6282
6283 Sound_Play(pSprite, Data4, 0x14);
6284 }
6285 else {
6286 //loc_2584A
6287 pSprite->field_A += 1;
6288 if (pSprite->field_A < 9)
6289 return;
6290
6291 Sprite_Destroy_Wrapper(pSprite);
6292 }
6293 }
6294
sub_2593D(sSprite * pSprite)6295 void cFodder::sub_2593D(sSprite* pSprite) {
6296 Sprite_XY_Store(pSprite);
6297
6298 if (pSprite->field_44)
6299 --pSprite->field_44;
6300 else {
6301 int16 Data0 = pSprite->field_26;
6302 int16 Data4 = pSprite->field_28;
6303
6304 if (Sprite_Direction_Between_Points(pSprite, Data0, Data4) < 0)
6305 mSprite_Reached_Target = -1;
6306 }
6307
6308 if (pSprite->field_18 != eSprite_Seal) {
6309 int16 Data0 = tool_RandomGet();
6310 int16 Data4 = Data0;
6311 Data0 &= 0x0E;
6312 if (Data4 < 0)
6313 Data0 = -Data0;
6314
6315 pSprite->field_10 += Data0;
6316 pSprite->field_10 &= 0x1FE;
6317 }
6318 //loc_259BE
6319 if (!Sprite_Reached_Target(pSprite)) {
6320 Sprite_Movement_Speed_Update(pSprite);
6321
6322 if (!word_3B25B)
6323 Sprite_Movement_Calculate(pSprite);
6324 }
6325 //loc_259D4
6326 Sprite_Reached_MapEdge(pSprite);
6327
6328 int16 Data4 = 0;
6329 Sprite_Terrain_Check(pSprite, Data4);
6330
6331 Data4 = pSprite->field_60;
6332
6333 if (Data4 == 6) {
6334 Sprite_XY_Restore(pSprite);
6335 return;
6336 }
6337
6338 if (Data4 != 4) {
6339 if (Data4 != 5)
6340 return;
6341
6342 pSprite->field_52 = 5;
6343 return;
6344 }
6345
6346 pSprite->field_52 = 3;
6347 }
6348
sub_25A31(sSprite * pSprite)6349 void cFodder::sub_25A31(sSprite* pSprite) {
6350
6351 if (mSprite_Reached_Target || word_3B25B)
6352 return;
6353
6354 pSprite->field_2A += 1;
6355 pSprite->field_2A &= 3;
6356 if (pSprite->field_2A)
6357 return;
6358
6359 pSprite->field_A += 1;
6360 pSprite->field_A &= 1;
6361 }
6362
sub_25A66(sSprite * pSprite)6363 void cFodder::sub_25A66(sSprite* pSprite) {
6364 int16 Data0 = pSprite->field_10;
6365
6366 Data0 >>= 5;
6367 Data0 -= 1;
6368 Data0 ^= 0x0F;
6369 Data0 &= 0x0E;
6370
6371 int16 Data4 = pSprite->field_A;
6372 Data4 &= 1;
6373 Data0 |= Data4;
6374 pSprite->field_A = Data0;
6375 }
6376
Sprite_Handle_Civilian_RandomMovement(sSprite * pSprite)6377 int16 cFodder::Sprite_Handle_Civilian_RandomMovement(sSprite* pSprite) {
6378 int16 Data8 = map_GetRandomX();
6379 Data8 += 4;
6380 if (Data8 >= mMapLoaded->getWidth())
6381 return -1;
6382
6383 int16 DataC = map_GetRandomY();
6384 DataC += 4;
6385 if (DataC >= mMapLoaded->getHeight())
6386 return -1;
6387
6388 Data8 <<= 4;
6389 Data8 += tool_RandomGet() & 0x0F;
6390
6391 DataC <<= 4;
6392 DataC += tool_RandomGet() & 0x0F;
6393
6394 int16 X, Y;
6395
6396 if (Map_Terrain_Get_Moveable_Wrapper(mTiles_NotFlyable, Data8, DataC, X, Y))
6397 return -1;
6398
6399 pSprite->field_26 = X;
6400 pSprite->field_28 = Y;
6401 return 0;
6402 }
6403
Sprite_Create_Civilian_Spear2(sSprite * pSprite)6404 int16 cFodder::Sprite_Create_Civilian_Spear2(sSprite* pSprite) {
6405 if (mPhase_Completed_Timer)
6406 return -1;
6407
6408 if (!pSprite->field_2E)
6409 return -1;
6410
6411 int16 Data0 = 1;
6412 sSprite* Data2C = 0, *Data30 = 0;
6413 if (Sprite_Get_Free_Max42(Data0, Data2C, Data30))
6414 return -1;
6415
6416 if (mSprite_Projectile_Counters[2] == 0x14)
6417 return -1;
6418
6419 ++mSprite_Projectile_Counters[2];
6420 Data2C->field_0 = pSprite->field_0;
6421 Data2C->field_4 = pSprite->field_4;
6422 Data2C->field_8 = 0xD7;
6423 Data2C->field_A = 0;
6424 Data2C->field_12 = 9;
6425 Data0 = pSprite->field_62;
6426
6427 Data0 >>= 3;
6428 Data0 += 8;
6429 if (Data0 > 0x10)
6430 Data0 = 0x10;
6431
6432 Data2C->field_12 = Data0;
6433 Data2C->field_18 = eSprite_Civilian_Spear2;
6434 Data2C->field_1E_Big = pSprite->field_1E_Big;
6435 Data2C->field_1E_Big += 0x60000;
6436
6437 Data2C->field_52 = pSprite->field_52;
6438 Data2C->field_22 = pSprite->field_22;
6439 Data2C->field_2C = eSprite_Draw_Second;
6440 Data0 = 0x32;
6441 Data0 += pSprite->field_62;
6442
6443 Data2C->field_4A = Data0;
6444 Data2C->field_36 = 0x18;
6445 Data2C->field_43 = 0;
6446 Data2C->field_44 = 0;
6447 Data2C->field_2E = pSprite->field_2E;
6448 Data2C->field_30 = pSprite->field_30;
6449 Data2C->field_2E += 7;
6450 Data2C->field_52 = 0;
6451 Data2C->field_3A = 0;
6452 Data2C->field_1A_sprite = pSprite;
6453 Data2C->field_2A = 2;
6454 Data2C->field_16 = 0;
6455 Data2C->field_14 = 2;
6456
6457 if (Data2C->field_A == 4)
6458 Data2C->field_14 = -1;
6459
6460 Data2C->field_34 = -1;
6461 Data2C->field_50 = 0;
6462 Data2C->field_59 = 0;
6463
6464 int16 Data8 = 7;
6465 Data0 = tool_RandomGet();
6466 int16 Data4 = Data0;
6467 Data0 &= Data8;
6468
6469 if (Data4 < 0)
6470 Data0 = -Data0;
6471
6472 Data2C->field_50 = Data0;
6473
6474 if (mMapLoaded->getTileType() == eTileTypes_Moors) {
6475 Data0 = tool_RandomGet() & 1;
6476 if (Data0)
6477 goto loc_25D9D;
6478 Data4 = 0x11;
6479 goto loc_25DA3;
6480
6481 loc_25D9D:;
6482 Data4 = 0x10;
6483
6484 loc_25DA3:;
6485 Sound_Play(pSprite, Data4, 0);
6486 }
6487
6488 //loc_25DB1
6489 Data2C->field_64 = 0;
6490 return 0;
6491 }
6492
sub_25DCF(sSprite * pSprite)6493 int16 cFodder::sub_25DCF(sSprite* pSprite) {
6494 sSprite* Data2C = 0, *Data30 = 0;
6495 int16 Data0;
6496
6497 if (pSprite->field_38 == eSprite_Anim_None)
6498 return 0;
6499
6500 if (pSprite->field_38 == eSprite_Anim_Die4)
6501 goto loc_25E8F;
6502
6503 if (!pSprite->field_2A) {
6504 pSprite->field_2A = 0x14;
6505 pSprite->field_A = 0;
6506 }
6507 pSprite->field_2A -= 1;
6508 if (!pSprite->field_2A)
6509 return Sprite_Destroy_Wrapper(pSprite);
6510
6511 //loc_25E19
6512 if (pSprite->field_2A >= 0x0A)
6513 goto loc_25E54;
6514
6515 pSprite->field_A = 0;
6516 if (pSprite->field_8 == 0xD5) {
6517 //loc_25E47
6518 pSprite->field_8 = 0x7C;
6519 return -1;
6520 }
6521
6522 pSprite->field_8 = 0xD5;
6523 return -1;
6524
6525 loc_25E54:;
6526 if (Sprite_Create_BloodTrail(pSprite, Data2C, Data30))
6527 return -1;
6528
6529 Data2C->field_4 += tool_RandomGet() & 3;
6530 Data2C->field_0 -= 4;
6531 Data2C->field_0 += tool_RandomGet() & 7;
6532 return -1;
6533
6534 loc_25E8F:;
6535 if (pSprite->field_8 != 0xE1) {
6536 pSprite->field_8 = 0xE1;
6537 pSprite->field_A = 0;
6538 pSprite->field_2A = 0;
6539 return -1;
6540 }
6541
6542 pSprite->field_2A += 2;
6543 Data0 = mSprite_Seal_Frames[pSprite->field_2A / 2];
6544
6545 if (Data0 >= 0) {
6546
6547 pSprite->field_A = Data0;
6548 return -1;
6549 }
6550
6551 pSprite->field_18 = eSprite_Explosion;
6552 pSprite->field_26 = 0x1F45;
6553 pSprite->field_28 = -3;
6554 return -1;
6555 }
6556
sub_25F2B(sSprite * pSprite)6557 void cFodder::sub_25F2B(sSprite* pSprite) {
6558
6559 if (word_3B2ED) {
6560 pSprite->field_8 = 0xD8;
6561 pSprite->field_A = 1;
6562 Sprite_XY_Restore(pSprite);
6563 return;
6564 }
6565
6566 if (word_3B2D1[2] != pSprite->field_0 || word_3B2D1[3] != pSprite->field_2)
6567 return;
6568
6569 if (word_3B2D1[4] != pSprite->field_4 || word_3B2D1[5] != pSprite->field_6)
6570 return;
6571
6572 pSprite->field_8 = 0xDA;
6573
6574 int16 Data0 = mMission_EngineTicks & 0x0F;
6575 if (!Data0) {
6576 Data0 = tool_RandomGet() & 0x06;
6577 pSprite->field_32 = mSprite_Hostage_Frames[Data0 / 2];
6578 }
6579
6580 pSprite->field_A = pSprite->field_32;
6581 }
6582
Sprite_Handle_Hostage_Movement(sSprite * pSprite)6583 void cFodder::Sprite_Handle_Hostage_Movement(sSprite* pSprite) {
6584 int16 Data0, Data4, Data8, DataC, Data10;
6585 sSprite* Data28 = 0;
6586
6587 if (pSprite->field_18 == eSprite_Enemy_Leader)
6588 goto CheckRescueTent;
6589
6590 // No known rescue tent?
6591 if (!mHostage_Rescue_Tent)
6592 goto loc_2608B;
6593
6594 if (pSprite->field_74) {
6595 pSprite->field_74 -= 1;
6596 goto loc_2608B;
6597 }
6598 //loc_2600B
6599
6600 pSprite->field_74 = -56;
6601
6602 Data8 = mHostage_Rescue_Tent->field_0 + 10;
6603 DataC = mHostage_Rescue_Tent->field_4 - 5;
6604 Data0 = pSprite->field_0;
6605 Data4 = pSprite->field_4;
6606 Data10 = 0x80;
6607
6608 // Distance to rescue tent < 127?
6609 Map_Get_Distance_BetweenPoints(Data0, Data4, Data8, Data10, DataC);
6610 if (Data10 < 0x7F)
6611 pSprite->field_5E = (int16)(mHostage_Rescue_Tent - mSprites.data());
6612
6613 loc_2608B:;
6614 word_3B2ED = 0;
6615 Data0 = eSprite_Hostage_Rescue_Tent;
6616 Data4 = eSprite_Enemy;
6617 Data8 = eSprite_Player;
6618 DataC = -1;
6619 if (Sprite_Find_By_Types(pSprite, Data0, Data4, Data8, DataC, Data10, Data28))
6620 return;
6621
6622 // Found Tent Nearby
6623 if (Data4 == eSprite_Hostage_Rescue_Tent) {
6624
6625 pSprite->field_26 = Data28->field_0 + 10;
6626 pSprite->field_28 = Data28->field_4 - 5;
6627
6628 Data0 = pSprite->field_0;
6629 Data4 = pSprite->field_4;
6630 Data8 = pSprite->field_26;
6631 DataC = pSprite->field_28;
6632 Data10 = 0x10;
6633 Map_Get_Distance_BetweenPoints(Data0, Data4, Data8, Data10, DataC);
6634 if (Data10 >= 0x10)
6635 goto loc_2620F;
6636
6637 if (Data0 >= 3)
6638 return;
6639
6640 mHostage_Count -= 1;
6641 Sprite_Destroy_Wrapper(pSprite);
6642 return;
6643
6644 // Found Enemy near by
6645 }
6646 else if (Data4 == eSprite_Enemy) {
6647 Data28->field_70 = pSprite;
6648 pSprite->field_26 = pSprite->field_0;
6649 pSprite->field_28 = pSprite->field_4;
6650 word_3B2ED = -1;
6651 return;
6652 }
6653
6654 pSprite->field_26 = Data28->field_0 + 4;
6655 pSprite->field_28 = Data28->field_4 - 6;
6656
6657 // Not in vehicle?
6658 if (!Data28->field_6E)
6659 goto loc_2620F;
6660
6661 // Vehicle Has Speed?
6662 if (Data28->field_6A_sprite->field_36 > 2)
6663 goto loc_2620F;
6664
6665 // Vehicle has height?
6666 if (Data28->field_6A_sprite->field_20 > 3)
6667 goto loc_2620F;
6668
6669 Data0 = Data28->field_6A_sprite->field_0;
6670 Data4 = Data28->field_6A_sprite->field_4;
6671 Data8 = pSprite->field_0;
6672 DataC = pSprite->field_4;
6673 Data10 = 0x10;
6674
6675 Map_Get_Distance_BetweenPoints(Data0, Data4, Data8, Data10, DataC);
6676 if (Data0 > 0x0A) {
6677 loc_2620F:;
6678 Data0 = tool_RandomGet() & 0x3F;
6679 if (Data0)
6680 return;
6681
6682 sub_26490(pSprite);
6683 return;
6684 }
6685
6686 pSprite->field_6E = -1;
6687 return;
6688
6689 CheckRescueTent:;
6690 word_3B2ED = 0;
6691 Data0 = eSprite_Player;
6692 Data4 = eSprite_Hostage_Rescue_Tent;
6693 Data8 = -1;
6694 if (Sprite_Find_By_Types(pSprite, Data0, Data4, Data8, DataC, Data10, Data28))
6695 return;
6696
6697 if (Data4 == eSprite_Hostage_Rescue_Tent) {
6698
6699 pSprite->field_26 = Data28->field_0 + 0x0A;
6700 pSprite->field_28 = Data28->field_4 - 0x05;
6701
6702 Data0 = pSprite->field_0;
6703 Data4 = pSprite->field_4;
6704 Data8 = pSprite->field_26;
6705 DataC = pSprite->field_28;
6706 Data10 = 0x10;
6707 Map_Get_Distance_BetweenPoints(Data0, Data4, Data8, Data10, DataC);
6708 if (Data0 >= 3)
6709 return;
6710 mHostage_Count -= 1;
6711
6712 Sprite_Destroy(pSprite + 1);
6713 Sprite_Destroy_Wrapper(pSprite);
6714 return;
6715 }
6716
6717 // Another Player
6718 word_3B2ED = -1;
6719 pSprite->field_8 = 0xD8;
6720 pSprite->field_26 = Data28->field_0 + 4;
6721 pSprite->field_28 = Data28->field_4 - 6;
6722
6723 // Not in vehicle?
6724 if (!Data28->field_6E)
6725 goto loc_263E5;
6726
6727 // Vehicle has speed?
6728 if (Data28->field_6A_sprite->field_36 > 2)
6729 goto loc_263E5;
6730
6731 // Vehicle has height
6732 if (Data28->field_6A_sprite->field_20 > 3)
6733 goto loc_263E5;
6734
6735 Data0 = Data28->field_6A_sprite->field_0;
6736 Data4 = Data28->field_6A_sprite->field_4;
6737 Data8 = pSprite->field_0;
6738 DataC = pSprite->field_4;
6739 Data10 = 0x10;
6740
6741 Map_Get_Distance_BetweenPoints(Data0, Data4, Data8, Data10, DataC);
6742 if (Data0 <= 0x0F) {
6743 pSprite->field_6E = -1;
6744 return;
6745 }
6746
6747 loc_263E5:;
6748 Data0 = tool_RandomGet() & 7;
6749 if (Data0)
6750 return;
6751
6752 sub_26490(pSprite);
6753 }
6754
Sprite_Handle_Hostage_FrameUpdate2(sSprite * pSprite)6755 void cFodder::Sprite_Handle_Hostage_FrameUpdate2(sSprite* pSprite) {
6756 int16 Data0 = pSprite->field_4A;
6757
6758 pSprite->field_2A += 1;
6759 pSprite->field_2A &= 1;
6760 if (!pSprite->field_2A)
6761 Data0 += 2;
6762
6763 Data0 &= 6;
6764
6765 pSprite->field_4A = Data0;
6766 pSprite->field_A = mSprite_Hostage_Frames[Data0 / 2];
6767
6768 }
6769
Sprite_Handle_Hostage_FrameUpdate(sSprite * pSprite)6770 void cFodder::Sprite_Handle_Hostage_FrameUpdate(sSprite* pSprite) {
6771 int16 Data0 = pSprite->field_10;
6772 Data0 >>= 5;
6773 Data0 -= 1;
6774 Data0 ^= 0x0F;
6775 Data0 &= 0x0E;
6776
6777 int16 Data4 = Data0;
6778 Data4 >>= 1;
6779 Data4 += Data0;
6780
6781 pSprite->field_A += Data4;
6782 }
6783
sub_26490(sSprite * pSprite)6784 void cFodder::sub_26490(sSprite* pSprite) {
6785 ++pSprite->field_5E;
6786 if (pSprite->field_5E >= (mParams->mSpritesMax - 2))
6787 pSprite->field_5E = 0;
6788 }
6789
sub_264B0(sSprite * pSprite)6790 void cFodder::sub_264B0(sSprite* pSprite) {
6791 int16 Data0, Data4;
6792
6793 if (!sub_222A3(pSprite))
6794 goto loc_264CF;
6795
6796 if (!mGame_Data.mGamePhase_Data.mGoals_Remaining[eObjective_Protect_Civilians - 1])
6797 return;
6798
6799 mPhase_Aborted = true;
6800 return;
6801
6802 loc_264CF:;
6803
6804 if (mTroops_Enemy_Count >= mParams->mSpawnEnemyMax) {
6805 pSprite->field_8 = 0x9B;
6806 return;
6807 }
6808
6809 pSprite->field_2C = eSprite_Draw_First;
6810 if (pSprite->field_43 < 0)
6811 goto loc_26580;
6812
6813 pSprite->field_43 -= 1;
6814 if (pSprite->field_43 == 0x14 || pSprite->field_43 == 0x0A)
6815 goto loc_265B1;
6816
6817 if (pSprite->field_43 >= 0) {
6818 pSprite->field_8 = 0x7C;
6819 return;
6820 }
6821
6822 pSprite->field_8 = 0x9B;
6823 Sound_Play(pSprite, eSound_Effect_BuildingDoor2, 1);
6824
6825 Data0 = tool_RandomGet() & 0x0F;
6826 Data4 = 0x14;
6827 Data4 -= mGame_Data.mGamePhase_Data.mSprite_Enemy_AggressionMax;
6828 if (Data4 < 0)
6829 Data0 = 0;
6830
6831 Data4 <<= 3;
6832 Data4 += Data0;
6833 pSprite->field_12 = Data4;
6834
6835 loc_26580:;
6836 pSprite->field_12 -= 1;
6837 if (pSprite->field_12 >= 0)
6838 return;
6839
6840 Data0 = tool_RandomGet() & 0x0F;
6841 Data0 += 6;
6842 pSprite->field_43 = static_cast<int8>(Data0);
6843 pSprite->field_8 = 0x7C;
6844
6845 loc_265B1:;
6846 sSprite* Data2C = 0, *Data30 = 0;
6847
6848 if (!Sprite_Create_Native(pSprite, Data2C, Data30)) {
6849 Data2C->field_4 -= 4;
6850 return;
6851 }
6852
6853 pSprite->field_12 = 0;
6854 pSprite->field_43 = -1;
6855 }
6856
Sprite_Handle_Helicopter_Callpad_InRange(sSprite * pSprite,sSprite * & pData2C)6857 int16 cFodder::Sprite_Handle_Helicopter_Callpad_InRange(sSprite* pSprite, sSprite*& pData2C) {
6858 sSprite** Data28 = mSprite_TroopsAlive;
6859 int16 Data0 = 0;
6860
6861 do {
6862 if (*Data28 == INVALID_SPRITE_PTR || *Data28 == 0)
6863 return -1;
6864
6865 pData2C = *Data28++;
6866
6867 if (pData2C->field_6E)
6868 continue;
6869 if (pData2C->field_38)
6870 continue;
6871
6872 Data0 = pSprite->field_0 - 2;
6873 int16 Data4 = pSprite->field_4 - 8;
6874 int16 Data8 = pData2C->field_0;
6875 int16 DataC = pData2C->field_4;
6876 int16 Data10 = 0x20;
6877
6878 Map_Get_Distance_BetweenPoints(Data0, Data4, Data8, Data10, DataC);
6879
6880 if (Data0 < 9)
6881 break;
6882
6883 } while (1);
6884
6885 return 0;
6886 }
6887
Sprite_Handle_Helicopter_Human_CallCheck(sSprite * pSprite)6888 void cFodder::Sprite_Handle_Helicopter_Human_CallCheck(sSprite* pSprite) {
6889 if (pSprite->field_75)
6890 return;
6891
6892 pSprite->field_26 = pSprite->field_0;
6893 pSprite->field_28 = pSprite->field_4;
6894 if (mHelicopterCall_X < 0)
6895 return;
6896
6897 pSprite->field_26 = mHelicopterCall_X;
6898 pSprite->field_28 = mHelicopterCall_Y;
6899 int16 Data0 = pSprite->field_0;
6900 int16 Data4 = pSprite->field_4;
6901 int16 Data8 = pSprite->field_26;
6902 int16 DataC = pSprite->field_28;
6903 int16 Data10 = 0x3F;
6904 Map_Get_Distance_BetweenPoints(Data0, Data4, Data8, Data10, DataC);
6905 if (Data0 >= 0x2C)
6906 return;
6907
6908 pSprite->field_75 = -1;
6909 pSprite->field_6E = -1;
6910 }
6911
Sprite_Handle_Computer(sSprite * pSprite,int16 pData1C)6912 void cFodder::Sprite_Handle_Computer(sSprite* pSprite, int16 pData1C) {
6913
6914 if (pSprite->field_38 == eSprite_Anim_Die3) {
6915 if (pSprite->field_74 >= pData1C) {
6916 pSprite->field_18 = eSprite_Explosion2;
6917 return;
6918 }
6919 pSprite->field_74 += 1;
6920 pSprite->field_38 = eSprite_Anim_None;
6921 }
6922 pSprite->field_A = 0;
6923
6924 int32 Data0 = pSprite->field_74;
6925 Data0 += 0x28;
6926 Data0 <<= 8;
6927 bool of = false;
6928
6929 if (((uint16)pSprite->field_5E) + Data0 > 0xFFFF)
6930 of = true;
6931
6932 pSprite->field_5E += Data0;
6933 if (of)
6934 return;
6935
6936 Data0 = pSprite->field_2A;
6937 Data0 += 2;
6938 if (Data0 >= 8)
6939 Data0 = 0;
6940
6941 pSprite->field_2A = Data0;
6942 pSprite->field_8 = mSprite_Computer_Animation[Data0 / 2];
6943 pSprite->field_20 = mSprite_Computer_Frames[Data0 / 2];
6944 }
6945
Map_Get_Distance_BetweenSprites_Within_Window(const sSprite * pSprite,const sSprite * pSprite2)6946 int16 cFodder::Map_Get_Distance_BetweenSprites_Within_Window( const sSprite *pSprite, const sSprite *pSprite2 ) {
6947
6948 auto X1 = pSprite->field_0;
6949 auto Y1 = pSprite->field_4;
6950
6951 auto X2 = pSprite2->field_0;
6952 auto Y2 = pSprite2->field_4;
6953
6954 return Map_Get_Distance_BetweenPoints_Within_Window(X1, Y1, X2, Y2);
6955 }
6956
Map_Get_Distance_BetweenPoints_Within_Window(int16 & pX,int16 pY,int16 & pX2,int16 & pY2)6957 int16 cFodder::Map_Get_Distance_BetweenPoints_Within_Window(int16& pX, int16 pY, int16& pX2, int16& pY2) {
6958 const int8* Data24 = mMap_Distance_Calculations;
6959 int16 Data10 = 0;
6960
6961 pX2 -= pX;
6962 if (pX2 < 0)
6963 pX2 = -pX2;
6964
6965 if (pX2 >= getWindowWidth())
6966 goto loc_29EBB;
6967
6968 pY2 -= pY;
6969 if (pY2 < 0)
6970 pY2 = -pY2;
6971
6972 if (pY2 >= getWindowWidth())
6973 goto loc_29EBB;
6974
6975
6976 for (;;) {
6977 if (pX2 <= 0x1F)
6978 if (pY2 <= 0x1F)
6979 break;
6980
6981 pX2 >>= 1;
6982 pY2 >>= 1;
6983 ++Data10;
6984 }
6985 //loc_29E8C
6986 pY2 <<= 5;
6987 pY2 |= pX2;
6988 pX = 0;
6989
6990 pX = Data24[pY2];
6991 pX <<= Data10;
6992 return pX;
6993
6994 loc_29EBB:;
6995 pX = 0x3E8;
6996
6997 return 0x3E8;
6998 }
6999
Sprite_Create_Native(sSprite * pSprite,sSprite * & pData2C,sSprite * & pData30)7000 int16 cFodder::Sprite_Create_Native(sSprite* pSprite, sSprite*& pData2C, sSprite*& pData30) {
7001 int16 Data4;
7002
7003 if (!pSprite->field_5C)
7004 return -1;
7005
7006 if (mPhase_Complete)
7007 return -1;
7008
7009 if (mTroops_Enemy_Count >= mParams->mSpawnEnemyMax)
7010 return -1;
7011
7012 int16 Data0 = 1;
7013
7014 Sprite_Get_Free_Max29(Data0, pData2C, pData30);
7015 if (Data0)
7016 return -1;
7017
7018 pData2C->Clear();
7019 pData2C->field_18 = mSpawnSpriteType;
7020 pData2C->field_0 = pSprite->field_0;
7021 pData2C->field_0 -= 6;
7022 pData2C->field_4 = pSprite->field_4;
7023 pData2C->field_4 += 4;
7024 pData2C->field_8 = 0x7C;
7025 pData2C->field_4A = 0;
7026 pData2C->field_22 = eSprite_PersonType_Native;
7027
7028 Data0 = tool_RandomGet();
7029 Data4 = Data0;
7030 Data0 &= 0x1E;
7031 if (Data4 < 0)
7032 Data0 = -Data0;
7033
7034 Data0 += 0x1C0;
7035 pData2C->field_10 = Data0;
7036 Data4 &= 0x0F;
7037 Data4 += 8;
7038 pData2C->field_44 = static_cast<int8>(Data4);
7039 return 0;
7040 }
7041
Direction_Between_Points(int16 & pData0,int16 & pData4,int16 & pData8,int16 & pDataC)7042 int16 cFodder::Direction_Between_Points(int16& pData0, int16& pData4, int16& pData8, int16& pDataC) {
7043 int16 Data10 = 0, Data14 = 0;
7044
7045 pData0 -= pData8;
7046 pData4 -= pDataC;
7047 if (pData0 < 0)
7048 Data10 = 1;
7049
7050 Data10 = -Data10;
7051 if (pData0 < 0)
7052 pData0 = -pData0;
7053
7054 if (pData4 < 0)
7055 Data14 = 1;
7056
7057 Data14 = -Data14;
7058 if (pData4 < 0)
7059 pData4 = -pData4;
7060
7061 pData8 = 9;
7062 do {
7063 int32 eax = 1 << pData8;
7064
7065 if (pData0 & eax)
7066 break;
7067
7068 if (pData4 & eax)
7069 break;
7070
7071 } while (--pData8 >= 0);
7072
7073 pData8 -= 4;
7074 if (pData8 >= 0) {
7075 pData0 >>= pData8;
7076 pData4 >>= pData8;
7077 }
7078
7079 pData4 <<= 5;
7080 pData4 |= pData0;
7081 //pData4 <<= 1;
7082 pData4 = mMap_DirectionsBetweenPoints[pData4];
7083 if (pData4 < 0)
7084 return pData4;
7085
7086 pData4 <<= 1;
7087
7088 if (Data10 < 0)
7089 goto loc_29FC2;
7090
7091 if (Data14 < 0)
7092 goto loc_29FAD;
7093
7094 pData0 = 0x80;
7095 pData0 -= pData4;
7096 pData0 &= 0x1FE;
7097
7098 pData4 = pData0;
7099 pData0 = 0;
7100 return 0;
7101
7102 loc_29FAD:;
7103 pData4 += 0x80;
7104 pData4 &= 0x1FE;
7105 pData0 = 0;
7106 return 0;
7107
7108 loc_29FC2:;
7109 if (Data14 >= 0) {
7110 pData4 += 0x180;
7111 pData4 &= 0x1FE;
7112 pData0 = 0;
7113 return 0;
7114 }
7115
7116 pData0 = 0x180;
7117 pData0 -= pData4;
7118 pData0 &= 0x1FE;
7119 pData4 = pData0;
7120 pData0 = 0;
7121
7122 return 0;
7123 }
7124
map_GetRandomX()7125 int16 cFodder::map_GetRandomX() {
7126
7127 return tool_RandomGet(1, mMapLoaded->getWidth() - 1);
7128 }
7129
map_GetRandomY()7130 int16 cFodder::map_GetRandomY() {
7131
7132 return tool_RandomGet(1, mMapLoaded->getHeight() - 1);
7133 }
7134
tool_RandomGet(size_t pMin,size_t pMax)7135 uint16 cFodder::tool_RandomGet(size_t pMin, size_t pMax) {
7136 uint16 Rand = mRandom.getu();
7137 uint16 Mod = (uint16) (pMax - pMin + 1);
7138
7139 return (uint16) ((Rand % Mod) + pMin);
7140 }
7141
tool_RandomGet()7142 int16 cFodder::tool_RandomGet() {
7143
7144 return mRandom.get();
7145 }
7146
Sprite_Movement_Calculate(sSprite * pSprite)7147 void cFodder::Sprite_Movement_Calculate(sSprite* pSprite) {
7148 mSprite_Bullet_Destroy = 0;
7149 if (!pSprite->field_36)
7150 return;
7151
7152 //loc_2A10D
7153 pSprite->field_10 &= 0x1FE;
7154 int16 Data4 = pSprite->field_10;
7155
7156 int16 Data8 = mMap_Direction_Calculations[Data4 / 2];
7157
7158 Data4 += 0x80;
7159 Data4 &= 0x1FE;
7160 int16 DataC = mMap_Direction_Calculations[Data4 / 2];
7161 Data8 >>= 2;
7162 DataC >>= 2;
7163 //seg007:064F
7164
7165 int32 DataaC = (int32)DataC;
7166 int32 Dataa8 = (int32)Data8;
7167
7168 Data4 = pSprite->field_36;
7169
7170 Dataa8 *= Data4;
7171 DataaC *= Data4;
7172
7173 int32 tmp = (pSprite->field_2 & 0xFFFF) | pSprite->field_0 << 16;
7174 tmp += Dataa8;
7175
7176 pSprite->field_2 = tmp & 0xFFFF;
7177 pSprite->field_0 = tmp >> 16;
7178
7179 if (pSprite->field_0 < 0) {
7180 pSprite->field_0 = 0;
7181 pSprite->field_2 = 0;
7182 mSprite_Bullet_Destroy = -1;
7183 }
7184
7185 tmp = (pSprite->field_6 & 0xFFFF) | pSprite->field_4 << 16;
7186 tmp += DataaC;
7187 pSprite->field_6 = tmp & 0xFFFF;
7188 pSprite->field_4 = tmp >> 16;
7189
7190 if (pSprite->field_4 < 0) {
7191 pSprite->field_6 = 0;
7192 pSprite->field_4 = 0;
7193 mSprite_Bullet_Destroy = -1;
7194 }
7195 }
7196
Sprite_Direction_Between_Points(sSprite * pSprite,int16 & pData0,int16 & pData4)7197 int16 cFodder::Sprite_Direction_Between_Points(sSprite* pSprite, int16& pData0, int16& pData4) {
7198 pData0 -= pSprite->field_0;
7199 pData4 -= pSprite->field_4;
7200
7201 int16 Data10 = 0;
7202 if (pData0 < 0)
7203 Data10 = 1;
7204 Data10 = -Data10;
7205
7206 if (pData0 < 0)
7207 pData0 = -pData0;
7208
7209 int16 Data14 = 0;
7210 if (pData4 < 0)
7211 Data14 = 1;
7212 Data14 = -Data14;
7213
7214 if (pData4 < 0)
7215 pData4 = -pData4;
7216
7217 int16 Data8 = 0x1F;
7218 int16 DataC = 0;
7219 if (pData0 <= Data8)
7220 if (pData4 <= Data8)
7221 goto loc_2A2F5;
7222
7223 //seg007:0755
7224 ++DataC;
7225 Data8 <<= 1;
7226 ++Data8;
7227
7228 //loc_2A283
7229 for (;;) {
7230 if (pData0 <= Data8)
7231 if (pData4 <= Data8)
7232 break;
7233 ++DataC;
7234 Data8 <<= 1;
7235 ++Data8;
7236 if (pData0 <= Data8)
7237 if (pData4 <= Data8)
7238 break;
7239
7240 ++DataC;
7241 Data8 <<= 1;
7242 ++Data8;
7243 if (pData0 <= Data8)
7244 if (pData4 <= Data8)
7245 break;
7246
7247 ++DataC;
7248 Data8 <<= 1;
7249 ++Data8;
7250 }
7251 //loc_2A2E5
7252 pData0 >>= DataC;
7253 pData4 >>= DataC;
7254
7255 loc_2A2F5:;
7256 pData4 <<= 5;
7257 pData4 |= pData0;
7258 //pData4 <<= 1;
7259 pData4 = mMap_DirectionsBetweenPoints[pData4];
7260 if (pData4 < 0) {
7261 word_3B25B = -1;
7262 return -1;
7263 }
7264
7265 pData4 <<= 1;
7266 if (Data10 < 0) {
7267 //loc_2A376
7268 if (Data14 >= 0) {
7269 pData4 += 0x180;
7270 pData4 &= 0x1FE;
7271 pSprite->field_10 = pData4;
7272
7273 }
7274 else {
7275 //loc_2A39F
7276 pData0 = 0x180;
7277 pData0 -= pData4;
7278 pData0 &= 0x1FE;
7279 pSprite->field_10 = pData0;
7280 }
7281
7282 word_3B25B = 0;
7283 return 0;
7284 }
7285
7286 //seg007:0804
7287 if (Data14 >= 0) {
7288 pData0 = 0x80;
7289 pData0 -= pData4;
7290 pData0 &= 0x1FE;
7291 pSprite->field_10 = pData0;
7292 word_3B25B = 0;
7293 return 0;
7294 }
7295
7296 //loc_2A354
7297 pData4 += 0x80;
7298 pData4 &= 0x1FE;
7299 pSprite->field_10 = pData4;
7300 word_3B25B = 0;
7301 return 0;
7302 }
7303
sub_2A3D4(sSprite * pSprite)7304 void cFodder::sub_2A3D4(sSprite* pSprite) {
7305
7306 mDirectionMod = 0;
7307 pSprite->field_3E -= 1;
7308 if (pSprite->field_3E >= 0)
7309 return;
7310
7311 pSprite->field_3E = 1;
7312 int16 Data8 = pSprite->field_3C;
7313 int16 Data0 = pSprite->field_10;
7314
7315 Data0 >>= 5;
7316 Data0 -= 1;
7317 Data0 ^= 0x0F;
7318 Data0 &= 0x0E;
7319 int16 Data4 = Data0;
7320 Data4 &= 0x0F;
7321
7322 int16 DataC = Data8;
7323 DataC -= Data4;
7324 DataC &= 0x0F;
7325 //seg007:0920
7326 DataC = (int16)mSprite_Direction_Frame_Unk[DataC];
7327 DataC <<= 1;
7328
7329 mDirectionMod = DataC;
7330 }
7331
Squad_Walk_Steps_Decrease()7332 void cFodder::Squad_Walk_Steps_Decrease() {
7333
7334 for (int16 Data0 = 2; Data0 >= 0; --Data0) {
7335
7336 if (mSquad_Walk_Target_Steps[Data0])
7337 --mSquad_Walk_Target_Steps[Data0];
7338
7339 }
7340 }
7341
Map_PathCheck_CalculateTo(int16 & pX1,int16 & pY1,int16 & pX2,int16 & pY2)7342 int16 cFodder::Map_PathCheck_CalculateTo(int16& pX1, int16& pY1, int16& pX2, int16& pY2) {
7343 pX1 >>= 4;
7344 pY1 >>= 4;
7345 pX2 >>= 4;
7346 pY2 >>= 4;
7347
7348 int16 Data18 = 2;
7349
7350 int16 RowBytes = mMapLoaded->getWidth();
7351 RowBytes <<= 1;
7352
7353 mCheckPattern_Position.mX = pX1;
7354 mCheckPattern_Position.mY = pY1;
7355
7356 Map_PathCheck_Generate(pX1, pY1, pX2, pY2, Data18, RowBytes);
7357
7358 return Map_PathCheck_CanPass(pX1);
7359 }
7360
Map_PathCheck_Generate(int16 & pX1,int16 & pY1,int16 & pX2,int16 & pY2,int16 & pColumnWidth,int16 & pRowWidth)7361 void cFodder::Map_PathCheck_Generate(int16& pX1, int16& pY1, int16& pX2, int16& pY2, int16& pColumnWidth, int16& pRowWidth) {
7362 int16 X = pX2 - pX1;
7363
7364 int16 Y = pY2 - pY1;
7365
7366 int16 Data28 = pX2;
7367
7368 int16 X_Move, Y_Move;
7369
7370 // Target to the left?
7371 if (X < 0) {
7372 X_Move = -pColumnWidth;
7373 X = -X;
7374 pColumnWidth = -1;
7375 }
7376 else {
7377 X_Move = pColumnWidth;
7378 pColumnWidth = 1;
7379 }
7380
7381 //loc_2A56A
7382 // If target position is above us
7383 if (Y < 0) {
7384 Y_Move = -pRowWidth;
7385 Y = -Y;
7386 pRowWidth = -1;
7387 } else {
7388 Y_Move = pRowWidth;
7389 pRowWidth = 1;
7390 }
7391
7392 //loc_2A59D
7393 pX2 = 0;
7394 if (Y == 0)
7395 pX2 = 1;
7396 else
7397 pX2 = 0;
7398
7399 pX2 = -pX2;
7400
7401 mMap_PathToDest.clear();
7402
7403 loc_2A5BA:;
7404
7405 // Reached target?
7406 if (Data28 == pX1 && pY2 == pY1)
7407 return;
7408
7409 // Move up/down
7410 if (pX2 >= 0) {
7411 pY1 += pRowWidth;
7412 pX2 -= X;
7413 mMap_PathToDest.push_back(Y_Move);
7414 goto loc_2A5BA;
7415 }
7416
7417 // Move left/right
7418 //loc_2A601
7419 pX1 += pColumnWidth;
7420 pX2 += Y;
7421 mMap_PathToDest.push_back(X_Move);
7422 goto loc_2A5BA;
7423 }
7424
Map_PathCheck_CanPass(int16 & pTileHit)7425 int16 cFodder::Map_PathCheck_CanPass(int16& pTileHit) {
7426
7427 int32 Data4 = mCheckPattern_Position.mY;
7428
7429 uint8* MapTilePtr = mMap->data() + 0x60;
7430 uint16 TileID = 0;
7431
7432 Data4 *= mMapLoaded->getWidth();
7433 Data4 += mCheckPattern_Position.mX;
7434
7435 MapTilePtr += (Data4 << 1);
7436
7437 for (size_t x = 0; x < mMap_PathToDest.size(); ++x) {
7438 int16 Movement = mMap_PathToDest[x];
7439
7440 if (Movement == 0 || (x + 1) >= mMap_PathToDest.size())
7441 goto loc_2A728;
7442
7443 if(mMap_PathToDest[x+1] == 0)
7444 goto loc_2A728;
7445
7446 MapTilePtr += Movement;
7447 Movement = mMap_PathToDest[++x];
7448
7449 loc_2A728:;
7450 MapTilePtr += Movement;
7451
7452 //loc_2A6A1
7453 if (MapTilePtr > mMap->data() && MapTilePtr < mMap->data() + mMap->size()) {
7454 TileID = readLE<uint16>(MapTilePtr);
7455 } else
7456 TileID = 0;
7457
7458 pTileHit = mTile_Hit[TileID & 0x1FF];
7459
7460 // Tile has hit?
7461 if (pTileHit >= 0) {
7462 pTileHit &= 0x0F;
7463
7464 // Check if tile is passable
7465 if (mTiles_NotWalkable[pTileHit]) {
7466 pTileHit = -1;
7467 return -1;
7468 }
7469 }
7470 }
7471
7472 pTileHit = 0;
7473 return 0;
7474 }
7475
7476 /**
7477 * Calculate the distance between two points on the map
7478 *
7479 * @return Distance between points
7480 */
Map_Get_Distance_BetweenPoints(int16 & pPosX,int16 & pPosY,int16 & pPosX2,int16 & pDistanceMax,int16 & pPosY2)7481 int16 cFodder::Map_Get_Distance_BetweenPoints(int16& pPosX, int16& pPosY, int16& pPosX2, int16& pDistanceMax, int16& pPosY2) {
7482 const int8* Data24 = mMap_Distance_Calculations;
7483
7484 pPosX2 -= pPosX;
7485 if (pPosX2 < 0)
7486 pPosX2 = -pPosX2;
7487
7488 if (pPosX2 >= pDistanceMax)
7489 goto loc_2A7DB;
7490
7491 pPosY2 -= pPosY;
7492 if (pPosY2 < 0)
7493 pPosY2 = -pPosY2;
7494
7495 if (pPosY2 >= pDistanceMax)
7496 goto loc_2A7DB;
7497
7498 pDistanceMax = 0;
7499 for (;;) {
7500 if (pPosX2 <= 0x1F)
7501 if (pPosY2 <= 0x1F)
7502 break;
7503
7504 pPosX2 >>= 1;
7505 pPosY2 >>= 1;
7506 ++pDistanceMax;
7507 }
7508 //loc_2A7AD
7509 pPosY2 <<= 5;
7510 pPosY2 |= pPosX2;
7511 pPosX = 0;
7512
7513 pPosX = Data24[pPosY2];
7514 pPosX <<= pDistanceMax;
7515
7516 return pPosX;
7517
7518 loc_2A7DB:;
7519 pPosX = 0x3E8;
7520 return 0x3E8;
7521 }
7522
Map_Get_Distance_BetweenPositions(cPosition pPos1,cPosition pPos2,int32 pDistanceMax)7523 int32 cFodder::Map_Get_Distance_BetweenPositions(cPosition pPos1, cPosition pPos2, int32 pDistanceMax) {
7524
7525 pPos2.mX -= pPos1.mX;
7526 if (pPos2.mX < 0)
7527 pPos2.mX = -pPos2.mX;
7528
7529 if (pPos2.mX >= pDistanceMax)
7530 goto loc_2A7DB;
7531
7532 pPos2.mY -= pPos1.mY;
7533 if (pPos2.mY < 0)
7534 pPos2.mY = -pPos2.mY;
7535
7536 if (pPos2.mY >= pDistanceMax)
7537 goto loc_2A7DB;
7538
7539 pDistanceMax = 0;
7540 for (;;) {
7541 if (pPos2.mX <= 0x1F)
7542 if (pPos2.mY <= 0x1F)
7543 break;
7544
7545 pPos2.mX >>= 1;
7546 pPos2.mY >>= 1;
7547 ++pDistanceMax;
7548 }
7549 //loc_2A7AD
7550 pPos2.mY <<= 5;
7551 pPos2.mY |= pPos2.mX;
7552
7553 if (pPos2.mY >= sizeof(mMap_Distance_Calculations) / sizeof(mMap_Distance_Calculations[0]) - 1)
7554 goto loc_2A7DB;
7555
7556 pPos1.mX = mMap_Distance_Calculations[pPos2.mY];
7557 pPos1.mX <<= pDistanceMax;
7558
7559 return pPos1.mX;
7560
7561 loc_2A7DB:;
7562 return 0x3E8;
7563 }
7564
7565 /**
7566 *
7567 * @param pY
7568 * @param pX Returns Terrain Type
7569 *
7570 * @return False if can walk
7571 */
Map_Terrain_Get_Type_And_Walkable(int16 & pY,int16 & pX)7572 int16 cFodder::Map_Terrain_Get_Type_And_Walkable(int16& pY, int16& pX) {
7573 int16 Data10 = pY;
7574 int16 Data14 = pX;
7575
7576 return Map_Terrain_Get(pY, pX, Data10, Data14);
7577 }
7578
7579 /**
7580 *
7581 * @param pSprite
7582 * @param pY
7583 * @param pX Returns Terrain Type
7584 *
7585 * @return False if can walk
7586 */
Map_Terrain_Get_Type_And_Walkable(sSprite * pSprite,int16 & pY,int16 & pX)7587 int16 cFodder::Map_Terrain_Get_Type_And_Walkable(sSprite* pSprite, int16& pY, int16& pX) {
7588
7589 pY += pSprite->field_4;
7590 if (pY >= 0) {
7591
7592 int16 Data14 = pY;
7593 pX += pSprite->field_0;
7594 if (pX >= 0) {
7595 int16 Data10 = pX;
7596
7597 return Map_Terrain_Get(pY, pX, Data10, Data14);
7598 }
7599 }
7600
7601 pY = -1;
7602 pX = 0;
7603
7604 return 0;
7605 }
7606
Map_Terrain_Get(int16 & pY,int16 & pX,int16 & pData10,int16 & pData14)7607 int16 cFodder::Map_Terrain_Get(int16& pY, int16& pX, int16& pData10, int16& pData14) {
7608
7609 if ((pY >> 4) > mMapLoaded->getHeight() || (pX >> 4) > mMapLoaded->getWidth())
7610 return 0;
7611
7612 int32 MapPtr = (pY >> 4) * mMapLoaded->getWidth();
7613 MapPtr += (pX >> 4);
7614 MapPtr <<= 1;
7615
7616 if (mMap->data() + (0x60 + MapPtr) >= mMap->data() + mMap->size())
7617 return 0;
7618
7619 uint16 TileID = readLE<uint16>(mMap->data() + (0x60 + MapPtr)) & 0x1FF;
7620
7621 // There is two tables, the HIT and the BHIT
7622 // HIT contains the type of terrain used by a tile, a value < 0 indicates
7623 // the tile contains two terrain types.
7624 // This is determined by looking up the terrain type and row
7625 // then checking if a bit is set for the column.
7626 // The bit being set, means we use the upper 4 bits as the terrain type
7627 // Not being set, means we use the lower 4 bits
7628
7629 // eTerrainFeature
7630 int16 TerrainType = Tile_Terrain_Get(TileID, pData10, pData14);
7631
7632 pY = mTiles_NotWalkable[TerrainType];
7633 pX = TerrainType;
7634
7635 return mTiles_NotWalkable[TerrainType];
7636 }
7637
Map_Terrain_Get(int16 pX,int16 pY)7638 int16 cFodder::Map_Terrain_Get(int16 pX, int16 pY) {
7639
7640 if ((pY >> 4) > mMapLoaded->getHeight() || (pX >> 4) > mMapLoaded->getWidth())
7641 return -1;
7642
7643 int32 MapPtr = (pY >> 4) * mMapLoaded->getWidth();
7644 MapPtr += (pX >> 4);
7645 MapPtr <<= 1;
7646
7647 if (mMap->data() + (0x60 + MapPtr) >= mMap->data() + mMap->size())
7648 return -1;
7649
7650 uint16 TileID = readLE<uint16>(mMap->data() + (0x60 + MapPtr)) & 0x1FF;
7651
7652 // eTerrainFeature
7653 return Tile_Terrain_Get(TileID, pX, pY);
7654 }
7655
Tile_Terrain_Get(const int16 pTileID,int16 pX,int16 pY)7656 int16 cFodder::Tile_Terrain_Get(const int16 pTileID, int16 pX, int16 pY) {
7657 // There is two tables, the HIT and the BHIT
7658 // HIT contains the type of terrain used by a tile, a value < 0 indicates
7659 // the tile contains two terrain types.
7660 // This is determined by looking up the terrain type and row
7661 // then checking if a bit is set for the column.
7662 // The bit being set, means we use the upper 4 bits as the terrain type
7663 // Not being set, means we use the lower 4 bits
7664
7665 int16 TerrainType = mTile_Hit[pTileID];
7666
7667 if (TerrainType < 0) {
7668 pX >>= 1;
7669 pX &= 0x07;
7670
7671 int16 TilePixel = 7;
7672 TilePixel -= pX;
7673
7674 // Y
7675 pY >>= 1;
7676 pY &= 0x07;
7677
7678 int8 RowTerrainType = mTile_BHit[pTileID][pY];
7679
7680 // If the bit for this X position is set, we use the UpperBits for the terrain type
7681 if (RowTerrainType & (1 << TilePixel))
7682 TerrainType >>= 4;
7683 }
7684
7685 return (TerrainType & 0x0F);
7686 }
7687
Squad_Walk_Target_Set(int16 pTargetX,int16 pTargetY,int16 pSquadNumber,int16 pData10)7688 void cFodder::Squad_Walk_Target_Set(int16 pTargetX, int16 pTargetY, int16 pSquadNumber, int16 pData10) {
7689 int16 Data1C;
7690 sSprite** Saved_Data24 = 0;
7691
7692 if (pSquadNumber < 0 || pSquadNumber >= 3)
7693 return;
7694
7695 pData10 = mSquad_Walk_Target_Indexes[pSquadNumber];
7696
7697 sSprite** Data24 = mSquads[pSquadNumber];
7698
7699 // Currently walking to a target?
7700 if (mSquad_Walk_Target_Steps[pSquadNumber]) {
7701
7702 // Add this target to the queue
7703 mSquad_WalkTargets[pSquadNumber][pData10].mX = pTargetX;
7704 mSquad_WalkTargets[pSquadNumber][pData10].mY = pTargetY;
7705
7706 mSquad_WalkTargets[pSquadNumber][pData10 + 1].asInt = -1;
7707
7708 if (pData10 < (sizeof(mSquad_WalkTargets[pSquadNumber]) / sizeof(mSquad_WalkTargets[pSquadNumber][0]))) // 0x74
7709 pData10++;
7710
7711 mSquad_Walk_Target_Indexes[pSquadNumber] = pData10;
7712 goto loc_2ABF8;
7713 }
7714
7715 //loc_2AA4C
7716 pData10 = 0;
7717 Data1C = -1;
7718
7719 Saved_Data24 = Data24;
7720
7721 for (;;) {
7722 if (*Data24++ == INVALID_SPRITE_PTR)
7723 break;
7724
7725 ++Data1C;
7726 pData10 += 1;
7727 }
7728
7729 if (mSquad_WalkTargetX) {
7730 mSquad_WalkTargets[pSquadNumber][pData10].mX = mSquad_WalkTargetX;
7731 mSquad_WalkTargets[pSquadNumber][pData10].mY = mSquad_WalkTargetY;
7732 pData10 += 1;
7733 }
7734 //loc_2AAAE
7735 mSquad_WalkTargets[pSquadNumber][pData10].mX = pTargetX;
7736 mSquad_WalkTargets[pSquadNumber][pData10].mY = pTargetY;
7737
7738 mSquad_WalkTargetX = pTargetX;
7739 mSquad_WalkTargetY = pTargetY;
7740
7741 mSquad_WalkTargets[pSquadNumber][pData10 + 1].asInt = -1;
7742
7743 Data24 = Saved_Data24;
7744 if (Data1C < 0)
7745 return;
7746
7747 mSquad_Walk_Target_Indexes[pSquadNumber] = pData10;
7748 mSquad_Walk_Target_Indexes[pSquadNumber]++;
7749
7750 for (;;) {
7751 sSprite* Data28 = *Data24++;
7752
7753 if (Data28 == INVALID_SPRITE_PTR)
7754 break;
7755
7756 if (Data28->field_5B)
7757 continue;
7758
7759 if (Data28->field_6E)
7760 continue;
7761
7762 Data28->field_4C = 0;
7763 Data28->field_4D = 0;
7764 Data28->field_45 = 0;
7765 Data28->field_43 = 0;
7766 Data28->field_40 = pData10;
7767 Data28->field_40++;
7768 pData10--;
7769
7770 mSquad_WalkTargets[pSquadNumber][pData10].mX = Data28->field_0;
7771 mSquad_WalkTargets[pSquadNumber][pData10].mY = Data28->field_4;
7772
7773 Data28->field_26 = pTargetX;
7774 Data28->field_28 = pTargetY;
7775
7776 pTargetX = Data28->field_0;
7777 pTargetY = Data28->field_4;
7778 }
7779
7780 loc_2ABF8:;
7781 mSquad_Walk_Target_Steps[pSquadNumber] = 8;
7782 }
7783
Squad_Member_Sprite_Hit_In_Region(sSprite * pSprite,int16 pData8,int16 pDataC,int16 pData10,int16 pData14)7784 int16 cFodder::Squad_Member_Sprite_Hit_In_Region(sSprite* pSprite, int16 pData8, int16 pDataC, int16 pData10, int16 pData14) {
7785 int16 Data4;
7786
7787 if (mPhase_Finished) {
7788 word_3AA45 = 0;
7789 return 0;
7790 }
7791
7792 mSprites_Found_Count = 0;
7793
7794 int16 Data0;
7795
7796 for( auto& Troop : mGame_Data.mSoldiers_Allocated ) {
7797
7798 if (Troop.mSprite == INVALID_SPRITE_PTR || Troop.mSprite == 0)
7799 continue;
7800
7801 if (pData8 > (Troop.mSprite->field_0 + 9))
7802 continue;
7803
7804 if (pDataC < Troop.mSprite->field_0)
7805 continue;
7806
7807 if (pData10 > (Troop.mSprite->field_4 - 6))
7808 continue;
7809
7810 if (pData14 < (Troop.mSprite->field_4 - 13))
7811 continue;
7812
7813 if (Troop.mSprite->field_20 >= 0x0B)
7814 continue;
7815
7816 if (!word_3AA45)
7817 goto loc_2AD3D;
7818
7819 if (Troop.mSprite->field_6E)
7820 continue;
7821
7822 if (pSprite->field_3A <= 4)
7823 goto loc_2AD25;
7824
7825 if (Troop.mSprite->field_52 >= 5)
7826 goto loc_2AD2D;
7827
7828 if (Troop.mSprite->field_4F)
7829 goto loc_2AD2D;
7830
7831
7832 Data0 = Troop.mSprite->field_32;
7833 if (word_3BED5[Data0]) {
7834 loc_2AD25:;
7835 Data0 = 0;
7836 goto loc_2AD36;
7837 }
7838
7839 loc_2AD2D:;
7840 Data0 = tool_RandomGet() & 7;
7841
7842 loc_2AD36:;
7843 if (!Data0)
7844 goto loc_2ADC3;
7845 continue;
7846
7847 loc_2AD3D:;
7848 Data0 = pDataC;
7849 Data0 -= pData8;
7850 Data0 >>= 1;
7851 Data0 += pData8;
7852
7853 Data4 = pData14;
7854 Data4 -= pData10;
7855 Data4 >>= 1;
7856 Data4 += pData10;
7857
7858 Sprite_Direction_Between_Points(Troop.mSprite, Data0, Data4);
7859
7860 Troop.mSprite->field_10 += 0x100;
7861 Troop.mSprite->field_10 &= 0x1FE;
7862
7863 loc_2ADC3:; // Hit
7864 if (Troop.mSprite->field_18)
7865 goto loc_2ADFF;
7866
7867 Troop.mSprite->field_10 = pSprite->field_10;
7868 Troop.mSprite->field_12 = pSprite->field_10;
7869
7870 loc_2ADFF:;
7871 Troop.mSprite->field_38 = eSprite_Anim_Hit;
7872 Troop.mSprite->field_64 = -1;
7873 mSprites_Found_Count += 1;
7874
7875 if (word_3AA45)
7876 break;
7877 }
7878
7879 word_3AA45 = 0;
7880 return mSprites_Found_Count;
7881 }
7882
Sprite_Get_Sheet(int16 pSpriteType,int16 pFrame)7883 const sSpriteSheet* cFodder::Sprite_Get_Sheet(int16 pSpriteType, int16 pFrame) {
7884 const sSpriteSheet* Sheet = &mSprite_SheetPtr[pSpriteType][pFrame];
7885
7886 return Sheet;
7887 }
7888
sub_2AEB6(int16 pColumns,int16 pRows,int16 * pData8,int16 * pDataC)7889 void cFodder::sub_2AEB6(int16 pColumns, int16 pRows, int16* pData8, int16* pDataC) {
7890 int32 Columns = pColumns * *pData8;
7891 int32 Rows = pRows * *pData8;
7892
7893 // Return
7894 *pDataC = (int16)(Rows / 0x64);
7895 *pData8 = (int16)(Columns / 0x64);
7896 }
7897
7898
Sprite_SetDirectionMod(sSprite * pSprite)7899 void cFodder::Sprite_SetDirectionMod(sSprite* pSprite) {
7900 mDirectionMod = 0;
7901 int16 Data0 = pSprite->field_10;
7902
7903 Data0 -= pSprite->field_3C;
7904 word_3B25D = Data0;
7905 if (Data0 < 0)
7906 word_3B25D = -word_3B25D;
7907
7908 Data0 >>= 5;
7909 Data0 -= 1;
7910 Data0 ^= 0x0F;
7911 int16 Data4 = Data0;
7912 Data4 &= 0x0F;
7913
7914 mDirectionMod = (int16)mSprite_Direction_Frame_Unk[Data4];
7915 }
7916
Sprite_Vehicle_Direction_Update(sSprite * pSprite,int16 & pData1C)7917 void cFodder::Sprite_Vehicle_Direction_Update(sSprite* pSprite, int16& pData1C) {
7918 int16 Data4 = mSprite_Field10_Saved;
7919 Data4 >>= 5;
7920 Data4 -= 1;
7921 Data4 ^= 0x0F;
7922
7923 int16 Data0 = pSprite->field_A;
7924
7925 Data0 -= Data4;
7926 Data4 = Data0;
7927 Data4 &= 0x0F;
7928 int16 DataC = mSprite_Direction_Frame_Unk[Data4];
7929 if (!DataC)
7930 return;
7931
7932 if (DataC == pData1C)
7933 goto loc_2B21D;
7934
7935 if (!pData1C)
7936 goto loc_2B21D;
7937
7938 DataC = pData1C;
7939
7940 loc_2B21D:;
7941 pSprite->field_A += DataC;
7942 pSprite->field_A &= 0x0F;
7943
7944 }
7945
Map_Terrain_Get_Moveable_Wrapper(const int8 * pMovementData,int16 & pX,int16 & pY,int16 & pData10,int16 & pData14)7946 int16 cFodder::Map_Terrain_Get_Moveable_Wrapper(const int8* pMovementData, int16& pX, int16& pY, int16& pData10, int16& pData14) {
7947
7948 pData10 = pX;
7949 pData14 = pY;
7950
7951 return Map_Terrain_Get_Moveable(pMovementData, pX, pY);
7952 }
7953
Map_Terrain_Get_Moveable(const int8 * pMovementData,int16 & pX,int16 & pY)7954 int16 cFodder::Map_Terrain_Get_Moveable(const int8* pMovementData, int16& pX, int16& pY) {
7955 uint32 DataC = pY;
7956 uint32 Data8 = pX;
7957
7958 if (pY < 0)
7959 DataC = 0;
7960 if (pX < 0)
7961 Data8 = 0;
7962
7963 DataC >>= 4;
7964
7965 DataC *= mMapLoaded->getWidth();
7966 Data8 >>= 4;
7967
7968 DataC += Data8;
7969 DataC <<= 1;
7970
7971 if (mMap->data() + 0x60 + DataC >= mMap->data() + mMap->size())
7972 return pMovementData[0];
7973
7974 int16 Data0 = readLE<uint16>(mMap->data() + 0x60 + DataC);
7975 Data0 &= 0x1FF;
7976
7977 int16 Data4 = mTile_Hit[Data0];
7978
7979 if (Data4 >= 0) {
7980 Data4 &= 0x0F;
7981 return pMovementData[Data4];
7982 }
7983
7984 Data8 = Data4;
7985 Data4 &= 0x0F;
7986
7987 Data0 = pMovementData[Data4];
7988 Data8 >>= 4;
7989 Data8 &= 0x0F;
7990
7991 Data0 |= pMovementData[Data8];
7992
7993 pX = Data8;
7994 pY = DataC;
7995 return Data0;
7996 }
7997
Map_Get_Distance_BetweenPoints_Within_640(int16 & pX,int16 & pY,int16 & pX2,int16 & pY2)7998 void cFodder::Map_Get_Distance_BetweenPoints_Within_640(int16& pX, int16& pY, int16& pX2, int16& pY2) {
7999 int16 Data10 = 0;
8000
8001 pX2 -= pX;
8002 if (pX2 < 0)
8003 pX2 = -pX2;
8004
8005 if (pX2 >= getWindowWidth() * 2)
8006 goto loc_2B403;
8007
8008 pY2 -= pY;
8009 if (pY2 < 0)
8010 pY2 = -pY2;
8011
8012 if (pY2 >= getWindowWidth() * 2)
8013 goto loc_2B403;
8014
8015 for (;;) {
8016 if (pX2 <= 31)
8017 if (pY2 <= 31)
8018 break;
8019
8020 pX2 >>= 1;
8021 pY2 >>= 1;
8022 Data10 += 1;
8023 }
8024
8025 pY2 <<= 5;
8026 pY2 |= pX2;
8027 pX = 0;
8028 pX = mMap_Distance_Calculations[pY2];
8029
8030 pX <<= Data10;
8031 return;
8032
8033 loc_2B403:;
8034 pX = getWindowWidth() * 2;
8035 }
8036
MapTile_Update_Position()8037 bool cFodder::MapTile_Update_Position() {
8038
8039 MapTile_Update_Y();
8040 MapTile_Update_X();
8041
8042 int16 TileColumns = mMapTile_DrawX - mMapTile_Column_CurrentScreen;
8043 int16 TileRows = mMapTile_DrawY - mMapTile_Row_CurrentScreen;
8044
8045 mMapTile_Column_CurrentScreen = mMapTile_DrawX;
8046 mMapTile_Row_CurrentScreen = mMapTile_DrawY;
8047
8048 if (TileColumns) {
8049 if (TileColumns < 0)
8050 MapTile_Move_Left(-TileColumns);
8051 else
8052 MapTile_Move_Right(TileColumns);
8053 }
8054
8055 if (TileRows) {
8056 if (TileRows < 0)
8057 MapTile_Move_Up(-TileRows);
8058 else
8059 MapTile_Move_Down(TileRows);
8060 }
8061
8062 if (TileColumns || TileRows) {
8063 if (!mStartParams->mDisableVideo)
8064 mGraphics->MapTiles_Draw();
8065 return true;
8066 }
8067
8068 return false;
8069 }
8070
MapTile_Move_Right(int16 pPanTiles)8071 void cFodder::MapTile_Move_Right(int16 pPanTiles) {
8072
8073 for (; pPanTiles > 0; --pPanTiles) {
8074
8075 ++mMapTile_ColumnOffset;
8076 mMapTile_ColumnOffset &= 0x0F;
8077 if (!mMapTile_ColumnOffset) {
8078 mMapTile_Ptr += 2;
8079 ++mMapTile_MovedHorizontal;
8080 }
8081 }
8082 }
8083
MapTile_Move_Left(int16 pPanTiles)8084 void cFodder::MapTile_Move_Left(int16 pPanTiles) {
8085
8086 for (; pPanTiles > 0; --pPanTiles) {
8087
8088 --mMapTile_ColumnOffset;
8089 mMapTile_ColumnOffset &= 0x0F;
8090 if (mMapTile_ColumnOffset == 0x0F) {
8091 mMapTile_Ptr -= 2;
8092 --mMapTile_MovedHorizontal;
8093 }
8094 }
8095 }
8096
MapTile_Move_Down(int16 pPanTiles)8097 void cFodder::MapTile_Move_Down(int16 pPanTiles) {
8098
8099 for (; pPanTiles > 0; --pPanTiles) {
8100
8101 ++mMapTile_RowOffset;
8102 mMapTile_RowOffset &= 0x0F;
8103 if (!mMapTile_RowOffset) {
8104 mMapTile_Ptr += (mMapLoaded->getWidth() << 1);
8105 ++mMapTile_MovedVertical;
8106 }
8107 }
8108 }
8109
MapTile_Move_Up(int16 pPanTiles)8110 void cFodder::MapTile_Move_Up(int16 pPanTiles) {
8111
8112 for (; pPanTiles > 0; --pPanTiles) {
8113
8114 --mMapTile_RowOffset;
8115 mMapTile_RowOffset &= 0x0F;
8116 if (mMapTile_RowOffset == 0x0F) {
8117 mMapTile_Ptr -= (mMapLoaded->getWidth() << 1);
8118 --mMapTile_MovedVertical;
8119 }
8120 }
8121 }
8122
MapTile_Update_Y()8123 void cFodder::MapTile_Update_Y() {
8124 int16 Data0 = mMapTile_MoveDirectionY;
8125
8126 if (Data0 < 0)
8127 Data0 = -1;
8128 else
8129 Data0 = 1;
8130 // Direction Change?
8131 if (Data0 != mMapTile_MoveDirectionY_Previous) {
8132 mMapTile_MoveDirectionY_Previous = Data0;
8133 Data0 = mMapTile_SpeedY >> 16;
8134 int16 Data4 = mMapTile_SpeedY_Previous;
8135
8136 Data0 >>= 4;
8137 Data4 >>= 4;
8138 if (Data4 != Data0)
8139 return;
8140 }
8141
8142 mCamera_MovePauseY = 0;
8143 mMapTile_DrawY = mMapTile_TargetY >> 16;
8144 mMapTile_SpeedY_Previous = mMapTile_SpeedY >> 16;
8145 }
8146
MapTile_Update_X()8147 void cFodder::MapTile_Update_X() {
8148 int16 Data0 = mMapTile_MoveDirectionX;
8149
8150 if (Data0 < 0)
8151 Data0 = -1;
8152 else
8153 Data0 = 1;
8154
8155 if (Data0 != mMapTile_MoveDirectionX_Previous) {
8156 mMapTile_MoveDirectionX_Previous = Data0;
8157 Data0 = mMapTile_SpeedX >> 16;
8158 int16 Data4 = mMapTile_SpeedX_Previous;
8159 Data0 >>= 4;
8160 Data4 >>= 4;
8161 if (Data0 != Data4)
8162 return;
8163 }
8164
8165 mCamera_MovePauseX = 0;
8166 mMapTile_DrawX = mMapTile_TargetX >> 16;
8167 mMapTile_SpeedX_Previous = mMapTile_SpeedX >> 16;
8168 }
8169
MapTile_Get(const size_t pTileX,const size_t pTileY)8170 int32 cFodder::MapTile_Get(const size_t pTileX, const size_t pTileY) {
8171
8172 if ((int32) pTileX > mMapLoaded->getWidth() || (int32) pTileY > mMapLoaded->getHeight())
8173 return -1;
8174
8175 size_t Tile = (((pTileY * mMapLoaded->getWidth()) + pTileX)) + mMapLoaded->getWidth();
8176
8177 uint8* CurrentMapPtr = mMap->data() + mMapTile_Ptr + (Tile * 2);
8178 if (CurrentMapPtr > mMap->data() + mMap->size())
8179 return -1;
8180
8181 return readLE<int16>(CurrentMapPtr);
8182 }
8183
8184 /**
8185 * Sets a map tile to a certain ID, positioned based on the current camera
8186 */
MapTile_Set(const size_t pTileX,const size_t pTileY,const size_t pTileID)8187 void cFodder::MapTile_Set(const size_t pTileX, const size_t pTileY, const size_t pTileID) {
8188
8189 if ((int32) pTileX > mMapLoaded->getWidth() || (int32) pTileY > mMapLoaded->getHeight())
8190 return;
8191
8192 size_t Tile = (((pTileY * mMapLoaded->getWidth()) + pTileX)) + mMapLoaded->getWidth();
8193
8194 uint8* CurrentMapPtr = mMap->data() + mMapTile_Ptr + (Tile * 2);
8195 if (CurrentMapPtr > mMap->data() + mMap->size())
8196 return;
8197
8198 writeLEWord(CurrentMapPtr, (uint16)pTileID);
8199 }
8200
Sprite_Add(size_t pSpriteID,int16 pSpriteX,int16 pSpriteY)8201 sSprite* cFodder::Sprite_Add(size_t pSpriteID, int16 pSpriteX, int16 pSpriteY) {
8202
8203 int16 Data0 = 3;
8204
8205 sSprite* First = 0, *Second = 0, *Third = 0, *Fourth = 0;
8206
8207 if (Sprite_Get_Free_Max42(Data0, First, Second))
8208 return First;
8209
8210 Third = Second + 1;
8211 Fourth = Third + 1;
8212
8213 First->field_18 = (int16)pSpriteID;
8214 First->field_0 = pSpriteX;
8215 First->field_4 = pSpriteY;
8216 First->field_26 = pSpriteX;
8217 First->field_28 = pSpriteY;
8218
8219 switch (pSpriteID) {
8220 case eSprite_BoilingPot: // 1 Null
8221 case eSprite_Tank_Human:
8222 case eSprite_VehicleNoGun_Human:
8223 case eSprite_VehicleGun_Human:
8224 case eSprite_VehicleNoGun_Enemy:
8225 case eSprite_VehicleGun_Enemy:
8226 case eSprite_Vehicle_Unk_Enemy:
8227 case eSprite_Enemy_Leader:
8228 Second->field_18 = eSprite_Null;
8229 Second->field_0 = pSpriteX;
8230 Second->field_4 = pSpriteY;
8231 Second->field_26 = pSpriteX;
8232 Second->field_28 = pSpriteY;
8233 break;
8234
8235 case eSprite_Helicopter_Grenade_Enemy: // 3 Nulls
8236 case eSprite_Helicopter_Grenade2_Enemy:
8237 case eSprite_Helicopter_Missile_Enemy:
8238 case eSprite_Helicopter_Homing_Enemy:
8239 case eSprite_Helicopter_Homing_Enemy2:
8240 Second->field_18 = eSprite_Null;
8241 Second->field_0 = pSpriteX;
8242 Second->field_4 = pSpriteY;
8243 Second->field_26 = pSpriteX;
8244 Second->field_28 = pSpriteY;
8245 Third->field_18 = eSprite_Null;
8246 Third->field_0 = pSpriteX;
8247 Third->field_4 = pSpriteY;
8248 Third->field_26 = pSpriteX;
8249 Third->field_28 = pSpriteY;
8250 Fourth->field_18 = eSprite_Null;
8251 Fourth->field_0 = pSpriteX;
8252 Fourth->field_4 = pSpriteY;
8253 Fourth->field_26 = pSpriteX;
8254 Fourth->field_28 = pSpriteY;
8255 break;
8256
8257 // Fall Through
8258 case eSprite_Helicopter_Grenade2_Human: // 2 Nulls
8259 case eSprite_Helicopter_Grenade_Human:
8260 case eSprite_Helicopter_Missile_Human:
8261 case eSprite_Helicopter_Homing_Human:
8262 case eSprite_Helicopter_Grenade2_Human_Called:
8263 case eSprite_Helicopter_Grenade_Human_Called:
8264 case eSprite_Helicopter_Missile_Human_Called:
8265 case eSprite_Helicopter_Homing_Human_Called:
8266 case eSprite_Tank_Enemy:
8267 Second->field_18 = eSprite_Null;
8268 Second->field_0 = pSpriteX;
8269 Second->field_4 = pSpriteY;
8270 Second->field_26 = pSpriteX;
8271 Second->field_28 = pSpriteY;
8272 Third->field_18 = eSprite_Null;
8273 Third->field_0 = pSpriteX;
8274 Third->field_4 = pSpriteY;
8275 Third->field_26 = pSpriteX;
8276 Third->field_28 = pSpriteY;
8277
8278 break;
8279 }
8280
8281 (*this.*mSprite_Function[First->field_18])(First);
8282
8283 if(Second && Second->field_0 != -32768)
8284 (*this.*mSprite_Function[Second->field_18])(Second);
8285
8286 if(Third && Third->field_0 != -32768)
8287 (*this.*mSprite_Function[Third->field_18])(Third);
8288
8289 if (Fourth && Fourth->field_0 != -32768)
8290 (*this.*mSprite_Function[Fourth->field_18])(Fourth);
8291
8292 return First;
8293 }
8294
Squad_Troops_Count()8295 void cFodder::Squad_Troops_Count() {
8296 sSprite** Data34 = mSprite_TroopsAlive;
8297
8298 mSquads_TroopCount[0] = 0;
8299 mSquads_TroopCount[1] = 0;
8300 mSquads_TroopCount[2] = 0;
8301 mSquads_TroopCount[3] = 0;
8302
8303 int16 TotalTroops = 0;
8304
8305 mSquad_0_Sprites[0] = INVALID_SPRITE_PTR;
8306 mSquad_1_Sprites[0] = INVALID_SPRITE_PTR;
8307 mSquad_2_Sprites[0] = INVALID_SPRITE_PTR;
8308 mSquad_3_Sprites[0] = INVALID_SPRITE_PTR;
8309 mSquad_4_Sprites[0] = INVALID_SPRITE_PTR;
8310
8311 // Loop through all mission troops
8312 for( auto& Troop : mGame_Data.mSoldiers_Allocated ) {
8313
8314 if (Troop.mSprite == INVALID_SPRITE_PTR || Troop.mSprite == 0)
8315 continue;
8316
8317 sSprite* Sprite = Troop.mSprite;
8318
8319 // Sprite is not invincible
8320 if (!(Sprite->field_75 & eSprite_Flag_Invincibility)) {
8321
8322 // Is dying
8323 if (Sprite->field_38 < eSprite_Anim_Slide1) {
8324 if (Sprite->field_38) {
8325
8326 // Not in vehicle
8327 if (!Sprite->field_6E)
8328 continue;
8329
8330 Sprite->field_38 = eSprite_Anim_None;
8331 }
8332 }
8333 }
8334 //loc_2D165
8335 if (Sprite->field_32 < 0)
8336 continue;
8337
8338 uint8 Data10 = mSquads_TroopCount[Sprite->field_32] & 0xFF;
8339 mSquads_TroopCount[Sprite->field_32] += 1;
8340 ++TotalTroops;
8341
8342 sSprite** Data30 = mSquads[Sprite->field_32];
8343 //seg009:0151
8344 Data30[Data10] = Sprite;
8345 Data30[Data10 + 1] = INVALID_SPRITE_PTR;
8346
8347 *Data34 = Sprite;
8348 ++Data34;
8349 }
8350 //seg009:019E
8351
8352 if (!TotalTroops)
8353 mPhase_TryAgain = true;
8354
8355 for (int16 Data0 = 2; Data0 >= 0; --Data0) {
8356 if (mSquads_TroopCount[Data0])
8357 continue;
8358
8359 mSquad_Join_TargetSquad[Data0] = -1;
8360 }
8361
8362 *Data34 = INVALID_SPRITE_PTR;
8363 }
8364
Mission_Troop_GetDeviatePotential(sMission_Troop * pData24)8365 int16 cFodder::Mission_Troop_GetDeviatePotential(sMission_Troop* pData24) {
8366 int16 Data0 = 0;
8367
8368 if (pData24)
8369 Data0 = pData24->mRank;
8370
8371 Data0 += 8;
8372
8373 if (Data0 > 0x0F)
8374 Data0 = 0x0F;
8375
8376 return mSprite_Bullet_UnitData[Data0].mDeviatePotential;
8377 }
8378
Squad_Member_Rotate_Can_Fire()8379 void cFodder::Squad_Member_Rotate_Can_Fire() {
8380 if (mSquad_Member_Fire_CoolDown_Override)
8381 mSquad_Member_Fire_CoolDown_Override = false;
8382 else {
8383 mSquad_Member_Fire_CoolDown -= 2;
8384 if (mSquad_Member_Fire_CoolDown >= 0)
8385 return;
8386 }
8387
8388 //loc_2D2EB
8389 sSprite* Data20 = mSquad_Leader;
8390 if (Data20 == INVALID_SPRITE_PTR || Data20 == 0)
8391 return;
8392
8393 sMission_Troop* Dataa20 = Data20->field_46_mission_troop;
8394 if (Dataa20 == 0)
8395 return;
8396
8397 mSquad_Member_Fire_CoolDown = mSprite_Weapon_Data.mCooldown;
8398 mSprite_Bullet_Time_Modifier = 0;
8399 mSprite_Bullet_Fire_Speed_Modifier = 0;
8400
8401 // TODO: 0x0F is the max rank, so what was this code for?
8402 {
8403 if (Dataa20->mRank > 0x14) {
8404 if (mSquad_Selected >= 0) {
8405 if (mSquads_TroopCount[mSquad_Selected] == 1) {
8406 mSquad_Member_Fire_CoolDown = 1;
8407 mSprite_Bullet_Time_Modifier = -3;
8408 mSprite_Bullet_Fire_Speed_Modifier = 0x0A;
8409 }
8410 }
8411 }
8412 }
8413
8414 //loc_2D381
8415 if (mSquad_Selected < 0)
8416 return;
8417
8418 int16 TroopsInSquad = (mSquads_TroopCount[mSquad_Selected] & 0xFF) - 1;
8419 int16 LastTroopNumber = TroopsInSquad;
8420
8421 if (LastTroopNumber < 0)
8422 return;
8423
8424 // Order based on number of troops in squad
8425 const std::vector<int16>& Rotate_Fire_Order = mSoldier_Squad_Fire_RotationOrder[TroopsInSquad];
8426 if (mTroop_Rotate_Next >= Rotate_Fire_Order.size())
8427 mTroop_Rotate_Next = 0;
8428
8429 size_t Data0 = mTroop_Rotate_Next;
8430
8431 // Squad Member Number
8432 int16 Data4 = Rotate_Fire_Order[Data0];
8433
8434 // Past the last troop in squad?
8435 if (Data4 < 0 || Data4 > LastTroopNumber) {
8436 Data4 = 0;
8437 Data0 = 0;
8438 }
8439
8440 // Next Troop in Squad
8441 Data0++;
8442 if (Rotate_Fire_Order[Data0] < 0)
8443 Data0 = 0;
8444
8445 mTroop_Rotate_Next = Data0;
8446
8447 // Can the squad member use their weapon
8448 Data20 = mSquads[mSquad_Selected][Data4];
8449 if (Data20->field_45)
8450 return;
8451
8452 // Soldier fires weapon
8453 Data20->field_4A = -1;
8454 }
8455
Sprite_Find_In_Region(sSprite * pSprite,sSprite * & pData24,int16 pData8,int16 pDataC,int16 pData10,int16 pData14)8456 int16 cFodder::Sprite_Find_In_Region(sSprite* pSprite, sSprite*& pData24, int16 pData8, int16 pDataC, int16 pData10, int16 pData14) {
8457
8458 if (mPhase_Finished) {
8459 word_3AA45 = 0;
8460 return 0;
8461 }
8462
8463 mSprites_Found_Count = 0;
8464
8465 pData24 = mSprites.data();
8466
8467 for (int32 Data1C = mParams->mSpritesMax - 2; Data1C >= 0; --Data1C, ++pData24) {
8468 int16 Data4 = pData24->field_18;
8469
8470 if (!mSprite_Can_Be_RunOver[Data4])
8471 continue;
8472
8473 if (pData24->field_0 < 0)
8474 continue;
8475
8476 if (pDataC < pData24->field_0)
8477 continue;
8478
8479 int16 Data0 = pData24->field_0;
8480 Data0 += mSprite_Width[Data4];
8481 if (pData8 > Data0)
8482 continue;
8483
8484 Data0 = pData24->field_4;
8485 Data0 -= mSprite_Height_Top[Data4];
8486 if (pData14 < Data0)
8487 continue;
8488
8489 //seg009:050C
8490 Data0 = pData24->field_4;
8491 Data0 += mSprite_Height_Bottom[Data4];
8492
8493 if (pData10 > Data0)
8494 continue;
8495
8496 int16 Data18 = pSprite->field_20;
8497 Data0 = mSprite_Height_Top[Data4];
8498 Data0 += 8;
8499
8500 Data0 += pData24->field_20;
8501
8502 if (Data18 > Data0)
8503 continue;
8504 Data18 += 0x0B;
8505
8506 if (Data18 < pData24->field_20)
8507 continue;
8508
8509 if (pData24->field_18 != eSprite_Player)
8510 goto loc_2D5FA;
8511
8512 if (pData24->field_38 != eSprite_Anim_Die5)
8513 continue;
8514
8515 loc_2D5FA:;
8516 if (pSprite->field_18 == eSprite_Explosion2)
8517 goto AnimDie3;
8518
8519 if (pSprite->field_18 == eSprite_Building_Explosion)
8520 goto loc_2D62C;
8521
8522 if (pSprite->field_18 != eSprite_Explosion)
8523 goto loc_2D642;
8524
8525 goto loc_2D62C;
8526
8527 AnimDie3:;
8528 pData24->field_38 = eSprite_Anim_Die3;
8529 goto loc_2D636;
8530
8531 loc_2D62C:;
8532 pData24->field_38 = eSprite_Anim_Die1;
8533
8534 loc_2D636:;
8535 pData24->field_64 = -1;
8536 goto loc_2D6ED;
8537
8538 loc_2D642:;
8539 if (mSprite_Can_Be_RunOver[Data4] == 2)
8540 goto loc_2D659;
8541
8542 mSprites_Found_Count = 1;
8543 goto loc_2D705;
8544 loc_2D659:;
8545
8546 pData24->field_38 = eSprite_Anim_Hit;
8547 pData24->field_64 = -1;
8548 Data0 = pSprite->field_10;
8549 Data4 = Data0;
8550 Data0 += 0x368;
8551 Data4 += 0x468;
8552
8553 pData8 = pData24->field_10;
8554 pDataC = pData8;
8555 pData8 += 0x368;
8556 pDataC += 0x468;
8557
8558 pData24->field_59 = 0;
8559 if (pData8 < Data0)
8560 goto loc_2D6D2;
8561
8562 if (pDataC > Data0)
8563 goto loc_2D6D2;
8564
8565 pData24->field_59 = -1;
8566
8567 loc_2D6D2:;
8568 if (pData8 < Data4)
8569 goto loc_2D6ED;
8570
8571 if (pDataC > Data4)
8572 goto loc_2D6ED;
8573
8574 pData24->field_59 = -1;
8575
8576 loc_2D6ED:;
8577 mSprites_Found_Count = -1;
8578 pData24->field_10 = pSprite->field_10;
8579
8580 loc_2D705:;
8581 if (word_3AA45)
8582 break;
8583 }
8584
8585 word_3AA45 = 0;
8586 return mSprites_Found_Count;
8587 }
8588
Sprite_Handle_Player_DestroyAll()8589 void cFodder::Sprite_Handle_Player_DestroyAll() {
8590
8591 for(auto& Sprite : mSprites) {
8592
8593 if (Sprite.field_0 == -32768)
8594 continue;
8595
8596 if (Sprite.field_18 == eSprite_Player)
8597 Sprite_Troop_Dies(&Sprite);
8598 }
8599 }
8600
Sprite_Handle_Player_Destroy_Unk()8601 void cFodder::Sprite_Handle_Player_Destroy_Unk() {
8602
8603 for (auto& Sprite : mSprites) {
8604
8605 if (Sprite.field_0 == -32768)
8606 continue;
8607
8608 if (Sprite.field_18 != eSprite_Player)
8609 continue;
8610
8611 if (!Sprite.field_38)
8612 continue;
8613
8614 if (Sprite.field_38 >= eSprite_Anim_Slide1)
8615 continue;
8616
8617 Sprite_Troop_Dies(&Sprite);
8618 }
8619 }
8620
Squad_Prepare_GrenadesAndRockets()8621 void cFodder::Squad_Prepare_GrenadesAndRockets() {
8622 mSquad_Grenades[0] = mGame_Data.mGamePhase_Data.mSoldiers_Available << 1;
8623 mSquad_Rockets[0] = mGame_Data.mGamePhase_Data.mSoldiers_Available;
8624
8625 if (mVersionCurrent->isCannonFodder1()) {
8626 if (mVersionCurrent->isAmigaTheOne()) {
8627 mSquad_Grenades[0] += mGame_Data.mGamePhase_Data.mSoldiers_Available;
8628
8629 if (mGame_Data.mMission_Number == 1 && mGame_Data.mMission_Phase < 3)
8630 mSquad_Grenades[0] = 0;
8631
8632 mSquad_Rockets[0] = 0;
8633 }
8634 else {
8635
8636 if (mGame_Data.mMission_Number < 4 || (mGame_Data.mMission_Number == 4 && mGame_Data.mMission_Phase < 2)) // Original CF: Map 5
8637 mSquad_Grenades[0] = 0;
8638
8639 if (mGame_Data.mMission_Number < 5 || (mGame_Data.mMission_Number == 5 && mGame_Data.mMission_Phase < 2)) // Original CF: Map 10
8640 mSquad_Rockets[0] = 0;
8641 }
8642 }
8643 else {
8644 if (mGame_Data.mMission_Number < 3) // Original CF2: Map 5
8645 mSquad_Grenades[0] = 0;
8646
8647 if (mGame_Data.mMission_Number < 4 || (mGame_Data.mMission_Number == 4 && mGame_Data.mMission_Phase < 2)) // Original CF2: Map 10
8648 mSquad_Rockets[0] = 0;
8649 }
8650
8651 // If grenades/rockets are provided in the campaign data, override with those
8652 if (mGame_Data.mPhase_Current->mGrenades != -1)
8653 mSquad_Grenades[0] = mGame_Data.mPhase_Current->mGrenades;
8654
8655 if (mGame_Data.mPhase_Current->mRockets != -1)
8656 mSquad_Rockets[0] = mGame_Data.mPhase_Current->mRockets;
8657 }
8658
Sprite_Aggression_Set()8659 void cFodder::Sprite_Aggression_Set() {
8660 mGame_Data.mGamePhase_Data.mSprite_Enemy_AggressionMin = mGame_Data.mPhase_Current->mAggression.mMin;
8661 mGame_Data.mGamePhase_Data.mSprite_Enemy_AggressionMax = mGame_Data.mPhase_Current->mAggression.mMax;
8662 mGame_Data.mGamePhase_Data.mSprite_Enemy_AggressionAverage = mGame_Data.mPhase_Current->mAggression.getAverage();
8663
8664 mGame_Data.mGamePhase_Data.mSprite_Enemy_AggressionNext = mGame_Data.mPhase_Current->mAggression.getAverage();
8665 mGame_Data.mGamePhase_Data.mSprite_Enemy_AggressionIncrement = 1;
8666
8667 for(auto& Sprite : mSprites ) {
8668
8669 if (Sprite.field_0 == -32768)
8670 continue;
8671
8672 if (Sprite.field_18 == eSprite_Enemy_Rocket || Sprite.field_18 == eSprite_Enemy)
8673 Sprite_Handle_Enemy_Aggression_Set(&Sprite);
8674 }
8675 }
8676
8677 /**
8678 * Set the aggression of a sprite, then calculate the next aggression rate
8679 *
8680 * This moves by 'Increment' in an up or down
8681 * direction inside the min/max range for this map
8682 */
Sprite_Handle_Enemy_Aggression_Set(sSprite * pSprite)8683 void cFodder::Sprite_Handle_Enemy_Aggression_Set(sSprite* pSprite) {
8684
8685 int16 Next = mGame_Data.mGamePhase_Data.mSprite_Enemy_AggressionNext;
8686 pSprite->field_62 = Next;
8687
8688 int16 Increment = mGame_Data.mGamePhase_Data.mSprite_Enemy_AggressionIncrement;
8689 Next += Increment;
8690
8691 if (Increment >= 0) {
8692
8693 if (Next >= mGame_Data.mGamePhase_Data.mSprite_Enemy_AggressionMax) {
8694 Next = mGame_Data.mGamePhase_Data.mSprite_Enemy_AggressionMax;
8695 Increment = -Increment;
8696 }
8697 }
8698 else {
8699 if (Next < 0 || Next <= mGame_Data.mGamePhase_Data.mSprite_Enemy_AggressionMin) {
8700 Next = mGame_Data.mGamePhase_Data.mSprite_Enemy_AggressionMin;
8701 Increment = -Increment;
8702 }
8703 }
8704 //loc_2D90D
8705 mGame_Data.mGamePhase_Data.mSprite_Enemy_AggressionIncrement = Increment;
8706 mGame_Data.mGamePhase_Data.mSprite_Enemy_AggressionNext = Next;
8707 }
8708
Sprite_Next_WalkTarget_Set(sSprite * pSprite)8709 int16 cFodder::Sprite_Next_WalkTarget_Set(sSprite* pSprite) {
8710
8711 int16 Data0 = mSquad_WalkTargets[pSprite->field_32][pSprite->field_40].mX;
8712 int16 Data4 = mSquad_WalkTargets[pSprite->field_32][pSprite->field_40].mY;
8713
8714 // Do we have a valid walk target?
8715 if (Data0 >= 0) {
8716 pSprite->field_26 = Data0;
8717 pSprite->field_28 = Data4;
8718 pSprite->field_40++;
8719 pSprite->field_42 = -1;
8720 return 0;
8721 }
8722
8723 //loc_2D9C0
8724 if (!pSprite->field_42)
8725 return -1;
8726
8727 pSprite->field_42 = 0;
8728
8729 return Squad_Join(pSprite);
8730 }
8731
Squad_Join(sSprite * pSprite)8732 int16 cFodder::Squad_Join(sSprite* pSprite) {
8733 int16 Data14 = pSprite->field_32;
8734 int16 Data0;
8735
8736 int16 Data18 = mSquad_Join_TargetSquad[Data14];
8737 if (Data18 < 0)
8738 return -1;
8739
8740 Data18 &= 0xFF;
8741
8742 if (mSquads_TroopCount[Data14] > 8)
8743 return -1;
8744
8745 sMission_Troop* Dataa24 = pSprite->field_46_mission_troop;
8746 Dataa24->mSelected &= 0xFE;
8747
8748 sMapTarget* Data24 = mSquad_WalkTargets[Data18];
8749 Data0 = 0;
8750
8751 for (;;) {
8752
8753 sMapTarget eax = *Data24++;
8754 if (eax.asInt < 0)
8755 break;
8756
8757 Data0++;
8758 }
8759
8760 pSprite->field_40 = Data0;
8761 pSprite->field_32 = Data18;
8762 Squad_Troops_Count();
8763
8764 mSquad_Selected = Data18;
8765
8766 mSquad_Grenades[Data18] += mSquad_Grenades[Data14];
8767 mSquad_Rockets[Data18] += mSquad_Rockets[Data14];
8768
8769 //seg010:0232
8770 mSquad_Grenades[Data14] = 0;
8771 mSquad_Rockets[Data14] = 0;
8772
8773 sub_305D5(pSprite);
8774 mGUI_Sidebar_Setup = 0;
8775
8776 return -1;
8777 }
8778
Squad_Join_Check(sSprite * pSprite)8779 int16 cFodder::Squad_Join_Check(sSprite* pSprite) {
8780
8781 if (mSquad_Join_TargetSquad[pSprite->field_32] < 0)
8782 return -1;
8783
8784 sSprite* Dataa2C = mSquad_Join_TargetSprite[pSprite->field_32];
8785 if (Dataa2C->field_18 != eSprite_Player)
8786 return -1;
8787
8788 sSprite** Data30 = mSquads[mSquad_Selected];
8789 int16 MaxDistance = 0;
8790
8791 for (MaxDistance = 0x0C;;) {
8792 if (*Data30 == INVALID_SPRITE_PTR)
8793 break;
8794
8795 sSprite* eax = *Data30++;
8796
8797 if (pSprite == eax)
8798 break;
8799 MaxDistance += 8;
8800 }
8801
8802 int16 Data0 = Dataa2C->field_0;
8803 int16 Data4 = Dataa2C->field_4;
8804 int16 Data8 = pSprite->field_0;
8805 int16 DataC = pSprite->field_4;
8806 Map_Get_Distance_BetweenPoints_Within_Window(Data0, Data4, Data8, DataC);
8807 if (Data0 <= MaxDistance)
8808 return Squad_Join(pSprite);
8809
8810 return 0;
8811 }
8812
Squad_Walk_Target_Update(int16 pData0)8813 void cFodder::Squad_Walk_Target_Update(int16 pData0) {
8814 mSquad_WalkTargets[pData0]->asInt = -1;
8815
8816 sSprite** Data24 = mSquads[pData0];
8817
8818 for (;;) {
8819
8820 if (*Data24 == INVALID_SPRITE_PTR)
8821 break;
8822
8823 sSprite* Data28 = *Data24++;
8824 Data28->field_40 = 0;
8825 Data28->field_26 = Data28->field_0;
8826 Data28->field_28 = Data28->field_4;
8827 }
8828
8829 }
8830
Sprite_Handle_Explosion_MapTiles(sSprite * pSprite)8831 void cFodder::Sprite_Handle_Explosion_MapTiles(sSprite* pSprite) {
8832
8833 int16 Data0 = pSprite->field_0 + 4;
8834 int16 Data4 = pSprite->field_4 - 8;
8835
8836 const int16* Data24 = mSprite_Explosion_Positions;
8837
8838 for (; *Data24 != -32768;) {
8839
8840 Data0 += *Data24++;
8841 Data4 += *Data24++;
8842
8843 // Dont use negative map x/y coorindates
8844 if (Data0 < 0 || Data4 < 0) {
8845 continue;
8846 }
8847
8848 mMap_Destroy_Tiles.emplace_back( Data0, (pSprite->field_18 == eSprite_Explosion2) ? -Data4 : Data4 );
8849 }
8850 }
8851
Map_Destroy_Tiles()8852 void cFodder::Map_Destroy_Tiles() {
8853 uint8* MapPtr = 0;
8854 const int16* IndestructibleTypes = 0;
8855 int32 Data0, Data4, MapTile, TileType;
8856 sMapPosition LastTile;
8857
8858 if (mMap_Destroy_Tiles_Countdown) {
8859 --mMap_Destroy_Tiles_Countdown;
8860 goto loc_2DFC7;
8861 }
8862
8863
8864 for (auto& Tile : mMap_Destroy_Tiles) {
8865 bool TriggerExplosion = false;
8866
8867 LastTile = Tile;
8868
8869 Data0 = Tile.mX;
8870 Data4 = Tile.mY;
8871
8872 mMap_Destroy_Tile_X = Tile.mX;
8873 mMap_Destroy_Tile_Y = Tile.mY;
8874
8875 if (mMap_Destroy_Tile_Y < 0) {
8876 TriggerExplosion = true;
8877 Data4 = -Data4;
8878 mMap_Destroy_Tile_Y = -Tile.mY;
8879 }
8880 //loc_2DE89
8881 Data4 >>= 4;
8882 Data4 *= mMapLoaded->getWidth();
8883
8884 Data0 >>= 4;
8885 Data4 += Data0;
8886 Data4 <<= 1;
8887
8888 // In some cases, tiles outside the map can be 'destroyed'. This continue prevents memory corruption
8889 if ((size_t)(0x60 + Data4) >= mMap->size())
8890 continue;
8891
8892 MapPtr = mMap->data() + 0x60 + Data4;
8893 MapTile = readLE<uint16>(MapPtr);
8894 MapTile &= 0x1FF;
8895 TileType = MapTile;
8896
8897 Data4 = mTile_Destroy_Swap[MapTile];
8898 if (Data4 < 0)
8899 continue;
8900
8901 if (TriggerExplosion)
8902 goto loc_2DF7B;
8903
8904 IndestructibleTypes = mTiles_Indestructible[mMapLoaded->getTileType()];
8905
8906 int16 ax;
8907 do {
8908 if (*IndestructibleTypes < 0)
8909 goto loc_2DF7B;
8910
8911 ax = *IndestructibleTypes;
8912 IndestructibleTypes++;
8913
8914 } while (TileType != ax);
8915 }
8916
8917 mMap_Destroy_Tiles.clear();
8918 return;
8919
8920 //seg010:064C
8921 //UNUNSED BLOCK
8922
8923 loc_2DF7B:;
8924 Data0 = Sprite_Create_Building_Explosion_Wrapper(mMap_Destroy_Tile_X, mMap_Destroy_Tile_Y);
8925 if (Data0)
8926 return;
8927
8928 mMap_Destroy_Tiles_Countdown = 1;
8929 writeLEWord(MapPtr, Data4);
8930 mMap_Destroy_Tile_LastTile = Data4;
8931
8932 while (!(*mMap_Destroy_Tiles.begin() == LastTile))
8933 Map_Destroy_Tiles_Next();
8934
8935 Map_Destroy_Tiles_Next();
8936
8937 loc_2DFC7:;
8938 int16 ax = (mMap_Destroy_Tile_X >> 4);
8939 ax -= mMapTile_MovedHorizontal;
8940 ax <<= 4;
8941 ax -= mMapTile_ColumnOffset;
8942 ax += 0x40;
8943
8944 mVideo_Draw_PosX = ax;
8945
8946 ax = (mMap_Destroy_Tile_Y >> 4);
8947 ax -= mMapTile_MovedVertical;
8948 ax <<= 4;
8949 ax -= mMapTile_RowOffset;
8950 ax += 0x10;
8951
8952 mVideo_Draw_PosY = ax;
8953
8954 mVideo_Draw_Columns = 0x10;
8955 mVideo_Draw_Rows = 0x10;
8956 if (!mStartParams->mDisableVideo)
8957 mGraphics->MapTiles_Draw();
8958 }
8959
Map_Destroy_Tiles_Next()8960 void cFodder::Map_Destroy_Tiles_Next() {
8961
8962 if (mMap_Destroy_Tiles.size())
8963 mMap_Destroy_Tiles.erase(mMap_Destroy_Tiles.begin());
8964 }
8965
Game_Save_Wrapper()8966 void cFodder::Game_Save_Wrapper() {
8967
8968 mGraphics->SetActiveSpriteSheet(eGFX_RECRUIT);
8969 Game_Save();
8970 }
8971
Game_Save()8972 void cFodder::Game_Save() {
8973 mInput.clear();
8974 mGUI_Select_File_String_Input_Callback = 0;
8975 mSurface->clearBuffer();
8976
8977 GUI_Element_Reset();
8978
8979 GUI_Render_Text_Centred("TYPE A SAVE NAME IN", 0x32);
8980
8981 GUI_Button_Draw("EXIT", 0xA0);
8982 GUI_Button_Setup(&cFodder::GUI_Button_Load_Exit);
8983
8984 mGUI_Select_File_String_Input_Callback = &cFodder::String_Input_Print;
8985 GUI_Select_File_Loop(true);
8986 mGUI_Select_File_String_Input_Callback = 0;
8987
8988 if (mGUI_SaveLoadAction != 2) {
8989 mGUI_SaveLoadAction = 1;
8990 return;
8991 }
8992
8993 {
8994 std::string Filename = g_ResourceMan->GetSaveNewName();
8995 std::ofstream outfile(Filename, std::ofstream::binary);
8996 outfile << mGame_Data.ToJson(mInput);
8997 outfile.close();
8998 }
8999
9000 g_ResourceMan->refresh();
9001 mMouse_Exit_Loop = false;
9002 }
9003
String_Input_Print(int16 pPosY)9004 void cFodder::String_Input_Print(int16 pPosY) {
9005 GUI_Input_CheckKey();
9006
9007 GUI_Render_Text_Centred(mInput.c_str(), pPosY);
9008
9009 if (mKeyCodeAscii == 0x0D && mInput.size())
9010 mGUI_SaveLoadAction = 2;
9011
9012 if (mKeyCodeAscii == 8)
9013 goto loc_2E675;
9014
9015 // Is Number
9016 if (mKeyCodeAscii >= 0x30 && mKeyCodeAscii <= 0x39)
9017 goto loc_2E636;
9018
9019 if (mKeyCodeAscii < 0x41 || mKeyCodeAscii > 0x5A)
9020 goto loc_2E6A4;
9021
9022 loc_2E636:;
9023 if (mInput.size() >= 12)
9024 goto loc_2E6A4;
9025
9026 mInput.push_back((char)mKeyCodeAscii);
9027
9028 goto loc_2E6A4;
9029
9030 loc_2E675:;
9031
9032 if (mInput.size()) {
9033 mInput.pop_back();
9034 }
9035
9036 loc_2E6A4:;
9037 String_Input_Check();
9038 }
9039
String_Input_Check()9040 void cFodder::String_Input_Check() {
9041
9042 if (mKeyCodeAscii != 0x0D) {
9043 byte_44AC0 &= 0x3F;
9044 if (byte_44AC0 < 0x20)
9045 goto loc_2E6EA;
9046 }
9047 return;
9048
9049 loc_2E6EA:;
9050 }
9051
Game_Load()9052 void cFodder::Game_Load() {
9053 auto Files = g_ResourceMan->GetSaves();
9054 std::vector<sSavedGame> SaveFiles;
9055
9056 SaveFiles = Game_Load_Filter(Files);
9057 Files.clear();
9058
9059
9060 const std::string File = GUI_Select_File("SELECT SAVED GAME", SaveFiles, Files);
9061 if (!File.size())
9062 return;
9063
9064 auto SaveData = g_ResourceMan->FileReadStr(g_ResourceMan->GetSave(File));
9065
9066 // Load the game data from the JSONstd::string((char*)SaveData->data(), SaveData->size()))
9067 if (!mGame_Data.FromJson(SaveData)) {
9068 return;
9069 }
9070
9071 // If the game was saved on a different platform, lets look for it and attempt to switch
9072 if (mGame_Data.mSavedVersion.mPlatform != mVersionCurrent->mPlatform) {
9073
9074 VersionSwitch( mVersions->GetForCampaign(mGame_Data.mCampaignName, mGame_Data.mSavedVersion.mPlatform) );
9075 }
9076
9077 mMouse_Exit_Loop = false;
9078
9079 for (int16 x = 0; x < 8; ++x)
9080 mMission_Troops_SpritePtrs[x] = INVALID_SPRITE_PTR;
9081
9082 for (auto& Troop : mGame_Data.mSoldiers_Allocated)
9083 Troop.mSprite = INVALID_SPRITE_PTR;
9084
9085 GameData_Backup();
9086 GameData_Restore();
9087 }
9088
Game_Load_Filter(const std::vector<std::string> & pFiles)9089 std::vector<sSavedGame> cFodder::Game_Load_Filter(const std::vector<std::string>& pFiles) {
9090 std::vector<sSavedGame> Results;
9091
9092 for (auto& CurrentFile : pFiles) {
9093
9094 auto SaveData = g_ResourceMan->FileRead(g_ResourceMan->GetSave(CurrentFile));
9095
9096 // Verify the savegame is for the current campaign
9097 try {
9098 sGameData NewData( std::string((char*)SaveData->data(), SaveData->size()) );
9099
9100 // Ensure for this campaign
9101 if (NewData.mCampaignName != mGame_Data.mCampaign.getName())
9102 continue;
9103
9104 // Ensure the game is the same
9105 if (NewData.mSavedVersion.mGame != mVersionCurrent->mGame)
9106 continue;
9107
9108 Results.push_back({ CurrentFile, NewData.mSavedName });
9109 }
9110 catch (...) {
9111 continue;
9112 }
9113 }
9114
9115 // Sort newest first
9116 std::sort(Results.begin(), Results.end(), [](sSavedGame& pLeft, sSavedGame& pRight) {
9117 return std::atoll(pLeft.mFileName.c_str()) > std::atoll(pRight.mFileName.c_str());
9118 });
9119
9120 return Results;
9121 }
9122
Menu_Button_Reset()9123 void cFodder::Menu_Button_Reset() {
9124 mCustom_ExitMenu = 0;
9125 mPhase_Aborted = false;
9126 mDemo_ExitMenu = -1;
9127 }
9128
9129 /**
9130 * Caller of Menu_Loop is responsible for cleaning up button states
9131 */
Menu_Loop(const std::function<void ()> pButtonHandler)9132 void cFodder::Menu_Loop(const std::function<void()> pButtonHandler) {
9133
9134 Menu_Button_Reset();
9135
9136 mSurface->Save();
9137 mGraphics->PaletteSet();
9138 mSurface->palette_FadeTowardNew();
9139
9140 for (;;) {
9141
9142 Cycle_End();
9143
9144 if (Menu_Draw(pButtonHandler))
9145 break;
9146 }
9147
9148 Image_FadeOut();
9149 mSurface->clearBuffer();
9150 }
9151
Menu_Draw(const std::function<void ()> pButtonHandler)9152 bool cFodder::Menu_Draw(const std::function<void()> pButtonHandler) {
9153
9154 // Handle Mouse
9155 Mouse_Inputs_Get();
9156 Mouse_DrawCursor();
9157
9158 // Button Pressed?
9159 if (mButtonPressLeft)
9160 pButtonHandler();
9161
9162 // Exit Time?
9163 if (mDemo_ExitMenu > 0 || mPhase_Aborted || mCustom_ExitMenu)
9164 return true;
9165
9166 if (mSurface->isPaletteAdjusting())
9167 mSurface->palette_FadeTowardNew();
9168
9169 Video_SurfaceRender();
9170 return false;
9171 }
9172
Demo_Quiz_ShowScreen(const char * pFilename)9173 void cFodder::Demo_Quiz_ShowScreen(const char* pFilename) {
9174
9175 Image_FadeOut();
9176
9177 mGraphics->Load_And_Draw_Image(pFilename, 32);
9178 mGraphics->PaletteSet();
9179
9180 mSurface->Save();
9181 mSurface->palette_FadeTowardNew();
9182
9183 for (;; ) {
9184 Cycle_End();
9185
9186 Mouse_Inputs_Get();
9187 Mouse_DrawCursor();
9188
9189 if (mButtonPressLeft || mPhase_Aborted)
9190 break;
9191
9192 if (mSurface->isPaletteAdjusting())
9193 mSurface->palette_FadeTowardNew();
9194
9195 Video_SurfaceRender();
9196 }
9197
9198 Image_FadeOut();
9199
9200 mGraphics->Load_And_Draw_Image("1.lbm", 32);
9201 mGraphics->PaletteSet();
9202
9203 mSurface->Save();
9204 mSurface->palette_FadeTowardNew();
9205
9206 Menu_Button_Reset();
9207 }
9208
Demo_Quiz()9209 void cFodder::Demo_Quiz() {
9210 Image_FadeOut();
9211
9212 mGraphics->Load_And_Draw_Image("1.lbm", 32);
9213 Mouse_Setup();
9214
9215 Menu_Loop(
9216 [this]() {
9217 if (mButtonPressLeft)
9218 GUI_Element_Mouse_Over(mPlusQuiz_Buttons);
9219 }
9220 );
9221
9222 mGraphics->Load_And_Draw_Image("apmenu.lbm", 32);
9223 mGraphics->PaletteSet();
9224 mSurface->palette_FadeTowardNew();
9225 mSurface->Save();
9226
9227 Menu_Button_Reset();
9228 }
9229
Squad_Select(int16 pData4,bool pCheckMouse)9230 void cFodder::Squad_Select(int16 pData4, bool pCheckMouse) {
9231
9232 if (pCheckMouse && Mouse_Button_Left_Toggled() < 0)
9233 return;
9234
9235 mSquad_Selected = pData4;
9236 Mission_Troops_Clear_Selected();
9237 Squad_Troops_Count();
9238
9239 sSprite* Data20 = 0;
9240 sub_305D5(Data20);
9241
9242 if (Data20 == INVALID_SPRITE_PTR)
9243 return;
9244
9245 mCamera_Panning_ToTarget = false;
9246 mCamera_StartPosition_X = Data20->field_0;
9247 mCamera_StartPosition_Y = Data20->field_4;
9248 mCamera_Start_Adjust = true;
9249 mSquad_Select_Timer = 1;
9250 mGUI_Sidebar_Setup = 0;
9251 mSquad_Grenade_SplitMode = eSquad_Weapon_Split_Half;
9252 mSquad_Rocket_SplitMode = eSquad_Weapon_Split_Half;
9253 word_3AC4B = 0;
9254 word_3AC4D = 0;
9255 }
9256
Mission_Set_Initial_Weapon()9257 void cFodder::Mission_Set_Initial_Weapon() {
9258
9259 // segra: I don't believe this condition can ever occur
9260 if (mSquad_CurrentWeapon[mGUI_Loop_Squad_Current] == eWeapon_Grenade) {
9261
9262 if (mSquad_Grenades[mGUI_Loop_Squad_Current])
9263 return;
9264 if (!mSquad_Rockets[mGUI_Loop_Squad_Current])
9265 return;
9266
9267 mSquad_CurrentWeapon[mGUI_Loop_Squad_Current] = eWeapon_Rocket;
9268 return;
9269 }
9270
9271 //loc_2EFF1
9272 if (mSquad_Rockets[mGUI_Loop_Squad_Current])
9273 return;
9274
9275 if (!mSquad_Grenades[mGUI_Loop_Squad_Current])
9276 return;
9277
9278 mSquad_CurrentWeapon[mGUI_Loop_Squad_Current] = eWeapon_Grenade;
9279 }
9280
Service_Show()9281 void cFodder::Service_Show() {
9282 if (mParams->mSkipService)
9283 return;
9284
9285 mWindow->SetScreenSize(mVersionCurrent->GetScreenSize());
9286 mVersionPlatformSwitchDisabled = true;
9287
9288 WindowTitleSet(false);
9289
9290 mGraphics->Load_Service_Data();
9291 mGraphics->SetActiveSpriteSheet(eGFX_SERVICE);
9292 mGraphics->PaletteSet();
9293
9294 mSound->Music_Play(0);
9295 Service_KIA_Loop();
9296
9297 if(!mVersionCurrent->isAmigaTheOne())
9298 Service_Promotion_Loop();
9299
9300 Mouse_Setup();
9301
9302 mGraphics->Load_pStuff();
9303 mVersionPlatformSwitchDisabled = false;
9304 mPhase_Aborted = false;
9305 }
9306
Service_KIA_Loop()9307 void cFodder::Service_KIA_Loop() {
9308 Mouse_Setup();
9309 mService_Promotion_Exit_Loop = 0;
9310
9311 if (Service_KIA_Troop_Prepare() < 0)
9312 return;
9313
9314 mSurface->clearBuffer();
9315
9316 if (mVersionCurrent->isPC()) {
9317 GUI_Draw_Frame_8(5, 0, 0x34, 0);
9318 GUI_Draw_Frame_16(7, 0, 0, 0x31);
9319 GUI_Draw_Frame_16(7, 0, 0xF0, 0x31);
9320 }
9321 else {
9322 GetGraphics<cGraphics_Amiga>()->Service_Draw(8, 0x30, 0);
9323 GetGraphics<cGraphics_Amiga>()->Service_Draw(0, 0, 0x40);
9324 GetGraphics<cGraphics_Amiga>()->Service_Draw(4, 0xF0, 0x40);
9325 }
9326
9327 mMouse_Exit_Loop = false;
9328 mService_ExitLoop = 0;
9329 mGraphics->PaletteSet();
9330 mSurface->Save();
9331
9332 do {
9333 Mouse_Inputs_Get();
9334
9335 if (mService_Promotion_Exit_Loop == -1 || mMouse_Exit_Loop) {
9336 mMouse_Exit_Loop = false;
9337 mSurface->paletteNew_SetToBlack();
9338 mService_ExitLoop = 1;
9339 }
9340
9341 if (mSurface->isPaletteAdjusting())
9342 mSurface->palette_FadeTowardNew();
9343
9344 Service_Draw_List();
9345 Cycle_End();
9346 Service_ScrollUp_DrawList();
9347
9348 Video_SurfaceRender();
9349
9350 } while (mSurface->isPaletteAdjusting() || mService_ExitLoop == 0);
9351 }
9352
Service_Promotion_Loop()9353 void cFodder::Service_Promotion_Loop() {
9354 Mouse_Setup();
9355 mService_Promotion_Exit_Loop = 0;
9356
9357 if (Service_Promotion_Prepare_Draw() < 0)
9358 goto loc_18001;
9359
9360 mSurface->clearBuffer();
9361 if (mVersionCurrent->isPC()) {
9362 GUI_Draw_Frame_8(6, 0, 0x34, 0);
9363 GUI_Draw_Frame_16(8, 0, 0, 0x31);
9364 GUI_Draw_Frame_16(8, 0, 0xF0, 0x31);
9365 }
9366 else {
9367 GetGraphics<cGraphics_Amiga>()->Service_Draw(9, 0x30, 0); // Heroes in Victory
9368 GetGraphics<cGraphics_Amiga>()->Service_Draw(3, 0, 0x40); // Left Symbol
9369 GetGraphics<cGraphics_Amiga>()->Service_Draw(7, 0xF0, 0x40); // Right Symbol
9370 }
9371
9372 mService_ExitLoop = 0;
9373 mMouse_Exit_Loop = false;
9374 mGraphics->PaletteSet();
9375 mSurface->Save();
9376
9377 do {
9378
9379 Mouse_Inputs_Get();
9380 if (mService_Promotion_Exit_Loop == -1 || mMouse_Exit_Loop) {
9381 mMouse_Exit_Loop = false;
9382 mSurface->paletteNew_SetToBlack();
9383 mService_ExitLoop = 1;
9384 }
9385
9386 if (mSurface->isPaletteAdjusting())
9387 mSurface->palette_FadeTowardNew();
9388
9389 Service_Promotion_Check();
9390 Service_Draw_List();
9391 Cycle_End();
9392 //sub_14445();
9393 Service_ScrollUp_DrawList();
9394
9395 Video_SurfaceRender();
9396
9397 } while (mSurface->isPaletteAdjusting() || mService_ExitLoop == 0);
9398
9399 loc_18001:;
9400
9401 for (auto& Troop : mGame_Data.mSoldiers_Allocated) {
9402 Troop.Promote();
9403 }
9404 }
9405
Service_KIA_Troop_Prepare()9406 int16 cFodder::Service_KIA_Troop_Prepare() {
9407 mService_Draw_List.clear();
9408
9409 mVideo_Draw_PosY = 0xE8;
9410 Service_Mission_Text_Prepare();
9411 mVideo_Draw_PosY += 0x40;
9412
9413 if (mGame_Data.mHeroes.empty() || mGame_Data.mGamePhase_Data.mHeroesCount == mGame_Data.mHeroes.size())
9414 return -1;
9415
9416
9417 for (size_t i = mGame_Data.mGamePhase_Data.mHeroesCount; i < mGame_Data.mHeroes.size(); ++i) {
9418
9419 auto& Hero = mGame_Data.mHeroes[i];
9420
9421 Service_Draw_Troop_And_Rank(Hero.mRecruitID, Hero.mRank);
9422 mVideo_Draw_PosY += 0x40;
9423 }
9424
9425 return 0;
9426 }
9427
Service_Promotion_Prepare_Draw()9428 int16 cFodder::Service_Promotion_Prepare_Draw() {
9429 mService_Draw_List.clear();
9430
9431 mVideo_Draw_PosY = 0xE8;
9432 Service_Mission_Text_Prepare();
9433 mVideo_Draw_PosY += 0x40;
9434 size_t Drawn = mService_Draw_List.size();
9435
9436 for (auto& Troop : mGame_Data.mSoldiers_Allocated) {
9437
9438 if (Troop.mSprite != INVALID_SPRITE_PTR) {
9439 int16 ax = Troop.mRecruitID;
9440 int8 bl = Troop.mRank;
9441
9442 bl &= 0xFF;
9443
9444 Service_Draw_Troop_And_Rank(ax, bl);
9445
9446 mVideo_Draw_PosY += 0x40;
9447 }
9448 }
9449
9450 // No names drawn?
9451 if (Drawn == mService_Draw_List.size())
9452 return -1;
9453
9454 return 0;
9455 }
9456
Service_Draw_String(const std::string & pText,const bool pLarge,const size_t pY)9457 void cFodder::Service_Draw_String(const std::string& pText, const bool pLarge, const size_t pY) {
9458
9459 const uint8* FontWidth = mFont_Briefing_Width;
9460 if (pLarge)
9461 FontWidth = mFont_ServiceName_Width;
9462
9463 String_CalculateWidth(320, FontWidth, pText.c_str());
9464 Service_Draw_String(pText, FontWidth, pLarge ? 3 : 0, mGUI_Temp_X, (int16) pY);
9465
9466 }
9467
Service_Draw_Troop_And_Rank(int16 pRecruitID,int16 pRank)9468 void cFodder::Service_Draw_Troop_And_Rank(int16 pRecruitID, int16 pRank) {
9469
9470 mService_Draw_List.emplace_back(PLATFORM_BASED(9, 0), PLATFORM_BASED(0, 1), 0x60, mVideo_Draw_PosY);
9471 mService_Draw_List.emplace_back(2, pRank, 0x64, mVideo_Draw_PosY + 4);
9472 mService_Draw_List.emplace_back(2, pRank, 0xCC, mVideo_Draw_PosY + 4);
9473
9474 //seg003:3237
9475 const char* si = mRecruits[pRecruitID].mName;
9476 std::stringstream tmpString;
9477
9478 for (int16 cx = 5; cx >= 0; --cx) {
9479 // Break on space
9480 if (*si == 0x20)
9481 break;
9482
9483 tmpString << *si++;
9484 }
9485
9486 Service_Draw_String(tmpString.str(), true, (size_t) mVideo_Draw_PosY + 6);
9487 }
9488
Service_Promotion_Check()9489 void cFodder::Service_Promotion_Check() {
9490 auto* Troop = &mGame_Data.mSoldiers_Allocated[0];
9491
9492 if (!mService_Draw_List.size())
9493 return;
9494
9495 for( size_t x = 0; x < mService_Draw_List.size() - 1; ++x) {
9496 auto Draw = &mService_Draw_List[x];
9497
9498 if (Draw->mSpriteType != 2)
9499 continue;
9500
9501 int16 newRank = Troop->GetPromotedRank();
9502 if (Troop->mRecruitID == -1) {
9503 ++Troop;
9504 --x;
9505 continue;
9506 }
9507 ++Troop;
9508 ++x;
9509
9510 if (Draw->mY >= (getCameraHeight() - 8) / 2)
9511 continue;
9512
9513 (Draw+0)->mFrame = newRank;
9514 (Draw+1)->mFrame = newRank;
9515 }
9516 }
9517
Service_Draw_List()9518 void cFodder::Service_Draw_List() {
9519
9520 for(auto& Draw : mService_Draw_List) {
9521
9522 if (Draw.mY < 8)
9523 continue;
9524
9525 Service_Sprite_Draw(Draw.mSpriteType, Draw.mFrame, Draw.mX, Draw.mY);
9526 }
9527 }
9528
Service_ScrollUp_DrawList()9529 void cFodder::Service_ScrollUp_DrawList() {
9530 mService_Promotion_Exit_Loop = -1;
9531
9532 for (auto& Draw : mService_Draw_List) {
9533
9534 Draw.mY -= 1;
9535
9536 if(Draw.mY >= -4)
9537 mService_Promotion_Exit_Loop = 0;
9538
9539 }
9540
9541 //auto remove = std::remove_if(mService_Draw_List.begin(), mService_Draw_List.end(), [](auto pVal)
9542 //{ return pVal.mY < -48; });
9543
9544 //mService_Draw_List.erase(remove, mService_Draw_List.end());
9545 }
9546
Service_Draw_String(const std::string & pText,const uint8 * pData28,int16 pData0,int16 pData8,int16 pDataC)9547 void cFodder::Service_Draw_String(const std::string& pText, const uint8* pData28, int16 pData0, int16 pData8, int16 pDataC) {
9548
9549 const char* Data20 = pText.c_str();
9550
9551 for (;;) {
9552 int16 Data4 = *Data20++;
9553 if (Data4 == 0)
9554 break;
9555
9556 int16 Data10 = Data4;
9557
9558 if (mString_GapCharID) {
9559
9560 if (Data4 == 0x20)
9561 goto loc_18229;
9562
9563 Data4 = mString_GapCharID;
9564 goto loc_18259;
9565 }
9566 //loc_18222
9567 if (Data4 == 0x20)
9568 goto loc_1826D;
9569 loc_18229:;
9570 if (Data4 > 0x39)
9571 goto loc_1823C;
9572
9573 Data4 -= 0x30;
9574 Data4 += 0x1A;
9575 goto loc_18259;
9576 loc_1823C:;
9577 if (Data4 >= 0x5A) {
9578 Data4 -= 0x61;
9579 Data4 += 0x39;
9580 }
9581 else {
9582 Data4 -= 0x41;
9583 Data4 += 0;
9584 }
9585
9586 loc_18259:;
9587 mService_Draw_List.emplace_back(pData0, Data4, pData8, pDataC);
9588
9589 loc_1826D:;
9590
9591 Data10 = pData28[Data10];
9592 pData8 += Data10;
9593 }
9594 }
9595
Service_Sprite_Draw(int16 & pSpriteType,int16 & pFrame,int16 & pX,int16 & pY)9596 int16 cFodder::Service_Sprite_Draw(int16& pSpriteType, int16& pFrame, int16& pX, int16& pY) {
9597 auto SheetData = Sprite_Get_Sheet(pSpriteType, pFrame);
9598
9599 mVideo_Draw_PaletteIndex = SheetData->mPalleteIndex & 0xFF;
9600 mVideo_Draw_FrameDataPtr = SheetData->GetGraphicsPtr();
9601
9602 mVideo_Draw_PosX = pX + 0x10;
9603 mVideo_Draw_PosY = pY + 0x10;
9604
9605
9606 mVideo_Draw_Columns = SheetData->mColCount;
9607 mVideo_Draw_Rows = SheetData->mRowCount;
9608
9609 if (!Service_Sprite_OnScreen_Check()) {
9610 if (mVersionCurrent->mPlatform == ePlatform::Amiga)
9611 mGraphics->Video_Draw_16(mFont_Service_PalleteIndex_Amiga);
9612 else
9613 mGraphics->Video_Draw_8(0, mFont_Service_PalleteIndex);
9614
9615 return 1;
9616 }
9617 return 0;
9618 }
9619
Service_Sprite_OnScreen_Check()9620 int16 cFodder::Service_Sprite_OnScreen_Check() {
9621 int16 ax;
9622
9623 if (mVideo_Draw_PosY < 0x2C) {
9624 ax = mVideo_Draw_PosY;
9625 ax += mVideo_Draw_Rows;
9626 --ax;
9627 if (ax < 0x2C)
9628 return -1;
9629
9630 ax -= 0x2C;
9631 ax -= mVideo_Draw_Rows;
9632 ++ax;
9633 ax = -ax;
9634 mVideo_Draw_PosY += ax;
9635 mVideo_Draw_Rows -= ax;
9636
9637 ax *= PLATFORM_BASED(160, 40);
9638
9639 mVideo_Draw_FrameDataPtr += ax;
9640 }
9641 //loc_184FC
9642
9643 ax = mVideo_Draw_PosY;
9644 ax += mVideo_Draw_Rows;
9645 --ax;
9646
9647 if (ax <= 0xE7)
9648 return 0;
9649
9650 if (mVideo_Draw_PosY > 0xE7)
9651 return -1;
9652
9653 ax -= 0xE7;
9654 mVideo_Draw_Rows -= ax;
9655 return 0;
9656 }
9657
Service_Mission_Text_Prepare()9658 void cFodder::Service_Mission_Text_Prepare() {
9659 std::stringstream Mission;
9660 Mission << "MISSION ";
9661
9662 Mission << tool_StripLeadingZero(std::to_string(mGame_Data.mMission_Number));
9663
9664 String_CalculateWidth(320, mFont_Service_Width, Mission.str().c_str());
9665
9666 Service_Draw_String(Mission.str(), mFont_Service_Width, 4, mGUI_Temp_X, mVideo_Draw_PosY);
9667 }
9668
Briefing_Draw_Phase()9669 void cFodder::Briefing_Draw_Phase() {
9670 const char* Str_Brief = "BRIEFING";
9671 const char* Str_Phase = "PHASE ";
9672 const char* Str_Of = " OF ";
9673
9674 mString_GapCharID = 0x25;
9675
9676 String_Print_Large(Str_Brief, true, 0x4E);
9677
9678 Briefing_DrawBox(1, 0x49, 0x13E, 0x6B, 0xF3);
9679 Briefing_DrawBox(0, 0x48, 0x13E, 0x6B, 0xF2);
9680
9681 mString_GapCharID = 0;
9682
9683 std::stringstream Phase;
9684
9685 Phase << Str_Phase << tool_StripLeadingZero(std::to_string(mGame_Data.mMission_Phase));
9686 Phase << Str_Of << tool_StripLeadingZero(std::to_string(mGame_Data.mMission_Current->NumberOfPhases()));
9687
9688 String_Print_Small(Phase.str(), 0x1D);
9689
9690 Phase_Goals_Set();
9691
9692 int16 DataC = 0x84;
9693 bool* Goals = mGame_Data.mGamePhase_Data.mGoals_Remaining;
9694
9695 for (const auto GoalName : mMissionGoal_Titles) {
9696 if (*Goals++) {
9697
9698 String_Print_Small(GoalName, DataC - 0x12);
9699 DataC += 0x0C;
9700 }
9701 }
9702 }
9703
Briefing_Show_PreReady()9704 void cFodder::Briefing_Show_PreReady() {
9705
9706 if (mVersionCurrent->isDemo() && !mGame_Data.mCampaign.isCustom() && !mGame_Data.mCampaign.isRandom())
9707 return;
9708
9709 if (!mVersionCurrent->hasGfx(eGFX_BRIEFING) && !mGame_Data.mCampaign.isRandom())
9710 VersionSwitch(mVersionDefault);
9711
9712 mWindow->SetScreenSize(mVersionCurrent->GetScreenSize());
9713 mSurface->clearBuffer();
9714 mGraphics->PaletteSet();
9715
9716 mGraphics->SetActiveSpriteSheet(eGFX_BRIEFING);
9717
9718 Briefing_Draw_Mission_Title(0x2C);
9719 Briefing_Draw_Phase();
9720
9721 Image_FadeIn();
9722 }
9723
Briefing_Show_Ready()9724 void cFodder::Briefing_Show_Ready() {
9725
9726 if (mVersionCurrent->isDemo() && !mGame_Data.mCampaign.isCustom() && !mGame_Data.mCampaign.isRandom())
9727 return;
9728
9729 mGraphics->SetActiveSpriteSheet(eGFX_BRIEFING);
9730
9731 Briefing_Draw_Mission_Title(0x2C);
9732 Briefing_Draw_Phase();
9733 Briefing_Draw_With();
9734
9735 mMouse_Exit_Loop = false;
9736
9737 do {
9738 Mouse_Inputs_Get();
9739
9740 if (mPhase_Aborted) {
9741 mBriefing_Aborted = -1;
9742 mMouseButtonStatus = -1;
9743 break;
9744 }
9745
9746 Video_SurfaceRender(false);
9747 Cycle_End();
9748
9749 } while (!mMouse_Exit_Loop);
9750
9751 mMouse_Exit_Loop = false;
9752
9753 Image_FadeOut();
9754 Mouse_Setup();
9755 }
9756
Briefing_Draw_With()9757 void cFodder::Briefing_Draw_With() {
9758 std::stringstream With;
9759
9760 With << "WITH ";
9761 With << tool_StripLeadingZero(std::to_string(mGame_Data.mGamePhase_Data.mSoldiers_Available));
9762
9763 if (mGame_Data.mGamePhase_Data.mSoldiers_Available == 1) {
9764 With << " SOLDIER YOU MUST";
9765 }
9766 else {
9767 With << " SOLDIERS YOU MUST";
9768 }
9769
9770 String_Print_Small(With.str(), 0x64);
9771 With.str("");
9772
9773 if (!mGame_Data.mRecruits_Available_Count) {
9774 With << "THIS IS YOUR LAST CHANCE";
9775 }
9776 else {
9777 With << mGame_Data.mRecruits_Available_Count;
9778 if (mGame_Data.mRecruits_Available_Count == 1)
9779 With << " RECRUIT REMAINING";
9780 else
9781 With << " RECRUITS REMAINING";
9782 }
9783
9784 String_Print_Small(With.str(), 0xA8);
9785 String_Print_Large("GO FOR IT", false, 0xB8);
9786 }
9787
Briefing_DrawBox(int16 pX,int16 pY,int16 pWidth,int16 pHeight,uint8 pColor)9788 void cFodder::Briefing_DrawBox(int16 pX, int16 pY, int16 pWidth, int16 pHeight, uint8 pColor) {
9789 pX += 0x10;
9790 pY += 0x10;
9791
9792 // Top and Bottom
9793 Briefing_Draw_Horizontal_Line(pX, pX + pWidth, pY, pColor);
9794
9795 Briefing_Draw_Horizontal_Line(pX, pX + pWidth, pY + pHeight, pColor);
9796
9797 // Sides of box
9798 Briefing_Draw_Vertical_Line(pX, pY + pHeight, pY, pColor);
9799
9800 Briefing_Draw_Vertical_Line(pX + pWidth, pY + pHeight, pY, pColor);
9801 }
9802
Briefing_Draw_Pixel(int16 pX,int16 pY,uint8 pColor)9803 void cFodder::Briefing_Draw_Pixel(int16 pX, int16 pY, uint8 pColor) {
9804 uint8* di = mSurface->GetSurfaceBuffer();
9805
9806 di += mSurface->GetWidth() * pY;
9807 di += pX;
9808 *di = pColor;
9809 }
9810
Briefing_Draw_Horizontal_Line(int16 pX,int16 pWidth,int16 pY,uint8 pColor)9811 void cFodder::Briefing_Draw_Horizontal_Line(int16 pX, int16 pWidth, int16 pY, uint8 pColor) {
9812
9813 do {
9814 Briefing_Draw_Pixel(pX, pY, pColor);
9815 ++pX;
9816 } while (pX <= pWidth);
9817 }
9818
Briefing_Draw_Vertical_Line(int16 pX,int16 pHeight,int16 pY,uint8 pColor)9819 void cFodder::Briefing_Draw_Vertical_Line(int16 pX, int16 pHeight, int16 pY, uint8 pColor) {
9820
9821 do {
9822 Briefing_Draw_Pixel(pX, pY, pColor);
9823 ++pY;
9824 } while (pY <= pHeight);
9825 }
9826
Sprite_Frame_Modifier_Update()9827 void cFodder::Sprite_Frame_Modifier_Update() {
9828
9829 mSprite_Frame_Modifier_Update_Countdown -= 1;
9830 if (mSprite_Frame_Modifier_Update_Countdown < 0) {
9831 mSprite_Frame_Modifier_Update_Countdown = 3;
9832
9833 mSprite_Frame_1 += mSprite_Frame1_Modifier;
9834 if (mSprite_Frame_1 == 0 || mSprite_Frame_1 == 2)
9835 mSprite_Frame1_Modifier ^= -2;
9836
9837 mSprite_Frame_2 += mSprite_Frame2_Modifier;
9838 if (mSprite_Frame2_Modifier == 0 || mSprite_Frame2_Modifier == 2)
9839 mSprite_Frame2_Modifier ^= -2;
9840 }
9841
9842 //loc_18DA7
9843 mSprite_Frame3_ChangeCount -= 1;
9844 if (mSprite_Frame3_ChangeCount < 0) {
9845 mSprite_Frame3_ChangeCount = 1;
9846
9847 mSprite_Frame_3 += mSprite_Frame_3_Modifier;
9848 if (mSprite_Frame_3 == 0 || mSprite_Frame_3 == 2)
9849 mSprite_Frame_3_Modifier ^= -2;
9850 }
9851 }
9852
Sprite_Handle_Loop()9853 void cFodder::Sprite_Handle_Loop() {
9854 sSprite* Data20 = mSprites.data();
9855
9856 for (int32 Data1C = mParams->mSpritesMax - 2; Data1C > 0; --Data1C, ++Data20) {
9857
9858 if (Data20->field_0 == -32768)
9859 continue;
9860
9861 (*this.*mSprite_Function[Data20->field_18])(Data20);
9862 }
9863 }
9864
Sprite_Handle_Null(sSprite * pSprite)9865 void cFodder::Sprite_Handle_Null(sSprite* pSprite) {
9866
9867 switch (pSprite->field_18) {
9868 case 4:
9869 return;
9870
9871 default:
9872 std::cout << "Sprite Function not implemented: " << pSprite->field_18 << "\n";
9873 break;
9874 }
9875
9876 }
9877
Sprite_Handle_Player(sSprite * pSprite)9878 void cFodder::Sprite_Handle_Player(sSprite *pSprite) {
9879 int16 Data0, Data4, eax;
9880 sSprite* Data28 = 0;
9881
9882 // player soldier in vehicle?
9883 if (pSprite->field_6E) {
9884 Sprite_Handle_Player_InVehicle(pSprite);
9885 return;
9886 }
9887
9888 // If player is invincible
9889 if (pSprite->field_75 & eSprite_Flag_Invincibility) {
9890
9891 // And dying
9892 if (pSprite->field_38 <= eSprite_Anim_Slide1)
9893 pSprite->field_38 = eSprite_Anim_None;
9894
9895 // No longer Sinking
9896 pSprite->field_5B = 0;
9897
9898 // Unknown
9899 pSprite->field_64 = 0;
9900 }
9901
9902 if (Sprite_Handle_Soldier_Animation(pSprite))
9903 return;
9904
9905 // Animation running?
9906 if (pSprite->field_38)
9907 return;
9908
9909 if (Sprite_Handle_Player_MissionOver(pSprite))
9910 return;
9911
9912 //loc_18E8D
9913 Sprite_Handle_Player_Enter_Vehicle(pSprite);
9914 mSprite_FaceWeaponTarget = 0;
9915
9916 word_3AA1D = word_3BED5[pSprite->field_32];
9917 //seg004:0183
9918
9919 if (mSquad_Join_TargetSquad[pSprite->field_32] < 0 && pSprite->field_32 != mSquad_Selected) {
9920 //loc_18F12
9921 mSprite_FaceWeaponTarget = -1;
9922
9923 Data28 = &mSprites[pSprite->field_5E];
9924
9925 // The original engine checked 1 sprite per cycle, this is problematic
9926 // with max sprites gets bigger, especially at 100,000. So we check every sprite
9927 // every cycle, if not using the original parameters.
9928 if (!mParams->isOriginalSpriteMax()) {
9929 bool looped = false;
9930
9931 while (Data28->field_0 == -32768) {
9932 ++pSprite->field_5E;
9933 if (pSprite->field_5E >= (mParams->mSpritesMax - 2)) {
9934 pSprite->field_5E = 0;
9935 if (looped)
9936 break;
9937
9938 looped = true;
9939 }
9940 Data28 = &mSprites[pSprite->field_5E];
9941 };
9942 }
9943
9944 if (Data28->field_0 != -32768) {
9945
9946 if (Data28->field_18 == eSprite_Enemy) {
9947 if (Data28->field_38 == eSprite_Anim_None) {
9948
9949 //seg004:021A
9950 if (pSprite->field_4F == 0) {
9951 //seg004:0228
9952 Data0 = pSprite->field_0;
9953 Data4 = pSprite->field_4;
9954
9955 int16 Data8 = Data28->field_0;
9956 int16 DataC = Data28->field_4;
9957
9958 Map_Get_Distance_BetweenPoints_Within_Window(Data0, Data4, Data8, DataC);
9959 if (Data0 < 0xD2) {
9960
9961 if (Data0 <= 0x28)
9962 goto loc_1904A;
9963
9964 //seg004:0270
9965 mSprite_Find_Distance = Data0;
9966 Data0 = pSprite->field_0;
9967 Data4 = pSprite->field_4;
9968 Data8 = Data28->field_0;
9969 DataC = Data28->field_4;
9970
9971 if (Map_PathCheck_CalculateTo(Data0, Data4, Data8, DataC) == 0) {
9972 Data0 = mSprite_Find_Distance;
9973 goto loc_1904A;
9974 }
9975 if (mSprite_Find_Distance < 0x40)
9976 goto loc_1904A;
9977 }
9978 }
9979 }
9980 }
9981 }
9982
9983 loc_1901C:;
9984 pSprite->field_4A = 0;
9985 pSprite->field_5E++;
9986 if (pSprite->field_5E >= (mParams->mSpritesMax - 2))
9987 pSprite->field_5E = 0;
9988
9989 goto loc_191C3;
9990
9991 loc_1904A:;
9992 Data0 = tool_RandomGet() & 0x1F;
9993
9994 if (Data0 == 5)
9995 goto loc_1901C;
9996
9997 pSprite->field_5A = -1;
9998 mTroop_Weapon_Grenade_Disabled = false;
9999 mTroop_Weapon_Bullet_Disabled = false;
10000 mTroop_Weapon_Rocket_Disabled = false;
10001
10002 pSprite->field_2E = Data28->field_0;
10003 pSprite->field_30 = Data28->field_4 - 0x0E;
10004
10005 // Fired Weapon?
10006 if (pSprite->field_4A <= 0) {
10007 //loc_190B9
10008 Data0 = tool_RandomGet() & 0x0F;
10009 ++Data0;
10010 pSprite->field_4A = Data0;
10011
10012 Data0 = tool_RandomGet() & 0x3F;
10013 if (Data0 == 0x2A)
10014 goto loc_1918C;
10015 }
10016
10017 HandleWeapon:;
10018 mTroop_Weapon_Grenade_Disabled = false;
10019 mTroop_Weapon_Bullet_Disabled = false;
10020 mTroop_Weapon_Rocket_Disabled = false;
10021
10022 if (pSprite->field_4F) {
10023 mTroop_Weapon_Rocket_Disabled = true;
10024 mTroop_Weapon_Bullet_Disabled = true;
10025 mTroop_Weapon_Grenade_Disabled = true;
10026 }
10027 else {
10028 //loc_19118
10029 if (pSprite == mSquad_Leader && mMouse_Button_LeftRight_Toggle) {
10030
10031 if (mSquad_CurrentWeapon[pSprite->field_32] == eWeapon_Rocket) {
10032 mTroop_Weapon_Grenade_Disabled = true;
10033 mTroop_Weapon_Bullet_Disabled = true;
10034 } else {
10035 if (mSquad_CurrentWeapon[pSprite->field_32] == eWeapon_Grenade) {
10036 mTroop_Weapon_Rocket_Disabled = true;
10037 mTroop_Weapon_Bullet_Disabled = true;
10038 }
10039 else
10040 goto loc_19198;
10041 }
10042 loc_1918C:;
10043 pSprite->field_4A = 1;
10044 goto loc_191BF;
10045 }
10046
10047 loc_19198:;
10048 mTroop_Weapon_Grenade_Disabled = true;
10049 mTroop_Weapon_Rocket_Disabled = true;
10050
10051 if(pSprite->field_46_mission_troop)
10052 Data0 = pSprite->field_46_mission_troop->field_6;
10053
10054 loc_191BF:;
10055 Sprite_Handle_Troop_Weapon(pSprite);
10056 }
10057 }
10058 else {
10059
10060 if (mSprite_Player_CheckWeapon) {
10061 goto HandleWeapon;
10062
10063 }
10064 }
10065
10066 loc_191C3:;
10067 if (pSprite->field_22 != eSprite_PersonType_Human)
10068 goto loc_1921E;
10069
10070 // seg004:047F
10071 eax = mSquad_WalkTargets[pSprite->field_32][pSprite->field_40].mY;
10072
10073 //seg004:04CC
10074 if (eax < 0) {
10075 loc_1921E:;
10076 if (mSprite_FaceWeaponTarget) {
10077
10078 if (pSprite->field_0 == pSprite->field_26 &&
10079 pSprite->field_4 == pSprite->field_28)
10080 goto loc_1931E;
10081 }
10082 }
10083 //loc_1925C
10084 // Just Fired a bullet or grenade?
10085 if (pSprite->field_54 != 2 && pSprite->field_54 != 1)
10086 goto loc_19338;
10087
10088
10089 // Just Fired bullet or grenade
10090 //loc_19274
10091 if (word_3AA1D != 2)
10092 goto loc_1931E;
10093
10094 mTmp_FrameNumber = pSprite->field_A;
10095 pSprite->field_5A = 0;
10096
10097 if (mSprite_FaceWeaponTarget)
10098 Sprite_Handle_Troop_Direct_TowardWeaponTarget(pSprite);
10099 else
10100 Sprite_Handle_Troop_Direct_TowardMouse(pSprite);
10101
10102 Data0 = pSprite->field_26;
10103 if (Data0 < 0)
10104 goto loc_1946D;
10105
10106 Data4 = pSprite->field_28;
10107 if (Data4 < 0)
10108 goto loc_1946D;
10109
10110 Sprite_XY_Store(pSprite);
10111
10112 if (Sprite_Direction_Between_Points(pSprite, Data0, Data4) >= 0) {
10113 Sprite_Handle_Player_Adjust_Movement_Speed(pSprite);
10114 Sprite_Draw_Row_Update(pSprite);
10115 }
10116
10117 if (pSprite->field_0 == pSprite->field_26) {
10118
10119 if (pSprite->field_4 == pSprite->field_28)
10120 Sprite_Next_WalkTarget_Set(pSprite);
10121 }
10122
10123 //loc_19314
10124 if (mSprite_Reached_Target == 0)
10125 return;
10126
10127 loc_1931E:;
10128
10129 if (pSprite->field_5A)
10130 goto loc_19403;
10131
10132 Sprite_Handle_Troop_Direct_TowardMouse(pSprite);
10133 Sprite_Handle_Troop_FrameUnk(pSprite);
10134 return;
10135
10136 loc_19338:;
10137 pSprite->field_43 = 0;
10138 mTmp_FrameNumber = pSprite->field_A;
10139 mSprite_Bumped_Into_SquadMember = 0;
10140
10141 sub_1FCF2(pSprite);
10142 Data0 = pSprite->field_26;
10143 if (Data0 < 0)
10144 goto loc_1946D;
10145 Data4 = pSprite->field_28;
10146 if (Data4 < 0)
10147 goto loc_1946D;
10148
10149 if (pSprite->field_44) {
10150 pSprite->field_44 -= 1;
10151 goto loc_193D6;
10152
10153 }
10154
10155 // Reached near target?
10156 //loc_19392
10157 if (Sprite_Direction_Between_Points(pSprite, Data0, Data4) >= 0)
10158 goto loc_193D6;
10159
10160 // Exactly on target?
10161 // Then move toward the next target
10162 if (pSprite->field_0 == pSprite->field_26) {
10163 if (pSprite->field_4 == pSprite->field_28)
10164 Sprite_Next_WalkTarget_Set(pSprite);
10165 }
10166 //loc_193D3
10167 goto loc_1946D;
10168
10169 loc_193D6:;
10170 Sprite_XY_Store(pSprite);
10171 sub_2A3D4(pSprite);
10172
10173 if (!pSprite->field_5A) {
10174 if (!pSprite->field_45)
10175 goto loc_19424;
10176
10177 pSprite->field_45 -= 1;
10178 return;
10179 }
10180
10181 loc_19403:;
10182 pSprite->field_5A = 0;
10183 sub_1FDE7(pSprite);
10184 return;
10185
10186 loc_19414:;
10187 pSprite->field_5A = 0;
10188 Sprite_Handle_Troop_Direct_TowardMouse(pSprite);
10189 return;
10190
10191 loc_19424:; // Soldier Walking
10192 Sprite_Draw_Row_Update(pSprite);
10193
10194 if (pSprite->field_0 == pSprite->field_26) {
10195 if (pSprite->field_4 == pSprite->field_28)
10196 Sprite_Next_WalkTarget_Set(pSprite);
10197 }
10198 //loc_19463
10199 if (mSprite_Reached_Target)
10200 goto loc_19414;
10201
10202 goto loc_1957A;
10203
10204 loc_1946D:;
10205 if (pSprite->field_5A)
10206 goto loc_19403;
10207
10208 if (!pSprite->field_45)
10209 goto loc_194A0;
10210
10211 pSprite->field_45 -= 1;
10212 goto loc_19414;
10213
10214 loc_19490:;
10215 pSprite->field_5A = 0;
10216 Sprite_Handle_Troop_Direct_TowardMouse(pSprite);
10217 return;
10218
10219 loc_194A0:;
10220 pSprite->field_43 = -1;
10221
10222 if (!word_3AA1D) {
10223 mDirectionMod = 0;
10224 Sprite_Handle_Troop_FrameUnk(pSprite);
10225 pSprite->field_A = 0;
10226 return;
10227 }
10228
10229 //loc_194CB
10230 if (mSquad_Selected == pSprite->field_32)
10231 goto loc_19490;
10232
10233 Sprite_Handle_Troop_Direct_TowardMouse(pSprite);
10234 return;
10235
10236 loc_1957A:;
10237 pSprite->field_3A = 0;
10238 Sprite_Handle_Troop_FrameUnk(pSprite);
10239
10240 }
10241
Sprite_Handle_Grenade(sSprite * pSprite)10242 void cFodder::Sprite_Handle_Grenade(sSprite* pSprite) {
10243 int16 Data0, Data4, Data8, DataC;
10244 sSprite* Data24;
10245 int16 a1;
10246 int32 Dataa4;
10247
10248 if (pSprite->field_38)
10249 goto loc_1992D;
10250
10251 if (!pSprite->field_12)
10252 goto loc_1992D;
10253
10254 if (!pSprite->field_56)
10255 goto loc_19701;
10256
10257 --pSprite->field_56;
10258 if (!pSprite->field_56) {
10259 // HACK: Disable grenade sound for cannon plus... it seems corrupted and causes a crash
10260 if (!mVersionCurrent->isCoverDisk())
10261 Sound_Play(pSprite, eSound_Effect_Grenade, 0x0F);
10262 }
10263
10264 Data24 = pSprite->field_46_sprite;
10265 pSprite->field_0 = Data24->field_0;
10266 pSprite->field_2 = Data24->field_2;
10267 pSprite->field_4 = Data24->field_4;
10268 pSprite->field_6 = Data24->field_6;
10269 pSprite->field_4 += 1;
10270 pSprite->field_0 += 3;
10271 pSprite->field_8 = 0x7C;
10272 pSprite->field_A = 0;
10273 return;
10274
10275 loc_19701:;
10276 pSprite->field_8 = 0x7D;
10277 Data0 = pSprite->field_26;
10278 Data4 = pSprite->field_28;
10279 Data8 = pSprite->field_0;
10280 DataC = pSprite->field_4;
10281
10282 Map_Get_Distance_BetweenPoints_Within_Window(Data0, Data4, Data8, DataC);
10283 if (Data0 <= 1)
10284 pSprite->field_36 = 0;
10285
10286 if (Data0 <= 4)
10287 pSprite->field_36 >>= 1;
10288
10289 if (pSprite->field_36) {
10290 pSprite->field_36 -= 1;
10291 Sprite_XY_Store(pSprite);
10292
10293 mTmp_FrameNumber = pSprite->field_A;
10294 Data0 = pSprite->field_26;
10295 Data4 = pSprite->field_28;
10296
10297 Sprite_Direction_Between_Points(pSprite, Data0, Data4);
10298 Sprite_Movement_Calculate(pSprite);
10299 Sprite_Handle_Grenade_Terrain_Check(pSprite);
10300
10301 (pSprite + 1)->field_10 = pSprite->field_10;
10302 }
10303
10304 //loc_197C5
10305 if (!pSprite->field_50) {
10306 if (pSprite->field_52) {
10307 pSprite->field_36 = 0;
10308 goto loc_198D3;
10309 }
10310 }
10311 //loc_197EA
10312 a1 = (int16)(((int64)pSprite->field_1A) >> 16);
10313
10314 if (a1 < 0)
10315 if (a1 < -8)
10316 pSprite->field_1A = (((int32)pSprite->field_1A & 0xFFFF) | -0x80000);
10317
10318 Dataa4 = pSprite->field_1A;
10319 Dataa4 -= 0x18000;
10320
10321 pSprite->field_1A = Dataa4;
10322 Dataa4 = pSprite->field_1A;
10323
10324 if (!pSprite->field_50)
10325 goto loc_19877;
10326
10327 if (Dataa4 >= 0)
10328 goto loc_19877;
10329
10330 if (pSprite->field_20 >= 2)
10331 goto loc_19877;
10332
10333 pSprite->field_1E = 0;
10334 pSprite->field_20 = 0;
10335
10336 loc_19855:;
10337
10338 Dataa4 = (Dataa4 >> 16) | ((Dataa4 & 0xFFFF) << 16);
10339 if (pSprite->field_52 >= 0x0A)
10340 goto loc_198D3;
10341
10342 pSprite->field_52 -= Dataa4;
10343 goto loc_198D3;
10344
10345 loc_19877:;
10346 pSprite->field_1E_Big += Dataa4;
10347
10348 if (pSprite->field_20 < 0) {
10349 pSprite->field_1E_Big = 0;
10350
10351 if (pSprite->field_50)
10352 goto loc_19855;
10353
10354 Dataa4 = (int64)pSprite->field_1A;
10355 Dataa4 = -Dataa4;
10356 Dataa4 >>= 1;
10357 pSprite->field_1A = Dataa4;
10358 }
10359
10360 loc_198D3:;
10361 if (!pSprite->field_36)
10362 pSprite->field_20 = 0;
10363
10364 Data4 = pSprite->field_20;
10365 Data4 >>= 4;
10366 if (Data4 > 3)
10367 Data4 = 3;
10368
10369 pSprite->field_A = Data4;
10370 (pSprite + 1)->field_A = Data4;
10371 pSprite->field_12 -= 1;
10372 return;
10373
10374 loc_1992D:;
10375
10376 if (pSprite->field_52 < 8) {
10377 pSprite->field_18 = eSprite_Explosion;
10378 Sprite_Projectile_Counters_Decrease(pSprite);
10379 Sprite_Destroy(pSprite + 1);
10380 return;
10381 }
10382 //loc_19957
10383 Sprite_Projectile_Counters_Decrease(pSprite);
10384 pSprite->field_0 = 0;
10385 pSprite->field_4 = 0;
10386
10387 Sprite_Destroy(pSprite);
10388 Sprite_Destroy(pSprite + 1);
10389 }
10390
Sprite_Projectile_Counters_Decrease(sSprite * pSprite)10391 void cFodder::Sprite_Projectile_Counters_Decrease(sSprite* pSprite) {
10392
10393 --mSprite_Projectile_Counters[pSprite->field_22];
10394 }
10395
Sprite_Handle_ShadowSmall(sSprite * pSprite)10396 void cFodder::Sprite_Handle_ShadowSmall(sSprite* pSprite) {
10397 sSprite* Data24 = pSprite - 1;
10398
10399 pSprite->field_0 = Data24->field_0;
10400 pSprite->field_4 = Data24->field_4;
10401 pSprite->field_52 = Data24->field_52;
10402
10403 }
10404
Sprite_Handle_Enemy(sSprite * pSprite)10405 void cFodder::Sprite_Handle_Enemy(sSprite* pSprite) {
10406
10407 if (Sprite_Handle_Soldier_Animation(pSprite))
10408 return;
10409
10410 if (pSprite->field_38)
10411 return;
10412
10413 mSprite_FaceWeaponTarget = 0;
10414 if (pSprite->field_44) {
10415 pSprite->field_44--;
10416 }
10417 else {
10418 sub_21CD1(pSprite);
10419 Sprite_Handle_Troop_Weapon(pSprite);
10420
10421 mTmp_FrameNumber = pSprite->field_A;
10422 int16 Data0 = pSprite->field_26;
10423 if (Data0 < 0)
10424 goto loc_19A89;
10425
10426 int16 Data4 = pSprite->field_28;
10427 if (Data4 < 0)
10428 goto loc_19A89;
10429
10430 if (Sprite_Direction_Between_Points(pSprite, Data0, Data4) < 0)
10431 goto loc_19A89;
10432 }
10433 //loc_19A5D
10434 Sprite_XY_Store(pSprite);
10435 sub_2A3D4(pSprite);
10436 sub_1FCF2(pSprite);
10437
10438 if (pSprite->field_45) {
10439 pSprite->field_45--;
10440 if (pSprite->field_45)
10441 return;
10442 }
10443 Sprite_Draw_Row_Update(pSprite);
10444 goto loc_19A96;
10445
10446 loc_19A89:;
10447 word_3ABB1 = 0;
10448 sub_1FDE7(pSprite);
10449 goto loc_19A9C;
10450
10451 loc_19A96:;
10452 word_3ABB1 = -1;
10453
10454 loc_19A9C:;
10455 pSprite->field_22 = eSprite_PersonType_AI;
10456 Sprite_Handle_Troop_FrameUnk(pSprite);
10457
10458 if (word_3ABB1)
10459 return;
10460 if (mSprite_FaceWeaponTarget)
10461 return;
10462
10463 pSprite->field_A = 1;
10464 }
10465
Sprite_Handle_Bullet(sSprite * pSprite)10466 void cFodder::Sprite_Handle_Bullet(sSprite* pSprite) {
10467 int16 Data8, DataC, Data0, Data4;
10468 int8 al;
10469
10470 pSprite->field_64 += 1;
10471
10472 if (!pSprite->field_2A)
10473 goto loc_19BA8;
10474
10475 Data0 = pSprite->field_1A_sprite->field_0;
10476 Data4 = pSprite->field_1A_sprite->field_4;
10477
10478 Data0 += pSprite->field_16;
10479 Data4 += pSprite->field_14;
10480 pSprite->field_0 = Data0;
10481 pSprite->field_4 = Data4;
10482
10483 pSprite->field_2A -= 1;
10484 if (pSprite->field_2A)
10485 return;
10486
10487 pSprite->field_8 = 0x7F;
10488 pSprite->field_A = 0;
10489
10490 if (pSprite->field_22 != eSprite_PersonType_Human)
10491 pSprite->field_A = 3;
10492
10493 Data0 = pSprite->field_1A_sprite->field_0;
10494 Data4 = pSprite->field_1A_sprite->field_4;
10495 Data0 += 7;
10496 Data4 += 5;
10497 pSprite->field_0 = Data0;
10498 pSprite->field_4 = Data4;
10499
10500 loc_19BA8:;
10501 if (pSprite->field_43)
10502 goto loc_19DCF;
10503
10504 if (!pSprite->field_12)
10505 goto loc_19DCF;
10506
10507 pSprite->field_12 -= 1;
10508 pSprite->field_3A += 1;
10509
10510 if (pSprite->field_44)
10511 goto loc_19D24;
10512
10513 Sprite_XY_Store(pSprite);
10514
10515 if (pSprite->field_59)
10516 goto loc_19C6B;
10517
10518 Data0 = pSprite->field_2E;
10519 Data4 = pSprite->field_30;
10520
10521 Sprite_Direction_Between_Points(pSprite, Data0, Data4);
10522
10523 Data0 = pSprite->field_50;
10524 if (Data0) {
10525 pSprite->field_10 += Data0;
10526 pSprite->field_10 &= 0x1FE;
10527 pSprite->field_59 = -1;
10528 }
10529 //loc_19C4D
10530
10531 if (pSprite->field_34 < 0) {
10532 pSprite->field_34 = pSprite->field_10;
10533 }
10534
10535 loc_19C6B:;
10536
10537 Sprite_Movement_Calculate(pSprite);
10538 if (mSprite_Bullet_Destroy)
10539 goto SpriteDestroy;
10540 pSprite->field_36 = pSprite->field_4A;
10541
10542 if (pSprite->field_59)
10543 goto loc_19D3C;
10544
10545 Data0 = pSprite->field_0;
10546 Data4 = pSprite->field_4;
10547 Data8 = pSprite->field_2E;
10548 DataC = pSprite->field_30;
10549
10550 Map_Get_Distance_BetweenPoints_Within_Window(Data0, Data4, Data8, DataC);
10551
10552 Data4 = pSprite->field_36;
10553 Data4 >>= 3;
10554
10555 if (Data0 > Data4)
10556 goto loc_19D3C;
10557
10558 pSprite->field_2C = eSprite_Draw_Second;
10559 pSprite->field_0 = pSprite->field_2E;
10560 pSprite->field_4 = pSprite->field_30;
10561 pSprite->field_44 = -1;
10562 goto loc_19D3C;
10563
10564 loc_19D24:;
10565 pSprite->field_2C = eSprite_Draw_First;
10566
10567 Sprite_Movement_Calculate(pSprite);
10568 if (mSprite_Bullet_Destroy)
10569 goto SpriteDestroy;
10570
10571 loc_19D3C:;
10572 if (pSprite->field_64 > 2) {
10573 Data0 = -9;
10574 Data4 = 0;
10575 if (Map_Terrain_Get_Type_And_Walkable(pSprite, Data0, Data4))
10576 goto loc_19DCF;
10577 }
10578
10579 if (!Sprite_Projectile_Collision_Check(pSprite))
10580 return;
10581
10582 if (mSprites_Found_Count == 1)
10583 goto loc_19DCF;
10584
10585 pSprite->field_43 = 1;
10586 pSprite->field_2C = eSprite_Draw_OnTop;
10587 pSprite->field_0 -= 4;
10588 if (pSprite->field_0 < 0)
10589 goto loc_19E50;
10590
10591 pSprite->field_4 -= 3;
10592 if (pSprite->field_4 < 0)
10593 goto loc_19E50;
10594
10595 pSprite->field_8 = 0x96;
10596 pSprite->field_A = 0;
10597 return;
10598
10599 loc_19DB0:;
10600 pSprite->field_12 = 0;
10601 pSprite->field_A += 1;
10602 if (pSprite->field_A >= 4)
10603 goto SpriteDestroy;
10604
10605 return;
10606
10607 loc_19DCF:;
10608 al = pSprite->field_43;
10609 if (al)
10610 goto loc_19E1C;
10611
10612 Sprite_Projectile_Collision_Check(pSprite);
10613 pSprite->field_43 = -1;
10614 pSprite->field_2C = eSprite_Draw_First;
10615 pSprite->field_0 -= 4;
10616 if (pSprite->field_0 < 0)
10617 goto loc_19E50;
10618
10619 pSprite->field_4 -= 3;
10620 if (pSprite->field_4 < 0)
10621 goto loc_19E50;
10622
10623 pSprite->field_A = 3;
10624 al = pSprite->field_43;
10625
10626 loc_19E1C:;
10627 if (al >= 0)
10628 goto loc_19DB0;
10629
10630 pSprite->field_12 = 0;
10631 pSprite->field_A += 1;
10632 if (pSprite->field_A < 8)
10633 return;
10634
10635 SpriteDestroy:;
10636
10637 mSprite_Projectile_Counters[2] -= 1;
10638 Sprite_Destroy(pSprite);
10639 return;
10640
10641 loc_19E50:;
10642 pSprite->field_0 = 0;
10643 pSprite->field_4 = 0x1000;
10644 goto SpriteDestroy;
10645 }
10646
Sprite_Handle_Helicopter(sSprite * pSprite)10647 void cFodder::Sprite_Handle_Helicopter(sSprite* pSprite) {
10648 word_3B4ED[0] = 0;
10649 int16 Data0 = tool_RandomGet() & 0x0E;
10650 int16 Data4, Data8, DataC, Data10, Data14, Data18, Data1C;
10651 sSprite* Data24 = 0, *Data2C = 0;
10652
10653 if (mVersionCurrent->isCoverDisk()) {
10654 static int FF = 0;
10655
10656 if (++FF == 100) {
10657 FF = 0;
10658 //TODO: Fix chopper
10659 Data0 = 0x01;
10660 }
10661 else
10662 Data0 = 0;
10663 }
10664 else
10665 Data0 = mSprite_Helicopter_Sounds[Data0 / 2];
10666
10667 if (pSprite->field_22 != eSprite_PersonType_Human) {
10668 if (pSprite->field_20 <= 1)
10669 goto loc_19EE5;
10670 }
10671 else {
10672
10673 // Just off the ground?
10674 if (pSprite->field_20 < 2) {
10675 if (pSprite != mSquad_CurrentVehicle)
10676 goto loc_19EE5;
10677 }
10678 }
10679
10680 word_3B4ED[0] = -1;
10681 Data4 = pSprite->field_20;
10682 if (Data4 < 0x10)
10683 Data4 = 0x10;
10684
10685 Sprite_Map_Sound_Play(Data0);
10686
10687 loc_19EE5:;
10688 pSprite->field_65 = -1;
10689
10690 if (pSprite->field_38 == eSprite_Anim_None)
10691 goto loc_1A149;
10692
10693 if (pSprite->field_18 == eSprite_Helicopter_Homing_Enemy2) {
10694
10695 if (mHelicopterCall_X >= 0) {
10696
10697 if (pSprite->field_75 != 0x71) {
10698 pSprite->field_75 = 0x71;
10699 pSprite->field_74 = static_cast<int8>(pSprite->field_A);
10700 }
10701
10702 pSprite->field_A += 1;
10703 pSprite->field_A &= 0x0F;
10704
10705 if (pSprite->field_A == pSprite->field_74) {
10706 pSprite->field_75 = 0;
10707 pSprite->field_38 = eSprite_Anim_None;
10708 }
10709
10710 Data24 = pSprite + 1;
10711
10712 Data24->field_8 = 0x8C;
10713 Data24->field_0 = pSprite->field_0;
10714 Data24->field_4 = pSprite->field_4 + 1;
10715 Data24->field_20 = pSprite->field_20 + 0x0E;
10716
10717 if (!word_3B4ED[0])
10718 if (!pSprite->field_1E && !pSprite->field_20)
10719 return;
10720
10721 if (pSprite->field_20 < 0x0C)
10722 if (mMission_EngineTicks & 1)
10723 return;
10724
10725 Data24->field_A += 1;
10726 Data24->field_A &= 3;
10727 return;
10728 }
10729 }
10730
10731 if (pSprite->field_26 != 0x7171) {
10732
10733 pSprite->field_26 = 0x7171;
10734 pSprite->field_1A = 0x10000;
10735
10736 Data0 = tool_RandomGet() & 0x0F;
10737 Data0 += 0x13;
10738
10739 pSprite->field_2A = Data0;
10740 }
10741
10742 dword_3B24B = -1;
10743
10744 Data2C = 0;
10745 Sprite_Create_Smoke(pSprite, Data2C);
10746 Sprite_Movement_Calculate(pSprite);
10747
10748 pSprite->field_1A = (((int64)pSprite->field_1A) + 0x2000);
10749 Data0 = ((int64)pSprite->field_1A) >> 16;
10750 pSprite->field_A += Data0;
10751 pSprite->field_A &= 0x0F;
10752 pSprite->field_2A -= 1;
10753 if (pSprite->field_2A >= 0) {
10754
10755 pSprite->field_1E_Big -= 0x18000;
10756 if (pSprite->field_1E_Big >= 0)
10757 goto loc_1A404;
10758
10759 pSprite->field_1E_Big = 0;
10760 }
10761
10762 pSprite->field_18 = eSprite_Explosion;
10763 pSprite->field_26 = 0x1F50;
10764 pSprite->field_28 = -9;
10765 (pSprite + 1)->field_18 = eSprite_Helicopter_PropCrash;
10766
10767 Data0 = tool_RandomGet() & 0x1FE;
10768 (pSprite + 1)->field_10 = Data0;
10769 (pSprite + 1)->field_36 = 0x60;
10770
10771 Sprite_Destroy(pSprite + 2);
10772
10773 if (pSprite->field_22 == eSprite_PersonType_Human)
10774 Sprites_HumanVehicles_Remove(pSprite);
10775
10776 if (mSprite_Helicopter_DestroyLight)
10777 Sprite_Destroy(pSprite + 3);
10778
10779 return;
10780
10781 loc_1A149:;
10782 pSprite->field_8 = 0x8B;
10783 if (pSprite->field_44)
10784 goto loc_1A217;
10785
10786 Data0 = pSprite->field_0;
10787 Data4 = pSprite->field_4;
10788 Data8 = pSprite->field_26;
10789 DataC = pSprite->field_28;
10790
10791 Map_Get_Distance_BetweenPoints_Within_Window(Data0, Data4, Data8, DataC);
10792 dword_3B24B = Data0;
10793
10794 if (Data0 >= 0x60)
10795 goto loc_1A217;
10796
10797 Data0 >>= 1;
10798
10799 if (Data0 > pSprite->field_36)
10800 goto loc_1A217;
10801
10802 if (pSprite->field_22 != eSprite_PersonType_Human) {
10803 pSprite->field_36 = Data0;
10804 if (!Data0) {
10805 Data8 = pSprite->field_0;
10806 DataC = pSprite->field_4;
10807
10808 if (Map_Terrain_Get_Moveable_Wrapper(mTiles_NotFlyable, Data8, DataC, Data10, Data14))
10809 goto loc_1A316;
10810
10811 Data8 = pSprite->field_0;
10812 Data8 -= 0x10;
10813 DataC = pSprite->field_4;
10814
10815 if (Map_Terrain_Get_Moveable_Wrapper(mTiles_NotFlyable, Data8, DataC, Data10, Data14))
10816 goto loc_1A316;
10817
10818 Data8 = pSprite->field_0;
10819 Data8 += 0x10;
10820 DataC = pSprite->field_4;
10821
10822 if (Map_Terrain_Get_Moveable_Wrapper(mTiles_NotFlyable, Data8, DataC, Data10, Data14))
10823 goto loc_1A316;
10824
10825 if (pSprite->field_20) {
10826 pSprite->field_1E_Big -= 0x8000;
10827 }
10828 goto loc_1A316;
10829 }
10830
10831 goto loc_1A316;
10832 }
10833
10834 pSprite->field_36 = Data0;
10835 if (!pSprite->field_6E)
10836 goto loc_1A316;
10837
10838 pSprite->field_1E_Big -= 0xC000;
10839
10840 if (pSprite->field_1E_Big < 0) {
10841 pSprite->field_1E_Big = 0;
10842 }
10843 Sprite_Handle_Helicopter_Terrain_Check(pSprite);
10844 goto loc_1A316;
10845
10846 loc_1A217:;
10847 if (pSprite->field_20 < 0x20) {
10848 pSprite->field_20++;
10849 if (pSprite->field_20 < 0x12)
10850 goto loc_1A316;
10851 }
10852 //loc_1A239
10853 if (pSprite->field_36 >= 0x30)
10854 goto loc_1A316;
10855
10856 pSprite->field_36 += 2;
10857 if (dword_3B24B >= 0x60)
10858 goto loc_1A316;
10859
10860 if (!pSprite->field_6E)
10861 goto loc_1A316;
10862
10863 pSprite->field_1E_Big -= 0xC000;
10864
10865 if (pSprite->field_1E_Big < 0) {
10866 pSprite->field_1E_Big = 0;
10867 }
10868 goto loc_1A316;
10869
10870 loc_1A316:;
10871 if (pSprite->field_26 >= 0 && pSprite->field_28 >= 0) {
10872
10873 if (pSprite->field_20)
10874 Sprite_Movement_Calculate(pSprite);
10875 }
10876
10877 if (pSprite->field_22 == eSprite_PersonType_Human && !pSprite->field_36 &&
10878 pSprite->field_20 >= 0x20) {
10879 Data0 = mMouseX + (mCameraX >> 16);
10880 Data0 -= 0x10;
10881
10882 Data4 = mMouseY + (mCameraY >> 16);
10883 Data4 += 0x20;
10884 pSprite->field_36 = 0x1E;
10885 sub_23E01(pSprite, Data0, Data4);
10886 pSprite->field_36 = 0;
10887
10888 Data8 = pSprite->field_3C;
10889 if (pSprite->field_22 != eSprite_PersonType_Human) {
10890 if (!pSprite->field_36)
10891 goto loc_1A404;
10892 }
10893 pSprite->field_A = Data8;
10894 }
10895 else {
10896
10897 word_3B2F7 = 0x3A;
10898 Data0 = pSprite->field_26;
10899 Data4 = pSprite->field_28;
10900 sub_22CD7(pSprite, Data0, Data4);
10901 }
10902
10903 loc_1A404:;
10904 Data24 = pSprite + 1;
10905 Data24->field_8 = 0x8C;
10906 Data24->field_0 = pSprite->field_0;
10907 Data24->field_4 = pSprite->field_4;
10908 Data24->field_4 += 1;
10909 Data0 = pSprite->field_20;
10910 Data0 += 0x0E;
10911 Data24->field_20 = Data0;
10912
10913 if (!word_3B4ED[0])
10914 if (!pSprite->field_1E_Big)
10915 goto loc_1A49C;
10916
10917 if (pSprite->field_20 < 0x0C)
10918 if (mMission_EngineTicks & 1)
10919 goto loc_1A49C;
10920
10921 Data24->field_A += 1;
10922 Data24->field_A &= 3;
10923
10924 loc_1A49C:;
10925 Data24++;
10926 Data24->field_8 = 0x8D;
10927
10928 Data0 = pSprite->field_20;
10929 Data0 >>= 4;
10930 if (Data0 > 2)
10931 Data0 = 2;
10932
10933 Data24->field_A = Data0;
10934 Data24->field_2C = eSprite_Draw_First;
10935
10936 Data0 = pSprite->field_20;
10937 Data0 >>= 1;
10938 Data4 = Data0;
10939 Data0 += 9;
10940
10941 Data0 += pSprite->field_0;
10942 Data24->field_0 = Data0;
10943 Data4 -= 1;
10944 Data4 += pSprite->field_4;
10945 Data24->field_4 = Data4;
10946
10947 if (pSprite->field_22 == eSprite_PersonType_Human) {
10948 if (pSprite->field_20) {
10949
10950 Data8 = pSprite->field_0;
10951 DataC = pSprite->field_0;
10952 DataC += 0x1E;
10953 Data10 = pSprite->field_4;
10954 Data10 -= 0x14;
10955 Data14 = pSprite->field_4;
10956 Data18 = pSprite->field_20;
10957 Data1C = Data18;
10958 Data1C += 0x0E;
10959
10960 Sprite_Under_Vehicle(pSprite, Data8, DataC, Data10, Data14, Data18, Data1C);
10961 }
10962 }
10963
10964 pSprite->field_22 = eSprite_PersonType_Human;
10965 }
10966
Sprite_Handle_Explosion(sSprite * pSprite)10967 void cFodder::Sprite_Handle_Explosion(sSprite* pSprite) {
10968 if (pSprite->field_8 == 0x7C) {
10969 Sprite_Destroy_Wrapper_2(pSprite);
10970 return;
10971 }
10972
10973 if (pSprite->field_8 == 0xC0 || pSprite->field_8 == 0x8E) {
10974 //loc_1A8D1
10975
10976 int16 X_Left = pSprite->field_0;
10977 X_Left += 8;
10978
10979 if (pSprite->field_26 == 0x5F5F)
10980 X_Left += pSprite->field_28;
10981
10982 int16 X_Right = pSprite->field_0;
10983 X_Right += 0x24;
10984
10985 int16 Y_Top = pSprite->field_4;
10986 Y_Top -= 0x20;
10987
10988 int16 Y_Bottom = pSprite->field_4;
10989 Y_Bottom -= 6;
10990
10991 const int16* Explosion_Area_PerFrame = mSprite_Explosion_Area_PerFrame;
10992 int16 Frame = pSprite->field_A;
10993
10994 if (pSprite->field_8 == 0xC0)
10995 Frame += 2;
10996 Frame -= 1;
10997
10998 if (Frame >= 0) {
10999
11000 do {
11001 X_Left -= *Explosion_Area_PerFrame;
11002 X_Right -= *(Explosion_Area_PerFrame + 1);
11003 Y_Top += *Explosion_Area_PerFrame;
11004
11005 ++Explosion_Area_PerFrame;
11006 Y_Bottom += *Explosion_Area_PerFrame;
11007 ++Explosion_Area_PerFrame;
11008
11009 } while (--Frame >= 0);
11010 }
11011 //loc_1A99D
11012 sSprite* Data24 = 0;
11013
11014 pSprite->field_62 = ~pSprite->field_62;
11015 if (pSprite->field_62 >= 0)
11016 Squad_Member_Sprite_Hit_In_Region(pSprite, X_Left, X_Right, Y_Top, Y_Bottom);
11017 else
11018 Sprite_Find_In_Region(pSprite, Data24, X_Left, X_Right, Y_Top, Y_Bottom);
11019
11020 pSprite->field_12 -= 1;
11021 if (pSprite->field_12 >= 0)
11022 return;
11023
11024 pSprite->field_12 = 1;
11025
11026 Explosion_Area_PerFrame = mSprite_Explosion_Area_PerFrame;
11027 int16 Data4 = pSprite->field_A;
11028 if (pSprite->field_8 == 0xC0)
11029 Data4 += 2;
11030
11031 //seg004:1CC9
11032 pSprite->field_0 -= Explosion_Area_PerFrame[Data4];
11033 pSprite->field_4 += Explosion_Area_PerFrame[Data4 + 1];
11034 pSprite->field_A += 1;
11035 if (pSprite->field_8 != 0xC0)
11036 goto loc_1AA63;
11037
11038 if (pSprite->field_A < 4)
11039 return;
11040
11041 Sprite_Destroy_Wrapper(pSprite);
11042 return;
11043
11044 loc_1AA63:;
11045 if (pSprite->field_20 && pSprite->field_A >= 2) {
11046 pSprite->field_8 = 0xC0;
11047 pSprite->field_A = 0;
11048 }
11049 if (pSprite->field_A >= 7)
11050 Sprite_Destroy_Wrapper(pSprite);
11051
11052 return;
11053 }
11054
11055 //loc_1AA9F
11056 if (pSprite->field_5C) {
11057 Sprite_Handle_Explosion_MapTiles(pSprite);
11058 int16 Data0 = tool_RandomGet() & 0x1FE;
11059 int16 Data18 = Data0;
11060 Sprite_Create_Sparks(pSprite, Data18);
11061 Data18 += 0x100;
11062 Data18 &= 0x1FE;
11063 Sprite_Create_Sparks(pSprite, Data18);
11064 }
11065 //loc_1AAFD
11066 pSprite->field_0 -= 6;
11067 if (pSprite->field_0 < 0) {
11068 Sprite_Destroy_Wrapper_At_TopLeft(pSprite);
11069 return;
11070 }
11071
11072 //loc_1AB0D
11073 pSprite->field_4 += 4;
11074 if (pSprite->field_4 < 0) {
11075 Sprite_Destroy_Wrapper_At_TopLeft(pSprite);
11076 return;
11077 }
11078
11079 int16 Data0 = pSprite->field_26;
11080 if (Data0 < 0) {
11081 Data0 &= 0x7FFF;
11082 pSprite->field_0 += Data0;
11083 if (pSprite->field_0 < 0) {
11084 Sprite_Destroy_Wrapper_At_TopLeft(pSprite);
11085 return;
11086 }
11087 pSprite->field_26 = 0;
11088 }
11089 //loc_1AB6F
11090 int16 Data4 = 5 + (mGame_InputTicks & 3);
11091
11092 Sound_Play(pSprite, Data4, 0x1E);
11093 pSprite->field_8 = 0x8E;
11094 pSprite->field_A = 0;
11095 pSprite->field_12 = 1;
11096 pSprite->field_52 = 0;
11097 pSprite->field_22 = eSprite_PersonType_None;
11098 pSprite->field_32 = -1;
11099 pSprite->field_2C = eSprite_Draw_First;
11100 }
11101
Sprite_Handle_Shrub(sSprite * pSprite)11102 void cFodder::Sprite_Handle_Shrub(sSprite* pSprite) {
11103 pSprite->field_8 = 0x8F;
11104 Sprite_Handle_Exploidable(pSprite);
11105 }
11106
Sprite_Handle_Tree(sSprite * pSprite)11107 void cFodder::Sprite_Handle_Tree(sSprite* pSprite) {
11108 pSprite->field_8 = 0x90;
11109 Sprite_Handle_Exploidable(pSprite);
11110 }
11111
Sprite_Handle_BuildingRoof(sSprite * pSprite)11112 void cFodder::Sprite_Handle_BuildingRoof(sSprite* pSprite) {
11113 pSprite->field_8 = 0x91;
11114 Sprite_Handle_Exploidable(pSprite);
11115 }
11116
Sprite_Handle_Snowman(sSprite * pSprite)11117 void cFodder::Sprite_Handle_Snowman(sSprite* pSprite) {
11118 pSprite->field_8 = 0x92;
11119 Sprite_Handle_Exploidable(pSprite);
11120 }
11121
Sprite_Handle_Shrub2(sSprite * pSprite)11122 void cFodder::Sprite_Handle_Shrub2(sSprite* pSprite) {
11123 pSprite->field_8 = 0x93;
11124 Sprite_Handle_Exploidable(pSprite);
11125 }
11126
Sprite_Handle_Waterfall(sSprite * pSprite)11127 void cFodder::Sprite_Handle_Waterfall(sSprite* pSprite) {
11128 pSprite->field_8 = 0x94;
11129 pSprite->field_2C = eSprite_Draw_First;
11130
11131 int16 Data0 = pSprite->field_12;
11132 Data0 ^= 1;
11133 Data0 &= 1;
11134 pSprite->field_12 = Data0;
11135
11136 if (Data0)
11137 return;
11138
11139 pSprite->field_A += 1;
11140 if (pSprite->field_A < 3)
11141 return;
11142
11143 pSprite->field_A = 0;
11144 }
11145
Sprite_Handle_Bird2_Left(sSprite * pSprite)11146 void cFodder::Sprite_Handle_Bird2_Left(sSprite* pSprite) {
11147
11148 pSprite->field_8 = 0x98;
11149 pSprite->field_2C = eSprite_Draw_OnTop;
11150 pSprite->field_12 += 1;
11151 pSprite->field_12 &= 1;
11152 if (!pSprite->field_12)
11153 pSprite->field_A ^= 1;
11154
11155 pSprite->field_0 -= 2;
11156 if (pSprite->field_0 < -64)
11157 pSprite->field_0 = 0x7D0;
11158 }
11159
Sprite_Handle_BuildingDoor(sSprite * pSprite)11160 void cFodder::Sprite_Handle_BuildingDoor(sSprite* pSprite) {
11161 int16 Data0, Data4;
11162 sSprite* Data2C = 0;
11163
11164 if (Sprite_Handle_BuildingDoor_Explode(pSprite))
11165 return;
11166
11167 if (mTroops_Enemy_Count >= mParams->mSpawnEnemyMax) {
11168 pSprite->field_8 = 0x99;
11169 return;
11170 }
11171
11172 //loc_1ACEC
11173 pSprite->field_2C = eSprite_Draw_First;
11174 if (pSprite->field_43 < 0)
11175 goto loc_1AD86;
11176
11177 pSprite->field_43 -= 1;
11178 if (pSprite->field_43 == 0x14 || pSprite->field_43 == 0x0A) {
11179
11180 Sprite_Create_Enemy(pSprite, Data2C);
11181 return;
11182 }
11183
11184 if (pSprite->field_43 >= 0) {
11185 pSprite->field_8 = 0x7C;
11186 return;
11187 }
11188
11189 pSprite->field_8 = 0x99;
11190 Sound_Play(pSprite, eSound_Effect_BuildingDoor2, 0x01);
11191 Data0 = tool_RandomGet() & 0x0F;
11192
11193 Data4 = 0x14 - mGame_Data.mGamePhase_Data.mSprite_Enemy_AggressionMax;
11194 if (Data4 < 0)
11195 Data4 = 0;
11196
11197 Data4 <<= 3;
11198
11199 Data4 += Data0;
11200 pSprite->field_12 = Data4;
11201
11202 loc_1AD86:;
11203 pSprite->field_12 -= 1;
11204 if (pSprite->field_12 >= 0)
11205 return;
11206
11207 Data0 = tool_RandomGet() & 0x0F;
11208 Data0 += 6;
11209 pSprite->field_43 = static_cast<int8>(Data0);
11210 pSprite->field_8 = 0x7C;
11211
11212 if (!Sprite_Create_Enemy(pSprite, Data2C))
11213 return;
11214
11215 pSprite->field_12 = -1;
11216 pSprite->field_43 = -1;
11217 }
11218
Sprite_Handle_Player_Rank(sSprite * pSprite)11219 void cFodder::Sprite_Handle_Player_Rank(sSprite* pSprite) {
11220 sSprite* Data24 = mSquad_Leader;
11221 int16 Data4, Data0;
11222
11223 if (mSquad_Selected < 0)
11224 goto loc_1AF63;
11225
11226 if (Data24 == INVALID_SPRITE_PTR)
11227 goto loc_1AF63;
11228
11229 if (!mPhase_Completed_Timer) {
11230 Data4 = mSquad_Selected;
11231
11232 if (mSquad_Walk_Target_Steps[Data4])
11233 goto loc_1AF63;
11234 }
11235
11236 // No rank for non human soldiers, or if they're sinking
11237 if (Data24->field_18 != eSprite_Player || Data24->field_5B)
11238 goto loc_1AE64;
11239
11240 if (!Data24->field_38)
11241 goto loc_1AE76;
11242
11243 if (Data24->field_38 >= eSprite_Anim_Slide1)
11244 goto loc_1AE76;
11245
11246 loc_1AE64:;
11247 sub_305D5(Data24);
11248 goto loc_1AF63;
11249
11250 loc_1AE76:;
11251
11252 Data0 = Data24->field_0;
11253 if (Data0 < 0)
11254 goto loc_1AF63;
11255
11256 Data0 += 3;
11257 Data4 = Data24->field_4;
11258
11259 pSprite->field_0 = Data0;
11260 pSprite->field_4 = Data4;
11261
11262 if (Data24->field_6E)
11263 goto loc_1AF63;
11264
11265 pSprite->field_8 = 0x95;
11266
11267 Data0 = Data24->field_46_mission_troop->mRank;
11268
11269 pSprite->field_A = Data0;
11270 Data0 = pSprite->field_3A;
11271 Data0 += pSprite->field_10;
11272
11273 if (!Data0)
11274 goto loc_1AF1F;
11275
11276 if (Data0 < 6)
11277 goto loc_1AF27;
11278
11279 loc_1AF1F:;
11280 pSprite->field_10 = -pSprite->field_10;
11281
11282 loc_1AF27:;
11283 Data0 = 0;
11284 pSprite->field_20 = 1;
11285 pSprite->field_3A = Data0;
11286
11287 Data0 += Data24->field_20;
11288 Data0 += 0x12;
11289 pSprite->field_20 = Data0;
11290 return;
11291
11292 loc_1AF63:;
11293 pSprite->field_8 = 0x7C;
11294 pSprite->field_A = 0;
11295 }
11296
Sprite_Handle_Player_Shadow(sSprite * pSprite)11297 void cFodder::Sprite_Handle_Player_Shadow(sSprite* pSprite) {
11298 sSprite* Data28 = pSprite->field_1A_sprite;
11299 int16 Data0;
11300
11301 if (Data28 != pSprite->field_6A_sprite)
11302 goto loc_1B06D;
11303
11304 Data0 = pSprite->field_62;
11305
11306 if (Data0 != Data28->field_18)
11307 goto loc_1B06D;
11308
11309 if (Data28->field_8 == 0x7C)
11310 goto loc_1B06D;
11311
11312 if (Data28->field_52)
11313 goto loc_1B06D;
11314
11315 pSprite->field_8 = 0x97;
11316 pSprite->field_A = 1;
11317 if (Data28->field_20 > 8)
11318 pSprite->field_A = 0;
11319
11320 pSprite->field_0 = Data28->field_0;
11321 pSprite->field_4 = Data28->field_4;
11322
11323 Data0 = Data28->field_20;
11324 Data0 >>= 2;
11325 pSprite->field_0 += Data0;
11326 pSprite->field_4 += Data0;
11327 pSprite->field_0 += 5;
11328 pSprite->field_4 -= 3;
11329
11330 if (Data28->field_8 == 0x7C)
11331 pSprite->field_8 = 0x7C;
11332 return;
11333
11334 loc_1B06D:;
11335 Data28->field_58 = 0;
11336 Sprite_Destroy_Wrapper(pSprite);
11337 }
11338
Sprite_Handle_BloodTrail(sSprite * pSprite)11339 void cFodder::Sprite_Handle_BloodTrail(sSprite* pSprite) {
11340
11341 if (pSprite->field_20)
11342 --pSprite->field_20;
11343
11344 --pSprite->field_12;
11345 if (pSprite->field_12 >= 0)
11346 return;
11347
11348 pSprite->field_12 = 1;
11349 pSprite->field_A += 1;
11350 if (pSprite->field_A < 4)
11351 return;
11352
11353 Sprite_Destroy_Wrapper(pSprite);
11354 }
11355
Sprite_Handle_GroundHole(sSprite * pSprite)11356 void cFodder::Sprite_Handle_GroundHole(sSprite* pSprite) {
11357 if (!mEnemy_BuildingCount)
11358 return;
11359
11360 if (pSprite->field_2A) {
11361 //loc_1B194
11362 sSprite* Data2C = 0;
11363
11364 if (!Sprite_Create_Enemy(pSprite, Data2C)) {
11365 Data2C->field_0 += 6;
11366 Data2C->field_4 -= 5;
11367 Data2C->field_52 = 0x0C;
11368 }
11369
11370 pSprite->field_2A = 0;
11371 return;
11372 }
11373
11374 pSprite->field_2C = eSprite_Draw_First;
11375 if (pSprite->field_43 < 0) {
11376 //loc_1B161
11377 pSprite->field_12 -= 1;
11378 if (pSprite->field_12 >= 0)
11379 return;
11380
11381 int16 Data0 = tool_RandomGet() & 0x0F;
11382 Data0 += 6;
11383 pSprite->field_43 = static_cast<int8>(Data0);
11384 pSprite->field_2A = 0;
11385 return;
11386 }
11387
11388 pSprite->field_43 -= 1;
11389 if (pSprite->field_43 != 0x14 && pSprite->field_43 != 0x0A) {
11390
11391 if (pSprite->field_43 >= 0)
11392 return;
11393 }
11394
11395 //loc_1B11A
11396 pSprite->field_2A = -1;
11397 pSprite->field_A = 0;
11398
11399 int16 Data0 = tool_RandomGet() & 0xFF;
11400 int16 Data4 = 0x64;
11401 Data4 -= mGame_Data.mGamePhase_Data.mSprite_Enemy_AggressionAverage;
11402 Data0 += 0x0A;
11403 Data4 += mGame_Data.mGamePhase_Data.mSprite_Enemy_AggressionAverage;
11404
11405 pSprite->field_12 = Data0;
11406 return;
11407 }
11408
Sprite_Handle_BuildingDoor2(sSprite * pSprite)11409 void cFodder::Sprite_Handle_BuildingDoor2(sSprite* pSprite) {
11410 int16 Data0, Data4;
11411 sSprite* Data2C = 0;
11412
11413 if (sub_222A3(pSprite))
11414 return;
11415
11416 if (mTroops_Enemy_Count >= mParams->mSpawnEnemyMax) {
11417 pSprite->field_8 = 0x9B;
11418 return;
11419 }
11420
11421 pSprite->field_2C = eSprite_Draw_First;
11422 if (pSprite->field_43 < 0)
11423 goto loc_1B285;
11424
11425 pSprite->field_43 -= 1;
11426 if (pSprite->field_43 == 0x14)
11427 goto loc_1B2B6;
11428
11429 if (pSprite->field_43 == 0x0A)
11430 goto loc_1B2B6;
11431
11432 if (pSprite->field_43 >= 0) {
11433 pSprite->field_8 = 0x7C;
11434 return;
11435 }
11436
11437 pSprite->field_8 = 0x9B;
11438
11439 Sound_Play(pSprite, eSound_Effect_BuildingDoor2, 1);
11440 Data0 = tool_RandomGet() & 0x0F;
11441 Data4 = 0x14;
11442
11443 Data4 -= mGame_Data.mGamePhase_Data.mSprite_Enemy_AggressionMax;
11444 if (Data4 < 0)
11445 Data0 = 0;
11446
11447 Data4 <<= 3;
11448 Data4 += Data0;
11449 pSprite->field_12 = Data4;
11450
11451 loc_1B285:;
11452 pSprite->field_12 -= 1;
11453 if (pSprite->field_12 >= 0)
11454 return;
11455
11456 Data0 = tool_RandomGet() & 0x0F;
11457 Data0 += 6;
11458 pSprite->field_43 = static_cast<int8>(Data0);
11459 pSprite->field_8 = 0x7C;
11460
11461 loc_1B2B6:;
11462
11463 if (!Sprite_Create_Enemy(pSprite, Data2C)) {
11464 Data2C->field_4 -= 4;
11465 return;
11466 }
11467
11468 pSprite->field_12 = 0;
11469 pSprite->field_43 = -1;
11470 }
11471
Sprite_Handle_Floating_Dead_Soldier(sSprite * pSprite)11472 void cFodder::Sprite_Handle_Floating_Dead_Soldier(sSprite* pSprite) {
11473 int16 Data0, Data4;
11474
11475 pSprite->field_8 = 0x9E;
11476
11477 if (!pSprite->field_12) {
11478 pSprite->field_12 = 0x10;
11479 pSprite->field_10 = 0x100;
11480 }
11481
11482 if (pSprite->field_10 <= 0x100)
11483 goto loc_1B35A;
11484
11485 if (pSprite->field_12 == 0x10)
11486 goto loc_1B350;
11487
11488 pSprite->field_12 = 0x10;
11489 goto loc_1B35A;
11490
11491 loc_1B350:;
11492 pSprite->field_12 = -16;
11493
11494 loc_1B35A:;
11495
11496 Sprite_XY_Store(pSprite);
11497 Sprite_Movement_Calculate(pSprite);
11498 Data0 = -3;
11499 Data4 = 8;
11500 Map_Terrain_Get_Type_And_Walkable(pSprite, Data0, Data4);
11501 if (Data4 < eTerrainFeature_QuickSand || Data4 > eTerrainFeature_Water) {
11502 pSprite->field_0 = mStoredSpriteX & 0xFFFF;
11503 pSprite->field_4 = mStoredSpriteY & 0xFFFF;
11504 pSprite->field_36 = 0;
11505 Data0 = pSprite->field_12;
11506
11507 pSprite->field_10 += Data0;
11508 pSprite->field_10 &= 0x1FE;
11509 }
11510
11511 //loc_1B3CA
11512 if (pSprite->field_36 < 4)
11513 pSprite->field_36++;
11514
11515 pSprite->field_2C = eSprite_Draw_Second;
11516 }
11517
Sprite_Handle_Text_Complete(sSprite * pSprite)11518 void cFodder::Sprite_Handle_Text_Complete(sSprite* pSprite) {
11519 pSprite->field_0 = mMapTile_TargetX >> 16;
11520 pSprite->field_0 += (getCameraWidth() / 2) - 65;
11521 pSprite->field_4 -= 0x20;
11522
11523 int16 Data0 = mMapTile_TargetY >> 16;
11524 Data0 += getCameraHeight() / 2 + 7;
11525
11526 if (Data0 < pSprite->field_4)
11527 return;
11528
11529 pSprite->field_4 = Data0;
11530 }
11531
Sprite_Handle_Text_Mission(sSprite * pSprite)11532 void cFodder::Sprite_Handle_Text_Mission(sSprite* pSprite) {
11533 pSprite->field_0 = mMapTile_TargetX >> 16;
11534 pSprite->field_0 += (getCameraWidth() / 2) - 50;
11535 pSprite->field_4 -= 0x20;
11536
11537 int16 Data0 = mMapTile_TargetY >> 16;
11538 Data0 += (getCameraHeight() / 2 - 13);
11539
11540 if (Data0 < pSprite->field_4)
11541 return;
11542
11543 pSprite->field_4 = Data0;
11544 }
11545
Sprite_Handle_Text_Phase(sSprite * pSprite)11546 void cFodder::Sprite_Handle_Text_Phase(sSprite* pSprite) {
11547 pSprite->field_0 = mMapTile_TargetX >> 16;
11548 pSprite->field_0 += (getCameraWidth() / 2) - 41;
11549
11550 pSprite->field_4 -= 0x20;
11551
11552 int16 Data0 = mMapTile_TargetY >> 16;
11553 Data0 += (getCameraHeight() / 2 - 13);
11554
11555 if (Data0 < pSprite->field_4)
11556 return;
11557
11558 pSprite->field_4 = Data0;
11559 }
11560
Sprite_Handle_Vehicle(sSprite * pSprite)11561 void cFodder::Sprite_Handle_Vehicle(sSprite* pSprite) {
11562 int16 Data0 = 2;
11563 int16 Data4 = pSprite->field_36;
11564 int16 Data8, DataC;
11565
11566 if (!Data4) {
11567 if (pSprite->field_22 == eSprite_PersonType_Human) {
11568
11569 if (pSprite != mSquad_CurrentVehicle)
11570 goto loc_1B523;
11571 }
11572 }
11573
11574 Data4 += 0x10;
11575 if (Data4 > 0x40)
11576 Data4 = 0x40;
11577 Data0 = Data4;
11578
11579 Data0 >>= 4;
11580 if (Data0 > 3)
11581 Data0 = 3;
11582 Data0 += 0x38;
11583
11584 Sprite_Map_Sound_Play(Data0);
11585
11586 loc_1B523:;
11587 pSprite->field_65 = -1;
11588 if (Sprite_Animation_SlideOrDie(pSprite))
11589 return;
11590
11591 pSprite->field_8 = 0xA5;
11592 sub_22C87(pSprite);
11593 if (pSprite->field_20 < 3) {
11594 word_3B2F7 = 0x48;
11595 Data0 = pSprite->field_26;
11596 Data4 = pSprite->field_28;
11597
11598 sub_22CD7(pSprite, Data0, Data4);
11599 }
11600
11601 Data0 = pSprite->field_26;
11602 Data4 = pSprite->field_28;
11603 Data8 = pSprite->field_0;
11604 DataC = pSprite->field_4;
11605
11606 Map_Get_Distance_BetweenPoints_Within_Window(Data0, Data4, Data8, DataC);
11607 if (Data0 >= 0x1E)
11608 goto loc_1B5D2;
11609
11610 if (Data0 >= pSprite->field_36)
11611 goto loc_1B655;
11612
11613 pSprite->field_36 = Data0;
11614 goto loc_1B655;
11615
11616 loc_1B5D2:;
11617
11618 if (!pSprite->field_52) {
11619 dword_3B24B = -1;
11620 sSprite* Data2C = 0;
11621
11622 if (!Sprite_Create_Smoke(pSprite, Data2C))
11623 Data2C->field_2C = eSprite_Draw_First;
11624 }
11625
11626 if (!pSprite->field_36) {
11627 if (mDirectionMod)
11628 goto loc_1B655;
11629 }
11630
11631 // Sinking? No, Then we can speed up
11632 if (pSprite->field_52 < 4) {
11633
11634 pSprite->field_36 += 3;
11635
11636 // This vehicle only moves at a single speed
11637 if (pSprite->field_18 == eSprite_Vehicle_Unk_Enemy) {
11638
11639 pSprite->field_36 = 0x14;
11640
11641 }
11642 else {
11643 if (pSprite->field_36 >= 0x32)
11644 pSprite->field_36 = 0x32;
11645 }
11646
11647 }
11648 loc_1B655:;
11649 // VEhicle in the air, increase speed
11650 if (pSprite->field_20 > 4)
11651 pSprite->field_36 += 0x1C;
11652
11653 Sprite_XY_Store(pSprite);
11654 Sprite_Movement_Calculate(pSprite);
11655
11656 if (pSprite->field_20 < 9) {
11657 Sprite_Handle_Vehicle_Terrain_Check(pSprite);
11658
11659 if (pSprite->field_20 <= 4)
11660 pSprite->field_20 = 0;
11661 }
11662 else {
11663 pSprite->field_36 += 0x40;
11664 }
11665
11666 sub_243E9(pSprite);
11667
11668 Data8 = pSprite->field_0;
11669 DataC = pSprite->field_0;
11670 DataC += 0x1C;
11671 int16 Data10 = pSprite->field_4;
11672 Data10 -= 0x10;
11673 int16 Data14 = pSprite->field_4;
11674
11675 int16 Data18 = pSprite->field_20;
11676 int16 Data1C = Data18;
11677 Data1C += 0x0E;
11678 Sprite_Under_Vehicle(pSprite, Data8, DataC, Data10, Data14, Data18, Data1C);
11679
11680 }
11681
Sprite_Handle_Rocket(sSprite * pSprite)11682 void cFodder::Sprite_Handle_Rocket(sSprite* pSprite) {
11683 sSprite* Data24 = 0;
11684
11685 if (pSprite->field_56) {
11686
11687 pSprite->field_56 -= 1;
11688 if (!pSprite->field_56) {
11689 if (mVersionCurrent->isCoverDisk())
11690 Sound_Play(pSprite, 0x10, 0x0F);
11691 else
11692 Sound_Play(pSprite, eSound_Effect_Rocket, 0x0F);
11693
11694 }
11695 Data24 = pSprite->field_46_sprite;
11696 pSprite->field_0 = Data24->field_0;
11697 pSprite->field_2 = Data24->field_2;
11698 pSprite->field_4 = Data24->field_4;
11699 pSprite->field_6 = Data24->field_6;
11700
11701 pSprite->field_4 += 1;
11702 pSprite->field_0 += 3;
11703 pSprite->field_8 = 0x7C;
11704 pSprite->field_A = 0;
11705 return;
11706 }
11707
11708 pSprite->field_8 = 0xA3;
11709 int16 Data0 = pSprite->field_26;
11710 int16 Data4 = pSprite->field_28;
11711 int16 Data8 = pSprite->field_0;
11712 int16 DataC = pSprite->field_4;
11713
11714 Map_Get_Distance_BetweenPoints_Within_Window(Data0, Data4, Data8, DataC);
11715 if (Data0 <= 7)
11716 goto loc_1B843;
11717
11718 Data0 = pSprite->field_26;
11719 Data4 = pSprite->field_28;
11720 Sprite_Direction_Between_Points(pSprite, Data0, Data4);
11721 Sprite_Movement_Calculate(pSprite);
11722
11723 Data0 = pSprite->field_10;
11724 Data0 >>= 5;
11725 Data0 -= 1;
11726 Data0 ^= 0x0F;
11727 Data0 &= 0x0F;
11728 pSprite->field_A = Data0;
11729
11730 Data0 = -9;
11731 Data4 = 2;
11732
11733 if (!Map_Terrain_Get_Type_And_Walkable(pSprite, Data0, Data4))
11734 return;
11735
11736 loc_1B843:;
11737 // Hit Target
11738 pSprite->field_18 = eSprite_Explosion;
11739 Sprite_Projectile_HitTarget(pSprite);
11740 Data24 = pSprite + 1;
11741
11742 Sprite_Destroy(Data24);
11743 }
11744
Sprite_Handle_Text_GameOver(sSprite * pSprite)11745 void cFodder::Sprite_Handle_Text_GameOver(sSprite* pSprite) {
11746
11747 pSprite->field_0 = mMapTile_TargetX >> 16;
11748 pSprite->field_0 += 0x5B;
11749 pSprite->field_4 -= 0x20;
11750
11751 int16 Data0 = mMapTile_TargetY >> 16;
11752 Data0 += 0x77;
11753
11754 if (Data0 < pSprite->field_4)
11755 return;
11756
11757 pSprite->field_4 = Data0;
11758 }
11759
Sprite_Handle_Shadow(sSprite * pSprite)11760 void cFodder::Sprite_Handle_Shadow(sSprite* pSprite) {
11761 sSprite* Data28 = pSprite->field_1A_sprite;
11762
11763 if (Data28->field_18 == eSprite_Explosion) {
11764 Sprite_Destroy_Wrapper(pSprite);
11765 return;
11766 }
11767
11768 if (Data28->field_52) {
11769 Sprite_Destroy_Wrapper(pSprite);
11770 return;
11771 }
11772
11773 pSprite->field_8 = 0x8D;
11774 int16 Data0 = Data28->field_20;
11775
11776 Data0 >>= 3;
11777 Data0 += 1;
11778 if (Data0 > 2)
11779 Data0 = 1;
11780
11781 pSprite->field_A = Data0;
11782 pSprite->field_0 = Data28->field_0;
11783 pSprite->field_4 = Data28->field_4;
11784 Data0 = Data28->field_20;
11785 Data0 >>= 2;
11786 pSprite->field_0 += Data0;
11787 pSprite->field_4 += Data0;
11788 pSprite->field_0 += 5;
11789 pSprite->field_4 -= 3;
11790
11791 if (Data28->field_8 == 0x7C)
11792 pSprite->field_8 = 0x7C;
11793 }
11794
Sprite_Handle_Enemy_Rocket(sSprite * pSprite)11795 void cFodder::Sprite_Handle_Enemy_Rocket(sSprite* pSprite) {
11796
11797 if (Sprite_Handle_Soldier_Animation(pSprite))
11798 return;
11799
11800 if (pSprite->field_38 != eSprite_Anim_None)
11801 return;
11802
11803 mSprite_FaceWeaponTarget = 0;
11804 pSprite->field_43 = -1;
11805
11806 sub_21CD1(pSprite);
11807
11808 mTroop_Weapon_Bullet_Disabled = true;
11809 mTroop_Weapon_Grenade_Disabled = true;
11810 mTroop_Weapon_Rocket_Disabled = true;
11811
11812 Sprite_Handle_Troop_Weapon(pSprite);
11813 sub_2A3D4(pSprite);
11814
11815 mSprite_FaceWeaponTarget = 0;
11816 word_3ABB1 = 0;
11817
11818 pSprite->field_54 = 3;
11819 pSprite->field_5A = -1;
11820 pSprite->field_55 = 0;
11821 pSprite->field_A = 0;
11822
11823 sub_1FDE7(pSprite);
11824 pSprite->field_A = 2;
11825 }
11826
Sprite_Handle_GrenadeBox(sSprite * pSprite)11827 void cFodder::Sprite_Handle_GrenadeBox(sSprite* pSprite) {
11828
11829 if (pSprite->field_38) {
11830 pSprite->field_18 = eSprite_Explosion;
11831 return;
11832 }
11833
11834 int16 Data0 = 0;
11835 pSprite->field_8 = 0xC2;
11836 if (Map_Get_Distance_Between_Sprite_And_Squadleader(pSprite, Data0))
11837 return;
11838
11839 mGUI_RefreshSquadGrenades[mSquad_Selected] = -1;
11840 mGUI_RefreshSquadRockets[mSquad_Selected] = -1;
11841 mSquad_Grenades[mSquad_Selected] += 4;
11842
11843 Sprite_Destroy_Wrapper(pSprite);
11844 }
11845
Sprite_Handle_RocketBox(sSprite * pSprite)11846 void cFodder::Sprite_Handle_RocketBox(sSprite* pSprite) {
11847 if (pSprite->field_38) {
11848 pSprite->field_18 = eSprite_Explosion;
11849 return;
11850 }
11851
11852 int16 Data0 = 0;
11853 pSprite->field_8 = 0xC3;
11854 if (Map_Get_Distance_Between_Sprite_And_Squadleader(pSprite, Data0))
11855 return;
11856
11857 mGUI_RefreshSquadRockets[mSquad_Selected] = -1;
11858 mGUI_RefreshSquadGrenades[mSquad_Selected] = -1;
11859 mSquad_Rockets[mSquad_Selected] += 4;
11860
11861 // Plus uses homing missiles
11862 if (mVersionCurrent->isCoverDisk())
11863 mSquad_Leader->field_75 |= eSprite_Flag_HomingMissiles;
11864
11865 Sprite_Destroy_Wrapper(pSprite);
11866 }
11867
Sprite_Handle_Building_Explosion(sSprite * pSprite)11868 void cFodder::Sprite_Handle_Building_Explosion(sSprite* pSprite) {
11869 int16 Data0, Data4, Data6, Data8, DataC, Data10, Data14;
11870 const int16* Data2C = mSprite_Explosion_Area_PerFrame;
11871 sSprite* Data24 = 0;
11872
11873 if (pSprite->field_8 == 0x7C) {
11874 Sprite_Destroy_Wrapper_2(pSprite);
11875 return;
11876 }
11877
11878 pSprite->field_62 = ~pSprite->field_62;
11879 if (pSprite->field_62 < 0)
11880 goto loc_1BC07;
11881
11882
11883 Data8 = pSprite->field_0;
11884 Data8 += 8;
11885 if (pSprite->field_26 == 0x5F5F)
11886 Data8 += pSprite->field_28;
11887
11888 DataC = pSprite->field_0 + 0x24;
11889
11890 Data10 = pSprite->field_4 - 0x20;
11891 Data14 = pSprite->field_4 - 6;
11892
11893 Data0 = pSprite->field_A;
11894
11895 if (pSprite->field_8 == 0xC0)
11896 Data0 += 2;
11897
11898 Data0 -= 1;
11899
11900 for (; Data0 >= 0; --Data0) {
11901 Data8 -= *Data2C;
11902 DataC -= *Data2C++;
11903 Data10 += *Data2C;
11904 Data14 += *Data2C++;
11905 }
11906
11907 Squad_Member_Sprite_Hit_In_Region(pSprite, Data8, DataC, Data10, Data14);
11908 goto loc_1BC48;
11909
11910 loc_1BC07:;
11911 Data8 = pSprite->field_0;
11912 DataC = pSprite->field_0 + 0x1E;
11913 Data10 = pSprite->field_4 - 30;
11914 Data14 = pSprite->field_4;
11915
11916 Sprite_Find_In_Region(pSprite, Data24, Data8, DataC, Data10, Data14);
11917 loc_1BC48:;
11918
11919 Data2C = mSprite_Explosion_Area_PerFrame;
11920 Data4 = pSprite->field_A;
11921 if (pSprite->field_8 == 0xC0)
11922 Data4 += 2;
11923
11924 Data4 <<= 1;
11925 Data2C += Data4;
11926
11927 Data4 = *(Data2C + 1);
11928 Data6 = *Data2C;
11929
11930 pSprite->field_0 -= Data4;
11931 pSprite->field_4 += Data6;
11932
11933 pSprite->field_A += 1;
11934 if (pSprite->field_8 == 0xC0) {
11935 if (pSprite->field_A < 4)
11936 return;
11937
11938 Sprite_Destroy_Wrapper(pSprite);
11939 return;
11940 }
11941
11942 if (!pSprite->field_20 || pSprite->field_A < 2)
11943 goto loc_1BD06;
11944
11945 pSprite->field_8 = 0xC0;
11946 pSprite->field_A = 0;
11947 loc_1BD06:;
11948
11949 if (pSprite->field_A < 3)
11950 return;
11951
11952 Sprite_Destroy_Wrapper(pSprite);
11953 }
11954
Sprite_Handle_Helicopter_Grenade_Enemy(sSprite * pSprite)11955 void cFodder::Sprite_Handle_Helicopter_Grenade_Enemy(sSprite* pSprite) {
11956
11957 pSprite->field_6F = eVehicle_Helicopter_Grenade;
11958 Sprite_Handle_Helicopter_Enemy(pSprite);
11959 }
11960
Sprite_Handle_Flashing_Light(sSprite * pSprite)11961 void cFodder::Sprite_Handle_Flashing_Light(sSprite* pSprite) {
11962
11963 pSprite->field_2C = eSprite_Draw_Second;
11964 pSprite->field_8 = 0xC4;
11965
11966 pSprite->field_43++;
11967 pSprite->field_43 &= 1;
11968 if (!pSprite->field_43) {
11969 pSprite->field_A++;
11970 pSprite->field_A &= 3;
11971 }
11972
11973 pSprite->field_4 += 0x18;
11974 pSprite->field_20 += 0x18;
11975 }
11976
Sprite_Handle_Helicopter_Grenade2_Enemy(sSprite * pSprite)11977 void cFodder::Sprite_Handle_Helicopter_Grenade2_Enemy(sSprite* pSprite) {
11978
11979 pSprite->field_6F = eVehicle_Helicopter;
11980 Sprite_Handle_Helicopter_Enemy(pSprite);
11981 }
11982
Sprite_Handle_Helicopter_Missile_Enemy(sSprite * pSprite)11983 void cFodder::Sprite_Handle_Helicopter_Missile_Enemy(sSprite* pSprite) {
11984
11985 pSprite->field_6F = eVehicle_Helicopter_Missile;
11986 Sprite_Handle_Helicopter_Enemy(pSprite);
11987 }
11988
Sprite_Handle_Helicopter_Homing_Enemy(sSprite * pSprite)11989 void cFodder::Sprite_Handle_Helicopter_Homing_Enemy(sSprite* pSprite) {
11990
11991 pSprite->field_6F = eVehicle_Helicopter_Homing;
11992 Sprite_Handle_Helicopter_Enemy(pSprite);
11993 }
11994
Sprite_Handle_Missile(sSprite * pSprite)11995 void cFodder::Sprite_Handle_Missile(sSprite* pSprite) {
11996
11997 dword_3B24B = -1;
11998 Sprite_Create_FireTrail(pSprite);
11999
12000 pSprite->field_8 = 0xA3;
12001 int16 Data0 = pSprite->field_26;
12002 int16 Data4 = pSprite->field_28;
12003 int16 Data8 = pSprite->field_0;
12004 int16 DataC = pSprite->field_4;
12005 int16 Data10 = 0x10;
12006
12007 Map_Get_Distance_BetweenPoints(Data0, Data4, Data8, Data10, DataC);
12008 if (Data0 <= 7)
12009 goto loc_1BECD;
12010
12011 if (pSprite->field_20 > 4) {
12012 pSprite->field_1E_Big -= 0xA000;
12013 }
12014
12015 Data0 = pSprite->field_26;
12016 Data4 = pSprite->field_28;
12017
12018 Sprite_Direction_Between_Points(pSprite, Data0, Data4);
12019 Sprite_Movement_Calculate(pSprite);
12020
12021 if (mSprite_Bullet_Destroy)
12022 goto loc_1BECD;
12023
12024 Data0 = pSprite->field_10;
12025
12026 Data0 >>= 5;
12027 Data0 -= 1;
12028 Data0 ^= 0x0F;
12029 Data0 &= 0x0F;
12030 pSprite->field_A = Data0;
12031
12032 if (pSprite->field_36 < 0x60)
12033 pSprite->field_36 += pSprite->field_3A;
12034
12035 Data0 = mMission_EngineTicks;
12036 Data0 &= 3;
12037
12038 if (!Data0)
12039 pSprite->field_3A <<= 1;
12040
12041 if (!pSprite->field_32)
12042 return;
12043
12044 Data0 = -9;
12045 Data4 = 2;
12046 if (!Map_Terrain_Get_Type_And_Walkable(pSprite, Data0, Data4))
12047 return;
12048
12049 loc_1BECD:;
12050
12051 pSprite->field_18 = eSprite_Explosion2;
12052 pSprite->field_4 -= 4;
12053 Sprite_Projectile_HitTarget(pSprite);
12054
12055 Sprite_Destroy(pSprite + 1);
12056 }
12057
Sprite_Handle_MissileHoming(sSprite * pSprite)12058 void cFodder::Sprite_Handle_MissileHoming(sSprite* pSprite) {
12059 int16 Data0, Data4, Data8, DataC;
12060 sSprite* Data34 = 0;
12061
12062 if (pSprite->field_38)
12063 goto MissileExplode;
12064
12065 dword_3B24B = -1;
12066 Sprite_Create_FireTrail(pSprite);
12067
12068 pSprite->field_8 = 0xA3;
12069 Data34 = pSprite->field_1A_sprite;
12070
12071 if (!Data34 || Data34->field_0 == -32768) {
12072 pSprite->field_36 += 2;
12073 pSprite->field_20 -= 2;
12074 if (pSprite->field_20 >= 0) {
12075 Sprite_Movement_Calculate(pSprite);
12076 return;
12077 }
12078
12079 pSprite->field_20 = 0;
12080 goto MissileExplode;
12081 }
12082
12083 Data0 = Data34->field_0 + 8;
12084 Data4 = Data34->field_4 + 8;
12085 Data8 = pSprite->field_0;
12086 DataC = pSprite->field_4;
12087 Map_Get_Distance_BetweenPoints_Within_Window(Data0, Data4, Data8, DataC);
12088
12089 Data4 = pSprite->field_36 >> 4;
12090 Data4 += 1;
12091
12092 if (Data0 <= Data4)
12093 goto MissileExplode;
12094
12095 if (Data34->field_20 <= 0x10) {
12096
12097 // Distance to target > 0x30?
12098 if (Data0 > 0x30) {
12099 Data0 = pSprite->field_0;
12100 Data4 = pSprite->field_4;
12101 Data8 = Data34->field_0;
12102 DataC = Data34->field_4;
12103 Data8 += 8;
12104 DataC += 8;
12105
12106 if (!Map_PathCheck_CalculateTo(Data0, Data4, Data8, DataC)) {
12107 if (pSprite->field_20 > 8)
12108 pSprite->field_1E_Big -= 0x12000;
12109 }
12110 else {
12111
12112 if (pSprite->field_20 < 0x18)
12113 pSprite->field_1E_Big += 0x28000;
12114 }
12115
12116 }
12117 else {
12118 // Near Target
12119 Data4 = Data34->field_20;
12120 Data4 -= pSprite->field_20;
12121 Data4 >>= 3;
12122 pSprite->field_20 += Data4;
12123 }
12124 }
12125 else {
12126
12127 Data4 = pSprite->field_20;
12128 if (Data4 != Data34->field_20) {
12129
12130 if (Data4 > Data34->field_20)
12131 pSprite->field_1E_Big -= 0x8000;
12132 else
12133 pSprite->field_1E_Big += 0x8000;
12134 }
12135 }
12136
12137 Data0 = Data34->field_0;
12138 Data0 += 8;
12139 Data4 = Data34->field_4;
12140 Data4 += 8;
12141 Sprite_Direction_Between_Points(pSprite, Data0, Data4);
12142 Sprite_Movement_Calculate(pSprite);
12143
12144 Data4 = pSprite->field_A;
12145 Data0 = pSprite->field_10;
12146 Data0 >>= 5;
12147 Data0 -= 1;
12148 Data0 ^= 0x0F;
12149 Data0 &= 0x0F;
12150 pSprite->field_A = Data0;
12151
12152 if (pSprite->field_22 == eSprite_PersonType_Human || Data4 == Data0) {
12153 if (pSprite->field_36 <= 0x3C) {
12154
12155 Data0 = (int16)(pSprite->field_6A >> 16);
12156 pSprite->field_36 += Data0;
12157 pSprite->field_6A = pSprite->field_6A + 0x200;
12158 }
12159 else {
12160 pSprite->field_36 = 0x3C;
12161 }
12162
12163 return;
12164 }
12165
12166 if (pSprite->field_36 > 0x1E) {
12167
12168 pSprite->field_6A = 0;
12169 pSprite->field_36 -= 2;
12170 if (pSprite->field_36 < 0)
12171 pSprite->field_36 = 0;
12172 }
12173
12174 return;
12175
12176 MissileExplode:;
12177 pSprite->field_18 = eSprite_Explosion2;
12178 pSprite->field_4 -= 4;
12179 Sprite_Projectile_HitTarget(pSprite);
12180 Sprite_Destroy(pSprite + 1);
12181
12182 }
12183
Sprite_Handle_Sparks(sSprite * pSprite)12184 void cFodder::Sprite_Handle_Sparks(sSprite* pSprite) {
12185 Sprite_Movement_Calculate(pSprite);
12186 int32 Data0 = (int32)pSprite->field_1A;
12187
12188 Data0 += pSprite->field_1E;
12189
12190 pSprite->field_1E_Big = Data0;
12191
12192 if (pSprite->field_1E_Big < 0) {
12193 pSprite->field_1E_Big = 0;
12194 Data0 = -Data0;
12195 Data0 >>= 1;
12196 }
12197
12198 Data0 -= 0x22000;
12199 pSprite->field_1A = Data0;
12200
12201 Data0 = Data0 >> 16;
12202 if (!pSprite->field_A)
12203 goto loc_1C248;
12204
12205 if (pSprite->field_20)
12206 goto loc_1C262;
12207
12208 if (Data0 > 1)
12209 goto loc_1C262;
12210
12211 loc_1C248:;
12212 pSprite->field_A++;
12213 if (pSprite->field_A >= 3) {
12214 Sprite_Destroy_Wrapper(pSprite);
12215 return;
12216 }
12217
12218 loc_1C262:;
12219 Sprite_Create_FireTrail(pSprite);
12220 }
12221
Sprite_Handle_FireTrail(sSprite * pSprite)12222 void cFodder::Sprite_Handle_FireTrail(sSprite* pSprite) {
12223 pSprite->field_2A += 1;
12224 pSprite->field_2A &= 1;
12225 if (pSprite->field_2A)
12226 return;
12227
12228 pSprite->field_A += 1;
12229 if (pSprite->field_A != 4)
12230 return;
12231
12232 Sprite_Destroy_Wrapper(pSprite);
12233 }
12234
Sprite_Handle_Helicopter_Grenade_Human(sSprite * pSprite)12235 void cFodder::Sprite_Handle_Helicopter_Grenade_Human(sSprite* pSprite) {
12236
12237 pSprite->field_6F = eVehicle_Helicopter;
12238 Sprite_Handle_Helicopter_Human(pSprite);
12239 }
12240
Sprite_Handle_Helicopter_Grenade2_Human(sSprite * pSprite)12241 void cFodder::Sprite_Handle_Helicopter_Grenade2_Human(sSprite* pSprite) {
12242
12243 pSprite->field_6F = eVehicle_Helicopter_Grenade;
12244 Sprite_Handle_Helicopter_Human(pSprite);
12245 }
12246
12247
Sprite_Handle_Helicopter_Missile_Human(sSprite * pSprite)12248 void cFodder::Sprite_Handle_Helicopter_Missile_Human(sSprite* pSprite) {
12249
12250 pSprite->field_6F = eVehicle_Helicopter_Missile;
12251 Sprite_Handle_Helicopter_Human(pSprite);
12252 }
12253
Sprite_Handle_Helicopter_Homing_Human(sSprite * pSprite)12254 void cFodder::Sprite_Handle_Helicopter_Homing_Human(sSprite* pSprite) {
12255
12256 pSprite->field_6F = eVehicle_Helicopter_Homing;
12257 Sprite_Handle_Helicopter_Human(pSprite);
12258 }
12259
Sprite_Handle_Helicopter_PropCrash(sSprite * pSprite)12260 void cFodder::Sprite_Handle_Helicopter_PropCrash(sSprite* pSprite) {
12261 pSprite->field_A += 1;
12262 pSprite->field_A &= 3;
12263
12264 Sprite_Movement_Calculate(pSprite);
12265 if (mSprite_Bullet_Destroy)
12266 goto loc_1C321;
12267
12268 pSprite->field_36 -= 1;
12269 if (pSprite->field_36 < 0)
12270 pSprite->field_36 = 0;
12271
12272 pSprite->field_1E_Big -= 0x8000;
12273
12274 if (pSprite->field_1E_Big < 0) {
12275 pSprite->field_1E_Big = 0;
12276 }
12277
12278 loc_1C321:;
12279 pSprite->field_18 = eSprite_Explosion;
12280 Sprite_Create_FireTrail(pSprite);
12281 }
12282
Sprite_Handle_Mine(sSprite * pSprite)12283 void cFodder::Sprite_Handle_Mine(sSprite* pSprite) {
12284 pSprite->field_2C = eSprite_Draw_First;
12285
12286 if (!pSprite->field_38) {
12287 int16 Data0;
12288 pSprite->field_8 = 0xC7;
12289 Map_Get_Distance_Between_Sprite_And_Squadleader(pSprite, Data0);
12290 }
12291 else {
12292 pSprite->field_18 = eSprite_Explosion2;
12293 }
12294 }
12295
Sprite_Handle_Mine2(sSprite * pSprite)12296 void cFodder::Sprite_Handle_Mine2(sSprite* pSprite) {
12297 int16 Data0;
12298
12299 pSprite->field_2C = eSprite_Draw_First;
12300 if (pSprite->field_38)
12301 goto loc_1C406;
12302
12303 if (pSprite->field_2A) {
12304 pSprite->field_2A += 1;
12305 if (pSprite->field_2A >= 0x0A)
12306 goto loc_1C406;
12307 }
12308
12309 Data0 = 0;
12310 pSprite->field_8 = 0xC8;
12311 if (Map_Get_Distance_Between_Sprite_And_Squadleader(pSprite, Data0))
12312 return;
12313
12314 if (mSquad_Leader->field_38)
12315 return;
12316
12317 if (!mSquad_Leader->field_36)
12318 return;
12319
12320 if (mSquad_Leader->field_52)
12321 return;
12322
12323 if (mSquad_Leader->field_20)
12324 return;
12325
12326 mSquad_Leader->field_38 = eSprite_Anim_Slide1;
12327 mSquad_Leader->field_2A = 1;
12328 return;
12329
12330 loc_1C406:;
12331 pSprite->field_18 = eSprite_Explosion;
12332 }
12333
Sprite_Handle_Spike(sSprite * pSprite)12334 void cFodder::Sprite_Handle_Spike(sSprite* pSprite) {
12335 sSprite* Data28 = mSquad_Leader;
12336 int16 Data0 = 0;
12337
12338 pSprite->field_8 = 0xC9;
12339
12340 if (pSprite->field_A)
12341 goto loc_1C4AD;
12342
12343 if (Map_Get_Distance_Between_Sprite_And_Squadleader(pSprite, Data0))
12344 return;
12345
12346 if (Data0 >= 6)
12347 return;
12348
12349 if (Data0 == 5)
12350 goto loc_1C4AD;
12351
12352 Data28->field_0 = pSprite->field_0;
12353 Data28->field_0 -= 3;
12354 Data28->field_4 = pSprite->field_4;
12355 Data28->field_4 += 1;
12356 Data28->field_38 = eSprite_Anim_Die4;
12357 Data28->field_64 = -1;
12358 Data28->field_20 = 7;
12359
12360 loc_1C4AD:;
12361 if (pSprite->field_A >= 2)
12362 return;
12363
12364 pSprite->field_A += 1;
12365 }
12366
Sprite_Handle_Smoke(sSprite * pSprite)12367 void cFodder::Sprite_Handle_Smoke(sSprite* pSprite) {
12368 pSprite->field_2A += 1;
12369 pSprite->field_2A &= 1;
12370 if (pSprite->field_2A)
12371 return;
12372
12373 pSprite->field_A -= 1;
12374 if (pSprite->field_A >= 0)
12375 return;
12376
12377 Sprite_Destroy_Wrapper(pSprite);
12378 }
12379
Sprite_Handle_Text_Try(sSprite * pSprite)12380 void cFodder::Sprite_Handle_Text_Try(sSprite* pSprite) {
12381 pSprite->field_0 = mMapTile_TargetX >> 16;
12382 pSprite->field_0 += (getCameraWidth() / 2) - 23;
12383 pSprite->field_4 -= 0x20;
12384
12385 int16 Data0 = mMapTile_TargetY >> 16;
12386 Data0 += (getCameraHeight() / 2 - 13);
12387
12388 if (Data0 < pSprite->field_4)
12389 return;
12390
12391 pSprite->field_4 = Data0;
12392 }
12393
Sprite_Handle_Text_Again(sSprite * pSprite)12394 void cFodder::Sprite_Handle_Text_Again(sSprite* pSprite) {
12395 pSprite->field_0 = mMapTile_TargetX >> 16;
12396 pSprite->field_0 += (getCameraWidth() / 2) - 49;
12397 pSprite->field_4 -= 0x20;
12398
12399 int16 Data0 = mMapTile_TargetY >> 16;
12400 Data0 += getCameraHeight() / 2 + 5;
12401
12402 if (Data0 < pSprite->field_4)
12403 return;
12404
12405 pSprite->field_4 = Data0;
12406 }
12407
Sprite_Handle_BoilingPot(sSprite * pSprite)12408 void cFodder::Sprite_Handle_BoilingPot(sSprite* pSprite) {
12409 pSprite->field_8 = 0xCD;
12410 pSprite->field_A += 1;
12411 pSprite->field_A &= 3;
12412
12413 sSprite* Data24 = pSprite + 1;
12414 Data24->field_8 = 0xCE;
12415 Data24->field_2A += 1;
12416 Data24->field_2A &= 1;
12417
12418 if (!Data24->field_2A) {
12419 Data24->field_A += 1;
12420
12421 if (Data24->field_A >= 6)
12422 Data24->field_A = 0;
12423 }
12424
12425 Data24->field_20 = 0x10;
12426 }
12427
Sprite_Handle_Civilian(sSprite * pSprite)12428 void cFodder::Sprite_Handle_Civilian(sSprite* pSprite) {
12429 if (pSprite->field_38) {
12430 Sprite_Handle_Civilian_Death(pSprite);
12431 return;
12432 }
12433
12434 pSprite->field_22 = eSprite_PersonType_Native;
12435 pSprite->field_8 = 0xD0;
12436
12437 int16 ax = Sprite_Handle_Civilian_Within_Range_OpenCloseDoor(pSprite);
12438
12439 if (ax) {
12440 if (ax >= 0)
12441 return;
12442
12443 Sprite_Handle_Civilian_Movement(pSprite);
12444 }
12445
12446 pSprite->field_36 = 6;
12447 sub_2593D(pSprite);
12448 sub_25A31(pSprite);
12449 sub_25A66(pSprite);
12450 }
12451
Sprite_Handle_Civilian2(sSprite * pSprite)12452 void cFodder::Sprite_Handle_Civilian2(sSprite* pSprite) {
12453
12454 if (pSprite->field_38) {
12455 Sprite_Handle_Civilian_Death(pSprite);
12456 return;
12457 }
12458
12459 pSprite->field_22 = eSprite_PersonType_Native;
12460 pSprite->field_8 = 0xD0;
12461
12462 int16 ax = Sprite_Handle_Civilian_Within_Range_OpenCloseDoor(pSprite);
12463 if (ax > 0)
12464 return;
12465 if (ax < 0)
12466 Sprite_Handle_Civilian_Movement(pSprite);
12467
12468 pSprite->field_36 = 0x0A;
12469 sub_2593D(pSprite);
12470 sub_25A31(pSprite);
12471 sub_25A66(pSprite);
12472 if (!word_3B2D1[1])
12473 return;
12474
12475 Sprite_Handle_Civilian_Unk(pSprite);
12476 }
12477
Sprite_Handle_VehicleNoGun_Human(sSprite * pSprite)12478 void cFodder::Sprite_Handle_VehicleNoGun_Human(sSprite* pSprite) {
12479
12480 pSprite->field_6F = eVehicle_Jeep;
12481 Sprite_Handle_Vehicle_Human(pSprite);
12482 }
12483
Sprite_Handle_VehicleGun_Human(sSprite * pSprite)12484 void cFodder::Sprite_Handle_VehicleGun_Human(sSprite* pSprite) {
12485
12486 pSprite->field_6F = eVehicle_JeepRocket;
12487 Sprite_Handle_Vehicle_Human(pSprite);
12488 }
12489
Sprite_Handle_Tank_Human(sSprite * pSprite)12490 void cFodder::Sprite_Handle_Tank_Human(sSprite* pSprite) {
12491
12492 if (pSprite->field_38 == eSprite_Anim_Die1)
12493 pSprite->field_38 = eSprite_Anim_None;
12494
12495 if (pSprite->field_38) {
12496 pSprite->field_22 = eSprite_PersonType_Human;
12497
12498 sub_23525(pSprite);
12499 pSprite->field_22 = eSprite_PersonType_Human;
12500 return;
12501 }
12502 pSprite->field_22 = eSprite_PersonType_Human;
12503 sub_23525(pSprite);
12504 pSprite->field_22 = eSprite_PersonType_Human;
12505 Sprite_Handle_Tank_FireMissile(pSprite);
12506
12507 sSprite* Data24 = pSprite + 1;
12508 Data24->field_18 = eSprite_Null;
12509 }
12510
Sprite_Handle_Bird_Left(sSprite * pSprite)12511 void cFodder::Sprite_Handle_Bird_Left(sSprite* pSprite) {
12512
12513 pSprite->field_8 = 0xD3;
12514 pSprite->field_2C = eSprite_Draw_OnTop;
12515
12516 if (!pSprite->field_12) {
12517
12518 pSprite->field_57 = 8;
12519 pSprite->field_12 = 1;
12520
12521 int16 Data0 = tool_RandomGet();
12522 int16 Data4 = Data0;
12523 Data0 &= 3;
12524 Data0 += 1;
12525
12526 pSprite->field_A = Data0;
12527 if (Data4 < 0)
12528 pSprite->field_12 = -1;
12529 }
12530
12531 int16 Data0 = pSprite->field_12;
12532 pSprite->field_A += Data0;
12533
12534 if (pSprite->field_A) {
12535 if (pSprite->field_A < 5)
12536 goto loc_1C82D;
12537 }
12538
12539 Data0 = -Data0;
12540 pSprite->field_12 = Data0;
12541
12542 loc_1C82D:;
12543 bool cf = false;
12544
12545 if (pSprite->field_2 >= 0 && pSprite->field_2 - 32768 < 0)
12546 cf = true;
12547
12548 pSprite->field_2 -= 32768;
12549 pSprite->field_0 -= 1 + (cf == true ? 1 : 0);
12550
12551
12552 if (Data0 < 0) {
12553 if (pSprite->field_2 >= 0 && pSprite->field_2 - 32768 < 0)
12554 cf = true;
12555 else
12556 cf = false;
12557
12558 pSprite->field_2 -= 32768;
12559 pSprite->field_0 -= 0 + (cf == true ? 1 : 0);
12560 }
12561
12562 if (pSprite->field_5C)
12563 goto loc_1C8C5;
12564
12565 if (!pSprite->field_57)
12566 goto loc_1C87E;
12567
12568 pSprite->field_57 -= 1;
12569 goto loc_1C8C5;
12570
12571 loc_1C87E:;
12572
12573 pSprite->field_57 = 0x3F;
12574
12575 Data0 = (tool_RandomGet() & 0x3F) + (mMapTile_TargetX >> 16) + getWindowWidth();
12576 pSprite->field_0 = Data0;
12577
12578 Data0 = (tool_RandomGet() & 0xFF) + (mMapTile_TargetY >> 16);
12579 pSprite->field_4 = Data0;
12580
12581 loc_1C8C5:;
12582
12583 if (mMapLoaded->getTileType() == eTileTypes_Jungle)
12584 Sprite_Native_Sound_Play(pSprite, 0x1A);
12585
12586 if (mMapLoaded->getTileType() == eTileTypes_Ice || mMapLoaded->getTileType() == eTileTypes_AFX)
12587 Sprite_Native_Sound_Play(pSprite, 0x1F);
12588
12589 }
12590
Sprite_Handle_Bird_Right(sSprite * pSprite)12591 void cFodder::Sprite_Handle_Bird_Right(sSprite* pSprite) {
12592 pSprite->field_8 = 0xD4;
12593 pSprite->field_2C = eSprite_Draw_OnTop;
12594
12595 if (!pSprite->field_12) {
12596 pSprite->field_57 = 8;
12597 pSprite->field_12 = 1;
12598
12599 int16 Data0 = tool_RandomGet();
12600 int16 Data4 = Data0;
12601 Data0 &= 3;
12602 Data0 += 1;
12603
12604 pSprite->field_A = Data0;
12605 if (Data4 < 0)
12606 pSprite->field_12 = -1;
12607 }
12608
12609 //loc_1C950
12610 int16 Data0 = pSprite->field_12;
12611 pSprite->field_A += Data0;
12612 if (!pSprite->field_A || pSprite->field_A >= 5) {
12613 Data0 = -Data0;
12614 pSprite->field_12 = Data0;
12615 }
12616
12617 bool cf = false;
12618
12619 if (pSprite->field_2 < 0 && pSprite->field_2 + 32768 > 0)
12620 cf = true;
12621
12622 pSprite->field_2 += 32768;
12623 pSprite->field_0 += 1 + (cf == true ? 1 : 0);
12624
12625 if (Data0 < 0) {
12626 if (pSprite->field_2 < 0 && pSprite->field_2 + 32768 > 0)
12627 cf = true;
12628 else
12629 cf = false;
12630
12631 pSprite->field_2 += 32768;
12632 pSprite->field_0 += 0 + (cf == true ? 1 : 0);
12633 }
12634
12635 //loc_1C9B0
12636 if (pSprite->field_5C)
12637 goto loc_1CA20;
12638
12639 if (pSprite->field_57) {
12640 pSprite->field_57 -= 1;
12641 goto loc_1CA20;
12642 }
12643
12644 //loc_1C9D3
12645 pSprite->field_57 = 0x3F;
12646 Data0 = tool_RandomGet() & 0x3F;
12647 Data0 = -Data0;
12648 Data0 += mMapTile_TargetX >> 16;
12649
12650 pSprite->field_0 = Data0;
12651 Data0 = tool_RandomGet() & 0xFF;
12652 Data0 += mMapTile_TargetY >> 16;
12653 pSprite->field_4 = Data0;
12654
12655 loc_1CA20:;
12656 if (mMapLoaded->getTileType() == eTileTypes_Jungle)
12657 Sprite_Native_Sound_Play(pSprite, 0x1A);
12658
12659 if (mMapLoaded->getTileType() == eTileTypes_Ice || mMapLoaded->getTileType() == eTileTypes_AFX)
12660 Sprite_Native_Sound_Play(pSprite, 0x1F);
12661 }
12662
Sprite_Handle_Seal(sSprite * pSprite)12663 void cFodder::Sprite_Handle_Seal(sSprite* pSprite) {
12664 if (sub_25DCF(pSprite))
12665 return;
12666
12667 pSprite->field_22 = eSprite_PersonType_Native;
12668 pSprite->field_8 = 0xD5;
12669
12670 if (!pSprite->field_2E) {
12671 pSprite->field_2E = -1;
12672 pSprite->field_54 = tool_RandomGet() & 0x0F;
12673 }
12674
12675 if (mMission_EngineTicks & 1)
12676 ++pSprite->field_54;
12677
12678 int16 Data0 = pSprite->field_54 & 0x0F;
12679
12680 Data0 = mSprite_Seal_AnimFrames[Data0];
12681 pSprite->field_A = Data0;
12682
12683 if (mMapLoaded->getTileType() == eTileTypes_Moors) {
12684 Data0 = tool_RandomGet() & 3;
12685 if (Data0 != 3) {
12686 Data0 += 0x23;
12687 Sprite_Native_Sound_Play(pSprite, Data0);
12688 }
12689 }
12690
12691 if (mMapLoaded->getTileType() == eTileTypes_Ice || mMapLoaded->getTileType() == eTileTypes_AFX) {
12692 Sprite_Native_Sound_Play(pSprite, 0x1E);
12693 }
12694 }
12695
Sprite_Handle_Tank_Enemy(sSprite * pSprite)12696 void cFodder::Sprite_Handle_Tank_Enemy(sSprite* pSprite) {
12697 int16 Data0, Data4, Data8, DataC, Data10, Data14;
12698 sSprite* Data24 = 0, *Data30 = 0;
12699
12700 if (pSprite->field_38 == eSprite_Anim_Die1)
12701 pSprite->field_38 = eSprite_Anim_None;
12702
12703 if (pSprite->field_38) {
12704 pSprite->field_22 = eSprite_PersonType_AI;
12705 sub_23525(pSprite);
12706 pSprite->field_22 = eSprite_PersonType_AI;
12707
12708 Data24 = pSprite + 2;
12709 if (Data24->field_18 == eSprite_Flashing_Light)
12710 Sprite_Destroy(Data24);
12711
12712 return;
12713 }
12714
12715 if (pSprite->field_4C)
12716 pSprite->field_4C--;
12717
12718 int16 Data1C = pSprite->field_5E_Squad;
12719 if (mSquads[Data1C / 9] == (sSprite**)INVALID_SPRITE_PTR)
12720 goto NextSquadMember;
12721
12722 Data30 = mSquads[Data1C / 9][Data1C % 9];
12723 if (Data30 == INVALID_SPRITE_PTR)
12724 goto NextSquadMember;
12725
12726 if (Data30->field_52)
12727 goto NextSquadMember;
12728
12729 Data8 = Data30->field_0;
12730 Data8 += 8;
12731
12732 DataC = Data30->field_4;
12733 DataC += -5;
12734
12735 if (Map_Terrain_Get_Moveable_Wrapper(mTiles_NotDriveable, Data8, DataC, Data10, Data14))
12736 goto NextSquadMember;
12737
12738 Data0 = pSprite->field_0;
12739 Data4 = pSprite->field_4;
12740 Data8 = Data30->field_0;
12741 DataC = Data30->field_4;
12742
12743 mSprite_Tank_SpriteX = Data0;
12744 mSprite_Tank_SpriteY = Data4;
12745 mSprite_Tank_Squad0_X = Data8;
12746 mSprite_Tank_DistanceTo_Squad0 = DataC;
12747
12748 Map_Get_Distance_BetweenPoints_Within_Window(Data0, Data4, Data8, DataC);
12749 mSprite_DistanceTo_Squad0 = Data0;
12750 if (Data0 >= 250)
12751 goto NextSquadMember;
12752
12753 Data0 = mSprite_Tank_SpriteX;
12754 Data4 = mSprite_Tank_SpriteY;
12755 Data8 = mSprite_Tank_Squad0_X;
12756 DataC = mSprite_Tank_DistanceTo_Squad0;
12757 Data8 += 0x0F;
12758 DataC -= 0x0A;
12759
12760 if (Map_PathCheck_CalculateTo(Data0, Data4, Data8, DataC))
12761 goto NextSquadMember;
12762
12763 pSprite->field_2E = Data30->field_0;
12764 pSprite->field_30 = Data30->field_4;
12765 pSprite->field_4C = 0x5A;
12766
12767 // If we have reached our current target
12768 if (pSprite->field_0 == pSprite->field_26 && pSprite->field_4 == pSprite->field_28) {
12769
12770 if (!(tool_RandomGet() & 0x3F)) {
12771 pSprite->field_26 = Data30->field_0;
12772 pSprite->field_28 = Data30->field_4;
12773 }
12774 }
12775
12776 if (mSprite_DistanceTo_Squad0 <= 0x32)
12777 goto loc_1CDA3;
12778
12779 Data0 = tool_RandomGet() & 0x1F;
12780 if (Data0 != 4)
12781 goto loc_1CDA3;
12782
12783 pSprite->field_54 = -1;
12784 Sprite_Handle_Tank_FireMissile(pSprite);
12785 goto loc_1CDA3;
12786
12787 NextSquadMember:;
12788 pSprite->field_5E_Squad += 1;
12789 if (pSprite->field_5E_Squad >= 0x1E) {
12790 pSprite->field_5E_Squad = 0;
12791 pSprite->field_2E = -1;
12792 }
12793
12794 loc_1CDA3:;
12795 mSprite_Helicopter_DestroyLight = -1;
12796 pSprite->field_22 = eSprite_PersonType_AI;
12797 sub_23525(pSprite);
12798 pSprite->field_22 = eSprite_PersonType_AI;
12799 mSprite_Helicopter_DestroyLight = 0;
12800
12801 if (mSprite_Reached_Target) {
12802 pSprite->field_4C = 0;
12803 pSprite->field_26 = pSprite->field_0;
12804 pSprite->field_28 = pSprite->field_4;
12805 }
12806
12807 Data24 = pSprite + 1;
12808 Data24->field_18 = eSprite_Null;
12809
12810 Data24 = pSprite + 2;
12811 Data24->field_18 = eSprite_Flashing_Light;
12812 Data24->field_0 = pSprite->field_0 + 0x0F;
12813 Data24->field_4 = (pSprite->field_4 - 0x16) - pSprite->field_52;
12814 Data24->field_20 = pSprite->field_20;
12815 }
12816
Sprite_Handle_Civilian_Spear(sSprite * pSprite)12817 void cFodder::Sprite_Handle_Civilian_Spear(sSprite* pSprite) {
12818 pSprite->field_22 = eSprite_PersonType_AI;
12819 if (pSprite->field_38) {
12820 Sprite_Handle_Civilian_Death(pSprite);
12821 return;
12822 }
12823
12824 pSprite->field_22 = eSprite_PersonType_Native;
12825 pSprite->field_8 = 0xD0;
12826
12827 if (mMapLoaded->getTileType() == eTileTypes_Moors)
12828 Sprite_Native_Sound_Play(pSprite, 0x26);
12829
12830 if (mMapLoaded->getTileType() == eTileTypes_Int)
12831 Sprite_Native_Sound_Play(pSprite, 0x1F);
12832
12833 int16 ax = Sprite_Handle_Civilian_Within_Range_OpenCloseDoor(pSprite);
12834 if (ax > 0)
12835 return;
12836 if (ax)
12837 Sprite_Handle_Civilian_Movement(pSprite);
12838
12839 pSprite->field_36 = 0x0C;
12840
12841 sub_2593D(pSprite);
12842 sub_25A31(pSprite);
12843 sub_25A66(pSprite);
12844 Sprite_Handle_Civilian_Unk(pSprite);
12845 }
12846
Sprite_Handle_Civilian_Spear2(sSprite * pSprite)12847 void cFodder::Sprite_Handle_Civilian_Spear2(sSprite* pSprite) {
12848 int16 Data0, Data4, Data8, DataC, Data1C;
12849
12850 ++pSprite->field_64;
12851
12852 if (!pSprite->field_12)
12853 goto loc_1D0F6;
12854
12855 pSprite->field_12 -= 1;
12856 pSprite->field_3A += 1;
12857
12858 if (pSprite->field_44)
12859 goto loc_1CFF7;
12860
12861 Sprite_XY_Store(pSprite);
12862 Data1C = pSprite->field_10;
12863
12864 if (pSprite->field_59)
12865 goto loc_1CF3E;
12866
12867 Data0 = pSprite->field_2E;
12868 Data4 = pSprite->field_30;
12869
12870 Sprite_Direction_Between_Points(pSprite, Data0, Data4);
12871 Data0 = pSprite->field_50;
12872
12873 if (Data0) {
12874 pSprite->field_10 += Data0;
12875 pSprite->field_10 &= 0x1FE;
12876 pSprite->field_59 = -1;
12877 }
12878
12879 if (pSprite->field_34 < 0)
12880 pSprite->field_34 = pSprite->field_10;
12881
12882 loc_1CF3E:;
12883 Sprite_Movement_Calculate(pSprite);
12884 if (mSprite_Bullet_Destroy)
12885 goto loc_1D17A;
12886
12887 pSprite->field_36 = pSprite->field_4A;
12888 if (pSprite->field_59)
12889 goto loc_1D00F;
12890
12891 Data0 = pSprite->field_0;
12892 Data4 = pSprite->field_4;
12893 Data8 = pSprite->field_2E;
12894 DataC = pSprite->field_30;
12895
12896 Map_Get_Distance_BetweenPoints_Within_Window(Data0, Data4, Data8, DataC);
12897 Data4 = pSprite->field_36;
12898 Data4 >>= 3;
12899 if (Data0 > Data4)
12900 goto loc_1D00F;
12901
12902 pSprite->field_2C = eSprite_Draw_Second;
12903 pSprite->field_0 = pSprite->field_2E;
12904 pSprite->field_4 = pSprite->field_30;
12905 pSprite->field_44 = -1;
12906 goto loc_1D00F;
12907 loc_1CFF7:;
12908 pSprite->field_2C = eSprite_Draw_First;
12909 Sprite_Movement_Calculate(pSprite);
12910 if (mSprite_Bullet_Destroy)
12911 goto loc_1D17A;
12912
12913 loc_1D00F:;
12914 if (pSprite->field_64 > 2) {
12915 Data0 = -9;
12916 Data4 = 0;
12917 if (Map_Terrain_Get_Type_And_Walkable(pSprite, Data0, Data4))
12918 goto loc_1D0F6;
12919 }
12920
12921 if (Sprite_Projectile_Collision_Check(pSprite))
12922 goto loc_1D07B;
12923
12924 if (pSprite->field_8 != 0xD7)
12925 return;
12926
12927 Data0 = pSprite->field_10;
12928 Data0 >>= 5;
12929 Data0 -= 1;
12930 Data0 ^= 0x0F;
12931 Data0 &= 0x0F;
12932 Data0 >>= 1;
12933 pSprite->field_A = Data0;
12934 return;
12935 loc_1D07B:;
12936
12937 if (mSprites_Found_Count == 1)
12938 goto loc_1D0F6;
12939
12940 pSprite->field_43 = 1;
12941 pSprite->field_2C = eSprite_Draw_OnTop;
12942 pSprite->field_4 -= 5;
12943 if (pSprite->field_4 < 0)
12944 goto loc_1D18D;
12945 pSprite->field_8 = 0x96;
12946 pSprite->field_A = 0;
12947
12948 Sound_Play(pSprite, eSound_Effect_Spear, 0x0F);
12949 return;
12950
12951 loc_1D0CB:;
12952 pSprite->field_8 = 0x96;
12953 pSprite->field_12 = 0;
12954 pSprite->field_A += 1;
12955 if (pSprite->field_A >= 4)
12956 goto loc_1D17A;
12957 return;
12958
12959 loc_1D0F6:;
12960 if (pSprite->field_43)
12961 goto loc_1D14D;
12962
12963 pSprite->field_43 = -1;
12964 pSprite->field_2C = eSprite_Draw_First;
12965 pSprite->field_4 -= 5;
12966 if (pSprite->field_4 < 0)
12967 goto loc_1D18D;
12968
12969 pSprite->field_A = 3;
12970 Sound_Play(pSprite, eSound_Effect_Spear, 0x0F);
12971 loc_1D14D:;
12972 if (pSprite->field_43 >= 0)
12973 goto loc_1D0CB;
12974
12975 pSprite->field_12 = 0;
12976 pSprite->field_8 = 0x7F;
12977 pSprite->field_A += 1;
12978 if (pSprite->field_A >= 8)
12979 goto loc_1D17A;
12980 return;
12981
12982 loc_1D17A:;
12983 --mSprite_Projectile_Counters[2];
12984 Sprite_Destroy(pSprite);
12985 return;
12986
12987 loc_1D18D:;
12988 pSprite->field_0 = 0;
12989 pSprite->field_4 = 0x1000;
12990 goto loc_1D17A;
12991 }
12992
Sprite_Handle_Hostage(sSprite * pSprite)12993 void cFodder::Sprite_Handle_Hostage(sSprite* pSprite) {
12994 int16 Data0, Data4;
12995 int16 Sprite_Field_10;
12996 sSprite* Data24 = 0;
12997
12998 if (pSprite->field_6E)
12999 goto loc_1D349;
13000
13001 pSprite->field_22 = eSprite_PersonType_Native;
13002 pSprite->field_8 = 0xD9;
13003
13004 word_3B2D1[2] = pSprite->field_0;
13005 word_3B2D1[3] = pSprite->field_2;
13006 word_3B2D1[4] = pSprite->field_4;
13007 word_3B2D1[5] = pSprite->field_6;
13008
13009 Sprite_Handle_Hostage_Movement(pSprite);
13010 Sprite_Handle_Civilian_Movement(pSprite);
13011
13012 pSprite->field_36 = 0x0C;
13013 sub_2593D(pSprite);
13014 pSprite->field_38 = eSprite_Anim_None;
13015
13016 Sprite_Handle_Hostage_FrameUpdate2(pSprite);
13017 //seg004:44B6
13018
13019 Sprite_Field_10 = pSprite->field_10;
13020 pSprite->field_10 += 0x20;
13021 pSprite->field_10 &= 0x1C0;
13022
13023 Sprite_Handle_Hostage_FrameUpdate(pSprite);
13024 pSprite->field_10 = Sprite_Field_10;
13025 sub_25F2B(pSprite);
13026
13027 if (pSprite->field_18 != eSprite_Enemy_Leader)
13028 return;
13029
13030 Data24 = pSprite + 1;
13031
13032 //seg004:4505
13033 if (pSprite->field_5E) {
13034 Data24->field_18 = eSprite_Null;
13035 Data24->field_8 = 0x7C;
13036 Data24->field_A = 0;
13037 }
13038
13039 Data24->field_18 = eSprite_Flashing_Light;
13040
13041 Data4 = pSprite->field_0;
13042 Data4 += 6;
13043
13044 Data24->field_0 = Data4;
13045 Data4 = pSprite->field_4 - 0x0B;
13046 Data4 += pSprite->field_52;
13047 Data24->field_4 = Data4;
13048 Data24->field_20 = pSprite->field_20;
13049
13050 if (pSprite->field_6E) {
13051 Data24->field_18 = eSprite_Null;
13052 Data24->field_8 = 0x7C;
13053 Data24->field_A = 0;
13054 }
13055
13056 Data0 = pSprite->field_0;
13057 if (Data0 == mStoredSpriteX) {
13058 Data0 = pSprite->field_4;
13059 if (Data0 == mStoredSpriteY)
13060 return;
13061 }
13062 pSprite->field_8 = 0xD8;
13063 return;
13064
13065 loc_1D349:;
13066 pSprite->field_38 = eSprite_Anim_None;
13067 sSprite* Data28 = &mSprites[pSprite->field_5E];
13068 if (Data28->field_6E)
13069 goto loc_1D44C;
13070
13071 pSprite->field_0 = Data28->field_0;
13072 pSprite->field_4 = Data28->field_4;
13073 pSprite->field_0 += 8;
13074 pSprite->field_4 += 0x0A;
13075 mStoredSpriteY = pSprite->field_4;
13076
13077 loc_1D3C6:;
13078 Data0 = -3;
13079 Data4 = 8;
13080 if (!Map_Terrain_Get_Type_And_Walkable(pSprite, Data0, Data4))
13081 goto loc_1D411;
13082
13083 pSprite->field_4 -= 1;
13084 if (pSprite->field_4 >= 0)
13085 goto loc_1D3C6;
13086
13087 pSprite->field_4 = mStoredSpriteY;
13088 pSprite->field_0 -= 1;
13089 if (pSprite->field_0 >= 0)
13090 goto loc_1D3C6;
13091
13092 pSprite->field_0 = 0;
13093 pSprite->field_38 = eSprite_Anim_Die1;
13094
13095 loc_1D411:;
13096 Data4 = pSprite->field_4;
13097 Data0 = mMapLoaded->getHeightPixels();
13098
13099 if (Data4 < Data0)
13100 goto loc_1D441;
13101
13102 Data0 -= 1;
13103 pSprite->field_4 = Data0;
13104
13105 loc_1D441:;
13106 pSprite->field_6E = 0;
13107 return;
13108
13109 loc_1D44C:;
13110 pSprite->field_8 = 0x7C;
13111 pSprite->field_A = 0;
13112 pSprite->field_0 = Data28->field_0;
13113 pSprite->field_4 = Data28->field_4;
13114 }
13115
Sprite_Handle_Hostage_Rescue_Tent(sSprite * pSprite)13116 void cFodder::Sprite_Handle_Hostage_Rescue_Tent(sSprite* pSprite) {
13117 pSprite->field_8 = 0xDD;
13118
13119 mHostage_Rescue_Tent = pSprite;
13120 if (pSprite->field_38 == eSprite_Anim_Die3)
13121 pSprite->field_18 = eSprite_Explosion2;
13122 }
13123
Sprite_Handle_Door_Civilian(sSprite * pSprite)13124 void cFodder::Sprite_Handle_Door_Civilian(sSprite* pSprite) {
13125 mSpawnSpriteType = 0x3D;
13126
13127 sub_264B0(pSprite);
13128 }
13129
Sprite_Handle_Door2_Civilian(sSprite * pSprite)13130 void cFodder::Sprite_Handle_Door2_Civilian(sSprite* pSprite) {
13131 mSpawnSpriteType = 0x3E;
13132
13133 sub_264B0(pSprite);
13134 }
13135
Sprite_Handle_Door_Civilian_Spear(sSprite * pSprite)13136 void cFodder::Sprite_Handle_Door_Civilian_Spear(sSprite* pSprite) {
13137 mSpawnSpriteType = 0x46;
13138
13139 sub_264B0(pSprite);
13140 }
13141
Sprite_Handle_Cannon(sSprite * pSprite)13142 void cFodder::Sprite_Handle_Cannon(sSprite* pSprite) {
13143 int16 Data0, Data4, Data8, DataC, Data1C;
13144 ++pSprite->field_64;
13145
13146 if (!pSprite->field_12)
13147 goto loc_1D65C;
13148
13149 pSprite->field_12 -= 1;
13150 pSprite->field_3A++;
13151
13152 if (pSprite->field_44)
13153 goto loc_1D5B3;
13154
13155 Sprite_XY_Store(pSprite);
13156 Data1C = pSprite->field_10;
13157
13158 Sprite_Movement_Calculate(pSprite);
13159
13160 if (mSprite_Bullet_Destroy)
13161 goto loc_1D6CA;
13162
13163 Data0 = pSprite->field_0;
13164 Data4 = pSprite->field_4;
13165 Data8 = pSprite->field_2E;
13166 DataC = pSprite->field_30;
13167
13168 Map_Get_Distance_BetweenPoints_Within_Window(Data0, Data4, Data8, DataC);
13169
13170 Data4 = pSprite->field_36;
13171 Data4 >>= 3;
13172
13173 if (Data0 > Data4)
13174 goto loc_1D5CB;
13175
13176 pSprite->field_2C = eSprite_Draw_Second;
13177 pSprite->field_0 = pSprite->field_2E;
13178 pSprite->field_4 = pSprite->field_30;
13179 pSprite->field_44 = -1;
13180 goto loc_1D5CB;
13181 loc_1D5B3:;
13182 pSprite->field_2C = eSprite_Draw_First;
13183 Sprite_Movement_Calculate(pSprite);
13184
13185 if (mSprite_Bullet_Destroy)
13186 goto loc_1D6CA;
13187
13188 loc_1D5CB:;
13189 if (pSprite->field_64 > 3) {
13190 Data0 = -9;
13191 Data4 = 0;
13192 if (Map_Terrain_Get_Type_And_Walkable(pSprite, Data0, Data4))
13193 goto loc_1D65C;
13194 }
13195
13196 if (!Sprite_Projectile_Collision_Check(pSprite))
13197 return;
13198
13199 if (mSprites_Found_Count == 1)
13200 goto loc_1D65C;
13201
13202 pSprite->field_43 = 1;
13203 pSprite->field_2C = eSprite_Draw_OnTop;
13204 pSprite->field_4 -= 5;
13205 if (pSprite->field_4 < 0)
13206 goto loc_1D6DD;
13207 pSprite->field_8 = 0x96;
13208 pSprite->field_A = 0;
13209 return;
13210
13211 loc_1D633:;
13212 pSprite->field_8 = 0x96;
13213 pSprite->field_12 = 0;
13214 pSprite->field_A += 1;
13215 if (pSprite->field_A >= 4)
13216 goto loc_1D6CA;
13217
13218 loc_1D65C:;
13219
13220 if (pSprite->field_43)
13221 goto loc_1D69F;
13222
13223 Sprite_Projectile_Collision_Check(pSprite);
13224 pSprite->field_43 = -1;
13225 pSprite->field_2C = eSprite_Draw_First;
13226 pSprite->field_4 -= 5;
13227 if (pSprite->field_4 < 0)
13228 goto loc_1D6DD;
13229
13230 pSprite->field_A = 3;
13231
13232 loc_1D69F:;
13233 if (pSprite->field_43 >= 0)
13234 goto loc_1D633;
13235
13236 pSprite->field_12 = 0;
13237 pSprite->field_8 = 0x7F;
13238 pSprite->field_A += 1;
13239
13240 if (pSprite->field_8 >= 8)
13241 goto loc_1D6CA;
13242
13243 return;
13244
13245 loc_1D6CA:;
13246
13247 mSprite_Projectile_Counters[2] -= 1;
13248 Sprite_Destroy(pSprite);
13249 return;
13250
13251 loc_1D6DD:;
13252 pSprite->field_0 = 0;
13253 pSprite->field_4 = 0x1000;
13254 goto loc_1D6CA;
13255
13256 }
13257
Sprite_Handle_VehicleNoGun_Enemy(sSprite * pSprite)13258 void cFodder::Sprite_Handle_VehicleNoGun_Enemy(sSprite* pSprite) {
13259 pSprite->field_6F = eVehicle_Jeep;
13260 Sprite_Handle_Vehicle_Enemy(pSprite);
13261 }
13262
Sprite_Handle_VehicleGun_Enemy(sSprite * pSprite)13263 void cFodder::Sprite_Handle_VehicleGun_Enemy(sSprite* pSprite) {
13264 pSprite->field_6F = eVehicle_JeepRocket;
13265 Sprite_Handle_Vehicle_Enemy(pSprite);
13266 }
13267
Sprite_Handle_Vehicle_Unk_Enemy(sSprite * pSprite)13268 void cFodder::Sprite_Handle_Vehicle_Unk_Enemy(sSprite* pSprite) {
13269
13270 pSprite->field_6F = eVehicle_DontTargetPlayer;
13271
13272 pSprite->field_26 = pSprite->field_0;
13273 pSprite->field_26 += 0x28;
13274
13275 Sprite_Handle_Vehicle_Enemy(pSprite);
13276 }
13277
Sprite_Handle_Civilian_Invisible(sSprite * pSprite)13278 void cFodder::Sprite_Handle_Civilian_Invisible(sSprite* pSprite) {
13279
13280 if (!pSprite->field_38)
13281 return;
13282
13283 Sprite_Handle_Civilian_Death(pSprite);
13284
13285 /* Unused code block
13286
13287 seg004:4A78 C4 36 20 00 les si, ds:20h
13288 seg004:4A7C 26 C7 44 22 02 00 mov word ptr es:[si+22h], 2
13289 seg004:4A82 C4 36 20 00 les si, ds:20h
13290 seg004:4A86 26 C7 44 08 D0 00 mov word ptr es:[si+8], 0D0h ; 'ð'
13291 */
13292 }
13293
Sprite_Handle_Turret_Missile_Enemy(sSprite * pSprite)13294 void cFodder::Sprite_Handle_Turret_Missile_Enemy(sSprite* pSprite) {
13295 pSprite->field_22 = eSprite_PersonType_AI;
13296 pSprite->field_6F = eVehicle_Turret_Cannon;
13297
13298 Sprite_Handle_Turret(pSprite);
13299 }
13300
Sprite_Handle_Turret_Missile2_Enemy(sSprite * pSprite)13301 void cFodder::Sprite_Handle_Turret_Missile2_Enemy(sSprite* pSprite) {
13302 pSprite->field_22 = eSprite_PersonType_AI;
13303 pSprite->field_6F = eVehicle_Turret_Missile;
13304
13305 Sprite_Handle_Turret(pSprite);
13306 }
13307
Sprite_Handle_Turret_HomingMissile_Enemy(sSprite * pSprite)13308 void cFodder::Sprite_Handle_Turret_HomingMissile_Enemy(sSprite* pSprite) {
13309 pSprite->field_22 = eSprite_PersonType_AI;
13310 pSprite->field_6F = eVehicle_Turret_Homing;
13311
13312 Sprite_Handle_Turret(pSprite);
13313 }
13314
Sprite_Handle_Turret_Missile_Human(sSprite * pSprite)13315 void cFodder::Sprite_Handle_Turret_Missile_Human(sSprite* pSprite) {
13316 pSprite->field_22 = eSprite_PersonType_Human;
13317 pSprite->field_6F = eVehicle_Turret_Cannon;
13318
13319 Sprite_Handle_Turret(pSprite);
13320 }
13321
Sprite_Handle_Turret_Missile2_Human(sSprite * pSprite)13322 void cFodder::Sprite_Handle_Turret_Missile2_Human(sSprite* pSprite) {
13323 pSprite->field_22 = eSprite_PersonType_Human;
13324 pSprite->field_6F = eVehicle_Turret_Missile;
13325
13326 Sprite_Handle_Turret(pSprite);
13327 }
13328
Sprite_Handle_Vehicle_Sinking_1(sSprite * pSprite)13329 void cFodder::Sprite_Handle_Vehicle_Sinking_1(sSprite* pSprite) {
13330 Sound_Play(pSprite, eSound_Effect_Vehicle_Sinking, 0x0F);
13331 pSprite->field_A -= 1;
13332
13333 if (pSprite->field_A < 0)
13334 Sprite_Destroy_Wrapper(pSprite);
13335 }
13336
Sprite_Handle_Vehicle_Sinking_2(sSprite * pSprite)13337 void cFodder::Sprite_Handle_Vehicle_Sinking_2(sSprite* pSprite) {
13338 pSprite->field_A += 1;
13339
13340 if (pSprite->field_A == 6)
13341 Sprite_Destroy_Wrapper(pSprite);
13342 }
13343
Sprite_Handle_BuildingDoor3(sSprite * pSprite)13344 void cFodder::Sprite_Handle_BuildingDoor3(sSprite* pSprite) {
13345 int16 Data0, Data4;
13346 sSprite* Data2C = 0;
13347
13348 if (sub_1D92E(pSprite))
13349 return;
13350
13351 if (mTroops_Enemy_Count >= mParams->mSpawnEnemyMax) {
13352 pSprite->field_8 = 0xE0;
13353 return;
13354 }
13355
13356 pSprite->field_2C = eSprite_Draw_First;
13357 if (pSprite->field_43 < 0)
13358 goto loc_1D8DC;
13359
13360 pSprite->field_43 -= 1;
13361 if (pSprite->field_43 == 0x14 || pSprite->field_43 == 0x0A)
13362 goto loc_1D928;
13363
13364 if (pSprite->field_43 >= 0) {
13365 pSprite->field_8 = 0x7C;
13366 return;
13367 }
13368
13369 pSprite->field_8 = 0xE0;
13370 Sound_Play(pSprite, eSound_Effect_BuildingDoor2, 1);
13371
13372 Data0 = tool_RandomGet() & 0x0F;
13373 Data4 = 0x14 - mGame_Data.mGamePhase_Data.mSprite_Enemy_AggressionMax;
13374
13375 if (Data4 < 0)
13376 Data0 = 0;
13377
13378 Data4 <<= 3;
13379 Data4 += Data0;
13380 pSprite->field_12 = Data4;
13381
13382 loc_1D8DC:;
13383
13384 pSprite->field_12 -= 1;
13385 if (pSprite->field_12 >= 0)
13386 return;
13387
13388 Data0 = tool_RandomGet() & 0x0F;
13389 Data0 += 6;
13390 pSprite->field_43 = static_cast<int8>(Data0);
13391 pSprite->field_8 = 0x7C;
13392
13393 if (!Sprite_Create_Enemy(pSprite, Data2C))
13394 return;
13395
13396 pSprite->field_12 = -1;
13397 pSprite->field_43 = -1;
13398 return;
13399
13400 loc_1D928:;
13401 Sprite_Create_Enemy(pSprite, Data2C);
13402 }
13403
Sprite_Handle_Explosion2(sSprite * pSprite)13404 void cFodder::Sprite_Handle_Explosion2(sSprite* pSprite) {
13405
13406 Sprite_Handle_Explosion(pSprite);
13407 }
13408
Sprite_Handle_Door_Civilian_Rescue(sSprite * pSprite)13409 void cFodder::Sprite_Handle_Door_Civilian_Rescue(sSprite* pSprite) {
13410 mSprite_OpenCloseDoor_Ptr = pSprite;
13411
13412 if (sub_222A3(pSprite)) {
13413 mSprite_OpenCloseDoor_Ptr = 0;
13414 mPhase_Aborted = true;
13415 return;
13416 }
13417 pSprite->field_2C = eSprite_Draw_First;
13418 if (!pSprite->field_2A) {
13419 pSprite->field_8 = 0x9B;
13420 return;
13421 }
13422
13423 pSprite->field_2A -= 1;
13424 if (!pSprite->field_2A)
13425 Sound_Play(pSprite, eSound_Effect_DoorCloseDoor, 1);
13426
13427 if (pSprite->field_8 == 0x9B)
13428 Sound_Play(pSprite, eSound_Effect_DoorCloseDoor, 1);
13429
13430 pSprite->field_8 = 0x7C;
13431 }
13432
Sprite_Handle_Seal_Mine(sSprite * pSprite)13433 void cFodder::Sprite_Handle_Seal_Mine(sSprite* pSprite) {
13434 Sprite_Handle_Seal(pSprite);
13435
13436 if (pSprite->field_8 == 0xE1)
13437 return;
13438
13439 if (pSprite->field_38)
13440 return;
13441
13442 if (mSquad_Leader == INVALID_SPRITE_PTR)
13443 return;
13444
13445 sSprite* Data24 = mSquad_Leader;
13446 int16 Data0 = Data24->field_0;
13447 int16 Data4 = Data24->field_4;
13448 int16 Data8 = pSprite->field_0;
13449 int16 DataC = pSprite->field_4;
13450
13451 Map_Get_Distance_BetweenPoints_Within_Window(Data0, Data4, Data8, DataC);
13452 if (Data0 > 0x14)
13453 return;
13454
13455 pSprite->field_38 = eSprite_Anim_Die4;
13456 }
13457
Sprite_Handle_Spider_Mine(sSprite * pSprite)13458 void cFodder::Sprite_Handle_Spider_Mine(sSprite* pSprite) {
13459 int16 Data0, Data4, Data8, DataC, Data10;
13460 sSprite* Data14 = 0;
13461
13462 if (pSprite->field_38)
13463 goto loc_1DC50;
13464
13465 pSprite->field_8 = 0xE2;
13466 if (!pSprite->field_2E) {
13467 pSprite->field_2E = -1;
13468 Data0 = tool_RandomGet() & 0x1E;
13469 pSprite->field_2A = Data0;
13470 }
13471
13472 Data0 = pSprite->field_2A;
13473 Data0 += 2;
13474 Data0 &= 0x1E;
13475 pSprite->field_2A = Data0;
13476
13477 pSprite->field_A = mSprite_SpiderMine_Frames[Data0 / 2];
13478 Data14 = mSquad_Leader;
13479
13480 if (Data14 == INVALID_SPRITE_PTR)
13481 return;
13482
13483 Data0 = Data14->field_0;
13484 Data4 = Data14->field_4;
13485 Data8 = pSprite->field_0;
13486 Data8 += 4;
13487 DataC = pSprite->field_4;
13488 DataC -= 2;
13489 Data10 = 0x20;
13490 Map_Get_Distance_BetweenPoints_Within_Window(Data0, Data4, Data8, DataC);
13491 if (Data0 > 0x0A)
13492 return;
13493
13494 loc_1DC50:;
13495 pSprite->field_18 = eSprite_Explosion;
13496 pSprite->field_26 = -32763;
13497 pSprite->field_28 = -3;
13498 }
13499
Sprite_Handle_Bonus_RankToGeneral(sSprite * pSprite)13500 void cFodder::Sprite_Handle_Bonus_RankToGeneral(sSprite* pSprite) {
13501 int16 Data0;
13502
13503 // Blow up?
13504 if (pSprite->field_38) {
13505 pSprite->field_18 = eSprite_Explosion;
13506 return;
13507 }
13508
13509 pSprite->field_8 = 0x95;
13510 pSprite->field_A = 0x0F;
13511 if (Map_Get_Distance_Between_Sprite_And_Squadleader(pSprite, Data0))
13512 return;
13513
13514 mSquad_Leader->field_46_mission_troop->mRank = 0x0F;
13515 mGUI_Sidebar_Setup = 0;
13516
13517 Sprite_Destroy_Wrapper(pSprite);
13518 }
13519
13520
Sprite_Handle_Bonus_Rockets(sSprite * pSprite)13521 void cFodder::Sprite_Handle_Bonus_Rockets(sSprite* pSprite) {
13522 int16 Data0;
13523
13524 // Blow up?
13525 if (pSprite->field_38) {
13526 pSprite->field_18 = eSprite_Explosion;
13527 return;
13528 }
13529
13530 pSprite->field_8 = 0xE4;
13531 pSprite->field_A = 0;
13532 if (Map_Get_Distance_Between_Sprite_And_Squadleader(pSprite, Data0))
13533 return;
13534
13535 // Has Homing missiles
13536 mSquad_Leader->field_75 |= eSprite_Flag_HomingMissiles;
13537 mGUI_RefreshSquadRockets[mSquad_Selected] = -1;
13538 mSquad_Rockets[mSquad_Selected] = 50;
13539
13540 Sprite_Destroy_Wrapper(pSprite);
13541 }
13542
Sprite_Handle_Bonus_Armour(sSprite * pSprite)13543 void cFodder::Sprite_Handle_Bonus_Armour(sSprite* pSprite) {
13544 if (pSprite->field_38) {
13545 pSprite->field_18 = eSprite_Explosion;
13546 return;
13547 }
13548
13549 pSprite->field_8 = 0xE3;
13550 pSprite->field_A = 0;
13551 int16 Data0;
13552 if (Map_Get_Distance_Between_Sprite_And_Squadleader(pSprite, Data0))
13553 return;
13554
13555 mSquad_Leader->field_75 |= eSprite_Flag_Invincibility;
13556
13557 Sprite_Destroy_Wrapper(pSprite);
13558 }
13559
Sprite_Handle_Bonus_RankHomingInvin_SquadLeader(sSprite * pSprite)13560 void cFodder::Sprite_Handle_Bonus_RankHomingInvin_SquadLeader(sSprite* pSprite) {
13561 if (pSprite->field_38) {
13562 pSprite->field_18 = eSprite_Explosion;
13563 return;
13564 }
13565
13566 int16 Data0 = 0;
13567 pSprite->field_8 = 0xE5;
13568 pSprite->field_A = 0;
13569 if (Map_Get_Distance_Between_Sprite_And_Squadleader(pSprite, Data0))
13570 return;
13571
13572 // Invincible + HomingMissiles
13573 mSquad_Leader->field_75 |= (eSprite_Flag_HomingMissiles | eSprite_Flag_Invincibility);
13574 mSquad_Leader->field_46_mission_troop->mRank = 0x0F;
13575 mGUI_Sidebar_Setup = 0;
13576
13577 mGUI_RefreshSquadRockets[mSquad_Selected] = -1;
13578 mSquad_Rockets[mSquad_Selected] = 50;
13579
13580 Sprite_Destroy_Wrapper(pSprite);
13581 }
13582
Sprite_Handle_MissileHoming2(sSprite * pSprite)13583 void cFodder::Sprite_Handle_MissileHoming2(sSprite* pSprite) {
13584
13585 Sprite_Handle_MissileHoming(pSprite);
13586 }
13587
Sprite_Handle_Bonus_RankHomingInvin_Squad(sSprite * pSprite)13588 void cFodder::Sprite_Handle_Bonus_RankHomingInvin_Squad(sSprite* pSprite) {
13589
13590 if (pSprite->field_38) {
13591 pSprite->field_18 = eSprite_Explosion;
13592 return;
13593 }
13594
13595 int16 Data0 = 0;
13596 pSprite->field_8 = 0xE6;
13597 pSprite->field_A = 0;
13598 if (Map_Get_Distance_Between_Sprite_And_Squadleader(pSprite, Data0))
13599 return;
13600
13601 if (mSquad_Selected < 0)
13602 return;
13603
13604 sSprite** Data28 = mSquads[mSquad_Selected];
13605 for (; *Data28 != INVALID_SPRITE_PTR;) {
13606
13607 sSprite* Data2C = *Data28++;
13608 Data2C->field_75 |= (eSprite_Flag_HomingMissiles | eSprite_Flag_Invincibility);
13609
13610 Data2C->field_46_mission_troop->mRank = 0x0F;
13611 }
13612
13613 mGUI_Sidebar_Setup = 0;
13614 mGUI_RefreshSquadRockets[mSquad_Selected] = -1;
13615 mSquad_Rockets[mSquad_Selected] = 0x32;
13616
13617 Sprite_Destroy_Wrapper(pSprite);
13618 }
13619
Sprite_Handle_Helicopter_CallPad(sSprite * pSprite)13620 void cFodder::Sprite_Handle_Helicopter_CallPad(sSprite* pSprite) {
13621 sSprite* Data2C = 0;
13622
13623 pSprite->field_8 = 0xE7;
13624 pSprite->field_2C = eSprite_Draw_First;
13625
13626 // Find a troop inrange
13627 if (Sprite_Handle_Helicopter_Callpad_InRange(pSprite, Data2C)) {
13628 pSprite->field_75 = 0;
13629 }
13630 else {
13631 ++mHelicopterCallPadPressedCount;
13632
13633 if (!pSprite->field_75) {
13634 mTroop_InRange_Callpad = Data2C;
13635 pSprite->field_75 = -1;
13636 }
13637 }
13638
13639 if (mHelicopterCall_X < 0) {
13640 pSprite->field_A = 0;
13641 return;
13642 }
13643
13644 int16 Data0 = pSprite->field_32;
13645 Data0 += 2;
13646 Data0 &= 6;
13647
13648 pSprite->field_A = mSprite_Helicopter_CallPad_Frames[Data0 / 2];
13649 pSprite->field_32 = Data0;
13650 }
13651
Sprite_Handle_BuildingDoor_Reinforced(sSprite * pSprite)13652 void cFodder::Sprite_Handle_BuildingDoor_Reinforced(sSprite* pSprite) {
13653 if (pSprite->field_38 != eSprite_Anim_Die3) {
13654 Sprite_Handle_BuildingDoor3(pSprite);
13655 return;
13656 }
13657
13658 if (pSprite->field_74 >= 0x69) {
13659 Sprite_Handle_BuildingDoor3(pSprite);
13660 return;
13661 }
13662
13663 pSprite->field_74 += 1;
13664 pSprite->field_38 = eSprite_Anim_None;
13665 Sprite_Handle_BuildingDoor3(pSprite);
13666 }
13667
Sprite_Handle_Helicopter_Grenade2_Human_Called(sSprite * pSprite)13668 void cFodder::Sprite_Handle_Helicopter_Grenade2_Human_Called(sSprite* pSprite) {
13669 Sprite_Handle_Helicopter_Human_CallCheck(pSprite);
13670 Sprite_Handle_Helicopter_Grenade2_Human(pSprite);
13671
13672 }
13673
Sprite_Handle_Helicopter_Grenade_Human_Called(sSprite * pSprite)13674 void cFodder::Sprite_Handle_Helicopter_Grenade_Human_Called(sSprite* pSprite) {
13675 Sprite_Handle_Helicopter_Human_CallCheck(pSprite);
13676 Sprite_Handle_Helicopter_Grenade_Human(pSprite);
13677 }
13678
Sprite_Handle_Helicopter_Missile_Human_Called(sSprite * pSprite)13679 void cFodder::Sprite_Handle_Helicopter_Missile_Human_Called(sSprite* pSprite) {
13680 Sprite_Handle_Helicopter_Human_CallCheck(pSprite);
13681 Sprite_Handle_Helicopter_Missile_Human(pSprite);
13682 }
13683
Sprite_Handle_Helicopter_Homing_Human_Called(sSprite * pSprite)13684 void cFodder::Sprite_Handle_Helicopter_Homing_Human_Called(sSprite* pSprite) {
13685 Sprite_Handle_Helicopter_Human_CallCheck(pSprite);
13686 Sprite_Handle_Helicopter_Homing_Human(pSprite);
13687 }
13688
Sprite_Handle_Enemy_Leader(sSprite * pSprite)13689 void cFodder::Sprite_Handle_Enemy_Leader(sSprite* pSprite) {
13690
13691 Sprite_Handle_Hostage(pSprite);
13692 }
13693
Sprite_Handle_Helicopter_Homing_Enemy2(sSprite * pSprite)13694 void cFodder::Sprite_Handle_Helicopter_Homing_Enemy2(sSprite* pSprite) {
13695
13696 Sprite_Handle_Helicopter_Homing_Enemy(pSprite);
13697 }
13698
Sprite_Handle_Computer_1(sSprite * pSprite)13699 void cFodder::Sprite_Handle_Computer_1(sSprite* pSprite) {
13700
13701 Sprite_Handle_Computer(pSprite, 0x46);
13702 }
13703
Sprite_Handle_Computer_2(sSprite * pSprite)13704 void cFodder::Sprite_Handle_Computer_2(sSprite* pSprite) {
13705
13706 Sprite_Handle_Computer(pSprite, 0x69);
13707 }
13708
Sprite_Handle_Computer_3(sSprite * pSprite)13709 void cFodder::Sprite_Handle_Computer_3(sSprite* pSprite) {
13710
13711 Sprite_Handle_Computer(pSprite, 0xAF);
13712 }
13713
Sprite_Handle_UFO_Callpad(sSprite * pSprite)13714 void cFodder::Sprite_Handle_UFO_Callpad(sSprite* pSprite) {
13715
13716 if (mHelicopterCall_X > 0) {
13717
13718 mSwitchesActivated = true;
13719 pSprite->field_8 = 0xE8;
13720 pSprite->field_A = 0;
13721
13722 sSprite* Data24 = pSprite + 1;
13723 Data24->field_8 = 0x8D;
13724 Data24->field_A = 0x01;
13725 if (pSprite->field_20 >= 0x14)
13726 pSprite->field_1E_Big -= 0xC000;
13727
13728 int16 Data0 = mHelicopterCall_X;
13729 int16 Data4 = mHelicopterCall_Y - 0x28;
13730
13731 Sprite_Direction_Between_Points(pSprite, Data0, Data4);
13732
13733 Data0 = mHelicopterCall_X;
13734 Data4 = mHelicopterCall_Y - 0x28;
13735 int16 Data8 = pSprite->field_0;
13736 int16 DataC = pSprite->field_4;
13737 int16 Data10 = 0x60;
13738
13739 Data0 = Map_Get_Distance_BetweenPoints(Data0, Data4, Data8, Data10, DataC);
13740 Data0 >>= 3;
13741 Data0 += 1;
13742 if (Data0 < 8)
13743 Data0 = 8;
13744
13745 pSprite->field_36 = Data0;
13746 Sprite_Movement_Calculate(pSprite);
13747 Sprite_PositionNext_AdjustByHeight(pSprite);
13748 } else {
13749 // loc_2DBE8
13750 pSprite->field_8 = 0x7C;
13751 pSprite->field_A = 0;
13752
13753 sSprite* Data24 = pSprite + 1;
13754 Data24->field_8 = 0x7C;
13755 Data24->field_A = 0;
13756
13757 if (mSquad_Leader && mSquad_Leader != INVALID_SPRITE_PTR) {
13758
13759 pSprite->field_0 = mSquad_Leader->field_0 + 0x190;
13760 pSprite->field_4 = mSquad_Leader->field_4;
13761 }
13762
13763 pSprite->field_20 = 0x64;
13764 Sprite_PositionNext_AdjustByHeight(pSprite);
13765 }
13766 }
13767
Sprite_Handle_Turret_Cannon_Invulnerable(sSprite * pSprite)13768 void cFodder::Sprite_Handle_Turret_Cannon_Invulnerable(sSprite* pSprite) {
13769
13770 if (pSprite->field_38 == eSprite_Anim_Die1)
13771 pSprite->field_38 = eSprite_Anim_None;
13772
13773 pSprite->field_22 = eSprite_PersonType_AI;
13774 pSprite->field_6F = eVehicle_Turret_Cannon;
13775
13776 Sprite_Handle_Turret(pSprite);
13777 }
13778
Sprite_Handle_Turret_Missile_Invulnerable(sSprite * pSprite)13779 void cFodder::Sprite_Handle_Turret_Missile_Invulnerable(sSprite* pSprite) {
13780
13781 if (pSprite->field_38 == eSprite_Anim_Die1)
13782 pSprite->field_38 = eSprite_Anim_None;
13783
13784 pSprite->field_22 = eSprite_PersonType_AI;
13785 pSprite->field_6F = eVehicle_Turret_Missile;
13786
13787 Sprite_Handle_Turret(pSprite);
13788 }
13789
Sprite_Handle_Looping_Vehicle_Left(sSprite * pSprite)13790 void cFodder::Sprite_Handle_Looping_Vehicle_Left(sSprite* pSprite) {
13791
13792 pSprite->field_6F = eVehicle_DontTargetPlayer;
13793
13794 if (pSprite->field_0 <= 6) {
13795 pSprite->field_0 = mMapLoaded->getWidthPixels() - 4;
13796 pSprite->field_75 = 0;
13797 }
13798
13799 pSprite->field_26 = pSprite->field_0 - 0x28;
13800 Sprite_Handle_Vehicle_Enemy(pSprite);
13801
13802 if (tool_RandomGet() & 0x0F)
13803 return;
13804
13805 int16 Saved_F0 = pSprite->field_0;
13806 int16 Saved_F4 = pSprite->field_4;
13807
13808 int16 Data0 = (tool_RandomGet() & 0x07) + 0x0A;
13809 pSprite->field_0 += Data0;
13810 pSprite->field_4 += -8;
13811 if (pSprite->field_4 < 0)
13812 pSprite->field_4 = 0;
13813
13814 if (!Sprite_Create_Cannon(pSprite)) {
13815 Sound_Play(pSprite, 0x10, 0x1E);
13816 }
13817
13818 pSprite->field_0 = Saved_F0;
13819 pSprite->field_4 = Saved_F4;
13820 }
13821
Sprite_Handle_Looping_Vehicle_Right(sSprite * pSprite)13822 void cFodder::Sprite_Handle_Looping_Vehicle_Right(sSprite* pSprite) {
13823
13824 pSprite->field_6F = eVehicle_DontTargetPlayer;
13825
13826 if (pSprite->field_0 >= mMapLoaded->getWidthPixels()) {
13827 pSprite->field_0 = 0;
13828 pSprite->field_75 = 0;
13829 }
13830
13831 pSprite->field_26 = pSprite->field_0 + 0x28;
13832 Sprite_Handle_Vehicle_Enemy(pSprite);
13833 }
13834
Sprite_Handle_Looping_Vehicle_Up(sSprite * pSprite)13835 void cFodder::Sprite_Handle_Looping_Vehicle_Up(sSprite* pSprite) {
13836
13837 pSprite->field_6F = eVehicle_DontTargetPlayer;
13838
13839 if (pSprite->field_4 <= 6) {
13840 pSprite->field_4 = mMapLoaded->getHeightPixels() - 4;
13841 pSprite->field_75 = 0;
13842 }
13843
13844 pSprite->field_28 = pSprite->field_4 - 0x28;
13845 Sprite_Handle_Vehicle_Enemy(pSprite);
13846 }
13847
Sprite_Handle_Looping_Vehicle_Down(sSprite * pSprite)13848 void cFodder::Sprite_Handle_Looping_Vehicle_Down(sSprite* pSprite) {
13849
13850 pSprite->field_6F = eVehicle_DontTargetPlayer;
13851
13852 if (pSprite->field_4 >= mMapLoaded->getHeightPixels()) {
13853 pSprite->field_4 = 0;
13854 pSprite->field_75 = 0;
13855 }
13856
13857 pSprite->field_28 = pSprite->field_4 + 0x28;
13858 Sprite_Handle_Vehicle_Enemy(pSprite);
13859 }
13860
Sprite_PositionNext_AdjustByHeight(sSprite * pSprite)13861 void cFodder::Sprite_PositionNext_AdjustByHeight(sSprite* pSprite) {
13862 sSprite* Data24 = pSprite + 1;
13863
13864 Data24->field_0 = pSprite->field_0 + 8;
13865 Data24->field_4 = pSprite->field_4;
13866
13867 Data24->field_0 += (pSprite->field_20 >> 2);
13868 Data24->field_4 += (pSprite->field_20 >> 2);
13869 Data24->field_2C = eSprite_Draw_First;
13870 }
13871
sub_1D92E(sSprite * pSprite)13872 int16 cFodder::sub_1D92E(sSprite* pSprite) {
13873 int16 Data0, Data4;
13874
13875 if (pSprite->field_38 == eSprite_Anim_Die3)
13876 goto loc_1D95B;
13877
13878 if (pSprite->field_38 == eSprite_Anim_Die2)
13879 goto loc_1D9C9;
13880
13881 if (pSprite->field_58)
13882 goto loc_1D9C9;
13883
13884 return 0;
13885
13886 loc_1D95B:;
13887 pSprite->field_38 = eSprite_Anim_Die2;
13888 pSprite->field_8 = 0xE0;
13889
13890 Data0 = tool_RandomGet();
13891 Data4 = Data0;
13892 Data0 &= 0x1E;
13893 if (Data4 < 0)
13894 Data0 = -Data0;
13895
13896 Data0 += 0x1C0;
13897 pSprite->field_10 = Data0;
13898
13899 Data4 &= 3;
13900 Data4 += 5;
13901
13902 pSprite->field_44 = (int8)Data4;
13903 pSprite->field_36 = 0x78;
13904 pSprite->field_58 = -1;
13905
13906 loc_1D9C9:;
13907 pSprite->field_44 -= 1;
13908 if (!pSprite->field_44)
13909 goto loc_1DA13;
13910
13911 Sprite_Movement_Calculate(pSprite);
13912 if (mSprite_Bullet_Destroy)
13913 goto loc_1DA13;
13914
13915 Data0 = -3;
13916 Data4 = 2;
13917 if (Map_Terrain_Get_Type_And_Walkable(pSprite, Data0, Data4))
13918 goto loc_1DA13;
13919
13920 if (pSprite->field_36 <= 0)
13921 goto loc_1DA13;
13922
13923 return -1;
13924
13925 loc_1DA13:;
13926 pSprite->field_0 -= 8;
13927 if (pSprite->field_0 < 0)
13928 pSprite->field_0 = 0;
13929
13930 pSprite->field_4 -= 8;
13931 Sprite_Turn_Into_Building_Explosion(pSprite);
13932 return -1;
13933 }
13934
Sprite_Native_Sound_Play(sSprite * pSprite,int16 pSoundID)13935 void cFodder::Sprite_Native_Sound_Play(sSprite* pSprite, int16 pSoundID) {
13936
13937 if (mPhase_Completed_Timer)
13938 return;
13939
13940 if ((tool_RandomGet() & 0x7F) != 0x0E)
13941 return;
13942
13943 int16 Data8 = 0;
13944
13945 if (mMapLoaded->getTileType() == eTileTypes_Int || mMapLoaded->getTileType() == eTileTypes_Moors)
13946 Data8 = 0x7F;
13947
13948 Sound_Play(pSprite, pSoundID, Data8);
13949 }
13950
Sprite_Handle_Soldier_Animation(sSprite * pSprite)13951 int16 cFodder::Sprite_Handle_Soldier_Animation(sSprite* pSprite) {
13952 int32 Dataa4;
13953 int16 Data0, Data4, Data8;
13954 const int16* Data28;
13955 sSprite* Data20 = 0, *Data2C = 0, *Data30 = 0;
13956 int16 Field_52;
13957 int16 Field_0;
13958 int16 Field_4;
13959
13960 if (pSprite->field_38 == eSprite_Anim_Hit3)
13961 goto loc_1E831;
13962
13963 if (pSprite->field_38 == eSprite_Anim_Die2)
13964 goto loc_1EA48;
13965
13966 if (pSprite->field_38 == eSprite_Anim_Hit2)
13967 goto loc_1EB87;
13968
13969 Data0 = pSprite->field_4;
13970 if (Data0 >= mMapLoaded->getHeightPixels())
13971 pSprite->field_4 = mMapLoaded->getHeightPixels();
13972
13973 //loc_1E0A4
13974 if (pSprite->field_56)
13975 goto loc_1E831;
13976
13977 if (pSprite->field_5B == 1)
13978 goto loc_1E74C;
13979
13980 if (pSprite->field_38 == eSprite_Anim_Die5)
13981 goto loc_1E2F4;
13982
13983 if (pSprite->field_38 == eSprite_Anim_Slide1)
13984 goto loc_1ECA6;
13985
13986 if (pSprite->field_38 == eSprite_Anim_Slide2)
13987 goto loc_1ED5B;
13988
13989 if (pSprite->field_38 == eSprite_Anim_Slide3)
13990 goto loc_1EE59;
13991
13992 if (pSprite->field_38 == eSprite_Anim_Vehicle_Enter)
13993 goto Sprite_EnteringVehicle;
13994
13995 if (pSprite->field_38 == eSprite_Anim_Vehicle_Inside)
13996 goto Sprite_EnteredVehicle;
13997
13998 //seg004:53BD
13999 // Is Sprite Dying
14000 if (!pSprite->field_38)
14001 goto loc_1EA3F;
14002
14003 if (!pSprite->field_64)
14004 goto loc_1E3D2;
14005
14006 pSprite->field_64 = 0;
14007 if (mPhase_TryAgain)
14008 pSprite->field_40 = -26506;
14009
14010 if (!pSprite->field_58) {
14011 Sprite_Create_Player_Shadow(pSprite);
14012 pSprite->field_58 = -1;
14013 }
14014
14015 //loc_1E15D
14016 Data8 = pSprite->field_10;
14017 Data8 >>= 5;
14018 Data8 -= 1;
14019 Data8 ^= 0x0F;
14020 Data8 &= 0x0E;
14021 Data0 = pSprite->field_22;
14022
14023 Data28 = mSprite_AnimationPtrs[Data0];
14024 pSprite->field_8 = Data28[(Data8 + 0x20) / 2];
14025
14026 if (pSprite->field_59)
14027 pSprite->field_8 = Data28[(Data8 + 0x10) / 2];
14028
14029 //loc_1E1E9
14030 pSprite->field_A = 0;
14031 pSprite->field_2A = 0;
14032
14033 if (pSprite->field_1A < 0xB0000) {
14034 int32 Dataa0 = tool_RandomGet() & 0x07;
14035 Dataa0 += 2;
14036 Dataa0 = (Dataa0 << 16) | (Dataa0 >> 16);
14037 Dataa0 += pSprite->field_1A;
14038
14039 pSprite->field_1A = Dataa0;
14040 }
14041 //loc_1E232
14042 pSprite->field_12 = 2;
14043 Data0 = tool_RandomGet();
14044 Data4 = 0;
14045 Data0 &= 7;
14046 Data4 = mSprite_Civilian_Sound_Death[Data0];
14047 //seg004:5508
14048 Sound_Play(pSprite, Data4, 0x14);
14049
14050 if (pSprite->field_36 < 0x1E)
14051 pSprite->field_36 += 0x0F;
14052
14053 pSprite->field_3E = pSprite->field_10;
14054 pSprite->field_3A = -1;
14055 Data0 = tool_RandomGet() & 0x01;
14056 if (!Data0)
14057 pSprite->field_3A = pSprite->field_10;
14058
14059 Sprite_Create_BloodTrail(pSprite, Data2C, Data30);
14060 pSprite->field_26 = -1;
14061 if (pSprite->field_38 != eSprite_Anim_Die4)
14062 goto loc_1E3D2;
14063
14064 // Die on spike
14065 pSprite->field_36 = 0;
14066 pSprite->field_38 = eSprite_Anim_Die5;
14067 loc_1E2F4:;
14068 pSprite->field_3A -= 1;
14069 if (pSprite->field_3A < 0) {
14070 pSprite->field_38 = eSprite_Anim_Hit;
14071 return -1;
14072 }
14073 //loc_1E30C
14074 Data0 = 0x21;
14075 if (pSprite->field_22 != eSprite_PersonType_Human)
14076 Data0 = 0x63;
14077
14078 pSprite->field_8 = Data0;
14079 Data0 = pSprite->field_2A & 7;
14080 //seg004:55F3
14081
14082 if (!Data0) {
14083 sSprite* Data2C = 0;
14084 Data30 = 0;
14085
14086 Sprite_Create_BloodTrail(pSprite, Data2C, Data30);
14087
14088 if (pSprite->field_A)
14089 pSprite->field_A = 0;
14090 else
14091 pSprite->field_A = 1;
14092 }
14093 //loc_1E36C
14094
14095 pSprite->field_2A -= 1;
14096 if (pSprite->field_2A >= 0)
14097 return -1;
14098
14099 Data0 = tool_RandomGet() & 7;
14100 Data0 += 8;
14101 pSprite->field_2A = Data0;
14102 Data0 = tool_RandomGet() & 7;
14103
14104 Data4 = mSprite_Civilian_Sound_Death[Data0];
14105 Data8 = 0;
14106 Sound_Play(pSprite, Data4, Data8);
14107 return -1;
14108
14109 loc_1E3D2:;
14110
14111 if (pSprite->field_40 == -26506) {
14112 sSprite* Data2C = 0;
14113 Data30 = 0;
14114
14115 pSprite->field_28 += 1;
14116 Sprite_Create_BloodTrail(pSprite, Data2C, Data30);
14117
14118 if (!(pSprite->field_28 & 7)) {
14119 Data0 = tool_RandomGet() & 7;
14120 Data4 = mSprite_Civilian_Sound_Death[Data0];
14121 Data8 = 0x14;
14122 Sound_Play(pSprite, Data4, Data8);
14123 }
14124 }
14125 //loc_1E437
14126
14127 if (pSprite->field_3A >= 0) {
14128 pSprite->field_3E = pSprite->field_3A;
14129
14130 Data0 = pSprite->field_36 << 2;
14131 pSprite->field_3A += Data0;
14132 //seg004:5724
14133 pSprite->field_3A &= 0x1FE;
14134 Data8 = pSprite->field_3A;
14135
14136 Data8 >>= 5;
14137 Data8 -= 1;
14138 Data8 ^= 0x0F;
14139 Data8 &= 0x0E;
14140
14141 Data28 = mSprite_AnimationPtrs[pSprite->field_22];
14142 pSprite->field_8 = Data28[(Data8 + 0x20) / 2];
14143
14144 if (pSprite->field_59)
14145 pSprite->field_8 = Data28[(Data8 + 0x10) / 2];
14146
14147 // FIX: Added as only 2 frames exist for all sprites in mSprite_AnimationPtrs
14148 pSprite->field_A %= 2;
14149 }
14150 //loc_1E50A
14151 Sprite_XY_Store(pSprite);
14152 mTmp_FrameNumber = pSprite->field_A;
14153 Sprite_Movement_Calculate(pSprite);
14154
14155 if (pSprite->field_20 < 0x0C) {
14156
14157 int16 Field10 = pSprite->field_10;
14158 Sprite_Terrain_Check(pSprite, Data4);
14159 pSprite->field_10 = Field10;
14160 }
14161 else {
14162 //loc_1E542
14163 int16 Field0 = pSprite->field_0;
14164 int16 Field4 = pSprite->field_4;
14165 int16 Field10 = pSprite->field_10;
14166
14167 Sprite_Terrain_Check(pSprite, Data4);
14168
14169 pSprite->field_10 = Field10;
14170 pSprite->field_4 = Field4;
14171 pSprite->field_0 = Field0;
14172 }
14173
14174 //loc_1E579
14175 if (!pSprite->field_20) {
14176 if (pSprite->field_4F || pSprite->field_50) {
14177 pSprite->field_52 = 6;
14178 }
14179 }
14180 //loc_1E5A7
14181 Dataa4 = (int64)pSprite->field_1A;
14182
14183 pSprite->field_1E_Big += pSprite->field_1A;
14184
14185 if (pSprite->field_1E_Big < 0) {
14186 pSprite->field_1E_Big = 0;
14187
14188 Dataa4 = -Dataa4;
14189 Dataa4 >>= 2;
14190
14191 if (pSprite->field_52) {
14192 pSprite->field_36 = 0;
14193 Dataa4 = 0;
14194 }
14195 }
14196 //loc_1E619
14197 Dataa4 -= 0x18000;
14198 pSprite->field_1A = Dataa4;
14199 if (pSprite->field_36) {
14200 pSprite->field_36 -= 2;
14201
14202 if (pSprite->field_36 < 0)
14203 pSprite->field_36 = 0;
14204 }
14205 //loc_1E653
14206 if (pSprite->field_26) {
14207
14208 if (!pSprite->field_20) {
14209 sSprite* Data2C = 0;
14210 Data30 = 0;
14211 Sprite_Create_BloodTrail(pSprite, Data2C, Data30);
14212 pSprite->field_26 = 0;
14213 }
14214 }
14215 //loc_1E67A
14216 pSprite->field_12 -= 1;
14217 if (!pSprite->field_12) {
14218
14219 pSprite->field_12 = 6;
14220 if (pSprite->field_A < 1)
14221 pSprite->field_A += 1;
14222 }
14223 //loc_1E6A3
14224 if (pSprite->field_2A <= 0x14) {
14225
14226 pSprite->field_2A++;
14227 return -1; // DOS version jumped to loc_1EB5D; here, which was different from Amiga and caused a bug
14228 }
14229 //loc_1E6BA
14230 if (pSprite->field_20)
14231 return -1; // DOS version jumped to loc_1EB5D; here, which was different from Amiga and caused a bug
14232
14233 //seg004:5978
14234 if (!pSprite->field_52) {
14235 if (!pSprite->field_50) {
14236
14237 Data0 = tool_RandomGet() & 0x7F;
14238 if (!Data0) {
14239
14240 pSprite->field_3A = 0x1F4;
14241 pSprite->field_38 = eSprite_Anim_Die5;
14242 mGUI_Sidebar_Setup = 0;
14243 return -1;
14244 }
14245 }
14246 }
14247 //loc_1E708
14248 pSprite->field_38 = eSprite_Anim_Die2;
14249 pSprite->field_10 = pSprite->field_3E;
14250 pSprite->field_12 = 0;
14251 pSprite->field_45 = 1;
14252
14253 return -1;
14254
14255 loc_1E74C:;
14256 if (pSprite->field_52 < 5) {
14257 pSprite->field_52 = 5;
14258 Data4 = 0x0E;
14259 Data8 = 0x0A;
14260
14261 Sound_Play(pSprite, Data4, Data8);
14262 pSprite->field_8 = 0x38;
14263 if (pSprite->field_22 != eSprite_PersonType_Human)
14264 pSprite->field_8 = 0x7A;
14265
14266 pSprite->field_A = 0;
14267 pSprite->field_12 = 0x0A;
14268
14269 return 1;
14270 }
14271 //loc_1E7AC
14272 pSprite->field_12 -= 1;
14273 if (!pSprite->field_12) {
14274
14275 pSprite->field_52 += 1;
14276 if (pSprite->field_52 >= 0x0D) {
14277
14278 pSprite->field_38 = eSprite_Anim_Die2;
14279 pSprite->field_10 = pSprite->field_3E;
14280 pSprite->field_12 = 0;
14281 pSprite->field_45 = 1;
14282
14283 goto loc_1E825;
14284 }
14285 else {
14286 pSprite->field_12 = 0x0A;
14287 }
14288 }
14289 //loc_1E806
14290 if (!(pSprite->field_12 & 2) && pSprite->field_A < 5)
14291 pSprite->field_A += 1;
14292 loc_1E825:;
14293 Data0 = -1;
14294 return -1;
14295
14296 loc_1E831:;
14297 if (pSprite->field_56 == 1) {
14298 pSprite->field_12 = 1;
14299 pSprite->field_28 += 2;
14300 }
14301 Data0 = pSprite->field_12;
14302 pSprite->field_12 += 1;
14303
14304 if (pSprite->field_38 == eSprite_Anim_Hit3) {
14305 pSprite->field_52 += Data0;
14306
14307 if (pSprite->field_52 < 0x0E)
14308 return -1;
14309
14310 pSprite->field_52 = 0x0E;
14311 pSprite->field_12 = 0x14;
14312 Data0 = tool_RandomGet() & 0x07;
14313 Data4 = mSprite_Civilian_Sound_Death[Data0];
14314 Data8 = 0x0A;
14315 Sound_Play(pSprite, Data4, Data8);
14316 goto loc_1E9EC;
14317 }
14318 //loc_1E8D6
14319 pSprite->field_4 += Data0;
14320 Data0 = pSprite->field_4;
14321 if (Data0 >= mMapLoaded->getHeightPixels())
14322 pSprite->field_38 = eSprite_Anim_Hit2;
14323
14324 mStoredSpriteY = pSprite->field_4;
14325 Data0 = 8;
14326 Data0 += pSprite->field_26;
14327 Data4 = -3;
14328 Data4 += pSprite->field_28;
14329
14330 Map_Terrain_Get_Type_And_Walkable(Data0, Data4);
14331
14332 if (Data4 == eTerrainFeature_Drop || Data4 == eTerrainFeature_Drop2) {
14333 Data0 = pSprite->field_12;
14334 pSprite->field_28 += Data0;
14335 Data8 = pSprite->field_28;
14336
14337 sMapTarget* WalkTarget = mSquad_WalkTargets[pSprite->field_32];
14338 //seg004:5C49
14339 Data0 = pSprite->field_40;
14340 if (WalkTarget[Data0].mX >= 0)
14341 WalkTarget[Data0].mY = Data8;
14342 }
14343 //loc_1E9CD;
14344 Sprite_Terrain_Check(pSprite, Data4);
14345 if (pSprite->field_12 > 5)
14346 sub_223B2(pSprite);
14347
14348 if (Data4 == 9)
14349 return -1;
14350
14351 loc_1E9EC:; // Troop Falling?
14352 if (pSprite->field_12 < 0x0C) {
14353 pSprite->field_3E = 0;
14354 pSprite->field_56 = 0;
14355
14356 return 0;
14357 }
14358
14359 pSprite->field_38 = eSprite_Anim_Die2;
14360 pSprite->field_10 = pSprite->field_3E;
14361 pSprite->field_12 = 0;
14362 pSprite->field_45 = 1;
14363 return -1;
14364
14365 loc_1EA3F:;
14366 Data0 = 0;
14367 return 0;
14368
14369 loc_1EA48:;
14370 pSprite->field_12 += 1;
14371 if (pSprite->field_12 >= 0x0F)
14372 return Sprite_Troop_Dies(pSprite);
14373
14374 if (pSprite->field_12 >= 0x07 && pSprite->field_8 != 0x7C) {
14375 pSprite->field_8 = 0x7C;
14376 goto loc_1EB0E;
14377 }
14378
14379 loc_1EA82:;
14380 Data8 = pSprite->field_10;
14381 Data8 >>= 5;
14382 Data8 -= 1;
14383 Data8 ^= 0x0F;
14384 Data8 &= 0x0E;
14385
14386 Data28 = mSprite_AnimationPtrs[pSprite->field_22];
14387 pSprite->field_8 = Data28[(Data8 + 0x20) / 2];
14388
14389 if (pSprite->field_59)
14390 pSprite->field_8 = Data28[(Data8 + 0x10) / 2];
14391
14392 // FIX: Added as only 2 frames exist for all sprites in mSprite_AnimationPtrs
14393 pSprite->field_A %= 2;
14394 loc_1EB0E:;
14395 Field_52 = pSprite->field_52;
14396 Field_0 = pSprite->field_0;
14397 Field_4 = pSprite->field_4;
14398 Sprite_Terrain_Check(pSprite, Data4);
14399 pSprite->field_4 = Field_4;
14400 pSprite->field_0 = Field_0;
14401 pSprite->field_52 = Field_52;
14402
14403 if (pSprite->field_4F || pSprite->field_50) {
14404
14405 if (pSprite->field_52 >= 0x0D)
14406 pSprite->field_52 = 0x0B;
14407
14408 pSprite->field_52 += 2;
14409 }
14410
14411 return -1;
14412
14413 loc_1EB87:;
14414 pSprite->field_12 += 1;
14415 if (pSprite->field_12 >= 0x0F)
14416 return Sprite_Troop_Dies(pSprite);
14417
14418 if (pSprite->field_12 < 0x07)
14419 goto loc_1EA82;
14420
14421 if (pSprite->field_8 != 0x7C) {
14422 pSprite->field_8 = 0x7C;
14423 goto loc_1EB0E;
14424 }
14425
14426 Data8 = pSprite->field_10;
14427 Data8 >>= 5;
14428 Data8 -= 1;
14429 Data8 ^= 0x0F;
14430 Data8 &= 0x0E;
14431
14432 Data28 = mSprite_AnimationPtrs[pSprite->field_22];
14433 pSprite->field_8 = Data28[(Data8 + 0x20) / 2];
14434
14435 if (pSprite->field_59)
14436 pSprite->field_8 = Data28[(Data8 + 0x10) / 2];
14437
14438 pSprite->field_A = 0;
14439 //loc_1EC4F
14440 Field_52 = pSprite->field_52;
14441 Sprite_Terrain_Check(pSprite, Data4);
14442 pSprite->field_52 = Field_52;
14443
14444 if (pSprite->field_4F || pSprite->field_50) {
14445 if (pSprite->field_52 >= 0x0D)
14446 pSprite->field_52 = 0x0B;
14447 pSprite->field_52 += 2;
14448 }
14449
14450 //loc_1EC9A
14451 return -1;
14452
14453 loc_1ECA6:;
14454 if (pSprite->field_60 <= eTerrainFeature_Water && pSprite->field_60 >= eTerrainFeature_QuickSand) {
14455 pSprite->field_38 = eSprite_Anim_None;
14456 return 0;
14457 }
14458
14459 pSprite->field_38 = eSprite_Anim_Slide2;
14460 pSprite->field_36 = 0x24;
14461
14462 Data0 = tool_RandomGet() & 6;
14463 Data0 = mSprite_Soldier_Unk[Data0];
14464
14465 Data0 += pSprite->field_10;
14466 Data0 &= 0x1FE;
14467 pSprite->field_10 = Data0;
14468 pSprite->field_8 = 0xA4;
14469
14470 if (pSprite->field_22 != eSprite_PersonType_Human)
14471 pSprite->field_8 = 0xA7;
14472
14473 Data8 = Sprite_Handle_Troop_Get_Frame_For_Direction(pSprite);
14474 Data8 >>= 1;
14475 pSprite->field_A = Data8;
14476 return -1;
14477
14478 loc_1ED5B:;
14479 Sprite_XY_Store(pSprite);
14480 mTmp_FrameNumber = pSprite->field_A;
14481
14482 Sprite_Movement_Calculate(pSprite);
14483 Sprite_Reached_MapEdge(pSprite);
14484 Sprite_Terrain_Check(pSprite, Data4);
14485
14486 if (pSprite->field_38 != eSprite_Anim_Slide2)
14487 goto loc_1EE3E;
14488
14489 if (pSprite->field_60 > eTerrainFeature_Water || pSprite->field_60 < eTerrainFeature_QuickSand) {
14490 pSprite->field_36 -= 5;
14491 if (pSprite->field_36) {
14492 if (pSprite->field_36 >= 0)
14493 return -1;
14494
14495 pSprite->field_36 = 0;
14496 }
14497 }
14498 Data8 = Sprite_Handle_Troop_Get_Frame_For_Direction(pSprite);
14499
14500 //seg004:606C
14501 Data28 = mSprite_AnimationPtrs[pSprite->field_22];
14502 Data0 = Data28[(0x60 + Data8) / 2];
14503
14504 if (Data0 != pSprite->field_8) {
14505 pSprite->field_8 = Data28[(0x60 + Data8) / 2];
14506 pSprite->field_A = 0;
14507 return -1;
14508 }
14509 //loc_1EE34
14510 pSprite->field_38 = eSprite_Anim_None;
14511
14512 loc_1EE3E:;
14513 pSprite->field_43 = 0;
14514 sub_305D5(Data20);
14515 return -1;
14516
14517 loc_1EE59:;
14518 if (pSprite->field_60 <= eTerrainFeature_Water && pSprite->field_60 >= eTerrainFeature_QuickSand) {
14519 pSprite->field_38 = eSprite_Anim_None;
14520 return 0;
14521 }
14522
14523 pSprite->field_38 = eSprite_Anim_Slide2;
14524 pSprite->field_36 = 0x2E;
14525
14526 Data0 = tool_RandomGet() & 0x1F;
14527
14528 pSprite->field_10 += Data0;
14529 pSprite->field_8 = 0xA4;
14530 if (pSprite->field_22 != eSprite_PersonType_Human)
14531 pSprite->field_8 = 0xA7;
14532
14533 Data8 = Sprite_Handle_Troop_Get_Frame_For_Direction(pSprite);
14534 Data8 >>= 1;
14535 pSprite->field_A = Data8;
14536 return -1;
14537
14538 Sprite_EnteringVehicle:;
14539
14540 // Not walking to a vehicle?
14541 if (!pSprite->field_66) {
14542 pSprite->field_38 = eSprite_Anim_None;
14543 return 0;
14544 }
14545
14546 pSprite->field_38 = eSprite_Anim_Vehicle_Inside;
14547 pSprite->field_8 = 0xCC;
14548 pSprite->field_A = 4;
14549 return -1;
14550
14551 Sprite_EnteredVehicle:;
14552 pSprite->field_A -= 1;
14553 if (pSprite->field_A < 0)
14554 return loc_1F043(pSprite);
14555
14556 pSprite->field_36 = 0x30;
14557 Sprite_Draw_Row_Update(pSprite);
14558 return -1;
14559
14560 }
14561
Sprite_Troop_Dies(sSprite * pSprite)14562 int16 cFodder::Sprite_Troop_Dies(sSprite* pSprite) {
14563 sMission_Troop* Troop = 0;
14564
14565 // Is Player?
14566 if (pSprite->field_22 == eSprite_PersonType_Human) {
14567 //Yes, is player
14568
14569 ++mGame_Data.mScore_Kills_Away;
14570
14571 if (pSprite->field_46_mission_troop) {
14572
14573 mGame_Data.Soldier_Died(pSprite->field_46_mission_troop);
14574
14575 pSprite->field_46_mission_troop->mSprite = INVALID_SPRITE_PTR;
14576 pSprite->field_46_mission_troop->mRecruitID = -1;
14577 pSprite->field_46_mission_troop->mRank = 0;
14578 }
14579
14580 if (mSquad_Selected < 0) {
14581 mGUI_Sidebar_Setup = 0;
14582 mSquad_Select_Timer = 0;
14583 }
14584 else {
14585 mGUI_Sidebar_Setup = 0;
14586 }
14587
14588 //loc_1F03D
14589 return Sprite_Destroy_Wrapper(pSprite);
14590 }
14591
14592 if (pSprite->field_18 == eSprite_Enemy_Rocket || pSprite->field_18 == eSprite_Enemy) {
14593
14594 ++mGame_Data.mScore_Kills_Home;
14595 --mTroops_Enemy_Count;
14596 if (pSprite->field_5D) {
14597 pSprite->field_5D = 0;
14598
14599 // Default to first human soldier
14600 Troop = mGame_Data.mSoldiers_Allocated;
14601
14602 if (pSprite->field_5E_SoldierAllocated) {
14603 Troop = pSprite->field_5E_SoldierAllocated;
14604 goto loc_1F1E9;
14605 }
14606 }
14607
14608 // Sprite didnt have a soldier who killed it attached
14609 if (mSquad_Selected != -1) {
14610 //loc_1F13E
14611 // use the first squad member
14612 if (mSquads[mSquad_Selected][0] != INVALID_SPRITE_PTR && mSquads[mSquad_Selected][0] != 0)
14613 Troop = mSquads[mSquad_Selected][0]->field_46_mission_troop;
14614 }
14615 loc_1F1E9:;
14616
14617 if (Troop >= mGame_Data.mSoldiers_Allocated && Troop <= &mGame_Data.mSoldiers_Allocated[8]) {
14618
14619 if (Troop->mNumberOfKills >= 999)
14620 Troop->mNumberOfKills = 998;
14621
14622 ++Troop->mNumberOfKills;
14623 }
14624 }
14625
14626 return Sprite_Destroy_Wrapper(pSprite);
14627 }
14628
loc_1F043(sSprite * pSprite)14629 int16 cFodder::loc_1F043(sSprite* pSprite) {
14630 if (!pSprite->field_66) {
14631 pSprite->field_38 = eSprite_Anim_None;
14632 return 0;
14633 }
14634
14635 loc_1F092(pSprite, (sSprite*)pSprite->field_66);
14636 pSprite->field_A = 0;
14637 pSprite->field_8 = 0x7C;
14638 pSprite->field_38 = eSprite_Anim_None;
14639 return 0;
14640 }
14641
loc_1F092(sSprite * pSprite,sSprite * pData24)14642 void cFodder::loc_1F092(sSprite* pSprite, sSprite* pData24) {
14643 int16 Data0 = pData24->field_0;
14644 Data0 += 0x10;
14645 if (pData24->field_6F == eVehicle_Turret_Cannon)
14646 goto loc_1F0B9;
14647
14648 if (pData24->field_6F == eVehicle_Turret_Missile)
14649 goto loc_1F0BE;
14650 loc_1F0B9:;
14651 Data0 -= 0x0C;
14652
14653 loc_1F0BE:;
14654
14655 int16 Data4 = pData24->field_4;
14656 Data4 -= 0x09;
14657
14658 pSprite->field_0 = Data0;
14659 pSprite->field_4 = Data4;
14660 }
14661
Sprite_Handle_Player_MissionOver(sSprite * pSprite)14662 int16 cFodder::Sprite_Handle_Player_MissionOver(sSprite* pSprite) {
14663
14664 if (!mPhase_Aborted)
14665 if (!mPhase_Complete)
14666 return 0;
14667
14668 int16 Data0 = -1;
14669 int16 Data4 = 8;
14670
14671 Map_Terrain_Get_Type_And_Walkable(pSprite, Data0, Data4);
14672
14673 if (Data4 == eTerrainFeature_Water) {
14674 Data0 = pSprite->field_20;
14675 Data0 -= 8;
14676
14677 if (Data0 >= 0) {
14678 Data0 = 0;
14679 }
14680 else {
14681 Data0 = -Data0;
14682 if (Data0 > 8)
14683 Data0 = 8;
14684 }
14685
14686 pSprite->field_52 = Data0;
14687 }
14688 //loc_1F283
14689
14690 if (pSprite->field_8 == 0x41)
14691 goto loc_1F3C4;
14692
14693 if (pSprite->field_8 == 0x9F)
14694 goto loc_1F340;
14695
14696 if (pSprite->field_8 == 0x38)
14697 goto loc_1F3A2;
14698
14699 pSprite->field_A = 0;
14700 pSprite->field_36 = 0;
14701
14702 if (!mPhase_Aborted) {
14703
14704 Data0 = tool_RandomGet() & 1;
14705 if (Data0 == 0)
14706 goto loc_1F32C;
14707
14708 if (!pSprite->field_52) {
14709 Data0 = tool_RandomGet() & 1;
14710
14711 if (!Data0) {
14712 //loc_1F2F9
14713 pSprite->field_8 = 0x41;
14714 Data0 = tool_RandomGet() & 3;
14715 pSprite->field_A = Data0;
14716 pSprite->field_2A = 1;
14717 Sprite_Create_Player_Shadow(pSprite);
14718 goto loc_1F3C4;
14719 }
14720 }
14721 else
14722 goto loc_1F32C;
14723 }
14724
14725 //loc_1F2EC
14726 pSprite->field_8 = 0x38;
14727 goto loc_1F3A2;
14728
14729 loc_1F32C:;
14730 pSprite->field_8 = 0x9F;
14731 pSprite->field_2A = 0;
14732
14733 loc_1F340:;
14734
14735 Data0 = pSprite->field_2A;
14736
14737 pSprite->field_A = mSprite_Player_MissionOver_Frames[Data0];
14738 pSprite->field_36 ^= -32768;
14739 if (pSprite->field_36 < 0)
14740 goto loc_1F41D;
14741
14742 pSprite->field_2A += 1;
14743 if (pSprite->field_2A < 7)
14744 goto loc_1F41D;
14745
14746 pSprite->field_2A = 3;
14747 goto loc_1F41D;
14748
14749 loc_1F3A2:;
14750 pSprite->field_36 ^= -32768;
14751 if (pSprite->field_36 < 0)
14752 goto loc_1F3C2;
14753
14754 if (pSprite->field_A >= 5)
14755 goto loc_1F41D;
14756
14757 pSprite->field_A += 1;
14758 loc_1F3C2:;
14759 goto loc_1F41D;
14760
14761 loc_1F3C4:;
14762
14763 pSprite->field_A += pSprite->field_2A;
14764 if (!pSprite->field_A)
14765 goto loc_1F3E9;
14766
14767 if (pSprite->field_A != 5)
14768 goto loc_1F3F1;
14769
14770 loc_1F3E9:;
14771 pSprite->field_2A = -pSprite->field_2A;
14772
14773 loc_1F3F1:;
14774 Data0 = pSprite->field_A;
14775 Data0 -= 1;
14776 if (Data0 < 0)
14777 Data0 = 0;
14778
14779 Data0 <<= 3;
14780 pSprite->field_20 = Data0;
14781
14782 loc_1F41D:;
14783 Data0 = -1;
14784
14785 return -1;
14786 }
14787
Sprite_Handle_Troop_Weapon(sSprite * pSprite)14788 void cFodder::Sprite_Handle_Troop_Weapon(sSprite* pSprite) {
14789
14790 if (pSprite->field_22 == eSprite_PersonType_Human) {
14791
14792 // Fired Weapon?
14793 if (!pSprite->field_4A)
14794 return;
14795
14796 // Delay before weapon fires?
14797 if (pSprite->field_4A >= 0) {
14798
14799 pSprite->field_4A--;
14800 if (pSprite->field_4A)
14801 return;
14802 }
14803
14804 }
14805 else {
14806 // No weapon firing?
14807 if (!pSprite->field_4A)
14808 return;
14809
14810 if (pSprite->field_4A >= 0) {
14811
14812 pSprite->field_4A -= 1;
14813 if (pSprite->field_4A)
14814 return;
14815
14816 pSprite->field_4A = -1;
14817 }
14818 }
14819
14820 // In water? no weapons
14821 if (pSprite->field_4F)
14822 return;
14823
14824 // Are we enemy with rockets?
14825 if (pSprite->field_18 == eSprite_Enemy_Rocket) {
14826 mTroop_Weapon_Bullet_Disabled = true;
14827 mTroop_Weapon_Grenade_Disabled = true;
14828 mTroop_Weapon_Rocket_Disabled = true;
14829
14830 // Only fire is unit is more than 24 away
14831 if (mSprite_Find_Distance > 0x18)
14832 mTroop_Weapon_Rocket_Disabled = false;
14833
14834 }
14835 else {
14836
14837 // Enemy, after 4th map (can throw grenades)
14838 //loc_1F4B0
14839 if (pSprite->field_18 == eSprite_Enemy) {
14840
14841 // Retail CF didn't allow enemy troops to use grenades until mission 4
14842 if(!(mVersionCurrent->isRetail() && mGame_Data.mMission_Number < 4)) {
14843
14844 // Use a grenade?
14845 if (!(tool_RandomGet() & 0x1F)) {
14846
14847 mTroop_Weapon_Bullet_Disabled = true;
14848 mTroop_Weapon_Grenade_Disabled = false;
14849 }
14850 }
14851 }
14852 }
14853
14854 // bullet weapon disabled?
14855 if (!mTroop_Weapon_Bullet_Disabled) {
14856
14857 if (Sprite_Create_Bullet(pSprite))
14858 pSprite->field_4A = -1;
14859 else
14860 pSprite->field_4A = 0;
14861
14862 if (word_3AA1D != 2)
14863 pSprite->field_45 = 0x0F;
14864 }
14865 mTroop_Weapon_Bullet_Disabled = false;
14866
14867 // Grenade disabled?
14868 if (!mTroop_Weapon_Grenade_Disabled) {
14869
14870 if (!Sprite_Create_Grenade(pSprite))
14871 pSprite->field_4A = 0;
14872 else
14873 pSprite->field_4A = -1;
14874
14875 if (word_3AA1D != 2)
14876 pSprite->field_45 = 0x0C;
14877
14878 }
14879 mTroop_Weapon_Grenade_Disabled = false;
14880
14881 // Second weapon disabled?
14882 if (!mTroop_Weapon_Rocket_Disabled) {
14883
14884 if (!Sprite_Create_Rocket(pSprite))
14885 pSprite->field_4A = 0;
14886 else
14887 pSprite->field_4A = -1;
14888
14889 //
14890 if (pSprite->field_45 < 0x0A) {
14891
14892 pSprite->field_45 += 5;
14893 pSprite->field_44 = pSprite->field_45;
14894 }
14895 }
14896 mTroop_Weapon_Rocket_Disabled = false;
14897 }
14898
Sprite_Handle_Troop_Direct_TowardWeaponTarget(sSprite * pSprite)14899 void cFodder::Sprite_Handle_Troop_Direct_TowardWeaponTarget(sSprite* pSprite) {
14900
14901 int16 Data0 = pSprite->field_2E;
14902 int16 Data4 = pSprite->field_30;
14903
14904 Sprite_Direction_Between_Points(pSprite, Data0, Data4);
14905 Sprite_Set_Direction_To_Next(pSprite);
14906 Sprite_Handle_Troop_FrameUnk(pSprite);
14907 }
14908
Sprite_Handle_Troop_Direct_TowardMouse(sSprite * pSprite)14909 void cFodder::Sprite_Handle_Troop_Direct_TowardMouse(sSprite* pSprite) {
14910
14911 int16 Data0 = mMouseX;
14912 Data0 += mCameraX >> 16;
14913 Data0 -= 0x18;
14914
14915 int16 Data4 = mMouseY;
14916 Data4 += mCameraY >> 16;
14917
14918 Sprite_Direction_Between_Points(pSprite, Data0, Data4);
14919 Sprite_Set_Direction_To_Next(pSprite);
14920
14921 mStoredSpriteFrame = pSprite->field_A;
14922 Sprite_Handle_Troop_FrameUnk(pSprite);
14923
14924 if (!pSprite->field_43)
14925 return;
14926
14927 pSprite->field_A = mStoredSpriteFrame;
14928 }
14929
Sprite_XY_Store(sSprite * pSprite)14930 void cFodder::Sprite_XY_Store(sSprite* pSprite) {
14931 mSprite_Reached_Target = 0;
14932
14933 mStoredSpriteX = (pSprite->field_0 & 0xFFFF) | (pSprite->field_2 << 16);
14934 mStoredSpriteY = (pSprite->field_4 & 0xFFFF) | (pSprite->field_6 << 16);
14935 }
14936
Sprite_XY_Restore(sSprite * pSprite)14937 void cFodder::Sprite_XY_Restore(sSprite* pSprite) {
14938 mSprite_Reached_Target = -1;
14939
14940 pSprite->field_0 = mStoredSpriteX & 0xFFFF;
14941 pSprite->field_2 = mStoredSpriteX >> 16;
14942
14943 pSprite->field_4 = mStoredSpriteY & 0xFFFF;
14944 pSprite->field_6 = mStoredSpriteY >> 16;
14945 }
14946
Sprite_Handle_Player_Adjust_Movement_Speed(sSprite * pSprite)14947 void cFodder::Sprite_Handle_Player_Adjust_Movement_Speed(sSprite* pSprite) {
14948 sub_1FCF2(pSprite);
14949
14950 if (pSprite->field_4F)
14951 return;
14952
14953 if (pSprite->field_50)
14954 return;
14955
14956 int16 Data0 = pSprite->field_10;
14957 Data0 >>= 5;
14958 Data0 -= 1;
14959 Data0 ^= 0x0F;
14960
14961 int16 Data4 = 0;
14962 for (Data4 = 0; Data4 < 0x0E; Data4 += 2) {
14963 if (Data0 == pSprite->field_3C)
14964 break;
14965
14966 Data0 += 2;
14967 Data0 &= 0x0E;
14968 }
14969
14970 pSprite->field_36 = mSprite_Speed_Direction_Modifier[Data4 / 2];
14971 }
14972
Sprite_Draw_Row_Update(sSprite * pSprite)14973 void cFodder::Sprite_Draw_Row_Update(sSprite* pSprite) {
14974 int16 Data4 = 0;
14975
14976 // Sprite still moving?
14977 if (!Sprite_Reached_Target(pSprite)) {
14978 Sprite_Movement_Speed_Update(pSprite);
14979 Sprite_Movement_Calculate(pSprite);
14980 }
14981
14982 Squad_Join_Check(pSprite);
14983 Sprite_Reached_MapEdge(pSprite);
14984
14985 // Check the terrain
14986 int8 PreviousTileType = pSprite->field_60;
14987 Sprite_Terrain_Check(pSprite, Data4);
14988
14989 // Not leaving water?
14990 if (PreviousTileType != eTerrainFeature_Water)
14991 goto loc_1F75D;
14992
14993 // Leaving water and into Quick sand?
14994 if (pSprite->field_60 == eTerrainFeature_QuickSand)
14995 goto loc_1F753;
14996
14997 // Leaving water for the edge/bank
14998 if (pSprite->field_60 == eTerrainFeature_WaterEdge)
14999 goto loc_1F75D;
15000
15001 pSprite->field_52 = 5;
15002 goto loc_1F75D;
15003
15004 loc_1F753:;
15005 pSprite->field_52 = 3;
15006
15007 loc_1F75D:;
15008 Sprite_Handle_Player_Close_To_SquadMember(pSprite);
15009 }
15010
Sprite_Handle_Troop_FrameUnk(sSprite * pSprite)15011 void cFodder::Sprite_Handle_Troop_FrameUnk(sSprite* pSprite) {
15012 int16 Data0, Data8;
15013 sSprite* Dataa30 = 0;
15014 sMapTarget* Data30 = 0;
15015 const int16* Data28 = 0;
15016 sMission_Troop* Data24 = 0;
15017
15018 // Is Human
15019 if (pSprite->field_22 == eSprite_PersonType_Human)
15020 goto AlterAnimation;
15021
15022 // Hostage Following Sprite?
15023 if (!pSprite->field_70)
15024 goto AlterAnimation;
15025
15026 // Hasnt Reached X Target
15027 if (pSprite->field_0 != pSprite->field_26)
15028 goto AlterAnimation;
15029
15030 // Hasnt Reached Y Target
15031 if (pSprite->field_4 != pSprite->field_28)
15032 goto AlterAnimation;
15033
15034 // Idle
15035 pSprite->field_8 = 0xDC;
15036 pSprite->field_A = 0;
15037 word_3ABB1 = -1;
15038 return;
15039
15040 AlterAnimation:;
15041 if (word_3AA1D == 2)
15042 goto loc_1F7FF;
15043
15044 if (pSprite->field_5A)
15045 goto loc_1F7F9;
15046
15047 if (!pSprite->field_43)
15048 goto loc_1F7FF;
15049
15050 if (pSprite->field_4F)
15051 goto loc_1F7FF;
15052
15053 loc_1F7F9:;
15054 mSprite_Bumped_Into_SquadMember = -1;
15055
15056 loc_1F7FF:;
15057 Data8 = pSprite->field_3C;
15058 Data8 += mDirectionMod;
15059 Data8 &= 0x0E;
15060
15061 pSprite->field_3C = Data8;
15062 Data8 /= 2;
15063
15064 Data28 = mSprite_AnimationPtrs[pSprite->field_22];
15065 if (!mSprite_FaceWeaponTarget)
15066 goto loc_1F9C0;
15067
15068 if (pSprite->field_22 == eSprite_PersonType_Human) {
15069 Data30 = mSquad_WalkTargets[pSprite->field_32];
15070 if (Data30[pSprite->field_40].mX >= 0)
15071 goto loc_1F9C0;
15072
15073 //seg005:01CC
15074 Dataa30 = mSquads[pSprite->field_32][0];
15075
15076 if (Dataa30 == INVALID_SPRITE_PTR || Dataa30 == 0)
15077 goto loc_1F9C0;
15078
15079 //seg005:020C
15080 if (Dataa30 != pSprite) {
15081
15082 Data0 = Dataa30->field_0;
15083
15084 if (Data0 != Dataa30->field_26)
15085 goto loc_1F9C0;
15086
15087 Data0 = Dataa30->field_4;
15088 if (Data0 != Dataa30->field_28)
15089 goto loc_1F9C0;
15090
15091 if (!word_3B2F3)
15092 goto loc_1F9C0;
15093 }
15094 else {
15095
15096 Data0 = pSprite->field_0;
15097 if (Data0 != pSprite->field_26)
15098 goto loc_1F9C0;
15099
15100 //seg005:0246
15101 Data0 = pSprite->field_4;
15102 if (Data0 != pSprite->field_28)
15103 goto loc_1F9C0;
15104 }
15105 }
15106
15107 if (pSprite->field_60 == eTerrainFeature_Water)
15108 goto loc_1F9C0;
15109
15110 //seg005:02A6
15111 pSprite->field_8 = *(Data28 + Data8 + 0x30);
15112 pSprite->field_A = 0;
15113 mStoredSpriteFrame = 0;
15114 return;
15115
15116 loc_1F9C0:;
15117 if (pSprite->field_54 != 2)
15118 goto loc_1FA39;
15119
15120 if (word_3AA1D) {
15121 if (word_3AA1D == 2) {
15122 pSprite->field_8 = *(Data28 + Data8);
15123 pSprite->field_A = mSprite_Frame_3;
15124 // FIX: Added as only 2 frames exist for all sprites in mSprite_AnimationPtrs
15125 pSprite->field_A %= 2;
15126 }
15127 else {
15128 //loc_1F9FF
15129 pSprite->field_8 = *(Data28 + Data8);
15130 pSprite->field_A = 0;
15131 }
15132 }
15133 //loc_1FA20
15134 --pSprite->field_57;
15135 if (pSprite->field_57)
15136 return;
15137
15138 pSprite->field_54 = 0;
15139 goto loc_1FB00;
15140
15141 loc_1FA39:;
15142 if (pSprite->field_54 != 1)
15143 goto loc_1FB00;
15144
15145 Data0 = *(Data28 + Data8 + 0x28);
15146
15147 if (Data0 != pSprite->field_8) {
15148 pSprite->field_8 = *(Data28 + Data8 + 0x28);
15149 pSprite->field_55 = 0;
15150 pSprite->field_A = 0;
15151 return;
15152 }
15153 //loc_1FA93
15154 pSprite->field_55++;
15155 if (pSprite->field_55 != 2)
15156 return;
15157 pSprite->field_55 = 0;
15158 pSprite->field_A++;
15159 mStoredSpriteFrame = pSprite->field_A;
15160
15161 if (pSprite->field_A < 3)
15162 return;
15163 mStoredSpriteFrame = 0;
15164 pSprite->field_A = 0;
15165 pSprite->field_54 = 0;
15166 pSprite->field_5A = 0;
15167 pSprite->field_55 = 0;
15168
15169 loc_1FB00:;
15170 if (pSprite->field_54 != 3)
15171 goto loc_1FBA4;
15172
15173 Data0 = *(Data28 + Data8 + 0x38);
15174 if (Data0 != pSprite->field_8) {
15175 pSprite->field_8 = Data0;
15176 pSprite->field_55 = 0;
15177 pSprite->field_A = 0;
15178 return;
15179 }
15180 //loc_1FB5A
15181 pSprite->field_55++;
15182 if (pSprite->field_55 != 7)
15183 return;
15184
15185 pSprite->field_55 = 0;
15186 pSprite->field_A = 0;
15187 pSprite->field_54 = 0;
15188 pSprite->field_5A = 0;
15189 pSprite->field_55 = 0;
15190
15191 loc_1FBA4:;
15192 // If in water
15193 if (pSprite->field_4F) {
15194
15195 pSprite->field_8 = *(Data28 + Data8 + 0x20);
15196 Data0 = mSprite_Frame_1;
15197
15198 // Reached another troop?
15199 if (pSprite->field_43)
15200 Data0 = mSprite_Frame_2;
15201
15202 Data0 &= 1;
15203 pSprite->field_A = Data0;
15204 goto loc_1FCD7;
15205 }
15206 //loc_1FBF8
15207 if (!word_3AA1D) {
15208 pSprite->field_8 = *(Data28 + Data8 + 0x18);
15209 pSprite->field_A = mSprite_Frame_2;
15210 goto loc_1FCD7;
15211 }
15212 //loc_1FC29
15213 if (pSprite->field_8 == *(Data28 + Data8 + 0x18) && pSprite->field_A) {
15214 pSprite->field_A = 0;
15215 goto loc_1FCD7;
15216 }
15217
15218 //loc_1FC61
15219 Data24 = pSprite->field_46_mission_troop;
15220
15221 if (Data24 == 0)
15222 Data0 = 0x70;
15223 else
15224 Data0 = Data24->field_6;
15225
15226 if (Data0 == 3)
15227 pSprite->field_8 = *(Data28 + Data8 + 0);
15228 else
15229 pSprite->field_8 = *(Data28 + Data8);
15230
15231 //loc_1FCB4
15232 if (Data0 != 2)
15233 pSprite->field_A = mSprite_Frame_1;
15234 else
15235 pSprite->field_A = mSprite_Frame_3;
15236
15237 loc_1FCD7:;
15238 // Bumped into other troop
15239 if (!mSprite_Bumped_Into_SquadMember)
15240 return;
15241
15242 // FIX: Added % as only 2 frames exist for all sprites in mSprite_AnimationPtrs
15243 // There is one case where mTmp_FrameNumber isnt set by the current sprite
15244 pSprite->field_A = mTmp_FrameNumber % 2;
15245 mSprite_Bumped_Into_SquadMember = 0;
15246 }
15247
sub_1FCF2(sSprite * pSprite)15248 void cFodder::sub_1FCF2(sSprite* pSprite) {
15249 int16 Data0;
15250
15251 pSprite->field_36 = 0x10;
15252
15253 if (pSprite->field_18 == eSprite_Enemy) {
15254 Data0 = 0x0C;
15255 Data0 += pSprite->field_62;
15256 if (Data0 > 0x1A)
15257 Data0 = 0x1A;
15258 pSprite->field_36 = Data0;
15259 }
15260 else {
15261
15262 //loc_1FD36
15263 Data0 = word_3BED5[pSprite->field_32];
15264 if (!Data0)
15265 pSprite->field_36 >>= 1;
15266 else {
15267 if (Data0 != 1)
15268 pSprite->field_36 = 0x18;
15269 }
15270 }
15271
15272 if (pSprite->field_4F)
15273 goto loc_1FDDC;
15274
15275 Data0 = pSprite->field_52;
15276 if (Data0 == pSprite->field_50)
15277 goto loc_1FDD5;
15278 if (Data0 < pSprite->field_50)
15279 goto loc_1FDC3;
15280
15281 Data0--;
15282 if (Data0 == pSprite->field_50)
15283 goto loc_1FDD5;
15284 Data0--;
15285 goto loc_1FDC8;
15286
15287 loc_1FDC3:;
15288 Data0++;
15289 loc_1FDC8:;
15290 pSprite->field_52 = Data0;
15291 loc_1FDD5:;
15292 if (!Data0)
15293 return;
15294 loc_1FDDC:;
15295 pSprite->field_36 = 6;
15296 }
15297
sub_1FDE7(sSprite * pSprite)15298 void cFodder::sub_1FDE7(sSprite* pSprite) {
15299
15300 int16 Data0 = pSprite->field_2E;
15301 int16 Data4 = pSprite->field_30;
15302
15303 Sprite_Direction_Between_Points(pSprite, Data0, Data4);
15304 Sprite_Set_Direction_To_Next(pSprite);
15305
15306 mStoredSpriteFrame = pSprite->field_A;
15307
15308 Sprite_Handle_Troop_FrameUnk(pSprite);
15309 if (!pSprite->field_43)
15310 return;
15311
15312 pSprite->field_A = mStoredSpriteFrame;
15313 }
15314
Sprite_Create_Player_Shadow(sSprite * pSprite)15315 void cFodder::Sprite_Create_Player_Shadow(sSprite* pSprite) {
15316 int16 Data0 = 0;
15317
15318 sSprite* Data2C, *Data30;
15319
15320 if (pSprite->field_5C == 0)
15321 return;
15322
15323 if (Sprite_Get_Free_Max42(Data0, Data2C, Data30))
15324 return;
15325
15326 Data2C->field_1A_sprite = pSprite;
15327 Data2C->field_6A_sprite = pSprite;
15328
15329 Data2C->field_0 = pSprite->field_0;
15330 Data2C->field_4 = pSprite->field_4;
15331 Data2C->field_0 += 4;
15332 Data2C->field_8 = 0x8D;
15333 Data2C->field_A = 2;
15334 Data2C->field_2 = pSprite->field_2;
15335 Data2C->field_6 = pSprite->field_6;
15336 Data2C->field_18 = eSprite_Player_Shadow;
15337 Data2C->field_62 = pSprite->field_18;
15338 Data2C->field_20 = 0;
15339 Data2C->field_32 = -1;
15340 Data2C->field_2C = eSprite_Draw_First;
15341 Data2C->field_52 = 0;
15342 }
15343
Sprite_Create_BloodTrail(sSprite * pSprite,sSprite * & pData2C,sSprite * & pData30)15344 int16 cFodder::Sprite_Create_BloodTrail(sSprite* pSprite, sSprite*& pData2C, sSprite*& pData30) {
15345 int16 Data0;
15346
15347 Data0 = 1;
15348
15349 if (!Sprite_Get_Free_Max42(Data0, pData2C, pData30)) {
15350 pData2C->field_0 = pSprite->field_0;
15351 pData2C->field_2 = pSprite->field_2;
15352 pData2C->field_4 = pSprite->field_4;
15353 pData2C->field_6 = pSprite->field_6;
15354
15355 pData2C->field_0 += 3;
15356 pData2C->field_4 -= 8;
15357 pData2C->field_8 = 0x96;
15358 pData2C->field_A = 0;
15359 pData2C->field_18 = eSprite_BloodTrail;
15360 pData2C->field_20 = pSprite->field_20;
15361 pData2C->field_32 = -1;
15362 pData2C->field_2C = eSprite_Draw_OnTop;
15363 pData2C->field_52 = 0;
15364 pData2C->field_12 = 1;
15365 Data0 = 0;
15366 }
15367
15368 return Data0;
15369 }
15370
Sprite_Terrain_Check(sSprite * pSprite,int16 & pData4)15371 void cFodder::Sprite_Terrain_Check(sSprite* pSprite, int16& pData4) {
15372 int16 Data0 = -3; // Y
15373 pData4 = 8; // X
15374
15375 // pData4 becomes terrain type
15376 if (Map_Terrain_Get_Type_And_Walkable(pSprite, Data0, pData4))
15377 goto CheckFalling;
15378
15379 pSprite->field_60 = pData4 & 0xFF;
15380 pSprite->field_50 = 0;
15381 pSprite->field_4F = 0;
15382
15383 if (pData4 == eTerrainFeature_Drop2) {
15384 if (pSprite->field_18 == eSprite_Enemy)
15385 goto loc_20251;
15386
15387 if (pSprite->field_22 == eSprite_PersonType_Native)
15388 goto loc_20251;
15389
15390 if (!pSprite->field_38 || pSprite->field_38 >= eSprite_Anim_Slide1) {
15391 pSprite->field_38 = eSprite_Anim_Hit3;
15392 return;
15393 }
15394 }
15395
15396 //loc_20044
15397 if (pData4 == eTerrainFeature_Drop) {
15398
15399 if (pSprite->field_18 == eSprite_Enemy)
15400 goto loc_20251;
15401
15402 if (pSprite->field_22 == eSprite_PersonType_Native)
15403 goto loc_20251;
15404
15405 ++pSprite->field_56;
15406 return;
15407 }
15408
15409 //loc_20072
15410 pSprite->field_56 = 0;
15411 if (pData4 == eTerrainFeature_QuickSandEdge)
15412 goto loc_201CC;
15413
15414 if (pData4 == eTerrainFeature_Rocky)
15415 goto loc_20108;
15416
15417 if (pData4 == eTerrainFeature_Rocky2)
15418 goto loc_2014D;
15419
15420 if (!pSprite->field_61)
15421 goto loc_200C0;
15422
15423 pSprite->field_20 -= 3;
15424 if (!pSprite->field_20)
15425 goto loc_200B7;
15426 if (pSprite->field_20 >= 0)
15427 goto loc_200C0;
15428
15429 pSprite->field_20 = 0;
15430 loc_200B7:;
15431 pSprite->field_61 = 0;
15432
15433 loc_200C0:;
15434 if (pData4 == eTerrainFeature_QuickSand)
15435 goto Soldier_InQuickSand;
15436
15437 if (pData4 == eTerrainFeature_WaterEdge)
15438 goto Soldier_WaterEdge;
15439
15440 if (pData4 != eTerrainFeature_Water)
15441 goto checkSinking;
15442
15443 // Is a Native?
15444 if (pSprite->field_22 == eSprite_PersonType_Native)
15445 goto loc_20251;
15446
15447 // In Water
15448 pSprite->field_4F = -1;
15449 pSprite->field_50 = 0;
15450 pSprite->field_52 = 0;
15451 return;
15452
15453 loc_20108:;
15454 pSprite->field_52 = 0;
15455 if (pSprite->field_61) {
15456 pSprite->field_20 = 2;
15457 return;
15458 }
15459 if (!pSprite->field_20) {
15460 pSprite->field_61 = -1;
15461 pSprite->field_20 = 1;
15462 }
15463 return;
15464
15465 loc_2014D:;
15466 pSprite->field_52 = 0;
15467 if (pSprite->field_61) {
15468 if (pSprite->field_20 >= 6)
15469 return;
15470
15471 pSprite->field_20 += 2;
15472 return;
15473 }
15474 //loc_2017C
15475 if (pSprite->field_20)
15476 return;
15477 pSprite->field_61 = -1;
15478 pSprite->field_20 = 1;
15479 return;
15480
15481 Soldier_InQuickSand:;
15482 pSprite->field_50 = 3;
15483 return;
15484
15485 Soldier_WaterEdge:;
15486 pSprite->field_50 = 6;
15487 return;
15488
15489 checkSinking:;
15490 if (pData4 == eTerrainFeature_Sink)
15491 goto HumanSinking;
15492
15493 pSprite->field_52 = 0;
15494 return;
15495
15496 loc_201CC:;
15497 if (pSprite->field_38)
15498 return;
15499 if (!pSprite->field_36)
15500 return;
15501 if (pSprite->field_52)
15502 return;
15503 if (pSprite->field_20)
15504 return;
15505
15506 Data0 = tool_RandomGet() & 0x3F;
15507 if (Data0)
15508 return;
15509
15510 if (pSprite->field_22 == eSprite_PersonType_Native)
15511 return;
15512
15513 pSprite->field_38 = eSprite_Anim_Slide1;
15514 return;
15515
15516 HumanSinking:;
15517 pSprite->field_5B = 1;
15518 return;
15519
15520 CheckFalling:;
15521 if (pData4 == eTerrainFeature_Drop || pData4 == eTerrainFeature_Drop2) {
15522 pSprite->field_38 = eSprite_Anim_Hit2;
15523 return;
15524 }
15525
15526 loc_20251:;
15527 pSprite->field_43 = 1;
15528 mSprite_Reached_Target = -1;
15529 if (pSprite->field_22 == eSprite_PersonType_Human)
15530 goto loc_2035C;
15531
15532 pSprite->field_0 = mStoredSpriteX & 0xFFFF;
15533
15534 Data0 = -3;
15535 pData4 = 8;
15536 if (Map_Terrain_Get_Type_And_Walkable(pSprite, Data0, pData4))
15537 goto loc_202E5;
15538
15539 if (pData4 == eTerrainFeature_Drop)
15540 goto loc_202E5;
15541
15542 if (pData4 == eTerrainFeature_Drop2)
15543 goto loc_202E5;
15544
15545 if (pSprite->field_22 == eSprite_PersonType_Native && pData4 == eTerrainFeature_Water)
15546 goto loc_202E5;
15547
15548 Data0 = pSprite->field_10;
15549 if (Data0 <= 0x80 || Data0 > 0x180) {
15550 pSprite->field_10 = 0;
15551 goto loc_20307;
15552 }
15553
15554 pSprite->field_10 = 0x100;
15555 goto loc_20307;
15556
15557 loc_202E5:;
15558 if (pSprite->field_10 > 0x100) {
15559 pSprite->field_10 = 0x180;
15560 goto loc_20307;
15561 }
15562
15563 pSprite->field_10 = 0x80;
15564 loc_20307:;
15565
15566 Data0 = mGame_InputTicks;
15567 Data0 >>= 2;
15568 Data0 &= 0x3F;
15569 Data0 -= 0x20;
15570 Data0 &= 0x1FE;
15571 pSprite->field_10 += Data0;
15572 pSprite->field_4 = mStoredSpriteY;
15573
15574 Data0 = mGame_InputTicks;
15575 Data0 &= 0x1F;
15576 Data0 += 0x0C;
15577 pSprite->field_44 = (int8)Data0;
15578 return;
15579
15580 loc_2035C:;
15581
15582 int16 word_3A9E6 = pSprite->field_0;
15583 pSprite->field_0 = mStoredSpriteX & 0xFFFF;
15584
15585 Data0 = -3;
15586 pData4 = 8;
15587 if (!Map_Terrain_Get_Type_And_Walkable(pSprite, Data0, pData4))
15588 return;
15589
15590 pSprite->field_0 = word_3A9E6;
15591 pSprite->field_4 = mStoredSpriteY & 0xFFFF;
15592
15593 Data0 = -3;
15594 pData4 = 8;
15595 if (!Map_Terrain_Get_Type_And_Walkable(pSprite, Data0, pData4))
15596 return;
15597
15598 //loc_203BA
15599 pSprite->field_A = mTmp_FrameNumber;
15600 Sprite_XY_Restore(pSprite);
15601 pSprite->field_26 = pSprite->field_0;
15602 pSprite->field_28 = pSprite->field_4;
15603
15604 sMapTarget* Data30 = mSquad_WalkTargets[pSprite->field_32];
15605 pData4 = 0;
15606
15607 for (;;) {
15608 sMapTarget eax = *Data30++;
15609
15610 if (eax.asInt < 0)
15611 break;
15612
15613 pData4++;
15614 }
15615
15616 pSprite->field_40 = pData4;
15617 pSprite->field_4C = -1;
15618 }
15619
String_Print_Small(std::string pText,const size_t pY)15620 void cFodder::String_Print_Small(std::string pText, const size_t pY) {
15621 std::transform(pText.begin(), pText.end(), pText.begin(), ::toupper);
15622
15623 String_CalculateWidth(320, mFont_Briefing_Width, pText);
15624 String_Print(mFont_Briefing_Width, 0, mGUI_Temp_X, pY, pText);
15625 }
15626
String_Print_Small(std::string pText,const size_t pX,const size_t pY)15627 void cFodder::String_Print_Small(std::string pText, const size_t pX, const size_t pY) {
15628 std::transform(pText.begin(), pText.end(), pText.begin(), ::toupper);
15629
15630 String_CalculateWidth(320, mFont_Briefing_Width, pText);
15631 String_Print(mFont_Briefing_Width, 0, pX, pY, pText);
15632 }
15633
String_Print_Large(std::string pText,const bool pOverAndUnderLine,const size_t pY)15634 void cFodder::String_Print_Large(std::string pText, const bool pOverAndUnderLine, const size_t pY) {
15635 std::transform(pText.begin(), pText.end(), pText.begin(), ::toupper);
15636
15637 String_CalculateWidth(320, mFont_Underlined_Width, pText);
15638 String_Print(mFont_Underlined_Width, pOverAndUnderLine == true ? 1 : 3, mGUI_Temp_X, pY, pText);
15639 }
15640
String_Print_Large(std::string pText,const bool pOverAndUnderLine,const size_t pX,const size_t pY)15641 void cFodder::String_Print_Large(std::string pText, const bool pOverAndUnderLine, const size_t pX, const size_t pY) {
15642 std::transform(pText.begin(), pText.end(), pText.begin(), ::toupper);
15643
15644 String_CalculateWidth(320, mFont_Underlined_Width, pText);
15645 String_Print(mFont_Underlined_Width, pOverAndUnderLine == true ? 1 : 3, pX, pY, pText);
15646 }
15647
String_Print(const uint8 * pWidths,int32 pFontSpriteID,size_t pParam08,size_t pParamC,const std::string & pText)15648 void cFodder::String_Print(const uint8* pWidths, int32 pFontSpriteID, size_t pParam08, size_t pParamC, const std::string& pText) {
15649
15650 String_Print(pWidths, pFontSpriteID, pParam08, pParamC, pText.c_str());
15651 }
15652
String_Print(const uint8 * pWidths,int32 pFontSpriteID,size_t pParam08,size_t pParamC,const char * pText)15653 void cFodder::String_Print(const uint8* pWidths, int32 pFontSpriteID, size_t pParam08, size_t pParamC, const char* pText) {
15654 const uint8* ptr = 0;
15655 uint8 al = 0;
15656 int32 unk14 = 0;
15657
15658 mGUI_Temp_Y = (int16)pParamC;
15659 mGUI_Draw_LastHeight = 0;
15660
15661 for (;;) {
15662 String_Print_Next:;
15663 uint8 NextChar = *pText++;
15664 uint8 NextChar10 = 0;
15665
15666 //seg007:0170
15667 if (NextChar == 0xFD) {
15668 //sub_29DE2(0x10);
15669
15670 }
15671 else if (NextChar == 0xFE) {
15672 //sub_29DE2(0x0F);
15673
15674 }
15675 else if (NextChar == 0x00)
15676 break;
15677
15678 else {
15679 //seg007:01A1
15680 NextChar10 = NextChar;
15681
15682 if (!(NextChar & 0x80)) {
15683
15684 //01AB
15685 if (mString_GapCharID) {
15686 if (NextChar == 0x20) {
15687 NextChar = (uint8)mString_GapCharID;
15688 goto loc_29D71;
15689 }
15690 }
15691 else {
15692 //1C4
15693 if (NextChar == 0x20)
15694 goto loc_29DC7;
15695 }
15696 //1CD
15697 if (NextChar <= 0x39) {
15698 if (NextChar >= 0x30) {
15699 NextChar -= 0x30;
15700 NextChar += 0x1A;
15701 goto loc_29D71;
15702 }
15703 }
15704 else {
15705 //loc_29D07
15706 if (NextChar > 0x5A) {
15707 NextChar -= 0x61;
15708 NextChar += PLATFORM_BASED(0x39, 0x28);
15709
15710 goto loc_29D71;
15711 }
15712 else {
15713 if (NextChar >= 0x41) {
15714 NextChar -= 0x41;
15715 goto loc_29D71;
15716 }
15717 }
15718 }
15719 }
15720
15721 // Must be a special character
15722 // 20D
15723 //loc_29D2D
15724 unk14 = -1;
15725 ptr = mGUI_Font_SpecialCharacters;
15726 do {
15727
15728 // Reached end of table? then skip this character
15729 if (*ptr == 0xFF)
15730 goto String_Print_Next;
15731
15732 ++unk14;
15733 al = *ptr++;
15734
15735 // Loop until we find this character in the table
15736 } while (al != NextChar);
15737
15738 // Found the special character, lets use its index
15739 NextChar = 0x24 + unk14;
15740
15741 loc_29D71:;
15742
15743 if (mGUI_Print_String_To_Sidebar)
15744 mGraphics->Sidebar_Copy_Sprite_To_ScreenBufPtr(pFontSpriteID + NextChar, pParam08, pParamC);
15745 else
15746 GUI_Draw_Frame_8(pFontSpriteID, NextChar, pParam08, pParamC);
15747
15748 }
15749 loc_29DC7:;
15750
15751 NextChar10 = pWidths[NextChar10];
15752
15753 pParam08 += NextChar10;
15754 }
15755 }
15756
Vehicle_Input_Handle()15757 void cFodder::Vehicle_Input_Handle() {
15758
15759 if (!mButtonPressLeft) {
15760 mVehicle_Input_Disabled = false;
15761 return;
15762 }
15763
15764 if (mVehicle_Input_Disabled)
15765 return;
15766
15767 if (Mouse_Button_Left_Toggled() >= 0)
15768 if (sub_313CD() < 0)
15769 return;
15770
15771 sSprite* Data20 = mSquad_Leader;
15772
15773 if (Data20 == INVALID_SPRITE_PTR)
15774 return;
15775 int16 Data0 = mMouseX + (mCameraX >> 16);
15776 int16 Data4 = mMouseY + (mCameraY >> 16);
15777
15778 Data0 -= 0x1C;
15779
15780 if (Data0 < 0)
15781 Data0 = 0;
15782 Data4 += 6;
15783 if (Data4 < 0)
15784 Data4 = 0x14;
15785
15786 if (Data4 < 0x14)
15787 Data4 = 0x14;
15788
15789 if (Data20->field_6F >= eVehicle_Helicopter) {
15790 if (Data20->field_50 <= 8)
15791 Data4 += 0x20;
15792 }
15793
15794 mCamera_PanTargetX = Data0;
15795 mCamera_PanTargetY = Data4;
15796
15797 mMouse_Locked = false;
15798
15799 Data20->field_26 = Data0;
15800 Data20->field_28 = Data4;
15801 }
15802
sub_311A7()15803 void cFodder::sub_311A7() {
15804 if (mSquad_Selected < 0)
15805 return;
15806
15807 sSprite** Data24 = mSquads[mSquad_Selected];
15808
15809 for (;;) {
15810 if (*Data24 == INVALID_SPRITE_PTR)
15811 break;
15812 sSprite* Data28 = *Data24++;
15813 Data28->field_66 = 0;
15814 }
15815
15816 int16 Data0 = mMouseX;
15817 int16 Data4 = mMouseY;
15818
15819 Data0 += mCameraX >> 16;
15820 Data4 += mCameraY >> 16;
15821
15822 Data0 -= 0x0F;
15823 Data4 -= 3;
15824
15825 for(auto& Sprite : mSprites) {
15826
15827 if (Sprite.field_0 == -32768)
15828 continue;
15829
15830 if (!Sprite.field_65)
15831 continue;
15832
15833 if (Sprite.field_22 != eSprite_PersonType_Human)
15834 continue;
15835
15836 if (Sprite.field_20)
15837 continue;
15838
15839 int16 Data18 = Sprite.field_18;
15840 int16 Data8 = Sprite.field_0;
15841
15842 if (Sprite.field_6F == eVehicle_Turret_Cannon ||
15843 Sprite.field_6F == eVehicle_Turret_Missile)
15844 Data8 -= 8;
15845
15846 if (Data0 < Data8)
15847 continue;
15848
15849 Data8 += mSprite_Width[Data18];
15850 if (Data0 > Data8)
15851 continue;
15852
15853 Data8 = Sprite.field_4 - mSprite_Height_Top[Data18];
15854 Data8 -= 0x14;
15855 if (Data4 < Data8)
15856 continue;
15857
15858 Data8 = Sprite.field_4 + mSprite_Height_Bottom[Data18];
15859 if (Data4 > Data8)
15860 continue;
15861
15862 if (mSquad_Selected < 0)
15863 break;
15864
15865 Data24 = mSquads[mSquad_Selected];
15866 for (;;) {
15867 if (*Data24 == INVALID_SPRITE_PTR)
15868 goto loc_313C6;
15869
15870 sSprite* Data28 = *Data24++;
15871 Data28->field_66 = &Sprite;
15872 }
15873 }
15874
15875 loc_313C6:;
15876 }
15877
sub_313CD()15878 int16 cFodder::sub_313CD() {
15879 const int16* Data2C = mSprite_Width;
15880 const int16* Data30 = mSprite_Height_Top;
15881
15882 int16 Data0 = mMouseX;
15883 int16 Data4 = mMouseY;
15884 int16 Data8, Data18;
15885
15886 sSprite* Data20, *Dataa30;
15887 sSprite** Dataa2C;
15888
15889 Data0 += mCameraX >> 16;
15890 Data4 += mCameraY >> 16;
15891
15892 Data0 -= 0x0F;
15893 Data4 -= 3;
15894
15895 if (!mSquad_CurrentVehicle)
15896 goto loc_31692;
15897
15898 Data20 = mSquad_CurrentVehicle;
15899 if (Data20->field_0 == -32768)
15900 goto loc_31689;
15901
15902 if (Data20->field_22 != eSprite_PersonType_Human)
15903 goto loc_31689;
15904
15905 Data18 = Data20->field_18;
15906 Data8 = Data20->field_0;
15907 if (Data0 < Data8)
15908 goto loc_31689;
15909
15910 Data8 += Data2C[Data18];
15911 if (Data0 > Data8)
15912 goto loc_31689;
15913
15914 //seg011:29DA
15915 Data8 = Data20->field_4;
15916 Data8 -= Data20->field_20;
15917
15918 Data8 -= Data30[Data18];
15919 Data8 -= 0x14;
15920 if (Data4 < Data8)
15921 goto loc_31689;
15922
15923 Data8 = Data20->field_4;
15924 Data8 -= Data20->field_20;
15925 if (Data4 > Data8)
15926 goto loc_31689;
15927
15928 if (!Data20->field_20)
15929 goto loc_31514;
15930
15931 Data20->field_6E = -1;
15932 mVehicle_Input_Disabled = true;
15933 goto loc_3167D;
15934
15935 loc_31514:;
15936 Data0 = -3;
15937 Data4 = 8;
15938
15939 if (Map_Terrain_Get_Type_And_Walkable(Data20, Data0, Data4))
15940 goto loc_31689;
15941
15942 Data0 = mSquad_Selected;
15943 if (Data0 < 0)
15944 goto loc_31668;
15945
15946 //seg011:2A84
15947 mSquad_EnteredVehicleTimer[Data0] = 0;
15948 Dataa2C = mSquads[Data0];
15949
15950 //loc_31578
15951 for (; Data18 >= 0; --Data18) {
15952
15953 if (*Dataa2C == INVALID_SPRITE_PTR)
15954 goto loc_31668;
15955
15956 sSprite* Sprite = *Dataa2C++;
15957
15958 if (!Sprite->field_6E)
15959 continue;
15960
15961 //seg011:2AE9
15962
15963 Sprite->field_6E = 0;
15964 Dataa30 = Sprite->field_6A_sprite;
15965 Sprite->field_6A_sprite = 0;
15966 Sprite->field_66 = 0;
15967
15968 Sprite->field_0 = Dataa30->field_0;
15969 Sprite->field_4 = Dataa30->field_4;
15970
15971 if (Sprite->field_6F == eVehicle_Turret_Cannon)
15972 goto loc_3162B;
15973
15974 if (Sprite->field_6F == eVehicle_Turret_Missile)
15975 goto loc_3162B;
15976
15977 Sprite->field_0 += 0x0F;
15978 Sprite->field_4 += -10;
15979
15980 loc_3162B:;
15981 Sprite->field_26 = Sprite->field_0;
15982 Sprite->field_28 = Sprite->field_4;
15983 Sprite->field_26 -= 6;
15984 Sprite->field_28 += 0x10;
15985 }
15986
15987 loc_31668:;
15988 mVehicle_Input_Disabled = true;
15989 Data20->field_6E = -1;
15990 mMouse_Button_LeftRight_Toggle = false;
15991 loc_3167D:;
15992 Data0 = -1;
15993 return -1;
15994
15995 loc_31689:;
15996 Data20->field_6E = 0;
15997 loc_31692:;
15998 Data0 = 0;
15999 return 0;
16000 }
16001
Vehicle_Target_Set()16002 void cFodder::Vehicle_Target_Set() {
16003
16004 if (Mouse_Button_Right_Toggled() < 0)
16005 return;
16006
16007 sSprite* Vehicle = mSquad_CurrentVehicle;
16008 Vehicle->field_54 = -1;
16009
16010 int16 PosX = mMouseX;
16011 int16 PosY = mMouseY;
16012 PosX += mCameraX >> 16;
16013 PosY += mCameraY >> 16;
16014 PosX -= 0x10;
16015
16016 if (!PosX)
16017 PosX = 1;
16018
16019 PosY -= 8;
16020 Vehicle->field_2E = PosX;
16021 Vehicle->field_30 = PosY;
16022 }
16023
String_CalculateWidth(int32 pPosX,const uint8 * pWidths,const std::string & pString)16024 void cFodder::String_CalculateWidth(int32 pPosX, const uint8* pWidths, const std::string& pString) {
16025
16026 String_CalculateWidth(pPosX, pWidths, pString.c_str());
16027 }
16028
String_CalculateWidth(int32 pPosX,const uint8 * pWidths,const char * pString)16029 void cFodder::String_CalculateWidth(int32 pPosX, const uint8* pWidths, const char* pString) {
16030 int32 PositionX = 0;
16031
16032 for (const char* Text = pString; *Text; ++Text) {
16033 uint8 Char = *Text;
16034
16035 if (Char == 0xFE || Char == 0xFD || Char == 0xFF)
16036 break;
16037
16038 PositionX += pWidths[Char];
16039 }
16040
16041 pPosX -= PositionX;
16042 if (pPosX < 0) {
16043 pPosX = 0;
16044 PositionX = 318;
16045 }
16046
16047 pPosX >>= 1;
16048 mGUI_Temp_X = pPosX;
16049 mGUI_Temp_Width = PositionX;
16050 }
16051
Intro_OpenFodder()16052 void cFodder::Intro_OpenFodder() {
16053
16054 if (!mOpenFodder_Intro_Done && !mParams->mSkipIntro) {
16055 bool CF2 = false;
16056
16057 mPhase_Aborted = false;
16058 mGame_Data.mMission_Number = 0;
16059
16060 // Use a CF2 intro?
16061 if (mVersions->isCampaignAvailable("Cannon Fodder 2"))
16062 CF2 = (tool_RandomGet() & 2);
16063 if (CF2)
16064 VersionSwitch(mVersions->GetForCampaign("Cannon Fodder 2", mParams->mDefaultPlatform));
16065
16066 // Random intro
16067 auto Tileset = static_cast<eTileTypes>(((uint8)tool_RandomGet()) % eTileTypes_Hid);
16068 Mission_Intro_Play(true, Tileset);
16069 mOpenFodder_Intro_Done = true;
16070 if (CF2)
16071 VersionSwitch(mVersions->GetForCampaign("Cannon Fodder", mParams->mDefaultPlatform));
16072 }
16073 }
16074
intro_LegionMessage()16075 void cFodder::intro_LegionMessage() {
16076 int16 Duration = 325 / 4;
16077 bool DoBreak = false;
16078
16079 mSurface->clearBuffer();
16080 mGraphics->PaletteSet();
16081
16082 Intro_Print_String(&mVersionCurrent->getIntroData()->at(0).mText[0]);
16083 Intro_Print_String(&mVersionCurrent->getIntroData()->at(0).mText[1]);
16084 Intro_Print_String(&mVersionCurrent->getIntroData()->at(0).mText[2]);
16085
16086 while (mSurface->isPaletteAdjusting() || DoBreak == false) {
16087
16088 Mouse_Inputs_Get();
16089
16090 if (mSurface->isPaletteAdjusting())
16091 mSurface->palette_FadeTowardNew();
16092
16093 if (Duration > 1)
16094 --Duration;
16095 else {
16096 if (DoBreak == false) {
16097 mSurface->paletteNew_SetToBlack();
16098 Duration = 0;
16099 DoBreak = true;
16100 }
16101 }
16102
16103 Video_SurfaceRender(false);
16104 Cycle_End();
16105 }
16106 }
16107
intro_Play()16108 int16 cFodder::intro_Play() {
16109
16110 mGraphics->Load_Sprite_Font();
16111 mGraphics->SetActiveSpriteSheet(eGFX_Types::eGFX_FONT);
16112
16113 for (word_3B2CF = 1; mVersionCurrent->getIntroData()->at(word_3B2CF).mImageNumber != 0; ++word_3B2CF) {
16114
16115 mIntro_PlayTextDuration = 0x288 / 5;
16116
16117 mSurface->palette_SetToBlack();
16118
16119 if (mVersionCurrent->getIntroData()->at(word_3B2CF).mImageNumber == 0 && mVersionCurrent->getIntroData()->at(word_3B2CF).mText == 0)
16120 break;
16121
16122 if (mVersionCurrent->getIntroData()->at(word_3B2CF).mImageNumber != 0xFF) {
16123
16124 std::stringstream ImageName;
16125 ImageName << (char)mVersionCurrent->getIntroData()->at(word_3B2CF).mImageNumber;
16126
16127 mGraphics->Load_And_Draw_Image(ImageName.str(), 0xD0);
16128 }
16129 else {
16130 mIntro_PlayTextDuration = 0xAF / 2;
16131 mSurface->clearBuffer();
16132 }
16133
16134 mGraphics->PaletteSet();
16135 const sIntroString* IntroString = mVersionCurrent->getIntroData()->at(word_3B2CF).mText;
16136 if (IntroString) {
16137 while (IntroString->mPosition) {
16138
16139 Intro_Print_String(IntroString);
16140 ++IntroString;
16141 }
16142 }
16143 //loc_16710
16144
16145 int16 Duration = mIntro_PlayTextDuration;
16146 bool DoBreak = false;
16147
16148 while (mSurface->isPaletteAdjusting() || DoBreak == false) {
16149 --Duration;
16150
16151 if (Duration) {
16152 mSurface->palette_FadeTowardNew();
16153
16154 Mouse_Inputs_Get();
16155 if (mMouseButtonStatus) {
16156
16157 if (mVersionCurrent->getIntroData()->size() >= 2)
16158 word_3B2CF = ((int16)mVersionCurrent->getIntroData()->size()) - 2;
16159
16160 mImage_Aborted = -1;
16161 mSurface->paletteNew_SetToBlack();
16162 DoBreak = true;
16163 }
16164 }
16165 else {
16166 mSurface->paletteNew_SetToBlack();
16167 DoBreak = true;
16168 }
16169
16170 Video_SurfaceRender(false);
16171 Cycle_End();
16172 }
16173
16174
16175 }
16176
16177 return mImage_Aborted;
16178 }
16179
Mission_Intro_Play(const bool pShowHelicopter,eTileTypes pTileset)16180 void cFodder::Mission_Intro_Play(const bool pShowHelicopter, eTileTypes pTileset) {
16181
16182 // Single maps
16183 if (mCustom_Mode == eCustomMode_Map)
16184 return;
16185
16186 // If we don't have the briefing graphics, there is no point in switching here,
16187 // As the correct background for the map intro won't exist
16188 if (!mVersionCurrent->hasGfx(eGFX_BRIEFING))
16189 return;
16190
16191 mSurface->clearBuffer();
16192 mWindow->SetScreenSize(mVersionCurrent->GetScreenSize());
16193
16194 if (pTileset >= eTileTypes_Hid)
16195 pTileset = eTileTypes_Jungle;
16196
16197 mGraphics->Mission_Intro_Load_Resources(pTileset);
16198 mGraphics->SetActiveSpriteSheet(eGFX_BRIEFING);
16199
16200 mMouse_Exit_Loop = false;
16201 mSound->Music_Play(0x07);
16202 Mission_Intro_Helicopter_Start();
16203
16204 Mission_Intro_Draw_Mission_Name();
16205 mSurface->Save();
16206
16207 // Prior to mission 4, the UFO is not shown on the mission intro
16208 bool ShowHelicopter = true;
16209 if (mVersionCurrent->isCannonFodder2() && mGame_Data.mMission_Number < 4 && !pShowHelicopter)
16210 ShowHelicopter = false;
16211
16212
16213 mVersionPlatformSwitchDisabled = true;
16214 mGraphics->Mission_Intro_Play(ShowHelicopter, pTileset);
16215 mVersionPlatformSwitchDisabled = false;
16216 }
16217
Intro_Print_String(const sIntroString * pString)16218 void cFodder::Intro_Print_String(const sIntroString* pString) {
16219
16220 auto PosY = pString->mPosition + PLATFORM_BASED(-0x19, 9);
16221
16222 String_CalculateWidth(320, mFont_Intro_Width, pString->mText);
16223 String_Print(mFont_Intro_Width, 0, mGUI_Temp_X, PosY, pString->mText);
16224 }
16225
Image_FadeIn()16226 void cFodder::Image_FadeIn() {
16227 mSurface->Save();
16228 mGraphics->PaletteSet();
16229 mGame_Data.mDemoRecorded.DisableTicks();
16230 while (mSurface->isPaletteAdjusting()) {
16231 mSurface->palette_FadeTowardNew();
16232 Mouse_Inputs_Get();
16233
16234 Video_SurfaceRender();
16235 Cycle_End();
16236 }
16237
16238 mGame_Data.mDemoRecorded.EnableTicks();
16239 }
16240
Image_FadeOut()16241 void cFodder::Image_FadeOut() {
16242
16243 mSurface->Save();
16244 mSurface->paletteNew_SetToBlack();
16245 #ifdef EMSCRIPTEN
16246 return;
16247 #endif
16248 mGame_Data.mDemoRecorded.DisableTicks();
16249 while (mSurface->isPaletteAdjusting()) {
16250
16251 Mouse_Inputs_Get();
16252 //Mouse_DrawCursor();
16253
16254 // BUGFIX: Prevent a pallete bug when version switching
16255 if (mRecruit_Screen_Active) {
16256 Recruit_Cycle();
16257 } else
16258 mSurface->palette_FadeTowardNew();
16259
16260 Video_SurfaceRender();
16261 Cycle_End();
16262
16263 }
16264 mGame_Data.mDemoRecorded.EnableTicks();
16265
16266 }
16267
SetActiveSpriteSheetPtr(const sSpriteSheet ** pSpriteSheet)16268 void cFodder::SetActiveSpriteSheetPtr(const sSpriteSheet** pSpriteSheet) {
16269
16270 mSprite_SheetPtr = pSpriteSheet;
16271 }
16272
intro_Retail()16273 void cFodder::intro_Retail() {
16274
16275 // Disabled: GOG CD Version doesn't require a manual check
16276 // CopyProtection();
16277 mGraphics->Load_Sprite_Font();
16278
16279 mSound->Music_Play(CANNON_BASED(16, 20));
16280
16281 if (mVersionCurrent->isCannonFodder1())
16282 intro_LegionMessage();
16283
16284 if (mVersionCurrent->isCannonFodder2())
16285 sleepLoop(1000);
16286
16287 mPhase_Aborted = false;
16288
16289 if (ShowImage_ForDuration("cftitle", CANNON_BASED(0x1F8 / 3, 0x280 / 3)))
16290 return;
16291
16292 if (intro_Play())
16293 return;
16294
16295 if (ShowImage_ForDuration("virgpres", 0x2D0 / 3))
16296 return;
16297
16298 if (ShowImage_ForDuration("sensprod", 0x2D0 / 3))
16299 return;
16300
16301 if (ShowImage_ForDuration("cftitle", 0x318 / 3))
16302 return;
16303 }
16304
intro_AmigaTheOne()16305 void cFodder::intro_AmigaTheOne() {
16306 static bool ShownWarning = false;
16307
16308 if (!ShownWarning) {
16309 ShownWarning = true;
16310 ShowImage_ForDuration("PRETENTIOUS1", 0x60, 3, false);
16311 }
16312
16313 if (ShowImage_ForDuration("sensprod.lbm", 0x60))
16314 return;
16315
16316 if (ShowImage_ForDuration("virgpres.lbm", 0x60))
16317 return;
16318
16319 if (ShowImage_ForDuration("cftitle.lbm", 0x100))
16320 return;
16321 }
16322
ShowImage_ForDuration(const std::string & pFilename,uint16 pDuration,size_t pBackColor,bool pCanAbort)16323 int16 cFodder::ShowImage_ForDuration(const std::string& pFilename, uint16 pDuration, size_t pBackColor, bool pCanAbort) {
16324 bool DoBreak = false;
16325
16326 mGraphics->Load_And_Draw_Image(pFilename, 0x100, pBackColor);
16327 mGraphics->PaletteSet();
16328
16329 while (mSurface->isPaletteAdjusting() || DoBreak == false) {
16330 Mouse_Inputs_Get();
16331 --pDuration;
16332
16333 if (pDuration) {
16334 if (mSurface->isPaletteAdjusting())
16335 mSurface->palette_FadeTowardNew();
16336
16337 if (pCanAbort && (mMouseButtonStatus || mPhase_Aborted)) {
16338 mPhase_Aborted = false;
16339 mImage_Aborted = -1;
16340 mSurface->paletteNew_SetToBlack();
16341 DoBreak = true;
16342 }
16343 }
16344 else {
16345 mSurface->paletteNew_SetToBlack();
16346 DoBreak = true;
16347 }
16348
16349 Video_SurfaceRender(false);
16350 Cycle_End();
16351 }
16352
16353 return mImage_Aborted;
16354 }
16355
Video_SurfaceRender(const bool pRestoreSurface)16356 void cFodder::Video_SurfaceRender(const bool pRestoreSurface) {
16357
16358 if (mStartParams->mDisableVideo)
16359 return;
16360
16361 mSurface->draw();
16362 mWindow->RenderAt(mSurface);
16363 mWindow->FrameEnd();
16364
16365 if(pRestoreSurface)
16366 mSurface->Restore();
16367 }
16368
Cycle_End()16369 void cFodder::Cycle_End() {
16370 #ifndef _OFED
16371 if (mParams->mSleepDelta) {
16372 mTicksDiff = SDL_GetTicks() - mTicksDiff;
16373 mTicks = mTicksDiff * 40 / 1000;
16374 sleepLoop(mParams->mSleepDelta * 1000 / 40 - mTicksDiff);
16375 mTicksDiff = SDL_GetTicks();
16376 }
16377 #endif
16378
16379 // New Cycle begins
16380
16381 mWindow->Cycle();
16382 eventsProcess();
16383 }
16384
sleepLoop(int64 pMilliseconds)16385 void cFodder::sleepLoop(int64 pMilliseconds) {
16386 #ifdef EMSCRIPTEN
16387 return;
16388 #endif
16389 uint64 TimeStarted = SDL_GetTicks();
16390 uint64 TimeFinish = TimeStarted + pMilliseconds;
16391
16392 do {
16393 mWindow->EventCheck();
16394
16395 if (SDL_GetTicks() >= TimeFinish)
16396 break;
16397
16398 SDL_Delay(1);
16399
16400 } while (1);
16401
16402 }
16403
WonGame()16404 void cFodder::WonGame() {
16405
16406 if (mParams->mSinglePhase)
16407 return;
16408
16409 mMouseX = -1;
16410 mMouseY = -1;
16411
16412 mWindow->SetScreenSize(mVersionCurrent->GetSecondScreenSize());
16413
16414 if (mVersionCurrent->isAmigaTheOne()) {
16415 // mGraphics->Load_And_Draw_Image("PRETENTIOUS2", 0x100);
16416 mGraphics->Load_And_Draw_Image("PRETENTIOUS3", 0x100);
16417 } else {
16418 mSound->Music_Play(17);
16419 mGraphics->Load_And_Draw_Image("WON", 0x100);
16420 }
16421
16422 Image_FadeIn();
16423
16424 for (int count = 500; count >= 0; --count) {
16425 Video_SurfaceRender();
16426 Cycle_End();
16427 }
16428
16429 Image_FadeOut();
16430
16431 mWindow->SetScreenSize(mVersionCurrent->GetScreenSize());
16432 }
16433
Sprite_Handle_Troop_Get_Frame_For_Direction(sSprite * pSprite)16434 int16 cFodder::Sprite_Handle_Troop_Get_Frame_For_Direction(sSprite* pSprite) {
16435 int16 FrameNumber = pSprite->field_10;
16436
16437 FrameNumber >>= 5;
16438 FrameNumber -= 1;
16439 FrameNumber ^= 0x0F;
16440 FrameNumber &= 0x0E;
16441
16442 return FrameNumber;
16443 }
16444
Sprite_Reached_MapEdge(sSprite * pSprite)16445 void cFodder::Sprite_Reached_MapEdge(sSprite* pSprite) {
16446
16447 if (pSprite->field_4 < 0 || pSprite->field_4 <= 13) {
16448 pSprite->field_4 = mStoredSpriteY;
16449 mSprite_Reached_Target = -1;
16450 }
16451
16452 if (pSprite->field_4 >= mMapLoaded->getHeightPixels()) {
16453 if (pSprite->field_38 == eSprite_Anim_None || pSprite->field_38 >= eSprite_Anim_Slide1) {
16454 pSprite->field_4 = mStoredSpriteY;
16455 mSprite_Reached_Target = -1;
16456 }
16457 }
16458 //loc_204E1
16459 if (pSprite->field_0 <= 0) {
16460 if (mStoredSpriteX <= 0)
16461 return;
16462
16463 goto loc_20521;
16464 }
16465
16466 if (pSprite->field_0 + 12 < mMapLoaded->getWidthPixels())
16467 return;
16468
16469 if (mStoredSpriteX + 16 >= mMapLoaded->getWidthPixels())
16470 return;
16471
16472 loc_20521:;
16473 pSprite->field_0 = mStoredSpriteX;
16474 mSprite_Reached_Target = -1;
16475 }
16476
Sprite_Destroy_Wrapper(sSprite * pSprite)16477 int16 cFodder::Sprite_Destroy_Wrapper(sSprite* pSprite) {
16478
16479 return Sprite_Destroy(pSprite);
16480 }
16481
Sprite_Destroy(sSprite * pSprite)16482 int16 cFodder::Sprite_Destroy(sSprite* pSprite) {
16483
16484 pSprite->field_65 = 0;
16485 pSprite->field_8 = 0x7C;
16486 pSprite->field_18 = eSprite_Null;
16487 pSprite->field_A = 0;
16488 pSprite->field_24 = 1;
16489
16490 return 1;
16491 }
16492
Sprite_Create_Bullet(sSprite * pSprite)16493 int16 cFodder::Sprite_Create_Bullet(sSprite* pSprite) {
16494 int16 Data0 = 1, Data8, Data4;
16495 sSprite* Data2C = 0, *Data30 = 0;
16496
16497 if (mPhase_Completed_Timer)
16498 return -1;
16499
16500 if (!pSprite->field_2E)
16501 return -1;
16502
16503 if (pSprite == mSquad_Leader)
16504 if (pSprite->field_54 == 1)
16505 return -1;
16506
16507 if (Sprite_Get_Free_Max42(Data0, Data2C, Data30))
16508 return -1;
16509
16510 if (mSprite_Projectile_Counters[2] == 0x14)
16511 return -1;
16512
16513 ++mSprite_Projectile_Counters[2];
16514 pSprite->field_54 = 2;
16515 pSprite->field_5A = -1;
16516 pSprite->field_57 = 8;
16517 Data2C->field_0 = pSprite->field_0;
16518 Data2C->field_2 = pSprite->field_2;
16519 Data2C->field_4 = pSprite->field_4;
16520 Data2C->field_6 = pSprite->field_6;
16521 Data2C->field_8 = 0x9D;
16522 //seg005:1023
16523 Data0 = pSprite->field_3C;
16524 Data0 >>= 1;
16525 Data0 &= 0x07;
16526 Data2C->field_A = Data0;
16527 Data2C->field_12 = 9;
16528
16529 if (pSprite->field_18 != eSprite_Player) {
16530
16531 Data0 = pSprite->field_62;
16532 Data0 >>= 3;
16533 Data0 += 8;
16534 if (Data0 > 0x10)
16535 Data0 = 0x10;
16536 Data2C->field_12 = Data0;
16537 }
16538 else {
16539
16540 Data2C->field_5E_SoldierAllocated = pSprite->field_46_mission_troop;
16541 Data2C->field_5D = -1;
16542
16543 // Bullet Travel time
16544 Data0 = mSprite_Weapon_Data.mAliveTime;
16545 Data0 += mSprite_Bullet_Time_Modifier;
16546 Data2C->field_12 = Data0;
16547 }
16548
16549 Data2C->field_18 = eSprite_Bullet;
16550 Data2C->field_1E_Big = pSprite->field_1E_Big;
16551 Data2C->field_20 += 6;
16552 Data2C->field_52 = pSprite->field_52;
16553 Data2C->field_22 = pSprite->field_22;
16554 Data2C->field_32 = pSprite->field_32;
16555 Data2C->field_2C = eSprite_Draw_Second;
16556 if (pSprite->field_22 != eSprite_PersonType_Human)
16557 goto loc_2087D;
16558
16559 Data0 = mSprite_Weapon_Data.mSpeed;
16560 Data0 += mSprite_Bullet_Fire_Speed_Modifier;
16561 Data2C->field_4A = Data0;
16562
16563 Data0 = tool_RandomGet() & 0x0F;
16564 Data0 <<= 3;
16565 Data2C->field_36 = Data0;
16566 goto loc_208A6;
16567
16568 loc_2087D:;
16569 // AI Fire Speed
16570 Data0 = 0x3C;
16571 Data0 += pSprite->field_62;
16572 Data2C->field_4A = Data0;
16573 Data2C->field_36 = 0x18;
16574
16575 loc_208A6:;
16576 Data2C->field_43 = 0;
16577 Data2C->field_44 = 0;
16578 Data2C->field_2E = pSprite->field_2E;
16579 Data2C->field_30 = pSprite->field_30;
16580 if (pSprite->field_18 != eSprite_Player)
16581 Data2C->field_2E += 7;
16582 else
16583 Data2C->field_30 += 0x0F;
16584
16585 Data2C->field_52 = 0;
16586 Data2C->field_3A = 0;
16587
16588 Data2C->field_1A_sprite = pSprite;
16589 Data2C->field_2A = 2;
16590 Data2C->field_16 = 0;
16591 Data2C->field_14 = 2;
16592
16593 if (Data2C->field_A == 4)
16594 Data2C->field_14 = -1;
16595
16596 Data2C->field_34 = -1;
16597 Data2C->field_50 = 0;
16598 Data2C->field_59 = 0;
16599 Data8 = 7;
16600
16601 // Is Human?
16602 if (pSprite->field_22 == eSprite_PersonType_Human) {
16603
16604 if (pSprite == mSquad_Leader) {
16605
16606 mSprite_Bullet_Deviate_Counter += 1;
16607 mSprite_Bullet_Deviate_Counter &= 3;
16608
16609 if (!mSprite_Bullet_Deviate_Counter)
16610 goto loc_209F3;
16611
16612 Data8 = mSprite_Weapon_Data.mDeviatePotential;
16613 }
16614 else {
16615
16616 Data8 = Mission_Troop_GetDeviatePotential(pSprite->field_46_mission_troop);
16617 }
16618 }
16619
16620 Data0 = tool_RandomGet();
16621 Data4 = Data0;
16622
16623 Data0 &= Data8;
16624 if (Data4 < 0)
16625 Data0 = -Data0;
16626
16627 Data2C->field_50 = Data0;
16628
16629 loc_209F3:;
16630 Data2C->field_64 = 0;
16631 Data0 = tool_RandomGet() & 1;
16632 if (!Data0)
16633 Data4 = 0x11;
16634 else
16635 Data4 = 0x10;
16636
16637 Sound_Play(pSprite, Data4, 0);
16638 return 0;
16639 }
16640
Sprite_Create_Grenade(sSprite * pSprite)16641 int16 cFodder::Sprite_Create_Grenade(sSprite* pSprite) {
16642 int16 Data0, Data4, Data8, DataC;
16643 sSprite* Data2C = 0, *Data30 = 0;
16644
16645 if (mPhase_Completed_Timer)
16646 goto loc_20ADE;
16647
16648 if (mSprite_Projectile_Counters[pSprite->field_22] == 2)
16649 goto loc_20ADE;
16650
16651 if (!pSprite->field_2E)
16652 goto loc_20ADE;
16653
16654 if (pSprite->field_18 != eSprite_Enemy)
16655 goto loc_20AC1;
16656
16657 Data0 = pSprite->field_0;
16658 Data4 = pSprite->field_4;
16659 Data8 = pSprite->field_2E;
16660 DataC = pSprite->field_30;
16661 Map_Get_Distance_BetweenPoints_Within_Window(Data0, Data4, Data8, DataC);
16662 if (Data0 >= 0x82)
16663 goto loc_20ADE;
16664
16665 loc_20AC1:;
16666
16667 Data0 = 2;
16668
16669 if (!Sprite_Get_Free_Max42(Data0, Data2C, Data30))
16670 goto loc_20B0A;
16671
16672 return -1;
16673
16674 loc_20ADE:;
16675 if (pSprite == mSquad_Leader)
16676 mMouse_Button_LeftRight_Toggle = false;
16677
16678 return -1;
16679
16680 loc_20B0A:;
16681 if (pSprite->field_18 != eSprite_Player)
16682 goto loc_20B6E;
16683
16684 Data0 = pSprite->field_32;
16685 Data4 = Data0;
16686 if (!mSquad_Grenades[Data0])
16687 goto loc_20ADE;
16688
16689 --mSquad_Grenades[Data0];
16690 mGUI_RefreshSquadGrenades[Data4] = -1;
16691
16692 loc_20B6E:;
16693
16694 ++mSprite_Projectile_Counters[pSprite->field_22];
16695 pSprite->field_55 = 1;
16696 pSprite->field_5A = -1;
16697 pSprite->field_54 = 1;
16698
16699 Data30 = Data2C;
16700 ++Data30;
16701 //seg005:14CE
16702 Data2C->field_0 = pSprite->field_0;
16703 Data2C->field_2 = pSprite->field_2;
16704 Data30->field_0 = pSprite->field_0;
16705 Data30->field_2 = pSprite->field_2;
16706 //seg005:14F4
16707 Data2C->field_4 = pSprite->field_4;
16708 Data2C->field_6 = pSprite->field_6;
16709 Data30->field_4 = pSprite->field_4;
16710 Data30->field_6 = pSprite->field_6;
16711 Data2C->field_8 = 0x7D;
16712 Data30->field_8 = 0x7E;
16713 Data2C->field_A = 0;
16714 Data30->field_A = 0;
16715 Data2C->field_12 = 0x10;
16716 Data0 = tool_RandomGet();
16717 Data0 &= 0x0F;
16718 Data2C->field_12 = Data0;
16719 Data8 = pSprite->field_2E;
16720 DataC = pSprite->field_30;
16721 DataC += 0x06;
16722 //seg005:158C
16723 Data2C->field_26 = Data8;
16724 Data2C->field_28 = DataC;
16725 Data0 = 0;
16726 Data0 = pSprite->field_0;
16727 Data4 = pSprite->field_4;
16728
16729 Map_Get_Distance_BetweenPoints_Within_Window(Data0, Data4, Data8, DataC);
16730 if (Data0 < 0x14)
16731 Data0 = 0x14;
16732
16733 Data0 /= 5;
16734
16735 if (Data0 > 0x64)
16736 Data0 = 0x64;
16737
16738 //loc_20CEA
16739 Data2C->field_12 = Data0;
16740 Data2C->field_36 = 0x32;
16741 Data30->field_36 = 0x32;
16742 Data2C->field_1E = 0x0000;
16743 Data2C->field_20 = 0x7;
16744 Data30->field_1E = 0;
16745 Data30->field_20 = 0;
16746 Data2C->field_4 += 1;
16747 Data2C->field_0 += 3;
16748 int32 Dataa0 = Data2C->field_12 << 16;
16749
16750 Dataa0 >>= 1;
16751 if (Dataa0 > 0x0E0000)
16752 Dataa0 = 0x0E0000;
16753
16754 Data2C->field_1A = Dataa0;
16755 Data2C->field_18 = eSprite_Grenade;
16756 Data30->field_18 = eSprite_ShadowSmall;
16757 Data2C->field_52 = 0;
16758 Data30->field_52 = 0;
16759 Data2C->field_50 = 0;
16760 Data2C->field_22 = pSprite->field_22;
16761 Data30->field_22 = pSprite->field_22;
16762 Data2C->field_32 = pSprite->field_32;
16763 Data2C->field_2C = eSprite_Draw_Second;
16764 Data30->field_2C = eSprite_Draw_First;
16765 Data2C->field_38 = eSprite_Anim_None;
16766 if (pSprite->field_18 == eSprite_Enemy)
16767 Data2C->field_12 += 0x1C;
16768 Data2C->field_56 = 4;
16769 Data2C->field_46_sprite = pSprite;
16770
16771 if (pSprite == mSquad_Leader)
16772 mMouse_Button_LeftRight_Toggle = false;
16773
16774 return 0;
16775 }
16776
Sprite_Set_Direction_To_Next(sSprite * pSprite)16777 void cFodder::Sprite_Set_Direction_To_Next(sSprite* pSprite) {
16778 int16 Data0 = pSprite->field_10;
16779
16780 Data0 >>= 5;
16781 Data0 -= 1;
16782 Data0 ^= 0x0F;
16783 Data0 &= 0x0F;
16784 pSprite->field_3C = Data0;
16785
16786 mDirectionMod = 0;
16787 }
16788
Sprite_Reached_Target(sSprite * pSprite)16789 int16 cFodder::Sprite_Reached_Target(sSprite* pSprite) {
16790
16791 // Sprite is moving?
16792 if (pSprite->field_36 <= 8)
16793 return 0;
16794
16795 int16 Data0 = pSprite->field_26;
16796 int16 Data4 = pSprite->field_28;
16797
16798 int16 Data8 = pSprite->field_0;
16799 int16 DataC = pSprite->field_4;
16800
16801 Map_Get_Distance_BetweenPoints_Within_Window(Data0, Data4, Data8, DataC);
16802 if (Data0 > 2)
16803 return 0;
16804
16805 pSprite->field_0 = pSprite->field_26;
16806 pSprite->field_4 = pSprite->field_28;
16807
16808 mSprite_Reached_Target = -1;
16809 return -1;
16810 }
16811
Sprite_Movement_Speed_Update(sSprite * pSprite)16812 void cFodder::Sprite_Movement_Speed_Update(sSprite* pSprite) {
16813 int16 Data0 = pSprite->field_10;
16814
16815 if (pSprite->field_60 != eTerrainFeature_D)
16816 goto loc_20FBB;
16817
16818 //seg005:1843
16819
16820 if (Data0 < 0xD0)
16821 goto loc_20F63;
16822
16823 if (Data0 < 0x130)
16824 goto loc_20FD1;
16825
16826 if (Data0 <= 0x170)
16827 goto loc_20FD9;
16828
16829 if (Data0 <= 0x190)
16830 return;
16831
16832 if (Data0 <= 0x1C0)
16833 goto loc_20F9B;
16834
16835 goto loc_20F7B;
16836
16837 loc_20F63:;
16838 if (Data0 >= 0x90)
16839 goto loc_20FD9;
16840
16841 if (Data0 >= 0x70)
16842 return;
16843
16844 if (Data0 >= 0x40)
16845 goto loc_20F9B;
16846
16847 loc_20F7B:;
16848 Data0 = pSprite->field_36;
16849 Data0 >>= 2;
16850 pSprite->field_36 += Data0;
16851 return;
16852
16853 loc_20F9B:;
16854 Data0 = pSprite->field_36;
16855 Data0 >>= 3;
16856 pSprite->field_36 += Data0;
16857 return;
16858
16859 loc_20FBB:;
16860 if (pSprite->field_60 == eTerrainFeature_Rocky)
16861 goto loc_20FD1;
16862
16863 if (pSprite->field_60 != eTerrainFeature_Rocky2)
16864 goto loc_20FE3;
16865
16866 loc_20FD1:;
16867 pSprite->field_36 >>= 1;
16868
16869 loc_20FD9:;
16870 pSprite->field_36 >>= 1;
16871 return;
16872 loc_20FE3:;
16873 if (pSprite->field_60 != eTerrainFeature_Snow)
16874 return;
16875
16876 Data0 = pSprite->field_0;
16877 Data0 += pSprite->field_4;
16878 Data0 &= 3;
16879 if (Data0 == 0)
16880 return;
16881 Data0 = pSprite->field_36;
16882 Data0 >>= 2;
16883 pSprite->field_36 -= Data0;
16884 }
16885
Sprite_Handle_Player_Close_To_SquadMember(sSprite * pSprite)16886 void cFodder::Sprite_Handle_Player_Close_To_SquadMember(sSprite* pSprite) {
16887
16888 // Not Human?
16889 if (pSprite->field_22 != eSprite_PersonType_Human) {
16890 pSprite->field_4D = 0;
16891 return;
16892 }
16893
16894 word_3B2F3 = 0;
16895
16896 // Find this sprite in the squad
16897 sSprite** PreviousMember = mSquads[pSprite->field_32];
16898
16899 // Loop until we find this squad member
16900 for (;;) {
16901 if (*PreviousMember == INVALID_SPRITE_PTR)
16902 return;
16903
16904 sSprite* eax = *PreviousMember;
16905 ++PreviousMember;
16906
16907 // Found this troop?
16908 if (pSprite == eax)
16909 break;
16910 }
16911
16912 // Get the previous squad member
16913 --PreviousMember;
16914
16915 // If PreviousMember is Squad Leader, return
16916 if (mSquads[pSprite->field_32] == PreviousMember)
16917 return;
16918
16919 // Get the previous members, previous member
16920 PreviousMember--;
16921
16922 //seg005:1A13
16923 sSprite* Data24 = *PreviousMember;
16924
16925 // Near the other member?
16926 if (pSprite->field_0 + 8 < Data24->field_0)
16927 return;
16928
16929 if (Data24->field_0 + 8 < pSprite->field_0)
16930 return;
16931
16932 if (Data24->field_4 + 2 < pSprite->field_4 - 2)
16933 return;
16934
16935 if (pSprite->field_4 + 2 < Data24->field_4 - 2)
16936 return;
16937
16938 // In Vehicle?
16939 if (Data24->field_6E)
16940 return;
16941
16942 // Different Walk Target?
16943 int16 Data1C = pSprite->field_40;
16944 if (Data1C != Data24->field_40)
16945 return;
16946
16947 // Restore the previous XY
16948 Sprite_XY_Restore(pSprite);
16949 mSprite_Bumped_Into_SquadMember = -1;
16950
16951 pSprite->field_43 = 1;
16952 word_3B2F3 = -1;
16953 }
16954
Sprite_Get_Free_Max42(int16 & pData0,sSprite * & pData2C,sSprite * & pData30)16955 int16 cFodder::Sprite_Get_Free_Max42(int16& pData0, sSprite*& pData2C, sSprite*& pData30) {
16956
16957 //
16958 if (!mSprite_SpareUsed) {
16959
16960 // Looking for two sprites?
16961 if (pData0 == 3) {
16962 pData2C = mSprites.data();
16963
16964 // Loop all sprites
16965 for (int32_t Data1C = mParams->mSpritesMax - 5; Data1C >= 0; --Data1C, ++pData2C) {
16966
16967 // Sprite free?
16968 if (pData2C->field_0 != -32768)
16969 continue;
16970
16971 if ((pData2C + 1)->field_0 != -32768)
16972 continue;
16973
16974 // Second sprite free?
16975 if ((pData2C + 2)->field_0 == -32768) {
16976 pData30 = pData2C + 1;
16977
16978 pData2C->Clear();
16979 pData30->Clear();
16980 (pData30 + 1)->Clear(); // Yuck
16981
16982 pData0 = 0;
16983 return 0;
16984 }
16985 }
16986 } else if (pData0 == 2) {
16987 pData2C = mSprites.data();
16988
16989 // Loop all sprites
16990 for (int32_t Data1C = mParams->mSpritesMax - 4; Data1C >= 0; --Data1C, ++pData2C) {
16991
16992 // Sprite free?
16993 if (pData2C->field_0 != -32768)
16994 continue;
16995
16996 // Second sprite free?
16997 if ((pData2C + 1)->field_0 == -32768) {
16998 pData30 = pData2C + 1;
16999
17000 pData2C->Clear();
17001 pData30->Clear();
17002 pData0 = 0;
17003 return 0;
17004 }
17005 }
17006 }
17007 else {
17008 // Only looking for 1 sprite
17009 pData2C = &mSprites[mParams->mSpritesMax - 3];
17010
17011 for (int32 Data1C = mParams->mSpritesMax - 3; Data1C >= 0; --Data1C) {
17012
17013 // Free?
17014 if (pData2C->field_0 == -32768) {
17015 pData2C->Clear();
17016 pData0 = 0;
17017 return 0;
17018 }
17019
17020 --pData2C;
17021 }
17022 }
17023 }
17024
17025 //loc_211F0
17026 pData2C = &mSprite_Spare;
17027 pData30 = &mSprite_Spare;
17028 pData0 = -1;
17029 mSprite_SpareUsed = pData0;
17030 return -1;
17031 }
17032
Sprite_Get_Free_Max29(int16 & pData0,sSprite * & pData2C,sSprite * & pData30)17033 int16 cFodder::Sprite_Get_Free_Max29(int16& pData0, sSprite*& pData2C, sSprite*& pData30) {
17034 if (mSprite_SpareUsed2)
17035 goto loc_21B4B;
17036
17037 if (pData0 == 2)
17038 goto loc_21B91;
17039
17040 pData2C = &mSprites[mParams->mSpritesMax - 16];
17041 for (int32_t Data1C = mParams->mSpritesMax - 16; Data1C >= 0; --Data1C, --pData2C) {
17042
17043 if (pData2C->field_0 == -32768) {
17044 pData2C->Clear();
17045 pData0 = 0;
17046 return 0;
17047 }
17048 }
17049
17050 loc_21B4B:;
17051 pData2C = &mSprite_Spare;
17052 pData30 = &mSprite_Spare;
17053 pData0 = -1;
17054 mSprite_SpareUsed2 = pData0;
17055 return -1;
17056
17057 loc_21B91:;
17058 pData2C = mSprites.data();
17059
17060 for (int32_t Data1C = mParams->mSpritesMax - 17; Data1C >= 0; --Data1C, ++pData2C) {
17061
17062 if (pData2C->field_0 != -32768)
17063 continue;
17064
17065 if ((pData2C + 1)->field_0 == -32768) {
17066 pData30 = pData2C + 1;
17067 pData0 = 0;
17068 }
17069 }
17070
17071 pData2C = &mSprite_Spare;
17072 pData30 = &mSprite_Spare;
17073 pData0 = -1;
17074 mSprite_SpareUsed2 = pData0;
17075 return -1;
17076 }
17077
Sprite_Handle_Exploidable(sSprite * pSprite)17078 void cFodder::Sprite_Handle_Exploidable(sSprite* pSprite) {
17079 int64 Dat0;
17080 int32 Dat4;
17081 int16 Data0, Data4;
17082
17083 if (pSprite->field_5B)
17084 goto loc_2132A;
17085
17086 if (pSprite->field_20)
17087 goto loc_2132A;
17088
17089 if (pSprite->field_38 == eSprite_Anim_Die1)
17090 goto loc_213F7;
17091
17092 if (pSprite->field_38 > eSprite_Anim_Die1)
17093 goto loc_2132A;
17094
17095 pSprite->field_5B = 0;
17096 return;
17097
17098 loc_2132A:;
17099
17100 Sprite_Movement_Calculate(pSprite);
17101
17102 Dat0 = (int64)pSprite->field_1A;
17103 Dat4 = (pSprite->field_1E & 0xFFFF) | (pSprite->field_20 << 16);
17104
17105 Dat0 -= 0x28000;
17106 Dat4 += (int32)Dat0;
17107
17108 if (Dat4 < 0) {
17109 Dat4 = 0;
17110 Dat0 = -Dat0;
17111 Dat0 >>= 2;
17112 }
17113
17114 pSprite->field_1A = (int32)Dat0;
17115 pSprite->field_1E_Big = Dat4;
17116
17117 if (!(Dat4 >> 16)) {
17118 if (!(Dat0 >> 16))
17119 goto loc_21464;
17120 }
17121
17122 Data0 = -3;
17123 Data4 = 0x0C;
17124
17125 Map_Terrain_Get_Type_And_Walkable(pSprite, Data0, Data4);
17126
17127 if (pSprite->field_20)
17128 return;
17129
17130 if (Data4 == eTerrainFeature_WaterEdge)
17131 goto loc_21464;
17132
17133 if (Data4 == eTerrainFeature_Water)
17134 goto loc_21464;
17135
17136 if (Data4 == eTerrainFeature_Drop)
17137 goto loc_21464;
17138
17139 if (Data4 == eTerrainFeature_Drop2)
17140 goto loc_21464;
17141
17142 return;
17143
17144 loc_213F7:;
17145
17146 if (mPhase_Completed_Timer)
17147 return;
17148
17149 pSprite->field_38 = eSprite_Anim_Die2;
17150 pSprite->field_5B = -1;
17151 pSprite->field_1E = 0x0000;
17152 pSprite->field_20 = 0x1;
17153
17154 Data0 = tool_RandomGet() & 0x1FE;
17155 pSprite->field_10 = Data0;
17156
17157 Data0 = tool_RandomGet() & 0x1F;
17158 Data0 += 0x14;
17159
17160 pSprite->field_36 = Data0;
17161 pSprite->field_1A = 0x1C0000;
17162 Sprite_Create_Shadow(pSprite);
17163 return;
17164
17165 loc_21464:;
17166 pSprite->field_18 = eSprite_Explosion;
17167 pSprite->field_26 = 0x5F5F;
17168 pSprite->field_28 = 8;
17169 }
17170
Sprite_Create_Shadow(sSprite * pSprite)17171 void cFodder::Sprite_Create_Shadow(sSprite* pSprite) {
17172 int16 Data0 = 1;
17173 sSprite* Data2C = 0, *Data30 = 0;
17174
17175 if (Sprite_Get_Free_Max42(Data0, Data2C, Data30))
17176 return;
17177
17178 Data2C->field_1A_sprite = pSprite;
17179
17180 Data2C->field_0 = pSprite->field_0;
17181 Data2C->field_2 = pSprite->field_2;
17182 Data2C->field_4 = pSprite->field_4;
17183 Data2C->field_6 = pSprite->field_6;
17184
17185 Data2C->field_0 += 0x0E;
17186 Data2C->field_4 += 0x10;
17187 Data2C->field_8 = 0x8D;
17188 Data2C->field_A = 0;
17189 Data2C->field_18 = eSprite_Shadow;
17190 Data2C->field_20 = 0;
17191 Data2C->field_32 = -1;
17192 Data2C->field_2C = eSprite_Draw_First;
17193 Data2C->field_52 = 0;
17194 }
17195
Sprite_Handle_Grenade_Terrain_Check(sSprite * pSprite)17196 void cFodder::Sprite_Handle_Grenade_Terrain_Check(sSprite* pSprite) {
17197 int16 Data0 = -3;
17198 int16 Data4 = 2;
17199
17200 if (Map_Terrain_Get_Type_And_Walkable(pSprite, Data0, Data4))
17201 goto loc_21599;
17202
17203 if (Data4 == eTerrainFeature_Drop || Data4 == eTerrainFeature_Drop2) {
17204
17205 if (pSprite->field_20 <= 1) {
17206 pSprite->field_12 = 1;
17207 return;
17208 }
17209 }
17210 //loc_21561
17211 if (Data4 == eTerrainFeature_QuickSand || Data4 == eTerrainFeature_WaterEdge
17212 || Data4 == eTerrainFeature_Water) {
17213
17214 if (pSprite->field_20)
17215 return;
17216
17217 pSprite->field_52 = 6;
17218 (pSprite + 1)->field_52 = 6;
17219 return;
17220 }
17221 //loc_21597
17222 return;
17223
17224 loc_21599:;
17225 if (pSprite->field_20 >= 8)
17226 return;
17227
17228 pSprite->field_0 = mStoredSpriteX >> 16;
17229 Data0 = -3;
17230 Data4 = 2;
17231
17232 if (!Map_Terrain_Get_Type_And_Walkable(pSprite, Data0, Data4)) {
17233 Data0 = 0x100;
17234 Data0 -= pSprite->field_10;
17235 Data0 &= 0x1FE;
17236 pSprite->field_10 = Data0;
17237 }
17238 else {
17239 Data0 = 0x200;
17240 Data0 -= pSprite->field_10;
17241 Data0 &= 0x1FE;
17242 pSprite->field_10 = Data0;
17243 }
17244 Sprite_XY_Restore(pSprite);
17245 }
17246
Sprite_Projectile_Collision_Check(sSprite * pSprite)17247 int16 cFodder::Sprite_Projectile_Collision_Check(sSprite* pSprite) {
17248
17249 // If the projectile doesn't belong to a human, check if it hit a squad member
17250 if (pSprite->field_22 != eSprite_PersonType_Human) {
17251
17252 int16 Data8 = pSprite->field_0;
17253 int16 DataC = pSprite->field_0 + 6;
17254 int16 Data10 = pSprite->field_4 - 9;
17255 int16 Data14 = pSprite->field_4 - 4;
17256 word_3AA45 = 1;
17257
17258 return Squad_Member_Sprite_Hit_In_Region(pSprite, Data8, DataC, Data10, Data14);
17259 }
17260
17261 //loc_21673
17262 int16 Data8 = pSprite->field_0 - 6;
17263 int16 DataC = pSprite->field_0 + 10;
17264 int16 Data10 = pSprite->field_4 - 10;
17265 int16 Data14 = pSprite->field_4 + 6;
17266
17267 if (mVersionCurrent->isAmigaTheOne()) {
17268 Data8 = pSprite->field_0;
17269 DataC = pSprite->field_0 + 4;
17270 Data10 = pSprite->field_4 - 4;
17271 Data14 = pSprite->field_4;
17272 }
17273
17274 word_3AA45 = 1;
17275 sSprite* Data24 = 0;
17276 if (Sprite_Find_In_Region(pSprite, Data24, Data8, DataC, Data10, Data14) >= 0)
17277 return 0;
17278
17279 if (Data24->field_18 == eSprite_Enemy) {
17280
17281 Data24->field_5E_Squad = pSprite->field_5E_Squad;
17282 Data24->field_5E = pSprite->field_5E;
17283 Data24->field_5D = pSprite->field_5D;
17284 }
17285
17286 return -1;
17287 }
17288
Sprite_Create_Sparks(sSprite * pSprite,int16 pData18)17289 void cFodder::Sprite_Create_Sparks(sSprite* pSprite, int16 pData18) {
17290 int16 Data0 = 2;
17291 sSprite* Data2C, *Data30;
17292
17293 if (Sprite_Get_Free_Max42(Data0, Data2C, Data30))
17294 return;
17295
17296 Data30 = Data2C + 1;
17297 Data2C->field_0 = pSprite->field_0 + 2;
17298 Data2C->field_2 = pSprite->field_2;
17299 Data2C->field_4 = pSprite->field_4 - 4;
17300 Data2C->field_6 = pSprite->field_6;
17301
17302 Data30->field_0 = Data2C->field_0;
17303 Data30->field_4 = Data2C->field_4;
17304
17305 Data2C->field_1E_Big = pSprite->field_1E_Big;
17306
17307 Data30->field_20 = 0;
17308 Data2C->field_8 = 0xC5;
17309 Data30->field_8 = 0x7E;
17310 Data2C->field_A = 0;
17311 Data30->field_A = 0;
17312 Data2C->field_36 = 0x0C;
17313 Data30->field_36 = 0x0C;
17314 Data2C->field_18 = eSprite_Sparks;
17315 Data30->field_18 = eSprite_ShadowSmall;
17316 Data2C->field_52 = 0;
17317 Data30->field_52 = 0;
17318 Data2C->field_2C = eSprite_Draw_Second;
17319 Data30->field_2C = eSprite_Draw_First;
17320 Data2C->field_38 = eSprite_Anim_None;
17321
17322 Data2C->field_10 = pData18;
17323 Data2C->field_1A = 0x0A8000;
17324
17325 }
17326
Sprite_Create_FireTrail(sSprite * pSprite)17327 void cFodder::Sprite_Create_FireTrail(sSprite* pSprite) {
17328
17329 if (!pSprite->field_5C)
17330 return;
17331
17332 // cmp ds:word_3B1A9, 14h
17333 int16 Data0 = 1;
17334 sSprite* Data2C = 0, *Data30 = 0;
17335
17336 if (Sprite_Get_Free_Max42(Data0, Data2C, Data30))
17337 return;
17338
17339 Data2C->field_0 = pSprite->field_0;
17340 Data2C->field_2 = pSprite->field_2;
17341 Data2C->field_4 = pSprite->field_4;
17342 Data2C->field_6 = pSprite->field_6;
17343
17344 if (dword_3B24B == 0) {
17345 Data2C->field_4 -= 3;
17346 }
17347 else {
17348 Data2C->field_4 += 2;
17349 dword_3B24B = 0;
17350 }
17351
17352 Data2C->field_20 = pSprite->field_20;
17353 Data2C->field_52 = 0;
17354 Data2C->field_8 = 0xC6;
17355 Data2C->field_A = 0;
17356 Data2C->field_18 = eSprite_FireTrail;
17357 }
17358
Sprite_Turn_Into_Building_Explosion(sSprite * pSprite)17359 void cFodder::Sprite_Turn_Into_Building_Explosion(sSprite* pSprite) {
17360 int16 Data8 = pSprite->field_0;
17361 int16 DataC = pSprite->field_4;
17362
17363 pSprite->Clear();
17364 Sprite_Create_Building_Explosion(pSprite, Data8, DataC);
17365 }
17366
Sprite_Create_Building_Explosion_Wrapper(int16 & pX,int16 & pY)17367 int16 cFodder::Sprite_Create_Building_Explosion_Wrapper(int16& pX, int16& pY) {
17368 int16 Data0 = 1;
17369 sSprite* Data2C, *Data30;
17370
17371 if (Sprite_Get_Free_Max42(Data0, Data2C, Data30))
17372 return -1;
17373
17374 Data2C->Clear();
17375
17376 pX &= -16;
17377 pY &= -16;
17378
17379 return Sprite_Create_Building_Explosion(Data2C, pX, pY);
17380 }
17381
Sprite_Create_Building_Explosion(sSprite * pData2C,int16 & pX,int16 & pY)17382 int16 cFodder::Sprite_Create_Building_Explosion(sSprite* pData2C, int16& pX, int16& pY) {
17383
17384 pData2C->field_0 = pX;
17385 pData2C->field_4 = pY;
17386 pData2C->field_4 += 0x10;
17387
17388 int16 Data4 = mGame_InputTicks;
17389 Data4 &= 3;
17390 Data4 += 5;
17391
17392 Sound_Play(pData2C, Data4, 0x1E);
17393
17394 pData2C->field_18 = eSprite_Building_Explosion;
17395 pData2C->field_8 = 0x8E;
17396 pData2C->field_A = 0;
17397 pData2C->field_12 = 1;
17398 pData2C->field_22 = eSprite_PersonType_None;
17399 pData2C->field_32 = -1;
17400 pData2C->field_2C = eSprite_Draw_OnTop;
17401
17402 return 0;
17403 }
17404
Sprite_Create_Enemy(sSprite * pSprite,sSprite * & pData2C)17405 int16 cFodder::Sprite_Create_Enemy(sSprite* pSprite, sSprite*& pData2C) {
17406
17407 if (mPhase_Complete || mTroops_Enemy_Count >= mParams->mSpawnEnemyMax)
17408 return -1;
17409 int16 Data0 = 1;
17410 sSprite* Data30 = 0;
17411
17412 if (Sprite_Get_Free_Max29(Data0, pData2C, Data30))
17413 return -1;
17414
17415 //loc_21A1C:;
17416 pData2C->Clear();
17417 pData2C->field_18 = eSprite_Enemy;
17418 pData2C->field_0 = pSprite->field_0;
17419 pData2C->field_0 -= 6;
17420 pData2C->field_4 = pSprite->field_4;
17421 pData2C->field_4 += 4;
17422 pData2C->field_8 = 0x7C;
17423 pData2C->field_4A = 0;
17424 pData2C->field_22 = eSprite_PersonType_AI;
17425
17426 Data0 = tool_RandomGet() & 0xFF;
17427 Data0 += 0x78;
17428 Data0 = -Data0;
17429 pData2C->field_5E = Data0;
17430 Data0 = tool_RandomGet();
17431 int16 Data4 = Data0;
17432 Data0 &= 0x1E;
17433 if (Data4 < 0)
17434 Data0 = -Data0;
17435
17436 Data0 += 0x1C0;
17437 pData2C->field_10 = Data0;
17438 Data4 &= 0x0F;
17439 Data4 += 8;
17440 pData2C->field_44 = (int8)Data4;
17441 Sprite_Enemy_Aggression_Update(pData2C);
17442
17443 mGame_Data.mGamePhase_Data.mSprite_Enemy_AggressionCreated_Count += 1;
17444 mGame_Data.mGamePhase_Data.mSprite_Enemy_AggressionCreated_Count &= 0x0F;
17445 if (!mGame_Data.mGamePhase_Data.mSprite_Enemy_AggressionCreated_Count && mGame_Data.mGamePhase_Data.mSprite_Enemy_AggressionMax < 0x1E)
17446 ++mGame_Data.mGamePhase_Data.mSprite_Enemy_AggressionMax;
17447
17448 ++mTroops_Enemy_Count;
17449 return 0;
17450 }
17451
Sprite_Enemy_Aggression_Update(sSprite * pData2C)17452 void cFodder::Sprite_Enemy_Aggression_Update(sSprite* pData2C) {
17453 int16 Data8 = mGame_Data.mGamePhase_Data.mSprite_Enemy_AggressionNext;
17454 pData2C->field_62 = Data8;
17455
17456 int16 Data4 = mGame_Data.mGamePhase_Data.mSprite_Enemy_AggressionIncrement;
17457 Data8 += Data4;
17458
17459 if (Data4 < 0)
17460 goto loc_21C42;
17461
17462 if (Data8 < mGame_Data.mGamePhase_Data.mSprite_Enemy_AggressionMax)
17463 goto loc_21C5E;
17464
17465 Data8 = mGame_Data.mGamePhase_Data.mSprite_Enemy_AggressionMax;
17466 Data4 = -Data4;
17467 goto loc_21C5E;
17468
17469 loc_21C42:;
17470 if (Data8 < 0)
17471 goto loc_21C52;
17472
17473 if (Data8 > mGame_Data.mGamePhase_Data.mSprite_Enemy_AggressionMin)
17474 goto loc_21C5E;
17475
17476 loc_21C52:;
17477 Data8 = mGame_Data.mGamePhase_Data.mSprite_Enemy_AggressionMin;
17478 Data4 = -Data4;
17479
17480 loc_21C5E:;
17481 mGame_Data.mGamePhase_Data.mSprite_Enemy_AggressionIncrement = Data4;
17482 mGame_Data.mGamePhase_Data.mSprite_Enemy_AggressionNext = Data8;
17483 }
17484
Sprite_Create_Rank()17485 void cFodder::Sprite_Create_Rank() {
17486 sSprite* Sprite = 0, *Data30 = 0;
17487 int16 Data0 = 1;
17488
17489 if (Sprite_Get_Free_Max42(Data0, Sprite, Data30))
17490 return;
17491
17492 Sprite->field_0 = 0;
17493 Sprite->field_4 = 0;
17494 Sprite->field_8 = 0x7C;
17495 Sprite->field_A = 0;
17496 Sprite->field_10 = 1;
17497 Sprite->field_18 = eSprite_Player_Rank;
17498 Sprite->field_22 = eSprite_PersonType_None;
17499 Sprite->field_3A = 0;
17500 }
17501
sub_21CD1(sSprite * pSprite)17502 void cFodder::sub_21CD1(sSprite* pSprite) {
17503 sSprite* Data30 = 0;
17504
17505 mTroop_Weapon_Bullet_Disabled = false;
17506 mTroop_Weapon_Grenade_Disabled = true;
17507 mTroop_Weapon_Rocket_Disabled = true;
17508 mDirectionMod = 0;
17509 mSprite_FaceWeaponTarget = -1;
17510
17511 int16 Dataa0, Data4, Data8, DataC, Data10;
17512
17513 sSprite* Data0, *Following = 0, *Squad0_Member = 0;
17514
17515 if (pSprite->field_5E_Squad < 0) {
17516
17517 pSprite->field_5E_Squad += 1;
17518 mSprite_FaceWeaponTarget = 0;
17519
17520 Data0 = mSquad_Leader;
17521 if (mSquad_Leader == INVALID_SPRITE_PTR)
17522 goto loc_22125;
17523
17524 }
17525 else {
17526
17527 Squad0_Member = mSquad_0_Sprites[pSprite->field_5E_Squad];
17528 if (Squad0_Member == INVALID_SPRITE_PTR)
17529 goto loc_21E4A;
17530
17531 if ((tool_RandomGet() & 0x3F) == 0)
17532 goto loc_21E4A;
17533
17534 if (Squad0_Member->field_0 == -32768)
17535 goto loc_21E4A;
17536
17537 if (Squad0_Member->field_18 != eSprite_Player)
17538 goto loc_21E4A;
17539
17540 if (Squad0_Member->field_38 < eSprite_Anim_Slide1) {
17541 if (Squad0_Member->field_38)
17542 goto loc_21E4A;
17543 }
17544
17545 if (Squad0_Member->field_20 >= 0x0D)
17546 goto loc_21E4A;
17547
17548 Dataa0 = pSprite->field_0;
17549 Data4 = pSprite->field_4;
17550
17551 Data8 = Squad0_Member->field_0;
17552 DataC = Squad0_Member->field_4;
17553
17554 Map_Get_Distance_BetweenPoints_Within_Window(Dataa0, Data4, Data8, DataC);
17555
17556 mSprite_Find_Distance = Dataa0;
17557 if (Dataa0 > 0xC8)
17558 goto loc_21E4A;
17559
17560 if (Dataa0 <= 0x28)
17561 goto loc_21F77;
17562
17563 Dataa0 = pSprite->field_0;
17564 Data4 = pSprite->field_4;
17565 Data8 = Squad0_Member->field_0;
17566 DataC = Squad0_Member->field_4;
17567
17568 if (!Map_PathCheck_CalculateTo(Dataa0, Data4, Data8, DataC)) {
17569 Dataa0 = mSprite_Find_Distance;
17570 goto loc_21F77;
17571 }
17572
17573 if (mSprite_Find_Distance < 0x40)
17574 goto loc_21F8A;
17575
17576 loc_21E4A:;
17577
17578 // Following a Sprite?
17579 if (pSprite->field_70) {
17580
17581 Following = pSprite->field_70;
17582
17583 if (Following->field_0 != -32768) {
17584
17585 // Following a hostage?
17586 if (Following->field_18 == eSprite_Hostage) {
17587
17588 pSprite->field_5E_Squad += 1;
17589 if (pSprite->field_5E_Squad >= 0x1E)
17590 pSprite->field_5E_Squad = 0;
17591
17592 mSprite_FaceWeaponTarget = 0;
17593 pSprite->field_26 = Following->field_0 + 0x0C;
17594 pSprite->field_28 = Following->field_4;
17595 return;
17596 }
17597 }
17598
17599 pSprite->field_70 = 0;
17600 }
17601
17602 if (!(tool_RandomGet() & 0x0F)) {
17603 Dataa0 = tool_RandomGet() & 0xFF;
17604 Dataa0 = (int16)Dataa0;
17605 pSprite->field_2E += Dataa0;
17606
17607 Dataa0 = tool_RandomGet() & 0xFF;
17608 pSprite->field_30 += Dataa0;
17609 }
17610
17611 pSprite->field_26 = pSprite->field_0;
17612 pSprite->field_28 = pSprite->field_4;
17613 pSprite->field_4A = 0;
17614
17615 pSprite->field_5E_Squad += 1;
17616 if (pSprite->field_5E_Squad > 0x1E)
17617 pSprite->field_5E_Squad = 0;
17618
17619 goto loc_22000;
17620
17621 loc_21F77:;
17622 pSprite->field_70 = 0;
17623 mSprite_FaceWeaponTarget = 0;
17624
17625 loc_21F8A:;
17626 if (Dataa0 > 0x87)
17627 goto loc_22000;
17628
17629 //seg005:28A2
17630 // This is a strange segment, I can't reliably tell where data30 comes from,
17631 // in atleast one situation, its possible its not even pointing at an sSprite structure
17632 // or other times it might be pointing towards a completely irrelevant sprite from a previous use case.
17633 // i set it to spare, because that *could* happen if we are out of sprites and a previous sprite create had
17634 // failed...
17635 Data30 = &mSprite_Spare;
17636
17637 // Logic wise, it doesnt really make sense either... which makes me think perhaps Data30 should be Squad0_Member
17638
17639
17640 if (Data30->field_0 != Data30->field_26)
17641 goto loc_22000;
17642
17643 if (Data30->field_4 != Data30->field_28)
17644 goto loc_22000;
17645
17646 pSprite->field_2E = Squad0_Member->field_0;
17647 pSprite->field_30 += 7; // TODO: Is this an original bug and we should be adding to field_2E, code/logic wise it makes sense if it is
17648
17649 pSprite->field_30 = Squad0_Member->field_4;
17650 pSprite->field_30 -= 0x0E;
17651 sub_2212A(pSprite);
17652
17653
17654 loc_22000:;
17655 if (mSprite_FaceWeaponTarget)
17656 goto loc_22125;
17657
17658 if (mSquad_0_Sprites[pSprite->field_5E_Squad] == INVALID_SPRITE_PTR)
17659 goto loc_22125;
17660
17661 Data0 = mSquad_0_Sprites[pSprite->field_5E_Squad];
17662 }
17663
17664 // "Sort of" Random Movement Target
17665 // Depending on the sprite index, we add a factor to the X/Y target of a movement
17666 Data8 = (int16)(pSprite - mSprites.data());
17667 Data8 *= 0x76;
17668 Data8 &= 0x1FE;
17669
17670 DataC = mMap_Direction_Calculations[Data8 / 2];
17671 Data8 += 0x80;
17672 Data8 &= 0x1FE;
17673 Data10 = mMap_Direction_Calculations[Data8 / 2];
17674
17675 //seg005:29B2
17676 DataC >>= 8;
17677 Data10 >>= 8;
17678 DataC >>= 2;
17679 Data10 >>= 2;
17680
17681 pSprite->field_2E = Data0->field_0;
17682 pSprite->field_26 = Data0->field_0 + DataC; // Target X
17683
17684 pSprite->field_30 = Data0->field_4;
17685 pSprite->field_28 = Data0->field_4 + Data10; // Target Y
17686
17687 loc_22125:;
17688 sub_2212A(pSprite);
17689 }
17690
sub_2212A(sSprite * pSprite)17691 void cFodder::sub_2212A(sSprite* pSprite) {
17692
17693 if (pSprite->field_4A)
17694 return;
17695
17696 int16 Data0 = tool_RandomGet();
17697
17698 int16 Data8 = pSprite->field_62;
17699 int16 DataC = Data8;
17700 DataC <<= 2;
17701 Data8 >>= 2;
17702 int16 Data4 = 0x1F;
17703 Data4 >>= Data8;
17704 Data0 &= Data4;
17705 Data4 = 0x32;
17706 Data4 -= DataC;
17707 if (Data4 < 0)
17708 Data4 = 0;
17709
17710 Data0 += Data4;
17711 if (Data0 < 5)
17712 Data0 = 5;
17713
17714 pSprite->field_4A = Data0;
17715 }
17716
Sprite_Handle_BuildingDoor_Explode(sSprite * pSprite)17717 int16 cFodder::Sprite_Handle_BuildingDoor_Explode(sSprite* pSprite) {
17718 int16 Data0, Data4;
17719
17720 if (pSprite->field_38 == eSprite_Anim_Die3 || pSprite->field_38 == eSprite_Anim_Die1)
17721 goto loc_221D0;
17722
17723 if (pSprite->field_38 == eSprite_Anim_Die2)
17724 goto loc_22235;
17725
17726 return 0;
17727 loc_221D0:; // Building Explodes
17728 pSprite->field_38 = eSprite_Anim_Die2;
17729 pSprite->field_8 = 0x99;
17730
17731 Data0 = tool_RandomGet();
17732 Data4 = Data0;
17733
17734 Data0 &= 0x1E;
17735 if (Data4 < 0)
17736 Data0 = -Data0;
17737
17738 Data0 += 0x1C0;
17739 pSprite->field_10 = Data0;
17740 Data4 &= 3;
17741 Data4 += 5;
17742 pSprite->field_44 = (int8)Data4;
17743 pSprite->field_36 = 0x78;
17744
17745 loc_22235:; // Door moving
17746 pSprite->field_44 -= 1;
17747 if (!pSprite->field_44)
17748 goto loc_2227F;
17749
17750 Sprite_Movement_Calculate(pSprite);
17751 if (mSprite_Bullet_Destroy)
17752 goto loc_2227F;
17753
17754 Data0 = -3;
17755 Data4 = 2;
17756 if (Map_Terrain_Get_Type_And_Walkable(pSprite, Data0, Data4))
17757 goto loc_2227F;
17758
17759 if (pSprite->field_36 <= 0)
17760 goto loc_2227F;
17761
17762 return -1;
17763
17764 loc_2227F:; // Door Finished
17765 pSprite->field_0 -= 8;
17766 pSprite->field_4 -= 8;
17767
17768 Sprite_Turn_Into_Building_Explosion(pSprite);
17769
17770 return -1;
17771 }
17772
sub_222A3(sSprite * pSprite)17773 int16 cFodder::sub_222A3(sSprite* pSprite) {
17774 int16 Data0, Data4;
17775
17776 if (pSprite->field_38 != eSprite_Anim_Die3 && pSprite->field_38 != eSprite_Anim_Die1) {
17777
17778 if (pSprite->field_38 == eSprite_Anim_Die2)
17779 goto loc_22339;
17780
17781 return 0;
17782 }
17783
17784 //loc_222CD
17785 pSprite->field_38 = eSprite_Anim_Die2;
17786 pSprite->field_8 = 0x9B;
17787
17788 Data0 = tool_RandomGet();
17789 Data4 = Data0;
17790 Data0 &= 0x1E;
17791
17792 if (Data4 < 0)
17793 Data0 = -Data0;
17794
17795 if (mMapLoaded->getTileType() == eTileTypes_Ice || mMapLoaded->getTileType() == eTileTypes_AFX)
17796 Data0 += 0x1C0;
17797
17798 pSprite->field_10 = Data0;
17799 Data4 &= 3;
17800 Data4 += 5;
17801
17802 pSprite->field_44 = (int8)Data4;
17803 pSprite->field_36 = 0x6E;
17804
17805 loc_22339:;
17806 pSprite->field_44 -= 1;
17807 if (pSprite->field_44 == 1)
17808 goto loc_22383;
17809
17810 Sprite_Movement_Calculate(pSprite);
17811 if (mSprite_Bullet_Destroy)
17812 goto loc_22383;
17813
17814 Data0 = -3;
17815 Data4 = 2;
17816 if (!Map_Terrain_Get_Type_And_Walkable(pSprite, Data0, Data4))
17817 if (pSprite->field_36 > 0)
17818 return -1;
17819
17820 loc_22383:;
17821
17822 pSprite->field_0 -= 8;
17823 if (pSprite->field_0 < 0)
17824 pSprite->field_0 = 0;
17825
17826 pSprite->field_4 -= 8;
17827 Sprite_Turn_Into_Building_Explosion(pSprite);
17828 return -1;
17829 }
17830
sub_223B2(sSprite * pSprite)17831 void cFodder::sub_223B2(sSprite* pSprite) {
17832 int16 Data8 = pSprite->field_3C;
17833
17834 Data8 += mDirectionMod;
17835 Data8 &= 0x0E;
17836
17837 pSprite->field_3C = Data8;
17838
17839 const int16* Data28 = mSprite_AnimationPtrs[pSprite->field_22];
17840 Data28 += ((0x80 + Data8) / 2);
17841
17842 pSprite->field_8 = *Data28;
17843 pSprite->field_3E = pSprite->field_10;
17844 pSprite->field_A = 0;
17845 }
17846
17847 /**
17848 * Check the distance between the provided sprite, and the squad leader
17849 *
17850 * @param pSprite
17851 * @param pData0
17852 *
17853 * @return 0 if within range, 1 if not
17854 */
Map_Get_Distance_Between_Sprite_And_Squadleader(sSprite * pSprite,int16 & pData0)17855 int16 cFodder::Map_Get_Distance_Between_Sprite_And_Squadleader(sSprite* pSprite, int16& pData0) {
17856 int16 Data4, Data8, DataC, Data10;
17857
17858 // Current Squad in vehicle?
17859 if (mSquad_CurrentVehicle)
17860 return 1;
17861
17862 // No Squad Leader?
17863 if (mSquad_Leader == INVALID_SPRITE_PTR || mSquad_Leader == 0)
17864 return 1;
17865
17866 // Vehicle?
17867 if (mSquad_Leader->field_6E)
17868 return 1;
17869
17870 // Anim playing?
17871 if (mSquad_Leader->field_38)
17872 return 1;
17873
17874 pData0 = pSprite->field_0;
17875
17876 Data4 = pSprite->field_4;
17877 Data8 = mSquad_Leader->field_0;
17878 DataC = mSquad_Leader->field_4;
17879 Data10 = 0x20;
17880
17881 DataC += 2;
17882
17883 Map_Get_Distance_BetweenPoints(pData0, Data4, Data8, Data10, DataC);
17884 if (pData0 >= 6)
17885 return 1;
17886
17887 Data4 = 0;
17888 return 0;
17889 }
17890
Sprite_Create_Rocket(sSprite * pSprite)17891 int16 cFodder::Sprite_Create_Rocket(sSprite* pSprite) {
17892 sSprite* Data2C = 0, *Data30 = 0, *Data34 = 0;
17893 int16 Data0, Data4, Data8, DataC;
17894
17895 if (mPhase_Completed_Timer) {
17896 loc_22592:;
17897
17898 if (pSprite == mSquad_Leader)
17899 mMouse_Button_LeftRight_Toggle = false;
17900
17901 return -1;
17902 }
17903
17904 if (mSprite_Missile_Projectile_Counters[pSprite->field_22] == 2)
17905 goto loc_22592;
17906
17907 if (!pSprite->field_2E)
17908 goto loc_22592;
17909
17910 //seg005:2E39
17911 if (pSprite->field_18 == eSprite_Enemy) {
17912 Data0 = pSprite->field_0;
17913 Data4 = pSprite->field_4;
17914 Data8 = pSprite->field_2E;
17915 DataC = pSprite->field_30;
17916
17917 // Don't let the AI fire further than 129
17918 Map_Get_Distance_BetweenPoints_Within_Window(Data0, Data4, Data8, DataC);
17919 if (Data0 >= 0x82)
17920 goto loc_22592;
17921 }
17922
17923 Data0 = 2;
17924 Sprite_Get_Free_Max42(Data0, Data2C, Data30);
17925
17926 // No Free sprites?
17927 if (Data0)
17928 return -1;
17929
17930 if (pSprite->field_18 == eSprite_Player) {
17931 Data0 = pSprite->field_32;
17932 Data4 = Data0;
17933
17934 if (!mSquad_Rockets[Data0])
17935 goto loc_22592;
17936
17937 --mSquad_Rockets[Data0];
17938 mGUI_RefreshSquadRockets[Data4] = -1;
17939 }
17940
17941 ++mSprite_Missile_Projectile_Counters[pSprite->field_22];
17942 pSprite->field_55 = 1;
17943 pSprite->field_5A = -1;
17944 pSprite->field_54 = 3;
17945 Data30 = Data2C;
17946 Data30++;
17947
17948 //seg005:2F86
17949 Data2C->field_0 = pSprite->field_0;
17950 Data2C->field_2 = pSprite->field_2;
17951 Data30->field_0 = pSprite->field_0;
17952 Data30->field_2 = pSprite->field_2;
17953 Data2C->field_4 = pSprite->field_4;
17954 Data2C->field_6 = pSprite->field_6;
17955 Data30->field_4 = pSprite->field_4;
17956 Data30->field_6 = pSprite->field_6;
17957
17958 //seg005:2FD2
17959 Data2C->field_26 = pSprite->field_2E;
17960 Data2C->field_28 = pSprite->field_30;
17961 Data2C->field_28 += 0x10;
17962 Data2C->field_8 = 0x7C;
17963 Data30->field_8 = 0x7E;
17964 Data2C->field_10 = 0;
17965 Data30->field_10 = 1;
17966 Data2C->field_36 = 0x64;
17967 Data30->field_36 = 0x64;
17968 Data2C->field_1E = 0x0000;
17969 Data2C->field_20 = 0x0A;
17970
17971 Data30->field_1E = 0;
17972 Data30->field_20 = 0;
17973
17974 Data2C->field_4++;
17975 Data2C->field_0 += 3;
17976
17977 // Amiga Power always has homing missiles
17978 if (pSprite->field_22 == eSprite_PersonType_Human &&
17979 (mVersionCurrent->isCoverDisk() || (pSprite->field_75 & eSprite_Flag_HomingMissiles))) {
17980
17981 // Within lock on range?
17982 if (Sprite_Homing_LockInRange(pSprite, Data34)) {
17983
17984 Data2C->field_1A_sprite = Data34;
17985 Data2C->field_18 = eSprite_MissileHoming2;
17986 Data2C->field_6A = 0x10000;
17987 Data2C->field_26 = pSprite->field_2E;
17988 Data2C->field_28 = pSprite->field_30;
17989 Data2C->field_28 += 0x10;
17990 Data2C->field_38 = eSprite_Anim_None;
17991 Data2C->field_36 = 0;
17992 Data30->field_36 = 0;
17993
17994 }
17995 else {
17996 Data2C->field_32 = 0;
17997 Data2C->field_18 = eSprite_Missile;
17998 }
17999
18000 }
18001 else {
18002
18003 Data2C->field_18 = eSprite_Rocket;
18004 Data2C->field_46_sprite = pSprite;
18005 }
18006
18007 Data30->field_18 = eSprite_ShadowSmall;
18008 Data2C->field_52 = 0;
18009 Data30->field_32 = 0;
18010 Data2C->field_22 = pSprite->field_22;
18011 Data30->field_22 = Data2C->field_22;
18012 Data2C->field_32 = pSprite->field_32;
18013 Data2C->field_2C = eSprite_Draw_Second;
18014 Data30->field_2C = eSprite_Draw_First;
18015 Data2C->field_56 = 6;
18016
18017 if (pSprite == mSquad_Leader)
18018 mMouse_Button_LeftRight_Toggle = false;
18019
18020 return 0;
18021 }
18022
Sprite_Homing_LockInRange(sSprite * pSprite,sSprite * & pFoundSprite)18023 int16 cFodder::Sprite_Homing_LockInRange(sSprite* pSprite, sSprite*& pFoundSprite) {
18024
18025 int16 MouseX = mMouseX;
18026 int16 MouseY = mMouseY;
18027
18028 MouseX += mCameraX >> 16;
18029 MouseY += mCameraY >> 16;
18030
18031 MouseX -= 0x10;
18032 if (!MouseX)
18033 MouseX = 1;
18034
18035 MouseY += 0x08;
18036
18037 for( auto& Sprite : mSprites ) {
18038 pFoundSprite = &Sprite;
18039
18040 if (pFoundSprite->field_0 == -32768)
18041 continue;
18042
18043 if (!mSprite_Missile_CanLock[pFoundSprite->field_18])
18044 continue;
18045
18046 if (pFoundSprite->field_22 == pSprite->field_22)
18047 continue;
18048
18049 int16 Data0 = pFoundSprite->field_0 + 5;
18050 int16 Data4 = pFoundSprite->field_4 - 5;
18051
18052 Data4 -= pFoundSprite->field_20;
18053 int16 Distance = 0x1F;
18054 int16 S_Data8 = MouseX;
18055 int16 S_DataC = MouseY;
18056
18057 Map_Get_Distance_BetweenPoints(Data0, Data4, MouseX, Distance, MouseY);
18058
18059 MouseX = S_Data8;
18060 MouseY = S_DataC;
18061
18062 if (Data0 < 0x16) {
18063 Data0 = -1;
18064 return -1;
18065 }
18066 }
18067
18068 return 0;
18069 }
18070
Sprite_Projectile_HitTarget(sSprite * pSprite)18071 void cFodder::Sprite_Projectile_HitTarget(sSprite* pSprite) {
18072
18073 mSprite_Missile_Projectile_Counters[pSprite->field_22] -= 1;
18074 }
18075
Sprite_Destroy_Wrapper_At_TopLeft(sSprite * pSprite)18076 void cFodder::Sprite_Destroy_Wrapper_At_TopLeft(sSprite* pSprite) {
18077 pSprite->field_0 = 1;
18078 pSprite->field_4 = 1;
18079
18080 Sprite_Destroy_Wrapper_2(pSprite);
18081 }
18082
Sprite_Destroy_Wrapper_2(sSprite * pSprite)18083 int16 cFodder::Sprite_Destroy_Wrapper_2(sSprite* pSprite) {
18084 return Sprite_Destroy_Wrapper(pSprite);
18085 }
18086
Sprite_Handle_Player_InVehicle(sSprite * pSprite)18087 void cFodder::Sprite_Handle_Player_InVehicle(sSprite* pSprite) {
18088 pSprite->field_8 = 0x7C;
18089 pSprite->field_A = 0;
18090 pSprite->field_38 = eSprite_Anim_None;
18091
18092 sSprite* Data24 = pSprite->field_6A_sprite;
18093 if (Data24->field_0 == -32768 || Data24->field_18 == eSprite_Explosion) {
18094 //loc_22AEE
18095 pSprite->field_6E = 0;
18096 pSprite->field_66 = 0;
18097 pSprite->field_6A_sprite = 0;
18098 pSprite->field_38 = eSprite_Anim_Hit;
18099 pSprite->field_64 = -1;
18100
18101 pSprite->field_10 = tool_RandomGet() & 0x1FE;
18102 }
18103
18104 //loc_22B3C
18105
18106 pSprite->field_0 = Data24->field_0;
18107 pSprite->field_4 = Data24->field_4;
18108 pSprite->field_20 = Data24->field_20;
18109 }
18110
Game_Setup()18111 void cFodder::Game_Setup() {
18112
18113 if (mParams->mMissionNumber < 1)
18114 mParams->mMissionNumber = 1;
18115
18116 GameData_Reset();
18117
18118 mIntroDone = false;
18119 mPhase_Complete = false;
18120
18121 mGame_Data.mMission_Phases_Remaining = 1;
18122 mGame_Data.mMission_Number = (uint16) (mParams->mMissionNumber);
18123 mGame_Data.mMission_Phase = (uint16) (mParams->mPhaseNumber ? (mParams->mPhaseNumber) : 1);
18124
18125 mGame_Data.Phase_Start();
18126
18127 mPhase_TryAgain = true;
18128 mGraphics->Load_pStuff();
18129 }
18130
18131 // This function is for viewing/iterating sprites
Playground()18132 void cFodder::Playground() {
18133 //return;
18134 mGame_Data.Phase_Start();
18135 Map_Load();
18136
18137 mGraphics->PaletteSet();
18138
18139 Recruit_Truck_Anim_Prepare();
18140 mGraphics->SetActiveSpriteSheet(eGFX_RECRUIT);
18141 //mGraphics->Recruit_Draw_Hill();
18142
18143 Recruit_Copy_Sprites();
18144
18145 if (mVersionCurrent->mPlatform == ePlatform::Amiga) {
18146
18147 GetGraphics<cGraphics_Amiga>()->Hill_Prepare_Overlays();
18148 }
18149
18150 // Load Icon
18151 mSurface->clearBuffer();
18152 mSurface->palette_FadeTowardNew();
18153 mSurface->Save();
18154 mString_GapCharID = 0x25;
18155 mGUI_Print_String_To_Sidebar = false;
18156
18157 int32 SpriteID = 0x62;
18158 int32 Frame = 0;
18159
18160
18161 for (;; ) {
18162 mKeyCode = 0;
18163 {
18164 mGraphics->SetActiveSpriteSheet(eGFX_BRIEFING);
18165 std::stringstream SPRITE_STRING;
18166 SPRITE_STRING << "SPRITE: 0x" << std::hex << SpriteID;
18167 SPRITE_STRING << " FRAME: 0x" << std::hex << Frame;
18168
18169 String_Print_Large(SPRITE_STRING.str(), false, 0);
18170
18171 }
18172
18173 {
18174 mGraphics->SetActiveSpriteSheet(eGFX_IN_GAME);
18175 GUI_Draw_Frame_8(SpriteID, Frame, 65, 65);
18176 }
18177
18178 if (mSurface->isPaletteAdjusting())
18179 mSurface->palette_FadeTowardNew();
18180
18181 //Mouse_Inputs_Get();
18182 //Mouse_DrawCursor();
18183
18184 Video_SurfaceRender();
18185 Cycle_End();
18186
18187 // Q
18188 if (mKeyCode == 0x14) {
18189 --SpriteID;
18190 }
18191 // W
18192 if (mKeyCode == 0x1A) {
18193 ++SpriteID;
18194 }
18195
18196 // A
18197 if (mKeyCode == 0x04) {
18198 --Frame;
18199 }
18200
18201 // S
18202 if (mKeyCode == 0x16) {
18203 ++Frame;
18204 }
18205
18206 // Safety
18207 if (SpriteID >= 232)
18208 SpriteID = 0;
18209
18210 if (Frame >= 20)
18211 Frame = 0;
18212
18213 if (mDemo_ExitMenu)
18214 break;
18215
18216 }
18217 }
18218
Demo_Load()18219 bool cFodder::Demo_Load() {
18220
18221 std::ifstream DemoContent(mStartParams->mDemoFile, std::ios::binary);
18222 if (DemoContent.is_open()) {
18223
18224 std::string SaveGameContent(
18225 (std::istreambuf_iterator<char>(DemoContent)),
18226 (std::istreambuf_iterator<char>())
18227 );
18228
18229 mGame_Data.mDemoRecorded.FromJson(SaveGameContent);
18230 return true;
18231 }
18232 return false;
18233 }
18234
Window_UpdateScreenSize()18235 void cFodder::Window_UpdateScreenSize() {
18236
18237 // We can override the window
18238 mWindow->SetScreenSize(getWindowSize());
18239 mWindow->SetOriginalRes(getWindowSize());
18240
18241
18242 // This next section is done
18243 //
18244 // If we're playing back a demo
18245 if (mParams->mDemoPlayback && g_Fodder->mVersionCurrent) {
18246 // And the current platform, does not match the platform the demo was recorded with
18247 if (mGame_Data.mDemoRecorded.mRecordedPlatform != mVersionCurrent->mPlatform && mGame_Data.mDemoRecorded.mRecordedPlatform != ePlatform::Any ) {
18248 // Alter the screen size, to the other platforms
18249 switch (mGame_Data.mDemoRecorded.mRecordedPlatform) {
18250 case ePlatform::Amiga: // Viewing Amiga recording on PC Data
18251 mWindow->SetScreenSize({ 320,225 });
18252 break;
18253 case ePlatform::PC: // Viewing PC recording on Amiga Data
18254 mWindow->SetScreenSize({ 320,200 });
18255 break;
18256 case ePlatform::Any:
18257 break;
18258 }
18259 }
18260 }
18261 }
18262
About()18263 void cFodder::About() {
18264
18265 mService_Draw_List.clear();
18266 VersionSwitch(mVersions->GetRetail(mParams->mDefaultPlatform, mParams->mDefaultGame));
18267 if (!mVersionCurrent)
18268 VersionSwitch(mVersions->GetDemo());
18269
18270 cAbout About;
18271 while (About.Cycle()) {
18272
18273
18274 mWindow->RenderAt(mSurface);
18275 mWindow->FrameEnd();
18276 Cycle_End();
18277 }
18278
18279 g_Fodder->mPhase_Aborted = false;
18280 }
18281
CreateRandom()18282 void cFodder::CreateRandom() {
18283 mGame_Data.mCampaign.CreateCustomCampaign();
18284 mGame_Data.mCampaign.setRandom(true);
18285 mGame_Data.mCampaign.setName("Random");
18286
18287 VersionSwitch(mVersions->GetRetail(mParams->mDefaultPlatform, mParams->mDefaultGame));
18288
18289 if (!mParams->mRandomFilename.size()) {
18290 mParams->mRandomFilename = "random";
18291 }
18292
18293 sMapParams Params(mRandom.get());
18294
18295 Map_Create(Params);
18296
18297 if (mParams->mScriptRun.size() == 0)
18298 mParams->mScriptRun = "test.js";
18299
18300 mGame_Data.mMission_Phases_Remaining = 1;
18301 mGame_Data.mMission_Number = 1;
18302 mGame_Data.mMission_Phase = 1;
18303 mGame_Data.Phase_Start();
18304
18305 mGame_Data.mPhase_Current->SetMapFilename(mParams->mRandomFilename);
18306
18307 // Fade in so text can be drawn
18308 Image_FadeIn();
18309
18310 if (g_Fodder->mStartParams->mDebugger)
18311 g_ScriptingEngine->debuggerEnable();
18312
18313 if (g_ScriptingEngine->Run(mParams->mScriptRun)) {
18314
18315 // Ensure final phase is saved
18316 mMapLoaded->save(mGame_Data.mPhase_Current->GetMapFilename(), true);
18317 }
18318
18319 // Fade out again
18320 Image_FadeOut();
18321
18322 Map_Load_Sprites();
18323
18324 // Back to mission 1 phase 1
18325 mGame_Data.mMission_Number = 1;
18326 mGame_Data.mMission_Phase = 1;
18327 mGame_Data.Phase_Start();
18328 }
18329
Start()18330 void cFodder::Start() {
18331
18332 if (mParams->mShowAbout) {
18333 About();
18334 return;
18335 }
18336
18337 if (mParams->mDemoPlayback) {
18338 Demo_Load();
18339 mGame_Data.mDemoRecorded.playback();
18340 mParams = mGame_Data.mDemoRecorded.mParams;
18341 mParams->mDefaultPlatform = mStartParams->mDefaultPlatform;
18342
18343 mOpenFodder_Intro_Done = false;
18344 }
18345
18346 if (mParams->mDemoRecord)
18347 mGame_Data.mDemoRecorded.clear();
18348
18349 Start:;
18350 mGame_Data.mCampaign.Clear();
18351 mSound = 0;
18352 mVersionDefault = 0;
18353 mVersionCurrent = 0;
18354 VersionSwitch(mVersions->GetRetail( mParams->mDefaultPlatform, mParams->mDefaultGame ));
18355
18356 if (!mVersionCurrent) {
18357 VersionSwitch(mVersions->GetDemo());
18358
18359 // This should never happen ,as a check in Prepare ensures atleast 1 ver is available
18360 if (!mVersionCurrent)
18361 return;
18362 }
18363
18364 if (mParams->mDemoRecord && mGame_Data.mDemoRecorded.mRecordedPlatform == ePlatform::Any)
18365 mGame_Data.mDemoRecorded.mRecordedPlatform = mVersionCurrent->mPlatform;
18366
18367 mGame_Data.mDemoRecorded.save();
18368
18369 // Play the intro
18370 Intro_OpenFodder();
18371
18372 if (mParams->mPlayground) {
18373 Playground();
18374 return;
18375 }
18376
18377 // Start a random map?
18378 if (mParams->mRandom || mParams->mSingleMap.size()) {
18379
18380 mGame_Data.mCampaign.SetSingleMapCampaign();
18381 mCustom_Mode = eCustomMode_Map;
18382
18383 if(mParams->mRandom)
18384 VersionSwitch(mVersions->GetForCampaign("Random Map", mParams->mDefaultPlatform));
18385 else
18386 VersionSwitch(mVersions->GetForCampaign("Single Map", mParams->mDefaultPlatform));
18387 } else {
18388
18389 // Select campaign menu
18390 if (!(mParams->mCampaignName.size() && Campaign_Load(mParams->mCampaignName))) {
18391 Campaign_Selection();
18392 // Exit pushed?
18393 if (mGUI_SaveLoadAction == 1)
18394 return;
18395
18396 if (mGUI_SaveLoadAction == 4) {
18397 About();
18398 goto Start;
18399 }
18400 }
18401 }
18402
18403 mVersionDefault = mVersionCurrent;
18404 Mouse_Setup();
18405 Mouse_Inputs_Get();
18406
18407 if (Engine_Loop())
18408 goto Start;
18409 }
18410
18411 /**
18412 * Main Engine Loop
18413 *
18414 * false = Exit
18415 * true = Restart
18416 */
Engine_Loop()18417 bool cFodder::Engine_Loop() {
18418
18419 for (;;) {
18420
18421 Game_Setup();
18422
18423 if (Mission_Loop() == -1)
18424 return true;
18425
18426 if (mParams->mSinglePhase)
18427 break;
18428 }
18429
18430 return false;
18431 }
18432
GameOverCheck()18433 bool cFodder::GameOverCheck() {
18434
18435 if (!mParams->mUnitTesting) {
18436 // Mission completed?
18437 if (!mPhase_Aborted && !mPhase_TryAgain) {
18438
18439 // Demo / Custom Mission restart
18440 if (mVersionCurrent->isDemo() && mCustom_Mode != eCustomMode_Set && !mVersionCurrent->isAmigaTheOne())
18441 return false;
18442
18443 // Reached last map in this mission set?
18444 if (!mGame_Data.Phase_Next()) {
18445
18446 mGame_Data.mGameWon = true;
18447 WonGame();
18448 return true;
18449 }
18450 }
18451 }
18452
18453 // Double escape aborts out to OF selection, on Amiga the one
18454 if (mPhase_Aborted2 && mVersionCurrent->isAmigaTheOne()) {
18455 return true;
18456 }
18457
18458 return false;
18459 }
18460
Briefing_Show()18461 int16 cFodder::Briefing_Show() {
18462
18463 if (mParams->mSkipBriefing)
18464 return 1;
18465
18466 if (mVersionCurrent->isDemo() && mVersionDefault->isDemo())
18467 return 1;
18468
18469 // Show the Briefing screen for Retail and Custom
18470 if (mVersionCurrent->hasBriefingScreen() || mCustom_Mode != eCustomMode_None || mGame_Data.mCampaign.isRandom()) {
18471
18472 Window_UpdateScreenSize();
18473
18474 // Show the pre ready Briefing Screen
18475 Briefing_Show_PreReady();
18476
18477 Map_Load();
18478 Map_Load_Sprites();
18479 Map_Overview_Prepare();
18480
18481 // Prepare Squads
18482 Phase_Soldiers_Count();
18483 mGame_Data.Soldier_Sort();
18484 Phase_Soldiers_Prepare(false);
18485 Phase_Soldiers_AttachToSprites();
18486
18487 mPhase_Aborted = false;
18488
18489 // Needs to split into cycle function
18490 Briefing_Show_Ready();
18491
18492 // Aborted?
18493 if (mBriefing_Aborted == -1) {
18494
18495 if (mGame_Data.mCampaign.isRandom())
18496 return -1;// Return to version select
18497
18498 GameData_Restore();
18499
18500 mRecruit_Mission_Restarting = true;
18501 mGame_Data.mMission_Recruitment = -1;
18502 mPhase_Aborted = true;
18503
18504 if (!mStartParams->mDisableSound)
18505 mSound->Music_Play(0);
18506
18507 return 0;
18508 }
18509 }
18510
18511 return 1;
18512 }
18513
Mission_Loop()18514 int16 cFodder::Mission_Loop() {
18515
18516 for (;;) {
18517 mGame_Data.mDemoRecorded.save();
18518
18519 if (GameOverCheck())
18520 return -1;
18521
18522 // Prepare the next mission
18523 Phase_EngineReset();
18524 Phase_SquadPrepare();
18525
18526 mInput_Enabled = false;
18527
18528 intro_main();
18529
18530 // Prepare a new game?
18531 if (mGame_Data.mMission_Recruitment && !mParams->mSkipRecruit) {
18532 mGame_Data.mMission_Recruitment = 0;
18533
18534 switch (Recruit_Show()) {
18535 case 0: // Start Mission
18536 break;
18537
18538 case -1: // Return to version select
18539 return -1;
18540
18541 case -2: // Custom set mode
18542 return -2;
18543
18544 case -3: // Load/Save pressed
18545 continue;
18546 }
18547 }
18548
18549 WindowTitleSet(true);
18550
18551 switch (Briefing_Show()) {
18552
18553 case -1:
18554 return -1; // Return to version select
18555
18556 case 0: // Back to hill
18557 continue;
18558
18559 case 1: // Continue to phase
18560 break;
18561 }
18562
18563 Phase_Prepare();
18564
18565 if (!Phase_Loop()) {
18566 mKeyCode = 0;
18567 mPhase_In_Progress = false;
18568 Squad_Member_PhaseCount();
18569 mPhase_TryingAgain = true;
18570
18571 }
18572 else {
18573 mKeyCode = 0;
18574 mPhase_In_Progress = false;
18575
18576 // Game over?
18577 if (!mGame_Data.mRecruits_Available_Count) {
18578
18579 // Retail/Custom Set can do the service screen
18580 if (mVersionCurrent->isRetail() || mCustom_Mode == eCustomMode_Set) {
18581
18582 if (!mPhase_Aborted)
18583 Service_Show();
18584 }
18585 break;
18586 }
18587 }
18588
18589 // Single Phase?
18590 if (mParams->mSinglePhase) {
18591 return 0;
18592 }
18593
18594 //loc_106F1
18595 if (mPhase_TryAgain) {
18596 mPhase_TryingAgain = true;
18597 continue;
18598 }
18599
18600 // Switch back to the default data?
18601 if (mVersionReturnAfterPhase) {
18602 mVersionReturnAfterPhase = false;
18603 VersionSwitch(mVersionDefault);
18604 }
18605
18606 // Demo/Single mission, but not set mode (its handled at the end of the loop)
18607 if (mVersionCurrent->isDemo() && mCustom_Mode != eCustomMode_Set) {
18608
18609 // Custom can do the service screen, as it requires a retail release
18610 if (!mPhase_Aborted && mVersionCurrent->isCustom())
18611 Service_Show();
18612
18613 if(!mVersionCurrent->isAmigaTheOne())
18614 break;
18615 }
18616
18617 if (mPhase_Aborted)
18618 continue;
18619
18620 if (mGame_Data.mMission_Phases_Remaining > 1)
18621 continue;
18622
18623 Service_Show();
18624 }
18625
18626 return 0;
18627 }
18628
intro_main()18629 void cFodder::intro_main() {
18630 if (!mIntroDone) {
18631 mImage_Aborted = 0;
18632 mVersionPlatformSwitchDisabled = true;
18633
18634 if (!mParams->mSkipIntro) {
18635 mWindow->SetScreenSize(mVersionCurrent->GetSecondScreenSize());
18636
18637 // Show the intro for retail releases (and the PC Format demo)
18638 if (mVersionCurrent->isRetail() || mVersionCurrent->isPCFormat()) {
18639 intro_Retail();
18640 }
18641 else {
18642 // Amiga The One has an intro too
18643 if (mVersionCurrent->isAmigaTheOne()) {
18644 intro_AmigaTheOne();
18645 }
18646 }
18647 }
18648
18649 mGraphics->Load_pStuff();
18650 mVersionPlatformSwitchDisabled = false;
18651 mIntroDone = true;
18652 }
18653 }
18654
MapTiles_Draw()18655 void cFodder::MapTiles_Draw() {
18656
18657 mMapTile_ColumnOffset = 0;
18658 mMapTile_RowOffset = 0;
18659
18660 // 0x60 - SidebarWidth - MapWidth
18661 mMapTile_Ptr = (0x60 - 8) - (mMapLoaded->getWidth() << 1);
18662
18663 // No sidebar in OFED
18664 #ifdef _OFED
18665 mMapTile_Ptr += 8;
18666 #endif
18667
18668 mMapTile_MovedHorizontal = 0;
18669 mMapTile_MovedVertical = 0;
18670 mMapTile_Column_CurrentScreen = 0;
18671 mMapTile_Row_CurrentScreen = 0;
18672
18673 if (!mStartParams->mDisableVideo)
18674 mGraphics->MapTiles_Draw();
18675 }
18676
Exit(unsigned int pExitCode)18677 void cFodder::Exit(unsigned int pExitCode) {
18678
18679 exit(pExitCode);
18680 }
18681
Squad_Split_Assets()18682 void cFodder::Squad_Split_Assets() {
18683 int16 Data8, DataC;
18684
18685 if (mSquad_Grenade_SplitMode == eSquad_Weapon_Split_All) {
18686 mSquad_Grenades[mSquad_Selected] = mSquad_Grenades[mSquad_JoiningTo];
18687 mSquad_Grenades[mSquad_JoiningTo] = 0;
18688 }
18689 else {
18690
18691 if (mSquad_Grenade_SplitMode == eSquad_Weapon_Split_Half) {
18692 Data8 = mSquad_Grenades[mSquad_JoiningTo];
18693 DataC = Data8;
18694 Data8 >>= 1;
18695
18696 mSquad_Grenades[mSquad_JoiningTo] = Data8;
18697 DataC -= Data8;
18698 mSquad_Grenades[mSquad_Selected] = DataC;
18699 }
18700 }
18701
18702 if (mSquad_Rocket_SplitMode == eSquad_Weapon_Split_All) {
18703 mSquad_Rockets[mSquad_Selected] = mSquad_Rockets[mSquad_JoiningTo];
18704 mSquad_Rockets[mSquad_JoiningTo] = 0;
18705 }
18706 else {
18707
18708 if (mSquad_Rocket_SplitMode == eSquad_Weapon_Split_Half) {
18709
18710 Data8 = mSquad_Rockets[mSquad_JoiningTo];
18711 DataC = Data8;
18712 Data8 >>= 1;
18713
18714 mSquad_Rockets[mSquad_JoiningTo] = Data8;
18715 DataC -= Data8;
18716 mSquad_Rockets[mSquad_Selected] = DataC;
18717 }
18718 }
18719
18720 mSquad_CurrentWeapon[mSquad_Selected] = mSquad_CurrentWeapon[mSquad_JoiningTo];
18721 }
18722
Squad_Member_Click_Check()18723 void cFodder::Squad_Member_Click_Check() {
18724 word_3A3BF = -1;
18725
18726 if (mSquad_Selected < 0)
18727 return;
18728
18729 int16 ClickedX = mMouseX;
18730 int16 ClickedY = mMouseY;
18731
18732 ClickedX += mCameraX >> 16;
18733 ClickedY += mCameraY >> 16;
18734 ClickedX -= 0x0F;
18735 ClickedY -= 3;
18736
18737 for (auto& SquadMember : mGame_Data.mSoldiers_Allocated) {
18738
18739 if (SquadMember.mSprite == INVALID_SPRITE_PTR || SquadMember.mSprite == 0)
18740 continue;
18741
18742 sSprite* SquadMemberSprite = SquadMember.mSprite;
18743
18744 if (SquadMemberSprite->field_32 == mSquad_Selected)
18745 ++word_3A3BF;
18746
18747 int16 SquadMemberX = SquadMemberSprite->field_0 + 4;
18748 int16 SquadMemberY = SquadMemberSprite->field_4 - SquadMemberSprite->field_20;
18749
18750 // Clicked before/after troop?
18751 if (ClickedX < SquadMemberX)
18752 continue;
18753 if (ClickedX > SquadMemberX + 6)
18754 continue;
18755
18756 // Clicked above/below troop?
18757 if (ClickedY < SquadMemberY - 13)
18758 continue;
18759 if (ClickedY > SquadMemberY)
18760 continue;
18761
18762 //
18763 if (mSquad_Selected == SquadMemberSprite->field_32) {
18764 mSquad_Member_Clicked_TroopInSameSquad = -1;
18765 mSquad_Member_Clicked_TroopPtr = SquadMemberSprite->field_46_mission_troop;
18766 return;
18767 }
18768
18769 // Two squads joined will have more than 8 members?
18770 if (mSquads_TroopCount[SquadMemberSprite->field_32] + mSquads_TroopCount[mSquad_Selected] > 8)
18771 return;
18772
18773 mSquad_Join_TargetSprite[mSquad_Selected] = SquadMemberSprite;
18774 mSquad_Join_TargetSquad[mSquad_Selected] = (int8)SquadMemberSprite->field_32;
18775
18776 Squad_Walk_Target_Update(SquadMemberSprite->field_32);
18777
18778 break;
18779 }
18780 }
18781
Mission_Troops_Clear_Selected()18782 void cFodder::Mission_Troops_Clear_Selected() {
18783
18784 for(auto& Troop : mGame_Data.mSoldiers_Allocated)
18785 Troop.mSelected &= 0;
18786 }
18787
sub_303AE()18788 void cFodder::sub_303AE() {
18789 GUI_Sidebar_Grenades_CurrentSquad_Draw();
18790 GUI_Sidebar_Squad_Split_Icon_Draw();
18791 }
18792
Squad_Switch_Weapon()18793 void cFodder::Squad_Switch_Weapon() {
18794
18795 if (!mInput_Enabled || mPhase_Finished)
18796 return;
18797
18798 if (mSquad_CurrentWeapon[mSquad_Selected] != eWeapon_Rocket) {
18799 if (mSquad_Rockets[mSquad_Selected])
18800 Squad_Select_Rockets();
18801 }
18802 else {
18803 if (mSquad_Grenades[mSquad_Selected])
18804 Squad_Select_Grenades();
18805 }
18806 }
18807
Mission_Final_TimeToDie()18808 void cFodder::Mission_Final_TimeToDie() {
18809
18810 // Retail CF1 only
18811 if (!mVersionCurrent->isRetail() || !mVersionCurrent->isCannonFodder1())
18812 return;
18813
18814 if (!(mGame_Data.mMission_Number == 24 && mGame_Data.mMission_Phase == 6))
18815 return;
18816
18817 ++mMission_Final_TimeToDie_Ticker;
18818 if (mMission_Final_TimeToDie_Ticker < 40)
18819 return;
18820
18821 mMission_Final_TimeToDie_Ticker = 0;
18822
18823 --mMission_Final_TimeRemain;
18824 if (mMission_Final_TimeRemain < 0)
18825 mMission_Final_TimeRemain = 0;
18826
18827 if (mParams->mDisableVideo)
18828 return;
18829
18830 for (unsigned int Y = 0x1000; Y < 0x1500; ++Y) {
18831
18832 mSidebar_Screen_Buffer[Y] = 0;
18833 }
18834
18835 mGUI_Sidebar_TroopList_Name_BreakOnSpace = 11;
18836
18837 GUI_Sidebar_TroopList_Name_Draw(0, 0, 0xB7, "TIME TO DIE ");
18838
18839 GUI_Sidebar_Number_Draw(mMission_Final_TimeRemain, 0, 0x30, 0xC0, 0xAF);
18840
18841 mGUI_Sidebar_TroopList_Name_BreakOnSpace = 0x05;
18842 }
18843
sub_305D5(sSprite * & pData20)18844 int16 cFodder::sub_305D5(sSprite*& pData20) {
18845 sSprite** Data30 = 0;
18846 int16 Data0 = mSquad_Selected;
18847
18848 if (Data0 < 0)
18849 goto loc_306AD;
18850
18851 Data30 = mSquads[Data0];
18852 if (*Data30 == INVALID_SPRITE_PTR || *Data30 == 0)
18853 goto loc_306AD;
18854
18855 do {
18856 if (*Data30 == INVALID_SPRITE_PTR || *Data30 == 0)
18857 goto loc_306AD;
18858
18859 pData20 = *Data30;
18860 ++Data30;
18861 //seg011:1B61
18862 if (pData20->field_18 != eSprite_Player)
18863 continue;
18864
18865 if (pData20->field_75 & eSprite_Flag_Invincibility)
18866 goto loc_3066E;
18867
18868 if (pData20->field_38) {
18869 if (pData20->field_38 < eSprite_Anim_Slide1)
18870 goto loc_30662;
18871 }
18872 //loc_30656
18873 if (!pData20->field_5B)
18874 goto loc_30681;
18875
18876 loc_30662:;
18877 if (!pData20->field_6E)
18878 continue;
18879
18880 loc_3066E:;
18881 pData20->field_38 = eSprite_Anim_None;
18882 pData20->field_5B = 0;
18883 loc_30681:;
18884
18885 if (!pData20->field_6E)
18886 break;
18887
18888 } while (*Data30 != INVALID_SPRITE_PTR);
18889 //loc_3069A
18890 goto loc_306BE;
18891
18892 loc_306AD:;
18893 pData20 = INVALID_SPRITE_PTR;
18894 mSquad_Selected = -1;
18895
18896 loc_306BE:;
18897 if (mSquad_CurrentVehicle)
18898 return 1;
18899
18900 mSquad_Leader = pData20;
18901 if (pData20 == INVALID_SPRITE_PTR || pData20 == 0)
18902 return -1;
18903
18904 return 1;
18905 }
18906
Mouse_Inputs_Check()18907 void cFodder::Mouse_Inputs_Check() {
18908 int16 Data0 = 0;
18909 int16 Data4 = 0;
18910
18911 if (mMouseDisabled)
18912 return;
18913
18914 if (mPhase_In_Progress)
18915 Mouse_Cursor_Update();
18916
18917 if (dword_3A030) {
18918 // TODO: Function pointer call, but appears not to be used
18919 //dword_3A030();
18920 return;
18921 }
18922
18923 for (sGUI_Element* Loop_Element = mGUI_Elements;; ++Loop_Element) {
18924
18925 if (Loop_Element->field_0 == 0)
18926 break;
18927
18928 if ((*this.*Loop_Element->field_0)() < 0)
18929 return;
18930
18931 Data0 = mGUI_Mouse_Modifier_X + Loop_Element->mX;
18932
18933 int16 Data4 = mMouseX + 0x20;
18934
18935 if (Data0 > Data4)
18936 continue;
18937
18938 Data0 += Loop_Element->mWidth;
18939 if (Data0 < Data4)
18940 continue;
18941
18942 Data0 = mGUI_Mouse_Modifier_Y;
18943 Data0 += Loop_Element->mY;
18944 if (Data0 > mMouseY)
18945 continue;
18946
18947 Data0 += Loop_Element->mHeight;
18948 if (Data0 < mMouseY)
18949 continue;
18950
18951 (*this.*Loop_Element->mMouseInsideFuncPtr)();
18952 return;
18953 }
18954
18955 if (!mButtonPressRight)
18956 goto loc_30814;
18957
18958 if (mSquad_Selected < 0)
18959 return;
18960
18961 if (mMouseSpriteNew < 0) {
18962 mMouseSpriteNew = eSprite_pStuff_Mouse_Target;
18963 mMouseX_Offset = -8;
18964 mMouseY_Offset = -8;
18965 }
18966 Squad_Member_Target_Set();
18967 if (!mSquad_CurrentVehicle)
18968 return;
18969
18970 loc_30814:;
18971
18972 if (mSquad_CurrentVehicle) {
18973 Vehicle_Input_Handle();
18974 return;
18975 }
18976
18977 if (Mouse_Button_Left_Toggled() < 0)
18978 return;
18979
18980 if (mMouse_Button_LeftRight_Toggle2)
18981 return;
18982
18983 if (mMouseSpriteNew < 0) {
18984 mMouseSpriteNew = eSprite_pStuff_Mouse_Cursor;
18985 mMouseX_Offset = 0;
18986 mMouseY_Offset = 0;
18987 }
18988
18989 if (mSquad_Selected < 0) {
18990
18991 Squad_Member_Click_Check();
18992 return;
18993 }
18994
18995 sSprite** Data24 = mSquads[mSquad_Selected];
18996 sSprite* Dataa24 = *Data24;
18997
18998 if (Dataa24 == INVALID_SPRITE_PTR) {
18999 Squad_Member_Click_Check();
19000 return;
19001 }
19002
19003 if (Dataa24->field_6E)
19004 return;
19005
19006 if (word_3B2F1)
19007 word_3B2F1 = 0;
19008 else
19009 sub_311A7();
19010
19011 mSquad_Member_Clicked_TroopInSameSquad = 0;
19012 Squad_Member_Click_Check();
19013
19014 // If we clicked on a member of the current squad, nothing to do
19015 if (mSquad_Member_Clicked_TroopInSameSquad)
19016 return;
19017
19018 if (mSquad_Leader == INVALID_SPRITE_PTR || mSquad_Leader == 0)
19019 return;
19020
19021 Data0 = mMouseX + (mCameraX >> 16);
19022 Data4 = mMouseY + (mCameraY >> 16);
19023
19024 Data0 += -22;
19025 if (Data0 < 0)
19026 Data0 = 0;
19027
19028 Data4 += -3;
19029 if (Data4 < 0)
19030 Data4 = 3;
19031
19032 if (Data4 < 3)
19033 Data4 = 3;
19034
19035 mCamera_PanTargetX = Data0;
19036 mCamera_PanTargetY = Data4;
19037
19038 mMouse_Locked = false;
19039
19040 for (auto& Troop : mGame_Data.mSoldiers_Allocated) {
19041
19042 if (Troop.mSprite == INVALID_SPRITE_PTR || Troop.mSprite == 0)
19043 continue;
19044
19045 // Not in the squad?
19046 if (mSquad_Selected != Troop.mSprite->field_32)
19047 continue;
19048
19049 Troop.mSprite->field_44 = 0;
19050 Troop.mSprite->field_2 = 0;
19051 Troop.mSprite->field_6 = 0;
19052 }
19053
19054 int16 Data10 = mSquad_Leader->field_0;
19055 int16 Data8 = Data4;
19056 Data4 = Data0;
19057
19058 Squad_Walk_Target_Set(Data4, Data8, mSquad_Leader->field_32, Data10);
19059
19060 // Reset the join target
19061 for (auto& JoinTargetSquad : mSquad_Join_TargetSquad) {
19062
19063 if (mSquad_Selected != JoinTargetSquad)
19064 continue;
19065
19066 JoinTargetSquad = -1;
19067 }
19068 }
19069
Squad_Member_Target_Set()19070 void cFodder::Squad_Member_Target_Set() {
19071 sSprite** Data20 = 0;
19072
19073 if (mSquad_CurrentVehicle) {
19074 Vehicle_Target_Set();
19075 return;
19076 }
19077
19078 mSprite_Player_CheckWeapon = -1;
19079 if (word_3A9B8 < 0) {
19080 word_3A9B8 = 0x30;
19081
19082 if (mSquad_Leader)
19083 mSquad_Leader->field_4A = 0;
19084 }
19085
19086 int16 TargetX = mMouseX + (mCameraX >> 16);
19087 int16 TargetY = mMouseY + (mCameraY >> 16);
19088
19089 TargetX -= 0x10;
19090 if (!TargetX)
19091 TargetX = 1;
19092
19093 TargetY -= 8;
19094 if (mSquad_Selected < 0)
19095 goto loc_30E05;
19096
19097 if ((mSquads_TroopCount[mSquad_Selected] - 1) < 0)
19098 goto loc_30E05;
19099
19100 Data20 = mSquads[mSquad_Selected];
19101
19102 for (;;) {
19103 if (*Data20 == INVALID_SPRITE_PTR || *Data20 == 0)
19104 break;
19105
19106 sSprite* Data24 = *Data20++;
19107
19108 Data24->field_2E = TargetX;
19109 Data24->field_30 = TargetY;
19110 }
19111
19112 loc_30E05:;
19113 Squad_Member_Rotate_Can_Fire();
19114 }
19115
Mouse_Button_Right_Toggled()19116 int16 cFodder::Mouse_Button_Right_Toggled() {
19117
19118 if (mMouse_Button_Right_Toggle < 0) {
19119 mMouse_Button_Right_Toggle = 1;
19120 return 1;
19121 }
19122
19123 return -1;
19124 }
19125
Squad_Switch_Timer()19126 void cFodder::Squad_Switch_Timer() {
19127
19128 if (!mSquad_Select_Timer)
19129 return;
19130
19131 --mSquad_Select_Timer;
19132 if (mSquad_Select_Timer)
19133 return;
19134
19135 if (mSquad_Selected >= 0)
19136 return;
19137
19138 for (int16 Data0 = 2; Data0 >= 0; --Data0) {
19139
19140 if (mSquads_TroopCount[Data0]) {
19141 Squad_Switch_To(Data0);
19142 return;
19143 }
19144
19145 }
19146 }
19147
Squad_Switch_To(int16 pData0)19148 void cFodder::Squad_Switch_To(int16 pData0) {
19149
19150 if (!mSquads_TroopCount[pData0])
19151 return;
19152
19153 mSquad_Selected = pData0;
19154 sSprite* Data20 = 0;
19155
19156 if (sub_305D5(Data20) >= 0) {
19157 mCamera_StartPosition_X = Data20->field_0;
19158 mCamera_StartPosition_Y = Data20->field_4;
19159 mCamera_Start_Adjust = true;
19160 mMouse_Locked = false;
19161 }
19162
19163 mGUI_Sidebar_Setup = 0;
19164 }
19165