1 #include "FileMan.h"
2 #include "Font_Control.h"
3 #include "Handle_Doors.h"
4 #include "Items.h"
5 #include "Local.h"
6 #include "Merc_Hiring.h"
7 #include "Real_Time_Input.h"
8 #include "Soldier_Find.h"
9 #include "Debug.h"
10 #include "JAScreens.h"
11 #include "PathAI.h"
12 #include "Soldier_Control.h"
13 #include "Animation_Control.h"
14 #include "Animation_Data.h"
15 #include "TileDef.h"
16 #include "Timer_Control.h"
17 #include "MouseSystem.h"
18 #include "Cursors.h"
19 #include "Handle_UI.h"
20 #include "Isometric_Utils.h"
21 #include "Input.h"
22 #include "Overhead.h"
23 #include "Sys_Globals.h"
24 #include "Interface.h"
25 #include "Cursor_Control.h"
26 #include "Points.h"
27 #include "Interactive_Tiles.h"
28 #include "OppList.h"
29 #include "WorldMan.h"
30 #include "Weapons.h"
31 #include "RenderWorld.h"
32 #include "Structure.h"
33 #include "Handle_Items.h"
34 #include "UI_Cursors.h"
35 #include "Message.h"
36 #include "Render_Fun.h"
37 #include "Interface_Items.h"
38 #include "StrategicMap.h"
39 #include "Soldier_Profile.h"
40 #include "Soldier_Create.h"
41 #include "Soldier_Add.h"
42 #include "Interface_Dialogue.h"
43 #include "Soldier_Macros.h"
44 #include "Soldier_Functions.h"
45 #include "Assignments.h"
46 #include "Squads.h"
47 #include "Strategic_Pathing.h"
48 #include "Strategic_Movement.h"
49 #include "Strategic.h"
50 #include "Exit_Grids.h"
51 #include "Structure_Wrap.h"
52 #include "Random.h"
53 #include "English.h"
54 #include "Vehicles.h"
55 #include "MessageBoxScreen.h"
56 #include "Text.h"
57 #include "Dialogue_Control.h"
58 #include "Line.h"
59 #include "Render_Dirty.h"
60 #include "GameSettings.h"
61 #include "LOS.h"
62 #include "Campaign_Types.h"
63 #include "Queen_Command.h"
64 #include "Options_Screen.h"
65 #include "SaveLoadGame.h"
66 #include "Spread_Burst.h"
67 #include "AI.h"
68 #include "Game_Clock.h"
69 #include "Civ_Quotes.h"
70 #include "QArray.h"
71 #include "Environment.h"
72 #include "Map_Information.h"
73 #include "Video.h"
74 #include "Screens.h"
75 #include "UILayout.h"
76 
77 #include "ContentManager.h"
78 #include "GameInstance.h"
79 #include "Soldier.h"
80 #include "MercProfile.h"
81 
82 #include <string_theory/format>
83 #include <string_theory/string>
84 
85 #include <algorithm>
86 #include <iterator>
87 
88 #define MAX_ON_DUTY_SOLDIERS 6
89 
90 /////////////////////////////////////////////////////////////////////////////////////
91 //  UI SYSTEM DESCRIPTION
92 //
93 //  The UI system here decouples event determination from event execution. IN other words,
94 //  first any user input is gathered and analysed for an event to happen. Once the event is determined,
95 //  it is then executed. For example, if the left mouse button is used to select a guy, it does not
96 //  execute the code to selected the guy, rather it sets a flag to a particular event, in this case
97 //  the I_SELECT_MERC event is set. The code then executes this event after all input is analysed. In
98 //  this way, more than one input method from the user will cause the came event to occur and hence no
99 //  duplication of code. Also, events have cetain charactoristics. The select merc event is executed just
100 //  once and then returns to the previous event. Most events are set to run continuously until new
101 //  input changes to another event. Other events have a 'SNAP-BACK' feature which snap the mouse back to
102 //  it's position before the event was executed.  Another issue is UI modes. In order to filter out input
103 //  depending on other flags, for example we do not want to cancel the confirm when a user moves to another
104 //  tile unless we are in the 'confirm' mode.  This could be done by flags ( and in effect it is ) where
105 //  if staements are used, but here at input collection time, we can switch on our current mode to handle
106 //  input differently based on the mode. Doing it this way also allows us to group certain commands togther
107 //  like menu commands which are initialized and deleted in the same manner.
108 //
109 //  UI_EVENTS
110 /////////////
111 //
112 //  UI_EVENTS have flags to itendtify themselves with special charactoristics, a UI_MODE catagory which
113 //  signifies the UI mode this event will cause the system to move to. Also, a pointer to a handle function is
114 //  used to actually handle the particular event. UI_EVENTS also have a couple of param variables and a number
115 //  of boolean flags used during run-time to determine states of events.
116 //
117 ////////////////////////////////////////////////////////////////////////////////////////////////
118 
119 #define GO_MOVE_ONE			40
120 #define GO_MOVE_TWO			80
121 #define GO_MOVE_THREE			100
122 
123 
124 // CALLBACKS FOR EVENTS
125 static ScreenID UIHandleIDoNothing(UI_EVENT*);
126 static ScreenID UIHandleNewMerc(UI_EVENT*);
127 static ScreenID UIHandleNewBadMerc(UI_EVENT*);
128 static ScreenID UIHandleSelectMerc(UI_EVENT*);
129 static ScreenID UIHandleEnterEditMode(UI_EVENT*);
130 static ScreenID UIHandleTestHit(UI_EVENT*);
131 static ScreenID UIHandleIOnTerrain(UI_EVENT*);
132 static ScreenID UIHandleIChangeToIdle(UI_EVENT*);
133 static ScreenID UIHandleISoldierDebug(UI_EVENT*);
134 static ScreenID UIHandleILOSDebug(UI_EVENT*);
135 static ScreenID UIHandleILevelNodeDebug(UI_EVENT*);
136 
137 static ScreenID UIHandleIETOnTerrain(UI_EVENT*);
138 
139 static ScreenID UIHandleMOnTerrain(UI_EVENT*);
140 static ScreenID UIHandleMChangeToAction(UI_EVENT*);
141 static ScreenID UIHandleMCycleMovement(UI_EVENT*);
142 static ScreenID UIHandleMCycleMoveAll(UI_EVENT*);
143 static ScreenID UIHandleMAdjustStanceMode(UI_EVENT*);
144 static ScreenID UIHandleMChangeToHandMode(UI_EVENT*);
145 
146 static ScreenID UIHandleAOnTerrain(UI_EVENT*);
147 static ScreenID UIHandleAChangeToMove(UI_EVENT*);
148 static ScreenID UIHandleAChangeToConfirmAction(UI_EVENT*);
149 static ScreenID UIHandleAEndAction(UI_EVENT*);
150 
151 static ScreenID UIHandleMovementMenu(UI_EVENT*);
152 static ScreenID UIHandlePositionMenu(UI_EVENT*);
153 
154 static ScreenID UIHandleCWait(UI_EVENT*);
155 static ScreenID UIHandleCMoveMerc(UI_EVENT*);
156 static ScreenID UIHandleCOnTerrain(UI_EVENT*);
157 
158 static ScreenID UIHandlePADJAdjustStance(UI_EVENT*);
159 
160 static ScreenID UIHandleCAOnTerrain(UI_EVENT*);
161 static ScreenID UIHandleCAMercShoot(UI_EVENT*);
162 static ScreenID UIHandleCAEndConfirmAction(UI_EVENT*);
163 
164 static ScreenID UIHandleHCOnTerrain(UI_EVENT*);
165 static ScreenID UIHandleHCGettingItem(UI_EVENT*);
166 
167 
168 static ScreenID UIHandleLCOnTerrain(UI_EVENT*);
169 static ScreenID UIHandleLCChangeToLook(UI_EVENT*);
170 static ScreenID UIHandleLCLook(UI_EVENT*);
171 
172 static ScreenID UIHandleTATalkingMenu(UI_EVENT*);
173 
174 static ScreenID UIHandleTOnTerrain(UI_EVENT*);
175 static ScreenID UIHandleTChangeToTalking(UI_EVENT*);
176 
177 static ScreenID UIHandleLUIOnTerrain(UI_EVENT*);
178 static ScreenID UIHandleLUIBeginLock(UI_EVENT*);
179 
180 static ScreenID UIHandleLAOnTerrain(UI_EVENT*);
181 static ScreenID UIHandleLABeginLockOurTurn(UI_EVENT*);
182 static ScreenID UIHandleLAEndLockOurTurn(UI_EVENT*);
183 
184 static ScreenID UIHandleRubberBandOnTerrain(UI_EVENT*);
185 static ScreenID UIHandleJumpOverOnTerrain(UI_EVENT*);
186 static ScreenID UIHandleJumpOver(UI_EVENT*);
187 
188 static ScreenID UIHandleOpenDoorMenu(UI_EVENT*);
189 
190 static ScreenID UIHandleEXExitSectorMenu(UI_EVENT*);
191 
192 
193 static SOLDIERTYPE* gpRequesterMerc        = NULL;
194 static SOLDIERTYPE* gpRequesterTargetMerc  = NULL;
195 static INT16        gsRequesterGridNo;
196 static INT16        gsOverItemsGridNo      = NOWHERE;
197 static INT16        gsOverItemsLevel       = 0;
198 static BOOLEAN      gfUIInterfaceSetBusy   = FALSE;
199 static UINT32       guiUIInterfaceBusyTime = 0;
200 
201 static UINT32     gfTacticalForceNoCursor         = FALSE;
202 static LEVELNODE* gpInvTileThatCausedMoveConfirm  = NULL;
203 BOOLEAN           gfResetUIMovementOptimization   = FALSE;
204 static BOOLEAN    gfBeginVehicleCursor            = FALSE;
205 static UINT16     gsOutOfRangeGridNo              = NOWHERE;
206 static UINT8      gubOutOfRangeMerc               = NOBODY;
207 static BOOLEAN    gfOKForExchangeCursor           = FALSE;
208 static UINT32     guiUIInterfaceSwapCursorsTime   = 0;
209 INT16             gsJumpOverGridNo                = 0;
210 
211 
212 #define M(flags, to, handler)		{ flags, to, handler, FALSE, FALSE, DONT_CHANGEMODE, { 0, 0, 0 } }
213 
214 static UI_EVENT gEvents[NUM_UI_EVENTS] =
215 {
216 	M(0,                   IDLE_MODE,           UIHandleIDoNothing            ),
217 	M(UIEVENT_SINGLEEVENT, DONT_CHANGEMODE,     UIHandleNewMerc               ),
218 	M(UIEVENT_SINGLEEVENT, DONT_CHANGEMODE,     UIHandleNewBadMerc            ),
219 	M(UIEVENT_SINGLEEVENT, MOVE_MODE,           UIHandleSelectMerc            ),
220 	M(UIEVENT_SINGLEEVENT, MOVE_MODE,           UIHandleEnterEditMode         ),
221 	M(UIEVENT_SINGLEEVENT, DONT_CHANGEMODE,     UIHandleEndTurn               ),
222 	M(UIEVENT_SINGLEEVENT, DONT_CHANGEMODE,     UIHandleTestHit               ),
223 	M(UIEVENT_SINGLEEVENT, MOVE_MODE,           UIHandleChangeLevel           ),
224 	M(UIEVENT_SINGLEEVENT, IDLE_MODE,           UIHandleIOnTerrain            ),
225 	M(UIEVENT_SINGLEEVENT, IDLE_MODE,           UIHandleIChangeToIdle         ),
226 	M(UIEVENT_SINGLEEVENT, DONT_CHANGEMODE,     UIHandleISoldierDebug         ),
227 	M(UIEVENT_SINGLEEVENT, DONT_CHANGEMODE,     UIHandleILOSDebug             ),
228 	M(UIEVENT_SINGLEEVENT, DONT_CHANGEMODE,     UIHandleILevelNodeDebug       ),
229 
230 	M(0,                   ENEMYS_TURN_MODE,    UIHandleIETOnTerrain          ),
231 
232 	M(0,                   MOVE_MODE,           UIHandleMOnTerrain            ),
233 	M(UIEVENT_SINGLEEVENT, ACTION_MODE,         UIHandleMChangeToAction       ),
234 	M(UIEVENT_SINGLEEVENT, HANDCURSOR_MODE,     UIHandleMChangeToHandMode     ),
235 	M(UIEVENT_SINGLEEVENT, MOVE_MODE,           UIHandleMCycleMovement        ),
236 	M(UIEVENT_SINGLEEVENT, CONFIRM_MOVE_MODE,   UIHandleMCycleMoveAll         ),
237 	M(UIEVENT_SNAPMOUSE,   ADJUST_STANCE_MODE,  UIHandleMAdjustStanceMode     ),
238 	M(0,                   ACTION_MODE,         UIHandleAOnTerrain            ),
239 	M(UIEVENT_SINGLEEVENT, MOVE_MODE,           UIHandleAChangeToMove         ),
240 	M(UIEVENT_SINGLEEVENT, CONFIRM_ACTION_MODE, UIHandleAChangeToConfirmAction),
241 	M(UIEVENT_SINGLEEVENT, MOVE_MODE,           UIHandleAEndAction            ),
242 	M(UIEVENT_SNAPMOUSE,   MENU_MODE,           UIHandleMovementMenu          ),
243 	M(UIEVENT_SNAPMOUSE,   MENU_MODE,           UIHandlePositionMenu          ),
244 	M(0,                   CONFIRM_MOVE_MODE,   UIHandleCWait                 ),
245 	M(UIEVENT_SINGLEEVENT, MOVE_MODE,           UIHandleCMoveMerc             ),
246 	M(0,                   CONFIRM_MOVE_MODE,   UIHandleCOnTerrain            ),
247 	M(0,                   MOVE_MODE,           UIHandlePADJAdjustStance      ),
248 	M(0,                   CONFIRM_ACTION_MODE, UIHandleCAOnTerrain           ),
249 	M(UIEVENT_SINGLEEVENT, ACTION_MODE,         UIHandleCAMercShoot           ),
250 	M(UIEVENT_SINGLEEVENT, ACTION_MODE,         UIHandleCAEndConfirmAction    ),
251 	M(0,                   HANDCURSOR_MODE,     UIHandleHCOnTerrain           ),
252 	M(0,                   GETTINGITEM_MODE,    UIHandleHCGettingItem         ),
253 	M(0,                   LOOKCURSOR_MODE,     UIHandleLCOnTerrain           ),
254 	M(UIEVENT_SINGLEEVENT, LOOKCURSOR_MODE,     UIHandleLCChangeToLook        ),
255 	M(UIEVENT_SINGLEEVENT, MOVE_MODE,           UIHandleLCLook                ),
256 	M(0,                   TALKINGMENU_MODE,    UIHandleTATalkingMenu         ),
257 	M(0,                   TALKCURSOR_MODE,     UIHandleTOnTerrain            ),
258 	M(UIEVENT_SINGLEEVENT, TALKCURSOR_MODE,     UIHandleTChangeToTalking      ),
259 	M(0,                   LOCKUI_MODE,         UIHandleLUIOnTerrain          ),
260 	M(0,                   LOCKUI_MODE,         UIHandleLUIBeginLock          ),
261 	M(UIEVENT_SINGLEEVENT, MOVE_MODE,           UIHandleLUIEndLock            ),
262 	M(0,                   OPENDOOR_MENU_MODE,  UIHandleOpenDoorMenu          ),
263 	M(0,                   LOCKOURTURN_UI_MODE, UIHandleLAOnTerrain           ),
264 	M(0,                   LOCKOURTURN_UI_MODE, UIHandleLABeginLockOurTurn    ),
265 	M(UIEVENT_SINGLEEVENT, MOVE_MODE,           UIHandleLAEndLockOurTurn      ),
266 	M(0,                   EXITSECTORMENU_MODE, UIHandleEXExitSectorMenu      ),
267 	M(0,                   RUBBERBAND_MODE,     UIHandleRubberBandOnTerrain   ),
268 	M(0,                   JUMPOVER_MODE,       UIHandleJumpOverOnTerrain     ),
269 	M(0,                   MOVE_MODE,           UIHandleJumpOver              )
270 };
271 
272 #undef M
273 
274 
275 UI_MODE gCurrentUIMode = IDLE_MODE;
276 static UI_MODE gOldUIMode = IDLE_MODE;
277 UIEventKind guiCurrentEvent = I_DO_NOTHING;
278 static UIEventKind guiOldEvent = I_DO_NOTHING;
279 UICursorID guiCurrentUICursor = NO_UICURSOR;
280 static UICursorID guiNewUICursor = NORMAL_SNAPUICURSOR;
281 UIEventKind guiPendingOverrideEvent = I_DO_NOTHING;
282 static UINT16 gusSavedMouseX;
283 static UINT16 gusSavedMouseY;
284 UIKEYBOARD_HOOK gUIKeyboardHook = NULL;
285 BOOLEAN gUIActionModeChangeDueToMouseOver = FALSE;
286 
287 static BOOLEAN    gfDisplayTimerCursor = FALSE;
288 static UICursorID guiTimerCursorID     = NO_UICURSOR;
289 static UINT32     guiTimerLastUpdate   = 0;
290 static UINT32     guiTimerCursorDelay  = 0;
291 
292 
293 MOUSE_REGION gDisableRegion;
294 BOOLEAN gfDisableRegionActive = FALSE;
295 
296 MOUSE_REGION gUserTurnRegion;
297 BOOLEAN gfUserTurnRegionActive = FALSE;
298 
299 
300 // For use with mouse button query routines
301 BOOLEAN	fRightButtonDown = FALSE;
302 BOOLEAN	fLeftButtonDown = FALSE;
303 BOOLEAN	fMiddleButtonDown = FALSE;
304 BOOLEAN fIgnoreLeftUp = FALSE;
305 
306 static BOOLEAN gUITargetReady = FALSE;
307 BOOLEAN gUITargetShotWaiting = FALSE;
308 BOOLEAN gUIUseReverse = FALSE;
309 
310 SGPRect gRubberBandRect = { 0, 0, 0, 0 };
311 BOOLEAN gRubberBandActive = FALSE;
312 BOOLEAN gfIgnoreOnSelectedGuy = FALSE;
313 static BOOLEAN gfViewPortAdjustedForSouth = FALSE;
314 
315 // FLAGS
316 // These flags are set for a single frame execution and then are reset for the next iteration.
317 BOOLEAN gfUIDisplayActionPoints = FALSE;
318 BOOLEAN gfUIDisplayActionPointsInvalid = FALSE;
319 BOOLEAN gfUIDisplayActionPointsBlack = FALSE;
320 BOOLEAN gfUIDisplayActionPointsCenter = FALSE;
321 
322 INT16 gUIDisplayActionPointsOffY = 0;
323 INT16 gUIDisplayActionPointsOffX = 0;
324 BOOLEAN gfUIHandleSelection = FALSE;
325 BOOLEAN gfUIHandleShowMoveGrid = FALSE;
326 UINT16 gsUIHandleShowMoveGridLocation = NOWHERE ;
327 GridNo gfUIOverItemPoolGridNo = NOWHERE;
328 INT16 gsCurrentActionPoints = 1;
329 BOOLEAN gfUIHandlePhysicsTrajectory = FALSE;
330 BOOLEAN gfUIMouseOnValidCatcher = FALSE;
331 const SOLDIERTYPE* gUIValidCatcher = NULL;
332 
333 
334 BOOLEAN gfUIConfirmExitArrows = FALSE;
335 
336 BOOLEAN gfUIShowCurIntTile = FALSE;
337 
338 BOOLEAN gfUIWaitingForUserSpeechAdvance = FALSE; // Waiting for key input/mouse click to advance speech
339 BOOLEAN gfUIAllMoveOn = FALSE; // Sets to all move
340 BOOLEAN gfUICanBeginAllMoveCycle = FALSE; // GEts set so we know that the next right-click is a move-call inc\stead of a movement cycle through
341 
342 INT16 gsSelectedGridNo = 0;
343 INT16 gsSelectedLevel = I_GROUND_LEVEL;
344 SOLDIERTYPE* gSelectedGuy = NULL;
345 
346 BOOLEAN gfUIRefreshArrows = FALSE;
347 
348 
349 // Thse flags are not re-set after each frame
350 BOOLEAN gfPlotNewMovement = FALSE;
351 static BOOLEAN gfPlotNewMovementNOCOST = FALSE;
352 UINT32 guiShowUPDownArrows = ARROWS_HIDE_UP | ARROWS_HIDE_DOWN;
353 static INT8    gbAdjustStanceDiff      = 0;
354 static INT8    gbClimbID               = 0;
355 
356 BOOLEAN        gfUIShowExitEast     = FALSE;
357 BOOLEAN        gfUIShowExitWest     = FALSE;
358 BOOLEAN        gfUIShowExitNorth    = FALSE;
359 BOOLEAN        gfUIShowExitSouth    = FALSE;
360 static BOOLEAN gfUIShowExitExitGrid = FALSE;
361 
362 static BOOLEAN gfUINewStateForIntTile = FALSE;
363 
364 BOOLEAN gfUIForceReExamineCursorData = FALSE;
365 
366 
367 SOLDIERTYPE*     gUIFullTarget;
368 SoldierFindFlags guiUIFullTargetFlags;
369 
370 
371 static void ClearEvent(UI_EVENT* pUIEvent);
372 static void SetUIMouseCursor(void);
373 
374 
375 // MAIN TACTICAL UI HANDLER
HandleTacticalUI(void)376 ScreenID HandleTacticalUI(void)
377 {
378 	LEVELNODE *pIntTile;
379 	static LEVELNODE *pOldIntTile = NULL;
380 
381 
382 	// RESET FLAGS
383 	gfUIDisplayActionPoints = FALSE;
384 	gfUIDisplayActionPointsInvalid = FALSE;
385 	gfUIDisplayActionPointsBlack = FALSE;
386 	gfUIDisplayActionPointsCenter = FALSE;
387 	gfUIHandleSelection = NO_GUY_SELECTION;
388 	gSelectedGuy = NULL;
389 	guiShowUPDownArrows = ARROWS_HIDE_UP | ARROWS_HIDE_DOWN;
390 	SetHitLocationText(ST::null);
391 	SetIntTileLocationText(ST::null);
392 	SetIntTileLocation2Text(ST::null);
393 	//gfUIForceReExamineCursorData = FALSE;
394 	gfUINewStateForIntTile = FALSE;
395 	gfUIShowExitExitGrid = FALSE;
396 	gfUIOverItemPoolGridNo = NOWHERE;
397 	gfUIHandlePhysicsTrajectory = FALSE;
398 	gfUIMouseOnValidCatcher = FALSE;
399 	gUIValidCatcher = NULL;
400 	gfIgnoreOnSelectedGuy = FALSE;
401 
402 	// Set old event value
403 	UIEventKind uiNewEvent = guiCurrentEvent;
404 	guiOldEvent            = uiNewEvent;
405 
406 	if ( gfUIInterfaceSetBusy )
407 	{
408 		if ( ( GetJA2Clock( ) - guiUIInterfaceBusyTime ) > 25000 )
409 		{
410 			gfUIInterfaceSetBusy = FALSE;
411 
412 			//UNLOCK UI
413 			UnSetUIBusy(GetSelectedMan());
414 
415 			// Decrease global busy  counter...
416 			gTacticalStatus.ubAttackBusyCount = 0;
417 			guiPendingOverrideEvent = LU_ENDUILOCK;
418 			UIHandleLUIEndLock( NULL );
419 		}
420 	}
421 
422 	if ( ( GetJA2Clock( ) - guiUIInterfaceSwapCursorsTime ) > 1000 )
423 	{
424 		gfOKForExchangeCursor = !gfOKForExchangeCursor;
425 		guiUIInterfaceSwapCursorsTime = GetJA2Clock( );
426 	}
427 
428 	// OK, do a check for on an int tile...
429 	pIntTile = GetCurInteractiveTile( );
430 
431 	if ( pIntTile != pOldIntTile )
432 	{
433 		gfUINewStateForIntTile = TRUE;
434 
435 		pOldIntTile = pIntTile;
436 	}
437 
438 	if ( guiPendingOverrideEvent == I_DO_NOTHING )
439 	{
440 		// When we are here, guiCurrentEvent is set to the last event
441 		// Within the input gathering phase, it may change
442 
443 		// GATHER INPUT
444 		// Any new event will overwrite previous events. Therefore,
445 		// PRIOTITIES GO LIKE THIS:
446 		//   Mouse Movement
447 		//   Keyboard Polling
448 		//   Mouse Buttons
449 		//   Keyboard Queued Events ( will override always )
450 
451 		// SWITCH ON INPUT GATHERING, DEPENDING ON MODE
452 		// IF WE ARE NOT IN COMBAT OR IN REALTIME COMBAT
453 		if (!(gTacticalStatus.uiFlags & INCOMBAT))
454 		{
455 			// FROM MOUSE POSITION
456 			GetRTMousePositionInput( &uiNewEvent );
457 			// FROM KEYBOARD POLLING
458 			GetPolledKeyboardInput( &uiNewEvent );
459 			// FROM MOUSE CLICKS
460 			GetRTMouseButtonInput( &uiNewEvent );
461 			// FROM KEYBOARD
462 			GetKeyboardInput( &uiNewEvent );
463 
464 		}
465 		else
466 		{
467 			// FROM MOUSE POSITION
468 			GetTBMousePositionInput( &uiNewEvent );
469 			// FROM KEYBOARD POLLING
470 			GetPolledKeyboardInput( &uiNewEvent );
471 			// FROM MOUSE CLICKS
472 			GetTBMouseButtonInput( &uiNewEvent );
473 			// FROM KEYBOARD
474 			GetKeyboardInput( &uiNewEvent );
475 		}
476 
477 
478 	}
479 	else
480 	{
481 		uiNewEvent = guiPendingOverrideEvent;
482 		guiPendingOverrideEvent = I_DO_NOTHING;
483 	}
484 
485 	if ( HandleItemPickupMenu( ) )
486 	{
487 		uiNewEvent = A_CHANGE_TO_MOVE;
488 	}
489 
490 	// Set Current event to new one!
491 	guiCurrentEvent = uiNewEvent;
492 
493 	//ATE: New! Get flags for over soldier or not...
494 	const GridNo usMapPos = GetMouseMapPos();
495 	if (usMapPos != NOWHERE)
496 	{
497 		// Look for soldier full
498 		SOLDIERTYPE* const s = FindSoldier(usMapPos, FINDSOLDIERSAMELEVEL(gsInterfaceLevel));
499 		gUIFullTarget        = s;
500 		guiUIFullTargetFlags = s ? GetSoldierFindFlags(*s) : NO_MERC;
501 	}
502 
503 	// Check if current event has changed and clear event if so, to prepare it for execution
504 	// Clearing it does things like set first time flag, param variavles, etc
505 	if ( uiNewEvent != guiOldEvent )
506 	{
507 		// Snap mouse back if it's that type
508 		if ( gEvents[ guiOldEvent ].uiFlags & UIEVENT_SNAPMOUSE )
509 		{
510 			SimulateMouseMovement( (UINT32)gusSavedMouseX, (UINT32)gusSavedMouseY );
511 		}
512 
513 		ClearEvent( &gEvents[ uiNewEvent ] );
514 	}
515 
516 	// Restore not scrolling from stance adjust....
517 	if ( gOldUIMode == ADJUST_STANCE_MODE )
518 	{
519 		gfIgnoreScrolling = FALSE;
520 	}
521 
522 	// IF this event is of type snap mouse, save position
523 	if ( gEvents[ uiNewEvent ].uiFlags & UIEVENT_SNAPMOUSE && gEvents[ uiNewEvent ].fFirstTime )
524 	{
525 			// Save mouse position
526 			gusSavedMouseX = gusMouseXPos;
527 			gusSavedMouseY = gusMouseYPos;
528 	}
529 
530 	// HANDLE UI EVENT
531 	ScreenID const ReturnVal = gEvents[uiNewEvent].HandleEvent(&gEvents[uiNewEvent]);
532 
533 	if ( gfInOpenDoorMenu )
534 	{
535 		return( ReturnVal );
536 	}
537 
538 	// Set first time flag to false, now that it has been executed
539 	gEvents[ uiNewEvent ].fFirstTime = FALSE;
540 
541 	// Check if UI mode has changed from previous event
542 	if (gEvents[uiNewEvent].ChangeToUIMode != gCurrentUIMode &&
543 		(gEvents[uiNewEvent].ChangeToUIMode != DONT_CHANGEMODE))
544 	{
545 		gEvents[ uiNewEvent ].uiMenuPreviousMode = gCurrentUIMode;
546 
547 		gOldUIMode = gCurrentUIMode;
548 
549 		gCurrentUIMode = gEvents[ uiNewEvent ].ChangeToUIMode;
550 
551 		// CHANGE MODE - DO SPECIAL THINGS IF WE ENTER THIS MODE
552 		switch( gCurrentUIMode )
553 		{
554 			case ACTION_MODE:
555 				ErasePath();
556 				break;
557 			default:
558 				break;
559 		}
560 
561 	}
562 
563 	// Check if menu event is done and if so set to privious mode
564 	// This is needed to hook into the interface stuff which sets the fDoneMenu flag
565 	if (gEvents[uiNewEvent].fDoneMenu)
566 	{
567 		if (gCurrentUIMode == MENU_MODE || gCurrentUIMode == LOOKCURSOR_MODE)
568 		{
569 			gCurrentUIMode = gEvents[ uiNewEvent ].uiMenuPreviousMode;
570 		}
571 	}
572 	// Check to return to privious mode
573 	// If the event is a single event, return to previous
574 	if ( gEvents[ uiNewEvent ].uiFlags & UIEVENT_SINGLEEVENT )
575 	{
576 		// ATE: OK - don't revert to single event if our mouse is not
577 		// in viewport - rather use m_on_t event
578 		if ( ( gViewportRegion.uiFlags & MSYS_MOUSE_IN_AREA )  )
579 		{
580 			guiCurrentEvent = guiOldEvent;
581 		}
582 		else
583 		{
584 			// ATE: Check first that some modes are met....
585 			if ( gCurrentUIMode != HANDCURSOR_MODE && gCurrentUIMode != LOOKCURSOR_MODE && gCurrentUIMode != TALKCURSOR_MODE )
586 			{
587 				guiCurrentEvent = M_ON_TERRAIN;
588 			}
589 		}
590 	}
591 
592 	// Donot display APs if not in combat
593 	if (!(gTacticalStatus.uiFlags & INCOMBAT))
594 	{
595 		gfUIDisplayActionPoints = FALSE;
596 	}
597 
598 
599 	// Will set the cursor but only if different
600 	SetUIMouseCursor( );
601 
602 	// ATE: Check to reset selected guys....
603 	if ( gTacticalStatus.fAtLeastOneGuyOnMultiSelect )
604 	{
605 		// If not in MOVE_MODE, CONFIRM_MOVE_MODE, RUBBERBAND_MODE, stop....
606 		if ( gCurrentUIMode != MOVE_MODE && gCurrentUIMode != CONFIRM_MOVE_MODE && gCurrentUIMode != RUBBERBAND_MODE && gCurrentUIMode != ADJUST_STANCE_MODE && gCurrentUIMode != TALKCURSOR_MODE && gCurrentUIMode != LOOKCURSOR_MODE )
607 		{
608 			ResetMultiSelection( );
609 		}
610 	}
611 
612 	return( ReturnVal );
613 }
614 
615 
SetUIMouseCursor(void)616 static void SetUIMouseCursor(void)
617 {
618 	BOOLEAN	fForceUpdateNewCursor = FALSE;
619 	BOOLEAN	fUpdateNewCursor = TRUE;
620 	static INT16 sOldExitGridNo = NOWHERE;
621 	static BOOLEAN	fOkForExit = FALSE;
622 
623 
624 	// Check if we moved from confirm mode on exit arrows
625 	// If not in move mode, return!
626 	if ( gCurrentUIMode == MOVE_MODE )
627 	{
628 		if ( gfUIConfirmExitArrows )
629 		{
630 			if (GetCursorMovementFlags() != MOUSE_STATIONARY)
631 			{
632 				gfUIConfirmExitArrows = FALSE;
633 			}
634 		}
635 
636 
637 		if ( gfUIShowExitEast )
638 		{
639 			gfUIDisplayActionPoints = FALSE;
640 			ErasePath();
641 
642 			if (OKForSectorExit(EAST_STRATEGIC_MOVE, 0))
643 			{
644 				if ( gfUIConfirmExitArrows )
645 				{
646 					guiNewUICursor = CONFIRM_EXIT_EAST_UICURSOR;
647 				}
648 				else
649 				{
650 					guiNewUICursor = EXIT_EAST_UICURSOR;
651 				}
652 			}
653 			else
654 			{
655 				guiNewUICursor = NOEXIT_EAST_UICURSOR;
656 			}
657 
658 			if (gusMouseXPos < SCREEN_WIDTH - NO_PX_SHOW_EXIT_CURS)
659 			{
660 				gfUIShowExitEast = FALSE;
661 			}
662 		}
663 
664 		if ( gfUIShowExitWest )
665 		{
666 			gfUIDisplayActionPoints = FALSE;
667 			ErasePath();
668 
669 			if (OKForSectorExit(WEST_STRATEGIC_MOVE, 0))
670 			{
671 				if ( gfUIConfirmExitArrows )
672 				{
673 					guiNewUICursor = CONFIRM_EXIT_WEST_UICURSOR;
674 				}
675 				else
676 				{
677 					guiNewUICursor = EXIT_WEST_UICURSOR;
678 				}
679 			}
680 			else
681 			{
682 				guiNewUICursor = NOEXIT_WEST_UICURSOR;
683 			}
684 
685 			if ( gusMouseXPos > NO_PX_SHOW_EXIT_CURS )
686 			{
687 				gfUIShowExitWest = FALSE;
688 			}
689 		}
690 
691 		if ( gfUIShowExitNorth )
692 		{
693 			gfUIDisplayActionPoints = FALSE;
694 			ErasePath();
695 
696 			if (OKForSectorExit(NORTH_STRATEGIC_MOVE, 0))
697 			{
698 				if ( gfUIConfirmExitArrows )
699 				{
700 					guiNewUICursor = CONFIRM_EXIT_NORTH_UICURSOR;
701 				}
702 				else
703 				{
704 					guiNewUICursor = EXIT_NORTH_UICURSOR;
705 				}
706 			}
707 			else
708 			{
709 				guiNewUICursor = NOEXIT_NORTH_UICURSOR;
710 			}
711 
712 			if ( gusMouseYPos > NO_PX_SHOW_EXIT_CURS )
713 			{
714 				gfUIShowExitNorth = FALSE;
715 			}
716 		}
717 
718 
719 		if ( gfUIShowExitSouth )
720 		{
721 			gfUIDisplayActionPoints = FALSE;
722 			ErasePath();
723 
724 			if (OKForSectorExit(SOUTH_STRATEGIC_MOVE, 0))
725 			{
726 				if ( gfUIConfirmExitArrows )
727 				{
728 					guiNewUICursor = CONFIRM_EXIT_SOUTH_UICURSOR;
729 				}
730 				else
731 				{
732 					guiNewUICursor = EXIT_SOUTH_UICURSOR;
733 				}
734 			}
735 			else
736 			{
737 				guiNewUICursor = NOEXIT_SOUTH_UICURSOR;
738 			}
739 
740 			if (gusMouseYPos < SCREEN_HEIGHT - NO_PX_SHOW_EXIT_CURS)
741 			{
742 				gfUIShowExitSouth = FALSE;
743 
744 				// Define region for viewport
745 				MSYS_RemoveRegion( &gViewportRegion );
746 
747 				MSYS_DefineRegion(&gViewportRegion, 0, 0 ,gsVIEWPORT_END_X, gsVIEWPORT_WINDOW_END_Y,
748 							MSYS_PRIORITY_NORMAL,
749 							VIDEO_NO_CURSOR, MSYS_NO_CALLBACK, MSYS_NO_CALLBACK);
750 
751 
752 				// Adjust where we blit our cursor!
753 				gsGlobalCursorYOffset = 0;
754 				SetCurrentCursorFromDatabase( CURSOR_NORMAL );
755 			}
756 			else if (!gfScrollPending && !g_scroll_inertia)
757 			{
758 				// Adjust viewport to edge of screen!
759 				// Define region for viewport
760 				MSYS_RemoveRegion(&gViewportRegion);
761 				MSYS_DefineRegion(&gViewportRegion, 0, 0, gsVIEWPORT_END_X, SCREEN_HEIGHT, MSYS_PRIORITY_NORMAL, VIDEO_NO_CURSOR, MSYS_NO_CALLBACK, MSYS_NO_CALLBACK);
762 
763 				gsGlobalCursorYOffset = SCREEN_HEIGHT - gsVIEWPORT_WINDOW_END_Y;
764 				SetCurrentCursorFromDatabase(gUICursors[guiNewUICursor].usFreeCursorName);
765 
766 				gfViewPortAdjustedForSouth = TRUE;
767 			}
768 		}
769 		else
770 		{
771 			if ( gfViewPortAdjustedForSouth )
772 			{
773 				// Define region for viewport
774 				MSYS_RemoveRegion( &gViewportRegion );
775 
776 				MSYS_DefineRegion(&gViewportRegion, 0, 0 ,gsVIEWPORT_END_X, gsVIEWPORT_WINDOW_END_Y,
777 							MSYS_PRIORITY_NORMAL,
778 							VIDEO_NO_CURSOR, MSYS_NO_CALLBACK, MSYS_NO_CALLBACK);
779 
780 
781 				// Adjust where we blit our cursor!
782 				gsGlobalCursorYOffset = 0;
783 				SetCurrentCursorFromDatabase( CURSOR_NORMAL );
784 
785 				gfViewPortAdjustedForSouth = FALSE;
786 			}
787 		}
788 
789 		if ( gfUIShowExitExitGrid )
790 		{
791 			gfUIDisplayActionPoints = FALSE;
792 			ErasePath();
793 
794 			const GridNo usMapPos = GetMouseMapPos();
795 			if (usMapPos != NOWHERE)
796 			{
797 				const SOLDIERTYPE* const sel = GetSelectedMan();
798 				if (sel != NULL && sel->bLevel == 0)
799 				{
800 					// ATE: Is this place revealed?
801 					if (GetRoom(usMapPos) == NO_ROOM || gpWorldLevelData[usMapPos].uiFlags & MAPELEMENT_REVEALED)
802 					{
803 						if ( sOldExitGridNo != usMapPos )
804 						{
805 							fOkForExit = OKForSectorExit((INT8)-1, usMapPos);
806 							sOldExitGridNo = usMapPos;
807 						}
808 
809 						if ( fOkForExit )
810 						{
811 							if ( gfUIConfirmExitArrows )
812 							{
813 								guiNewUICursor = CONFIRM_EXIT_GRID_UICURSOR;
814 							}
815 							else
816 							{
817 								guiNewUICursor = EXIT_GRID_UICURSOR;
818 							}
819 						}
820 						else
821 						{
822 							guiNewUICursor = NOEXIT_GRID_UICURSOR;
823 						}
824 					}
825 				}
826 			}
827 		}
828 		else
829 		{
830 			sOldExitGridNo = NOWHERE;
831 		}
832 
833 	}
834 	else
835 	{
836 		gsGlobalCursorYOffset = 0;
837 	}
838 
839 	if ( gfDisplayTimerCursor )
840 	{
841 		SetUICursor( guiTimerCursorID );
842 
843 		fUpdateNewCursor = FALSE;
844 
845 		if ( ( GetJA2Clock( ) - guiTimerLastUpdate ) > guiTimerCursorDelay )
846 		{
847 			gfDisplayTimerCursor = FALSE;
848 
849 			// OK, timer may be different, update...
850 			fForceUpdateNewCursor = TRUE;
851 			fUpdateNewCursor = TRUE;
852 		}
853 	}
854 
855 	if ( fUpdateNewCursor )
856 	{
857 		if ( !gfTacticalForceNoCursor )
858 		{
859 			if ( guiNewUICursor != guiCurrentUICursor || fForceUpdateNewCursor )
860 			{
861 				SetUICursor( guiNewUICursor );
862 
863 				guiCurrentUICursor = guiNewUICursor;
864 			}
865 		}
866 	}
867 }
868 
SetUIKeyboardHook(UIKEYBOARD_HOOK KeyboardHookFnc)869 void SetUIKeyboardHook( UIKEYBOARD_HOOK KeyboardHookFnc )
870 {
871 	gUIKeyboardHook = KeyboardHookFnc;
872 }
873 
874 
ClearEvent(UI_EVENT * pUIEvent)875 static void ClearEvent(UI_EVENT* pUIEvent)
876 {
877 	std::fill(std::begin(pUIEvent->uiParams), std::end(pUIEvent->uiParams), 0);
878 	pUIEvent->fDoneMenu = FALSE;
879 	pUIEvent->fFirstTime = TRUE;
880 	pUIEvent->uiMenuPreviousMode = DONT_CHANGEMODE;
881 }
882 
883 
EndMenuEvent(UINT32 uiEvent)884 void EndMenuEvent( UINT32 uiEvent )
885 {
886 	gEvents[ uiEvent ].fDoneMenu = TRUE;
887 
888 }
889 
890 
UIHandleIDoNothing(UI_EVENT * pUIEvent)891 static ScreenID UIHandleIDoNothing(UI_EVENT* pUIEvent)
892 {
893 	guiNewUICursor = NORMAL_SNAPUICURSOR;
894 
895 	return( GAME_SCREEN );
896 }
897 
898 
UIHandleNewMerc(UI_EVENT * pUIEvent)899 static ScreenID UIHandleNewMerc(UI_EVENT* pUIEvent)
900 {
901 	static UINT8 ubTemp = 3;
902 	MERC_HIRE_STRUCT HireMercStruct;
903 	INT8 bReturnCode;
904 
905 	const GridNo usMapPos = GetMouseMapPos();
906 	if (usMapPos != NOWHERE)
907 	{
908 		ubTemp+= 2;
909 
910 		HireMercStruct = MERC_HIRE_STRUCT{};
911 
912 		HireMercStruct.ubProfileID = ubTemp;
913 
914 		//DEF: temp
915 		HireMercStruct.sSectorX = gWorldSectorX;
916 		HireMercStruct.sSectorY = gWorldSectorY;
917 		HireMercStruct.bSectorZ = gbWorldSectorZ;
918 		HireMercStruct.ubInsertionCode	= INSERTION_CODE_GRIDNO;
919 		HireMercStruct.usInsertionData	= usMapPos;
920 		HireMercStruct.fCopyProfileItemsOver = TRUE;
921 		HireMercStruct.iTotalContractLength = 7;
922 
923 		//specify when the merc should arrive
924 		HireMercStruct.uiTimeTillMercArrives = 0;
925 
926 		//if we succesfully hired the merc
927 		bReturnCode = HireMerc(HireMercStruct);
928 
929 		if( bReturnCode == MERC_HIRE_FAILED )
930 		{
931 			SLOGD("Merc hire failed:  Either already hired or dislikes you." );
932 		}
933 		else if( bReturnCode == MERC_HIRE_OVER_20_MERCS_HIRED )
934 		{
935 			SLOGD("Can't hire more than 20 mercs." );
936 		}
937 		else
938 		{
939 			// Get soldier from profile
940 			SOLDIERTYPE* const pSoldier = FindSoldierByProfileID(ubTemp);
941 			MercArrivesCallback(*pSoldier);
942 			SelectSoldier(pSoldier, SELSOLDIER_FORCE_RESELECT);
943 		}
944 
945 	}
946 	return( GAME_SCREEN );
947 }
948 
949 
UIHandleNewBadMerc(UI_EVENT *)950 static ScreenID UIHandleNewBadMerc(UI_EVENT*)
951 {
952 	// Get map postion and place the enemy there
953 	GridNo const map_pos = GetMouseMapPos();
954 	if (map_pos == NOWHERE) return GAME_SCREEN;
955 
956 	// Are we an OK dest?
957 	if (!IsLocationSittable(map_pos, 0)) return GAME_SCREEN;
958 
959 	UINT32       const roll = Random(10);
960 	SoldierClass const sc   = roll < 4 ? SOLDIER_CLASS_ADMINISTRATOR :
961 					roll < 8 ? SOLDIER_CLASS_ARMY :
962 					SOLDIER_CLASS_ELITE;
963 	SOLDIERTYPE* const s = TacticalCreateEnemySoldier(sc);
964 	if (!s) return GAME_SCREEN;
965 
966 	// Add soldier strategic info, so it doesn't break the counters
967 	if (gbWorldSectorZ == 0)
968 	{
969 		SECTORINFO& sector = SectorInfo[SECTOR(gWorldSectorX, gWorldSectorY)];
970 		switch (s->ubSoldierClass)
971 		{
972 			case SOLDIER_CLASS_ADMINISTRATOR:
973 				++sector.ubNumAdmins;
974 				++sector.ubAdminsInBattle;
975 				break;
976 			case SOLDIER_CLASS_ARMY:
977 				++sector.ubNumTroops;
978 				++sector.ubTroopsInBattle;
979 				break;
980 			case SOLDIER_CLASS_ELITE:
981 				++sector.ubNumElites;
982 				++sector.ubElitesInBattle;
983 				break;
984 		}
985 	}
986 	else
987 	{
988 		if (UNDERGROUND_SECTORINFO* const sector = FindUnderGroundSector(gWorldSectorX, gWorldSectorY, gbWorldSectorZ))
989 		{
990 			switch (s->ubSoldierClass)
991 			{
992 				case SOLDIER_CLASS_ADMINISTRATOR:
993 					++sector->ubNumAdmins;
994 					++sector->ubAdminsInBattle;
995 					break;
996 				case SOLDIER_CLASS_ARMY:
997 					++sector->ubNumTroops;
998 					++sector->ubTroopsInBattle;
999 					break;
1000 				case SOLDIER_CLASS_ELITE:
1001 					++sector->ubNumElites;
1002 					++sector->ubElitesInBattle;
1003 					break;
1004 			}
1005 		}
1006 	}
1007 
1008 	s->ubStrategicInsertionCode = INSERTION_CODE_GRIDNO;
1009 	s->usStrategicInsertionData = map_pos;
1010 	UpdateMercInSector(*s, gWorldSectorX, gWorldSectorY, gbWorldSectorZ);
1011 	AllTeamsLookForAll(NO_INTERRUPTS);
1012 
1013 	return GAME_SCREEN;
1014 }
1015 
1016 
UIHandleEnterEditMode(UI_EVENT * pUIEvent)1017 static ScreenID UIHandleEnterEditMode(UI_EVENT* pUIEvent)
1018 {
1019 	return( EDIT_SCREEN );
1020 }
1021 
1022 
UIHandleEndTurn(UI_EVENT * pUIEvent)1023 ScreenID UIHandleEndTurn(UI_EVENT* pUIEvent)
1024 {
1025 	// ATE: If we have an item pointer end it!
1026 	CancelItemPointer( );
1027 
1028 	//ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, TacticalStr[ ENDING_TURN ] );
1029 
1030 	if ( CheckForEndOfCombatMode( FALSE ) )
1031 	{
1032 		// do nothing...
1033 	}
1034 	else
1035 	{
1036 		if( GCM->doesGameResExists( "../AutoSave.pls" ) && CanGameBeSaved() )
1037 		{
1038 			//Save the game
1039 			guiPreviousOptionScreen = guiCurrentScreen;
1040 			SaveGame( SAVE__END_TURN_NUM, "End Turn Auto Save" );
1041 		}
1042 
1043 		// End our turn!
1044 		EndTurn( OUR_TEAM + 1 );
1045 	}
1046 
1047 	return( GAME_SCREEN );
1048 }
1049 
1050 
UIHandleTestHit(UI_EVENT * pUIEvent)1051 static ScreenID UIHandleTestHit(UI_EVENT* pUIEvent)
1052 {
1053 	INT8 bDamage;
1054 
1055 	// CHECK IF WE'RE ON A GUY ( EITHER SELECTED, OURS, OR THEIRS
1056 	if (gUIFullTarget != NULL)
1057 	{
1058 		SOLDIERTYPE* const tgt = gUIFullTarget;
1059 
1060 		if ( _KeyDown( SHIFT ) )
1061 		{
1062 			tgt->bBreath -= 30;
1063 			if (tgt->bBreath < 0) tgt->bBreath = 0;
1064 			bDamage = 1;
1065 		}
1066 		else
1067 		{
1068 			if ( Random(2)  )
1069 			{
1070 				bDamage = 20;
1071 			}
1072 			else
1073 			{
1074 				bDamage = 25;
1075 			}
1076 		}
1077 
1078 		gTacticalStatus.ubAttackBusyCount++;
1079 
1080 		EVENT_SoldierGotHit(tgt, 1, bDamage, 10, tgt->bDirection, 320, NULL, FIRE_WEAPON_NO_SPECIAL, tgt->bAimShotLocation, NOWHERE);
1081 	}
1082 	return( GAME_SCREEN );
1083 }
1084 
ChangeInterfaceLevel(INT16 sLevel)1085 void ChangeInterfaceLevel( INT16 sLevel )
1086 {
1087 	// Only if different!
1088 	if ( sLevel == gsInterfaceLevel )
1089 	{
1090 		return;
1091 	}
1092 
1093 	gsInterfaceLevel = sLevel;
1094 
1095 	if ( gsInterfaceLevel == 1 )
1096 	{
1097 		gsRenderHeight += ROOF_LEVEL_HEIGHT;
1098 		gTacticalStatus.uiFlags |= SHOW_ALL_ROOFS;
1099 		InvalidateWorldRedundency( );
1100 	}
1101 	else if ( gsInterfaceLevel == 0 )
1102 	{
1103 		gsRenderHeight -= ROOF_LEVEL_HEIGHT;
1104 		gTacticalStatus.uiFlags &= (~SHOW_ALL_ROOFS );
1105 		InvalidateWorldRedundency( );
1106 	}
1107 
1108 	SetRenderFlags(RENDER_FLAG_FULL);
1109 	// Remove any interactive tiles we could be over!
1110 	BeginCurInteractiveTileCheck();
1111 	gfPlotNewMovement = TRUE;
1112 	ErasePath();
1113 }
1114 
1115 
UIHandleChangeLevel(UI_EVENT * pUIEvent)1116 ScreenID UIHandleChangeLevel(UI_EVENT* pUIEvent)
1117 {
1118 	if ( gsInterfaceLevel == 0 )
1119 	{
1120 		ChangeInterfaceLevel( 1 );
1121 	}
1122 	else if ( gsInterfaceLevel == 1 )
1123 	{
1124 		ChangeInterfaceLevel( 0 );
1125 	}
1126 
1127 	return( GAME_SCREEN );
1128 }
1129 
1130 
UIHandleSelectMerc(UI_EVENT * pUIEvent)1131 static ScreenID UIHandleSelectMerc(UI_EVENT* pUIEvent)
1132 {
1133 	INT32	iCurrentSquad;
1134 
1135 	// Get merc index at mouse and set current selection
1136 	if (gUIFullTarget != NULL)
1137 	{
1138 		iCurrentSquad = CurrentSquad( );
1139 
1140 		SelectSoldier(gUIFullTarget, SELSOLDIER_ACKNOWLEDGE | SELSOLDIER_FROM_UI);
1141 
1142 		// If different, display message
1143 		if ( CurrentSquad( ) != iCurrentSquad )
1144 		{
1145 			ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, st_format_printf(pMessageStrings[ MSG_SQUAD_ACTIVE ], ( CurrentSquad( ) + 1 )) );
1146 		}
1147 	}
1148 
1149 	return( GAME_SCREEN );
1150 }
1151 
1152 
1153 static void SetMovementModeCursor(const SOLDIERTYPE* pSoldier);
1154 static bool UIHandleInteractiveTilesAndItemsOnTerrain(SOLDIERTYPE* pSoldier, INT16 usMapPos, BOOLEAN fUseOKCursor, BOOLEAN fItemsOnlyIfOnIntTiles);
1155 
1156 
UIHandleMOnTerrain(UI_EVENT * pUIEvent)1157 static ScreenID UIHandleMOnTerrain(UI_EVENT* pUIEvent)
1158 {
1159 	BOOLEAN						fSetCursor = FALSE;
1160 	EXITGRID					ExitGrid;
1161 
1162 	static INT16			sGridNoForItemsOver;
1163 	static INT8				bLevelForItemsOver;
1164 	static UINT32			uiItemsOverTimer;
1165 	static BOOLEAN		fOverItems;
1166 
1167 	const GridNo usMapPos = GetMouseMapPos();
1168 	if (usMapPos == NOWHERE) return GAME_SCREEN;
1169 
1170 	gUIActionModeChangeDueToMouseOver = FALSE;
1171 
1172 	// If we are a vehicle..... just show an X
1173 	SOLDIERTYPE* const sel = GetSelectedMan();
1174 	if (sel != NULL)
1175 	{
1176 		if (OK_ENTERABLE_VEHICLE(sel))
1177 		{
1178 			if ( !UIHandleOnMerc( TRUE ) )
1179 			{
1180 				guiNewUICursor = FLOATING_X_UICURSOR;
1181 				return( GAME_SCREEN );
1182 			}
1183 		}
1184 	}
1185 
1186 	// CHECK IF WE'RE ON A GUY ( EITHER SELECTED, OURS, OR THEIRS
1187 	if ( !UIHandleOnMerc( TRUE ) )
1188 	{
1189 		// Are we over items...
1190 		const ITEM_POOL* pItemPool = GetItemPool(usMapPos, (UINT8)gsInterfaceLevel);
1191 		if (pItemPool != NULL && IsItemPoolVisible(pItemPool))
1192 		{
1193 			// Are we already in...
1194 			if ( fOverItems )
1195 			{
1196 				// Is this the same level & gridno...
1197 				if ( gsInterfaceLevel == (INT16)bLevelForItemsOver && usMapPos == sGridNoForItemsOver )
1198 				{
1199 					// Check timer...
1200 					if ( ( GetJA2Clock( ) - uiItemsOverTimer ) > 1500 )
1201 					{
1202 						// Change to hand curso mode
1203 						guiPendingOverrideEvent = M_CHANGE_TO_HANDMODE;
1204 						gsOverItemsGridNo = usMapPos;
1205 						gsOverItemsLevel = gsInterfaceLevel;
1206 						fOverItems = FALSE;
1207 					}
1208 				}
1209 				else
1210 				{
1211 					uiItemsOverTimer = GetJA2Clock( );
1212 					bLevelForItemsOver = (INT8)gsInterfaceLevel;
1213 					sGridNoForItemsOver = usMapPos;
1214 				}
1215 			}
1216 			else
1217 			{
1218 				fOverItems = TRUE;
1219 
1220 				uiItemsOverTimer = GetJA2Clock( );
1221 				bLevelForItemsOver = (INT8)gsInterfaceLevel;
1222 				sGridNoForItemsOver = usMapPos;
1223 			}
1224 		}
1225 		else
1226 		{
1227 			fOverItems = FALSE;
1228 		}
1229 
1230 		if (sel != NULL)
1231 		{
1232 			if (GetExitGrid(usMapPos, &ExitGrid) && sel->bLevel == 0)
1233 			{
1234 				gfUIShowExitExitGrid = TRUE;
1235 			}
1236 
1237 			// ATE: Draw invalidc cursor if heights different
1238 			if (gpWorldLevelData[usMapPos].sHeight != gpWorldLevelData[sel->sGridNo].sHeight)
1239 			{
1240 				// ERASE PATH
1241 				ErasePath();
1242 
1243 				guiNewUICursor = FLOATING_X_UICURSOR;
1244 
1245 				return( GAME_SCREEN );
1246 			}
1247 		}
1248 
1249 		// DO SOME CURSOR POSITION FLAGS SETTING
1250 		MouseMoveState const uiCursorFlags = GetCursorMovementFlags();
1251 
1252 		if (sel != NULL)
1253 		{
1254 			// Get interactvie tile node
1255 			const LEVELNODE* const pIntNode = GetCurInteractiveTile();
1256 
1257 			// Check were we are
1258 			// CHECK IF WE CAN MOVE HERE
1259 			// THIS IS JUST A CRUDE TEST FOR NOW
1260 			if (sel->bLife < OKLIFE)
1261 			{
1262 				// Show reg. cursor
1263 				// GO INTO IDLE MODE
1264 				// guiPendingOverrideEvent = I_CHANGE_TO_IDLE;
1265 
1266 				SelectSoldier(FindNextActiveAndAliveMerc(sel, FALSE, FALSE), SELSOLDIER_NONE);
1267 			}
1268 			else if (UIOKMoveDestination(sel, usMapPos) != 1 && pIntNode == NULL)
1269 			{
1270 				// ERASE PATH
1271 				ErasePath();
1272 
1273 				guiNewUICursor = CANNOT_MOVE_UICURSOR;
1274 
1275 			}
1276 			else
1277 			{
1278 				if (!UIHandleInteractiveTilesAndItemsOnTerrain(sel, usMapPos, FALSE, TRUE))
1279 				{
1280 					// Are we in combat?
1281 					if (gTacticalStatus.uiFlags & INCOMBAT)
1282 					{
1283 						// If so, draw path, etc
1284 						fSetCursor = HandleUIMovementCursor(sel, uiCursorFlags, usMapPos, MOVEUI_TARGET_NONE);
1285 					}
1286 					else
1287 					{
1288 						// Donot draw path until confirm
1289 						fSetCursor = TRUE;
1290 
1291 						// If so, draw path, etc
1292 						fSetCursor =  HandleUIMovementCursor(sel, uiCursorFlags, usMapPos, MOVEUI_TARGET_NONE);
1293 
1294 						//ErasePath();
1295 					}
1296 
1297 				}
1298 				else
1299 				{
1300 					fSetCursor = TRUE;
1301 				}
1302 			}
1303 		}
1304 		else
1305 		{
1306 			// IF GUSSELECTEDSOLDIER != NOSOLDIER
1307 			guiNewUICursor = NORMAL_SNAPUICURSOR;
1308 		}
1309 	}
1310 	else
1311 	{
1312 		if( ValidQuickExchangePosition( ) )
1313 		{
1314 			// Do new cursor!
1315 			guiNewUICursor = EXCHANGE_PLACES_UICURSOR;
1316 		}
1317 	}
1318 
1319 	//if (fSetCursor && guiNewUICursor != ENTER_VEHICLE_UICURSOR)
1320 	if (fSetCursor && !gfBeginVehicleCursor)
1321 	{
1322 		SetMovementModeCursor(sel);
1323 	}
1324 
1325 	return( GAME_SCREEN );
1326 }
1327 
1328 
UIHandleMovementMenu(UI_EVENT * pUIEvent)1329 static ScreenID UIHandleMovementMenu(UI_EVENT* pUIEvent)
1330 {
1331 	SOLDIERTYPE* const sel = GetSelectedMan();
1332 	if (sel == NULL) return GAME_SCREEN;
1333 
1334 	// Popup Menu
1335 	if ( pUIEvent->fFirstTime )
1336 	{
1337 		//Pop-up menu
1338 		PopupMovementMenu( pUIEvent );
1339 
1340 		// Change cusror to normal
1341 		guiNewUICursor = NORMAL_FREEUICURSOR;
1342 
1343 	}
1344 
1345 	// Check for done flag
1346 	if ( pUIEvent->fDoneMenu )
1347 	{
1348 			PopDownMovementMenu( );
1349 
1350 			// Excecute command, if user hit a button
1351 			if ( pUIEvent->uiParams[1] == TRUE )
1352 			{
1353 				if ( pUIEvent->uiParams[ 2 ] == MOVEMENT_MENU_LOOK )
1354 				{
1355 					guiPendingOverrideEvent = LC_CHANGE_TO_LOOK;
1356 				}
1357 				else if ( pUIEvent->uiParams[ 2 ] == MOVEMENT_MENU_HAND )
1358 				{
1359 					guiPendingOverrideEvent = HC_ON_TERRAIN;
1360 				}
1361 				else if ( pUIEvent->uiParams[ 2 ] == MOVEMENT_MENU_ACTIONC )
1362 				{
1363 					guiPendingOverrideEvent = M_CHANGE_TO_ACTION;
1364 				}
1365 				else if ( pUIEvent->uiParams[ 2 ] == MOVEMENT_MENU_TALK )
1366 				{
1367 					guiPendingOverrideEvent = T_CHANGE_TO_TALKING;
1368 				}
1369 				else
1370 				{
1371 					// Change stance based on params!
1372 					switch( pUIEvent->uiParams[ 0 ] )
1373 					{
1374 						case MOVEMENT_MENU_RUN:
1375 
1376 							if (sel->usUIMovementMode != WALKING && sel->usUIMovementMode != RUNNING)
1377 							{
1378 								UIHandleSoldierStanceChange(sel, ANIM_STAND);
1379 								sel->fUIMovementFast = 1;
1380 							}
1381 							else
1382 							{
1383 								sel->fUIMovementFast = 1;
1384 								sel->usUIMovementMode = RUNNING;
1385 								gfPlotNewMovement = TRUE;
1386 							}
1387 							break;
1388 
1389 						case MOVEMENT_MENU_WALK:  UIHandleSoldierStanceChange(sel, ANIM_STAND);  break;
1390 						case MOVEMENT_MENU_SWAT:  UIHandleSoldierStanceChange(sel, ANIM_CROUCH); break;
1391 						case MOVEMENT_MENU_PRONE: UIHandleSoldierStanceChange(sel, ANIM_PRONE);  break;
1392 					}
1393 
1394 					guiPendingOverrideEvent = A_CHANGE_TO_MOVE;
1395 				}
1396 			}
1397 	}
1398 
1399 	return( GAME_SCREEN );
1400 }
1401 
1402 
UIHandlePositionMenu(UI_EVENT * pUIEvent)1403 static ScreenID UIHandlePositionMenu(UI_EVENT* pUIEvent)
1404 {
1405 
1406 	return( GAME_SCREEN );
1407 }
1408 
1409 
UIHandleAOnTerrain(UI_EVENT * pUIEvent)1410 static ScreenID UIHandleAOnTerrain(UI_EVENT* pUIEvent)
1411 {
1412 	const GridNo usMapPos = GetMouseMapPos();
1413 	if (usMapPos == NOWHERE) return GAME_SCREEN;
1414 
1415 	if ( gpItemPointer != NULL )
1416 	{
1417 		return( GAME_SCREEN );
1418 	}
1419 
1420 	// Get soldier to determine range
1421 	SOLDIERTYPE* const sel = GetSelectedMan();
1422 	if (sel == NULL) return GAME_SCREEN;
1423 
1424 	SoldierSP selSoldier = GetSoldier(sel);
1425 
1426 	// ATE: Add stuff here to display a system message if we are targeting smeothing and
1427 	//  are out of range.
1428 	// Are we using a gun?
1429 	if (GetActionModeCursor(sel) == TARGETCURS)
1430 	{
1431 		SetActionModeDoorCursorText();
1432 
1433 		// Yep, she's a gun.
1434 		// Are we in range?
1435 		if (!InRange(sel, usMapPos))
1436 		{
1437 			// Are we over a guy?
1438 			const SOLDIERTYPE* const tgt = gUIFullTarget;
1439 			if (tgt != NULL)
1440 			{
1441 				// No, ok display message IF this is the first time at this gridno
1442 				if (gsOutOfRangeGridNo != tgt->sGridNo || gubOutOfRangeMerc != SOLDIER2ID(sel))
1443 				{
1444 					// Display
1445 					ScreenMsg(FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, TacticalStr[OUT_OF_RANGE_STRING]);
1446 
1447 					//PlayJA2Sample(TARGET_OUT_OF_RANGE, MIDVOLUME, 1, MIDDLEPAN);
1448 
1449 					// Set
1450 					gsOutOfRangeGridNo = tgt->sGridNo;
1451 					gubOutOfRangeMerc  = SOLDIER2ID(sel);
1452 				}
1453 			}
1454 		}
1455 	}
1456 
1457 	guiNewUICursor = GetProperItemCursor(sel, usMapPos, FALSE);
1458 
1459 	// Show UI ON GUY
1460 	UIHandleOnMerc( FALSE );
1461 
1462 	// If we are in realtime, and in a stationary animation, follow!
1463 	if (!(gTacticalStatus.uiFlags & INCOMBAT))
1464 	{
1465 		if (gAnimControl[sel->usAnimState].uiFlags & ANIM_STATIONARY && !selSoldier->hasPendingAction())
1466 		{
1467 			// Check if we have a shot waiting!
1468 			if (gUITargetShotWaiting) guiPendingOverrideEvent = CA_MERC_SHOOT;
1469 			gUITargetReady = TRUE;
1470 		}
1471 		else
1472 		{
1473 			gUITargetReady = FALSE;
1474 		}
1475 	}
1476 
1477 	return( GAME_SCREEN );
1478 }
1479 
1480 
UIHandleMChangeToAction(UI_EVENT * pUIEvent)1481 static ScreenID UIHandleMChangeToAction(UI_EVENT* pUIEvent)
1482 {
1483 	gUITargetShotWaiting = FALSE;
1484 
1485 	EndPhysicsTrajectoryUI( );
1486 
1487 	//guiNewUICursor = CONFIRM_MOVE_UICURSOR;
1488 
1489 	return( GAME_SCREEN );
1490 }
1491 
1492 
UIHandleMChangeToHandMode(UI_EVENT * pUIEvent)1493 static ScreenID UIHandleMChangeToHandMode(UI_EVENT* pUIEvent)
1494 {
1495 	ErasePath();
1496 
1497 	return( GAME_SCREEN );
1498 }
1499 
1500 
UIHandleAChangeToMove(UI_EVENT * pUIEvent)1501 static ScreenID UIHandleAChangeToMove(UI_EVENT* pUIEvent)
1502 {
1503 	// gsOutOfRangeGridNo = NOWHERE;
1504 
1505 	gfPlotNewMovement = TRUE;
1506 
1507 	return( GAME_SCREEN );
1508 }
1509 
1510 
1511 static void SetConfirmMovementModeCursor(SOLDIERTYPE* pSoldier, BOOLEAN fFromMove);
1512 
1513 
UIHandleCWait(UI_EVENT *)1514 static ScreenID UIHandleCWait(UI_EVENT*)
1515 {
1516 	GridNo const map_pos = GetMouseMapPos();
1517 	if (map_pos == NOWHERE) return GAME_SCREEN;
1518 
1519 	SOLDIERTYPE* const sel = GetSelectedMan();
1520 	if (!sel) return GAME_SCREEN;
1521 
1522 	LEVELNODE const* const int_tile = GetCurInteractiveTile();
1523 
1524 	if (int_tile && gpInvTileThatCausedMoveConfirm != int_tile)
1525 	{ // Get out og this mode
1526 		guiPendingOverrideEvent = A_CHANGE_TO_MOVE;
1527 		return GAME_SCREEN;
1528 	}
1529 
1530 	MouseMoveState const cursor_state = GetCursorMovementFlags();
1531 
1532 	if (int_tile)
1533 	{
1534 		HandleUIMovementCursor(sel, cursor_state, map_pos, MOVEUI_TARGET_INTTILES);
1535 
1536 		guiNewUICursor = GetInteractiveTileCursor(guiNewUICursor, TRUE);
1537 
1538 		// Make red tile under spot, if we've previously found one
1539 		if (gfUIHandleShowMoveGrid) gfUIHandleShowMoveGrid = 2;
1540 
1541 		return GAME_SCREEN;
1542 	}
1543 
1544 	gfUIDisplayActionPoints = TRUE;
1545 
1546 	if (!EnoughPoints(sel, gsCurrentActionPoints, 0, FALSE))
1547 	{
1548 		gfUIDisplayActionPointsInvalid = TRUE;
1549 	}
1550 
1551 	SetConfirmMovementModeCursor(sel, FALSE);
1552 
1553 	// If we are not in combat, draw path here!
1554 	if (!(gTacticalStatus.uiFlags & INCOMBAT))
1555 	{
1556 		HandleUIMovementCursor(sel, cursor_state, map_pos, MOVEUI_TARGET_NONE);
1557 	}
1558 
1559 	return GAME_SCREEN;
1560 }
1561 
1562 
1563 static BOOLEAN HandleMultiSelectionMove(INT16 sDestGridNo);
1564 
1565 
1566 // NOTE, ONCE AT THIS FUNCTION, WE HAVE ASSUMED TO HAVE CHECKED FOR ENOUGH APS THROUGH
1567 // SelectedMercCanAffordMove
UIHandleCMoveMerc(UI_EVENT * pUIEvent)1568 static ScreenID UIHandleCMoveMerc(UI_EVENT* pUIEvent)
1569 {
1570 	INT16 sDestGridNo;
1571 	INT16 sActionGridNo;
1572 	STRUCTURE *pStructure;
1573 	UINT8 ubDirection;
1574 	BOOLEAN fAllMove;
1575 	LEVELNODE *pIntTile;
1576 	INT16 sIntTileGridNo;
1577 	BOOLEAN fOldFastMove;
1578 
1579 	SOLDIERTYPE* const sel = GetSelectedMan();
1580 	if (sel != NULL)
1581 	{
1582 		SoldierSP selSoldier = GetSoldier(sel);
1583 
1584 		fAllMove = gfUIAllMoveOn;
1585 		gfUIAllMoveOn = FALSE;
1586 
1587 		const GridNo usMapPos = GetMouseMapPos();
1588 		if (usMapPos == NOWHERE) return GAME_SCREEN;
1589 
1590 		// ERASE PATH
1591 		ErasePath();
1592 
1593 		if ( fAllMove )
1594 		{
1595 			gfGetNewPathThroughPeople = TRUE;
1596 
1597 			// Loop through all mercs and make go!
1598 			// TODO: Only our squad!
1599 			FOR_EACH_IN_TEAM(pSoldier, OUR_TEAM)
1600 			{
1601 				SoldierSP soldier = GetSoldier(pSoldier);
1602 
1603 				if (OkControllableMerc(pSoldier) && pSoldier->bAssignment == CurrentSquad() && !pSoldier->fMercAsleep)
1604 				{
1605 					// If we can't be controlled, returninvalid...
1606 					if ( pSoldier->uiStatusFlags & SOLDIER_ROBOT )
1607 					{
1608 						if ( !CanRobotBeControlled( pSoldier ) )
1609 						{
1610 							continue;
1611 						}
1612 					}
1613 
1614 					AdjustNoAPToFinishMove( pSoldier, FALSE );
1615 
1616 					fOldFastMove = pSoldier->fUIMovementFast;
1617 
1618 					if ( fAllMove == 2 )
1619 					{
1620 						pSoldier->fUIMovementFast = TRUE;
1621 						pSoldier->usUIMovementMode = RUNNING;
1622 					}
1623 					else
1624 					{
1625 						pSoldier->fUIMovementFast = FALSE;
1626 						pSoldier->usUIMovementMode =  GetMoveStateBasedOnStance( pSoldier, gAnimControl[ pSoldier->usAnimState ].ubEndHeight );
1627 					}
1628 
1629 					soldier->removePendingAction();
1630 
1631 					//if ( !( gTacticalStatus.uiFlags & INCOMBAT ) && ( gAnimControl[ pSoldier->usAnimState ].uiFlags & ANIM_MOVING ) )
1632 					//{
1633 					//	pSoldier->sRTPendingMovementGridNo = usMapPos;
1634 					//	pSoldier->usRTPendingMovementAnim  = pSoldier->usUIMovementMode;
1635 					//}
1636 					//else
1637 					if ( EVENT_InternalGetNewSoldierPath( pSoldier, usMapPos, pSoldier->usUIMovementMode, TRUE, FALSE ) )
1638 					{
1639 						InternalDoMercBattleSound( pSoldier, BATTLE_SOUND_OK1, BATTLE_SND_LOWER_VOLUME );
1640 					}
1641 					else
1642 					{
1643 						ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, st_format_printf(TacticalStr[ NO_PATH_FOR_MERC ], pSoldier->name) );
1644 					}
1645 
1646 					pSoldier->fUIMovementFast = fOldFastMove;
1647 
1648 				}
1649 			}
1650 			gfGetNewPathThroughPeople = FALSE;
1651 
1652 			// RESET MOVE FAST FLAG
1653 			SetConfirmMovementModeCursor(sel, TRUE);
1654 
1655 			gfUIAllMoveOn = 0;
1656 
1657 		}
1658 		else
1659 		{
1660 			// FOR REALTIME - DO MOVEMENT BASED ON STANCE!
1661 			if (!(gTacticalStatus.uiFlags & INCOMBAT))
1662 			{
1663 				sel->usUIMovementMode = GetMoveStateBasedOnStance(sel, gAnimControl[sel->usAnimState].ubEndHeight);
1664 			}
1665 
1666 			sDestGridNo = usMapPos;
1667 
1668 			// Get structure info for in tile!
1669 			pIntTile = GetCurInteractiveTileGridNoAndStructure(&sIntTileGridNo, &pStructure);
1670 
1671 			// We should not have null here if we are given this flag...
1672 			if (pIntTile != NULL)
1673 			{
1674 				sActionGridNo = FindAdjacentGridEx(sel, sIntTileGridNo, &ubDirection, NULL, FALSE, TRUE);
1675 				if (sActionGridNo != -1)
1676 				{
1677 					SetUIBusy(sel);
1678 
1679 					// Set dest gridno
1680 					sDestGridNo = sActionGridNo;
1681 
1682 					// check if we are at this location
1683 					if (sel->sGridNo == sDestGridNo)
1684 					{
1685 						StartInteractiveObject(sIntTileGridNo, *pStructure, *sel, ubDirection);
1686 						InteractWithOpenableStruct(*sel, *pStructure, ubDirection);
1687 						return GAME_SCREEN;
1688 					}
1689 				}
1690 				else
1691 				{
1692 					ScreenMsg(FONT_MCOLOR_LTYELLOW, MSG_UI_FEEDBACK, TacticalStr[NO_PATH]);
1693 					return GAME_SCREEN;
1694 				}
1695 			}
1696 
1697 			SetUIBusy(sel);
1698 
1699 			if (!(gTacticalStatus.uiFlags & INCOMBAT))
1700 			{
1701 				// RESET MOVE FAST FLAG
1702 				SetConfirmMovementModeCursor(sel, TRUE);
1703 
1704 				if (!gTacticalStatus.fAtLeastOneGuyOnMultiSelect)
1705 				{
1706 					sel->fUIMovementFast = FALSE;
1707 				}
1708 			}
1709 
1710 			if (gTacticalStatus.fAtLeastOneGuyOnMultiSelect && pIntTile == NULL)
1711 			{
1712 				HandleMultiSelectionMove(sDestGridNo);
1713 			}
1714 			else
1715 			{
1716 				sel->bReverse = gUIUseReverse;
1717 
1718 				selSoldier->removePendingAction();
1719 
1720 				EVENT_InternalGetNewSoldierPath(sel, sDestGridNo, sel->usUIMovementMode, TRUE, sel->fNoAPToFinishMove);
1721 
1722 				if (sel->ubPathDataSize > 5)
1723 				{
1724 					DoMercBattleSound(sel, BATTLE_SOUND_OK1);
1725 				}
1726 
1727 				// HANDLE ANY INTERACTIVE OBJECTS HERE!
1728 				if (pIntTile != NULL)
1729 				{
1730 					StartInteractiveObject(sIntTileGridNo, *pStructure, *sel, ubDirection);
1731 				}
1732 			}
1733 		}
1734 	}
1735 	return( GAME_SCREEN );
1736 }
1737 
1738 
UIHandleMCycleMoveAll(UI_EVENT * pUIEvent)1739 static ScreenID UIHandleMCycleMoveAll(UI_EVENT* pUIEvent)
1740 {
1741 	if (GetSelectedMan() == NULL)
1742 		return GAME_SCREEN;
1743 
1744 	if ( gfUICanBeginAllMoveCycle )
1745 	{
1746 		gfUIAllMoveOn = TRUE;
1747 		gfUICanBeginAllMoveCycle = FALSE;
1748 	}
1749 	return( GAME_SCREEN );
1750 }
1751 
1752 
UIHandleMCycleMovement(UI_EVENT * pUIEvent)1753 static ScreenID UIHandleMCycleMovement(UI_EVENT* pUIEvent)
1754 {
1755 	SOLDIERTYPE* const sel = GetSelectedMan();
1756 	if (sel == NULL) return GAME_SCREEN;
1757 
1758 	gfUIAllMoveOn = FALSE;
1759 
1760 	if (sel->ubBodyType == ROBOTNOWEAPON)
1761 	{
1762 		sel->usUIMovementMode = WALKING;
1763 		gfPlotNewMovement = TRUE;
1764 		return GAME_SCREEN;
1765 	}
1766 
1767 	for (;;)
1768 	{
1769 		// Cycle gmovement state
1770 		switch (sel->usUIMovementMode)
1771 		{
1772 			INT16 move_mode;
1773 
1774 			case RUNNING:
1775 				move_mode = WALKING;
1776 				goto test_mode;
1777 			case WALKING:
1778 				move_mode = SWATTING;
1779 				goto test_mode;
1780 			case SWATTING:
1781 				move_mode = CRAWLING;
1782 				goto test_mode;
1783 
1784 			case CRAWLING:
1785 				sel->fUIMovementFast = 1;
1786 				move_mode            = RUNNING;
1787 				goto test_mode;
1788 
1789 test_mode:
1790 				sel->usUIMovementMode = move_mode;
1791 				if (IsValidMovementMode(sel, move_mode))
1792 				{
1793 					gfPlotNewMovement = TRUE;
1794 					return GAME_SCREEN;
1795 				}
1796 		}
1797 	}
1798 }
1799 
1800 
UIHandleCOnTerrain(UI_EVENT * pUIEvent)1801 static ScreenID UIHandleCOnTerrain(UI_EVENT* pUIEvent)
1802 {
1803 
1804 	return( GAME_SCREEN );
1805 }
1806 
1807 
UIHandleMAdjustStanceMode(UI_EVENT * pUIEvent)1808 static ScreenID UIHandleMAdjustStanceMode(UI_EVENT* pUIEvent)
1809 {
1810 	INT32 iPosDiff;
1811 	static UINT16 gusAnchorMouseY;
1812 	static UINT16 usOldMouseY;
1813 	static BOOLEAN ubNearHeigherLevel;
1814 	static BOOLEAN ubNearLowerLevel;
1815 	static UINT8 ubUpHeight, ubDownDepth;
1816 	static UINT32 uiOldShowUPDownArrows;
1817 
1818 	// Change cusror to normal
1819 	guiNewUICursor = NO_UICURSOR;
1820 
1821 
1822 	if ( pUIEvent->fFirstTime )
1823 	{
1824 		gusAnchorMouseY = gusMouseYPos;
1825 		usOldMouseY = gusMouseYPos;
1826 		ubNearHeigherLevel = FALSE;
1827 		ubNearLowerLevel = FALSE;
1828 
1829 		guiShowUPDownArrows = ARROWS_SHOW_DOWN_BESIDE | ARROWS_SHOW_UP_BESIDE;
1830 		uiOldShowUPDownArrows = guiShowUPDownArrows;
1831 
1832 		gbAdjustStanceDiff = 0;
1833 		gbClimbID = 0;
1834 
1835 		gfIgnoreScrolling = TRUE;
1836 
1837 		// Get soldier current height of animation
1838 		const SOLDIERTYPE* const sel = GetSelectedMan();
1839 		if (sel != NULL)
1840 		{
1841 			if (FindHigherLevel(sel)) ubNearHeigherLevel = TRUE;
1842 			if (FindLowerLevel(sel))  ubNearLowerLevel   = TRUE;
1843 
1844 			switch (gAnimControl[sel->usAnimState].ubEndHeight)
1845 			{
1846 				case ANIM_STAND:
1847 					if ( ubNearHeigherLevel )
1848 					{
1849 						ubUpHeight	= 1;
1850 						ubDownDepth = 2;
1851 					}
1852 					else if ( ubNearLowerLevel )
1853 					{
1854 						ubUpHeight	= 0;
1855 						ubDownDepth = 3;
1856 					}
1857 					else
1858 					{
1859 						ubUpHeight	= 0;
1860 						ubDownDepth = 2;
1861 					}
1862 					break;
1863 
1864 				case ANIM_CROUCH:
1865 					if ( ubNearHeigherLevel )
1866 					{
1867 						ubUpHeight	= 2;
1868 						ubDownDepth = 1;
1869 					}
1870 					else if ( ubNearLowerLevel )
1871 					{
1872 						ubUpHeight	= 1;
1873 						ubDownDepth = 2;
1874 					}
1875 					else
1876 					{
1877 						ubUpHeight	= 1;
1878 						ubDownDepth = 1;
1879 					}
1880 					break;
1881 
1882 				case ANIM_PRONE:
1883 					if ( ubNearHeigherLevel )
1884 					{
1885 						ubUpHeight	= 3;
1886 						ubDownDepth = 0;
1887 					}
1888 					else if ( ubNearLowerLevel )
1889 					{
1890 						ubUpHeight	= 2;
1891 						ubDownDepth = 1;
1892 					}
1893 					else
1894 					{
1895 						ubUpHeight	= 2;
1896 						ubDownDepth = 0;
1897 					}
1898 					break;
1899 			}
1900 
1901 
1902 		}
1903 
1904 	}
1905 
1906 	// Check if delta X has changed alot since last time
1907 	iPosDiff = ABS( (INT32)( usOldMouseY - gusMouseYPos) );
1908 
1909 	//guiShowUPDownArrows = ARROWS_SHOW_DOWN_BESIDE | ARROWS_SHOW_UP_BESIDE;
1910 	guiShowUPDownArrows = uiOldShowUPDownArrows;
1911 
1912 	{
1913 		if ( gusAnchorMouseY > gusMouseYPos )
1914 		{
1915 			if (GetSelectedMan() != NULL)
1916 			{
1917 					if ( iPosDiff < GO_MOVE_ONE && ubUpHeight >= 1 )
1918 					{
1919 						// Change arrows to move down arrow + show
1920 						//guiShowUPDownArrows = ARROWS_SHOW_UP_ABOVE_Y;
1921 						guiShowUPDownArrows = ARROWS_SHOW_DOWN_BESIDE | ARROWS_SHOW_UP_BESIDE;
1922 						gbAdjustStanceDiff = 0;
1923 						gbClimbID = 0;
1924 					}
1925 					else if ( iPosDiff > GO_MOVE_ONE && iPosDiff < GO_MOVE_TWO && ubUpHeight >= 1 )
1926 					{
1927 						//guiShowUPDownArrows = ARROWS_SHOW_UP_ABOVE_G;
1928 						if ( ubUpHeight == 1 && ubNearHeigherLevel )
1929 						{
1930 							guiShowUPDownArrows = ARROWS_SHOW_UP_ABOVE_CLIMB;
1931 							gbClimbID = 1;
1932 						}
1933 						else
1934 						{
1935 							guiShowUPDownArrows = ARROWS_SHOW_UP_ABOVE_Y;
1936 							gbClimbID = 0;
1937 						}
1938 						gbAdjustStanceDiff = 1;
1939 					}
1940 					else if ( iPosDiff >= GO_MOVE_TWO && iPosDiff < GO_MOVE_THREE && ubUpHeight >= 2 )
1941 					{
1942 						if ( ubUpHeight == 2 && ubNearHeigherLevel )
1943 						{
1944 							guiShowUPDownArrows = ARROWS_SHOW_UP_ABOVE_CLIMB;
1945 							gbClimbID = 1;
1946 						}
1947 						else
1948 						{
1949 							guiShowUPDownArrows = ARROWS_SHOW_UP_ABOVE_YY;
1950 							gbClimbID = 0;
1951 						}
1952 						gbAdjustStanceDiff = 2;
1953 					}
1954 					else if ( iPosDiff >= GO_MOVE_THREE && ubUpHeight >= 3 )
1955 					{
1956 						if ( ubUpHeight == 3 && ubNearHeigherLevel )
1957 						{
1958 							guiShowUPDownArrows = ARROWS_SHOW_UP_ABOVE_CLIMB;
1959 							gbClimbID = 1;
1960 						}
1961 					}
1962 			}
1963 
1964 		}
1965 
1966 		if ( gusAnchorMouseY < gusMouseYPos )
1967 		{
1968 			if (GetSelectedMan() != NULL)
1969 			{
1970 					if ( iPosDiff < GO_MOVE_ONE && ubDownDepth >= 1 )
1971 					{
1972 						// Change arrows to move down arrow + show
1973 						//guiShowUPDownArrows = ARROWS_SHOW_DOWN_BELOW_Y;
1974 						guiShowUPDownArrows = ARROWS_SHOW_DOWN_BESIDE | ARROWS_SHOW_UP_BESIDE;
1975 						gbAdjustStanceDiff = 0;
1976 						gbClimbID = 0;
1977 
1978 					}
1979 					else if ( iPosDiff >= GO_MOVE_ONE && iPosDiff < GO_MOVE_TWO && ubDownDepth >= 1 )
1980 					{
1981 //						guiShowUPDownArrows = ARROWS_SHOW_DOWN_BELOW_G;
1982 							if ( ubDownDepth == 1 && ubNearLowerLevel )
1983 							{
1984 								guiShowUPDownArrows = ARROWS_SHOW_DOWN_CLIMB;
1985 								gbClimbID = -1;
1986 							}
1987 							else
1988 							{
1989 								guiShowUPDownArrows = ARROWS_SHOW_DOWN_BELOW_Y;
1990 								gbClimbID = 0;
1991 							}
1992 							gbAdjustStanceDiff = -1;
1993 					}
1994 					else if ( iPosDiff > GO_MOVE_TWO && iPosDiff < GO_MOVE_THREE && ubDownDepth >= 2 )
1995 					{
1996 						//guiShowUPDownArrows = ARROWS_SHOW_DOWN_BELOW_GG;
1997 						if ( ubDownDepth == 2 && ubNearLowerLevel )
1998 						{
1999 							guiShowUPDownArrows = ARROWS_SHOW_DOWN_CLIMB;
2000 							gbClimbID = -1;
2001 						}
2002 						else
2003 						{
2004 							guiShowUPDownArrows = ARROWS_SHOW_DOWN_BELOW_YY;
2005 							gbClimbID = 0;
2006 						}
2007 						gbAdjustStanceDiff = -2;
2008 					}
2009 					else if ( iPosDiff > GO_MOVE_THREE && ubDownDepth >= 3 )
2010 					{
2011 						//guiShowUPDownArrows = ARROWS_SHOW_DOWN_BELOW_GG;
2012 						if ( ubDownDepth == 3 && ubNearLowerLevel )
2013 						{
2014 							guiShowUPDownArrows = ARROWS_SHOW_DOWN_CLIMB;
2015 							gbClimbID = -1;
2016 						}
2017 					}
2018 
2019 			}
2020 
2021 		}
2022 
2023 	}
2024 
2025 	uiOldShowUPDownArrows = guiShowUPDownArrows;
2026 
2027 	return( GAME_SCREEN );
2028 }
2029 
2030 
UIHandleAChangeToConfirmAction(UI_EVENT * pUIEvent)2031 static ScreenID UIHandleAChangeToConfirmAction(UI_EVENT* pUIEvent)
2032 {
2033 	SOLDIERTYPE* const sel = GetSelectedMan();
2034 	if (sel != NULL) HandleLeftClickCursor(sel);
2035 
2036 	ResetBurstLocations( );
2037 
2038 	return( GAME_SCREEN );
2039 }
2040 
2041 
UIHandleCAOnTerrain(UI_EVENT * pUIEvent)2042 static ScreenID UIHandleCAOnTerrain(UI_EVENT* pUIEvent)
2043 {
2044 	const GridNo usMapPos = GetMouseMapPos();
2045 	if (usMapPos == NOWHERE) return GAME_SCREEN;
2046 
2047 	SOLDIERTYPE* const sel = GetSelectedMan();
2048 	if (sel != NULL)
2049 	{
2050 		guiNewUICursor = GetProperItemCursor(sel, usMapPos, TRUE);
2051 		UIHandleOnMerc( FALSE );
2052 	}
2053 
2054 	return( GAME_SCREEN );
2055 }
2056 
2057 
UIHandleMercAttack(SOLDIERTYPE * pSoldier,SOLDIERTYPE * pTargetSoldier,UINT16 usMapPos)2058 static void UIHandleMercAttack(SOLDIERTYPE* pSoldier, SOLDIERTYPE* pTargetSoldier, UINT16 usMapPos)
2059 {
2060 	INT16 sTargetGridNo;
2061 	INT8 bTargetLevel;
2062 	LEVELNODE *pIntNode;
2063 	STRUCTURE *pStructure;
2064 	INT16 sGridNo, sNewGridNo;
2065 
2066 	// get cursor
2067 	ItemCursor const ubItemCursor = GetActionModeCursor(pSoldier);
2068 
2069 	if ( !(gTacticalStatus.uiFlags & INCOMBAT) && pTargetSoldier && GCM->getItem(pSoldier->inv[ HANDPOS ].usItem)->isWeapon() )
2070 	{
2071 		if ( NPCFirstDraw( pSoldier, pTargetSoldier ) )
2072 		{
2073 			// go into turnbased for that person
2074 			CancelAIAction(pTargetSoldier);
2075 			AddToShouldBecomeHostileOrSayQuoteList(pTargetSoldier);
2076 			//MakeCivHostile( pTargetSoldier, 2 );
2077 			//TriggerNPCWithIHateYouQuote( pTargetSoldier->ubProfile );
2078 			return;
2079 		}
2080 	}
2081 
2082 	// Set aim time to one in UI
2083 	pSoldier->bAimTime = (pSoldier->bShownAimTime/2);
2084 
2085 	// ATE: Check if we are targeting an interactive tile, and adjust gridno accordingly...
2086 	pIntNode = GetCurInteractiveTileGridNoAndStructure( &sGridNo, &pStructure );
2087 
2088 	if ( pTargetSoldier != NULL )
2089 	{
2090 		sTargetGridNo = pTargetSoldier->sGridNo;
2091 		bTargetLevel  = pTargetSoldier->bLevel;
2092 	}
2093 	else
2094 	{
2095 		sTargetGridNo = usMapPos;
2096 		bTargetLevel  = (INT8)gsInterfaceLevel;
2097 
2098 		if ( pIntNode != NULL )
2099 		{
2100 			// Change gridno....
2101 			sTargetGridNo = sGridNo;
2102 		}
2103 	}
2104 
2105 	// here, change gridno if we're targeting ourselves....
2106 	if ( pIntNode != NULL  )
2107 	{
2108 		// Are we in the same gridno?
2109 		if ( sGridNo == pSoldier->sGridNo && ubItemCursor != AIDCURS )
2110 		{
2111 			// Get orientation....
2112 			switch( pStructure->ubWallOrientation )
2113 			{
2114 				case OUTSIDE_TOP_LEFT:
2115 				case INSIDE_TOP_LEFT:
2116 
2117 					sNewGridNo = NewGridNo( sGridNo, DirectionInc( SOUTH ) );
2118 					break;
2119 
2120 				case OUTSIDE_TOP_RIGHT:
2121 				case INSIDE_TOP_RIGHT:
2122 
2123 					sNewGridNo = NewGridNo( sGridNo, DirectionInc( EAST ) );
2124 					break;
2125 
2126 				default:
2127 					sNewGridNo = sGridNo;
2128 			}
2129 
2130 			// Set target gridno to this one...
2131 			sTargetGridNo = sNewGridNo;
2132 
2133 			// now set target cube height
2134 			// CJC says to hardcode this value :)
2135 			pSoldier->bTargetCubeLevel = 2;
2136 		}
2137 		else
2138 		{
2139 			// ATE: Refine this a bit - if we have nobody as a target...
2140 			if ( pTargetSoldier == NULL )
2141 			{
2142 				sTargetGridNo = sGridNo;
2143 			}
2144 		}
2145 	}
2146 
2147 
2148 	// Cannot be fire if we are already in a fire animation....
2149 	// this is to stop the shooting trigger/happy duded from contiously pressing fire...
2150 	if ( !(gTacticalStatus.uiFlags & INCOMBAT) )
2151 	{
2152 		if ( gAnimControl[ pSoldier->usAnimState ].uiFlags & ANIM_FIRE )
2153 		{
2154 			return;
2155 		}
2156 	}
2157 
2158 	// If in turn-based mode - return to movement
2159 	if ( ( gTacticalStatus.uiFlags & INCOMBAT ) )
2160 	{
2161 		// Reset some flags for cont move...
2162 		pSoldier->sFinalDestination = pSoldier->sGridNo;
2163 		pSoldier->bGoodContPath = FALSE;
2164 		//guiPendingOverrideEvent = A_CHANGE_TO_MOVE;
2165 	}
2166 
2167 
2168 	ItemHandleResult iHandleReturn;
2169 	if (pSoldier->bWeaponMode == WM_ATTACHED)
2170 	{
2171 		iHandleReturn = HandleItem( pSoldier, sTargetGridNo, bTargetLevel, UNDER_GLAUNCHER, TRUE );
2172 	}
2173 	else
2174 	{
2175 		iHandleReturn = HandleItem( pSoldier, sTargetGridNo, bTargetLevel, pSoldier->inv[ HANDPOS ].usItem, TRUE );
2176 	}
2177 
2178 	if ( iHandleReturn < 0 )
2179 	{
2180 		if ( iHandleReturn == ITEM_HANDLE_RELOADING )
2181 		{
2182 			guiNewUICursor = ACTION_TARGET_RELOADING;
2183 			return;
2184 		}
2185 
2186 		if ( iHandleReturn == ITEM_HANDLE_NOROOM )
2187 		{
2188 			ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_UI_FEEDBACK, pMessageStrings[ MSG_CANT_FIRE_HERE ] );
2189 			return;
2190 		}
2191 	}
2192 
2193 
2194 	if (!(gTacticalStatus.uiFlags & INCOMBAT))
2195 	{
2196 		HandleUICursorRTFeedback( pSoldier );
2197 	}
2198 
2199 	gfUIForceReExamineCursorData = TRUE;
2200 }
2201 
2202 
AttackRequesterCallback(MessageBoxReturnValue const bExitValue)2203 static void AttackRequesterCallback(MessageBoxReturnValue const bExitValue)
2204 {
2205 	if( bExitValue == MSG_BOX_RETURN_YES )
2206 	{
2207 		gTacticalStatus.ubLastRequesterTargetID = gpRequesterTargetMerc->ubProfile;
2208 
2209 		UIHandleMercAttack( gpRequesterMerc , gpRequesterTargetMerc, gsRequesterGridNo );
2210 	}
2211 }
2212 
2213 
UIHandleCAMercShoot(UI_EVENT * pUIEvent)2214 static ScreenID UIHandleCAMercShoot(UI_EVENT* pUIEvent)
2215 {
2216 	SOLDIERTYPE* const sel = GetSelectedMan();
2217 	if (sel == NULL) return GAME_SCREEN;
2218 	// preinit to prevent false ap costs; actions which dont charge turning ap
2219 	// are coming after this line and put the value to true
2220 	sel->fDontChargeTurningAPs = FALSE;
2221 
2222 	const GridNo usMapPos = GetMouseMapPos();
2223 	if (usMapPos == NOWHERE) return GAME_SCREEN;
2224 
2225 	SOLDIERTYPE* const tgt = gUIFullTarget;
2226 	if (tgt != NULL)
2227 	{
2228 		// If this is one of our own guys.....pop up requiester...
2229 		if ((tgt->bTeam == OUR_TEAM || tgt->bTeam == MILITIA_TEAM) &&
2230 			GCM->getItem(sel->inv[HANDPOS].usItem)->getItemClass() != IC_MEDKIT &&
2231 			sel->inv[HANDPOS].usItem != GAS_CAN &&
2232 			gTacticalStatus.ubLastRequesterTargetID != tgt->ubProfile &&
2233 			tgt != sel)
2234 		{
2235 			gpRequesterMerc = sel;
2236 			gpRequesterTargetMerc = tgt;
2237 			gsRequesterGridNo = usMapPos;
2238 
2239 			ST::string zStr = st_format_printf(TacticalStr[ATTACK_OWN_GUY_PROMPT], tgt->name);
2240 			DoMessageBox(MSG_BOX_BASIC_STYLE, zStr, GAME_SCREEN, MSG_BOX_FLAG_YESNO, AttackRequesterCallback, NULL);
2241 			return GAME_SCREEN;
2242 		}
2243 	}
2244 
2245 	UIHandleMercAttack(sel, tgt, usMapPos);
2246 
2247 	return( GAME_SCREEN );
2248 }
2249 
2250 
UIHandleAEndAction(UI_EVENT * pUIEvent)2251 static ScreenID UIHandleAEndAction(UI_EVENT* pUIEvent)
2252 {
2253 	const GridNo usMapPos = GetMouseMapPos();
2254 	if (usMapPos == NOWHERE) return GAME_SCREEN;
2255 
2256 	SOLDIERTYPE* const sel = GetSelectedMan();
2257 	if (sel != NULL)
2258 	{
2259 		if (!(gTacticalStatus.uiFlags & INCOMBAT))
2260 		{
2261 			if ( gUITargetReady )
2262 			{
2263 				// Move to proper stance + direction!
2264 				SoldierReadyWeapon(sel, usMapPos, TRUE); // UNReady weapon
2265 				gUITargetReady = FALSE;
2266 			}
2267 
2268 		}
2269 	}
2270 	return( GAME_SCREEN );
2271 }
2272 
2273 
UIHandleCAEndConfirmAction(UI_EVENT * pUIEvent)2274 static ScreenID UIHandleCAEndConfirmAction(UI_EVENT* pUIEvent)
2275 {
2276 	return GAME_SCREEN;
2277 }
2278 
2279 
UIHandleIOnTerrain(UI_EVENT * pUIEvent)2280 static ScreenID UIHandleIOnTerrain(UI_EVENT* pUIEvent)
2281 {
2282 	const GridNo usMapPos = GetMouseMapPos();
2283 	if (usMapPos == NOWHERE) return GAME_SCREEN;
2284 
2285 	if ( !UIHandleOnMerc( TRUE ) )
2286 	{
2287 		// Check if dest is OK
2288 		//if ( !NewOKDestination( usMapPos, FALSE ) || IsRoofVisible( usMapPos ) )
2289 		////{
2290 		//	guiNewUICursor = CANNOT_MOVE_UICURSOR;
2291 		//}
2292 		//else
2293 		{
2294 			guiNewUICursor = NORMAL_SNAPUICURSOR;
2295 		}
2296 	}
2297 
2298 	return( GAME_SCREEN );
2299 }
2300 
2301 
UIHandleIChangeToIdle(UI_EVENT * pUIEvent)2302 static ScreenID UIHandleIChangeToIdle(UI_EVENT* pUIEvent)
2303 {
2304 	return( GAME_SCREEN );
2305 }
2306 
2307 
2308 static UINT8 GetAdjustedAnimHeight(UINT8 ubAnimHeight, INT8 bChange);
2309 
2310 
UIHandlePADJAdjustStance(UI_EVENT * pUIEvent)2311 static ScreenID UIHandlePADJAdjustStance(UI_EVENT* pUIEvent)
2312 {
2313 	guiShowUPDownArrows = ARROWS_HIDE_UP | ARROWS_HIDE_DOWN;
2314 
2315 	gfIgnoreScrolling = FALSE;
2316 
2317 	SOLDIERTYPE* const sel = GetSelectedMan();
2318 	if (sel == NULL || gbAdjustStanceDiff == 0) return GAME_SCREEN;
2319 
2320 	if (gbClimbID	== 1)
2321 	{
2322 		BeginSoldierClimbUpRoof(sel);
2323 	}
2324 	else if (gbClimbID == -1)
2325 	{
2326 		BeginSoldierClimbDownRoof(sel);
2327 	}
2328 	else
2329 	{
2330 		const UINT8 ubNewStance = GetAdjustedAnimHeight(gAnimControl[sel->usAnimState].ubEndHeight, gbAdjustStanceDiff);
2331 		// Set state to result
2332 		UIHandleSoldierStanceChange(sel, ubNewStance);
2333 	}
2334 
2335 	return( GAME_SCREEN );
2336 }
2337 
2338 
GetAdjustedAnimHeight(UINT8 ubAnimHeight,INT8 bChange)2339 static UINT8 GetAdjustedAnimHeight(UINT8 ubAnimHeight, INT8 bChange)
2340 {
2341 	UINT8 ubNewAnimHeight = ubAnimHeight;
2342 
2343 	if ( ubAnimHeight == ANIM_STAND )
2344 	{
2345 		if ( bChange == -1 )
2346 		{
2347 			ubNewAnimHeight = ANIM_CROUCH;
2348 		}
2349 		if ( bChange == -2 )
2350 		{
2351 			ubNewAnimHeight = ANIM_PRONE;
2352 		}
2353 		if ( bChange == 1 )
2354 		{
2355 			ubNewAnimHeight = 50;
2356 		}
2357 	}
2358 	else if ( ubAnimHeight == ANIM_CROUCH )
2359 	{
2360 		if ( bChange == 1 )
2361 		{
2362 			ubNewAnimHeight = ANIM_STAND;
2363 		}
2364 		if ( bChange == -1 )
2365 		{
2366 			ubNewAnimHeight = ANIM_PRONE;
2367 		}
2368 		if ( bChange == -2 )
2369 		{
2370 			ubNewAnimHeight = 55;
2371 		}
2372 	}
2373 	else if ( ubAnimHeight == ANIM_PRONE )
2374 	{
2375 		if ( bChange == -1 )
2376 		{
2377 			ubNewAnimHeight = 55;
2378 		}
2379 		if ( bChange == 1 )
2380 		{
2381 			ubNewAnimHeight = ANIM_CROUCH;
2382 		}
2383 		if ( bChange == 2 )
2384 		{
2385 			ubNewAnimHeight = ANIM_STAND;
2386 		}
2387 	}
2388 
2389 	return( ubNewAnimHeight );
2390 }
2391 
2392 
SelectedMercCanAffordAttack()2393 BOOLEAN SelectedMercCanAffordAttack( )
2394 {
2395 	SOLDIERTYPE* const sel = GetSelectedMan();
2396 	if (sel == NULL) return FALSE;
2397 
2398 	const GridNo usMapPos = GetMouseMapPos();
2399 	if (usMapPos == NOWHERE) return GAME_SCREEN;
2400 
2401 	// Get cursor value
2402 	ItemCursor const ubItemCursor = GetActionModeCursor(sel);
2403 	switch (ubItemCursor)
2404 	{
2405 		case INVALIDCURS: return FALSE;
2406 		case BOMBCURS:    return EnoughPoints(sel, GetTotalAPsToDropBomb(sel, usMapPos), 0, TRUE);
2407 		case REMOTECURS:  return EnoughPoints(sel, GetAPsToUseRemote(sel), 0, TRUE);
2408 
2409 		default:
2410 		{
2411 			// Look for a soldier at this position
2412 			const SOLDIERTYPE* const tgt           = gUIFullTarget;
2413 			const INT16              sTargetGridNo = (tgt != NULL ? tgt->sGridNo : usMapPos);
2414 			const INT16              sAPCost       = CalcTotalAPsToAttack(sel, sTargetGridNo, TRUE, sel->bShownAimTime / 2);
2415 
2416 			if (EnoughPoints(sel, sAPCost, 0, TRUE)) return TRUE;
2417 
2418 			// Play curse....
2419 			DoMercBattleSound(sel, BATTLE_SOUND_CURSE1);
2420 			return FALSE;
2421 		}
2422 	}
2423 }
2424 
2425 
SelectedMercCanAffordMove()2426 BOOLEAN SelectedMercCanAffordMove(  )
2427 {
2428 	SOLDIERTYPE* const sel = GetSelectedMan();
2429 	if (sel == NULL) return FALSE;
2430 
2431 	const GridNo usMapPos = GetMouseMapPos();
2432 	if (usMapPos == NOWHERE) return GAME_SCREEN;
2433 
2434 	// IF WE ARE OVER AN INTERACTIVE TILE, GIVE GRIDNO OF POSITION
2435 	if (GetCurInteractiveTile() != NULL)
2436 	{
2437 		// CHECK APS
2438 		return EnoughPoints(sel, gsCurrentActionPoints, 0, TRUE);
2439 	}
2440 
2441 	// Take the first direction!
2442 	UINT16 sAPCost = PtsToMoveDirection(sel, guiPathingData[0]);
2443 	sAPCost += GetAPsToChangeStance(sel, gAnimControl[sel->usUIMovementMode].ubHeight);
2444 
2445 	if (EnoughPoints(sel, sAPCost, 0, TRUE)) return TRUE;
2446 
2447 	// OK, remember where we were trying to get to.....
2448 	sel->sContPathLocation = usMapPos;
2449 	sel->bGoodContPath     = TRUE;
2450 
2451 	return( FALSE );
2452 }
2453 
2454 
RemoveTacticalCursor(void)2455 static void RemoveTacticalCursor(void)
2456 {
2457 	guiNewUICursor = NO_UICURSOR;
2458 	ErasePath();
2459 }
2460 
2461 
UIHandleHCOnTerrain(UI_EVENT * pUIEvent)2462 static ScreenID UIHandleHCOnTerrain(UI_EVENT* pUIEvent)
2463 {
2464 	const GridNo usMapPos = GetMouseMapPos();
2465 	if (usMapPos == NOWHERE) return GAME_SCREEN;
2466 
2467 	SOLDIERTYPE* const sel = GetSelectedMan();
2468 	if (sel == NULL) return GAME_SCREEN;
2469 
2470 	// If we are out of breath, no cursor...
2471 	if (sel->bBreath < OKBREATH && sel->bCollapsed)
2472 	{
2473 		guiNewUICursor = INVALID_ACTION_UICURSOR;
2474 	}
2475 	else
2476 	{
2477 		if (gsOverItemsGridNo != NOWHERE && (usMapPos != gsOverItemsGridNo || gsInterfaceLevel != gsOverItemsLevel))
2478 		{
2479 			gsOverItemsGridNo = NOWHERE;
2480 			guiPendingOverrideEvent = A_CHANGE_TO_MOVE;
2481 		}
2482 		else
2483 		{
2484 			guiNewUICursor = NORMALHANDCURSOR_UICURSOR;
2485 			UIHandleInteractiveTilesAndItemsOnTerrain(sel, usMapPos, TRUE, FALSE);
2486 		}
2487 	}
2488 	return( GAME_SCREEN );
2489 }
2490 
2491 
UIHandleHCGettingItem(UI_EVENT * pUIEvent)2492 static ScreenID UIHandleHCGettingItem(UI_EVENT* pUIEvent)
2493 {
2494 	guiNewUICursor = NORMAL_FREEUICURSOR;
2495 
2496 	return( GAME_SCREEN );
2497 }
2498 
2499 
UIHandleTATalkingMenu(UI_EVENT * pUIEvent)2500 static ScreenID UIHandleTATalkingMenu(UI_EVENT* pUIEvent)
2501 {
2502 	guiNewUICursor = NORMAL_FREEUICURSOR;
2503 
2504 	return( GAME_SCREEN );
2505 }
2506 
2507 
UIHandleEXExitSectorMenu(UI_EVENT * pUIEvent)2508 static ScreenID UIHandleEXExitSectorMenu(UI_EVENT* pUIEvent)
2509 {
2510 	guiNewUICursor = NORMAL_FREEUICURSOR;
2511 
2512 	return( GAME_SCREEN );
2513 }
2514 
2515 
UIHandleOpenDoorMenu(UI_EVENT * pUIEvent)2516 static ScreenID UIHandleOpenDoorMenu(UI_EVENT* pUIEvent)
2517 {
2518 	guiNewUICursor = NORMAL_FREEUICURSOR;
2519 
2520 	return( GAME_SCREEN );
2521 }
2522 
2523 
ToggleHandCursorMode(UIEventKind * const puiNewEvent)2524 void ToggleHandCursorMode(UIEventKind* const puiNewEvent)
2525 {
2526 	// Toggle modes
2527 	if ( gCurrentUIMode == HANDCURSOR_MODE )
2528 	{
2529 		*puiNewEvent = A_CHANGE_TO_MOVE;
2530 	}
2531 	else
2532 	{
2533 
2534 		*puiNewEvent = M_CHANGE_TO_HANDMODE;
2535 	}
2536 }
2537 
2538 
ToggleTalkCursorMode(UIEventKind * const puiNewEvent)2539 void ToggleTalkCursorMode(UIEventKind* const puiNewEvent)
2540 {
2541 	// Toggle modes
2542 	if ( gCurrentUIMode == TALKCURSOR_MODE )
2543 	{
2544 		*puiNewEvent = A_CHANGE_TO_MOVE;
2545 	}
2546 	else
2547 	{
2548 		*puiNewEvent = T_CHANGE_TO_TALKING;
2549 	}
2550 }
2551 
2552 
ToggleLookCursorMode()2553 void ToggleLookCursorMode()
2554 {
2555 	guiPendingOverrideEvent = gCurrentUIMode == LOOKCURSOR_MODE ? A_CHANGE_TO_MOVE :
2556 							LC_CHANGE_TO_LOOK;
2557 	HandleTacticalUI();
2558 }
2559 
2560 
UIHandleOnMerc(BOOLEAN fMovementMode)2561 BOOLEAN UIHandleOnMerc( BOOLEAN fMovementMode )
2562 {
2563 	const GridNo usMapPos = GetMouseMapPos();
2564 	if (usMapPos == NOWHERE) return GAME_SCREEN;
2565 
2566 	SoldierFindFlags const uiMercFlags = guiUIFullTargetFlags;
2567 
2568 	// CHECK IF WE'RE ON A GUY ( EITHER SELECTED, OURS, OR THEIRS
2569 	SOLDIERTYPE* const pSoldier = gUIFullTarget;
2570 	if (pSoldier != NULL)
2571 	{
2572 		if ( uiMercFlags & OWNED_MERC )
2573 		{
2574 			// If not unconscious, select
2575 			if ( !( uiMercFlags & UNCONSCIOUS_MERC ) )
2576 			{
2577 				if ( fMovementMode )
2578 				{
2579 					// ERASE PATH
2580 					ErasePath();
2581 
2582 					// Show cursor with highlight on selected merc
2583 					guiNewUICursor = NO_UICURSOR;
2584 
2585 					// IF selected, do selection one
2586 					if ( ( uiMercFlags & SELECTED_MERC ) )
2587 					{
2588 						// Add highlight to guy in interface.c
2589 						gfUIHandleSelection = SELECTED_GUY_SELECTION;
2590 
2591 						if ( gpItemPointer == NULL )
2592 						{
2593 							// Don't do this unless we want to
2594 
2595 							// Check if buddy is stationary!
2596 							if ( gAnimControl[ pSoldier->usAnimState ].uiFlags & ANIM_STATIONARY || pSoldier->fNoAPToFinishMove )
2597 							{
2598 								guiShowUPDownArrows = ARROWS_SHOW_DOWN_BESIDE |
2599 											ARROWS_SHOW_UP_BESIDE;
2600 							}
2601 						}
2602 
2603 					}
2604 					else
2605 					{
2606 						if ( !( uiMercFlags & NOINTERRUPT_MERC ) )
2607 						{
2608 							// Add highlight to guy in interface.c
2609 							gfUIHandleSelection = NONSELECTED_GUY_SELECTION;
2610 						}
2611 						else
2612 						{
2613 							gfUIHandleSelection = ENEMY_GUY_SELECTION;
2614 						}
2615 					}
2616 				}
2617 			}
2618 
2619 			// If not dead, show above guy!
2620 			if ( !( uiMercFlags & DEAD_MERC ) )
2621 			{
2622 				if ( fMovementMode )
2623 				{
2624 					// ERASE PATH
2625 					ErasePath();
2626 
2627 					// Show cursor with highlight on selected merc
2628 					guiNewUICursor = NO_UICURSOR;
2629 
2630 					gsSelectedGridNo = pSoldier->sGridNo;
2631 					gsSelectedLevel = pSoldier->bLevel;
2632 				}
2633 
2634 				gSelectedGuy = pSoldier;
2635 			}
2636 		}
2637 		else if (((uiMercFlags & ENEMY_MERC) || (uiMercFlags & NEUTRAL_MERC)) &&
2638 			(uiMercFlags & VISIBLE_MERC))
2639 		{
2640 			// ATE: If we are a vehicle, let the mouse cursor be a wheel...
2641 			if ( ( OK_ENTERABLE_VEHICLE( pSoldier ) ) )
2642 			{
2643 				return( FALSE );
2644 			}
2645 			else
2646 			{
2647 				if ( fMovementMode )
2648 				{
2649 
2650 					// Check if this guy is on the enemy team....
2651 					if ( !pSoldier->bNeutral && (pSoldier->bSide != OUR_TEAM ) )
2652 					{
2653 						gUIActionModeChangeDueToMouseOver = TRUE;
2654 
2655 						guiPendingOverrideEvent = M_CHANGE_TO_ACTION;
2656 						// Return FALSE
2657 						return( FALSE );
2658 					}
2659 					else
2660 					{
2661 						// ERASE PATH
2662 						ErasePath();
2663 
2664 						// Show cursor with highlight on selected merc
2665 						guiNewUICursor = NO_UICURSOR;
2666 						// Show cursor with highlight
2667 						gfUIHandleSelection = ENEMY_GUY_SELECTION;
2668 						gsSelectedGridNo = pSoldier->sGridNo;
2669 						gsSelectedLevel = pSoldier->bLevel;
2670 					}
2671 				}
2672 
2673 				gSelectedGuy = pSoldier;
2674 			}
2675 		}
2676 		else
2677 		{
2678 			if ( pSoldier->uiStatusFlags & SOLDIER_VEHICLE )
2679 			{
2680 				return( FALSE );
2681 			}
2682 		}
2683 	}
2684 	else
2685 	{
2686 		gfIgnoreOnSelectedGuy = FALSE;
2687 
2688 		return( FALSE );
2689 	}
2690 
2691 	return( TRUE );
2692 }
2693 
2694 
UIHandleISoldierDebug(UI_EVENT * pUIEvent)2695 static ScreenID UIHandleISoldierDebug(UI_EVENT* pUIEvent)
2696 {
2697 	// Use soldier display pages
2698 	SetDebugRenderHook(DebugSoldierPage1, 0);
2699 	SetDebugRenderHook(DebugSoldierPage2, 1);
2700 	SetDebugRenderHook(DebugSoldierPage3, 2);
2701 	SetDebugRenderHook(DebugSoldierPage4, 3);
2702 	gCurDebugPage = 1;
2703 
2704 	return( DEBUG_SCREEN );
2705 }
2706 
2707 
UIHandleILOSDebug(UI_EVENT * pUIEvent)2708 static ScreenID UIHandleILOSDebug(UI_EVENT* pUIEvent)
2709 {
2710 	SetDebugRenderHook(DebugStructurePage1, 0);
2711 	return( DEBUG_SCREEN );
2712 }
2713 
2714 
UIHandleILevelNodeDebug(UI_EVENT * pUIEvent)2715 static ScreenID UIHandleILevelNodeDebug(UI_EVENT* pUIEvent)
2716 {
2717 	SetDebugRenderHook(DebugLevelNodePage, 0);
2718 	return( DEBUG_SCREEN );
2719 }
2720 
2721 
UIHandleIETOnTerrain(UI_EVENT * pUIEvent)2722 static ScreenID UIHandleIETOnTerrain(UI_EVENT* pUIEvent)
2723 {
2724 	//guiNewUICursor = CANNOT_MOVE_UICURSOR;
2725 	guiNewUICursor = NO_UICURSOR;
2726 
2727 	SetCurrentCursorFromDatabase( VIDEO_NO_CURSOR );
2728 
2729 	return( GAME_SCREEN );
2730 }
2731 
2732 
2733 static void SetUIbasedOnStance(SOLDIERTYPE* pSoldier, INT8 bNewStance);
2734 static BOOLEAN SoldierCanAffordNewStance(SOLDIERTYPE* pSoldier, UINT8 ubDesiredStance);
2735 
2736 
UIHandleSoldierStanceChange(SOLDIERTYPE * s,INT8 bNewStance)2737 void UIHandleSoldierStanceChange(SOLDIERTYPE* s, INT8 bNewStance)
2738 {
2739 	// Is this a valid stance for our position?
2740 	if (!IsValidStance(s, bNewStance))
2741 	{
2742 		if (s->bCollapsed && s->bBreath < OKBREATH)
2743 		{
2744 			ScreenMsg(FONT_MCOLOR_LTYELLOW, MSG_UI_FEEDBACK, st_format_printf(gzLateLocalizedString[STR_LATE_04], s->name));
2745 		}
2746 		else
2747 		{
2748 			if (s->uiStatusFlags & SOLDIER_VEHICLE)
2749 			{
2750 				ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_UI_FEEDBACK, TacticalStr[ VEHICLES_NO_STANCE_CHANGE_STR ] );
2751 			}
2752 			else if (s->uiStatusFlags & SOLDIER_ROBOT)
2753 			{
2754 				ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_UI_FEEDBACK, TacticalStr[ ROBOT_NO_STANCE_CHANGE_STR ] );
2755 			}
2756 			else
2757 			{
2758 				if (s->bCollapsed)
2759 				{
2760 					ScreenMsg(FONT_MCOLOR_LTYELLOW, MSG_UI_FEEDBACK, st_format_printf(pMessageStrings[MSG_CANT_CHANGE_STANCE], s->name));
2761 				}
2762 				else
2763 				{
2764 					ScreenMsg(FONT_MCOLOR_LTYELLOW, MSG_UI_FEEDBACK, st_format_printf(TacticalStr[CANNOT_STANCE_CHANGE_STR], s->name));
2765 				}
2766 			}
2767 		}
2768 		return;
2769 	}
2770 
2771 	// IF turn-based - adjust stance now!
2772 	if (gTacticalStatus.uiFlags & INCOMBAT)
2773 	{
2774 		s->fTurningFromPronePosition = FALSE;
2775 
2776 		// Check if we have enough APS
2777 		if (SoldierCanAffordNewStance(s, bNewStance))
2778 		{
2779 			ChangeSoldierStance(s, bNewStance);
2780 
2781 			s->sFinalDestination = s->sGridNo;
2782 			s->bGoodContPath     = FALSE;
2783 		}
2784 		else
2785 			return;
2786 	}
2787 
2788 	// If realtime- change walking animation!
2789 	if (!(gTacticalStatus.uiFlags & INCOMBAT))
2790 	{
2791 
2792 		// If we are stationary, do something else!
2793 		if (gAnimControl[s->usAnimState].uiFlags & ANIM_STATIONARY)
2794 		{
2795 			// Change stance normally
2796 			ChangeSoldierStance(s, bNewStance);
2797 		}
2798 		else
2799 		{
2800 			// Pick moving animation based on stance
2801 
2802 			// LOCK VARIBLE FOR NO UPDATE INDEX...
2803 			s->usUIMovementMode = GetMoveStateBasedOnStance(s, bNewStance);
2804 
2805 			if (s->usUIMovementMode == CRAWLING && gAnimControl[s->usAnimState].ubEndHeight != ANIM_PRONE)
2806 			{
2807 				s->usDontUpdateNewGridNoOnMoveAnimChange = LOCKED_NO_NEWGRIDNO;
2808 				s->bPathStored = FALSE;
2809 			}
2810 			else
2811 			{
2812 				s->usDontUpdateNewGridNoOnMoveAnimChange = 1;
2813 			}
2814 
2815 			ChangeSoldierState(s, s->usUIMovementMode, 0, FALSE);
2816 		}
2817 	}
2818 
2819 	// Set UI value for soldier
2820 	SetUIbasedOnStance(s, bNewStance);
2821 
2822 	gfUIStanceDifferent = TRUE;
2823 
2824 	// ATE: If we are being serviced...stop...
2825 	// InternalReceivingSoldierCancelServices(s, FALSE);
2826 	InternalGivingSoldierCancelServices(s, FALSE);
2827 	//gfPlotNewMovement   = TRUE;
2828 }
2829 
GetCursorMovementFlags()2830 MouseMoveState GetCursorMovementFlags()
2831 {
2832 	static BOOLEAN fStationary = FALSE;
2833 	static UINT16  usOldMouseXPos = 32000;
2834 	static UINT16  usOldMouseYPos = 32000;
2835 	static UINT16  usOldMapPos = 32000;
2836 
2837 	static MouseMoveState uiSameFrameCursorFlags = MOUSE_STATIONARY;
2838 	static UINT32 uiOldFrameNumber = 99999;
2839 
2840 	// Check if this is the same frame as before, return already calculated value if so!
2841 	if ( uiOldFrameNumber == guiGameCycleCounter )
2842 	{
2843 		return uiSameFrameCursorFlags;
2844 	}
2845 
2846 	const GridNo usMapPos = GetMouseMapPos();
2847 
2848 	MouseMoveState cursor_flags;
2849 	if (gusMouseXPos == usOldMouseXPos && gusMouseYPos == usOldMouseYPos)
2850 	{
2851 		fStationary  = TRUE;
2852 		cursor_flags = MOUSE_STATIONARY;
2853 	}
2854 	else if (fStationary && usOldMapPos == usMapPos) // If cursor was previously stationary, make the additional check of grid pos change
2855 	{
2856 		cursor_flags = MOUSE_MOVING_IN_TILE;
2857 	}
2858 	else
2859 	{
2860 		fStationary  = FALSE;
2861 		cursor_flags = MOUSE_MOVING_NEW_TILE;
2862 	}
2863 
2864 	usOldMapPos = usMapPos;
2865 	usOldMouseXPos = gusMouseXPos;
2866 	usOldMouseYPos = gusMouseYPos;
2867 
2868 	uiOldFrameNumber = guiGameCycleCounter;
2869 	uiSameFrameCursorFlags = cursor_flags;
2870 	return cursor_flags;
2871 }
2872 
2873 
2874 static INT8 DrawUIMovementPath(SOLDIERTYPE* pSoldier, UINT16 usMapPos, MoveUITarget);
2875 
2876 
HandleUIMovementCursor(SOLDIERTYPE * const pSoldier,MouseMoveState const uiCursorFlags,UINT16 const usMapPos,MoveUITarget const uiFlags)2877 BOOLEAN HandleUIMovementCursor(SOLDIERTYPE* const pSoldier, MouseMoveState const uiCursorFlags, UINT16 const usMapPos, MoveUITarget const uiFlags)
2878 {
2879 	static const SOLDIERTYPE* target = NULL;
2880 
2881 	BOOLEAN fSetCursor = FALSE;
2882 	BOOLEAN fTargetFoundAndLookingForOne = FALSE;
2883 
2884 	// Determine if we can afford!
2885 	if ( !EnoughPoints( pSoldier, gsCurrentActionPoints, 0, FALSE ) )
2886 	{
2887 		gfUIDisplayActionPointsInvalid = TRUE;
2888 	}
2889 
2890 	// Check if we're stationary
2891 	if (!(gTacticalStatus.uiFlags & INCOMBAT) ||
2892 		(gAnimControl[pSoldier->usAnimState].uiFlags & ANIM_STATIONARY) ||
2893 		pSoldier->fNoAPToFinishMove)
2894 	{
2895 		// If we are targeting a merc for some reason, don't go thorugh normal channels if we
2896 		// are on someone now
2897 		if ( uiFlags == MOVEUI_TARGET_MERCS || uiFlags == MOVEUI_TARGET_MERCSFORAID )
2898 		{
2899 			if (target != gUIFullTarget || gfResetUIMovementOptimization)
2900 			{
2901 				gfResetUIMovementOptimization = FALSE;
2902 
2903 				// ERASE PATH
2904 				ErasePath();
2905 
2906 				// Try and get a path right away
2907 				DrawUIMovementPath( pSoldier, usMapPos,  uiFlags );
2908 			}
2909 
2910 			// Save for next time...
2911 			target = gUIFullTarget;
2912 
2913 			if (gUIFullTarget != NULL) fTargetFoundAndLookingForOne = TRUE;
2914 		}
2915 
2916 		if ( uiFlags == MOVEUI_TARGET_ITEMS )
2917 		{
2918 			gfUIOverItemPoolGridNo = usMapPos;
2919 		}
2920 		else if ( uiFlags == MOVEUI_TARGET_MERCSFORAID )
2921 		{
2922 			// Set values for AP display...
2923 			gfUIDisplayActionPointsCenter = TRUE;
2924 		}
2925 
2926 		// IF CURSOR IS MOVING
2927 		if (uiCursorFlags != MOUSE_STATIONARY || gfUINewStateForIntTile)
2928 		{
2929 			// SHOW CURSOR
2930 			fSetCursor = TRUE;
2931 
2932 			// IF CURSOR WAS PREVIOUSLY STATIONARY, MAKE THE ADDITIONAL CHECK OF GRID POS CHANGE
2933 			if ((uiCursorFlags == MOUSE_MOVING_NEW_TILE && !fTargetFoundAndLookingForOne) || gfUINewStateForIntTile)
2934 			{
2935 				// ERASE PATH
2936 				ErasePath();
2937 
2938 				// Reset counter
2939 				RESETCOUNTER( PATHFINDCOUNTER );
2940 
2941 				gfPlotNewMovement = TRUE;
2942 
2943 			}
2944 
2945 			if (uiCursorFlags == MOUSE_MOVING_IN_TILE)
2946 			{
2947 				gfUIDisplayActionPoints = TRUE;
2948 			}
2949 
2950 		}
2951 
2952 		if (uiCursorFlags == MOUSE_STATIONARY)
2953 		{
2954 			// CURSOR IS STATIONARY
2955 			if ( _KeyDown( SHIFT ) && !gfPlotNewMovementNOCOST )
2956 			{
2957 				gfPlotNewMovementNOCOST = TRUE;
2958 				gfPlotNewMovement = TRUE;
2959 			}
2960 			if ( !(_KeyDown( SHIFT ) ) && gfPlotNewMovementNOCOST )
2961 			{
2962 				gfPlotNewMovementNOCOST = FALSE;
2963 				gfPlotNewMovement = TRUE;
2964 			}
2965 
2966 
2967 			// ONLY DIPSLAY PATH AFTER A DELAY
2968 			if ( COUNTERDONE( PATHFINDCOUNTER ) )
2969 			{
2970 				// Reset counter
2971 				RESETCOUNTER( PATHFINDCOUNTER );
2972 
2973 				if ( gfPlotNewMovement  )
2974 				{
2975 					DrawUIMovementPath( pSoldier, usMapPos,  uiFlags );
2976 
2977 					gfPlotNewMovement = FALSE;
2978 				}
2979 			}
2980 
2981 			fSetCursor = TRUE;
2982 
2983 			// DISPLAY POINTS EVEN WITHOUT DELAY
2984 			// ONLY IF GFPLOT NEW MOVEMENT IS FALSE!
2985 			if ( !gfPlotNewMovement )
2986 			{
2987 				if (gsCurrentActionPoints < 0 || !(gTacticalStatus.uiFlags & INCOMBAT))
2988 				{
2989 					gfUIDisplayActionPoints = FALSE;
2990 				}
2991 				else
2992 				{
2993 					gfUIDisplayActionPoints = TRUE;
2994 
2995 					if ( uiFlags == MOVEUI_TARGET_INTTILES )
2996 					{
2997 						// Set values for AP display...
2998 						gUIDisplayActionPointsOffX = 22;
2999 						gUIDisplayActionPointsOffY = 15;
3000 					}
3001 					if ( uiFlags == MOVEUI_TARGET_BOMB )
3002 					{
3003 						// Set values for AP display...
3004 						gUIDisplayActionPointsOffX = 22;
3005 						gUIDisplayActionPointsOffY = 15;
3006 					}
3007 					else if ( uiFlags == MOVEUI_TARGET_ITEMS )
3008 					{
3009 						// Set values for AP display...
3010 						gUIDisplayActionPointsOffX = 22;
3011 						gUIDisplayActionPointsOffY = 15;
3012 					}
3013 					else
3014 					{
3015 						switch ( pSoldier->usUIMovementMode )
3016 						{
3017 							case WALKING:
3018 
3019 								gUIDisplayActionPointsOffY = 10;
3020 								gUIDisplayActionPointsOffX = 10;
3021 								break;
3022 
3023 							case RUNNING:
3024 								gUIDisplayActionPointsOffY = 15;
3025 								gUIDisplayActionPointsOffX = 21;
3026 								break;
3027 						}
3028 					}
3029 				}
3030 			}
3031 		}
3032 
3033 	}
3034 	else
3035 	{
3036 		// THE MERC IS MOVING
3037 		// We're moving, erase path, change cursor
3038 		ErasePath();
3039 
3040 		fSetCursor = TRUE;
3041 
3042 	}
3043 
3044 	return( fSetCursor );
3045 }
3046 
3047 
DrawUIMovementPath(SOLDIERTYPE * const pSoldier,UINT16 usMapPos,MoveUITarget const uiFlags)3048 static INT8 DrawUIMovementPath(SOLDIERTYPE* const pSoldier, UINT16 usMapPos, MoveUITarget const uiFlags)
3049 {
3050 	INT16 sAPCost;
3051 	INT16 sActionGridNo;
3052 	STRUCTURE *pStructure;
3053 	INT16 sAdjustedGridNo;
3054 	INT16 sIntTileGridNo;
3055 	LEVELNODE *pIntTile;
3056 	INT8 bReturnCode = 0;
3057 	BOOLEAN fPlot;
3058 
3059 	if ((gTacticalStatus.uiFlags & INCOMBAT) || _KeyDown( SHIFT ))
3060 	{
3061 		fPlot = PLOT;
3062 	}
3063 	else
3064 	{
3065 		fPlot = NO_PLOT;
3066 	}
3067 
3068 	sActionGridNo = usMapPos;
3069 	sAPCost = 0;
3070 
3071 	ErasePath();
3072 
3073 	// IF WE ARE OVER AN INTERACTIVE TILE, GIVE GRIDNO OF POSITION
3074 	if ( uiFlags == MOVEUI_TARGET_INTTILES )
3075 	{
3076 		// Get structure info for in tile!
3077 		pIntTile = GetCurInteractiveTileGridNoAndStructure( &sIntTileGridNo, &pStructure );
3078 
3079 		// We should not have null here if we are given this flag...
3080 		if ( pIntTile != NULL )
3081 		{
3082 			sActionGridNo = FindAdjacentGridEx(pSoldier, sIntTileGridNo, NULL, NULL, FALSE, TRUE);
3083 			if ( sActionGridNo == -1 )
3084 			{
3085 				sActionGridNo = sIntTileGridNo;
3086 			}
3087 			sAPCost  = AP_OPEN_DOOR;
3088 			sAPCost += UIPlotPath(pSoldier, sActionGridNo, NO_COPYROUTE, fPlot, pSoldier->usUIMovementMode, pSoldier->bActionPoints);
3089 
3090 			if ( sActionGridNo != pSoldier->sGridNo )
3091 			{
3092 				gfUIHandleShowMoveGrid = TRUE;
3093 				gsUIHandleShowMoveGridLocation = sActionGridNo;
3094 			}
3095 
3096 			// Add cost for stance change....
3097 			sAPCost += GetAPsToChangeStance( pSoldier, ANIM_STAND );
3098 		}
3099 		else
3100 		{
3101 			sAPCost += UIPlotPath(pSoldier, sActionGridNo, NO_COPYROUTE, fPlot, pSoldier->usUIMovementMode, pSoldier->bActionPoints);
3102 		}
3103 	}
3104 	else if ( uiFlags == MOVEUI_TARGET_WIREFENCE )
3105 	{
3106 		sActionGridNo = FindAdjacentGridEx(pSoldier, usMapPos, NULL, NULL, FALSE, TRUE);
3107 		if ( sActionGridNo == -1 )
3108 		{
3109 			sAPCost = 0;
3110 		}
3111 		else
3112 		{
3113 			sAPCost = GetAPsToCutFence( pSoldier );
3114 
3115 			sAPCost += UIPlotPath(pSoldier, sActionGridNo, NO_COPYROUTE, fPlot, pSoldier->usUIMovementMode, pSoldier->bActionPoints);
3116 
3117 			if ( sActionGridNo != pSoldier->sGridNo )
3118 			{
3119 				gfUIHandleShowMoveGrid = TRUE;
3120 				gsUIHandleShowMoveGridLocation = sActionGridNo;
3121 			}
3122 		}
3123 	}
3124 	else if ( uiFlags == MOVEUI_TARGET_JAR )
3125 	{
3126 		sActionGridNo = FindAdjacentGridEx(pSoldier, usMapPos, NULL, NULL, FALSE, TRUE);
3127 		if ( sActionGridNo == -1 )
3128 		{
3129 			sActionGridNo = usMapPos;
3130 		}
3131 
3132 		sAPCost = GetAPsToUseJar( pSoldier, sActionGridNo );
3133 
3134 		sAPCost += UIPlotPath(pSoldier, sActionGridNo, NO_COPYROUTE, fPlot, pSoldier->usUIMovementMode, pSoldier->bActionPoints);
3135 
3136 		if ( sActionGridNo != pSoldier->sGridNo )
3137 		{
3138 			gfUIHandleShowMoveGrid = TRUE;
3139 			gsUIHandleShowMoveGridLocation = sActionGridNo;
3140 		}
3141 	}
3142 	else if ( uiFlags == MOVEUI_TARGET_CAN )
3143 	{
3144 		// Get structure info for in tile!
3145 		pIntTile = GetCurInteractiveTileGridNoAndStructure( &sIntTileGridNo, &pStructure );
3146 
3147 		// We should not have null here if we are given this flag...
3148 		if ( pIntTile != NULL )
3149 		{
3150 			sActionGridNo = FindAdjacentGridEx(pSoldier, sIntTileGridNo, NULL, NULL, FALSE, TRUE);
3151 			if ( sActionGridNo != -1 )
3152 			{
3153 				sAPCost = AP_ATTACH_CAN;
3154 				sAPCost += UIPlotPath(pSoldier, sActionGridNo, NO_COPYROUTE, fPlot, pSoldier->usUIMovementMode, pSoldier->bActionPoints);
3155 
3156 				if ( sActionGridNo != pSoldier->sGridNo )
3157 				{
3158 					gfUIHandleShowMoveGrid = TRUE;
3159 					gsUIHandleShowMoveGridLocation = sActionGridNo;
3160 				}
3161 			}
3162 		}
3163 		else
3164 		{
3165 			sAPCost += UIPlotPath(pSoldier, sActionGridNo, NO_COPYROUTE, fPlot, pSoldier->usUIMovementMode, pSoldier->bActionPoints);
3166 		}
3167 
3168 	}
3169 	else if ( uiFlags == MOVEUI_TARGET_REPAIR )
3170 	{
3171 		// For repair, check if we are over a vehicle, then get gridnot to edge of that vehicle!
3172 		SOLDIERTYPE* tgt;
3173 		if (IsRepairableStructAtGridNo(usMapPos, &tgt) == 2)
3174 		{
3175 			const INT16 sNewGridNo = FindGridNoFromSweetSpotWithStructDataFromSoldier(pSoldier, pSoldier->usUIMovementMode, 5, 0, tgt);
3176 			if ( sNewGridNo != NOWHERE )
3177 			{
3178 				usMapPos = sNewGridNo;
3179 			}
3180 		}
3181 
3182 		sActionGridNo =  FindAdjacentGridEx(pSoldier, usMapPos, NULL, NULL, FALSE, TRUE);
3183 		if ( sActionGridNo == -1 )
3184 		{
3185 			sActionGridNo = usMapPos;
3186 		}
3187 
3188 		sAPCost = GetAPsToBeginRepair( pSoldier );
3189 
3190 		sAPCost += UIPlotPath(pSoldier, sActionGridNo, NO_COPYROUTE, fPlot, pSoldier->usUIMovementMode, pSoldier->bActionPoints);
3191 
3192 		if ( sActionGridNo != pSoldier->sGridNo )
3193 		{
3194 			gfUIHandleShowMoveGrid = TRUE;
3195 			gsUIHandleShowMoveGridLocation = sActionGridNo;
3196 		}
3197 	}
3198 	else if ( uiFlags == MOVEUI_TARGET_REFUEL )
3199 	{
3200 		// For refueling, check if we are over a vehicle, then get gridno to edge of that vehicle!
3201 		const SOLDIERTYPE* const tgt = GetRefuelableStructAtGridNo(usMapPos);
3202 		if (tgt != NULL)
3203 		{
3204 			const INT16 sNewGridNo = FindGridNoFromSweetSpotWithStructDataFromSoldier(pSoldier, pSoldier->usUIMovementMode, 5, 0, tgt);
3205 			if ( sNewGridNo != NOWHERE )
3206 			{
3207 				usMapPos = sNewGridNo;
3208 			}
3209 		}
3210 
3211 		sActionGridNo = FindAdjacentGridEx(pSoldier, usMapPos, NULL, NULL, FALSE, TRUE);
3212 		if ( sActionGridNo == -1 )
3213 		{
3214 			sActionGridNo = usMapPos;
3215 		}
3216 
3217 		sAPCost = GetAPsToRefuelVehicle( pSoldier );
3218 
3219 		sAPCost += UIPlotPath(pSoldier, sActionGridNo, NO_COPYROUTE, fPlot, pSoldier->usUIMovementMode, pSoldier->bActionPoints);
3220 
3221 		if ( sActionGridNo != pSoldier->sGridNo )
3222 		{
3223 			gfUIHandleShowMoveGrid = TRUE;
3224 			gsUIHandleShowMoveGridLocation = sActionGridNo;
3225 		}
3226 	}
3227 	else if ( uiFlags == MOVEUI_TARGET_MERCS )
3228 	{
3229 		INT16   sGotLocation = NOWHERE;
3230 		BOOLEAN fGotAdjacent = FALSE;
3231 
3232 		// Check if we are on a target
3233 		const SOLDIERTYPE* const tgt = gUIFullTarget;
3234 		if (tgt != NULL)
3235 		{
3236 			UINT8 cnt;
3237 			INT16 sSpot;
3238 
3239 			for ( cnt = 0; cnt < NUM_WORLD_DIRECTIONS; cnt++ )
3240 			{
3241 				sSpot = NewGridNo( pSoldier->sGridNo, DirectionInc( cnt ) );
3242 
3243 				// Make sure movement costs are OK....
3244 				if ( gubWorldMovementCosts[ sSpot ][ cnt ][ gsInterfaceLevel ] >= TRAVELCOST_BLOCKED )
3245 				{
3246 					continue;
3247 				}
3248 
3249 				// Check for who is there...
3250 				if (WhoIsThere2(sSpot, pSoldier->bLevel) == tgt)
3251 				{
3252 					// We've got a guy here....
3253 					// Who is the one we want......
3254 					sGotLocation = sSpot;
3255 					sAdjustedGridNo	= tgt->sGridNo;
3256 					break;
3257 				}
3258 			}
3259 
3260 				if ( sGotLocation == NOWHERE )
3261 				{
3262 				sActionGridNo = FindAdjacentGridEx(pSoldier, tgt->sGridNo, NULL, &sAdjustedGridNo, TRUE, FALSE);
3263 
3264 					if ( sActionGridNo == -1 )
3265 					{
3266 						sGotLocation = NOWHERE;
3267 					}
3268 					else
3269 					{
3270 						sGotLocation = sActionGridNo;
3271 					}
3272 					fGotAdjacent = TRUE;
3273 				}
3274 		}
3275 		else
3276 		{
3277 			sAdjustedGridNo = usMapPos;
3278 			sGotLocation = sActionGridNo;
3279 			fGotAdjacent = TRUE;
3280 		}
3281 
3282 		if ( sGotLocation != NOWHERE )
3283 		{
3284 			sAPCost += MinAPsToAttack( pSoldier, sAdjustedGridNo, TRUE );
3285 			sAPCost += UIPlotPath(pSoldier, sGotLocation, NO_COPYROUTE, fPlot, pSoldier->usUIMovementMode, pSoldier->bActionPoints);
3286 
3287 			if ( sGotLocation != pSoldier->sGridNo && fGotAdjacent )
3288 			{
3289 				gfUIHandleShowMoveGrid = TRUE;
3290 				gsUIHandleShowMoveGridLocation = sGotLocation;
3291 			}
3292 		}
3293 	}
3294 	else if ( uiFlags == MOVEUI_TARGET_STEAL )
3295 	{
3296 		// Check if we are on a target
3297 		const SOLDIERTYPE* const tgt = gUIFullTarget;
3298 		if (tgt != NULL)
3299 		{
3300 			sActionGridNo = FindAdjacentGridEx(pSoldier, tgt->sGridNo, NULL, &sAdjustedGridNo, TRUE, FALSE);
3301 			if ( sActionGridNo == -1 )
3302 			{
3303 				sActionGridNo = sAdjustedGridNo;
3304 			}
3305 			sAPCost += AP_STEAL_ITEM;
3306 			// CJC August 13 2002: take into account stance in AP prediction
3307 			if (!(PTR_STANDING))
3308 			{
3309 				sAPCost += GetAPsToChangeStance( pSoldier, ANIM_STAND );
3310 			}
3311 			sAPCost += UIPlotPath(pSoldier, sActionGridNo, NO_COPYROUTE, fPlot, pSoldier->usUIMovementMode, pSoldier->bActionPoints);
3312 
3313 			if ( sActionGridNo != pSoldier->sGridNo )
3314 			{
3315 				gfUIHandleShowMoveGrid = TRUE;
3316 				gsUIHandleShowMoveGridLocation = sActionGridNo;
3317 			}
3318 		}
3319 	}
3320 	else if ( uiFlags == MOVEUI_TARGET_BOMB )
3321 	{
3322 		sAPCost += GetAPsToDropBomb( pSoldier );
3323 		sAPCost += UIPlotPath(pSoldier, usMapPos, NO_COPYROUTE, fPlot, pSoldier->usUIMovementMode, pSoldier->bActionPoints);
3324 
3325 		gfUIHandleShowMoveGrid = TRUE;
3326 		gsUIHandleShowMoveGridLocation = usMapPos;
3327 	}
3328 	else if ( uiFlags == MOVEUI_TARGET_MERCSFORAID )
3329 	{
3330 		const SOLDIERTYPE* const tgt = gUIFullTarget;
3331 		if (tgt != NULL)
3332 		{
3333 			sActionGridNo = FindAdjacentGridEx(pSoldier, tgt->sGridNo, NULL, &sAdjustedGridNo, TRUE, FALSE);
3334 
3335 			// Try again at another gridno...
3336 			if ( sActionGridNo == -1 )
3337 			{
3338 				sActionGridNo = FindAdjacentGridEx(pSoldier, usMapPos, NULL, &sAdjustedGridNo, TRUE, FALSE);
3339 
3340 				if ( sActionGridNo == -1 )
3341 				{
3342 					sActionGridNo = sAdjustedGridNo;
3343 				}
3344 			}
3345 			sAPCost += GetAPsToBeginFirstAid( pSoldier );
3346 			sAPCost += UIPlotPath(pSoldier, sActionGridNo, NO_COPYROUTE, fPlot, pSoldier->usUIMovementMode, pSoldier->bActionPoints);
3347 			if ( sActionGridNo != pSoldier->sGridNo )
3348 			{
3349 				gfUIHandleShowMoveGrid = TRUE;
3350 				gsUIHandleShowMoveGridLocation = sActionGridNo;
3351 			}
3352 		}
3353 	}
3354 	else if ( uiFlags == MOVEUI_TARGET_ITEMS )
3355 	{
3356 		sActionGridNo = AdjustGridNoForItemPlacement( pSoldier, sActionGridNo );
3357 
3358 		if ( pSoldier->sGridNo != sActionGridNo )
3359 		{
3360 			sAPCost += UIPlotPath(pSoldier, sActionGridNo, NO_COPYROUTE, fPlot, pSoldier->usUIMovementMode, pSoldier->bActionPoints);
3361 			if ( sAPCost != 0 )
3362 			{
3363 				sAPCost += AP_PICKUP_ITEM;
3364 			}
3365 		}
3366 		else
3367 		{
3368 				sAPCost += AP_PICKUP_ITEM;
3369 		}
3370 
3371 		if ( sActionGridNo != pSoldier->sGridNo )
3372 		{
3373 			gfUIHandleShowMoveGrid = TRUE;
3374 			gsUIHandleShowMoveGridLocation = sActionGridNo;
3375 		}
3376 	}
3377 	else
3378 	{
3379 		sAPCost += UIPlotPath(pSoldier, sActionGridNo, NO_COPYROUTE, fPlot, pSoldier->usUIMovementMode, pSoldier->bActionPoints);
3380 	}
3381 
3382 	if ( gTacticalStatus.uiFlags & SHOW_AP_LEFT )
3383 	{
3384 		gsCurrentActionPoints = pSoldier->bActionPoints - sAPCost;
3385 	}
3386 	else
3387 	{
3388 		gsCurrentActionPoints = sAPCost;
3389 	}
3390 
3391 	return( bReturnCode );
3392 }
3393 
3394 
UIMouseOnValidAttackLocation(SOLDIERTYPE * const s)3395 bool UIMouseOnValidAttackLocation(SOLDIERTYPE* const s)
3396 {
3397 	GridNo map_pos = GetMouseMapPos();
3398 	if (map_pos == NOWHERE) return false;
3399 
3400 	OBJECTTYPE const& o           = s->inv[HANDPOS];
3401 	const ItemModel * item = GCM->getItem(o.usItem);
3402 	ItemCursor const  item_cursor = GetActionModeCursor(s);
3403 
3404 	if (item_cursor == INVALIDCURS) return false;
3405 
3406 	if (item_cursor == WIRECUTCURS)
3407 	{
3408 		return s->bLevel == 0 && IsCuttableWireFenceAtGridNo(map_pos);
3409 	}
3410 
3411 	SOLDIERTYPE const* const tgt = gUIFullTarget;
3412 	if (item_cursor == REPAIRCURS)
3413 	{
3414 		if (tgt) map_pos = tgt->sGridNo;
3415 		return s->bLevel == 0 && IsRepairableStructAtGridNo(map_pos, 0);
3416 	}
3417 
3418 	if (item_cursor == REFUELCURS)
3419 	{
3420 		if (tgt) map_pos = tgt->sGridNo;
3421 		return s->bLevel == 0 && GetRefuelableStructAtGridNo(map_pos);
3422 	}
3423 
3424 	if (item_cursor == BOMBCURS)
3425 	{
3426 		if (map_pos == s->sGridNo) return true;
3427 		if (!NewOKDestination(s, map_pos, TRUE, s->bLevel)) return false;
3428 	}
3429 
3430 	if (tgt == s && item->getItemClass() != IC_MEDKIT) return false;
3431 
3432 	if (HasObjectImprint(o) && s->ubProfile != o.ubImprintID)
3433 	{
3434 		// Access denied
3435 		PlayJA2Sample(RG_ID_INVALID, HIGHVOLUME, 1, MIDDLE);
3436 		ScreenMsg(FONT_MCOLOR_LTYELLOW, MSG_UI_FEEDBACK, ST::format("\"{}\"", TacticalStr[GUN_NOGOOD_FINGERPRINT]));
3437 		return false;
3438 	}
3439 
3440 	if (item->getItemClass() == IC_PUNCH)
3441 	{
3442 		// can't punch the ground
3443 		if (!tgt) return false;
3444 
3445 		// We test again whether the target is reachable
3446 		if (CalcTotalAPsToAttack(s, tgt->sGridNo, true, 0) == 0)
3447 		{
3448 			ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_UI_FEEDBACK, TacticalStr[ NO_PATH ] );
3449 			return false;
3450 		}
3451 		return tgt;
3452 	}
3453 
3454 	if (item->getItemClass() == IC_MEDKIT)
3455 	{
3456 		// If a guy's here, check if he needs medical help!
3457 		if (!tgt) return false;
3458 
3459 		if (tgt->uiStatusFlags & (SOLDIER_VEHICLE | SOLDIER_ROBOT))
3460 		{
3461 			ScreenMsg(FONT_MCOLOR_LTYELLOW, MSG_UI_FEEDBACK, st_format_printf(TacticalStr[CANNOT_DO_FIRST_AID_STR], tgt->name));
3462 			return false;
3463 		}
3464 
3465 		if (s->bMedical == 0)
3466 		{
3467 			ScreenMsg(FONT_MCOLOR_LTYELLOW, MSG_UI_FEEDBACK, st_format_printf(pMessageStrings[MSG_MERC_HAS_NO_MEDSKILL], s->name));
3468 			return false;
3469 		}
3470 
3471 		if (tgt->bBleeding == 0 && tgt->bLife != tgt->bLifeMax)
3472 		{
3473 			ScreenMsg(FONT_MCOLOR_LTYELLOW, MSG_UI_FEEDBACK, st_format_printf(gzLateLocalizedString[STR_LATE_19], tgt->name));
3474 			return false;
3475 		}
3476 
3477 		if (tgt->bBleeding == 0 && tgt->bLife >= OKLIFE)
3478 		{
3479 			ScreenMsg(FONT_MCOLOR_LTYELLOW, MSG_UI_FEEDBACK, st_format_printf(TacticalStr[CANNOT_NO_NEED_FIRST_AID_STR], tgt->name));
3480 			return false;
3481 		}
3482 	}
3483 
3484 	return true;
3485 }
3486 
3487 
UIOkForItemPickup(SOLDIERTYPE * pSoldier,INT16 sGridNo)3488 BOOLEAN UIOkForItemPickup( SOLDIERTYPE *pSoldier, INT16 sGridNo )
3489 {
3490 	INT16 sAPCost;
3491 
3492 	sAPCost = GetAPsToPickupItem( pSoldier, sGridNo );
3493 
3494 	if ( sAPCost == 0 )
3495 	{
3496 		ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_UI_FEEDBACK, TacticalStr[ NO_PATH ] );
3497 	}
3498 	else
3499 	{
3500 		if ( EnoughPoints( pSoldier, sAPCost, 0, TRUE ) )
3501 		{
3502 			return( TRUE );
3503 		}
3504 	}
3505 
3506 	return( FALSE );
3507 }
3508 
3509 
SoldierCanAffordNewStance(SOLDIERTYPE * pSoldier,UINT8 ubDesiredStance)3510 static BOOLEAN SoldierCanAffordNewStance(SOLDIERTYPE* pSoldier, UINT8 ubDesiredStance)
3511 {
3512 	INT8  bCurrentHeight;
3513 	UINT8 bAP = 0, bBP = 0;
3514 
3515 	bCurrentHeight = ( ubDesiredStance - gAnimControl[ pSoldier->usAnimState ].ubEndHeight );
3516 
3517 	// Now change to appropriate animation
3518 
3519 	switch( bCurrentHeight )
3520 	{
3521 		case ANIM_STAND - ANIM_CROUCH:
3522 		case ANIM_CROUCH - ANIM_STAND:
3523 
3524 			bAP = AP_CROUCH;
3525 			bBP = BP_CROUCH;
3526 			break;
3527 
3528 		case ANIM_STAND - ANIM_PRONE:
3529 		case ANIM_PRONE - ANIM_STAND:
3530 
3531 			bAP = AP_CROUCH + AP_PRONE;
3532 			bBP = BP_CROUCH + BP_PRONE;
3533 			break;
3534 
3535 		case ANIM_CROUCH - ANIM_PRONE:
3536 		case ANIM_PRONE - ANIM_CROUCH:
3537 
3538 			bAP = AP_PRONE;
3539 			bBP = BP_PRONE;
3540 			break;
3541 
3542 	}
3543 
3544 	return ( EnoughPoints( pSoldier, bAP, bBP , TRUE ) );
3545 }
3546 
3547 
SetUIbasedOnStance(SOLDIERTYPE * pSoldier,INT8 bNewStance)3548 static void SetUIbasedOnStance(SOLDIERTYPE* pSoldier, INT8 bNewStance)
3549 {
3550 	// Set UI based on our stance!
3551 	switch ( bNewStance )
3552 	{
3553 		case ANIM_STAND:
3554 			pSoldier->usUIMovementMode = WALKING;
3555 			break;
3556 
3557 		case ANIM_CROUCH:
3558 			pSoldier->usUIMovementMode = SWATTING;
3559 			break;
3560 
3561 		case ANIM_PRONE:
3562 			pSoldier->usUIMovementMode = CRAWLING;
3563 			break;
3564 	}
3565 
3566 	// Set UI cursor!
3567 }
3568 
3569 
SetMovementModeCursor(const SOLDIERTYPE * pSoldier)3570 static void SetMovementModeCursor(const SOLDIERTYPE* pSoldier)
3571 {
3572 	if (gTacticalStatus.uiFlags & INCOMBAT)
3573 	{
3574 		if ( ( OK_ENTERABLE_VEHICLE( pSoldier ) ) )
3575 		{
3576 			guiNewUICursor = MOVE_VEHICLE_UICURSOR;
3577 		}
3578 		else
3579 		{
3580 			// Change mouse cursor based on type of movement we want to do
3581 			switch ( pSoldier->usUIMovementMode )
3582 			{
3583 					case WALKING:
3584 						guiNewUICursor = MOVE_WALK_UICURSOR;
3585 						break;
3586 
3587 					case RUNNING:
3588 						guiNewUICursor = MOVE_RUN_UICURSOR;
3589 						break;
3590 
3591 					case SWATTING:
3592 						guiNewUICursor = MOVE_SWAT_UICURSOR;
3593 						break;
3594 
3595 					case CRAWLING:
3596 						guiNewUICursor = MOVE_PRONE_UICURSOR;
3597 						break;
3598 			}
3599 		}
3600 	}
3601 
3602 	if (!(gTacticalStatus.uiFlags & INCOMBAT))
3603 	{
3604 		if ( gfUIAllMoveOn )
3605 		{
3606 			guiNewUICursor = ALL_MOVE_REALTIME_UICURSOR;
3607 		}
3608 		else
3609 		{
3610 			//if ( pSoldier->fUIMovementFast )
3611 			//{
3612 			//	BeginDisplayTimedCursor( MOVE_RUN_REALTIME_UICURSOR, 300 );
3613 			//}
3614 
3615 			guiNewUICursor = MOVE_REALTIME_UICURSOR;
3616 		}
3617 	}
3618 
3619 	guiNewUICursor = GetInteractiveTileCursor( guiNewUICursor, FALSE );
3620 }
3621 
3622 
SetConfirmMovementModeCursor(SOLDIERTYPE * pSoldier,BOOLEAN fFromMove)3623 static void SetConfirmMovementModeCursor(SOLDIERTYPE* pSoldier, BOOLEAN fFromMove)
3624 {
3625 	if (gTacticalStatus.uiFlags & INCOMBAT)
3626 	{
3627 		if ( gfUIAllMoveOn )
3628 		{
3629 			if ( ( OK_ENTERABLE_VEHICLE( pSoldier ) ) )
3630 			{
3631 				guiNewUICursor = ALL_MOVE_VEHICLE_UICURSOR;
3632 			}
3633 			else
3634 			{
3635 				// Change mouse cursor based on type of movement we want to do
3636 				switch ( pSoldier->usUIMovementMode )
3637 				{
3638 					case WALKING:
3639 						guiNewUICursor = ALL_MOVE_WALK_UICURSOR;
3640 						break;
3641 
3642 					case RUNNING:
3643 						guiNewUICursor = ALL_MOVE_RUN_UICURSOR;
3644 						break;
3645 
3646 					case SWATTING:
3647 						guiNewUICursor = ALL_MOVE_SWAT_UICURSOR;
3648 						break;
3649 
3650 					case CRAWLING:
3651 						guiNewUICursor = ALL_MOVE_PRONE_UICURSOR;
3652 						break;
3653 				}
3654 			}
3655 		}
3656 		else
3657 		{
3658 			if ( pSoldier->uiStatusFlags & SOLDIER_VEHICLE )
3659 			{
3660 				guiNewUICursor = CONFIRM_MOVE_VEHICLE_UICURSOR;
3661 			}
3662 			else
3663 			{
3664 				// Change mouse cursor based on type of movement we want to do
3665 				switch ( pSoldier->usUIMovementMode )
3666 				{
3667 					case WALKING:
3668 						guiNewUICursor = CONFIRM_MOVE_WALK_UICURSOR;
3669 						break;
3670 
3671 					case RUNNING:
3672 						guiNewUICursor = CONFIRM_MOVE_RUN_UICURSOR;
3673 						break;
3674 
3675 					case SWATTING:
3676 						guiNewUICursor = CONFIRM_MOVE_SWAT_UICURSOR;
3677 						break;
3678 
3679 					case CRAWLING:
3680 						guiNewUICursor = CONFIRM_MOVE_PRONE_UICURSOR;
3681 						break;
3682 				}
3683 			}
3684 		}
3685 	}
3686 
3687 	if (!(gTacticalStatus.uiFlags & INCOMBAT))
3688 	{
3689 		if ( gfUIAllMoveOn )
3690 		{
3691 			if ( gfUIAllMoveOn == 2 )
3692 			{
3693 				BeginDisplayTimedCursor( MOVE_RUN_REALTIME_UICURSOR, 300 );
3694 			}
3695 			else
3696 			{
3697 				guiNewUICursor = ALL_MOVE_REALTIME_UICURSOR;
3698 			}
3699 		}
3700 		else
3701 		{
3702 			if ( pSoldier->fUIMovementFast && pSoldier->usAnimState == RUNNING && fFromMove )
3703 			{
3704 				BeginDisplayTimedCursor( MOVE_RUN_REALTIME_UICURSOR, 300 );
3705 			}
3706 
3707 			guiNewUICursor = CONFIRM_MOVE_REALTIME_UICURSOR;
3708 		}
3709 	}
3710 
3711 	guiNewUICursor = GetInteractiveTileCursor( guiNewUICursor, TRUE );
3712 
3713 }
3714 
3715 
UIHandleLCOnTerrain(UI_EVENT * pUIEvent)3716 static ScreenID UIHandleLCOnTerrain(UI_EVENT* pUIEvent)
3717 {
3718 	guiNewUICursor = LOOK_UICURSOR;
3719 
3720 	const SOLDIERTYPE* const sel = GetSelectedMan();
3721 	if (sel == NULL) return GAME_SCREEN;
3722 
3723 	gfUIDisplayActionPoints = TRUE;
3724 
3725 	gUIDisplayActionPointsOffX = 14;
3726 	gUIDisplayActionPointsOffY = 7;
3727 
3728 	const GridNo pos = GetMouseMapPos();
3729 
3730 	// Get direction from mouse pos
3731 	const INT16 sFacingDir = GetDirectionFromGridNo(pos, sel);
3732 
3733 	// Set # of APs
3734 	gsCurrentActionPoints = (sFacingDir == sel->bDirection ? 0 : GetAPsToLook(sel));
3735 
3736 	// Determine if we can afford!
3737 	if (!EnoughPoints(sel, gsCurrentActionPoints, 0, FALSE))
3738 	{
3739 		gfUIDisplayActionPointsInvalid = TRUE;
3740 	}
3741 
3742 	return( GAME_SCREEN );
3743 
3744 }
3745 
3746 
UIHandleLCChangeToLook(UI_EVENT * pUIEvent)3747 static ScreenID UIHandleLCChangeToLook(UI_EVENT* pUIEvent)
3748 {
3749 	ErasePath();
3750 
3751 	return( GAME_SCREEN );
3752 }
3753 
3754 
MakeSoldierTurn(SOLDIERTYPE * const pSoldier,const GridNo pos)3755 static BOOLEAN MakeSoldierTurn(SOLDIERTYPE* const pSoldier, const GridNo pos)
3756 {
3757 	// Get direction from mouse pos
3758 	const INT16 sFacingDir = GetDirectionFromGridNo(pos, pSoldier);
3759 
3760 	if ( sFacingDir != pSoldier->bDirection )
3761 	{
3762 		const INT16 sAPCost = GetAPsToLook(pSoldier);
3763 
3764 		// Check AP cost...
3765 		if ( !EnoughPoints( pSoldier, sAPCost, 0, TRUE ) )
3766 		{
3767 			return( FALSE );
3768 		}
3769 
3770 		// ATE: make stationary if...
3771 		if ( pSoldier->fNoAPToFinishMove )
3772 		{
3773 			SoldierGotoStationaryStance( pSoldier );
3774 		}
3775 
3776 		//DEF:  made it an event
3777 		SendSoldierSetDesiredDirectionEvent( pSoldier, sFacingDir );
3778 
3779 		pSoldier->bTurningFromUI = TRUE;
3780 
3781 		// ATE: Hard-code here previous event to ui busy event...
3782 		guiOldEvent = LA_BEGINUIOURTURNLOCK;
3783 
3784 		return( TRUE );
3785 	}
3786 
3787 	return( FALSE );
3788 }
3789 
3790 
UIHandleLCLook(UI_EVENT * pUIEvent)3791 static ScreenID UIHandleLCLook(UI_EVENT* pUIEvent)
3792 {
3793 	const GridNo pos = GetMouseMapPos();
3794 	if (pos == NOWHERE) return GAME_SCREEN;
3795 
3796 	if ( gTacticalStatus.fAtLeastOneGuyOnMultiSelect )
3797 	{
3798 		// OK, loop through all guys who are 'multi-selected' and
3799 		FOR_EACH_IN_TEAM(s, OUR_TEAM)
3800 		{
3801 			if (s->bInSector && s->uiStatusFlags & SOLDIER_MULTI_SELECTED)
3802 			{
3803 				MakeSoldierTurn(s, pos);
3804 			}
3805 		}
3806 	}
3807 	else
3808 	{
3809 		SOLDIERTYPE* const sel = GetSelectedMan();
3810 		if (sel == NULL) return GAME_SCREEN;
3811 
3812 		if (MakeSoldierTurn(sel, pos)) SetUIBusy(sel);
3813 	}
3814 	return( GAME_SCREEN );
3815 }
3816 
3817 
UIHandleTOnTerrain(UI_EVENT * pUIEvent)3818 static ScreenID UIHandleTOnTerrain(UI_EVENT* pUIEvent)
3819 {
3820 	INT16 sTargetGridNo;
3821 
3822 	const SOLDIERTYPE* const sel = GetSelectedMan();
3823 	if (sel == NULL) return GAME_SCREEN;
3824 
3825 	const GridNo usMapPos = GetMouseMapPos();
3826 	if (usMapPos == NOWHERE) return GAME_SCREEN;
3827 
3828 	if( ValidQuickExchangePosition( ) )
3829 	{
3830 		// Do new cursor!
3831 		guiPendingOverrideEvent = M_ON_TERRAIN;
3832 		return( UIHandleMOnTerrain( pUIEvent ) );
3833 	}
3834 
3835 	sTargetGridNo = usMapPos;
3836 
3837 
3838 	UIHandleOnMerc( FALSE );
3839 
3840 
3841 	//CHECK FOR VALID TALKABLE GUY HERE
3842 	const SOLDIERTYPE* const tgt = GetValidTalkableNPCFromMouse(FALSE, TRUE, FALSE);
3843 
3844 	// USe cursor based on distance
3845 	// Get distance away
3846 	if (tgt != NULL) sTargetGridNo = tgt->sGridNo;
3847 
3848 	const UINT32 uiRange = GetRangeFromGridNoDiff(sel->sGridNo, sTargetGridNo);
3849 
3850 
3851 	//ATE: Check if we have good LOS
3852 	// is he close enough to see that gridno if he turns his head?
3853 	const INT16 sDistVisible = DistanceVisible(sel, DIRECTION_IRRELEVANT, DIRECTION_IRRELEVANT, sTargetGridNo, sel->bLevel);
3854 
3855 
3856 	if ( uiRange <= NPC_TALK_RADIUS )
3857 	{
3858 		if (tgt != NULL)
3859 		{
3860 			guiNewUICursor = TALK_A_UICURSOR;
3861 		}
3862 		else
3863 		{
3864 			guiNewUICursor = TALK_NA_UICURSOR;
3865 		}
3866 	}
3867 	else
3868 	{
3869 		if (tgt != NULL)
3870 		{
3871 			//guiNewUICursor = TALK_OUT_RANGE_A_UICURSOR;
3872 			guiNewUICursor = TALK_A_UICURSOR;
3873 		}
3874 		else
3875 		{
3876 			guiNewUICursor = TALK_OUT_RANGE_NA_UICURSOR;
3877 		}
3878 	}
3879 
3880 	if (tgt != NULL)
3881 	{
3882 		if (!SoldierTo3DLocationLineOfSightTest(sel, sTargetGridNo, sel->bLevel, 3, sDistVisible, TRUE))
3883 		{
3884 			//. ATE: Make range far, so we alternate cursors...
3885 			guiNewUICursor = TALK_OUT_RANGE_A_UICURSOR;
3886 		}
3887 	}
3888 
3889 	gfUIDisplayActionPoints = TRUE;
3890 
3891 	gUIDisplayActionPointsOffX = 8;
3892 	gUIDisplayActionPointsOffY = 3;
3893 
3894 	// Set # of APs
3895 	gsCurrentActionPoints = 6;
3896 
3897 	// Determine if we can afford!
3898 	if (!EnoughPoints(sel, gsCurrentActionPoints, 0, FALSE))
3899 	{
3900 		gfUIDisplayActionPointsInvalid = TRUE;
3901 	}
3902 
3903 	return( GAME_SCREEN );
3904 }
3905 
3906 
UIHandleTChangeToTalking(UI_EVENT * pUIEvent)3907 static ScreenID UIHandleTChangeToTalking(UI_EVENT* pUIEvent)
3908 {
3909 	ErasePath();
3910 
3911 	return( GAME_SCREEN );
3912 }
3913 
3914 
UIHandleLUIOnTerrain(UI_EVENT * pUIEvent)3915 static ScreenID UIHandleLUIOnTerrain(UI_EVENT* pUIEvent)
3916 {
3917 	//guiNewUICursor = NO_UICURSOR;
3918 	//SetCurrentCursorFromDatabase( VIDEO_NO_CURSOR );
3919 
3920 	return( GAME_SCREEN );
3921 }
3922 
3923 
UIHandleLUIBeginLock(UI_EVENT * pUIEvent)3924 static ScreenID UIHandleLUIBeginLock(UI_EVENT* pUIEvent)
3925 {
3926 	// Don't let both versions of the locks to happen at the same time!
3927 	// ( They are mutually exclusive )!
3928 	UIHandleLAEndLockOurTurn( NULL );
3929 
3930 	if ( !gfDisableRegionActive )
3931 	{
3932 		gfDisableRegionActive = TRUE;
3933 
3934 		RemoveTacticalCursor( );
3935 		//SetCurrentCursorFromDatabase( VIDEO_NO_CURSOR );
3936 
3937 		MSYS_DefineRegion(&gDisableRegion, 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, MSYS_PRIORITY_HIGHEST,
3938 					CURSOR_WAIT, MSYS_NO_CALLBACK, MSYS_NO_CALLBACK);
3939 
3940 		//guiPendingOverrideEvent = LOCKUI_MODE;
3941 
3942 		// UnPause time!
3943 		PauseGame();
3944 		LockPauseState(LOCK_PAUSE_LOCKUI_MODE);
3945 	}
3946 
3947 	return( GAME_SCREEN );
3948 }
3949 
3950 
UIHandleLUIEndLock(UI_EVENT * pUIEvent)3951 ScreenID UIHandleLUIEndLock(UI_EVENT* pUIEvent)
3952 {
3953 	if ( gfDisableRegionActive )
3954 	{
3955 		gfDisableRegionActive = FALSE;
3956 
3957 		// Add region
3958 		MSYS_RemoveRegion( &gDisableRegion );
3959 		RefreshMouseRegions( );
3960 
3961 		//SetCurrentCursorFromDatabase( guiCurrentUICursor );
3962 
3963 		guiForceRefreshMousePositionCalculation = TRUE;
3964 		UIHandleMOnTerrain( NULL );
3965 
3966 		if ( gViewportRegion.uiFlags & MSYS_MOUSE_IN_AREA )
3967 		{
3968 			SetCurrentCursorFromDatabase( gUICursors[ guiNewUICursor ].usFreeCursorName );
3969 		}
3970 
3971 		guiPendingOverrideEvent = M_ON_TERRAIN;
3972 		HandleTacticalUI( );
3973 
3974 		// ATE: Only if NOT in conversation!
3975 		if ( !( gTacticalStatus.uiFlags & ENGAGED_IN_CONV ) )
3976 		{
3977 			// UnPause time!
3978 			UnLockPauseState();
3979 			UnPauseGame();
3980 		}
3981 	}
3982 
3983 	return( GAME_SCREEN );
3984 }
3985 
3986 
CheckForDisabledRegionRemove()3987 void CheckForDisabledRegionRemove( )
3988 {
3989 	if ( gfDisableRegionActive )
3990 	{
3991 		gfDisableRegionActive = FALSE;
3992 
3993 		// Remove region
3994 		MSYS_RemoveRegion( &gDisableRegion );
3995 
3996 		UnLockPauseState();
3997 		UnPauseGame();
3998 
3999 	}
4000 
4001 	if ( gfUserTurnRegionActive )
4002 	{
4003 		gfUserTurnRegionActive = FALSE;
4004 
4005 		gfUIInterfaceSetBusy = FALSE;
4006 
4007 		// Remove region
4008 		MSYS_RemoveRegion( &gUserTurnRegion );
4009 
4010 		UnLockPauseState();
4011 		UnPauseGame();
4012 	}
4013 }
4014 
4015 
UIHandleLAOnTerrain(UI_EVENT * pUIEvent)4016 static ScreenID UIHandleLAOnTerrain(UI_EVENT* pUIEvent)
4017 {
4018 	//guiNewUICursor = NO_UICURSOR;
4019 	//SetCurrentCursorFromDatabase( VIDEO_NO_CURSOR );
4020 
4021 	return( GAME_SCREEN );
4022 }
4023 
4024 
GetGridNoScreenXY(INT16 sGridNo,INT16 * pScreenX,INT16 * pScreenY)4025 static void GetGridNoScreenXY(INT16 sGridNo, INT16* pScreenX, INT16* pScreenY)
4026 {
4027 	INT16 sScreenX, sScreenY;
4028 	INT16 sOffsetX, sOffsetY;
4029 	INT16 sTempX_S, sTempY_S;
4030 	INT16 sXPos, sYPos;
4031 
4032 	ConvertGridNoToCellXY( sGridNo, &sXPos, &sYPos );
4033 
4034 	// Get 'TRUE' merc position
4035 	sOffsetX = sXPos - gsRenderCenterX;
4036 	sOffsetY = sYPos - gsRenderCenterY;
4037 
4038 	FromCellToScreenCoordinates( sOffsetX, sOffsetY, &sTempX_S, &sTempY_S );
4039 
4040 	sScreenX = ( g_ui.m_tacticalMapCenterX ) + (INT16)sTempX_S;
4041 	sScreenY = ( g_ui.m_tacticalMapCenterY ) + (INT16)sTempY_S;
4042 
4043 	// Adjust for offset position on screen
4044 	sScreenX -= gsRenderWorldOffsetX;
4045 	sScreenY -= gsRenderWorldOffsetY;
4046 	sScreenY -=	gpWorldLevelData[ sGridNo ].sHeight;
4047 
4048 	// Adjust based on interface level
4049 
4050 	// Adjust for render height
4051 	sScreenY += gsRenderHeight;
4052 
4053 	// Adjust y offset!
4054 	sScreenY += ( WORLD_TILE_Y/2);
4055 
4056 	(*pScreenX) = sScreenX;
4057 	(*pScreenY) = sScreenY;
4058 }
4059 
4060 
EndMultiSoldierSelection(BOOLEAN acknowledge)4061 void EndMultiSoldierSelection(BOOLEAN acknowledge)
4062 {
4063 	gTacticalStatus.fAtLeastOneGuyOnMultiSelect = FALSE;
4064 
4065 	if (gGameSettings.fOptions[TOPTION_MUTE_CONFIRMATIONS]) acknowledge = FALSE;
4066 
4067 	// loop through all guys who are 'multi-selected' and check if our currently
4068 	// selected guy is among them - if not, change to a guy who is
4069 	SOLDIERTYPE*             first = NULL;
4070 	const SOLDIERTYPE* const sel   = GetSelectedMan();
4071 	FOR_EACH_IN_TEAM(s, OUR_TEAM)
4072 	{
4073 		if (!s->bInSector)
4074 			continue;
4075 		if (!(s->uiStatusFlags & SOLDIER_MULTI_SELECTED))
4076 			continue;
4077 
4078 		gTacticalStatus.fAtLeastOneGuyOnMultiSelect = TRUE;
4079 
4080 		if (s == sel || first == NULL)
4081 			first = s;
4082 
4083 		if (acknowledge)
4084 			InternalDoMercBattleSound(s, BATTLE_SOUND_ATTN1, BATTLE_SND_LOWER_VOLUME);
4085 
4086 		if (s->fMercAsleep)
4087 			PutMercInAwakeState(s);
4088 	}
4089 
4090 	// If here, select the first guy...
4091 	if (first != NULL && first != sel)
4092 	{
4093 		SelectSoldier(first, SELSOLDIER_ACKNOWLEDGE | SELSOLDIER_FORCE_RESELECT);
4094 	}
4095 }
4096 
4097 
StopRubberBandedMercFromMoving()4098 void StopRubberBandedMercFromMoving( )
4099 {
4100 	if ( !gTacticalStatus.fAtLeastOneGuyOnMultiSelect )
4101 	{
4102 		return;
4103 	}
4104 
4105 	FOR_EACH_IN_TEAM(s, OUR_TEAM)
4106 	{
4107 		if (s->bInSector && s->uiStatusFlags & SOLDIER_MULTI_SELECTED)
4108 		{
4109 			s->fDelayedMovement = FALSE;
4110 			s->sFinalDestination = s->sGridNo;
4111 			StopSoldier(s);
4112 		}
4113 	}
4114 }
4115 
4116 
EndRubberBanding(BOOLEAN fCancel)4117 void EndRubberBanding(BOOLEAN fCancel)
4118 {
4119 	if (gRubberBandActive)
4120 	{
4121 		FreeMouseCursor( );
4122 		gfIgnoreScrolling = FALSE;
4123 		if (!fCancel)
4124 		{
4125 			EndMultiSoldierSelection(TRUE);
4126 		}
4127 
4128 		gRubberBandActive = FALSE;
4129 	}
4130 }
4131 
4132 
HandleMultiSelectionMove(INT16 sDestGridNo)4133 static BOOLEAN HandleMultiSelectionMove(INT16 sDestGridNo)
4134 {
4135 	BOOLEAN fAtLeastOneMultiSelect = FALSE;
4136 	BOOLEAN fMoveFast = FALSE;
4137 
4138 	// OK, loop through all guys who are 'multi-selected' and
4139 	// Make them move....
4140 
4141 	// Do a loop first to see if the selected guy is told to go fast...
4142 	gfGetNewPathThroughPeople = TRUE;
4143 
4144 	const SOLDIERTYPE* const sel = GetSelectedMan();
4145 	CFOR_EACH_IN_TEAM(s, OUR_TEAM)
4146 	{
4147 		if (s->bInSector &&
4148 			s->uiStatusFlags & SOLDIER_MULTI_SELECTED &&
4149 			s == sel)
4150 		{
4151 			fMoveFast = s->fUIMovementFast;
4152 			break;
4153 		}
4154 	}
4155 
4156 	FOR_EACH_IN_TEAM(pSoldier, OUR_TEAM)
4157 	{
4158 		SoldierSP soldier = GetSoldier(pSoldier);
4159 		if (pSoldier->bInSector)
4160 		{
4161 			if ( pSoldier->uiStatusFlags & SOLDIER_MULTI_SELECTED )
4162 			{
4163 				// If we can't be controlled, returninvalid...
4164 				if ( pSoldier->uiStatusFlags & SOLDIER_ROBOT )
4165 				{
4166 					if ( !CanRobotBeControlled( pSoldier ) )
4167 					{
4168 						continue;
4169 					}
4170 				}
4171 
4172 				pSoldier->fUIMovementFast  = fMoveFast;
4173 				pSoldier->usUIMovementMode =  GetMoveStateBasedOnStance( pSoldier, gAnimControl[ pSoldier->usAnimState ].ubEndHeight );
4174 
4175 				pSoldier->fUIMovementFast  = FALSE;
4176 
4177 				if ( gUIUseReverse )
4178 				{
4179 					pSoldier->bReverse = TRUE;
4180 				}
4181 				else
4182 				{
4183 					pSoldier->bReverse = FALSE;
4184 				}
4185 
4186 				soldier->removePendingAction();
4187 
4188 				if ( EVENT_InternalGetNewSoldierPath( pSoldier, sDestGridNo, pSoldier->usUIMovementMode , TRUE, pSoldier->fNoAPToFinishMove ) )
4189 				{
4190 					InternalDoMercBattleSound( pSoldier, BATTLE_SOUND_OK1, BATTLE_SND_LOWER_VOLUME );
4191 				}
4192 				else
4193 				{
4194 					ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, st_format_printf(TacticalStr[ NO_PATH_FOR_MERC ], pSoldier->name) );
4195 				}
4196 
4197 				fAtLeastOneMultiSelect = TRUE;
4198 			}
4199 		}
4200 	}
4201 	gfGetNewPathThroughPeople = FALSE;
4202 
4203 	return( fAtLeastOneMultiSelect );
4204 }
4205 
4206 
ResetMultiSelection()4207 void ResetMultiSelection( )
4208 {
4209 	FOR_EACH_IN_TEAM(s, OUR_TEAM)
4210 	{
4211 		if (s->bInSector && s->uiStatusFlags & SOLDIER_MULTI_SELECTED)
4212 		{
4213 			s->uiStatusFlags &= ~SOLDIER_MULTI_SELECTED;
4214 		}
4215 	}
4216 
4217 	gTacticalStatus.fAtLeastOneGuyOnMultiSelect = FALSE;
4218 }
4219 
4220 
UIHandleRubberBandOnTerrain(UI_EVENT * pUIEvent)4221 static ScreenID UIHandleRubberBandOnTerrain(UI_EVENT* pUIEvent)
4222 {
4223 	INT16   sScreenX, sScreenY;
4224 	INT32   iTemp;
4225 	SGPRect aRect;
4226 	BOOLEAN fAtLeastOne = FALSE;
4227 
4228 	guiNewUICursor = NO_UICURSOR;
4229 	//SetCurrentCursorFromDatabase( VIDEO_NO_CURSOR );
4230 
4231 	gRubberBandRect.iRight	= gusMouseXPos;
4232 	gRubberBandRect.iBottom	= gusMouseYPos;
4233 
4234 	// Copy into temp rect
4235 	aRect = gRubberBandRect;
4236 
4237 	if ( aRect.iRight < aRect.iLeft )
4238 	{
4239 		iTemp = aRect.iLeft;
4240 		aRect.iLeft = aRect.iRight;
4241 		aRect.iRight = iTemp;
4242 	}
4243 
4244 
4245 	if ( aRect.iBottom < aRect.iTop )
4246 	{
4247 		iTemp = aRect.iTop;
4248 		aRect.iTop = aRect.iBottom;
4249 		aRect.iBottom = iTemp;
4250 	}
4251 
4252 	// ATE:Check at least for one guy that's in point!
4253 	CFOR_EACH_IN_TEAM(s, OUR_TEAM)
4254 	{
4255 		// Check if this guy is OK to control....
4256 		if (OkControllableMerc(s) && !(s->uiStatusFlags & (SOLDIER_VEHICLE | SOLDIER_PASSENGER | SOLDIER_DRIVER)))
4257 		{
4258 			// Get screen pos of gridno......
4259 			GetGridNoScreenXY(s->sGridNo, &sScreenX, &sScreenY);
4260 
4261 			// ATE: If we are in a hiehger interface level, subttrasct....
4262 			if ( gsInterfaceLevel == 1 )
4263 			{
4264 				sScreenY -= 50;
4265 			}
4266 
4267 			if (IsPointInScreenRect(sScreenX, sScreenY, aRect))
4268 			{
4269 				fAtLeastOne = TRUE;
4270 			}
4271 		}
4272 	}
4273 
4274 	if ( !fAtLeastOne )
4275 	{
4276 		return( GAME_SCREEN );
4277 	}
4278 
4279 	// ATE: Now loop through our guys and see if any fit!
4280 	FOR_EACH_IN_TEAM(s, OUR_TEAM)
4281 	{
4282 		// Check if this guy is OK to control....
4283 		if (OkControllableMerc(s) && !(s->uiStatusFlags & (SOLDIER_VEHICLE | SOLDIER_PASSENGER | SOLDIER_DRIVER)))
4284 		{
4285 			if ( !_KeyDown( ALT ) )
4286 			{
4287 				s->uiStatusFlags &= ~SOLDIER_MULTI_SELECTED;
4288 			}
4289 
4290 			// Get screen pos of gridno......
4291 			GetGridNoScreenXY(s->sGridNo, &sScreenX, &sScreenY);
4292 
4293 			// ATE: If we are in a hiehger interface level, subttrasct....
4294 			if ( gsInterfaceLevel == 1 )
4295 			{
4296 				sScreenY -= 50;
4297 			}
4298 
4299 			if (IsPointInScreenRect(sScreenX, sScreenY, aRect))
4300 			{
4301 				// Adjust this guy's flag...
4302 				s->uiStatusFlags |= SOLDIER_MULTI_SELECTED;
4303 			}
4304 		}
4305 	}
4306 
4307 
4308 	return( GAME_SCREEN );
4309 }
4310 
4311 
UIHandleJumpOverOnTerrain(UI_EVENT * pUIEvent)4312 static ScreenID UIHandleJumpOverOnTerrain(UI_EVENT* pUIEvent)
4313 {
4314 	const SOLDIERTYPE* const sel = GetSelectedMan();
4315 	if (sel == NULL)
4316 		return GAME_SCREEN;
4317 
4318 	const GridNo usMapPos = GetMouseMapPos();
4319 	if (usMapPos == NOWHERE)
4320 		return GAME_SCREEN;
4321 
4322 	if (!IsValidJumpLocation(sel, usMapPos, FALSE))
4323 	{
4324 		guiPendingOverrideEvent = M_ON_TERRAIN;
4325 		return( GAME_SCREEN );
4326 	}
4327 
4328 	// Display APs....
4329 	gsCurrentActionPoints = GetAPsToJumpOver(sel);
4330 
4331 	gfUIDisplayActionPoints = TRUE;
4332 	gfUIDisplayActionPointsCenter = TRUE;
4333 
4334 	guiNewUICursor = JUMP_OVER_UICURSOR;
4335 
4336 	return( GAME_SCREEN );
4337 }
4338 
4339 
UIHandleJumpOver(UI_EVENT * pUIEvent)4340 static ScreenID UIHandleJumpOver(UI_EVENT* pUIEvent)
4341 {
4342 	// Here, first get map screen
4343 	SOLDIERTYPE* const sel = GetSelectedMan();
4344 	if (sel == NULL)
4345 		return GAME_SCREEN;
4346 
4347 	SoldierSP selSoldier = GetSoldier(sel);
4348 
4349 	const GridNo usMapPos = GetMouseMapPos();
4350 	if (usMapPos == NOWHERE)
4351 		return GAME_SCREEN;
4352 
4353 	if (!IsValidJumpLocation(sel, usMapPos, FALSE))
4354 		return GAME_SCREEN;
4355 
4356 	SetUIBusy(sel);
4357 
4358 	// OK, Start jumping!
4359 	// Remove any previous actions
4360 	selSoldier->removePendingAction();
4361 
4362 	// Get direction to goto....
4363 	const INT8 bDirection = GetDirectionFromGridNo(usMapPos, sel);
4364 
4365 	sel->fDontChargeTurningAPs = TRUE;
4366 	EVENT_SetSoldierDesiredDirection(sel, bDirection);
4367 	sel->fTurningUntilDone = TRUE;
4368 	// ATE: Reset flag to go back to prone...
4369 	//sel->fTurningFromPronePosition = TURNING_FROM_PRONE_OFF;
4370 	sel->usPendingAnimation = JUMP_OVER_BLOCKING_PERSON;
4371 
4372 	return( GAME_SCREEN );
4373 }
4374 
4375 
UIHandleLABeginLockOurTurn(UI_EVENT * pUIEvent)4376 static ScreenID UIHandleLABeginLockOurTurn(UI_EVENT* pUIEvent)
4377 {
4378 	// Don't let both versions of the locks to happen at the same time!
4379 	// ( They are mutually exclusive )!
4380 	UIHandleLUIEndLock( NULL );
4381 
4382 	if ( !gfUserTurnRegionActive )
4383 	{
4384 		gfUserTurnRegionActive = TRUE;
4385 
4386 		gfUIInterfaceSetBusy = TRUE;
4387 		guiUIInterfaceBusyTime = GetJA2Clock( );
4388 
4389 		//guiNewUICursor = NO_UICURSOR;
4390 		//SetCurrentCursorFromDatabase( VIDEO_NO_CURSOR );
4391 
4392 		MSYS_DefineRegion(&gUserTurnRegion, 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, MSYS_PRIORITY_HIGHEST, CURSOR_WAIT, MSYS_NO_CALLBACK, MSYS_NO_CALLBACK);
4393 
4394 		//guiPendingOverrideEvent = LOCKOURTURN_UI_MODE;
4395 
4396 		ErasePath();
4397 
4398 		// Pause time!
4399 		PauseGame();
4400 		LockPauseState(LOCK_PAUSE_LOCKOURTURN_UI_MODE);
4401 	}
4402 
4403 	return( GAME_SCREEN );
4404 }
4405 
4406 
UIHandleLAEndLockOurTurn(UI_EVENT * pUIEvent)4407 static ScreenID UIHandleLAEndLockOurTurn(UI_EVENT* pUIEvent)
4408 {
4409 	if ( gfUserTurnRegionActive )
4410 	{
4411 		gfUserTurnRegionActive = FALSE;
4412 
4413 		gfUIInterfaceSetBusy = FALSE;
4414 
4415 		// Add region
4416 		MSYS_RemoveRegion( &gUserTurnRegion );
4417 		RefreshMouseRegions( );
4418 		//SetCurrentCursorFromDatabase( guiCurrentUICursor );
4419 
4420 		gfPlotNewMovement = TRUE;
4421 
4422 		guiForceRefreshMousePositionCalculation = TRUE;
4423 		UIHandleMOnTerrain( NULL );
4424 
4425 		if ( gViewportRegion.uiFlags & MSYS_MOUSE_IN_AREA )
4426 		{
4427 			SetCurrentCursorFromDatabase( gUICursors[ guiNewUICursor ].usFreeCursorName );
4428 		}
4429 		guiPendingOverrideEvent = M_ON_TERRAIN;
4430 		HandleTacticalUI( );
4431 
4432 		TurnOffTeamsMuzzleFlashes( OUR_TEAM );
4433 
4434 		// UnPause time!
4435 		UnLockPauseState();
4436 		UnPauseGame();
4437 	}
4438 
4439 	return( GAME_SCREEN );
4440 }
4441 
4442 
GetValidTalkableNPCFromMouse(BOOLEAN fGive,BOOLEAN fAllowMercs,BOOLEAN fCheckCollapsed)4443 SOLDIERTYPE* GetValidTalkableNPCFromMouse(BOOLEAN fGive, BOOLEAN fAllowMercs, BOOLEAN fCheckCollapsed)
4444 {
4445 	// Check if there is a guy here to talk to!
4446 	SOLDIERTYPE* const tgt = gUIFullTarget;
4447 	if (tgt == NULL)
4448 		return NULL;
4449 	if (!IsValidTalkableNPC(tgt, fGive, fAllowMercs, fCheckCollapsed))
4450 		return NULL;
4451 	return tgt;
4452 }
4453 
4454 
IsValidTalkableNPC(const SOLDIERTYPE * pSoldier,BOOLEAN fGive,BOOLEAN fAllowMercs,BOOLEAN fCheckCollapsed)4455 BOOLEAN IsValidTalkableNPC(const SOLDIERTYPE* pSoldier, BOOLEAN fGive, BOOLEAN fAllowMercs, BOOLEAN fCheckCollapsed)
4456 {
4457 	BOOLEAN fValidGuy = FALSE;
4458 
4459 	const SOLDIERTYPE* const sel = GetSelectedMan();
4460 	if (sel != NULL && AM_A_ROBOT(sel)) return FALSE;
4461 
4462 	// CHECK IF ACTIVE!
4463 	if ( !pSoldier->bActive )
4464 	{
4465 		return( FALSE );
4466 	}
4467 
4468 	// CHECK IF DEAD
4469 	if( pSoldier->bLife == 0 )
4470 	{
4471 		return( FALSE );
4472 	}
4473 
4474 	if ( pSoldier->bCollapsed && fCheckCollapsed )
4475 	{
4476 		return( FALSE );
4477 	}
4478 
4479 	if ( pSoldier->uiStatusFlags & SOLDIER_VEHICLE )
4480 	{
4481 		return( FALSE );
4482 	}
4483 
4484 
4485 	// IF BAD GUY - CHECK VISIVILITY
4486 	if ( pSoldier->bTeam != OUR_TEAM )
4487 	{
4488 		if ( pSoldier->bVisible == -1 && !(gTacticalStatus.uiFlags&SHOW_ALL_MERCS) )
4489 		{
4490 			return( FALSE  );
4491 		}
4492 	}
4493 
4494 	if (pSoldier->ubProfile != NO_PROFILE && MercProfile(pSoldier->ubProfile).isNPCorRPC() &&
4495 		!RPC_RECRUITED(pSoldier) && !AM_AN_EPC(pSoldier))
4496 	{
4497 		fValidGuy = TRUE;
4498 	}
4499 
4500 	// Check for EPC...
4501 	if (pSoldier->ubProfile != NO_PROFILE && (gCurrentUIMode == TALKCURSOR_MODE || fGive)  && AM_AN_EPC(pSoldier))
4502 	{
4503 		fValidGuy = TRUE;
4504 	}
4505 
4506 	// ATE: We can talk to our own teammates....
4507 	if ( pSoldier->bTeam == OUR_TEAM && fAllowMercs  )
4508 	{
4509 		fValidGuy = TRUE;
4510 	}
4511 
4512 	if ( GetCivType( pSoldier ) != CIV_TYPE_NA && !fGive )
4513 	{
4514 		fValidGuy = TRUE;
4515 	}
4516 
4517 	// Alright, let's do something special here for robot...
4518 	if ( pSoldier->uiStatusFlags & SOLDIER_ROBOT )
4519 	{
4520 		// Can't talk to robots!
4521 		if (!fGive) fValidGuy = FALSE;
4522 	}
4523 
4524 	// OK, check if they are stationary or not....
4525 	// Do some checks common to all..
4526 	if ( fValidGuy )
4527 	{
4528 		if ((gAnimControl[pSoldier->usAnimState].uiFlags & ANIM_MOVING) &&
4529 			!(gTacticalStatus.uiFlags & INCOMBAT))
4530 		{
4531 			return( FALSE );
4532 		}
4533 
4534 		return( TRUE );
4535 	}
4536 
4537 	return( FALSE );
4538 }
4539 
4540 
HandleTalkInit()4541 BOOLEAN HandleTalkInit(  )
4542 {
4543 	INT16 sAPCost;
4544 	UINT8 ubNewDirection;
4545 	UINT8 ubQuoteNum;
4546 	UINT8 ubDiceRoll;
4547 
4548 	SOLDIERTYPE* const sel = GetSelectedMan();
4549 	if (sel == NULL)
4550 		return FALSE;
4551 
4552 	SoldierSP selSoldier = GetSoldier(sel);
4553 
4554 	const GridNo usMapPos = GetMouseMapPos();
4555 	if (usMapPos == NOWHERE)
4556 		return FALSE;
4557 
4558 	// Check if there is a guy here to talk to!
4559 	const SOLDIERTYPE* const pTSoldier = gUIFullTarget;
4560 	if (pTSoldier != NULL)
4561 	{
4562 		// Is he a valid NPC?
4563 		if (IsValidTalkableNPC(pTSoldier, FALSE, TRUE, FALSE))
4564 		{
4565 			if (pTSoldier != sel)
4566 			{
4567 				//ATE: Check if we have good LOS
4568 				// is he close enough to see that gridno if he turns his head?
4569 				const INT16 sDistVisible = DistanceVisible(sel, DIRECTION_IRRELEVANT, DIRECTION_IRRELEVANT, pTSoldier->sGridNo, pTSoldier->bLevel);
4570 
4571 				// Check LOS!
4572 				if (!SoldierTo3DLocationLineOfSightTest(sel, pTSoldier->sGridNo,  pTSoldier->bLevel, 3, sDistVisible, TRUE))
4573 				{
4574 					if ( pTSoldier->ubProfile != NO_PROFILE )
4575 					{
4576 						ScreenMsg(FONT_MCOLOR_LTYELLOW, MSG_UI_FEEDBACK, st_format_printf(TacticalStr[NO_LOS_TO_TALK_TARGET], sel->name, pTSoldier->name));
4577 					}
4578 					else
4579 					{
4580 						ScreenMsg(FONT_MCOLOR_LTYELLOW, MSG_UI_FEEDBACK, st_format_printf(gzLateLocalizedString[STR_LATE_45], sel->name));
4581 					}
4582 					return( FALSE );
4583 				}
4584 			}
4585 
4586 			if ( pTSoldier->bCollapsed )
4587 			{
4588 				ScreenMsg(FONT_MCOLOR_LTYELLOW, MSG_UI_FEEDBACK,
4589 						st_format_printf(gzLateLocalizedString[STR_LATE_21], pTSoldier->name));
4590 				return( FALSE );
4591 			}
4592 
4593 			// If Q on, turn off.....
4594 			if ( guiCurrentScreen == DEBUG_SCREEN )
4595 			{
4596 				gfExitDebugScreen = TRUE;
4597 			}
4598 
4599 			// ATE: if our own guy...
4600 			if ( pTSoldier->bTeam == OUR_TEAM && !AM_AN_EPC( pTSoldier ) )
4601 			{
4602 				if ( pTSoldier->ubProfile == DIMITRI )
4603 				{
4604 					ScreenMsg(FONT_MCOLOR_LTYELLOW, MSG_UI_FEEDBACK, st_format_printf(gzLateLocalizedString[STR_LATE_32], pTSoldier->name));
4605 					return( FALSE );
4606 				}
4607 
4608 				// Randomize quote to use....
4609 
4610 				// If buddy had a social trait...
4611 				if ( gMercProfiles[ pTSoldier->ubProfile ].bAttitude != ATT_NORMAL )
4612 				{
4613 					ubDiceRoll = (UINT8)Random( 3 );
4614 				}
4615 				else
4616 				{
4617 					ubDiceRoll = (UINT8)Random( 2 );
4618 				}
4619 
4620 				// If we are a PC, only use 0
4621 				if ( pTSoldier->ubWhatKindOfMercAmI == MERC_TYPE__PLAYER_CHARACTER )
4622 				{
4623 					ubDiceRoll = 0;
4624 				}
4625 
4626 				switch( ubDiceRoll )
4627 				{
4628 					case 0:
4629 
4630 						ubQuoteNum = QUOTE_NEGATIVE_COMPANY;
4631 						break;
4632 
4633 					case 1:
4634 
4635 						if ( QuoteExp_PassingDislike[ pTSoldier->ubProfile ] )
4636 						{
4637 							ubQuoteNum = QUOTE_PASSING_DISLIKE;
4638 						}
4639 						else
4640 						{
4641 							ubQuoteNum = QUOTE_NEGATIVE_COMPANY;
4642 						}
4643 						break;
4644 
4645 					case 2:
4646 
4647 						ubQuoteNum = QUOTE_SOCIAL_TRAIT;
4648 						break;
4649 
4650 					default:
4651 
4652 						ubQuoteNum = QUOTE_NEGATIVE_COMPANY;
4653 						break;
4654 				}
4655 
4656 				if ( pTSoldier->ubProfile == IRA )
4657 				{
4658 					ubQuoteNum = QUOTE_PASSING_DISLIKE;
4659 				}
4660 
4661 				TacticalCharacterDialogue( pTSoldier, ubQuoteNum );
4662 
4663 				return( FALSE );
4664 			}
4665 
4666 			// Check distance
4667 			const UINT32 uiRange = GetRangeFromGridNoDiff(sel->sGridNo, usMapPos);
4668 
4669 			// Double check path
4670 			if ( GetCivType( pTSoldier ) != CIV_TYPE_NA )
4671 			{
4672 				// ATE: If one is already active, just remove it!
4673 				if ( ShutDownQuoteBoxIfActive( ) )
4674 				{
4675 					return( FALSE );
4676 				}
4677 			}
4678 
4679 			if ( uiRange > NPC_TALK_RADIUS )
4680 			{
4681 				// First get an adjacent gridno....
4682 				const INT16 sActionGridNo = FindAdjacentGridEx(sel, pTSoldier->sGridNo, NULL, NULL, FALSE, TRUE);
4683 
4684 				if ( sActionGridNo == -1 )
4685 				{
4686 					ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_UI_FEEDBACK, TacticalStr[ NO_PATH ] );
4687 					return( FALSE );
4688 				}
4689 
4690 				if (UIPlotPath(sel, sActionGridNo, NO_COPYROUTE, FALSE, sel->usUIMovementMode, sel->bActionPoints) == 0)
4691 				{
4692 					ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_UI_FEEDBACK, TacticalStr[ NO_PATH ] );
4693 					return( FALSE );
4694 				}
4695 
4696 				// Walk up and talk to buddy....
4697 				gfNPCCircularDistLimit = TRUE;
4698 				const INT16 sGoodGridNo = FindGridNoFromSweetSpotWithStructData(sel, sel->usUIMovementMode, pTSoldier->sGridNo, NPC_TALK_RADIUS - 1, &ubNewDirection, TRUE);
4699 				gfNPCCircularDistLimit = FALSE;
4700 
4701 				// First calculate APs and validate...
4702 				sAPCost = AP_TALK;
4703 
4704 				// Check AP cost...
4705 				if (!EnoughPoints(sel, sAPCost, 0, TRUE))
4706 				{
4707 					return( FALSE );
4708 				}
4709 
4710 				// Now walkup to talk....
4711 				selSoldier->setPendingAction(MERC_TALK);
4712 				sel->uiPendingActionData1 = pTSoldier->ubID;
4713 
4714 				// WALK UP TO DEST FIRST
4715 				EVENT_InternalGetNewSoldierPath(sel, sGoodGridNo, sel->usUIMovementMode, TRUE, sel->fNoAPToFinishMove);
4716 
4717 				return( FALSE );
4718 			}
4719 			else
4720 			{
4721 				sAPCost = AP_TALK;
4722 
4723 				// Check AP cost...
4724 				if (!EnoughPoints(sel, sAPCost, 0, TRUE))
4725 				{
4726 					return( FALSE );
4727 				}
4728 
4729 				// OK, startup!
4730 				PlayerSoldierStartTalking(sel, pTSoldier->ubID, FALSE);
4731 			}
4732 
4733 			if ( GetCivType( pTSoldier ) != CIV_TYPE_NA )
4734 			{
4735 				return( FALSE );
4736 			}
4737 			else
4738 			{
4739 				return( TRUE );
4740 			}
4741 		}
4742 	}
4743 
4744 	return( FALSE );
4745 }
4746 
4747 
SetUIBusy(const SOLDIERTYPE * const s)4748 void SetUIBusy(const SOLDIERTYPE* const s)
4749 {
4750 	if ((gTacticalStatus.uiFlags & INCOMBAT) && (gTacticalStatus.ubCurrentTeam == OUR_TEAM))
4751 	{
4752 		if (s == GetSelectedMan())
4753 		{
4754 			guiPendingOverrideEvent	= LA_BEGINUIOURTURNLOCK;
4755 			HandleTacticalUI( );
4756 		}
4757 	}
4758 }
4759 
4760 
UnSetUIBusy(const SOLDIERTYPE * const s)4761 void UnSetUIBusy(const SOLDIERTYPE* const s)
4762 {
4763 	if ((gTacticalStatus.uiFlags & INCOMBAT) && (gTacticalStatus.ubCurrentTeam == OUR_TEAM ))
4764 	{
4765 		if ( !gTacticalStatus.fUnLockUIAfterHiddenInterrupt )
4766 		{
4767 			if (s == GetSelectedMan())
4768 			{
4769 				guiPendingOverrideEvent	= LA_ENDUIOUTURNLOCK;
4770 				HandleTacticalUI( );
4771 
4772 				// Set grace period...
4773 				gTacticalStatus.uiTactialTurnLimitClock = GetJA2Clock( );
4774 			}
4775 		}
4776 		// player getting control back so reset all muzzle flashes
4777 	}
4778 }
4779 
4780 
BeginDisplayTimedCursor(UICursorID const uiCursorID,UINT32 const uiDelay)4781 void BeginDisplayTimedCursor(UICursorID const uiCursorID, UINT32 const uiDelay)
4782 {
4783 	gfDisplayTimerCursor = TRUE;
4784 	guiTimerCursorID = uiCursorID;
4785 	guiTimerLastUpdate = GetJA2Clock( );
4786 	guiTimerCursorDelay = uiDelay;
4787 }
4788 
4789 
UIHandleInteractiveTilesAndItemsOnTerrain(SOLDIERTYPE * const pSoldier,INT16 const usMapPos,BOOLEAN const fUseOKCursor,BOOLEAN const fItemsOnlyIfOnIntTiles)4790 static bool UIHandleInteractiveTilesAndItemsOnTerrain(SOLDIERTYPE* const pSoldier, INT16 const usMapPos, BOOLEAN const fUseOKCursor, BOOLEAN const fItemsOnlyIfOnIntTiles)
4791 {
4792 	static BOOLEAN fOverPool  = FALSE;
4793 	static BOOLEAN fOverEnemy = FALSE;
4794 
4795 	MouseMoveState const uiCursorFlags = GetCursorMovementFlags();
4796 
4797 	// Default gridno to mouse pos
4798 	INT16 sActionGridNo = usMapPos;
4799 
4800 	// Look for being on a merc....
4801 	// Steal.....
4802 	UIHandleOnMerc(FALSE);
4803 
4804 	gfBeginVehicleCursor = FALSE;
4805 
4806 	SOLDIERTYPE const* const tgt = gUIFullTarget;
4807 	if (tgt)
4808 	{
4809 		if (OK_ENTERABLE_VEHICLE(tgt) && tgt->bVisible != -1)
4810 		{
4811 			// grab number of occupants in vehicles
4812 			if (!fItemsOnlyIfOnIntTiles)
4813 			{
4814 				guiNewUICursor = ENTER_VEHICLE_UICURSOR;
4815 				return true;
4816 			}
4817 			else if (!OKUseVehicle(tgt->ubProfile))
4818 			{
4819 				guiNewUICursor       = CANNOT_MOVE_UICURSOR;
4820 				gfBeginVehicleCursor = TRUE;
4821 				return true;
4822 			}
4823 			else if (GetNumberInVehicle(GetVehicle(tgt->bVehicleID)) == 0)
4824 			{
4825 				guiNewUICursor       = ENTER_VEHICLE_UICURSOR;
4826 				gfBeginVehicleCursor = TRUE;
4827 				return true;
4828 			}
4829 		}
4830 
4831 		if (!fItemsOnlyIfOnIntTiles &&
4832 			guiUIFullTargetFlags & ENEMY_MERC &&
4833 			!(guiUIFullTargetFlags & UNCONSCIOUS_MERC))
4834 		{
4835 			if (!fOverEnemy)
4836 			{
4837 				fOverEnemy        = TRUE;
4838 				gfPlotNewMovement = TRUE;
4839 			}
4840 
4841 			//Set UI CURSOR
4842 			guiNewUICursor = fUseOKCursor ||
4843 						(gTacticalStatus.uiFlags & INCOMBAT) ?
4844 						OKHANDCURSOR_UICURSOR : NORMALHANDCURSOR_UICURSOR;
4845 
4846 			HandleUIMovementCursor(pSoldier, uiCursorFlags, sActionGridNo, MOVEUI_TARGET_STEAL);
4847 
4848 			// Display action points
4849 			gfUIDisplayActionPoints = TRUE;
4850 
4851 			// Determine if we can afford!
4852 			if (!EnoughPoints(pSoldier, gsCurrentActionPoints, 0, FALSE))
4853 			{
4854 				gfUIDisplayActionPointsInvalid = TRUE;
4855 			}
4856 
4857 			return false;
4858 		}
4859 	}
4860 
4861 	if (fOverEnemy)
4862 	{
4863 		ErasePath();
4864 		fOverEnemy        = FALSE;
4865 		gfPlotNewMovement = TRUE;
4866 	}
4867 
4868 	// If we are over an interactive struct, adjust gridno to this....
4869 	INT16            sIntTileGridNo;
4870 	STRUCTURE*       pStructure;
4871 	LEVELNODE* const pIntTile = ConditionalGetCurInteractiveTileGridNoAndStructure(&sIntTileGridNo, &pStructure, FALSE);
4872 	gpInvTileThatCausedMoveConfirm = pIntTile;
4873 
4874 	if (pIntTile) sActionGridNo = sIntTileGridNo;
4875 
4876 	if (fItemsOnlyIfOnIntTiles && !pIntTile)
4877 	{
4878 		// If we want only on int tiles, and we have no int tiles, then ignore items!
4879 	}
4880 	else if (fItemsOnlyIfOnIntTiles && pIntTile && pStructure->fFlags & STRUCTURE_HASITEMONTOP)
4881 	{
4882 		// if in this mode, we don't want to automatically show hand cursor over items on strucutres
4883 	}
4884 	else if (pIntTile && pStructure->fFlags & STRUCTURE_SWITCH)
4885 	{
4886 		// We don't want switches messing around with items ever!
4887 	}
4888 	else if (pIntTile && pStructure->fFlags & STRUCTURE_ANYDOOR && (sActionGridNo != usMapPos || fItemsOnlyIfOnIntTiles))
4889 	{
4890 		// Next we look for if we are over a door and if the mouse position is != base door position, ignore items!
4891 	}
4892 	else
4893 	{
4894 		// Check if we are over an item pool
4895 		ITEM_POOL const* const pItemPool = GetItemPool(sActionGridNo, pSoldier->bLevel);
4896 		if (IsItemPoolVisible(pItemPool) ||
4897 			(gpWorldLevelData[sActionGridNo].uiFlags & MAPELEMENT_REVEALED &&
4898 			DoesItemPoolContainAnyHiddenItems(pItemPool)))
4899 		{
4900 			if (!fOverPool)
4901 			{
4902 				fOverPool         = TRUE;
4903 				gfPlotNewMovement = TRUE;
4904 			}
4905 
4906 			//Set UI CURSOR
4907 			guiNewUICursor = fUseOKCursor ||
4908 						(gTacticalStatus.uiFlags & INCOMBAT) ?
4909 						OKHANDCURSOR_UICURSOR : NORMALHANDCURSOR_UICURSOR;
4910 
4911 			HandleUIMovementCursor(pSoldier, uiCursorFlags, sActionGridNo, MOVEUI_TARGET_ITEMS);
4912 
4913 			// Display action points
4914 			gfUIDisplayActionPoints = TRUE;
4915 
4916 			if (gsOverItemsGridNo == sActionGridNo) gfPlotNewMovement = TRUE;
4917 
4918 			// Determine if we can afford!
4919 			if (!EnoughPoints(pSoldier, gsCurrentActionPoints, 0, FALSE))
4920 			{
4921 				gfUIDisplayActionPointsInvalid = TRUE;
4922 			}
4923 
4924 			return pIntTile != 0;
4925 		}
4926 	}
4927 
4928 	if (pIntTile)
4929 	{
4930 		if (fOverPool)
4931 		{
4932 			ErasePath();
4933 			fOverPool         = FALSE;
4934 			gfPlotNewMovement = TRUE;
4935 		}
4936 
4937 		HandleUIMovementCursor(pSoldier, uiCursorFlags, usMapPos, MOVEUI_TARGET_INTTILES);
4938 
4939 		guiNewUICursor = GetInteractiveTileCursor(guiNewUICursor, fUseOKCursor);
4940 		return true;
4941 	}
4942 	else if (!fItemsOnlyIfOnIntTiles)
4943 	{
4944 		// Let's at least show where the merc will walk to if they go here...
4945 		if (!fOverPool)
4946 		{
4947 			fOverPool         = TRUE;
4948 			gfPlotNewMovement = TRUE;
4949 		}
4950 
4951 		HandleUIMovementCursor(pSoldier, uiCursorFlags, sActionGridNo, MOVEUI_TARGET_ITEMS);
4952 
4953 		// Display action points
4954 		gfUIDisplayActionPoints = TRUE;
4955 
4956 		// Determine if we can afford!
4957 		if (!EnoughPoints(pSoldier, gsCurrentActionPoints, 0, FALSE))
4958 		{
4959 			gfUIDisplayActionPointsInvalid = TRUE;
4960 		}
4961 	}
4962 	return false;
4963 }
4964 
4965 
HandleTacticalUILoseCursorFromOtherScreen()4966 void HandleTacticalUILoseCursorFromOtherScreen( )
4967 {
4968 	SetUICursor(NO_UICURSOR);
4969 
4970 	gfTacticalForceNoCursor = TRUE;
4971 
4972 	ErasePath();
4973 
4974 	(*(GameScreens[GAME_SCREEN].HandleScreen))();
4975 
4976 	gfTacticalForceNoCursor = FALSE;
4977 
4978 	SetUICursor( guiCurrentUICursor );
4979 }
4980 
4981 
SelectedGuyInBusyAnimation()4982 BOOLEAN SelectedGuyInBusyAnimation( )
4983 {
4984 	const SOLDIERTYPE* const sel = GetSelectedMan();
4985 	if (sel == NULL) return FALSE;
4986 
4987 	return sel->usAnimState == LOB_ITEM                       ||
4988 		sel->usAnimState == THROW_ITEM                     ||
4989 		sel->usAnimState == PICKUP_ITEM                    ||
4990 		sel->usAnimState == DROP_ITEM                      ||
4991 		sel->usAnimState == OPEN_DOOR                      ||
4992 		sel->usAnimState == OPEN_STRUCT                    ||
4993 		sel->usAnimState == OPEN_STRUCT                    ||
4994 		sel->usAnimState == END_OPEN_DOOR                  ||
4995 		sel->usAnimState == END_OPEN_LOCKED_DOOR           ||
4996 		sel->usAnimState == ADJACENT_GET_ITEM              ||
4997 		sel->usAnimState == DROP_ADJACENT_OBJECT           ||
4998 		sel->usAnimState == OPEN_DOOR_CROUCHED             ||
4999 		sel->usAnimState == BEGIN_OPENSTRUCT_CROUCHED      ||
5000 		sel->usAnimState == CLOSE_DOOR_CROUCHED            ||
5001 		sel->usAnimState == OPEN_DOOR_CROUCHED             ||
5002 		sel->usAnimState == OPEN_STRUCT_CROUCHED           ||
5003 		sel->usAnimState == END_OPENSTRUCT_CROUCHED        ||
5004 		sel->usAnimState == END_OPEN_DOOR_CROUCHED         ||
5005 		sel->usAnimState == END_OPEN_LOCKED_DOOR_CROUCHED  ||
5006 		sel->usAnimState == END_OPENSTRUCT_LOCKED_CROUCHED ||
5007 		sel->usAnimState == BEGIN_OPENSTRUCT;
5008 }
5009 
5010 
ClimbUpOrDown()5011 void ClimbUpOrDown()
5012 {
5013 	SOLDIERTYPE* const s = GetSelectedMan();
5014 	if (s)
5015 	{
5016 		UINT8 direction;
5017 		if (FindHigherLevel(s, &direction))
5018 		{
5019 			BeginSoldierClimbUpRoof(s);
5020 		}
5021 		else
5022 		{
5023 			BeginSoldierClimbDownRoof(s);
5024 		}
5025 	}
5026 }
5027 
GotoHigherStance(SOLDIERTYPE * const s)5028 void GotoHigherStance(SOLDIERTYPE* const s)
5029 {
5030 	switch (gAnimControl[s->usAnimState].ubEndHeight)
5031 	{
5032 		case ANIM_STAND:
5033 			if (FindHigherLevel(s))
5034 				BeginSoldierClimbUpRoof(s);
5035 			break;
5036 		case ANIM_CROUCH:
5037 			HandleStanceChangeFromUIKeys(ANIM_STAND);
5038 			break;
5039 		case ANIM_PRONE:
5040 			HandleStanceChangeFromUIKeys(ANIM_CROUCH);
5041 			break;
5042 	}
5043 }
5044 
5045 
GotoLowerStance(SOLDIERTYPE * const s)5046 void GotoLowerStance(SOLDIERTYPE* const s)
5047 {
5048 	switch (gAnimControl[s->usAnimState].ubEndHeight)
5049 	{
5050 		case ANIM_STAND:
5051 			HandleStanceChangeFromUIKeys(ANIM_CROUCH);
5052 			break;
5053 		case ANIM_CROUCH:
5054 			HandleStanceChangeFromUIKeys(ANIM_PRONE);
5055 			break;
5056 		case ANIM_PRONE:
5057 			if (FindLowerLevel(s))
5058 				BeginSoldierClimbDownRoof(s);
5059 			break;
5060 	}
5061 }
5062 
SetInterfaceHeightLevel()5063 void SetInterfaceHeightLevel( )
5064 {
5065 	INT16 sHeight;
5066 	static INT16 sOldHeight = 0;
5067 	INT16 sGridNo;
5068 
5069 	if( gfBasement || gfCaves )
5070 	{
5071 		gsRenderHeight = 0;
5072 		sOldHeight = 0;
5073 
5074 		return;
5075 	}
5076 
5077 
5078 	// ATE: Use an entry point to determine what height to use....
5079 	if( gMapInformation.sNorthGridNo != -1 )
5080 		sGridNo = gMapInformation.sNorthGridNo;
5081 	else if( gMapInformation.sEastGridNo != -1 )
5082 		sGridNo = gMapInformation.sEastGridNo;
5083 	else if( gMapInformation.sSouthGridNo != -1 )
5084 		sGridNo = gMapInformation.sSouthGridNo;
5085 	else if( gMapInformation.sWestGridNo != -1 )
5086 		sGridNo = gMapInformation.sWestGridNo;
5087 	else
5088 	{
5089 		SLOGA("SetInterfaceHeightLevel: MapInformation seems corrupted");
5090 		return;
5091 	}
5092 
5093 
5094 	sHeight = gpWorldLevelData[ sGridNo ].sHeight;
5095 
5096 	if ( sHeight != sOldHeight )
5097 	{
5098 		gsRenderHeight = sHeight;
5099 
5100 		if ( gsInterfaceLevel > 0 )
5101 		{
5102 			gsRenderHeight += ROOF_LEVEL_HEIGHT;
5103 		}
5104 
5105 		SetRenderFlags(RENDER_FLAG_FULL);
5106 		ErasePath();
5107 
5108 		sOldHeight = sHeight;
5109 	}
5110 }
5111 
5112 
ValidQuickExchangePosition(void)5113 BOOLEAN ValidQuickExchangePosition(void)
5114 {
5115 	BOOLEAN fOnValidGuy = FALSE;
5116 	static BOOLEAN fOldOnValidGuy = FALSE;
5117 
5118 	// Check if we over a civ
5119 	const SOLDIERTYPE* const pOverSoldier = gUIFullTarget;
5120 	if (pOverSoldier != NULL)
5121 	{
5122 		//KM: Replaced this older if statement for the new one which allows exchanging with militia
5123 		//if ((pOverSoldier->bSide != OUR_TEAM) && pOverSoldier->bNeutral)
5124 		if ((pOverSoldier->bTeam != OUR_TEAM && pOverSoldier->bNeutral) ||
5125 			(pOverSoldier->bTeam == MILITIA_TEAM && pOverSoldier->bSide == 0))
5126 		{
5127 			// hehe - don't allow animals to exchange places
5128 			if ( !( pOverSoldier->uiStatusFlags & ( SOLDIER_ANIMAL ) ) )
5129 			{
5130 				// OK, we have a civ , now check if they are near selected guy.....
5131 				SOLDIERTYPE* const sel = GetSelectedMan();
5132 				if (sel != NULL && PythSpacesAway(sel->sGridNo, pOverSoldier->sGridNo) == 1)
5133 				{
5134 					// Check if we have LOS to them....
5135 					const INT16 sDistVisible = DistanceVisible(sel, DIRECTION_IRRELEVANT, DIRECTION_IRRELEVANT, pOverSoldier->sGridNo, pOverSoldier->bLevel);
5136 					if (SoldierTo3DLocationLineOfSightTest(sel, pOverSoldier->sGridNo,  pOverSoldier->bLevel, 3, sDistVisible, TRUE))
5137 					{
5138 						// ATE:
5139 						// Check that the path is good!
5140 						if (FindBestPath(sel, pOverSoldier->sGridNo, sel->bLevel, sel->usUIMovementMode, NO_COPYROUTE, PATH_IGNORE_PERSON_AT_DEST) == 1)
5141 						{
5142 							fOnValidGuy = TRUE;
5143 						}
5144 					}
5145 				}
5146 			}
5147 		}
5148 	}
5149 
5150 	if ( fOldOnValidGuy != fOnValidGuy )
5151 	{
5152 		// Update timer....
5153 		// ATE: Adjust clock for automatic swapping so that the 'feel' is there....
5154 		guiUIInterfaceSwapCursorsTime	= GetJA2Clock( );
5155 		// Default it!
5156 		gfOKForExchangeCursor = TRUE;
5157 	}
5158 
5159 	// Update old value.....
5160 	fOldOnValidGuy = fOnValidGuy;
5161 
5162 	if ( !gfOKForExchangeCursor )
5163 	{
5164 		fOnValidGuy = FALSE;
5165 	}
5166 
5167 	return( fOnValidGuy );
5168 }
5169 
5170 
5171 // This function contains the logic for allowing the player
5172 // to jump over people.
IsValidJumpLocation(const SOLDIERTYPE * pSoldier,INT16 sGridNo,BOOLEAN fCheckForPath)5173 BOOLEAN IsValidJumpLocation(const SOLDIERTYPE* pSoldier, INT16 sGridNo, BOOLEAN fCheckForPath)
5174 {
5175 	INT16 sSpot, sIntSpot;
5176 	UINT8 sDirs[4] = { NORTH, EAST, SOUTH, WEST };
5177 	UINT8 cnt;
5178 	UINT8 ubMovementCost;
5179 
5180 	// First check that action point cost is zero so far
5181 	// ie: NO PATH!
5182 	if ( gsCurrentActionPoints != 0 && fCheckForPath )
5183 	{
5184 		return( FALSE );
5185 	}
5186 
5187 	// Loop through positions...
5188 	for (cnt = 0; cnt < 4; cnt++)
5189 	{
5190 		// MOVE OUT TWO DIRECTIONS
5191 		sIntSpot = NewGridNo( sGridNo, DirectionInc( sDirs[ cnt ] ) );
5192 
5193 		// ATE: Check our movement costs for going through walls!
5194 		ubMovementCost = gubWorldMovementCosts[ sIntSpot ][ sDirs[ cnt ] ][ pSoldier->bLevel ];
5195 		if ( IS_TRAVELCOST_DOOR( ubMovementCost ) )
5196 		{
5197 			ubMovementCost = DoorTravelCost(pSoldier, sIntSpot, ubMovementCost, pSoldier->bTeam == OUR_TEAM, NULL);
5198 		}
5199 
5200 		// If we have hit an obstacle, STOP HERE
5201 		if ( ubMovementCost >= TRAVELCOST_BLOCKED )
5202 		{
5203 			// no good, continue
5204 			continue;
5205 		}
5206 
5207 
5208 		// TWICE AS FAR!
5209 		sSpot = NewGridNo( sIntSpot, DirectionInc( sDirs[ cnt ] ) );
5210 
5211 		// Is the soldier we're looking at here?
5212 		if (WhoIsThere2(sSpot, pSoldier->bLevel) == pSoldier)
5213 		{
5214 			// Double check OK destination......
5215 			if ( NewOKDestination( pSoldier, sGridNo, TRUE, (INT8)gsInterfaceLevel ) )
5216 			{
5217 				// If the soldier in the middle of doing stuff?
5218 				if ( !pSoldier->fTurningUntilDone )
5219 				{
5220 					// OK, NOW check if there is a guy in between us
5221 					const SOLDIERTYPE* const guy_there = WhoIsThere2(sIntSpot, pSoldier->bLevel);
5222 
5223 					// Is there a guy and is he prone?
5224 					if (guy_there != NULL &&
5225 						guy_there != pSoldier &&
5226 						gAnimControl[guy_there->usAnimState].ubHeight == ANIM_PRONE)
5227 					{
5228 						// It's a GO!
5229 						return( TRUE );
5230 					}
5231 				}
5232 			}
5233 		}
5234 	}
5235 
5236 	return( FALSE );
5237 }
5238