1 #include "Handle_Items.h"
2 #include "Items.h"
3 #include "Soldier_Find.h"
4 #include "Structure.h"
5 #include "TileDef.h"
6 #include "Timer_Control.h"
7 #include "Weapons.h"
8 #include "Soldier_Control.h"
9 #include "Overhead.h"
10 #include "Handle_UI.h"
11 #include "Animation_Control.h"
12 #include "Points.h"
13 #include "Sound_Control.h"
14 #include "Isometric_Utils.h"
15 #include "Animation_Data.h"
16 #include "UI_Cursors.h"
17 #include "LOS.h"
18 #include "Interface.h"
19 #include "Cursors.h"
20 #include "Cursor_Control.h"
21 #include "Structure_Wrap.h"
22 #include "Physics.h"
23 #include "Soldier_Macros.h"
24 #include "Text.h"
25 #include "Interactive_Tiles.h"
26 #include "PathAI.h"
27 #include "Debug.h"
28
29 #include "ContentManager.h"
30 #include "GameInstance.h"
31
32 #include <string_theory/string>
33
34
35 // FUNCTIONS FOR ITEM CURSOR HANDLING
36 static UICursorID HandleActivatedTargetCursor( SOLDIERTYPE*, GridNo map_pos, BOOLEAN recalc);
37 static UICursorID HandleNonActivatedTargetCursor(SOLDIERTYPE*, GridNo map_pos, BOOLEAN show_APs, BOOLEAN fRecalc, MouseMoveState);
38 static UICursorID HandleKnifeCursor( SOLDIERTYPE*, GridNo map_pos, BOOLEAN activated, MouseMoveState);
39 static UICursorID HandlePunchCursor( SOLDIERTYPE*, GridNo map_pos, BOOLEAN activated, MouseMoveState);
40 static UICursorID HandleAidCursor( SOLDIERTYPE*, GridNo map_pos, BOOLEAN activated, MouseMoveState);
41 static UICursorID HandleActivatedTossCursor();
42 static UICursorID HandleNonActivatedTossCursor( SOLDIERTYPE*, GridNo map_pos, BOOLEAN recalc, MouseMoveState, ItemCursor);
43 static UICursorID HandleWirecutterCursor( SOLDIERTYPE*, GridNo map_pos, MouseMoveState);
44 static UICursorID HandleRepairCursor( SOLDIERTYPE*, GridNo map_pos, MouseMoveState);
45 static UICursorID HandleRefuelCursor( SOLDIERTYPE*, GridNo map_pos, MouseMoveState);
46 static UICursorID HandleRemoteCursor( SOLDIERTYPE*, BOOLEAN activated, MouseMoveState);
47 static UICursorID HandleBombCursor( SOLDIERTYPE*, GridNo map_pos, BOOLEAN activated, MouseMoveState);
48 static UICursorID HandleJarCursor( SOLDIERTYPE*, GridNo map_pos, MouseMoveState);
49 static UICursorID HandleTinCanCursor( SOLDIERTYPE*, GridNo map_pos, MouseMoveState);
50
51
52 static BOOLEAN gfCannotGetThrough = FALSE;
53 static BOOLEAN gfDisplayFullCountRing = FALSE;
54
55
GetMouseRecalcAndShowAPFlags(MouseMoveState * const puiCursorFlags,BOOLEAN * const pfShowAPs)56 BOOLEAN GetMouseRecalcAndShowAPFlags(MouseMoveState* const puiCursorFlags, BOOLEAN* const pfShowAPs)
57 {
58 static bool do_new_tile = false;
59
60 // Set flags for certain mouse movements
61 MouseMoveState const cursor_flags = GetCursorMovementFlags();
62 bool recalc = false;
63
64 // Force if we are currently cycling guys
65 if (gfUIForceReExamineCursorData)
66 {
67 do_new_tile = true;
68 recalc = true;
69 gfUIForceReExamineCursorData = FALSE;
70 }
71
72 bool show_APs = false;
73 if (cursor_flags != MOUSE_STATIONARY)
74 {
75 // If cursor was previously stationary, make the additional check of grid
76 // pos change
77 RESETCOUNTER(PATHFINDCOUNTER);
78 do_new_tile = true;
79 }
80 else if (COUNTERDONE(PATHFINDCOUNTER)) // Only dipslay aps after a delay
81 {
82 // Don't reset counter: One when we move again do we do this!
83 show_APs = true;
84
85 if (do_new_tile)
86 {
87 do_new_tile = false;
88 recalc = true;
89 }
90 }
91
92 if (puiCursorFlags) *puiCursorFlags = cursor_flags;
93 if (pfShowAPs) *pfShowAPs = show_APs;
94 return recalc;
95 }
96
97
98 // Functions for cursor determination
GetProperItemCursor(SOLDIERTYPE * const s,GridNo const map_pos,BOOLEAN const activated)99 UICursorID GetProperItemCursor(SOLDIERTYPE* const s, GridNo const map_pos, BOOLEAN const activated)
100 {
101 MouseMoveState cursor_flags;
102 BOOLEAN show_APs;
103 BOOLEAN const recalc = GetMouseRecalcAndShowAPFlags(&cursor_flags, &show_APs);
104
105 // ATE: Update attacking weapon!
106 // CC has added this attackingWeapon stuff and I need to update it constantly
107 // for CTGH algorithms
108 if (gTacticalStatus.ubAttackBusyCount == 0)
109 {
110 UINT16 const in_hand = s->inv[HANDPOS].usItem;
111 if (GCM->getItem(in_hand)->isWeapon()) s->usAttackingWeapon = in_hand;
112 }
113
114 UICursorID cursor = NO_UICURSOR;
115 SOLDIERTYPE const* const tgt = gUIFullTarget;
116 GridNo const tgt_grid_no = tgt ? tgt->sGridNo : map_pos;
117 ItemCursor const item_cursor = GetActionModeCursor(s);
118 switch (item_cursor)
119 {
120 case TARGETCURS:
121 cursor =
122 activated ? HandleActivatedTargetCursor(s, tgt_grid_no, recalc) :
123 HandleNonActivatedTargetCursor(s, tgt_grid_no, show_APs, recalc, cursor_flags);
124
125 if (gCurrentUIMode == ACTION_MODE &&
126 gTacticalStatus.uiFlags & INCOMBAT &&
127 recalc &&
128 tgt &&
129 IsValidTargetMerc(tgt) &&
130 EnoughAmmo(s, FALSE, HANDPOS) && // ATE: Check for ammo
131 guiUIFullTargetFlags & ENEMY_MERC && // IF it's an ememy, goto confirm action mode
132 guiUIFullTargetFlags & VISIBLE_MERC &&
133 !(guiUIFullTargetFlags & DEAD_MERC) &&
134 !gfCannotGetThrough)
135 {
136 guiPendingOverrideEvent = A_CHANGE_TO_CONFIM_ACTION;
137 }
138 break;
139
140 case TOSSCURS:
141 case TRAJECTORYCURS:
142 cursor = activated && gfUIHandlePhysicsTrajectory ? HandleActivatedTossCursor() :
143 HandleNonActivatedTossCursor(s, tgt_grid_no, recalc, cursor_flags, item_cursor);
144 break;
145
146 case PUNCHCURS: cursor = HandlePunchCursor( s, tgt_grid_no, activated, cursor_flags); break;
147 case KNIFECURS: cursor = HandleKnifeCursor( s, tgt_grid_no, activated, cursor_flags); break;
148 case AIDCURS: cursor = HandleAidCursor( s, map_pos, activated, cursor_flags); break;
149 case BOMBCURS: cursor = HandleBombCursor( s, tgt_grid_no, activated, cursor_flags); break;
150 case REMOTECURS: cursor = HandleRemoteCursor( s, activated, cursor_flags); break;
151 case WIRECUTCURS: cursor = HandleWirecutterCursor(s, tgt_grid_no, cursor_flags); break;
152 case REPAIRCURS: cursor = HandleRepairCursor( s, tgt_grid_no, cursor_flags); break;
153 case JARCURS: cursor = HandleJarCursor( s, tgt_grid_no, cursor_flags); break;
154 case TINCANCURS: cursor = HandleTinCanCursor( s, tgt_grid_no, cursor_flags); break;
155 case REFUELCURS: cursor = HandleRefuelCursor( s, tgt_grid_no, cursor_flags); break;
156 case INVALIDCURS: cursor = INVALID_ACTION_UICURSOR; break;
157 default:
158 break;
159 }
160
161 return cursor;
162 }
163
164
165 static void DetermineCursorBodyLocation(SOLDIERTYPE*, BOOLEAN fDisplay, BOOLEAN fRecalc);
166
167
HandleActivatedTargetCursor(SOLDIERTYPE * const s,GridNo const map_pos,BOOLEAN const recalc)168 static UICursorID HandleActivatedTargetCursor(SOLDIERTYPE* const s, GridNo const map_pos, BOOLEAN const recalc)
169 {
170 bool const is_throwing_knife = GCM->getItem(s->inv[HANDPOS].usItem)->getItemClass() == IC_THROWING_KNIFE;
171 if (is_throwing_knife)
172 {
173 // If we are in realtime, follow!
174 if (!(gTacticalStatus.uiFlags & INCOMBAT) &&
175 gAnimControl[s->usAnimState].uiFlags & ANIM_STATIONARY &&
176 gUITargetShotWaiting)
177 {
178 guiPendingOverrideEvent = CA_MERC_SHOOT;
179 }
180 }
181
182 // Determine where we are shooting/aiming
183 DetermineCursorBodyLocation(s, TRUE, TRUE);
184
185 bool enough_points = true;
186 bool max_point_limit_hit = false;
187 if (gTacticalStatus.uiFlags & INCOMBAT)
188 {
189 gsCurrentActionPoints = CalcTotalAPsToAttack(s, map_pos, TRUE, s->bShownAimTime / 2);
190 gfUIDisplayActionPoints = TRUE;
191 gfUIDisplayActionPointsCenter = TRUE;
192
193 // If we don't have any points and we are at the first refine, do nothing but warn!
194 if (!EnoughPoints(s, gsCurrentActionPoints, 0 , FALSE))
195 {
196 gfUIDisplayActionPointsInvalid = TRUE;
197 max_point_limit_hit = true;
198 }
199 else
200 {
201 UINT8 const future_aim = s->bShownAimTime + 2;
202 if (future_aim <= REFINE_AIM_5)
203 {
204 INT16 const AP_costs = MinAPsToAttack(s, map_pos, TRUE) + future_aim / 2;
205 if (!EnoughPoints(s, AP_costs, 0, FALSE))
206 {
207 enough_points = false;
208 }
209 }
210 }
211 }
212
213 if (!(gTacticalStatus.uiFlags & INCOMBAT) && COUNTERDONE(TARGETREFINE))
214 {
215 RESETCOUNTER(TARGETREFINE);
216
217 if (s->bDoBurst)
218 {
219 s->bShownAimTime = REFINE_AIM_BURST;
220 }
221 else
222 {
223 ++s->bShownAimTime;
224 if (s->bShownAimTime > REFINE_AIM_5)
225 {
226 s->bShownAimTime = REFINE_AIM_5;
227 }
228 else if (s->bShownAimTime % 2 != 0)
229 {
230 PlayJA2Sample(TARG_REFINE_BEEP, MIDVOLUME, 1, MIDDLEPAN);
231 }
232 }
233 }
234
235 if (recalc)
236 {
237 SOLDIERTYPE const* const tgt = gUIFullTarget;
238 UINT8 const chance =
239 tgt ? SoldierToSoldierBodyPartChanceToGetThrough(s, tgt, s->bAimShotLocation) :
240 SoldierToLocationChanceToGetThrough(s, map_pos, gsInterfaceLevel, s->bTargetCubeLevel, 0);
241 gfCannotGetThrough = chance < OK_CHANCE_TO_GET_THROUGH;
242 }
243
244 UICursorID cursor = NO_UICURSOR;
245 if (max_point_limit_hit)
246 {
247 // Check if we're in burst mode!
248 cursor = s->bDoBurst ? ACTION_TARGETREDBURST_UICURSOR :
249 is_throwing_knife ? RED_THROW_UICURSOR :
250 ACTION_TARGETRED_UICURSOR;
251 }
252 else if (s->bDoBurst)
253 {
254 cursor = s->fDoSpread ? ACTION_TARGETREDBURST_UICURSOR :
255 ACTION_TARGETCONFIRMBURST_UICURSOR;
256 }
257 else
258 {
259 switch (s->bShownAimTime)
260 {
261 case REFINE_AIM_1:
262 if (is_throwing_knife)
263 {
264 cursor = gfDisplayFullCountRing ? ACTION_THROWAIMYELLOW1_UICURSOR :
265 enough_points ? ACTION_THROWAIM1_UICURSOR :
266 ACTION_THROWAIMCANT1_UICURSOR;
267 }
268 else
269 {
270 cursor = gfDisplayFullCountRing ? ACTION_TARGETAIMYELLOW1_UICURSOR :
271 enough_points ? ACTION_TARGETAIM1_UICURSOR :
272 ACTION_TARGETAIMCANT1_UICURSOR;
273 }
274 break;
275
276 case REFINE_AIM_2:
277 if (is_throwing_knife)
278 {
279 cursor = gfDisplayFullCountRing ? ACTION_THROWAIMYELLOW2_UICURSOR :
280 enough_points ? ACTION_THROWAIM3_UICURSOR :
281 ACTION_THROWAIMCANT2_UICURSOR;
282 }
283 else
284 {
285 cursor = gfDisplayFullCountRing ? ACTION_TARGETAIMYELLOW2_UICURSOR :
286 enough_points ? ACTION_TARGETAIM3_UICURSOR :
287 ACTION_TARGETAIMCANT2_UICURSOR;
288 }
289 break;
290
291 case REFINE_AIM_3:
292 if (is_throwing_knife)
293 {
294 cursor = gfDisplayFullCountRing ? ACTION_THROWAIMYELLOW3_UICURSOR :
295 enough_points ? ACTION_THROWAIM5_UICURSOR :
296 ACTION_THROWAIMCANT3_UICURSOR;
297 }
298 else
299 {
300 cursor = gfDisplayFullCountRing ? ACTION_TARGETAIMYELLOW3_UICURSOR :
301 enough_points ? ACTION_TARGETAIM5_UICURSOR :
302 ACTION_TARGETAIMCANT3_UICURSOR;
303 }
304 break;
305
306 case REFINE_AIM_4:
307 if (is_throwing_knife)
308 {
309 cursor = gfDisplayFullCountRing ? ACTION_THROWAIMYELLOW4_UICURSOR :
310 enough_points ? ACTION_THROWAIM7_UICURSOR :
311 ACTION_THROWAIMCANT4_UICURSOR;
312 }
313 else
314 {
315 cursor = gfDisplayFullCountRing ? ACTION_TARGETAIMYELLOW4_UICURSOR :
316 enough_points ? ACTION_TARGETAIM7_UICURSOR :
317 ACTION_TARGETAIMCANT4_UICURSOR;
318 }
319 break;
320
321 case REFINE_AIM_5:
322 if (is_throwing_knife)
323 {
324 cursor = gfDisplayFullCountRing ? ACTION_THROWAIMFULL_UICURSOR :
325 enough_points ? ACTION_THROWAIM9_UICURSOR :
326 ACTION_THROWAIMCANT5_UICURSOR;
327 }
328 else
329 {
330 cursor = gfDisplayFullCountRing ? ACTION_TARGETAIMFULL_UICURSOR :
331 enough_points ? ACTION_TARGETAIM9_UICURSOR :
332 ACTION_TARGETAIMCANT5_UICURSOR;
333 }
334 break;
335
336 case REFINE_AIM_MID1: cursor = ACTION_TARGETAIM2_UICURSOR; break;
337 case REFINE_AIM_MID2: cursor = ACTION_TARGETAIM4_UICURSOR; break;
338 case REFINE_AIM_MID3: cursor = ACTION_TARGETAIM6_UICURSOR; break;
339 case REFINE_AIM_MID4: cursor = ACTION_TARGETAIM8_UICURSOR; break;
340 }
341 }
342
343 if (!max_point_limit_hit)
344 {
345 UINT16 const free_cursor_name = gUICursors[cursor].usFreeCursorName;
346 RemoveCursorFlags(free_cursor_name, CURSOR_TO_FLASH | CURSOR_TO_PLAY_SOUND);
347 if (gfCannotGetThrough)
348 {
349 SetCursorSpecialFrame(free_cursor_name, 1);
350 }
351 else if (!InRange(s, map_pos))
352 {
353 // OK, make buddy flash!
354 SetCursorFlags(free_cursor_name, CURSOR_TO_FLASH | CURSOR_TO_PLAY_SOUND);
355 }
356 else
357 {
358 SetCursorSpecialFrame(free_cursor_name, 0);
359 }
360 }
361
362 return cursor;
363 }
364
365
HandleNonActivatedTargetCursor(SOLDIERTYPE * const s,GridNo const map_pos,BOOLEAN const show_APs,BOOLEAN const fRecalc,MouseMoveState const uiCursorFlags)366 static UICursorID HandleNonActivatedTargetCursor(SOLDIERTYPE* const s, GridNo const map_pos, BOOLEAN const show_APs, BOOLEAN const fRecalc, MouseMoveState const uiCursorFlags)
367 {
368 bool const is_throwing_knife = GCM->getItem(s->inv[HANDPOS].usItem)->getItemClass() == IC_THROWING_KNIFE;
369 if (!is_throwing_knife)
370 {
371 if (!(gTacticalStatus.uiFlags & INCOMBAT))
372 {
373 DetermineCursorBodyLocation(GetSelectedMan(), show_APs, fRecalc);
374 }
375
376 if (!EnoughAmmo(s, FALSE, HANDPOS))
377 {
378 // Check if ANY ammo exists
379 if (FindAmmoToReload(s, HANDPOS, NO_SLOT) == NO_SLOT) return BAD_RELOAD_UICURSOR;
380
381 gsCurrentActionPoints = GetAPsToAutoReload(s);
382 gfUIDisplayActionPoints = TRUE;
383 return GOOD_RELOAD_UICURSOR;
384 }
385 }
386
387 if (gTacticalStatus.uiFlags & INCOMBAT)
388 {
389 DetermineCursorBodyLocation(GetSelectedMan(), show_APs, fRecalc);
390
391 gsCurrentActionPoints = CalcTotalAPsToAttack(s, map_pos, TRUE, s->bShownAimTime / 2);
392
393 gfUIDisplayActionPoints = TRUE;
394 gfUIDisplayActionPointsCenter = TRUE;
395
396 if (!show_APs)
397 {
398 gfUIDisplayActionPoints = FALSE;
399 }
400 else if (!EnoughPoints(s, gsCurrentActionPoints, 0 , FALSE))
401 {
402 gfUIDisplayActionPointsInvalid = TRUE;
403 }
404 }
405
406 if (fRecalc)
407 {
408 gfCannotGetThrough = SoldierToLocationChanceToGetThrough(s, map_pos, gsInterfaceLevel, s->bTargetCubeLevel, 0) < OK_CHANCE_TO_GET_THROUGH;
409 }
410
411 // If we begin to move, reset the cursor
412 if (uiCursorFlags != MOUSE_STATIONARY) gfCannotGetThrough = FALSE;
413
414 if (gfCannotGetThrough)
415 {
416 return s->bDoBurst ? ACTION_NOCHANCE_BURST_UICURSOR :
417 is_throwing_knife ? BAD_THROW_UICURSOR :
418 ACTION_NOCHANCE_SHOOT_UICURSOR;
419 }
420 else if (!InRange(s, map_pos))
421 {
422 // Flash cursor!
423 return s->bDoBurst ? ACTION_FLASH_BURST_UICURSOR :
424 is_throwing_knife ? FLASH_THROW_UICURSOR :
425 ACTION_FLASH_SHOOT_UICURSOR;
426 }
427 else
428 {
429 return s->bDoBurst ? ACTION_TARGETBURST_UICURSOR :
430 is_throwing_knife ? GOOD_THROW_UICURSOR :
431 ACTION_SHOOT_UICURSOR;
432 }
433 }
434
435
DetermineCursorBodyLocation(SOLDIERTYPE * const s,BOOLEAN const display,BOOLEAN const recalc)436 static void DetermineCursorBodyLocation(SOLDIERTYPE* const s, BOOLEAN const display, BOOLEAN const recalc)
437 {
438 if (gTacticalStatus.ubAttackBusyCount > 0)
439 {
440 // ATE: Return if attacker busy count > 0, this helps in RT with re-setting
441 // the flag to random
442 return;
443 }
444
445 if (recalc)
446 {
447 // Always set aim location to nothing
448 s->bAimShotLocation = AIM_SHOT_RANDOM;
449
450 GridNo const map_pos = GetMouseMapPos();
451 if (map_pos == NOWHERE) return;
452
453 SOLDIERTYPE* tgt = 0;
454 UINT16 flags;
455
456 // Determine which body part it's on
457 for (LEVELNODE* n = gpWorldLevelData[map_pos].pMercHead; n; n = n->pNext)
458 {
459 if (!(n->uiFlags & LEVELNODE_MERCPLACEHOLDER)) continue;
460
461 SOLDIERTYPE* const potential_tgt = n->pSoldier;
462 if (!potential_tgt) continue;
463
464 // ATE: Check their stance - if prone - return!
465 if (gAnimControl[potential_tgt->usAnimState].ubHeight == ANIM_PRONE)
466 {
467 return;
468 }
469
470 // Check if we have a half tile profile
471 flags = n->uiAnimHitLocationFlags;
472 if (flags & (TILE_FLAG_NORTH_HALF | TILE_FLAG_SOUTH_HALF | TILE_FLAG_WEST_HALF |
473 TILE_FLAG_EAST_HALF | TILE_FLAG_TOP_HALF | TILE_FLAG_BOTTOM_HALF))
474 {
475 INT16 sCellX;
476 INT16 sCellY;
477 GetMouseWorldCoords(&sCellX, &sCellY);
478 // We are only interested in the sub-tile coordinates
479 sCellX %= CELL_X_SIZE;
480 sCellY %= CELL_Y_SIZE;
481
482 if (flags & TILE_FLAG_NORTH_HALF && sCellY > CELL_Y_SIZE / 2) continue;
483 if (flags & TILE_FLAG_SOUTH_HALF && sCellY <= CELL_Y_SIZE / 2) continue;
484 if (flags & TILE_FLAG_WEST_HALF && sCellX > CELL_X_SIZE / 2) continue;
485 if (flags & TILE_FLAG_EAST_HALF && sCellX <= CELL_X_SIZE / 2) continue;
486
487 if (flags & TILE_FLAG_TOP_HALF)
488 {
489 INT16 sScreenX;
490 INT16 sScreenY;
491 FromCellToScreenCoordinates(sCellX, sCellY, &sScreenX, &sScreenY);
492
493 // Check for Below
494 if (sScreenX > WORLD_TILE_Y / 2) continue;
495 }
496
497 if (flags & TILE_FLAG_BOTTOM_HALF)
498 {
499 INT16 sScreenX;
500 INT16 sScreenY;
501 FromCellToScreenCoordinates(sCellX, sCellY, &sScreenX, &sScreenY);
502
503 // Check for Below
504 if (sScreenX <= WORLD_TILE_Y / 2) continue;
505 }
506 }
507
508 // Check if mouse is in bounding box of soldier
509 if (!IsPointInSoldierBoundingBox(potential_tgt, gusMouseXPos, gusMouseYPos))
510 {
511 continue;
512 }
513
514 tgt = potential_tgt;
515 break;
516 }
517
518 if (!tgt)
519 {
520 // Check if we can find a soldier here
521 SOLDIERTYPE* const potential_tgt = gUIFullTarget;
522 if (potential_tgt)
523 {
524 flags = FindRelativeSoldierPosition(potential_tgt, gusMouseXPos, gusMouseYPos);
525 if (flags != 0) tgt = potential_tgt;
526 }
527 }
528
529 if (tgt && IsValidTargetMerc(tgt))
530 {
531 if (flags & TILE_FLAG_FEET) s->bAimShotLocation = AIM_SHOT_LEGS;
532 if (flags & TILE_FLAG_MID) s->bAimShotLocation = AIM_SHOT_TORSO;
533 if (flags & TILE_FLAG_HEAD) s->bAimShotLocation = AIM_SHOT_HEAD;
534 }
535 }
536
537 if (!display) return;
538 if (s->bDoBurst) return;
539
540 SOLDIERTYPE* const tgt = gUIFullTarget;
541 if (!tgt) return;
542
543 ST::string hit_location;
544 if (tgt->ubBodyType == CROW)
545 {
546 s->bAimShotLocation = AIM_SHOT_LEGS;
547 hit_location = TacticalStr[CROW_HIT_LOCATION_STR];
548 }
549 else
550 {
551 if (!IS_MERC_BODY_TYPE(tgt)) return;
552
553 switch (s->bAimShotLocation)
554 {
555 case AIM_SHOT_HEAD:
556 hit_location = // If we have a knife in hand, change string
557 GCM->getItem(s->inv[HANDPOS].usItem)->getItemClass() == IC_BLADE ?
558 TacticalStr[NECK_HIT_LOCATION_STR] :
559 TacticalStr[HEAD_HIT_LOCATION_STR];
560 break;
561
562 case AIM_SHOT_TORSO: hit_location = TacticalStr[TORSO_HIT_LOCATION_STR]; break;
563 case AIM_SHOT_LEGS: hit_location = TacticalStr[LEGS_HIT_LOCATION_STR]; break;
564
565 default: return;
566 }
567 }
568 SetHitLocationText(hit_location);
569 }
570
571
HandleKnifeCursor(SOLDIERTYPE * const s,GridNo const map_pos,BOOLEAN const activated,MouseMoveState const uiCursorFlags)572 static UICursorID HandleKnifeCursor(SOLDIERTYPE* const s, GridNo const map_pos, BOOLEAN const activated, MouseMoveState const uiCursorFlags)
573 {
574 HandleUIMovementCursor(s, uiCursorFlags, map_pos, MOVEUI_TARGET_MERCS);
575
576 if (activated)
577 {
578 DetermineCursorBodyLocation(s, TRUE, TRUE);
579
580 if (gfUIHandleShowMoveGrid) gfUIHandleShowMoveGrid = 2;
581
582 // Calculate action points
583 bool enough_points = true;
584 if (gTacticalStatus.uiFlags & INCOMBAT)
585 {
586 gsCurrentActionPoints = CalcTotalAPsToAttack(s, map_pos, TRUE, s->bShownAimTime / 2);
587 gfUIDisplayActionPoints = TRUE;
588 gfUIDisplayActionPointsCenter = TRUE;
589
590 // If we don't have any points and we are at the first refine, do nothing but warn!
591 if (!EnoughPoints(s, gsCurrentActionPoints, 0, FALSE))
592 {
593 gfUIDisplayActionPointsInvalid = TRUE;
594 if (s->bShownAimTime == REFINE_KNIFE_1) return KNIFE_HIT_UICURSOR;
595 }
596
597 INT8 const future_aim = REFINE_KNIFE_2;
598 INT16 const ap_costs = CalcTotalAPsToAttack(s, map_pos, TRUE, future_aim / 2);
599 if (!EnoughPoints(s, ap_costs, 0, FALSE)) enough_points = false;
600 }
601
602 if (!(gTacticalStatus.uiFlags & INCOMBAT) && COUNTERDONE(NONGUNTARGETREFINE))
603 {
604 RESETCOUNTER(NONGUNTARGETREFINE);
605
606 if (s->bShownAimTime == REFINE_KNIFE_1)
607 {
608 PlayJA2Sample(TARG_REFINE_BEEP, MIDVOLUME, 1, MIDDLEPAN);
609 }
610
611 s->bShownAimTime = REFINE_KNIFE_2;
612 }
613
614 switch (s->bShownAimTime)
615 {
616 case REFINE_KNIFE_1:
617 return gfDisplayFullCountRing ? KNIFE_YELLOW_AIM1_UICURSOR :
618 enough_points ? KNIFE_HIT_AIM1_UICURSOR :
619 KNIFE_NOGO_AIM1_UICURSOR;
620
621 case REFINE_KNIFE_2:
622 return gfDisplayFullCountRing ? KNIFE_YELLOW_AIM2_UICURSOR :
623 enough_points ? KNIFE_HIT_AIM2_UICURSOR :
624 KNIFE_NOGO_AIM2_UICURSOR;
625
626 default:
627 Assert(FALSE);
628 // no return value!
629 return NO_UICURSOR;
630 }
631 }
632 else
633 {
634 gfUIDisplayActionPointsCenter = TRUE;
635
636 // Check if we are on a guy (who's not selected)!
637 if (gUIFullTarget && !(guiUIFullTargetFlags & SELECTED_MERC))
638 {
639 DetermineCursorBodyLocation(s, TRUE, TRUE);
640 return KNIFE_HIT_UICURSOR;
641 }
642 else
643 {
644 return KNIFE_REG_UICURSOR;
645 }
646 }
647 }
648
649
HandlePunchCursor(SOLDIERTYPE * const s,GridNo const map_pos,BOOLEAN const activated,MouseMoveState const uiCursorFlags)650 static UICursorID HandlePunchCursor(SOLDIERTYPE* const s, GridNo const map_pos, BOOLEAN const activated, MouseMoveState const uiCursorFlags)
651 {
652 HandleUIMovementCursor(s, uiCursorFlags, map_pos, MOVEUI_TARGET_MERCS);
653
654 if (activated)
655 {
656 DetermineCursorBodyLocation(s, TRUE, TRUE);
657
658 if (gfUIHandleShowMoveGrid) gfUIHandleShowMoveGrid = 2;
659
660 // Calculate action points
661 bool enough_points = true;
662
663 gsCurrentActionPoints = CalcTotalAPsToAttack(s, map_pos, TRUE, s->bShownAimTime / 2);
664 gfUIDisplayActionPoints = TRUE;
665 gfUIDisplayActionPointsCenter = TRUE;
666
667 // If we don't have any points and we are at the first refine, do nothing but warn!
668 if (!EnoughPoints(s, gsCurrentActionPoints, 0, FALSE))
669 {
670 gfUIDisplayActionPointsInvalid = TRUE;
671 if (s->bShownAimTime == REFINE_PUNCH_1) return ACTION_PUNCH_RED;
672 }
673
674 INT8 const future_aim = REFINE_PUNCH_2;
675 INT16 const ap_costs = CalcTotalAPsToAttack(s, map_pos, TRUE, future_aim / 2);
676 if (!EnoughPoints(s, ap_costs, 0, FALSE)) enough_points = false;
677
678 if (!(gTacticalStatus.uiFlags & INCOMBAT) && COUNTERDONE(NONGUNTARGETREFINE))
679 {
680 RESETCOUNTER(NONGUNTARGETREFINE);
681
682 if (s->bShownAimTime == REFINE_PUNCH_1)
683 {
684 PlayJA2Sample(TARG_REFINE_BEEP, MIDVOLUME, 1, MIDDLEPAN);
685 }
686
687 s->bShownAimTime = REFINE_PUNCH_2;
688 }
689
690 switch (s->bShownAimTime)
691 {
692 case REFINE_PUNCH_1:
693 return gfDisplayFullCountRing ? ACTION_PUNCH_YELLOW_AIM1_UICURSOR :
694 enough_points ? ACTION_PUNCH_RED_AIM1_UICURSOR :
695 ACTION_PUNCH_NOGO_AIM1_UICURSOR;
696
697 case REFINE_PUNCH_2:
698 return gfDisplayFullCountRing ? ACTION_PUNCH_YELLOW_AIM2_UICURSOR :
699 enough_points ? ACTION_PUNCH_RED_AIM2_UICURSOR :
700 ACTION_PUNCH_NOGO_AIM2_UICURSOR;
701
702 default:
703 Assert(FALSE);
704 // no return value!
705 return NO_UICURSOR;
706 }
707 }
708 else
709 {
710 gfUIDisplayActionPointsCenter = TRUE;
711
712 // Check if we are on a guy (who's not selected)!
713 if (gUIFullTarget && !(guiUIFullTargetFlags & SELECTED_MERC))
714 {
715 DetermineCursorBodyLocation(s, TRUE, TRUE);
716 return ACTION_PUNCH_RED;
717 }
718 else
719 {
720 return ACTION_PUNCH_GRAY;
721 }
722 }
723 }
724
725
HandleAidCursor(SOLDIERTYPE * const s,GridNo const map_pos,BOOLEAN const activated,MouseMoveState const uiCursorFlags)726 static UICursorID HandleAidCursor(SOLDIERTYPE* const s, GridNo const map_pos, BOOLEAN const activated, MouseMoveState const uiCursorFlags)
727 {
728 HandleUIMovementCursor(s, uiCursorFlags, map_pos, MOVEUI_TARGET_MERCSFORAID);
729 return activated || gUIFullTarget ? ACTION_FIRSTAID_RED : ACTION_FIRSTAID_GRAY;
730 }
731
732
HandleActivatedTossCursor()733 static UICursorID HandleActivatedTossCursor()
734 {
735 return ACTION_TOSS_UICURSOR;
736 }
737
738
HandleNonActivatedTossCursor(SOLDIERTYPE * const s,GridNo const map_pos,BOOLEAN const recalc,MouseMoveState const uiCursorFlags,ItemCursor const ubItemCursor)739 static UICursorID HandleNonActivatedTossCursor(SOLDIERTYPE* const s, GridNo const map_pos, BOOLEAN const recalc, MouseMoveState const uiCursorFlags, ItemCursor const ubItemCursor)
740 {
741 static bool bad_ctgh = false;
742
743 // Check for enough ammo
744 BOOLEAN armed = FALSE;
745 if (ubItemCursor == TRAJECTORYCURS)
746 {
747 if (!EnoughAmmo(s, FALSE, HANDPOS))
748 {
749 // Check if ANY ammo exists
750 if (FindAmmoToReload(s, HANDPOS, NO_SLOT) == NO_SLOT) return BAD_RELOAD_UICURSOR;
751
752 gsCurrentActionPoints = GetAPsToAutoReload(s);
753 gfUIDisplayActionPoints = TRUE;
754 return GOOD_RELOAD_UICURSOR;
755 }
756
757 armed = TRUE;
758 }
759
760 // Add APs
761 if (gTacticalStatus.uiFlags & INCOMBAT)
762 {
763 gsCurrentActionPoints =
764 ubItemCursor == TRAJECTORYCURS ? CalcTotalAPsToAttack(s, map_pos, TRUE, s->bShownAimTime / 2) :
765 MinAPsToThrow(*s, map_pos, TRUE);
766
767 gfUIDisplayActionPoints = TRUE;
768 gfUIDisplayActionPointsCenter = TRUE;
769
770 // If we don't have any points and we are at the first refine, do nothing
771 // but warn!
772 if (!EnoughPoints(s, gsCurrentActionPoints, 0, FALSE))
773 {
774 gfUIDisplayActionPointsInvalid = TRUE;
775 }
776 }
777
778 // If we begin to move, reset the cursor
779 if (uiCursorFlags != MOUSE_STATIONARY) EndPhysicsTrajectoryUI();
780
781 gfUIHandlePhysicsTrajectory = TRUE;
782
783 if (recalc)
784 {
785 // Calculate chance to throw here
786 if (map_pos == s->sGridNo)
787 {
788 bad_ctgh = false;
789 }
790 else
791 {
792 OBJECTTYPE const& o = s->inv[HANDPOS];
793 // ATE: Find the object to use
794 OBJECTTYPE TempObject = o;
795
796 // Do we have a launchable?
797 for (INT8 i = 0; i != MAX_ATTACHMENTS; ++i)
798 {
799 UINT16 const attach_item = o.usAttachItem[i];
800 if (attach_item == NOTHING) continue;
801 if (!(GCM->getItem(attach_item)->isExplosive())) continue;
802 CreateItem(attach_item, o.bAttachStatus[i], &TempObject);
803 break;
804 }
805
806 if (s->bWeaponMode == WM_ATTACHED)
807 {
808 INT8 const slot = FindAttachment(&o, UNDER_GLAUNCHER);
809 if (slot != NO_SLOT)
810 {
811 CreateItem(UNDER_GLAUNCHER, o.bAttachStatus[slot], &TempObject);
812 }
813 }
814
815 INT16 final_grid_no;
816 INT8 level;
817 bad_ctgh = !CalculateLaunchItemChanceToGetThrough(s, &TempObject, map_pos, gsInterfaceLevel, gsInterfaceLevel * 256, &final_grid_no, armed, &level, TRUE);
818 BeginPhysicsTrajectoryUI(final_grid_no, level, bad_ctgh);
819 }
820 }
821
822 return bad_ctgh ? BAD_THROW_UICURSOR : GOOD_THROW_UICURSOR;
823 }
824
825
HandleWirecutterCursor(SOLDIERTYPE * const s,GridNo const map_pos,MouseMoveState const uiCursorFlags)826 static UICursorID HandleWirecutterCursor(SOLDIERTYPE* const s, GridNo const map_pos, MouseMoveState const uiCursorFlags)
827 {
828 HandleUIMovementCursor(s, uiCursorFlags, map_pos, MOVEUI_TARGET_WIREFENCE);
829 return s->bLevel == 0 && IsCuttableWireFenceAtGridNo(map_pos) ? GOOD_WIRECUTTER_UICURSOR :
830 BAD_WIRECUTTER_UICURSOR;
831 }
832
833
HandleRepairCursor(SOLDIERTYPE * const s,GridNo const map_pos,MouseMoveState const uiCursorFlags)834 static UICursorID HandleRepairCursor(SOLDIERTYPE* const s, GridNo const map_pos, MouseMoveState const uiCursorFlags)
835 {
836 HandleUIMovementCursor(s, uiCursorFlags, map_pos, MOVEUI_TARGET_REPAIR);
837 return s->bLevel == 0 && IsRepairableStructAtGridNo(map_pos, 0) ? GOOD_REPAIR_UICURSOR :
838 BAD_REPAIR_UICURSOR;
839 }
840
841
HandleRefuelCursor(SOLDIERTYPE * const s,GridNo const map_pos,MouseMoveState const uiCursorFlags)842 static UICursorID HandleRefuelCursor(SOLDIERTYPE* const s, GridNo const map_pos, MouseMoveState const uiCursorFlags)
843 {
844 HandleUIMovementCursor(s, uiCursorFlags, map_pos, MOVEUI_TARGET_REFUEL);
845 return s->bLevel == 0 && GetRefuelableStructAtGridNo(map_pos) ? REFUEL_RED_UICURSOR :
846 REFUEL_GREY_UICURSOR;
847 }
848
849
HandleJarCursor(SOLDIERTYPE * const s,GridNo const map_pos,MouseMoveState const uiCursorFlags)850 static UICursorID HandleJarCursor(SOLDIERTYPE* const s, GridNo const map_pos, MouseMoveState const uiCursorFlags)
851 {
852 HandleUIMovementCursor(s, uiCursorFlags, map_pos, MOVEUI_TARGET_JAR);
853 return IsCorpseAtGridNo(map_pos, s->bLevel) ? GOOD_JAR_UICURSOR :
854 BAD_JAR_UICURSOR;
855 }
856
857
HandleTinCanCursor(SOLDIERTYPE * const s,GridNo const map_pos,MouseMoveState const uiCursorFlags)858 static UICursorID HandleTinCanCursor(SOLDIERTYPE* const s, GridNo const map_pos, MouseMoveState const uiCursorFlags)
859 {
860 HandleUIMovementCursor(s, uiCursorFlags, map_pos, MOVEUI_TARGET_CAN);
861
862 // Check if a door exists here
863 STRUCTURE* structure;
864 INT16 int_tile_grid_no;
865 LEVELNODE* const int_tile = GetCurInteractiveTileGridNoAndStructure(&int_tile_grid_no, &structure);
866 return int_tile && structure->fFlags & STRUCTURE_ANYDOOR ? PLACE_TINCAN_GREY_UICURSOR :
867 PLACE_TINCAN_RED_UICURSOR;
868 }
869
870
HandleRemoteCursor(SOLDIERTYPE * const s,BOOLEAN const activated,MouseMoveState const uiCursorFlags)871 static UICursorID HandleRemoteCursor(SOLDIERTYPE* const s, BOOLEAN const activated, MouseMoveState const uiCursorFlags)
872 {
873 if (gTacticalStatus.uiFlags & INCOMBAT)
874 {
875 gsCurrentActionPoints = GetAPsToUseRemote(s);
876 gfUIDisplayActionPoints = TRUE;
877 gfUIDisplayActionPointsCenter = TRUE;
878
879 // If we don't have any points and we are at the first refine, do nothing but warn!
880 if (!EnoughPoints(s, gsCurrentActionPoints, 0, FALSE))
881 {
882 gfUIDisplayActionPointsInvalid = TRUE;
883 }
884 }
885
886 return activated ? PLACE_REMOTE_RED_UICURSOR : PLACE_REMOTE_GREY_UICURSOR;
887 }
888
889
HandleBombCursor(SOLDIERTYPE * const s,GridNo const map_pos,BOOLEAN const activated,MouseMoveState const uiCursorFlags)890 static UICursorID HandleBombCursor(SOLDIERTYPE* const s, GridNo const map_pos, BOOLEAN const activated, MouseMoveState const uiCursorFlags)
891 {
892 HandleUIMovementCursor(s, uiCursorFlags, map_pos, MOVEUI_TARGET_BOMB);
893
894 if (gTacticalStatus.uiFlags & INCOMBAT)
895 {
896 gsCurrentActionPoints = GetTotalAPsToDropBomb(s, map_pos);
897 gfUIDisplayActionPoints = TRUE;
898 gfUIDisplayActionPointsCenter = TRUE;
899
900 // If we don't have any points and we are at the first refine, do nothing but warn!
901 if (!EnoughPoints(s, gsCurrentActionPoints, 0, FALSE))
902 {
903 gfUIDisplayActionPointsInvalid = TRUE;
904 }
905 }
906
907 return activated ? PLACE_BOMB_RED_UICURSOR : PLACE_BOMB_GREY_UICURSOR;
908 }
909
910
HandleLeftClickCursor(SOLDIERTYPE * pSoldier)911 void HandleLeftClickCursor( SOLDIERTYPE *pSoldier )
912 {
913 ItemCursor const ubItemCursor = GetActionModeCursor(pSoldier);
914
915 // OK, if we are i realtime.. goto directly to shoot
916 if (!(gTacticalStatus.uiFlags & INCOMBAT) &&
917 ubItemCursor != TOSSCURS && ubItemCursor != TRAJECTORYCURS)
918 {
919 // GOTO DIRECTLY TO USING ITEM
920 // ( only if not burst mode.. )
921 if ( !pSoldier->bDoBurst )
922 {
923 guiPendingOverrideEvent = CA_MERC_SHOOT;
924 }
925 return;
926 }
927
928 const GridNo sGridNo = GetMouseMapPos();
929 if (sGridNo == NOWHERE) return;
930
931 gfUIForceReExamineCursorData = TRUE;
932
933 gfDisplayFullCountRing = FALSE;
934
935 switch( ubItemCursor )
936 {
937 case TARGETCURS:
938 pSoldier->bShownAimTime = REFINE_AIM_1;
939
940 // Reset counter
941 RESETCOUNTER( TARGETREFINE );
942 break;
943
944 case PUNCHCURS:
945 pSoldier->bShownAimTime = REFINE_PUNCH_1;
946
947 // Reset counter
948 RESETCOUNTER( NONGUNTARGETREFINE );
949 break;
950
951
952 case KNIFECURS:
953 pSoldier->bShownAimTime = REFINE_KNIFE_1;
954
955 // Reset counter
956 RESETCOUNTER( NONGUNTARGETREFINE );
957 break;
958
959 default:
960 // GOTO DIRECTLY TO USING ITEM
961 guiPendingOverrideEvent = CA_MERC_SHOOT;
962 }
963 }
964
965
966
967
HandleRightClickAdjustCursor(SOLDIERTYPE * pSoldier,INT16 usMapPos)968 void HandleRightClickAdjustCursor( SOLDIERTYPE *pSoldier, INT16 usMapPos )
969 {
970 INT16 sAPCosts;
971 INT8 bFutureAim;
972 INT16 sGridNo;
973 INT8 bTargetLevel;
974
975 ItemCursor const ubCursor = GetActionModeCursor(pSoldier);
976
977 // 'snap' cursor to target tile....
978 if (gUIFullTarget != NULL) usMapPos = gUIFullTarget->sGridNo;
979
980 switch( ubCursor )
981 {
982 case TARGETCURS:
983
984 // CHECK IF GUY HAS IN HAND A WEAPON
985 if ( pSoldier->bDoBurst )
986 {
987 // Do nothing!
988 // pSoldier->bShownAimTime = REFINE_AIM_BURST;
989 }
990 else
991 {
992 sGridNo = usMapPos;
993 bTargetLevel = (INT8)gsInterfaceLevel;
994
995 // Look for a target here...
996 const SOLDIERTYPE* const tgt = gUIFullTarget;
997 if (tgt != NULL)
998 {
999 // Get target soldier, if one exists
1000 sGridNo = tgt->sGridNo;
1001 bTargetLevel = pSoldier->bLevel;
1002
1003 if (!HandleCheckForBadChangeToGetThrough(pSoldier, tgt, sGridNo, bTargetLevel))
1004 {
1005 return;
1006 }
1007 }
1008
1009 bFutureAim = (INT8)( pSoldier->bShownAimTime + 2 );
1010
1011 if ( bFutureAim <= REFINE_AIM_5 )
1012 {
1013 sAPCosts = CalcTotalAPsToAttack( pSoldier, usMapPos, TRUE, (INT8)(bFutureAim / 2) );
1014
1015 // Determine if we can afford!
1016 if ( EnoughPoints( pSoldier, sAPCosts, 0, FALSE ) )
1017 {
1018 pSoldier->bShownAimTime+= 2;
1019 if ( pSoldier->bShownAimTime > REFINE_AIM_5 )
1020 {
1021 pSoldier->bShownAimTime = REFINE_AIM_5;
1022 }
1023 }
1024 // Else - goto first level!
1025 else
1026 {
1027 if ( !gfDisplayFullCountRing )
1028 {
1029 gfDisplayFullCountRing = TRUE;
1030 }
1031 else
1032 {
1033 pSoldier->bShownAimTime = REFINE_AIM_1;
1034 gfDisplayFullCountRing = FALSE;
1035 }
1036 }
1037 }
1038 else
1039 {
1040 if ( !gfDisplayFullCountRing )
1041 {
1042 gfDisplayFullCountRing = TRUE;
1043 }
1044 else
1045 {
1046 pSoldier->bShownAimTime = REFINE_AIM_1;
1047 gfDisplayFullCountRing = FALSE;
1048 }
1049 }
1050 }
1051 break;
1052
1053
1054 case PUNCHCURS:
1055
1056 bFutureAim = (INT8)( pSoldier->bShownAimTime + REFINE_PUNCH_2 );
1057
1058 if ( bFutureAim <= REFINE_PUNCH_2 )
1059 {
1060 sAPCosts = CalcTotalAPsToAttack( pSoldier, usMapPos, TRUE, (INT8)(bFutureAim / 2) );
1061
1062 // Determine if we can afford!
1063 if ( EnoughPoints( pSoldier, sAPCosts, 0, FALSE ) )
1064 {
1065 pSoldier->bShownAimTime+= REFINE_PUNCH_2;
1066
1067 if ( pSoldier->bShownAimTime > REFINE_PUNCH_2 )
1068 {
1069 pSoldier->bShownAimTime = REFINE_PUNCH_2;
1070 }
1071 }
1072 // Else - goto first level!
1073 else
1074 {
1075 if ( !gfDisplayFullCountRing )
1076 {
1077 gfDisplayFullCountRing = TRUE;
1078 }
1079 else
1080 {
1081 pSoldier->bShownAimTime = REFINE_PUNCH_1;
1082 gfDisplayFullCountRing = FALSE;
1083 }
1084 }
1085 }
1086 else
1087 {
1088 if ( !gfDisplayFullCountRing )
1089 {
1090 gfDisplayFullCountRing = TRUE;
1091 }
1092 else
1093 {
1094 pSoldier->bShownAimTime = REFINE_PUNCH_1;
1095 gfDisplayFullCountRing = FALSE;
1096 }
1097 }
1098 break;
1099
1100
1101 case KNIFECURS:
1102
1103 bFutureAim = (INT8)( pSoldier->bShownAimTime + REFINE_KNIFE_2 );
1104
1105 if ( bFutureAim <= REFINE_KNIFE_2 )
1106 {
1107 sAPCosts = CalcTotalAPsToAttack( pSoldier, usMapPos, TRUE, (INT8)(bFutureAim / 2) );
1108
1109 // Determine if we can afford!
1110 if ( EnoughPoints( pSoldier, sAPCosts, 0, FALSE ) )
1111 {
1112 pSoldier->bShownAimTime+= REFINE_KNIFE_2;
1113
1114 if ( pSoldier->bShownAimTime > REFINE_KNIFE_2 )
1115 {
1116 pSoldier->bShownAimTime = REFINE_KNIFE_2;
1117 }
1118 }
1119 // Else - goto first level!
1120 else
1121 {
1122 if ( !gfDisplayFullCountRing )
1123 {
1124 gfDisplayFullCountRing = TRUE;
1125 }
1126 else
1127 {
1128 pSoldier->bShownAimTime = REFINE_KNIFE_1;
1129 gfDisplayFullCountRing = FALSE;
1130 }
1131 }
1132 }
1133 else
1134 {
1135 if ( !gfDisplayFullCountRing )
1136 {
1137 gfDisplayFullCountRing = TRUE;
1138 }
1139 else
1140 {
1141 pSoldier->bShownAimTime = REFINE_KNIFE_1;
1142 gfDisplayFullCountRing = FALSE;
1143 }
1144 }
1145 break;
1146
1147 case TOSSCURS: break;
1148
1149 default:
1150
1151 ErasePath();
1152
1153 }
1154
1155 }
1156
1157
GetActionModeCursor(SOLDIERTYPE const * const pSoldier)1158 ItemCursor GetActionModeCursor(SOLDIERTYPE const* const pSoldier)
1159 {
1160 UINT16 usInHand;
1161
1162 // If we are an EPC, do nothing....
1163 //if ( ( pSoldier->uiStatusFlags & SOLDIER_VEHICLE ) )
1164 //{
1165 // return( INVALIDCURS );
1166 //}
1167
1168 // AN EPC is always not - attackable unless they are a robot!
1169 if ( AM_AN_EPC( pSoldier ) && !( pSoldier->uiStatusFlags & SOLDIER_ROBOT ) )
1170 {
1171 return( INVALIDCURS );
1172 }
1173
1174 // ATE: if a vehicle.... same thing
1175 if ( pSoldier->uiStatusFlags & SOLDIER_VEHICLE )
1176 {
1177 return( INVALIDCURS );
1178 }
1179
1180 // If we can't be controlled, returninvalid...
1181 if ( pSoldier->uiStatusFlags & SOLDIER_ROBOT )
1182 {
1183 if ( !CanRobotBeControlled( pSoldier ) )
1184 {
1185 // Display message that robot cannot be controlled....
1186 return( INVALIDCURS );
1187 }
1188 }
1189
1190
1191 // If we are in attach shoot mode, use toss cursor...
1192 if (pSoldier->bWeaponMode == WM_ATTACHED )
1193 {
1194 return( TRAJECTORYCURS );
1195 }
1196
1197 usInHand = pSoldier->inv[HANDPOS].usItem;
1198
1199 // Start off with what is in our hand
1200 ItemCursor ubCursor = GCM->getItem(usInHand)->getCursor();
1201
1202 // OK, check if what is in our hands has a detonator attachment...
1203 // Detonators can only be on invalidcurs things...
1204 if ( ubCursor == INVALIDCURS )
1205 {
1206 if ( FindAttachment( &(pSoldier->inv[HANDPOS]), DETONATOR) != ITEM_NOT_FOUND )
1207 {
1208 ubCursor = BOMBCURS;
1209 }
1210 else if ( FindAttachment( &(pSoldier->inv[HANDPOS]), REMDETONATOR) != ITEM_NOT_FOUND )
1211 {
1212 ubCursor = BOMBCURS;
1213 }
1214 }
1215
1216 // Now check our terrain to see if we cannot do the action now...
1217 if ( pSoldier->bOverTerrainType == DEEP_WATER )
1218 {
1219 ubCursor = INVALIDCURS;
1220 }
1221
1222 // If we are out of breath, no cursor...
1223 if ( pSoldier->bBreath < OKBREATH && pSoldier->bCollapsed )
1224 {
1225 ubCursor = INVALIDCURS;
1226 }
1227
1228 return( ubCursor );
1229 }
1230
1231 // Switch on item, display appropriate feedback cursor for a click....
HandleUICursorRTFeedback(SOLDIERTYPE * pSoldier)1232 void HandleUICursorRTFeedback( SOLDIERTYPE *pSoldier )
1233 {
1234 ItemCursor const ubItemCursor = GetActionModeCursor(pSoldier);
1235 switch( ubItemCursor )
1236 {
1237 case TARGETCURS:
1238
1239 if ( pSoldier->bDoBurst )
1240 {
1241 //BeginDisplayTimedCursor( ACTION_TARGETREDBURST_UICURSOR, 500 );
1242 }
1243 else
1244 {
1245 if ( GCM->getItem(pSoldier->inv[ HANDPOS ].usItem)->getItemClass() == IC_THROWING_KNIFE )
1246 {
1247 BeginDisplayTimedCursor( RED_THROW_UICURSOR, 500 );
1248 }
1249 else
1250 {
1251 BeginDisplayTimedCursor( ACTION_TARGETRED_UICURSOR, 500 );
1252 }
1253 }
1254 break;
1255
1256 default:
1257
1258 break;
1259 }
1260
1261 }
1262