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