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