1 #include "Directories.h"
2 #include "Font.h"
3 #include "Interface_Control.h"
4 #include "Isometric_Utils.h"
5 #include "Local.h"
6 #include "Soldier_Ani.h"
7 #include "Timer_Control.h"
8 #include "VObject.h"
9 #include "SysUtil.h"
10 #include "Overhead.h"
11 #include "MouseSystem.h"
12 #include "Button_System.h"
13 #include "Interface.h"
14 #include "VSurface.h"
15 #include "Input.h"
16 #include "Handle_UI.h"
17 #include "RenderWorld.h"
18 #include "Cursors.h"
19 #include "Radar_Screen.h"
20 #include "Font_Control.h"
21 #include "Render_Dirty.h"
22 #include "Sound_Control.h"
23 #include "Interface_Panels.h"
24 #include "Animation_Control.h"
25 #include "Soldier_Control.h"
26 #include "PathAI.h"
27 #include "Weapons.h"
28 #include "Faces.h"
29 #include "MapScreen.h"
30 #include "Message.h"
31 #include "Text.h"
32 #include "Interface_Items.h"
33 #include "Interface_Utils.h"
34 #include "Game_Clock.h"
35 #include "Soldier_Macros.h"
36 #include "StrategicMap.h"
37 #include "Soldier_Functions.h"
38 #include "GameScreen.h"
39 #include "Assignments.h"
40 #include "Points.h"
41 #include "Squads.h"
42 #include "Strategic.h"
43 #include "Map_Screen_Interface_Map.h"
44 #include "Overhead_Map.h"
45 #include "Map_Screen_Interface.h"
46 #include "Options_Screen.h"
47 #include "ShopKeeper_Interface.h"
48 #include "English.h"
49 #include "Keys.h"
50 #include "Soldier_Add.h"
51 #include "Vehicles.h"
52 #include "GameSettings.h"
53 #include "Dialogue_Control.h"
54 #include "Items.h"
55 #include "Drugs_And_Alcohol.h"
56 #include "LOS.h"
57 #include "OppList.h"
58 #include "VObject_Blitters.h"
59 #include "Finances.h"
60 #include "LaptopSave.h"
61 #include "Cursor_Control.h"
62 #include "MessageBoxScreen.h"
63 #include "WordWrap.h"
64 #include "Boxing.h"
65 #include "Video.h"
66 #include "Debug.h"
67 #include "JAScreens.h"
68 #include "ScreenIDs.h"
69 #include "UILayout.h"
70 
71 #include "ContentManager.h"
72 #include "GameInstance.h"
73 #include "WeaponModels.h"
74 #include "Logger.h"
75 
76 #include "policy/GamePolicy.h"
77 #include "HImage.h"
78 
79 #include <string_theory/format>
80 #include <string_theory/string>
81 
82 #include <algorithm>
83 #include <iterator>
84 
85 // DEFINES FOR VARIOUS PANELS
86 #define SM_ITEMDESC_START_X			214
87 #define SM_ITEMDESC_START_Y			1 + INV_INTERFACE_START_Y
88 #define SM_ITEMDESC_HEIGHT			128
89 #define SM_ITEMDESC_WIDTH			314
90 
91 // SINGLE MERC SCREEN
92 
93 #define SM_SELMERC_AP_X			67
94 #define SM_SELMERC_AP_Y			53
95 #define SM_SELMERC_AP_HEIGHT			10
96 #define SM_SELMERC_AP_WIDTH			17
97 
98 #define SM_SELMERC_HEALTH_X			69
99 #define SM_SELMERC_HEALTH_Y			47
100 
101 #define SM_SELMERCNAME_X			11
102 #define SM_SELMERCNAME_Y			53
103 #define SM_SELMERCNAME_WIDTH			53
104 #define SM_SELMERCNAME_HEIGHT			10
105 
106 #define SM_SELMERC_FACE_X			13
107 #define SM_SELMERC_FACE_Y			6
108 #define SM_SELMERC_FACE_HEIGHT			42
109 #define SM_SELMERC_FACE_WIDTH			48
110 
111 #define SM_SELMERC_PLATE_X			4
112 #define SM_SELMERC_PLATE_Y			2
113 #define SM_SELMERC_PLATE_HEIGHT		65
114 #define SM_SELMERC_PLATE_WIDTH			83
115 
116 
117 #define STATS_TITLE_FONT_COLOR			6
118 #define STATS_TEXT_FONT_COLOR			5
119 
120 
121 #define SM_TALKB_X				155
122 #define SM_TALKB_Y				108
123 #define SM_MUTEB_X				91
124 #define SM_MUTEB_Y				108
125 #define SM_STANCEUPB_X				187
126 #define SM_STANCEUPB_Y				40
127 #define SM_UPDOWNB_X				91
128 #define SM_UPDOWNB_Y				73
129 #define SM_CLIMBB_X				187
130 #define SM_CLIMBB_Y				8
131 #define SM_STANCEDOWNB_X			187
132 #define SM_STANCEDOWNB_Y			108
133 #define SM_HANDCURSORB_X			123
134 #define SM_HANDCURSORB_Y			73
135 #define SM_PREVMERCB_X				9
136 #define SM_PREVMERCB_Y				70
137 #define SM_NEXTMERCB_X				51
138 #define SM_NEXTMERCB_Y				70
139 #define SM_OPTIONSB_X				9
140 #define SM_OPTIONSB_Y				105
141 #define SM_BURSTMODEB_X			155
142 #define SM_BURSTMODEB_Y			73
143 #define SM_LOOKB_X				123
144 #define SM_LOOKB_Y				108
145 #define SM_STEALTHMODE_X			187
146 #define SM_STEALTHMODE_Y			73
147 #define SM_DONE_X				543
148 #define SM_DONE_Y				4
149 #define SM_MAPSCREEN_X				589
150 #define SM_MAPSCREEN_Y				4
151 
152 
153 #define SM_PERCENT_WIDTH			20
154 #define SM_PERCENT_HEIGHT			10
155 #define SM_ARMOR_X				347
156 #define SM_ARMOR_Y				79
157 #define SM_ARMOR_LABEL_X			363
158 #define SM_ARMOR_LABEL_Y			69
159 #define SM_ARMOR_PERCENT_X			368
160 #define SM_ARMOR_PERCENT_Y			79
161 
162 #define SM_WEIGHT_LABEL_X			430
163 #define SM_WEIGHT_LABEL_Y			107
164 #define SM_WEIGHT_PERCENT_X			449
165 #define SM_WEIGHT_PERCENT_Y			106
166 #define SM_WEIGHT_X				428
167 #define SM_WEIGHT_Y				106
168 
169 #define SM_CAMO_LABEL_X			430
170 #define SM_CAMO_LABEL_Y			122
171 #define SM_CAMO_PERCENT_X			449
172 #define SM_CAMO_PERCENT_Y			121
173 #define SM_CAMO_X				428
174 #define SM_CAMO_Y				121
175 
176 
177 #define SM_STATS_WIDTH				30
178 #define SM_STATS_HEIGHT			8
179 #define SM_AGI_X				99
180 #define SM_AGI_Y				7
181 #define SM_DEX_X				99
182 #define SM_DEX_Y				17
183 #define SM_STR_X				99
184 #define SM_STR_Y				27
185 #define SM_CHAR_X				99
186 #define SM_CHAR_Y				37
187 #define SM_WIS_X				99
188 #define SM_WIS_Y				47
189 #define SM_EXPLVL_X				148
190 #define SM_EXPLVL_Y				7
191 #define SM_MRKM_X				148
192 #define SM_MRKM_Y				17
193 #define SM_EXPL_X				148
194 #define SM_EXPL_Y				27
195 #define SM_MECH_X				148
196 #define SM_MECH_Y				37
197 #define SM_MED_X				148
198 #define SM_MED_Y				47
199 
200 #define MONEY_X				460
201 #define MONEY_Y				105
202 #define MONEY_WIDTH				30
203 #define MONEY_HEIGHT				22
204 
205 #define TM_FACE_X				14
206 #define TM_FACE_Y				6
207 #define TM_FACE_WIDTH				48
208 #define TM_FACE_HEIGHT				43
209 
210 #define TM_ENDTURN_X				507
211 #define TM_ENDTURN_Y				9
212 #define TM_ROSTERMODE_X			507
213 #define TM_ROSTERMODE_Y			45
214 #define TM_DISK_X				507
215 #define TM_DISK_Y				81
216 
217 #define TM_NAME_X				11
218 #define TM_NAME_Y				53
219 #define TM_NAME_WIDTH				53
220 #define TM_NAME_HEIGHT				10
221 
222 #define TM_AP_X				67
223 #define TM_AP_Y				53
224 #define TM_AP_WIDTH				18
225 #define TM_AP_HEIGHT				10
226 
227 #define TM_LIFEBAR_HEIGHT			42
228 
229 #define TM_FACEHIGHTL_X			4
230 #define TM_FACEHIGHTL_Y			2
231 #define TM_FACEHIGHTL_WIDTH			84
232 #define TM_FACEHIGHTL_HEIGHT			114
233 
234 #define TM_INV_WIDTH				58
235 #define TM_INV_HEIGHT				23
236 #define TM_INV_HAND1STARTX			8
237 #define TM_INV_HAND1STARTY			67
238 #define TM_INV_HAND_SEP			83
239 #define TM_INV_HAND_SEPY			24
240 
241 #define TM_BARS_X				67
242 #define TM_BARS_Y				3
243 #define TM_BARS_WIDTH				19
244 #define TM_BARS_HEIGHT				47
245 
246 #define INDICATOR_BOX_WIDTH			12
247 #define INDICATOR_BOX_HEIGHT			10
248 
249 
250 enum
251 {
252 	STANCEUP_IMAGES = 0,
253 	UPDOWN_IMAGES,
254 	CLIMB_IMAGES,
255 	STANCEDOWN_IMAGES,
256 	HANDCURSOR_IMAGES,
257 	PREVMERC_IMAGES,
258 	NEXTMERC_IMAGES,
259 	OPTIONS_IMAGES,
260 	//BURSTMODE_IMAGES,
261 	LOOK_IMAGES,
262 	TALK_IMAGES,
263 	MUTE_IMAGES,
264 	STANCE_IMAGES,
265 	DONE_IMAGES,
266 	MAPSCREEN_IMAGES,
267 	NUM_SM_BUTTON_IMAGES
268 };
269 
270 
271 
272 enum
273 {
274 	ENDTURN_IMAGES = 0,
275 	ROSTERMODE_IMAGES,
276 	DISK_IMAGES,
277 	NUM_TEAM_BUTTON_IMAGES
278 };
279 
280 
281 static BUTTON_PICS* iSMPanelImages[NUM_SM_BUTTON_IMAGES];
282 static BUTTON_PICS* iBurstButtonImages[NUM_WEAPON_MODES];
283 static BUTTON_PICS* iTEAMPanelImages[NUM_TEAM_BUTTON_IMAGES];
284 
285 static BUTTON_PICS* giSMStealthImages;
286 GUIButtonRef giSMStealthButton;
287 
288 BOOLEAN gfUIStanceDifferent = FALSE;
289 static BOOLEAN gfAllDisabled = FALSE;
290 
291 BOOLEAN gfSMDisableForItems = FALSE;
292 
293 BOOLEAN gfDisableTacticalPanelButtons = FALSE;
294 
295 BOOLEAN gfCheckForMouseOverItem = FALSE;
296 UINT32 guiMouseOverItemTime = 0;
297 INT8 gbCheckForMouseOverItemPos = 0;
298 SOLDIERTYPE* gSelectSMPanelToMerc = NULL;
299 static BOOLEAN gfReEvaluateDisabledINVPanelButtons = FALSE;
300 
301 
302 UINT8 gubHandPos;
303 UINT16 gusOldItemIndex;
304 UINT16 gusNewItemIndex;
305 BOOLEAN gfDeductPoints;
306 
307 
308 GUIButtonRef iSMPanelButtons[NUM_SM_BUTTONS];
309 GUIButtonRef iTEAMPanelButtons[NUM_TEAM_BUTTONS];
310 
311 // Video Surface for Single Merc Panel
312 static SGPVObject* guiSMPanel;
313 static SGPVObject* guiSMObjects;
314 static SGPVObject* guiSMObjects2;
315 
316 static SGPVObject* guiTEAMPanel;
317 static SGPVObject* guiTEAMObjects;
318 static SGPVObject* guiVEHINV;
319 
320 static SGPVObject* guiCLOSE;
321 
322 // Globals for various mouse regions
323 static MOUSE_REGION gSM_SELMERCPanelRegion;
324 static MOUSE_REGION gSM_SELMERCBarsRegion;
325 MOUSE_REGION        gSM_SELMERCMoneyRegion;
326 static MOUSE_REGION gSM_SELMERCEnemyIndicatorRegion;
327 static MOUSE_REGION gTEAM_PanelRegion;
328 
329 
330 // Globals - for one - the current merc here
331 SOLDIERTYPE *gpSMCurrentMerc = NULL;
332 
333 MOUSE_REGION gSMPanelRegion;
334 
335 
336 struct TeamPanelSlot
337 {
338 	SOLDIERTYPE* merc;
339 	MOUSE_REGION face;
340 	MOUSE_REGION enemy_indicator;
341 	MOUSE_REGION bars;
342 	MOUSE_REGION left_bars;
343 	MOUSE_REGION first_hand;
344 	MOUSE_REGION second_hand;
345 };
346 
347 static TeamPanelSlot gTeamPanel[NUM_TEAM_SLOTS];
348 
349 #define FOR_EACH_TEAM_PANEL_SLOT(iter)		FOR_EACH(TeamPanelSlot, iter, gTeamPanel)
350 
351 
352 // Wraps up check for AP-s get from a different soldier for in a vehicle...
GetUIApsToDisplay(SOLDIERTYPE const * s)353 static INT8 GetUIApsToDisplay(SOLDIERTYPE const* s)
354 {
355 	if (s->uiStatusFlags & SOLDIER_DRIVER)
356 	{
357 		return GetSoldierStructureForVehicle(GetVehicle(s->iVehicleId)).bActionPoints;
358 	}
359 	return s->bActionPoints;
360 }
361 
362 
CheckForDisabledForGiveItem(void)363 void CheckForDisabledForGiveItem(void)
364 {
365 	const SOLDIERTYPE* const cur = gpSMCurrentMerc;
366 	Assert(cur != NULL);
367 	Assert(cur->sGridNo != NOWHERE);
368 
369 	if (guiCurrentScreen == SHOPKEEPER_SCREEN)
370 	{
371 		gfSMDisableForItems = !CanMercInteractWithSelectedShopkeeper(cur);
372 		return;
373 	}
374 
375 	// Default to true
376 	gfSMDisableForItems = TRUE;
377 
378 	// ATE: Is the current merc unconscious.....
379 	if (cur->bLife < OKLIFE && gpItemPointer != NULL)
380 	{
381 		// Go through each merc and see if there is one closeby....
382 		CFOR_EACH_IN_TEAM(s, OUR_TEAM)
383 		{
384 			if (s->bLife >= OKLIFE && !IsMechanical(*s) && s->bInSector && IsMercOnCurrentSquad(s))
385 			{
386 				const INT16 sDist        = PythSpacesAway(cur->sGridNo, s->sGridNo);
387 				const INT16 sDistVisible = DistanceVisible(s, DIRECTION_IRRELEVANT, DIRECTION_IRRELEVANT, cur->sGridNo, cur->bLevel);
388 
389 				// Check LOS....
390 				if (SoldierTo3DLocationLineOfSightTest(s, cur->sGridNo, cur->bLevel, 3, sDistVisible, TRUE))
391 				{
392 					if (sDist <= PASSING_ITEM_DISTANCE_NOTOKLIFE)
393 					{
394 						gfSMDisableForItems = FALSE;
395 						break; // found one, no need to keep looking
396 					}
397 				}
398 			}
399 		}
400 	}
401 	else
402 	{
403 		const SOLDIERTYPE* src = gpItemPointerSoldier;
404 		if (src == NULL)
405 		{
406 			src = GetSelectedMan();
407 			if (src == NULL)
408 			{
409 				gfSMDisableForItems = FALSE;
410 				return;
411 			}
412 		}
413 
414 		// OK buddy, check our currently selected merc and disable/enable if not close enough...
415 		if (cur == src)
416 		{
417 			gfSMDisableForItems = FALSE;
418 			return;
419 		}
420 
421 		const INT16 sDestGridNo = cur->sGridNo;
422 		const INT8  bDestLevel  = cur->bLevel;
423 
424 		// Get distance....
425 		const INT16 sDist = PythSpacesAway(src->sGridNo, sDestGridNo);
426 
427 		// is he close enough to see that gridno if he turns his head?
428 		const INT16 sDistVisible = DistanceVisible(src, DIRECTION_IRRELEVANT, DIRECTION_IRRELEVANT, sDestGridNo, bDestLevel);
429 
430 		// Check LOS....
431 		if (SoldierTo3DLocationLineOfSightTest(src, sDestGridNo, bDestLevel, 3, sDistVisible, TRUE))
432 		{
433 			// UNCONSCIOUS GUYS ONLY 1 tile AWAY
434 			if (cur->bLife < CONSCIOUSNESS)
435 			{
436 				if (sDist <= PASSING_ITEM_DISTANCE_NOTOKLIFE)
437 				{
438 					gfSMDisableForItems = FALSE;
439 				}
440 			}
441 			else if (sDist <= PASSING_ITEM_DISTANCE_OKLIFE)
442 			{
443 				gfSMDisableForItems = FALSE;
444 			}
445 		}
446 	}
447 }
448 
449 
450 static void UpdateSMPanel();
451 
452 
SetSMPanelCurrentMerc(SOLDIERTYPE * s)453 void SetSMPanelCurrentMerc(SOLDIERTYPE* s)
454 {
455 	gSelectSMPanelToMerc = NULL;
456 
457 	gpSMCurrentMerc = s;
458 
459 	// Disable all faces
460 	SetAllAutoFacesInactive( );
461 
462 	// Turn off compat ammo....
463 	if ( gpItemPointer == NULL )
464 	{
465 		HandleCompatibleAmmoUI(s, HANDPOS, FALSE);
466 		gfCheckForMouseOverItem = FALSE;
467 	}
468 	else
469 	{
470 		// Turn it all false first....
471 		InternalHandleCompatibleAmmoUI(s, gpItemPointer, FALSE);
472 		InternalHandleCompatibleAmmoUI(s, gpItemPointer, TRUE);
473 	}
474 
475 	// Remove item desc panel if one up....
476 	if ( gfInItemDescBox )
477 	{
478 		DeleteItemDescriptionBox( );
479 	}
480 
481 	if ( gfInItemPickupMenu )
482 	{
483 		gfSMDisableForItems = TRUE;
484 	}
485 	else
486 	{
487 		if (gpItemPointer || guiCurrentScreen == SHOPKEEPER_SCREEN || s->bLife < OKLIFE)
488 		{
489 			CheckForDisabledForGiveItem( );
490 		}
491 		else
492 		{
493 			gfSMDisableForItems = FALSE;
494 		}
495 	}
496 
497 	if (gpItemPointer != NULL) ReevaluateItemHatches(s, FALSE);
498 
499 	DisableInvRegions( gfSMDisableForItems );
500 
501 	fInterfacePanelDirty = DIRTYLEVEL2;
502 
503 	gfUIStanceDifferent = TRUE;
504 
505 	UpdateSMPanel( );
506 
507 }
508 
509 
510 static void HandleMouseOverSoldierFaceForContMove(SOLDIERTYPE* pSoldier, BOOLEAN fOn);
511 static bool IsMouseInRegion(MOUSE_REGION const&);
512 
513 
UpdateForContOverPortrait(SOLDIERTYPE * pSoldier,BOOLEAN fOn)514 void UpdateForContOverPortrait( SOLDIERTYPE *pSoldier, BOOLEAN fOn )
515 {
516 	if ( gsCurInterfacePanel == SM_PANEL )
517 	{
518 		if ( gpSMCurrentMerc != NULL )
519 		{
520 			// Check if mouse is in region and if so, adjust...
521 			if (IsMouseInRegion(gSM_SELMERCPanelRegion))
522 			{
523 				HandleMouseOverSoldierFaceForContMove( gpSMCurrentMerc, fOn );
524 			}
525 		}
526 	}
527 	else
528 	{
529 		FOR_EACH_TEAM_PANEL_SLOT(i)
530 		{
531 			if (i->merc != pSoldier)
532 				continue;
533 			if (!IsMouseInRegion(i->face))
534 				continue;
535 			HandleMouseOverSoldierFaceForContMove(pSoldier, fOn);
536 		}
537 	}
538 }
539 
540 
SetButtonState(UINT const idx,bool const clicked)541 static void SetButtonState(UINT const idx, bool const clicked)
542 {
543 	GUI_BUTTON& b = *iSMPanelButtons[idx];
544 	if (b.ubToggleButtonActivated)
545 		return;
546 	b.uiFlags &= ~BUTTON_CLICKED_ON;
547 	b.uiFlags |= clicked ? BUTTON_CLICKED_ON : 0;
548 }
549 
550 
551 static void BtnStealthModeCallback(GUI_BUTTON* btn, INT32 reason);
552 static void CheckForReEvaluateDisabledINVPanelButtons(void);
553 
554 
UpdateSMPanel()555 static void UpdateSMPanel()
556 {
557 	SOLDIERTYPE& s = *gpSMCurrentMerc;
558 	if (s.sGridNo == NOWHERE) return;
559 
560 	UINT8 stance_state = s.ubDesiredHeight;
561 	if (stance_state == NO_DESIRED_HEIGHT)
562 	{
563 		stance_state = gAnimControl[s.usAnimState].ubEndHeight;
564 	}
565 
566 	INT32 stance_gfx; // XXX HACK000E
567 	switch (stance_state)
568 	{
569 		case ANIM_STAND:
570 			stance_gfx = 11;
571 			DisableButton(iSMPanelButtons[STANCEUP_BUTTON]);
572 			EnableButton(iSMPanelButtons[STANCEDOWN_BUTTON], IsValidStance(&s, ANIM_CROUCH));
573 			break;
574 
575 		case ANIM_CROUCH:
576 			stance_gfx = 5;
577 			EnableButton(iSMPanelButtons[STANCEUP_BUTTON]);
578 			EnableButton(iSMPanelButtons[STANCEDOWN_BUTTON], IsValidStance(&s, ANIM_PRONE));
579 			break;
580 
581 		case ANIM_PRONE:
582 			stance_gfx = 17;
583 			EnableButton(iSMPanelButtons[STANCEUP_BUTTON]);
584 			DisableButton(iSMPanelButtons[STANCEDOWN_BUTTON]);
585 			break;
586 
587 		default: abort(); // HACK000E
588 	}
589 
590 	// Stance button done whether we're disabled or not
591 	if (gfUIStanceDifferent)
592 	{
593 		// Remove old
594 		if (giSMStealthButton) RemoveButton(giSMStealthButton);
595 		if (giSMStealthImages) UnloadButtonImage(giSMStealthImages);
596 
597 		// Make new
598 		if (!s.bStealthMode) stance_gfx += 3;
599 		giSMStealthImages = UseLoadedButtonImage(iSMPanelImages[STANCE_IMAGES], stance_gfx + 2, stance_gfx,
600 								-1, stance_gfx + 1, -1);
601 		giSMStealthButton = QuickCreateButton(giSMStealthImages, SM_STEALTHMODE_X,
602 							INV_INTERFACE_START_Y + SM_STEALTHMODE_Y,
603 							MSYS_PRIORITY_HIGH - 1, BtnStealthModeCallback);
604 		giSMStealthButton->SetFastHelpText(TacticalStr[TOGGLE_STEALTH_MODE_POPUPTEXT]);
605 
606 		gfUIStanceDifferent = FALSE;
607 
608 		if (gfAllDisabled) DisableButton(giSMStealthButton);
609 	}
610 
611 	if (gfAllDisabled) return;
612 
613 	CheckForReEvaluateDisabledINVPanelButtons();
614 
615 	// Check for any newly added items we need
616 	if (s.fCheckForNewlyAddedItems)
617 	{
618 		// Startup any newly added items
619 		CheckForAnyNewlyAddedItems(&s);
620 		s.fCheckForNewlyAddedItems = FALSE;
621 	}
622 
623 	// Set Disable/Enable UI based on buddy's stats
624 	GUIButtonRef const burst = iSMPanelButtons[BURSTMODE_BUTTON];
625 	if (burst->image != iBurstButtonImages[s.bWeaponMode])
626 	{
627 		burst->image    = iBurstButtonImages[s.bWeaponMode];
628 		burst->uiFlags |= BUTTON_DIRTY;
629 	}
630 
631 	SetButtonState(MUTE_BUTTON, s.uiStatusFlags & SOLDIER_MUTE);
632 
633 	bool const enable_climb =
634 		(FindLowerLevel(&s)  && EnoughPoints(&s, GetAPsToClimbRoof(&s, TRUE),  0, FALSE)) ||
635 		(FindHigherLevel(&s) && EnoughPoints(&s, GetAPsToClimbRoof(&s, FALSE), 0, FALSE)) ||
636 		FindFenceJumpDirection(&s);
637 	EnableButton(iSMPanelButtons[CLIMB_BUTTON], enable_climb);
638 
639 	EnableButton(iSMPanelButtons[SM_DONE_BUTTON], gTacticalStatus.ubCurrentTeam == OUR_TEAM && gTacticalStatus.uiFlags & INCOMBAT);
640 
641 	SetButtonState(UPDOWN_BUTTON, gsInterfaceLevel > 0);
642 
643 	SetButtonState(HANDCURSOR_BUTTON, gCurrentUIMode == HANDCURSOR_MODE);
644 	SetButtonState(TALK_BUTTON,       gCurrentUIMode == TALKCURSOR_MODE);
645 	SetButtonState(LOOK_BUTTON,       gCurrentUIMode == LOOKCURSOR_MODE);
646 
647 	// If not selected (or dead), disable/gray some buttons
648 	if (&s != GetSelectedMan() ||
649 		s.bLife< OKLIFE ||
650 		gTacticalStatus.ubCurrentTeam != OUR_TEAM ||
651 		gfSMDisableForItems)
652 	{
653 		DisableButton(iSMPanelButtons[CLIMB_BUTTON]);
654 		DisableButton(iSMPanelButtons[BURSTMODE_BUTTON]);
655 		DisableButton(iSMPanelButtons[STANCEUP_BUTTON]);
656 		DisableButton(iSMPanelButtons[STANCEDOWN_BUTTON]);
657 		DisableButton(iSMPanelButtons[LOOK_BUTTON]);
658 		DisableButton(iSMPanelButtons[UPDOWN_BUTTON]);
659 		DisableButton(iSMPanelButtons[HANDCURSOR_BUTTON]);
660 		if (giSMStealthButton)
661 			DisableButton(giSMStealthButton);
662 	}
663 	else
664 	{
665 		bool const enable_burst = IsGunBurstCapable(&s, HANDPOS) ||
666 						FindAttachment(&s.inv[HANDPOS], UNDER_GLAUNCHER) != ITEM_NOT_FOUND;
667 		EnableButton(iSMPanelButtons[BURSTMODE_BUTTON], enable_burst);
668 		EnableButton(iSMPanelButtons[LOOK_BUTTON]);
669 		EnableButton(iSMPanelButtons[UPDOWN_BUTTON]);
670 		EnableButton(iSMPanelButtons[HANDCURSOR_BUTTON]);
671 
672 		if (giSMStealthButton)
673 			EnableButton(giSMStealthButton);
674 	}
675 
676 	// CJC Dec 4 2002: or if item pickup menu is up
677 	EnableButton(iSMPanelButtons[SM_MAP_SCREEN_BUTTON],
678 			!(gTacticalStatus.uiFlags & ENGAGED_IN_CONV) && !gfInItemPickupMenu);
679 }
680 
681 
ReevaluateItemHatches(SOLDIERTYPE * pSoldier,BOOLEAN fAllValid)682 void ReevaluateItemHatches(SOLDIERTYPE* pSoldier, BOOLEAN fAllValid)
683 {
684 	INT32 cnt;
685 
686 	// if there's an item in the cursor and we're not supposed to just make them all valid
687 	if ( ( gpItemPointer != NULL ) && !fAllValid )
688 	{
689 		// check all inventory positions and mark the ones where cursor item won't fit as invalid
690 		for ( cnt = 0; cnt < NUM_INV_SLOTS; cnt++ )
691 		{
692 			gbInvalidPlacementSlot[ cnt ] = !CanItemFitInPosition( pSoldier, gpItemPointer, (INT8)cnt, FALSE );
693 
694 			// !!! ATTACHING/MERGING ITEMS IN MAP SCREEN IS NOT SUPPORTED !!!
695 			// CJC: seems to be supported now...
696 			//if( guiCurrentScreen != MAP_SCREEN )
697 			{
698 				// Check attachments, override to valid placement if valid merge...
699 				if ( ValidAttachment( gpItemPointer->usItem, pSoldier->inv[ cnt ].usItem ) )
700 				{
701 					gbInvalidPlacementSlot[ cnt ] = FALSE;
702 				}
703 
704 				if ( ValidMerge( gpItemPointer->usItem, pSoldier->inv[ cnt ].usItem ) )
705 				{
706 					gbInvalidPlacementSlot[ cnt ] = FALSE;
707 				}
708 			}
709 		}
710 	}
711 	else
712 	{
713 		// mark all inventory positions as valid
714 		for ( cnt = 0; cnt < NUM_INV_SLOTS; cnt++ )
715 		{
716 			gbInvalidPlacementSlot[ cnt ] = FALSE;
717 		}
718 	}
719 
720 	fInterfacePanelDirty = DIRTYLEVEL2;
721 }
722 
723 
EnableSMPanelButtons(BOOLEAN fEnable,BOOLEAN fFromItemPickup)724 void EnableSMPanelButtons(BOOLEAN fEnable, BOOLEAN fFromItemPickup)
725 {
726 	if ( fFromItemPickup )
727 	{
728 		// If we have the item pointer up...
729 		// CJC Dec 4 2002: or if item pickup menu is up
730 		//if ( gpItemPointer != NULL )
731 		if ( gpItemPointer != NULL || gfInItemPickupMenu )
732 		{
733 			DisableTacticalTeamPanelButtons( TRUE );
734 		}
735 		else
736 		{
737 			DisableTacticalTeamPanelButtons( FALSE );
738 		}
739 
740 		fInterfacePanelDirty = DIRTYLEVEL2;
741 	}
742 
743 
744 	if ( gsCurInterfacePanel == SM_PANEL )
745 	{
746 		if ( fFromItemPickup )
747 		{
748 			// If we have the item pointer up...
749 			if ( gpItemPointer != NULL )
750 			{
751 				ReevaluateItemHatches( gpSMCurrentMerc, fEnable );
752 
753 				// Turn it all false first....
754 				InternalHandleCompatibleAmmoUI( gpSMCurrentMerc, gpItemPointer, FALSE );
755 				InternalHandleCompatibleAmmoUI( gpSMCurrentMerc, gpItemPointer, TRUE );
756 
757 				gfCheckForMouseOverItem = FALSE;
758 
759 				// Highlight guys ....
760 				HandleAnyMercInSquadHasCompatibleStuff(gpItemPointer);
761 
762 			}
763 			else
764 			{
765 				//InternalHandleCompatibleAmmoUI( gpSMCurrentMerc, gpItemPointer, FALSE );
766 				gfCheckForMouseOverItem = FALSE;
767 
768 				HandleAnyMercInSquadHasCompatibleStuff(NULL);
769 			}
770 
771 			if ( fEnable )
772 			{
773 				ReevaluateItemHatches( gpSMCurrentMerc, fEnable );
774 			}
775 
776 			fInterfacePanelDirty = DIRTYLEVEL2;
777 		}
778 
779 		if ( fEnable )
780 		{
781 			// only enable the following if NOT in shopkeeper's interface
782 			if (guiCurrentScreen != SHOPKEEPER_SCREEN)
783 			{
784 				EnableButton( iSMPanelButtons[ CLIMB_BUTTON ] );
785 				EnableButton( iSMPanelButtons[ BURSTMODE_BUTTON ] );
786 				EnableButton( iSMPanelButtons[ STANCEUP_BUTTON ] );
787 				EnableButton( iSMPanelButtons[ STANCEDOWN_BUTTON ] );
788 				EnableButton( iSMPanelButtons[ LOOK_BUTTON ] );
789 				EnableButton( iSMPanelButtons[ UPDOWN_BUTTON ] );
790 				EnableButton( iSMPanelButtons[ HANDCURSOR_BUTTON ] );
791 				if (giSMStealthButton) EnableButton(giSMStealthButton);
792 
793 				bool const enable = !gfDisableTacticalPanelButtons;
794 				EnableButton(iSMPanelButtons[OPTIONS_BUTTON],       enable);
795 				EnableButton(iSMPanelButtons[SM_DONE_BUTTON],       enable);
796 				EnableButton(iSMPanelButtons[SM_MAP_SCREEN_BUTTON], enable);
797 
798 				//enable the radar map region
799 				gRadarRegion.Enable();
800 
801 				gfSMDisableForItems = FALSE;
802 
803 				DisableInvRegions( gfSMDisableForItems );
804 			}
805 
806 			if ( !fFromItemPickup )
807 			{
808 				EnableButton( iSMPanelButtons[ NEXTMERC_BUTTON ] );
809 				EnableButton( iSMPanelButtons[ PREVMERC_BUTTON ] );
810 			}
811 		}
812 		else
813 		{
814 			DisableButton( iSMPanelButtons[ CLIMB_BUTTON ] );
815 			DisableButton( iSMPanelButtons[ BURSTMODE_BUTTON ] );
816 			DisableButton( iSMPanelButtons[ STANCEUP_BUTTON ] );
817 			DisableButton( iSMPanelButtons[ STANCEDOWN_BUTTON ] );
818 			DisableButton( iSMPanelButtons[ LOOK_BUTTON ] );
819 			DisableButton( iSMPanelButtons[ UPDOWN_BUTTON ] );
820 			DisableButton( iSMPanelButtons[ HANDCURSOR_BUTTON ] );
821 			if (giSMStealthButton) DisableButton(giSMStealthButton);
822 
823 			if ( !fFromItemPickup )
824 			{
825 				DisableButton( iSMPanelButtons[ NEXTMERC_BUTTON ] );
826 				DisableButton( iSMPanelButtons[ PREVMERC_BUTTON ] );
827 			}
828 
829 			DisableButton( iSMPanelButtons[ OPTIONS_BUTTON ] );
830 			DisableButton( iSMPanelButtons[ SM_DONE_BUTTON ] );
831 			DisableButton( iSMPanelButtons[ SM_MAP_SCREEN_BUTTON ] );
832 
833 			gRadarRegion.Disable();
834 		}
835 
836 		gfAllDisabled = !fEnable;
837 
838 	}
839 }
840 
841 
842 static void SMInvClickCallback(MOUSE_REGION* pRegion, INT32 iReason);
843 static void SMInvClickCamoCallback(MOUSE_REGION* pRegion, INT32 iReason);
844 static void SMInvMoneyButtonCallback(MOUSE_REGION* pRegion, INT32 iReason);
845 static void SMInvMoveCallback(MOUSE_REGION* pRegion, INT32 iReason);
846 static void SMInvMoveCamoCallback(MOUSE_REGION* pRegion, INT32 iReason);
847 static void SelectedMercButtonCallback(MOUSE_REGION* pRegion, INT32 iReason);
848 static void SelectedMercButtonMoveCallback(MOUSE_REGION* pRegion, INT32 iReason);
849 static void SelectedMercEnemyIndicatorCallback(MOUSE_REGION* pRegion, INT32 iReason);
850 
851 
852 /** Fill empty space at the bottom of the screen. */
FillEmptySpaceAtBottom()853 static void FillEmptySpaceAtBottom()
854 {
855 	if(g_ui.isBigScreen())
856 	{
857 		ColorFillVideoSurfaceArea(guiSAVEBUFFER, 640, g_ui.get_INV_INTERFACE_START_Y(),
858 						g_ui.m_screenWidth, g_ui.m_screenHeight, 0);
859 	}
860 }
861 
InitializeSMPanel(void)862 void InitializeSMPanel(void)
863 {
864 	guiSMPanel    = AddVideoObjectFromFile(INTERFACEDIR "/inventory_bottom_panel.sti");
865 	guiSMObjects  = AddVideoObjectFromFile(INTERFACEDIR "/inventory_gold_front.sti");
866 	guiSMObjects2 = AddVideoObjectFromFile(INTERFACEDIR "/inv_frn.sti");
867 
868 	FillEmptySpaceAtBottom();
869 
870 	// INit viewport region
871 	// Set global mouse regions
872 	// Define region for viewport
873 	MSYS_DefineRegion(&gViewportRegion, 0, 0, gsVIEWPORT_END_X, gsVIEWPORT_WINDOW_END_Y, MSYS_PRIORITY_NORMAL, VIDEO_NO_CURSOR, MSYS_NO_CALLBACK, MSYS_NO_CALLBACK);
874 
875 	// Create buttons
876 	CreateSMPanelButtons();
877 
878 	const INT32 dy = INV_INTERFACE_START_Y;
879 
880 	// Set viewports
881 	// Define region for panel
882 	MSYS_DefineRegion(&gSMPanelRegion, 0, dy, SCREEN_WIDTH, SCREEN_HEIGHT, MSYS_PRIORITY_NORMAL, CURSOR_NORMAL, MSYS_NO_CALLBACK, MSYS_NO_CALLBACK);
883 
884 	INT32 x;
885 	INT32 y;
886 
887 	x = SM_SELMERC_FACE_X;
888 	y = dy + SM_SELMERC_FACE_Y;
889 
890 	//DEfine region for selected guy panel
891 	MSYS_DefineRegion(&gSM_SELMERCPanelRegion, x, y, x + SM_SELMERC_FACE_WIDTH, y + SM_SELMERC_FACE_HEIGHT, MSYS_PRIORITY_NORMAL, MSYS_NO_CURSOR, SelectedMercButtonMoveCallback, SelectedMercButtonCallback);
892 
893 	//DEfine region for selected guy panel
894 	MSYS_DefineRegion(&gSM_SELMERCEnemyIndicatorRegion, x + 1, y + 1, x + INDICATOR_BOX_WIDTH,
895 				y + INDICATOR_BOX_HEIGHT, MSYS_PRIORITY_NORMAL, MSYS_NO_CURSOR,
896 				MSYS_NO_CALLBACK, SelectedMercEnemyIndicatorCallback);
897 
898 	//DEfine region for money button
899 	x = MONEY_X;
900 	y = dy + MONEY_Y;
901 	MSYS_DefineRegion(&gSM_SELMERCMoneyRegion, x, y, x + MONEY_WIDTH, y + MONEY_HEIGHT, MSYS_PRIORITY_HIGH, MSYS_NO_CURSOR, MSYS_NO_CALLBACK, SMInvMoneyButtonCallback);
902 	gSM_SELMERCMoneyRegion.SetFastHelpText(TacticalStr[MONEY_BUTTON_HELP_TEXT]);
903 
904 	// Check if mouse is in region and if so, adjust...
905 	if (IsMouseInRegion(gSM_SELMERCPanelRegion))
906 	{
907 		HandleMouseOverSoldierFaceForContMove(gpSMCurrentMerc, TRUE);
908 	}
909 
910 	//DEfine region for selected guy panel
911 	MSYS_DefineRegion(&gSM_SELMERCBarsRegion, 62, dy + 2, 85, dy + 51, MSYS_PRIORITY_NORMAL, MSYS_NO_CURSOR, MSYS_NO_CALLBACK, SelectedMercButtonCallback);
912 
913 	InitInvSlotInterface(g_ui.m_invSlotPositionTac, &g_ui.m_invCamoRegion, SMInvMoveCallback, SMInvClickCallback, SMInvMoveCamoCallback, SMInvClickCamoCallback);
914 	InitKeyRingInterface(KeyRingItemPanelButtonCallback);
915 
916 	// this is important! It will disable buttons like SM_MAP_SCREEN_BUTTON when they're supposed to be
917 	// disabled - the previous disabled state is lost everytime panel is reinitialized, because all the
918 	// buttons are created from scratch!
919 	if (gpItemPointer == NULL)
920 	{
921 		// empty cursor - enable, not from item pickup
922 		EnableSMPanelButtons(TRUE, FALSE);
923 	}
924 	else
925 	{
926 		// full cursor - disable, from item pickup
927 		EnableSMPanelButtons(FALSE, TRUE);
928 	}
929 }
930 
931 
MakeButtonN(UINT idx,BUTTON_PICS * image,INT16 x,INT16 y,const GUI_CALLBACK click,const ST::string & help)932 static void MakeButtonN(UINT idx, BUTTON_PICS* image, INT16 x, INT16 y, const GUI_CALLBACK click, const ST::string& help)
933 try
934 {
935 	GUIButtonRef const btn = QuickCreateButtonToggle(image, x, y, MSYS_PRIORITY_HIGH - 1, click);
936 	iSMPanelButtons[idx] = btn;
937 	btn->SetFastHelpText(help);
938 }
939 catch (...)
940 {
941 	SLOGE("Cannot create Interface button");
942 	throw;
943 }
944 
945 
MakeButtonT(UINT idx,BUTTON_PICS * image,INT16 x,INT16 y,const GUI_CALLBACK click,const ST::string & help)946 static void MakeButtonT(UINT idx, BUTTON_PICS* image, INT16 x, INT16 y, const GUI_CALLBACK click, const ST::string& help)
947 try
948 {
949 	GUIButtonRef const btn = QuickCreateButton(image, x, y, MSYS_PRIORITY_HIGH - 1, click);
950 	iSMPanelButtons[idx] = btn;
951 	btn->SetFastHelpText(help);
952 }
953 catch (...)
954 {
955 	SLOGE("Cannot create Interface button");
956 	throw;
957 }
958 
959 
960 static void BtnBurstModeCallback(GUI_BUTTON* btn, INT32 reason);
961 static void BtnClimbCallback(GUI_BUTTON* btn, INT32 reason);
962 static void BtnHandCursorCallback(GUI_BUTTON* btn, INT32 reason);
963 static void BtnLookCallback(GUI_BUTTON* btn, INT32 reason);
964 static void BtnMapScreenCallback(GUI_BUTTON* btn, INT32 reason);
965 static void BtnMuteCallback(GUI_BUTTON* btn, INT32 reason);
966 static void BtnNextMercCallback(GUI_BUTTON* btn, INT32 reason);
967 static void BtnOptionsCallback(GUI_BUTTON* btn, INT32 reason);
968 static void BtnPrevMercCallback(GUI_BUTTON* btn, INT32 reason);
969 static void BtnSMDoneCallback(GUI_BUTTON* btn, INT32 reason);
970 static void BtnStanceDownCallback(GUI_BUTTON* btn, INT32 reason);
971 static void BtnStanceUpCallback(GUI_BUTTON* btn, INT32 reason);
972 static void BtnTalkCallback(GUI_BUTTON* btn, INT32 reason);
973 static void BtnUpdownCallback(GUI_BUTTON* btn, INT32 reason);
974 
975 
CreateSMPanelButtons(void)976 void CreateSMPanelButtons(void)
977 {
978 	giSMStealthImages = NULL;
979 	gfUIStanceDifferent = TRUE;
980 	gfAllDisabled	= FALSE;
981 
982 	// Load button Graphics
983 	iSMPanelImages[STANCEUP_IMAGES]   = LoadButtonImage(INTERFACEDIR "/inventory_buttons.sti",    0, 10);
984 	iSMPanelImages[UPDOWN_IMAGES]     = UseLoadedButtonImage(iSMPanelImages[STANCEUP_IMAGES],     9, 19);
985 	iSMPanelImages[CLIMB_IMAGES]      = UseLoadedButtonImage(iSMPanelImages[STANCEUP_IMAGES],     3, 13);
986 	iSMPanelImages[STANCEDOWN_IMAGES] = UseLoadedButtonImage(iSMPanelImages[STANCEUP_IMAGES],     8, 18);
987 	iSMPanelImages[HANDCURSOR_IMAGES] = UseLoadedButtonImage(iSMPanelImages[STANCEUP_IMAGES],     1, 11);
988 	iSMPanelImages[PREVMERC_IMAGES]   = UseLoadedButtonImage(iSMPanelImages[STANCEUP_IMAGES],    20, 22);
989 	iSMPanelImages[NEXTMERC_IMAGES]   = UseLoadedButtonImage(iSMPanelImages[STANCEUP_IMAGES],    21, 23);
990 #if 0
991 	iSMPanelImages[BURSTMODE_IMAGES]  = UseLoadedButtonImage(iSMPanelImages[STANCEUP_IMAGES],     7, 17);
992 #endif
993 	iSMPanelImages[LOOK_IMAGES]       = UseLoadedButtonImage(iSMPanelImages[STANCEUP_IMAGES],     2, 12);
994 	iSMPanelImages[TALK_IMAGES]       = UseLoadedButtonImage(iSMPanelImages[STANCEUP_IMAGES],     6, 16);
995 	iSMPanelImages[MUTE_IMAGES]       = UseLoadedButtonImage(iSMPanelImages[STANCEUP_IMAGES],     5, 15);
996 	iSMPanelImages[OPTIONS_IMAGES]    = UseLoadedButtonImage(iSMPanelImages[STANCEUP_IMAGES],    24, 25);
997 
998 	iBurstButtonImages[WM_NORMAL]     = UseLoadedButtonImage(iSMPanelImages[STANCEUP_IMAGES],     7,  7);
999 	iBurstButtonImages[WM_BURST]      = UseLoadedButtonImage(iSMPanelImages[STANCEUP_IMAGES],    17, 17);
1000 	iBurstButtonImages[WM_ATTACHED]   = UseLoadedButtonImage(iSMPanelImages[STANCEUP_IMAGES],    26, 26);
1001 
1002 	iSMPanelImages[STANCE_IMAGES]     = LoadButtonImage(INTERFACEDIR "/invadd-ons.sti", 0, 0, -1, 2, -1);
1003 
1004 	iSMPanelImages[DONE_IMAGES]       = LoadButtonImage(INTERFACEDIR "/inventory_buttons_2.sti",  1,  3);
1005 	iSMPanelImages[MAPSCREEN_IMAGES]  = UseLoadedButtonImage(iSMPanelImages[DONE_IMAGES],         0,  2);
1006 
1007 
1008 	// Create buttons
1009 
1010 	// SET BUTTONS TO -1
1011 	std::fill(std::begin(iSMPanelButtons), std::end(iSMPanelButtons), GUIButtonRef::NoButton());
1012 
1013 	const INT32 dy = INV_INTERFACE_START_Y;
1014 
1015 	MakeButtonT(SM_MAP_SCREEN_BUTTON, iSMPanelImages[MAPSCREEN_IMAGES],  SM_MAPSCREEN_X,   dy + SM_MAPSCREEN_Y,   BtnMapScreenCallback,  TacticalStr[MAPSCREEN_POPUPTEXT]);
1016 	MakeButtonT(SM_DONE_BUTTON,       iSMPanelImages[DONE_IMAGES],       SM_DONE_X,        dy + SM_DONE_Y,        BtnSMDoneCallback,     TacticalStr[END_TURN_POPUPTEXT]);
1017 	MakeButtonN(TALK_BUTTON,          iSMPanelImages[TALK_IMAGES],       SM_TALKB_X,       dy + SM_TALKB_Y,       BtnTalkCallback,       TacticalStr[TALK_CURSOR_POPUPTEXT]);
1018 	MakeButtonN(MUTE_BUTTON,          iSMPanelImages[MUTE_IMAGES],       SM_MUTEB_X,       dy + SM_MUTEB_Y,       BtnMuteCallback,       TacticalStr[TOGGLE_MUTE_POPUPTEXT]);
1019 	MakeButtonT(STANCEUP_BUTTON,      iSMPanelImages[STANCEUP_IMAGES],   SM_STANCEUPB_X,   dy + SM_STANCEUPB_Y,   BtnStanceUpCallback,   TacticalStr[CHANGE_STANCE_UP_POPUPTEXT]);
1020 	MakeButtonN(UPDOWN_BUTTON,        iSMPanelImages[UPDOWN_IMAGES],     SM_UPDOWNB_X,     dy + SM_UPDOWNB_Y,     BtnUpdownCallback,     TacticalStr[CURSOR_LEVEL_POPUPTEXT]);
1021 	MakeButtonT(CLIMB_BUTTON,         iSMPanelImages[CLIMB_IMAGES],      SM_CLIMBB_X,      dy + SM_CLIMBB_Y,      BtnClimbCallback,      TacticalStr[JUMPCLIMB_POPUPTEXT]);
1022 	MakeButtonT(STANCEDOWN_BUTTON,    iSMPanelImages[STANCEDOWN_IMAGES], SM_STANCEDOWNB_X, dy + SM_STANCEDOWNB_Y, BtnStanceDownCallback, TacticalStr[CHANGE_STANCE_DOWN_POPUPTEXT]);
1023 	MakeButtonN(HANDCURSOR_BUTTON,    iSMPanelImages[HANDCURSOR_IMAGES], SM_HANDCURSORB_X, dy + SM_HANDCURSORB_Y, BtnHandCursorCallback, TacticalStr[EXAMINE_CURSOR_POPUPTEXT]);
1024 	MakeButtonT(PREVMERC_BUTTON,      iSMPanelImages[PREVMERC_IMAGES],   SM_PREVMERCB_X,   dy + SM_PREVMERCB_Y,   BtnPrevMercCallback,   TacticalStr[PREV_MERC_POPUPTEXT]);
1025 	MakeButtonT(NEXTMERC_BUTTON,      iSMPanelImages[NEXTMERC_IMAGES],   SM_NEXTMERCB_X,   dy + SM_NEXTMERCB_Y,   BtnNextMercCallback,   TacticalStr[NEXT_MERC_POPUPTEXT]);
1026 	MakeButtonT(OPTIONS_BUTTON,       iSMPanelImages[OPTIONS_IMAGES],    SM_OPTIONSB_X,    dy + SM_OPTIONSB_Y,    BtnOptionsCallback,    TacticalStr[CHANGE_OPTIONS_POPUPTEXT]);
1027 #if 0
1028 	MakeButtonN(BURSTMODE_BUTTON,     iSMPanelImages[BURSTMODE_IMAGES],  SM_BURSTMODEB_X,  dy + SM_BURSTMODEB_Y,  BtnBurstModeCallback,  TacticalStr[TOGGLE_BURSTMODE_POPUPTEXT]);
1029 #endif
1030 	MakeButtonT(BURSTMODE_BUTTON,     iBurstButtonImages[WM_NORMAL],     SM_BURSTMODEB_X,  dy + SM_BURSTMODEB_Y,  BtnBurstModeCallback,  TacticalStr[TOGGLE_BURSTMODE_POPUPTEXT]);
1031 	MakeButtonN(LOOK_BUTTON,          iSMPanelImages[LOOK_IMAGES],       SM_LOOKB_X,       dy + SM_LOOKB_Y,       BtnLookCallback,       TacticalStr[LOOK_CURSOR_POPUPTEXT]);
1032 }
1033 
1034 
RemoveSMPanelButtons(void)1035 void RemoveSMPanelButtons(void)
1036 {
1037 	for (UINT32 cnt = 0; cnt < NUM_SM_BUTTONS; ++cnt)
1038 	{
1039 		if (iSMPanelButtons[cnt]) RemoveButton(iSMPanelButtons[cnt]);
1040 	}
1041 
1042 	for (UINT32 cnt = 0; cnt < NUM_SM_BUTTON_IMAGES; ++cnt)
1043 	{
1044 		UnloadButtonImage(iSMPanelImages[cnt]);
1045 	}
1046 
1047 	if (giSMStealthButton) RemoveButton(giSMStealthButton);
1048 	if (giSMStealthImages) UnloadButtonImage(giSMStealthImages);
1049 
1050 	UnloadButtonImage(iBurstButtonImages[WM_NORMAL]);
1051 	UnloadButtonImage(iBurstButtonImages[WM_BURST]);
1052 	UnloadButtonImage(iBurstButtonImages[WM_ATTACHED]);
1053 }
1054 
1055 
ShutdownSMPanel(void)1056 void ShutdownSMPanel(void)
1057 {
1058 	// All buttons and regions and video objects and video surfaces will be deleted at shutddown of SGM
1059 	// We may want to delete them at the interm as well, to free up room for other panels
1060 	DeleteVideoObject(guiSMPanel);
1061 	DeleteVideoObject(guiSMObjects);
1062 	DeleteVideoObject(guiSMObjects2);
1063 
1064 	gSelectSMPanelToMerc = NULL;
1065 
1066 	// CJC: delete key ring if open
1067 	DeleteKeyRingPopup(); // function will abort if key ring is not up
1068 
1069 	// ATE: Delete desc panel if it was open....
1070 	if (gfInItemDescBox)
1071 	{
1072 		DeleteItemDescriptionBox();
1073 	}
1074 
1075 	ShutdownInvSlotInterface();
1076 	ShutdownKeyRingInterface();
1077 
1078 	MSYS_RemoveRegion(&gSMPanelRegion);
1079 	MSYS_RemoveRegion(&gSM_SELMERCPanelRegion);
1080 	MSYS_RemoveRegion(&gSM_SELMERCBarsRegion);
1081 	MSYS_RemoveRegion(&gSM_SELMERCMoneyRegion);
1082 	MSYS_RemoveRegion(&gSM_SELMERCEnemyIndicatorRegion);
1083 
1084 	HandleMouseOverSoldierFaceForContMove(gpSMCurrentMerc, FALSE);
1085 
1086 	MSYS_RemoveRegion(&gViewportRegion);
1087 
1088 	RemoveSMPanelButtons();
1089 }
1090 
1091 
PrintAP(SOLDIERTYPE * const s,INT16 const x,INT16 const y,INT16 const w,INT16 const h)1092 static void PrintAP(SOLDIERTYPE* const s, INT16 const x, INT16 const y, INT16 const w, INT16 const h)
1093 {
1094 	if (!(gTacticalStatus.uiFlags & INCOMBAT))
1095 		return;
1096 	if (s->bLife < OKLIFE)
1097 		return;
1098 
1099 	INT8  const ap         = GetUIApsToDisplay(s);
1100 	UINT8 const min_ap     = MinAPsToAttack(s, s->sLastTarget, TRUE);
1101 	UINT8 const foreground =
1102 		!EnoughPoints(s, min_ap, 0, FALSE) ? FONT_MCOLOR_DKRED    :
1103 		ap < 0                             ? FONT_MCOLOR_DKRED    :
1104 		MercUnderTheInfluence(s)           ? FONT_MCOLOR_LTBLUE   :
1105 		s->bStealthMode                    ? FONT_MCOLOR_LTYELLOW :
1106 		FONT_MCOLOR_LTGRAY;
1107 	SetFontAttributes(TINYFONT1, foreground);
1108 
1109 	RestoreExternBackgroundRect(x, y, w, h);
1110 	ST::string buf = ST::format("{}", ap);
1111 	INT16 sFontX;
1112 	INT16 sFontY;
1113 	FindFontCenterCoordinates(x, y, w, h, buf, TINYFONT1, &sFontX, &sFontY);
1114 	MPrint(sFontX, sFontY, buf);
1115 }
1116 
1117 
SetStatsHelp(MOUSE_REGION & r,SOLDIERTYPE const & s)1118 static void SetStatsHelp(MOUSE_REGION& r, SOLDIERTYPE const& s)
1119 {
1120 	ST::string help;
1121 	ST::string text;
1122 	if (s.bLife != 0)
1123 	{
1124 		if (s.uiStatusFlags & SOLDIER_VEHICLE)
1125 		{
1126 			text = st_format_printf(TacticalStr[VEHICLE_VITAL_STATS_POPUPTEXT], s.bLife, s.bLifeMax, s.bBreath, s.bBreathMax);
1127 		}
1128 		else if (s.uiStatusFlags & SOLDIER_ROBOT)
1129 		{
1130 			text = st_format_printf(gzLateLocalizedString[STR_LATE_16], s.bLife, s.bLifeMax);
1131 		}
1132 		else
1133 		{
1134 			text = st_format_printf(TacticalStr[MERC_VITAL_STATS_POPUPTEXT], s.bLife, s.bLifeMax, s.bBreath, s.bBreathMax, GetMoraleString(s));
1135 		}
1136 		help = text;
1137 	}
1138 	r.SetFastHelpText(help);
1139 }
1140 
ProgressBarBackgroundRect(const INT16 sLeft,const INT16 sTop,const INT16 sWidth,const INT16 sHeight,const UINT32 rgb,const UINT8 scale_rgb)1141 void ProgressBarBackgroundRect(const INT16 sLeft, const INT16 sTop, const INT16 sWidth, const INT16 sHeight, const UINT32 rgb, const UINT8 scale_rgb)
1142 {
1143 	SGPVSurface::Lock l(guiSAVEBUFFER);
1144 
1145 	#define s(a)				((a) / 2) + ((a) / 2) * (scale_rgb) / 100
1146 
1147 	const int r = s(0xff & rgb >> 16);
1148 	const int g = s(0xff & rgb >> 8);
1149 	const int b = s(0xff & rgb);
1150 
1151 	const UINT16 fill_color = Get16BPPColor((b << 16) + (g << 8) + r);
1152 
1153 	UINT16* const dst = l.Buffer<UINT16>();
1154 
1155 	for (int y = 0; y < sHeight; ++y)
1156 	{
1157 		for(int x = 0; x < sWidth; ++x)
1158 		{
1159 			dst[(y + sTop)*l.Pitch() / 2 + sLeft + x] = fill_color;
1160 		}
1161 	}
1162 }
1163 
PrintStat(UINT32 const change_time,UINT16 const stat_bit,INT8 const stat_val,INT16 const x,INT16 const y,INT32 const progress)1164 static void PrintStat(UINT32 const change_time, UINT16 const stat_bit, INT8 const stat_val, INT16 const x, INT16 const y, INT32 const progress)
1165 {
1166 	SOLDIERTYPE const& s  = *gpSMCurrentMerc;
1167 
1168 	UINT8       const  fg =
1169 		s.bLife < OKLIFE                                             ? FONT_MCOLOR_DKGRAY    :
1170 		GetJA2Clock() >= CHANGE_STAT_RECENTLY_DURATION + change_time ? STATS_TEXT_FONT_COLOR :
1171 		change_time == 0                                             ? STATS_TEXT_FONT_COLOR :
1172 		s.usValueGoneUp & stat_bit                                   ? FONT_LTGREEN          :
1173 		FONT_RED;
1174 
1175 	SetFontForeground(fg);
1176 
1177 	ST::string str = ST::format("{3d}", stat_val);
1178 	if (gamepolicy(gui_extras))
1179 	{
1180 		ProgressBarBackgroundRect(x + 16, y - 2, 15 * progress / 100, 10, 0x514A05, progress);
1181 	}
1182 
1183 	DrawStringRight(str, x, y, SM_STATS_WIDTH, SM_STATS_HEIGHT, BLOCKFONT2);
1184 }
1185 
RenderSMPanel(DirtyLevel * const dirty_level)1186 void RenderSMPanel(DirtyLevel* const dirty_level)
1187 {
1188 	// Give him the panel
1189 	if (gSelectSMPanelToMerc) SetSMPanelCurrentMerc(gSelectSMPanelToMerc);
1190 
1191 	// ATE: Don't do anything if we are in stack popup and are refreshing stuff
1192 	if ((InItemStackPopup() || InKeyRingPopup()) && *dirty_level == DIRTYLEVEL1)
1193 		return;
1194 
1195 	if (!gpSMCurrentMerc) return;
1196 
1197 	SOLDIERTYPE& s = *gpSMCurrentMerc;
1198 
1199 	if (gfCheckForMouseOverItem && GetJA2Clock() - guiMouseOverItemTime > 100)
1200 	{
1201 		if (HandleCompatibleAmmoUI(&s, (INT8)gbCheckForMouseOverItemPos, TRUE))
1202 		{
1203 			*dirty_level = DIRTYLEVEL2;
1204 		}
1205 
1206 		gfCheckForMouseOverItem = FALSE;
1207 	}
1208 
1209 	HandleNewlyAddedItems(s, dirty_level);
1210 
1211 	if (InItemDescriptionBox()) HandleItemDescriptionBox(dirty_level);
1212 
1213 	INT32 const dy = INV_INTERFACE_START_Y;
1214 
1215 	if (*dirty_level == DIRTYLEVEL2)
1216 	{
1217 		BltVideoObject(guiSAVEBUFFER, guiSMPanel, 0, INTERFACE_START_X, dy);
1218 
1219 		{
1220 			SGPVObject const* gfx;
1221 			if (gfSMDisableForItems)
1222 			{
1223 				gfx = guiSMObjects2;
1224 			}
1225 			else if (gTacticalStatus.ubCurrentTeam == OUR_TEAM &&
1226 				&s == GetSelectedMan() &&
1227 				OK_INTERRUPT_MERC(&s))
1228 			{
1229 				gfx = guiSMObjects;
1230 			}
1231 			else
1232 			{
1233 				goto no_plate;
1234 			}
1235 			INT32 const x = SM_SELMERC_PLATE_X;
1236 			INT32 const y = SM_SELMERC_PLATE_Y + dy;
1237 			BltVideoObject(guiSAVEBUFFER, gfx, 0, x, y);
1238 			RestoreExternBackgroundRect(x, y, SM_SELMERC_PLATE_WIDTH, SM_SELMERC_PLATE_HEIGHT);
1239 		}
1240 no_plate:
1241 
1242 		RenderSoldierFace(s, SM_SELMERC_FACE_X, dy + SM_SELMERC_FACE_Y);
1243 
1244 		if (InItemDescriptionBox())
1245 		{
1246 			RenderItemDescriptionBox();
1247 		}
1248 		else
1249 		{
1250 			RenderInvBodyPanel(&s, SM_BODYINV_X, SM_BODYINV_Y);
1251 
1252 			// Render Values for stats
1253 			SetFontDestBuffer(guiSAVEBUFFER);
1254 			SetFontAttributes(BLOCKFONT2, STATS_TITLE_FONT_COLOR);
1255 			for (UINT32 i = 0; i != 5; ++i)
1256 			{
1257 				INT32 const y = dy + 7 + i * 10;
1258 				MPrint( 92, y, pShortAttributeStrings[i]);
1259 				MPrint(137, y, pShortAttributeStrings[i + 5]);
1260 			}
1261 
1262 			MPrint(SM_ARMOR_LABEL_X - StringPixLength(pInvPanelTitleStrings[0], BLOCKFONT2) / 2, dy + SM_ARMOR_LABEL_Y, pInvPanelTitleStrings[0]);
1263 			MPrint(SM_ARMOR_PERCENT_X, dy + SM_ARMOR_PERCENT_Y, "%");
1264 
1265 			MPrint(SM_WEIGHT_LABEL_X - StringPixLength(pInvPanelTitleStrings[1], BLOCKFONT2), dy + SM_WEIGHT_LABEL_Y, pInvPanelTitleStrings[1]);
1266 			MPrint(SM_WEIGHT_PERCENT_X, dy + SM_WEIGHT_PERCENT_Y, "%");
1267 
1268 			MPrint(SM_CAMO_LABEL_X - StringPixLength(pInvPanelTitleStrings[2], BLOCKFONT2), dy + SM_CAMO_LABEL_Y, pInvPanelTitleStrings[2]);
1269 			MPrint(SM_CAMO_PERCENT_X, dy + SM_CAMO_PERCENT_Y, "%");
1270 
1271 			MERCPROFILESTRUCT& p = GetProfile(s.ubProfile);
1272 			PrintStat(s.uiChangeAgilityTime,      AGIL_INCREASE,     s.bAgility,      SM_AGI_X,    dy + SM_AGI_Y,    p.sAgilityGain*2);
1273 			PrintStat(s.uiChangeDexterityTime,    DEX_INCREASE,      s.bDexterity,    SM_DEX_X,    dy + SM_DEX_Y,    p.sDexterityGain*2);
1274 			PrintStat(s.uiChangeStrengthTime,     STRENGTH_INCREASE, s.bStrength,     SM_STR_X,    dy + SM_STR_Y,    p.sStrengthGain*2);
1275 			PrintStat(s.uiChangeLeadershipTime,   LDR_INCREASE,      s.bLeadership,   SM_CHAR_X,   dy + SM_CHAR_Y,   p.sLeadershipGain*2);
1276 			PrintStat(s.uiChangeWisdomTime,       WIS_INCREASE,      s.bWisdom,       SM_WIS_X,    dy + SM_WIS_Y,    p.sWisdomGain*2);
1277 			PrintStat(s.uiChangeLevelTime,        LVL_INCREASE,      s.bExpLevel,     SM_EXPLVL_X, dy + SM_EXPLVL_Y, p.sExpLevelGain*100/(350*p.bExpLevel));
1278 			PrintStat(s.uiChangeMarksmanshipTime, MRK_INCREASE,      s.bMarksmanship, SM_MRKM_X,   dy + SM_MRKM_Y,   p.sMarksmanshipGain*4);
1279 			PrintStat(s.uiChangeExplosivesTime,   EXP_INCREASE,      s.bExplosive,    SM_EXPL_X,   dy + SM_EXPL_Y,   p.sExplosivesGain*4);
1280 			PrintStat(s.uiChangeMechanicalTime,   MECH_INCREASE,     s.bMechanical,   SM_MECH_X,   dy + SM_MECH_Y,   p.sMechanicGain*4);
1281 			PrintStat(s.uiChangeMedicalTime,      MED_INCREASE,      s.bMedical,      SM_MED_X,    dy + SM_MED_Y,    p.sMedicalGain*4);
1282 
1283 			SetFontForeground(s.bLife >= OKLIFE ? STATS_TEXT_FONT_COLOR : FONT_MCOLOR_DKGRAY);
1284 
1285 			INT16   usX;
1286 			INT16   usY;
1287 			ST::string sString;
1288 
1289 			// Display armour value
1290 			sString = ST::format("{3d}", ArmourPercent(&s));
1291 			FindFontRightCoordinates(SM_ARMOR_X, dy + SM_ARMOR_Y, SM_PERCENT_WIDTH, SM_PERCENT_HEIGHT, sString, BLOCKFONT2, &usX, &usY);
1292 			MPrint(usX, usY , sString);
1293 
1294 			// Display weight value
1295 			sString = ST::format("{3d}", CalculateCarriedWeight(&s));
1296 			FindFontRightCoordinates(SM_WEIGHT_X, dy + SM_WEIGHT_Y, SM_PERCENT_WIDTH, SM_PERCENT_HEIGHT, sString, BLOCKFONT2, &usX, &usY);
1297 			MPrint(usX, usY, sString);
1298 
1299 			// Display camo value
1300 			sString = ST::format("{3d}", s.bCamo);
1301 			FindFontRightCoordinates(SM_CAMO_X, dy + SM_CAMO_Y, SM_PERCENT_WIDTH, SM_PERCENT_HEIGHT, sString, BLOCKFONT2, &usX, &usY);
1302 			MPrint(usX, usY, sString);
1303 
1304 			SetFontDestBuffer(FRAME_BUFFER);
1305 
1306 			RestoreExternBackgroundRect(INTERFACE_START_X, INV_INTERFACE_START_Y, SCREEN_WIDTH - INTERFACE_START_X, SCREEN_HEIGHT - INV_INTERFACE_START_Y);
1307 		}
1308 
1309 		// Render name
1310 		UINT8 const fg = s.bStealthMode ? FONT_MCOLOR_LTYELLOW : FONT_MCOLOR_LTGRAY;
1311 		SetFontAttributes(BLOCKFONT2, fg);
1312 
1313 		INT32 const x = SM_SELMERCNAME_X;
1314 		INT32 const y = SM_SELMERCNAME_Y + dy;
1315 		INT32 const w = SM_SELMERCNAME_WIDTH;
1316 		INT32 const h = SM_SELMERCNAME_HEIGHT;
1317 		RestoreExternBackgroundRect(x, y, w, h);
1318 		INT16 sFontX;
1319 		INT16 sFontY;
1320 		FindFontCenterCoordinates(x, y, w, h, s.name, BLOCKFONT2, &sFontX, &sFontY);
1321 		MPrint(sFontX, sFontY, s.name);
1322 	}
1323 
1324 	if (*dirty_level != DIRTYLEVEL0)
1325 	{
1326 		SetStatsHelp(gSM_SELMERCBarsRegion, s);
1327 
1328 		// Display AP
1329 		if (!(s.uiStatusFlags & SOLDIER_DEAD))
1330 		{
1331 			PrintAP(&s, SM_SELMERC_AP_X, dy + SM_SELMERC_AP_Y, SM_SELMERC_AP_WIDTH, SM_SELMERC_AP_HEIGHT);
1332 			DrawSoldierUIBars(s, SM_SELMERC_HEALTH_X, dy + SM_SELMERC_HEALTH_Y, TRUE, FRAME_BUFFER);
1333 		}
1334 	}
1335 
1336 	UpdateSMPanel();
1337 
1338 	// Render items in guy's hand
1339 	HandleRenderInvSlots(s, *dirty_level);
1340 
1341 	if (gfSMDisableForItems && *dirty_level != DIRTYLEVEL0)
1342 	{
1343 		SGPRect ClipRect;
1344 		ClipRect.iLeft = 87;
1345 		ClipRect.iRight = 536;
1346 		ClipRect.iTop = INV_INTERFACE_START_Y;
1347 		ClipRect.iBottom = SCREEN_HEIGHT;
1348 		SGPVSurface::Lock l(FRAME_BUFFER);
1349 		Blt16BPPBufferHatchRect(l.Buffer<UINT16>(), l.Pitch(), &ClipRect);
1350 	}
1351 }
1352 
1353 
SMInvMoveCallback(MOUSE_REGION * pRegion,INT32 iReason)1354 static void SMInvMoveCallback(MOUSE_REGION* pRegion, INT32 iReason)
1355 {
1356 	UINT32 uiHandPos;
1357 
1358 	uiHandPos = MSYS_GetRegionUserData( pRegion, 0 );
1359 
1360 	if ( gpSMCurrentMerc->inv[ uiHandPos ].usItem == NOTHING )
1361 		return;
1362 
1363 	if (iReason == MSYS_CALLBACK_REASON_GAIN_MOUSE)
1364 	{
1365 		if ( gpItemPointer == NULL )
1366 		{
1367 			// Setup a timer....
1368 			guiMouseOverItemTime = GetJA2Clock( );
1369 			gfCheckForMouseOverItem = TRUE;
1370 			gbCheckForMouseOverItemPos = (INT8)uiHandPos;
1371 		}
1372 	}
1373 	if (iReason == MSYS_CALLBACK_REASON_LOST_MOUSE )
1374 	{
1375 		if ( gpItemPointer == NULL )
1376 		{
1377 			HandleCompatibleAmmoUI( gpSMCurrentMerc, (INT8)uiHandPos, FALSE );
1378 			gfCheckForMouseOverItem = FALSE;
1379 			fInterfacePanelDirty = DIRTYLEVEL2;
1380 		}
1381 	}
1382 }
1383 
1384 
SMInvMoveCamoCallback(MOUSE_REGION * const pRegion,const INT32 iReason)1385 static void SMInvMoveCamoCallback(MOUSE_REGION* const pRegion, const INT32 iReason)
1386 {
1387 	if (iReason == MSYS_CALLBACK_REASON_GAIN_MOUSE )
1388 	{
1389 		// Setup a timer....
1390 		guiMouseOverItemTime = GetJA2Clock( );
1391 		gfCheckForMouseOverItem = TRUE;
1392 		gbCheckForMouseOverItemPos = NO_SLOT;
1393 	}
1394 	if (iReason == MSYS_CALLBACK_REASON_LOST_MOUSE )
1395 	{
1396 		HandleCompatibleAmmoUI( gpSMCurrentMerc, (INT8)NO_SLOT, FALSE );
1397 		gfCheckForMouseOverItem = FALSE;
1398 	}
1399 }
1400 
1401 
SMInvClickCamoCallback(MOUSE_REGION * pRegion,INT32 iReason)1402 static void SMInvClickCamoCallback(MOUSE_REGION* pRegion, INT32 iReason)
1403 {
1404 	if (iReason & MSYS_CALLBACK_REASON_LBUTTON_DWN)
1405 	{
1406 		// Apply camo (if we have something in cursor...)
1407 		// If we do not have an item in hand, start moving it
1408 		OBJECTTYPE* const obj = gpItemPointer;
1409 		if (obj == NULL) return;
1410 
1411 		SOLDIERTYPE* const s = gpSMCurrentMerc;
1412 		if (s->bLife < CONSCIOUSNESS) return;
1413 
1414 		BOOLEAN fGoodAPs;
1415 		// Try to apply camo....
1416 		if (ApplyCamo(s, obj, &fGoodAPs))
1417 		{
1418 			if (!fGoodAPs) return;
1419 
1420 			// Say OK acknowledge....
1421 			DoMercBattleSound(s, BATTLE_SOUND_COOL1);
1422 		}
1423 		else if (ApplyCanteen(s, obj, &fGoodAPs))
1424 		{
1425 			if (!fGoodAPs) return;
1426 		}
1427 		else if (ApplyElixir(s, obj, &fGoodAPs))
1428 		{
1429 			if (!fGoodAPs) return;
1430 
1431 			// Say OK acknowledge....
1432 			DoMercBattleSound(s, BATTLE_SOUND_COOL1);
1433 		}
1434 		else if (ApplyDrugs(s, obj))
1435 		{
1436 			// Say OK acknowledge....
1437 			DoMercBattleSound(s, BATTLE_SOUND_COOL1);
1438 		}
1439 		else
1440 		{
1441 			ScreenMsg(FONT_MCOLOR_LTYELLOW, MSG_UI_FEEDBACK, TacticalStr[CANNOT_DO_INV_STUFF_STR]);
1442 			return;
1443 		}
1444 
1445 		fInterfacePanelDirty = DIRTYLEVEL2;
1446 
1447 		// Check if it's the same now!
1448 		if (obj->ubNumberOfObjects == 0)
1449 		{
1450 			gbCompatibleApplyItem = FALSE;
1451 			EndItemPointer();
1452 		}
1453 	}
1454 }
1455 
1456 
HandleNailsVestFetish(const SOLDIERTYPE * const s,const UINT32 uiHandPos,const UINT16 usReplaceItem)1457 BOOLEAN HandleNailsVestFetish(const SOLDIERTYPE* const s, const UINT32 uiHandPos, const UINT16 usReplaceItem)
1458 {
1459 	if (s->ubProfile != NAILS) return FALSE;
1460 	if (uiHandPos != VESTPOS)  return FALSE;
1461 
1462 	switch (usReplaceItem)
1463 	{
1464 		case LEATHER_JACKET:
1465 		case LEATHER_JACKET_W_KEVLAR:
1466 		case LEATHER_JACKET_W_KEVLAR_18:
1467 		case LEATHER_JACKET_W_KEVLAR_Y:
1468 		case COMPOUND18:
1469 		case JAR_QUEEN_CREATURE_BLOOD:
1470 			return FALSE;
1471 
1472 		default:
1473 			TacticalCharacterDialogue(s, 61);
1474 			return TRUE;
1475 	}
1476 }
1477 
1478 
UIHandleItemPlacement(UINT8 ubHandPos,UINT16 usOldItemIndex,UINT16 usNewItemIndex,BOOLEAN fDeductPoints)1479 static BOOLEAN UIHandleItemPlacement(UINT8 ubHandPos, UINT16 usOldItemIndex, UINT16 usNewItemIndex, BOOLEAN fDeductPoints)
1480 {
1481 	if ( _KeyDown(CTRL) )
1482 	{
1483 		CleanUpStack( &( gpSMCurrentMerc->inv[ ubHandPos ] ), gpItemPointer );
1484 		if ( gpItemPointer->ubNumberOfObjects == 0 )
1485 		{
1486 			EndItemPointer( );
1487 		}
1488 		return( TRUE );
1489 	}
1490 
1491 	// Try to place here
1492 	if ( PlaceObject( gpSMCurrentMerc, ubHandPos, gpItemPointer ) )
1493 	{
1494 		if ( fDeductPoints )
1495 		{
1496 			// Deduct points
1497 			if ( gpItemPointerSoldier->bLife >= CONSCIOUSNESS )
1498 			{
1499 				DeductPoints( gpItemPointerSoldier,  2, 0 );
1500 			}
1501 			if ( gpSMCurrentMerc->bLife >= CONSCIOUSNESS )
1502 			{
1503 				DeductPoints( gpSMCurrentMerc,  2, 0 );
1504 			}
1505 		}
1506 
1507 		HandleTacticalEffectsOfEquipmentChange( gpSMCurrentMerc, ubHandPos, usOldItemIndex, usNewItemIndex );
1508 
1509 		// Dirty
1510 		fInterfacePanelDirty = DIRTYLEVEL2;
1511 
1512 		// Check if cursor is empty now
1513 		if ( gpItemPointer->ubNumberOfObjects == 0 )
1514 		{
1515 			EndItemPointer( );
1516 		}
1517 
1518 		if ( gpItemPointerSoldier != gpSMCurrentMerc )
1519 		{
1520 			ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, st_format_printf(pMessageStrings[ MSG_ITEM_PASSED_TO_MERC ], ShortItemNames[ usNewItemIndex ], gpSMCurrentMerc->name) );
1521 		}
1522 
1523 		// UPDATE ITEM POINTER.....
1524 		gpItemPointerSoldier = gpSMCurrentMerc;
1525 
1526 		if ( gpItemPointer != NULL )
1527 		{
1528 			ReevaluateItemHatches( gpSMCurrentMerc, FALSE );
1529 		}
1530 
1531 		// Set cursor back to normal mode...
1532 		guiPendingOverrideEvent = A_CHANGE_TO_MOVE;
1533 
1534 		return( TRUE );
1535 
1536 	}
1537 	else
1538 	{
1539 		return( FALSE );
1540 	}
1541 
1542 }
1543 
1544 
1545 static void MergeMessageBoxCallBack(MessageBoxReturnValue);
1546 
1547 
SMInvClickCallback(MOUSE_REGION * pRegion,INT32 iReason)1548 static void SMInvClickCallback(MOUSE_REGION* pRegion, INT32 iReason)
1549 {
1550 	UINT32 uiHandPos;
1551 	// Copyies of values
1552 	UINT16 usOldItemIndex, usNewItemIndex;
1553 	UINT16 usItemPrevInItemPointer;
1554 	BOOLEAN fNewItem = FALSE;
1555 	static BOOLEAN fRightDown = FALSE;
1556 
1557 
1558 	uiHandPos = MSYS_GetRegionUserData( pRegion, 0 );
1559 
1560 	if (fInMapMode) return; // XXX necessary?
1561 
1562 	//if we are in the shop keeper interface
1563 	if (guiCurrentScreen == SHOPKEEPER_SCREEN)
1564 	{
1565 		// and this inventory slot is hatched out
1566 		if( ShouldSoldierDisplayHatchOnItem( gpSMCurrentMerc->ubProfile, (INT16)uiHandPos ) )
1567 		{
1568 			// it means that item is a copy of one in the player's offer area, so we treat it as if the slot was empty (ignore)
1569 			// if the cursor has an item in it, we still ignore the click, because handling swaps in this situation would be
1570 			// ugly, we'd have to the the swap, then make the bOwnerSlot of the item just picked up a -1 in its offer area spot.
1571 			return;
1572 		}
1573 	}
1574 
1575 
1576 	if (iReason & MSYS_CALLBACK_REASON_LBUTTON_DWN )
1577 	{
1578 		// If we do not have an item in hand, start moving it
1579 		if ( gpItemPointer == NULL )
1580 		{
1581 
1582 			// Return if empty
1583 			if ( gpSMCurrentMerc->inv[ uiHandPos ].usItem == NOTHING )
1584 				return;
1585 
1586 			SelectSoldier(gpSMCurrentMerc, SELSOLDIER_NONE);
1587 
1588 			// OK, check if this is Nails, and we're in the vest position , don't allow it to come off....
1589 			if ( HandleNailsVestFetish( gpSMCurrentMerc, uiHandPos, NOTHING ) )
1590 			{
1591 				return;
1592 			}
1593 
1594 			if ( _KeyDown(CTRL) )
1595 			{
1596 				CleanUpStack( &( gpSMCurrentMerc->inv[ uiHandPos ] ), NULL );
1597 				return;
1598 			}
1599 
1600 			// Turn off new item glow!
1601 			gpSMCurrentMerc->bNewItemCount[ uiHandPos ] = 0;
1602 
1603 			usOldItemIndex = gpSMCurrentMerc->inv[ uiHandPos ].usItem;
1604 
1605 			// move item into the mouse cursor
1606 			BeginItemPointer( gpSMCurrentMerc, (UINT8)uiHandPos );
1607 
1608 			//if we are in the shopkeeper interface
1609 			if (guiCurrentScreen == SHOPKEEPER_SCREEN)
1610 			{
1611 				// pick up item from regular inventory slot into cursor OR try to sell it
1612 				// ( unless CTRL is held down )
1613 				BeginSkiItemPointer(PLAYERS_INVENTORY, (INT8)uiHandPos, !_KeyDown(CTRL));
1614 			}
1615 
1616 			HandleTacticalEffectsOfEquipmentChange( gpSMCurrentMerc, uiHandPos, usOldItemIndex, NOTHING );
1617 
1618 			// HandleCompatibleAmmoUI( gpSMCurrentMerc, (INT8)uiHandPos, FALSE );
1619 		}
1620 		else // item in cursor
1621 		{
1622 			BOOLEAN fOKToGo = FALSE;
1623 			BOOLEAN fDeductPoints = FALSE;
1624 
1625 			// ATE: OK, get source, dest guy if different... check for and then charge appropriate APs
1626 			if (gpSMCurrentMerc == gpItemPointerSoldier)
1627 			{
1628 				// We are doing this ourselve, continue
1629 				fOKToGo = TRUE;
1630 			}
1631 			else
1632 			{
1633 				// These guys are different....
1634 				fDeductPoints = TRUE;
1635 
1636 				// First check points for src guy
1637 				if ( gpItemPointerSoldier->bLife >= CONSCIOUSNESS )
1638 				{
1639 					if ( EnoughPoints( gpItemPointerSoldier, 3, 0, TRUE ) )
1640 					{
1641 						fOKToGo = TRUE;
1642 					}
1643 				}
1644 				else
1645 				{
1646 					fOKToGo = TRUE;
1647 				}
1648 
1649 				// Should we go on?
1650 				if ( fOKToGo )
1651 				{
1652 					if ( gpSMCurrentMerc->bLife >= CONSCIOUSNESS )
1653 					{
1654 						if ( EnoughPoints( gpSMCurrentMerc, 3, 0, TRUE ) )
1655 						{
1656 							fOKToGo = TRUE;
1657 						}
1658 						else
1659 						{
1660 							fOKToGo = FALSE;
1661 						}
1662 					}
1663 				}
1664 			}
1665 
1666 			if ( fOKToGo )
1667 			{
1668 				// OK, check if this is Nails, and we're in the vest position , don't allow
1669 				// it to come off....
1670 				if ( HandleNailsVestFetish( gpSMCurrentMerc, uiHandPos, gpItemPointer->usItem ) )
1671 				{
1672 					return;
1673 				}
1674 
1675 				usOldItemIndex = gpSMCurrentMerc->inv[ uiHandPos ].usItem;
1676 				usNewItemIndex = gpItemPointer->usItem;
1677 
1678 				if ( uiHandPos == HANDPOS || uiHandPos == SECONDHANDPOS || uiHandPos == HELMETPOS || uiHandPos == VESTPOS || uiHandPos == LEGPOS )
1679 				{
1680 					//if ( ValidAttachmentClass( usNewItemIndex, usOldItemIndex ) )
1681 					if ( ValidAttachment( usNewItemIndex, usOldItemIndex ) )
1682 					{
1683 						// it's an attempt to attach; bring up the inventory panel
1684 						if ( !InItemDescriptionBox( ) )
1685 						{
1686 							InitItemDescriptionBox( gpSMCurrentMerc, (UINT8)uiHandPos, SM_ITEMDESC_START_X, SM_ITEMDESC_START_Y, 0 );
1687 						}
1688 						return;
1689 					}
1690 					else if ( ValidMerge( usNewItemIndex, usOldItemIndex ) )
1691 					{
1692 						// bring up merge requestor
1693 						gubHandPos = (UINT8) uiHandPos;
1694 						gusOldItemIndex = usOldItemIndex;
1695 						gusNewItemIndex = usNewItemIndex;
1696 						gfDeductPoints = fDeductPoints;
1697 
1698 						if (guiCurrentScreen == SHOPKEEPER_SCREEN)
1699 						{
1700 							//the only way to merge items is to pick them up.  In SKI when you pick up an item, the cursor is
1701 							//locked in a region, free it up.
1702 							FreeMouseCursor();
1703 
1704 							DoMessageBox(MSG_BOX_BASIC_STYLE, g_langRes->Message[STR_MERGE_ITEMS], SHOPKEEPER_SCREEN, MSG_BOX_FLAG_YESNO, MergeMessageBoxCallBack, NULL);
1705 						}
1706 						else
1707 							DoMessageBox(MSG_BOX_BASIC_STYLE, g_langRes->Message[STR_MERGE_ITEMS], GAME_SCREEN, MSG_BOX_FLAG_YESNO, MergeMessageBoxCallBack, NULL);
1708 						return;
1709 					}
1710 					// else handle normally
1711 				}
1712 
1713 
1714 				// remember the item type currently in the item pointer
1715 				usItemPrevInItemPointer = gpItemPointer->usItem;
1716 
1717 				if (guiCurrentScreen == SHOPKEEPER_SCREEN)
1718 				{
1719 					// If it's just been purchased or repaired, mark it as a "new item"
1720 					fNewItem = ( BOOLEAN ) ( gMoveingItem.uiFlags & ( ARMS_INV_JUST_PURCHASED | ARMS_INV_ITEM_REPAIRED ) );
1721 				}
1722 
1723 				// try to place the item in the cursor into this inventory slot
1724 				if ( UIHandleItemPlacement( (UINT8) uiHandPos, usOldItemIndex, usNewItemIndex, fDeductPoints ) )
1725 				{
1726 					// it worked!  if we're in the SKI...
1727 					if (guiCurrentScreen == SHOPKEEPER_SCREEN)
1728 					{
1729 						SetNewItem( gpSMCurrentMerc, ( UINT8 ) uiHandPos, fNewItem );
1730 
1731 						// and the cursor is now empty
1732 						if( gpItemPointer == NULL )
1733 						{
1734 							// clean up
1735 							gMoveingItem = INVENTORY_IN_SLOT{};
1736 							SetSkiCursor( CURSOR_NORMAL );
1737 						}
1738 						else
1739 						{
1740 							// if we're holding something else in the pointer now
1741 							if ( usItemPrevInItemPointer != gpItemPointer->usItem )
1742 							{
1743 								// pick up item swapped out of inventory slot into
1744 								// cursor (don't try to sell)
1745 								BeginSkiItemPointer( PLAYERS_INVENTORY, -1, FALSE );
1746 							}
1747 							else
1748 							{
1749 								// otherwise, leave the cursor as is, means more items
1750 								// were picked up at once than can be placed in this slot
1751 								// we deal with this by leaving the remainder in the
1752 								// cursor, to be put down elsewhere using subsequent
1753 								// clicks
1754 							}
1755 						}
1756 					}
1757 
1758 					// Setup a timer....
1759 					//guiMouseOverItemTime = GetJA2Clock( );
1760 					//gfCheckForMouseOverItem = TRUE;
1761 					//gbCheckForMouseOverItemPos = (INT8)uiHandPos;
1762 				}
1763 
1764 				/*
1765 				// Try to place here
1766 				if ( PlaceObject( gpSMCurrentMerc, (UINT8)uiHandPos, gpItemPointer ) )
1767 				{
1768 
1769 					if ( fDeductPoints )
1770 					{
1771 						// Deduct points
1772 						if ( gpItemPointerSoldier->bLife >= CONSCIOUSNESS )
1773 						{
1774 							DeductPoints( gpItemPointerSoldier,  2, 0 );
1775 						}
1776 						if ( gpSMCurrentMerc->bLife >= CONSCIOUSNESS )
1777 						{
1778 							DeductPoints( gpSMCurrentMerc,  2, 0 );
1779 						}
1780 					}
1781 
1782 					HandleTacticalEffectsOfEquipmentChange( gpSMCurrentMerc, uiHandPos, usOldItemIndex, usNewItemIndex );
1783 
1784 					// Dirty
1785 					fInterfacePanelDirty = DIRTYLEVEL2;
1786 
1787 					// Check if it's the same now!
1788 					if ( gpItemPointer->ubNumberOfObjects == 0 )
1789 					{
1790 						EndItemPointer( );
1791 					}
1792 
1793 					// Setup a timer....
1794 					guiMouseOverItemTime = GetJA2Clock( );
1795 					gfCheckForMouseOverItem = TRUE;
1796 					gbCheckForMouseOverItemPos = (INT8)uiHandPos;
1797 
1798 				}*/
1799 			}
1800 		}
1801 	}
1802 	else if (iReason & MSYS_CALLBACK_REASON_RBUTTON_DWN)
1803 	{
1804 		fRightDown = TRUE;
1805 	}
1806 	else if (iReason & MSYS_CALLBACK_REASON_RBUTTON_UP && fRightDown )
1807 	{
1808 		fRightDown = FALSE;
1809 
1810 		// Return if empty
1811 		if ( gpSMCurrentMerc->inv[ uiHandPos ].usItem == NOTHING )
1812 			return;
1813 
1814 		// Turn off new item glow!
1815 		gpSMCurrentMerc->bNewItemCount[ uiHandPos ] = 0;
1816 
1817 		// Some global stuff here - for esc, etc
1818 		// Check for # of slots in item
1819 		if((gpSMCurrentMerc->inv[uiHandPos].ubNumberOfObjects > 1 &&
1820 			ItemSlotLimit(gpSMCurrentMerc->inv[uiHandPos].usItem, (UINT8)uiHandPos) > 0) &&
1821 			(guiCurrentScreen != MAP_SCREEN))
1822 		{
1823 			if ( !InItemStackPopup( )  )
1824 			{
1825 				InitItemStackPopup(gpSMCurrentMerc, (UINT8)uiHandPos, SM_ITEMDESC_START_X,
1826 							INV_INTERFACE_START_Y, SM_ITEMDESC_WIDTH,
1827 							SCREEN_HEIGHT - INV_INTERFACE_START_Y );
1828 			}
1829 		}
1830 		else
1831 		{
1832 			if ( !InItemDescriptionBox( ) )
1833 			{
1834 				InitItemDescriptionBox(gpSMCurrentMerc, (UINT8)uiHandPos,
1835 							SM_ITEMDESC_START_X, SM_ITEMDESC_START_Y, 0);
1836 			}
1837 		}
1838 	}
1839 	else if (iReason & MSYS_CALLBACK_REASON_LOST_MOUSE )
1840 	{
1841 		fRightDown = FALSE;
1842 	}
1843 
1844 }
1845 
1846 
MergeMessageBoxCallBack(MessageBoxReturnValue const ubExitValue)1847 static void MergeMessageBoxCallBack(MessageBoxReturnValue const ubExitValue)
1848 {
1849 	if ( ubExitValue == MSG_BOX_RETURN_YES )
1850 	{
1851 		AttachObject( gpItemPointerSoldier, &( gpSMCurrentMerc->inv[ gubHandPos ] ), gpItemPointer );
1852 
1853 		// re-evaluate repairs
1854 		gfReEvaluateEveryonesNothingToDo = TRUE;
1855 
1856 		if (gpItemPointer->usItem == NOTHING)
1857 		{
1858 			// merge item consumed
1859 			EndItemPointer();
1860 			fInterfacePanelDirty = DIRTYLEVEL2;
1861 		}
1862 	}
1863 	else
1864 	{
1865 		UIHandleItemPlacement( gubHandPos, gusOldItemIndex, gusNewItemIndex, gfDeductPoints );
1866 	}
1867 }
1868 
1869 
HandleMouseOverSoldierFaceForContMove(SOLDIERTYPE * pSoldier,BOOLEAN fOn)1870 static void HandleMouseOverSoldierFaceForContMove(SOLDIERTYPE* pSoldier, BOOLEAN fOn)
1871 {
1872 	INT16 sGridNo;
1873 
1874 	if ( pSoldier == NULL )
1875 	{
1876 		return;
1877 	}
1878 
1879 	if ( fOn )
1880 	{
1881 		// Check if we are waiting to continue move...
1882 		if ( CheckForMercContMove( pSoldier ) )
1883 		{
1884 			// Display 'cont' on face....
1885 			// Get face
1886 			FACETYPE* const pFace = pSoldier->face;
1887 
1888 			pFace->fDisplayTextOver = FACE_DRAW_TEXT_OVER;
1889 			pFace->zDisplayText = TacticalStr[ CONTINUE_OVER_FACE_STR ];
1890 
1891 			sGridNo = pSoldier->sFinalDestination;
1892 
1893 			if ( pSoldier->bGoodContPath )
1894 			{
1895 				sGridNo = pSoldier->sContPathLocation;
1896 			}
1897 
1898 			// While our mouse is here, draw a path!
1899 			PlotPath(pSoldier, sGridNo, NO_COPYROUTE, PLOT, pSoldier->usUIMovementMode, pSoldier->bActionPoints);
1900 		}
1901 	}
1902 	else
1903 	{
1904 		// Remove 'cont' on face....
1905 		// Get face
1906 		FACETYPE* const pFace = pSoldier->face;
1907 
1908 		pFace->fDisplayTextOver = FACE_ERASE_TEXT_OVER;
1909 
1910 		// Erase path!
1911 		ErasePath();
1912 	}
1913 
1914 	fInterfacePanelDirty = DIRTYLEVEL2;
1915 }
1916 
1917 
SelectedMercButtonMoveCallback(MOUSE_REGION * pRegion,INT32 iReason)1918 static void SelectedMercButtonMoveCallback(MOUSE_REGION* pRegion, INT32 iReason)
1919 {
1920 	if ( gpSMCurrentMerc == NULL )
1921 	{
1922 		return;
1923 	}
1924 
1925 	if (iReason & MSYS_CALLBACK_REASON_MOVE )
1926 	{
1927 		HandleMouseOverSoldierFaceForContMove( gpSMCurrentMerc, TRUE );
1928 	}
1929 	else if ( iReason & MSYS_CALLBACK_REASON_LOST_MOUSE )
1930 	{
1931 		HandleMouseOverSoldierFaceForContMove( gpSMCurrentMerc, FALSE );
1932 	}
1933 }
1934 
1935 
SelectedMercButtonCallback(MOUSE_REGION * pRegion,INT32 iReason)1936 static void SelectedMercButtonCallback(MOUSE_REGION* pRegion, INT32 iReason)
1937 {
1938 	if ( gpSMCurrentMerc == NULL )
1939 	{
1940 		return;
1941 	}
1942 
1943 	//if we are in the shop keeper interface
1944 	if (guiCurrentScreen == SHOPKEEPER_SCREEN) return;
1945 
1946 	if (iReason & MSYS_CALLBACK_REASON_LBUTTON_UP)
1947 	{
1948 		// ATE: Don't if this guy can't....
1949 		if ( !gfSMDisableForItems )
1950 		{
1951 			if ( gpSMCurrentMerc->uiStatusFlags & ( SOLDIER_DRIVER | SOLDIER_PASSENGER ) )
1952 			{
1953 				SOLDIERTYPE& vs = GetSoldierStructureForVehicle(GetVehicle(gpSMCurrentMerc->iVehicleId));
1954 				HandleLocateSelectMerc(&vs, false);
1955 			}
1956 			else
1957 			{
1958 				if ( CheckForMercContMove( gpSMCurrentMerc ) )
1959 				{
1960 					// Continue
1961 					ContinueMercMovement( gpSMCurrentMerc );
1962 					ErasePath();
1963 				}
1964 				else
1965 				{
1966 					HandleLocateSelectMerc(gpSMCurrentMerc, false);
1967 				}
1968 			}
1969 		}
1970 	}
1971 	else if (iReason & MSYS_CALLBACK_REASON_RBUTTON_DWN)
1972 	{
1973 		// ATE: Cannot get out by right clicking...
1974 		//if ( gpItemPointer == NULL )
1975 		{
1976 			//if ( !gfSMDisableForItems || ( gfSMDisableForItems && gpItemPointer == NULL ) )
1977 			{
1978 				// Delete desc
1979 				if ( InItemDescriptionBox( ) )
1980 				{
1981 					DeleteItemDescriptionBox( );
1982 				}
1983 
1984 				SetNewPanel(0);
1985 			}
1986 		}
1987 	}
1988 }
1989 
1990 
SelectedMercEnemyIndicatorCallback(MOUSE_REGION * pRegion,INT32 iReason)1991 static void SelectedMercEnemyIndicatorCallback(MOUSE_REGION* pRegion, INT32 iReason)
1992 {
1993 	if ( gpSMCurrentMerc == NULL )
1994 	{
1995 		return;
1996 	}
1997 
1998 	//if we are in the shop keeper interface
1999 	if (guiCurrentScreen == SHOPKEEPER_SCREEN) return;
2000 
2001 	if (iReason & MSYS_CALLBACK_REASON_LBUTTON_UP)
2002 	{
2003 		// ATE: Don't if this guy can't....
2004 		if ( !gfSMDisableForItems )
2005 		{
2006 			if ( gpSMCurrentMerc->uiStatusFlags & ( SOLDIER_DRIVER | SOLDIER_PASSENGER ) )
2007 			{
2008 			}
2009 			else
2010 			{
2011 				if ( gpSMCurrentMerc->bOppCnt > 0 )
2012 				{
2013 					CycleVisibleEnemies( gpSMCurrentMerc );
2014 				}
2015 				else
2016 				{
2017 					SelectedMercButtonCallback( pRegion, iReason );
2018 				}
2019 			}
2020 		}
2021 	}
2022 }
2023 
2024 
BtnStanceUpCallback(GUI_BUTTON * btn,INT32 reason)2025 static void BtnStanceUpCallback(GUI_BUTTON* btn, INT32 reason)
2026 {
2027 	if (reason & MSYS_CALLBACK_REASON_LBUTTON_UP)
2028 	{
2029 		INT8 bNewStance = gAnimControl[gpSMCurrentMerc->usAnimState].ubEndHeight;
2030 		switch (bNewStance)
2031 		{
2032 			case ANIM_CROUCH:
2033 				bNewStance = ANIM_STAND;
2034 				break;
2035 			case ANIM_PRONE:
2036 				bNewStance = ANIM_CROUCH;
2037 				break;
2038 		}
2039 		UIHandleSoldierStanceChange(gpSMCurrentMerc, bNewStance);
2040 	}
2041 }
2042 
2043 
BtnUpdownCallback(GUI_BUTTON * btn,INT32 reason)2044 void BtnUpdownCallback(GUI_BUTTON* btn, INT32 reason)
2045 {
2046 	if (reason & MSYS_CALLBACK_REASON_LBUTTON_UP)
2047 	{
2048 		// Change interface level via HandleUI handler
2049 		UIHandleChangeLevel(NULL);
2050 	}
2051 }
2052 
2053 
BtnClimbCallback(GUI_BUTTON * const btn,INT32 const reason)2054 static void BtnClimbCallback(GUI_BUTTON* const btn, INT32 const reason)
2055 {
2056 	if (reason & MSYS_CALLBACK_REASON_LBUTTON_UP)
2057 	{
2058 		SOLDIERTYPE* const s = gpSMCurrentMerc;
2059 		if (FindLowerLevel(s))
2060 		{
2061 			BeginSoldierClimbDownRoof(s);
2062 		}
2063 		else if (FindHigherLevel(s))
2064 		{
2065 			BeginSoldierClimbUpRoof(s);
2066 		}
2067 		else if (FindFenceJumpDirection(s))
2068 		{
2069 			BeginSoldierClimbFence(s);
2070 		}
2071 	}
2072 }
2073 
2074 
BtnStanceDownCallback(GUI_BUTTON * btn,INT32 reason)2075 static void BtnStanceDownCallback(GUI_BUTTON* btn, INT32 reason)
2076 {
2077 	if (reason & MSYS_CALLBACK_REASON_LBUTTON_UP)
2078 	{
2079 		INT8 bNewStance = gAnimControl[gpSMCurrentMerc->usAnimState].ubEndHeight;
2080 		switch (bNewStance)
2081 		{
2082 			case ANIM_STAND:
2083 				bNewStance = ANIM_CROUCH;
2084 				break;
2085 			case ANIM_CROUCH:
2086 				bNewStance = ANIM_PRONE;
2087 				break;
2088 		}
2089 		UIHandleSoldierStanceChange(gpSMCurrentMerc, bNewStance);
2090 	}
2091 }
2092 
2093 
BtnStealthModeCallback(GUI_BUTTON * btn,INT32 reason)2094 static void BtnStealthModeCallback(GUI_BUTTON* btn, INT32 reason)
2095 {
2096 	if (reason & MSYS_CALLBACK_REASON_LBUTTON_UP)
2097 	{
2098 		gpSMCurrentMerc->bStealthMode = !gpSMCurrentMerc->bStealthMode;
2099 		gfUIStanceDifferent = TRUE;
2100 		gfPlotNewMovement = TRUE;
2101 		fInterfacePanelDirty = DIRTYLEVEL2;
2102 	}
2103 }
2104 
2105 
BtnHandCursorCallback(GUI_BUTTON * btn,INT32 reason)2106 static void BtnHandCursorCallback(GUI_BUTTON* btn, INT32 reason)
2107 {
2108 	if (reason & MSYS_CALLBACK_REASON_LBUTTON_UP)
2109 	{
2110 		ToggleHandCursorMode(&guiCurrentEvent);
2111 	}
2112 }
2113 
2114 
BtnTalkCallback(GUI_BUTTON * btn,INT32 reason)2115 static void BtnTalkCallback(GUI_BUTTON* btn, INT32 reason)
2116 {
2117 	if (reason & MSYS_CALLBACK_REASON_LBUTTON_UP)
2118 	{
2119 		ToggleTalkCursorMode(&guiCurrentEvent);
2120 	}
2121 }
2122 
2123 
BtnMuteCallback(GUI_BUTTON * btn,INT32 reason)2124 static void BtnMuteCallback(GUI_BUTTON* btn, INT32 reason)
2125 {
2126 	if (reason & MSYS_CALLBACK_REASON_LBUTTON_UP)
2127 	{
2128 		gpSMCurrentMerc->uiStatusFlags ^= SOLDIER_MUTE;
2129 		ST::string msg = (gpSMCurrentMerc->uiStatusFlags & SOLDIER_MUTE ? TacticalStr[MUTE_ON_STR] : TacticalStr[MUTE_OFF_STR]);
2130 		ScreenMsg(FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, st_format_printf(msg, gpSMCurrentMerc->name));
2131 	}
2132 }
2133 
2134 
SelectMerc(SOLDIERTYPE * const s)2135 static void SelectMerc(SOLDIERTYPE* const s)
2136 {
2137 	gSelectSMPanelToMerc = s;
2138 
2139 	if (!gfInItemPickupMenu)
2140 	{
2141 		BOOLEAN set_locator;
2142 		if (guiCurrentScreen == SHOPKEEPER_SCREEN)
2143 		{
2144 			// Refresh background for player slots (in case item values change due to Flo's discount)
2145 			gubSkiDirtyLevel = SKI_DIRTY_LEVEL2;
2146 			set_locator = DONTSETLOCATOR;
2147 		}
2148 		else
2149 		{
2150 			set_locator = SETLOCATOR;
2151 		}
2152 		LocateSoldier(s, set_locator);
2153 	}
2154 
2155 	// If the user is in the shop keeper interface and is in the item desc
2156 	if (guiCurrentScreen == SHOPKEEPER_SCREEN && InItemDescriptionBox())
2157 	{
2158 		DeleteItemDescriptionBox();
2159 	}
2160 }
2161 
2162 
BtnPrevMercCallback(GUI_BUTTON * btn,INT32 reason)2163 static void BtnPrevMercCallback(GUI_BUTTON* btn, INT32 reason)
2164 {
2165 	if (reason & MSYS_CALLBACK_REASON_LBUTTON_UP)
2166 	{
2167 		SelectMerc(FindPrevActiveAndAliveMerc(gpSMCurrentMerc, TRUE, TRUE));
2168 	}
2169 }
2170 
2171 
BtnNextMercCallback(GUI_BUTTON * btn,INT32 reason)2172 static void BtnNextMercCallback(GUI_BUTTON* btn, INT32 reason)
2173 {
2174 	if (reason & MSYS_CALLBACK_REASON_LBUTTON_UP)
2175 	{
2176 		SelectMerc(FindNextActiveAndAliveMerc(gpSMCurrentMerc, TRUE, TRUE));
2177 	}
2178 }
2179 
2180 
BtnOptionsCallback(GUI_BUTTON * btn,INT32 reason)2181 static void BtnOptionsCallback(GUI_BUTTON* btn, INT32 reason)
2182 {
2183 	if (reason & MSYS_CALLBACK_REASON_LBUTTON_UP)
2184 	{
2185 		guiPreviousOptionScreen = guiCurrentScreen;
2186 		LeaveTacticalScreen(OPTIONS_SCREEN);
2187 	}
2188 }
2189 
2190 
BtnSMDoneCallback(GUI_BUTTON * btn,INT32 reason)2191 static void BtnSMDoneCallback(GUI_BUTTON* btn, INT32 reason)
2192 {
2193 	if (reason & MSYS_CALLBACK_REASON_LBUTTON_UP)
2194 	{
2195 		gfBeginEndTurn = TRUE;
2196 	}
2197 }
2198 
2199 
BtnMapScreenCallback(GUI_BUTTON * btn,INT32 reason)2200 static void BtnMapScreenCallback(GUI_BUTTON* btn, INT32 reason)
2201 {
2202 	if (reason & MSYS_CALLBACK_REASON_LBUTTON_UP)
2203 	{
2204 		// Enter mapscreen...
2205 		//gfEnteringMapScreen = TRUE;
2206 		GoToMapScreenFromTactical();
2207 	}
2208 }
2209 
2210 
BtnBurstModeCallback(GUI_BUTTON * btn,INT32 reason)2211 static void BtnBurstModeCallback(GUI_BUTTON* btn, INT32 reason)
2212 {
2213 	if (reason & MSYS_CALLBACK_REASON_LBUTTON_UP)
2214 	{
2215 		ChangeWeaponMode(gpSMCurrentMerc);
2216 	}
2217 }
2218 
2219 
BtnLookCallback(GUI_BUTTON * btn,INT32 reason)2220 static void BtnLookCallback(GUI_BUTTON* btn, INT32 reason)
2221 {
2222 	if (reason & MSYS_CALLBACK_REASON_LBUTTON_UP)
2223 	{
2224 		ToggleLookCursorMode();
2225 	}
2226 }
2227 
2228 
MakeRegion(TeamPanelSlot & tp,MOUSE_REGION & r,INT32 const x,INT32 const y,INT32 const w,INT32 const h,MOUSE_CALLBACK const move,MOUSE_CALLBACK const click)2229 static void MakeRegion(TeamPanelSlot& tp, MOUSE_REGION& r, INT32 const x, INT32 const y, INT32 const w, INT32 const h, MOUSE_CALLBACK const move, MOUSE_CALLBACK const click)
2230 {
2231 	MSYS_DefineRegion(&r, x, y , x + w, y + h, MSYS_PRIORITY_NORMAL, MSYS_NO_CURSOR, move, click);
2232 	r.SetUserPtr(&tp);
2233 }
2234 
2235 
2236 static void EnemyIndicatorClickCallback(MOUSE_REGION* pRegion, INT32 iReason);
2237 static void MercFacePanelCallback(MOUSE_REGION* pRegion, INT32 iReason);
2238 static void MercFacePanelMoveCallback(MOUSE_REGION* pRegion, INT32 iReason);
2239 static void TMClickFirstHandInvCallback(MOUSE_REGION* pRegion, INT32 iReason);
2240 static void TMClickSecondHandInvCallback(MOUSE_REGION* pRegion, INT32 iReason);
2241 
2242 
InitializeTEAMPanel(void)2243 void InitializeTEAMPanel(void)
2244 {
2245 	// INit viewport region
2246 	// Set global mouse regions
2247 	// Define region for viewport
2248 	MSYS_DefineRegion(&gViewportRegion, 0, 0, gsVIEWPORT_END_X, gsVIEWPORT_END_Y, MSYS_PRIORITY_NORMAL, VIDEO_NO_CURSOR, MSYS_NO_CALLBACK, MSYS_NO_CALLBACK);
2249 
2250 	guiTEAMPanel   = AddVideoObjectFromFile(INTERFACEDIR "/bottom_bar.sti");
2251 	guiTEAMObjects = AddVideoObjectFromFile(INTERFACEDIR "/gold_front.sti");
2252 	guiVEHINV      = AddVideoObjectFromFile(INTERFACEDIR "/inventor.sti");
2253 
2254 	FillEmptySpaceAtBottom();
2255 
2256 	// Create buttons
2257 	CreateTEAMPanelButtons();
2258 
2259 	// Set viewports
2260 	// Define region for panel
2261 	MSYS_DefineRegion(&gTEAM_PanelRegion, 0, gsVIEWPORT_END_Y, SCREEN_WIDTH, SCREEN_HEIGHT, MSYS_PRIORITY_NORMAL, CURSOR_NORMAL, MSYS_NO_CALLBACK, MSYS_NO_CALLBACK);
2262 
2263 	INT32       dx = 0;
2264 	INT32 const dy = INTERFACE_START_Y;
2265 	FOR_EACH_TEAM_PANEL_SLOT(i)
2266 	{
2267 		TeamPanelSlot& tp = *i;
2268 
2269 		INT32 const face_x = dx + TM_FACE_X;
2270 		INT32 const face_y = dy + TM_FACE_Y;
2271 		MakeRegion(tp, tp.face, face_x, face_y, TM_FACE_WIDTH, TM_FACE_HEIGHT,
2272 				MercFacePanelMoveCallback, MercFacePanelCallback);
2273 		MakeRegion(tp, tp.enemy_indicator, face_x + 1, face_y + 1, INDICATOR_BOX_WIDTH - 1,
2274 				INDICATOR_BOX_HEIGHT - 1, MSYS_NO_CALLBACK, EnemyIndicatorClickCallback);
2275 
2276 		if (IsMouseInRegion(tp.face))
2277 		{
2278 			SOLDIERTYPE* const s = tp.merc;
2279 			if (s) HandleMouseOverSoldierFaceForContMove(s, TRUE);
2280 		}
2281 
2282 		MakeRegion(tp, tp.bars, dx + TM_BARS_X, dy + TM_BARS_Y,
2283 				TM_BARS_WIDTH, TM_BARS_HEIGHT, MSYS_NO_CALLBACK, MercFacePanelCallback);
2284 		MakeRegion(tp, tp.left_bars, dx + TM_FACE_X - 8, dy + TM_FACE_Y, 8, TM_BARS_HEIGHT,
2285 				MSYS_NO_CALLBACK, MercFacePanelCallback);
2286 
2287 		INT32 const hand_x = dx + TM_INV_HAND1STARTX;
2288 		INT32 const hand_y = dy + TM_INV_HAND1STARTY;
2289 		MakeRegion(tp, tp.first_hand, hand_x, hand_y, TM_INV_WIDTH, TM_INV_HEIGHT,
2290 				MSYS_NO_CALLBACK, TMClickFirstHandInvCallback);
2291 		MakeRegion(tp, tp.second_hand, hand_x, hand_y + TM_INV_HAND_SEPY, TM_INV_WIDTH,
2292 				TM_INV_HEIGHT, MSYS_NO_CALLBACK, TMClickSecondHandInvCallback);
2293 
2294 		dx += TM_INV_HAND_SEP;
2295 	}
2296 }
2297 
2298 
ShutdownTEAMPanel(void)2299 void ShutdownTEAMPanel(void)
2300 {
2301 	// All buttons and regions and video objects and video surfaces will be deleted at shutddown of SGM
2302 	// We may want to delete them at the interm as well, to free up room for other panels
2303 	DeleteVideoObject(guiTEAMPanel);
2304 	DeleteVideoObject(guiTEAMObjects);
2305 	DeleteVideoObject(guiVEHINV);
2306 
2307 	MSYS_RemoveRegion(&gTEAM_PanelRegion);
2308 	MSYS_RemoveRegion(&gViewportRegion);
2309 
2310 	FOR_EACH_TEAM_PANEL_SLOT(i)
2311 	{
2312 		MSYS_RemoveRegion(&i->face);
2313 		MSYS_RemoveRegion(&i->enemy_indicator);
2314 		MSYS_RemoveRegion(&i->bars);
2315 		MSYS_RemoveRegion(&i->left_bars);
2316 		MSYS_RemoveRegion(&i->first_hand);
2317 		MSYS_RemoveRegion(&i->second_hand);
2318 
2319 		SOLDIERTYPE* const s = i->merc;
2320 		if (s) HandleMouseOverSoldierFaceForContMove(s, FALSE);
2321 	}
2322 
2323 	RemoveTEAMPanelButtons();
2324 
2325 	// start rendering radar region again,
2326 	fRenderRadarScreen = TRUE;
2327 }
2328 
2329 
RenderTeamSlotBorder(const SOLDIERTYPE * const s,const INT32 dx,const INT32 dy)2330 static void RenderTeamSlotBorder(const SOLDIERTYPE* const s, const INT32 dx, const INT32 dy)
2331 {
2332 	UINT16 region;
2333 	if      (gTacticalStatus.ubCurrentTeam != OUR_TEAM) region = 1; // Hatch out
2334 	else if (INTERRUPT_QUEUED && (!s || s->bMoved))     region = 1; // Hatch out
2335 	else if (s && s == GetSelectedMan())                region = 0; // Active border
2336 	else                                                return;
2337 	const INT32 x = dx + TM_FACEHIGHTL_X;
2338 	const INT32 y = dy + TM_FACEHIGHTL_Y;
2339 	BltVideoObject(guiSAVEBUFFER, guiTEAMObjects, region, x, y);
2340 }
2341 
2342 
2343 static void RenderSoldierTeamInv(SOLDIERTYPE const&, INT16 x, INT16 y, DirtyLevel);
2344 static void UpdateTEAMPanel(void);
2345 
2346 
RenderTEAMPanel(DirtyLevel const dirty_level)2347 void RenderTEAMPanel(DirtyLevel const dirty_level)
2348 {
2349 	if (dirty_level == DIRTYLEVEL2)
2350 	{
2351 		MarkAButtonDirty(iTEAMPanelButtons[TEAM_DONE_BUTTON]);
2352 		MarkAButtonDirty(iTEAMPanelButtons[TEAM_MAP_SCREEN_BUTTON]);
2353 		MarkAButtonDirty(iTEAMPanelButtons[CHANGE_SQUAD_BUTTON]);
2354 
2355 		BltVideoObject(guiSAVEBUFFER, guiTEAMPanel, 0, INTERFACE_START_X, INTERFACE_START_Y);
2356 
2357 		// LOOP THROUGH ALL MERCS ON TEAM PANEL
2358 		INT32       dx = 0;
2359 		INT32 const dy = INTERFACE_START_Y;
2360 		FOR_EACH_TEAM_PANEL_SLOT(i)
2361 		{
2362 			SOLDIERTYPE const* const s  = i->merc;
2363 			if (s)
2364 			{
2365 				RenderSoldierFace(*s, dx + TM_FACE_X, dy + TM_FACE_Y);
2366 			}
2367 			else
2368 			{
2369 				//BLIT CLOSE PANEL
2370 				BltVideoObject(guiSAVEBUFFER, guiCLOSE, 5, dx + TM_FACE_X, dy + TM_FACE_Y);
2371 			}
2372 
2373 			RenderTeamSlotBorder(s, dx, dy);
2374 
2375 			if (s)
2376 			{
2377 				ST::string help;
2378 				ST::string help_buf;
2379 
2380 				// Add text for first hand popup
2381 				if (s->uiStatusFlags & SOLDIER_DRIVER)
2382 				{
2383 					// Get soldier pointer for vehicle.....
2384 					SOLDIERTYPE const& vs = GetSoldierStructureForVehicle(GetVehicle(s->iVehicleId));
2385 					help_buf = st_format_printf(TacticalStr[DRIVER_POPUPTEXT], vs.bLife,
2386 							vs.bLifeMax, vs.bBreath, vs.bBreathMax);
2387 					help = help_buf;
2388 				}
2389 				else if (s->uiStatusFlags & SOLDIER_DEAD)
2390 				{
2391 					help = ST::null;
2392 				}
2393 				else
2394 				{
2395 					help_buf = GetHelpTextForItem(s->inv[HANDPOS]);
2396 					help = help_buf;
2397 				}
2398 				i->first_hand.SetFastHelpText(help);
2399 
2400 				// Add text for seonc hand popup
2401 				if (s->uiStatusFlags & (SOLDIER_PASSENGER | SOLDIER_DRIVER))
2402 				{
2403 					help = TacticalStr[EXIT_VEHICLE_POPUPTEXT];
2404 				}
2405 				else if (s->uiStatusFlags & SOLDIER_DEAD)
2406 				{
2407 					help = ST::null;
2408 				}
2409 				else
2410 				{
2411 					help_buf = GetHelpTextForItem(s->inv[SECONDHANDPOS]);
2412 					help = help_buf;
2413 				}
2414 				i->second_hand.SetFastHelpText(help);
2415 
2416 				// Restore AP/LIFE POSIITONS
2417 
2418 				// Render name!
2419 				UINT8 const foreground = s->bStealthMode ? FONT_MCOLOR_LTYELLOW : FONT_MCOLOR_LTGRAY;
2420 				SetFontAttributes(BLOCKFONT2, foreground);
2421 
2422 				// RENDER ON SAVE BUFFER!
2423 				SetFontDestBuffer(guiSAVEBUFFER);
2424 				INT16 sFontX;
2425 				INT16 sFontY;
2426 				FindFontCenterCoordinates(dx + TM_NAME_X, dy + TM_NAME_Y, TM_NAME_WIDTH, TM_NAME_HEIGHT,
2427 								s->name, BLOCKFONT2, &sFontX, &sFontY);
2428 				MPrint(sFontX, sFontY, s->name);
2429 				// reset to frame buffer!
2430 				SetFontDestBuffer(FRAME_BUFFER);
2431 			}
2432 
2433 			dx += TM_INV_HAND_SEP;
2434 		}
2435 
2436 		RestoreExternBackgroundRect(INTERFACE_START_X, INTERFACE_START_Y, SCREEN_WIDTH - INTERFACE_START_X,
2437 						SCREEN_HEIGHT - INTERFACE_START_Y);
2438 
2439 		RenderTownIDString();
2440 	}
2441 
2442 	// Loop through all mercs and make go
2443 	INT32       dx = 0;
2444 	INT32 const dy = INTERFACE_START_Y;
2445 	FOR_EACH_TEAM_PANEL_SLOT(i)
2446 	{
2447 		SOLDIERTYPE* const s = i->merc;
2448 		if (s)
2449 		{
2450 			// Update animations....
2451 			if (s->fClosePanel || s->fClosePanelToDie)
2452 			{
2453 				s->sPanelFaceX = s->face->usFaceX;
2454 				s->sPanelFaceY = s->face->usFaceY;
2455 			}
2456 
2457 			if (dirty_level != DIRTYLEVEL0)
2458 			{
2459 				// Update stats!
2460 				if (dirty_level == DIRTYLEVEL2) SetStatsHelp(i->bars, *s);
2461 
2462 				const INT32 x = dx + TM_AP_X;
2463 				const INT32 y = dy + TM_AP_Y;
2464 				const INT32 w = TM_AP_WIDTH;
2465 				const INT32 h = TM_AP_HEIGHT;
2466 				if (!(s->uiStatusFlags & SOLDIER_DEAD))
2467 				{
2468 					PrintAP(s, x, y, w, h);
2469 					DrawSoldierUIBars(*s, dx + TM_BARS_X + 2, dy + TM_BARS_Y + 2 + TM_LIFEBAR_HEIGHT,
2470 								TRUE, FRAME_BUFFER);
2471 				}
2472 				else
2473 				{
2474 					// Erase APs
2475 					RestoreExternBackgroundRect(x, y, w, h);
2476 				}
2477 			}
2478 
2479 			RenderSoldierTeamInv(*s, dx + TM_INV_HAND1STARTX, dy + TM_INV_HAND1STARTY, dirty_level);
2480 		}
2481 		dx += TM_INV_HAND_SEP;
2482 	}
2483 	UpdateTEAMPanel();
2484 
2485 	if (fRenderRadarScreen)
2486 	{
2487 		CreateMouseRegionForPauseOfClock();
2488 	}
2489 	else
2490 	{
2491 		RemoveMouseRegionForPauseOfClock();
2492 	}
2493 }
2494 
2495 
MakeButtonTeam(UINT idx,BUTTON_PICS * image,INT16 x,INT16 y,const GUI_CALLBACK click,const ST::string & help)2496 static void MakeButtonTeam(UINT idx, BUTTON_PICS* image, INT16 x, INT16 y, const GUI_CALLBACK click, const ST::string& help)
2497 try
2498 {
2499 	GUIButtonRef const btn = QuickCreateButton(image, x, y, MSYS_PRIORITY_HIGH - 1, click);
2500 	iTEAMPanelButtons[idx] = btn;
2501 	btn->SetFastHelpText(help);
2502 }
2503 catch (...)
2504 {
2505 	SLOGE("Cannot create Interface button");
2506 	throw;
2507 }
2508 
2509 
2510 static void BtnEndTurnCallback(GUI_BUTTON* btn, INT32 reason);
2511 static void BtnRostermodeCallback(GUI_BUTTON* btn, INT32 reason);
2512 static void BtnSquadCallback(GUI_BUTTON* btn, INT32 reason);
2513 
2514 
CreateTEAMPanelButtons(void)2515 void CreateTEAMPanelButtons(void)
2516 {
2517 	// Load button Graphics
2518 	iTEAMPanelImages[ENDTURN_IMAGES]    = LoadButtonImage(INTERFACEDIR "/bottom_bar_buttons.sti", 0, 3);
2519 	iTEAMPanelImages[ROSTERMODE_IMAGES] = UseLoadedButtonImage(iTEAMPanelImages[ENDTURN_IMAGES],  1, 4);
2520 	iTEAMPanelImages[DISK_IMAGES]       = UseLoadedButtonImage(iTEAMPanelImages[ENDTURN_IMAGES],  2, 5);
2521 
2522 	const INT32 dy = INTERFACE_START_Y;
2523 	MakeButtonTeam(TEAM_DONE_BUTTON, iTEAMPanelImages[ENDTURN_IMAGES], TM_ENDTURN_X, dy + TM_ENDTURN_Y,
2524 			BtnEndTurnCallback, TacticalStr[END_TURN_POPUPTEXT]);
2525 	MakeButtonTeam(TEAM_MAP_SCREEN_BUTTON, iTEAMPanelImages[ROSTERMODE_IMAGES], TM_ROSTERMODE_X,
2526 			dy + TM_ROSTERMODE_Y, BtnRostermodeCallback, TacticalStr[MAPSCREEN_POPUPTEXT]);
2527 	MakeButtonTeam(CHANGE_SQUAD_BUTTON, iTEAMPanelImages[DISK_IMAGES], TM_DISK_X, dy + TM_DISK_Y,
2528 			BtnSquadCallback, TacticalStr[CHANGE_SQUAD_POPUPTEXT]);
2529 }
2530 
2531 
RemoveTEAMPanelButtons(void)2532 void RemoveTEAMPanelButtons(void)
2533 {
2534 	for (UINT32 i = 0; i < NUM_TEAM_BUTTONS; ++i)
2535 	{
2536 		RemoveButton(iTEAMPanelButtons[i]);
2537 		UnloadButtonImage(iTEAMPanelImages[i]);
2538 	}
2539 }
2540 
2541 
BtnEndTurnCallback(GUI_BUTTON * btn,INT32 reason)2542 static void BtnEndTurnCallback(GUI_BUTTON* btn, INT32 reason)
2543 {
2544 	if (reason & MSYS_CALLBACK_REASON_LBUTTON_UP)
2545 	{
2546 		UIHandleEndTurn(NULL);
2547 	}
2548 }
2549 
2550 
BtnRostermodeCallback(GUI_BUTTON * btn,INT32 reason)2551 static void BtnRostermodeCallback(GUI_BUTTON* btn, INT32 reason)
2552 {
2553 	if (reason & MSYS_CALLBACK_REASON_LBUTTON_UP)
2554 	{
2555 		if (guiCurrentScreen == GAME_SCREEN) GoToMapScreenFromTactical();
2556 	}
2557 }
2558 
2559 
2560 // callback to handle squad switching callback
BtnSquadCallback(GUI_BUTTON * btn,INT32 reason)2561 static void BtnSquadCallback(GUI_BUTTON* btn, INT32 reason)
2562 {
2563 	if (reason & MSYS_CALLBACK_REASON_LBUTTON_UP)
2564 	{
2565 		ToggleRadarScreenRender();
2566 	}
2567 }
2568 
2569 
SetTEAMPanelCurrentMerc(void)2570 void SetTEAMPanelCurrentMerc(void)
2571 {
2572 	fInterfacePanelDirty = DIRTYLEVEL2;
2573 	UpdateTEAMPanel();
2574 }
2575 
2576 
UpdateTEAMPanel(void)2577 static void UpdateTEAMPanel(void)
2578 {
2579 	EnableButton(iTEAMPanelButtons[TEAM_DONE_BUTTON], gTacticalStatus.ubCurrentTeam == OUR_TEAM &&
2580 			gTacticalStatus.uiFlags & INCOMBAT);
2581 
2582 	EnableButton(iTEAMPanelButtons[TEAM_MAP_SCREEN_BUTTON], !(gTacticalStatus.uiFlags & ENGAGED_IN_CONV));
2583 
2584 	if (gfDisableTacticalPanelButtons)
2585 	{
2586 		DisableButton(iTEAMPanelButtons[TEAM_DONE_BUTTON]);
2587 		DisableButton(iTEAMPanelButtons[TEAM_MAP_SCREEN_BUTTON]);
2588 		DisableButton(iTEAMPanelButtons[CHANGE_SQUAD_BUTTON]);
2589 
2590 		// OK, disable item regions.......
2591 		FOR_EACH_TEAM_PANEL_SLOT(i)
2592 		{
2593 			i->enemy_indicator.Disable();
2594 			i->first_hand.Disable();
2595 			i->second_hand.Disable();
2596 		}
2597 
2598 		//disable the radar map region
2599 		// If NOT in overhead map
2600 		if (!InOverheadMap()) gRadarRegion.Disable();
2601 	}
2602 	else
2603 	{
2604 		EnableButton(iTEAMPanelButtons[CHANGE_SQUAD_BUTTON]);
2605 
2606 		FOR_EACH_TEAM_PANEL_SLOT(i)
2607 		{
2608 			i->enemy_indicator.Enable();
2609 			i->first_hand.Enable();
2610 			i->second_hand.Enable();
2611 		}
2612 
2613 		gRadarRegion.Enable();
2614 	}
2615 }
2616 
2617 
MercFacePanelMoveCallback(MOUSE_REGION * pRegion,INT32 iReason)2618 static void MercFacePanelMoveCallback(MOUSE_REGION* pRegion, INT32 iReason)
2619 {
2620 	// If our flags are set to do this, gofoit!
2621 	if (fInMapMode) return; // XXX necessary?
2622 
2623 	SOLDIERTYPE* const s = pRegion->GetUserPtr<TeamPanelSlot>()->merc;
2624 	if (!s || !s->bActive) return;
2625 
2626 	if (iReason & MSYS_CALLBACK_REASON_MOVE)
2627 	{
2628 		HandleMouseOverSoldierFaceForContMove(s, TRUE);
2629 	}
2630 	else if (iReason & MSYS_CALLBACK_REASON_LOST_MOUSE)
2631 	{
2632 		HandleMouseOverSoldierFaceForContMove(s, FALSE);
2633 	}
2634 }
2635 
2636 
EnemyIndicatorClickCallback(MOUSE_REGION * pRegion,INT32 iReason)2637 static void EnemyIndicatorClickCallback(MOUSE_REGION* pRegion, INT32 iReason)
2638 {
2639 	SOLDIERTYPE* const s = pRegion->GetUserPtr<TeamPanelSlot>()->merc;
2640 	if (!s || !s->bActive) return;
2641 
2642 	if (iReason & MSYS_CALLBACK_REASON_LBUTTON_DWN)
2643 	{
2644 		if (!(s->uiStatusFlags & (SOLDIER_DRIVER | SOLDIER_PASSENGER)))
2645 		{
2646 			if (s->bOppCnt > 0)
2647 			{	// Cycle....
2648 				CycleVisibleEnemies(s);
2649 			}
2650 			else
2651 			{
2652 				MercFacePanelCallback(pRegion, iReason);
2653 			}
2654 		}
2655 	}
2656 }
2657 
2658 
MercFacePanelCallback(MOUSE_REGION * pRegion,INT32 iReason)2659 static void MercFacePanelCallback(MOUSE_REGION* pRegion, INT32 iReason)
2660 {
2661 	SOLDIERTYPE* const s = pRegion->GetUserPtr<TeamPanelSlot>()->merc;
2662 	if (!s || !s->bActive) return;
2663 
2664 	// If our flags are set to do this, gofoit!
2665 	if (fInMapMode) // XXX necessary?
2666 	{
2667 		if (iReason & MSYS_CALLBACK_REASON_LBUTTON_DWN) SetInfoChar(s);
2668 		return;
2669 	}
2670 
2671 	if (iReason & MSYS_CALLBACK_REASON_LBUTTON_DWN)
2672 	{
2673 		if (!gfInItemPickupMenu && gpItemPointer == NULL)
2674 		{
2675 			if (s->uiStatusFlags & (SOLDIER_DRIVER | SOLDIER_PASSENGER))
2676 			{
2677 				SOLDIERTYPE& vs = GetSoldierStructureForVehicle(GetVehicle(s->iVehicleId));
2678 				HandleLocateSelectMerc(&vs, false);
2679 			}
2680 			else
2681 			{
2682 				if (!InOverheadMap())
2683 				{
2684 					// If we can continue a move, do so!
2685 					if (CheckForMercContMove(s))
2686 					{
2687 						// Continue
2688 						ContinueMercMovement(s);
2689 						ErasePath();
2690 					}
2691 					else
2692 					{
2693 						HandleLocateSelectMerc(s, false);
2694 					}
2695 				}
2696 				else
2697 				{
2698 					SelectSoldier(s, SELSOLDIER_ACKNOWLEDGE);
2699 				}
2700 			}
2701 		}
2702 	}
2703 	else if (iReason & MSYS_CALLBACK_REASON_RBUTTON_DWN)
2704 	{
2705 		if (!InOverheadMap())
2706 		{
2707 			// Only if guy is not dead!
2708 			if (!(s->uiStatusFlags & SOLDIER_DEAD) &&
2709 					!AM_AN_EPC(s) &&
2710 					!(s->uiStatusFlags & (SOLDIER_DRIVER | SOLDIER_PASSENGER)))
2711 			{
2712 				SetNewPanel(s);
2713 			}
2714 		}
2715 	}
2716 }
2717 
2718 
HandleLocateSelectMerc(SOLDIERTYPE * const s,bool const force_select)2719 void HandleLocateSelectMerc(SOLDIERTYPE* const s, bool const force_select)
2720 {
2721 	if (!s->bActive) return;
2722 
2723 	if (gpItemPointer != NULL)
2724 	{
2725 		// ATE: Disable for feel purposes....
2726 		//return;
2727 	}
2728 
2729 	// ATE: No matter what we do... if below OKLIFE, just locate....
2730 	if (s->bLife < OKLIFE)
2731 	{
2732 		LocateSoldier(s, SETLOCATOR);
2733 		return;
2734 	}
2735 
2736 	if (_KeyDown(ALT))
2737 	{
2738 		if (gGameSettings.fOptions[TOPTION_OLD_SELECTION_METHOD])
2739 		{
2740 			// Select merc
2741 			SelectSoldier(s, SELSOLDIER_ACKNOWLEDGE | SELSOLDIER_FROM_UI);
2742 			s->fFlashLocator = FALSE;
2743 			ResetMultiSelection();
2744 		}
2745 		else
2746 		{
2747 			// Just locate....
2748 			LocateSoldier(s, SETLOCATOR);
2749 		}
2750 	}
2751 	else
2752 	{
2753 		BOOLEAN fSelect = force_select;
2754 
2755 		if (s->fFlashLocator == FALSE)
2756 		{
2757 			// If we are currently selected, slide to location
2758 			if (s == GetSelectedMan())
2759 			{
2760 				SlideTo(s, SETLOCATOR);
2761 			}
2762 			else
2763 			{
2764 				if (gGameSettings.fOptions[TOPTION_OLD_SELECTION_METHOD])
2765 				{
2766 					LocateSoldier(s, SETLOCATOR);
2767 				}
2768 				else
2769 				{
2770 					fSelect = TRUE;
2771 				}
2772 			}
2773 		}
2774 		else
2775 		{
2776 			if (gGameSettings.fOptions[TOPTION_OLD_SELECTION_METHOD])
2777 			{
2778 				// If we are currently selected, slide to location
2779 				if (s == GetSelectedMan())
2780 				{
2781 					SlideTo(s, DONTSETLOCATOR);
2782 				}
2783 				else
2784 				{
2785 					LocateSoldier(s, DONTSETLOCATOR);
2786 				}
2787 
2788 				fSelect = TRUE;
2789 			}
2790 			else
2791 			{
2792 				if (s == GetSelectedMan())
2793 				{
2794 					LocateSoldier(s, DONTSETLOCATOR);
2795 				}
2796 				else
2797 				{
2798 					fSelect = TRUE;
2799 				}
2800 			}
2801 		}
2802 
2803 		if (fSelect)
2804 		{
2805 			// Select merc, only if alive!
2806 			if (!(s->uiStatusFlags & SOLDIER_DEAD))
2807 			{
2808 				SelectSoldier(s, SELSOLDIER_ACKNOWLEDGE | SELSOLDIER_FROM_UI);
2809 			}
2810 		}
2811 	}
2812 
2813 	ResetMultiSelection();
2814 
2815 	// Handle locate select merc....
2816 	HandleMouseOverSoldierFaceForContMove(s, TRUE);
2817 }
2818 
2819 
ShowRadioLocator(SOLDIERTYPE * s,UINT8 ubLocatorSpeed)2820 void ShowRadioLocator(SOLDIERTYPE* s, UINT8 ubLocatorSpeed)
2821 {
2822 	//LocateSoldier(s, FALSE); // IC - this is already being done outside of this function :)
2823 	s->fFlashLocator = TRUE;
2824 	s->sLocatorFrame = 0;
2825 
2826 	if ( ubLocatorSpeed == SHOW_LOCATOR_NORMAL )
2827 	{
2828 		s->ubNumLocateCycles = 5;
2829 	}
2830 	else
2831 	{
2832 		s->ubNumLocateCycles = 3;
2833 	}
2834 }
2835 
2836 
EndRadioLocator(SOLDIERTYPE * s)2837 void EndRadioLocator(SOLDIERTYPE* s)
2838 {
2839 	s->fFlashLocator = FALSE;
2840 	s->fShowLocator = FALSE;
2841 }
2842 
2843 
FinishAnySkullPanelAnimations(void)2844 void FinishAnySkullPanelAnimations(void)
2845 {
2846 	FOR_EACH_IN_TEAM(s, OUR_TEAM)
2847 	{
2848 		if (s->bLife == 0 &&
2849 			(s->fUIdeadMerc || s->fClosePanelToDie))
2850 		{
2851 			HandlePlayerTeamMemberDeathAfterSkullAnimation(s);
2852 
2853 			s->fUIdeadMerc      = FALSE;
2854 			s->fClosePanelToDie = FALSE;
2855 		}
2856 	}
2857 }
2858 
2859 
HandlePanelFaceAnimations(SOLDIERTYPE * pSoldier)2860 void HandlePanelFaceAnimations(SOLDIERTYPE* pSoldier)
2861 {
2862 	if ( pSoldier->bTeam != OUR_TEAM )
2863 	{
2864 		return;
2865 	}
2866 
2867 
2868 	if ( !pSoldier->bActive )
2869 	{
2870 		return;
2871 	}
2872 
2873 	if ( pSoldier->uiStatusFlags & SOLDIER_VEHICLE )
2874 	{
2875 		// Don't do this for a vehice.
2876 		return;
2877 	}
2878 
2879 	if ( pSoldier->fUICloseMerc )
2880 	{
2881 		pSoldier->fUICloseMerc = FALSE;
2882 	}
2883 
2884 	if ( pSoldier->fUIdeadMerc  )
2885 	{
2886 		pSoldier->sPanelFaceX = pSoldier->face->usFaceX;
2887 		pSoldier->sPanelFaceY = pSoldier->face->usFaceY;
2888 
2889 		pSoldier->fUIdeadMerc = FALSE;
2890 		pSoldier->fClosePanel = TRUE;
2891 		pSoldier->fClosePanelToDie = TRUE;
2892 		pSoldier->ubClosePanelFrame = 0;
2893 		pSoldier->ubDeadPanelFrame = 0;
2894 		RESETTIMECOUNTER( pSoldier->PanelAnimateCounter, 160 );
2895 	}
2896 
2897 	if ( pSoldier->fClosePanel )
2898 	{
2899 		if ( TIMECOUNTERDONE( pSoldier->PanelAnimateCounter, 160 ) )
2900 		{
2901 			pSoldier->ubClosePanelFrame++;
2902 
2903 			if ( pSoldier->ubClosePanelFrame > 5 )
2904 			{
2905 				pSoldier->fClosePanel = FALSE;
2906 				pSoldier->ubClosePanelFrame = 5;
2907 
2908 				if ( pSoldier->fClosePanelToDie )
2909 				{
2910 					pSoldier->fDeadPanel = TRUE;
2911 					//PlayJA2Sample(HEADCR_1, HIGHVOLUME, 1, MIDDLEPAN);
2912 				}
2913 				else
2914 				{
2915 					if (!pSoldier->face->fDisabled)
2916 					{
2917 						RestoreExternBackgroundRect( pSoldier->sPanelFaceX, pSoldier->sPanelFaceY, TM_FACE_WIDTH, TM_FACE_HEIGHT );
2918 					}
2919 				}
2920 				}
2921 			RESETTIMECOUNTER( pSoldier->PanelAnimateCounter, 160 );
2922 		}
2923 	}
2924 
2925 	if ( pSoldier->fClosePanel )
2926 	{
2927 		if (!pSoldier->face->fDisabled)
2928 		{
2929 			RestoreExternBackgroundRect(pSoldier->sPanelFaceX, pSoldier->sPanelFaceY, TM_FACE_WIDTH, TM_FACE_HEIGHT);
2930 			BltVideoObject(FRAME_BUFFER, guiCLOSE, pSoldier->ubClosePanelFrame,
2931 					pSoldier->sPanelFaceX, pSoldier->sPanelFaceY);
2932 			InvalidateRegion(pSoldier->sPanelFaceX, pSoldier->sPanelFaceY,
2933 					pSoldier->sPanelFaceX + TM_FACE_WIDTH,
2934 					pSoldier->sPanelFaceY + TM_FACE_HEIGHT);
2935 		}
2936 	}
2937 
2938 
2939 	if ( pSoldier->fDeadPanel )
2940 	{
2941 		if ( TIMECOUNTERDONE(  pSoldier->PanelAnimateCounter, 160 ) )
2942 		{
2943 			pSoldier->ubDeadPanelFrame++;
2944 
2945 			if ( pSoldier->ubDeadPanelFrame == 4 )
2946 			{
2947 				ScreenMsg(FONT_RED, MSG_SKULL_UI_FEEDBACK, st_format_printf(pMercDeadString, pSoldier->name));
2948 
2949 				PlayJA2Sample(DOORCR_1, HIGHVOLUME, 1, MIDDLEPAN);
2950 				PlayJA2Sample(HEADCR_1, HIGHVOLUME, 1, MIDDLEPAN);
2951 			}
2952 
2953 			if ( pSoldier->ubDeadPanelFrame > 5 )
2954 			{
2955 				pSoldier->fDeadPanel = FALSE;
2956 				pSoldier->ubDeadPanelFrame = 5;
2957 				pSoldier->fClosePanelToDie = FALSE;
2958 
2959 				// Finish!
2960 				if (!pSoldier->face->fDisabled)
2961 				{
2962 					BltVideoObject(guiSAVEBUFFER, guiDEAD, pSoldier->ubDeadPanelFrame,
2963 							pSoldier->sPanelFaceX, pSoldier->sPanelFaceY);
2964 
2965 					// Blit hatch!
2966 					BltVideoObject(guiSAVEBUFFER, guiHATCH, 0, pSoldier->sPanelFaceX,
2967 							pSoldier->sPanelFaceY);
2968 
2969 					RestoreExternBackgroundRect(pSoldier->sPanelFaceX,
2970 									pSoldier->sPanelFaceY, TM_FACE_WIDTH,
2971 									TM_FACE_HEIGHT);
2972 				}
2973 				HandlePlayerTeamMemberDeathAfterSkullAnimation( pSoldier );
2974 
2975 			}
2976 			RESETTIMECOUNTER( pSoldier->PanelAnimateCounter, 160 );
2977 		}
2978 	}
2979 
2980 	if ( pSoldier->fDeadPanel )
2981 	{
2982 		// Render panel!
2983 		if (!pSoldier->face->fDisabled)
2984 		{
2985 			BltVideoObject(FRAME_BUFFER, guiDEAD, pSoldier->ubDeadPanelFrame,
2986 					pSoldier->sPanelFaceX, pSoldier->sPanelFaceY);
2987 
2988 			// Blit hatch!
2989 			BltVideoObject(guiSAVEBUFFER, guiHATCH, 0, pSoldier->sPanelFaceX, pSoldier->sPanelFaceY);
2990 
2991 			InvalidateRegion(pSoldier->sPanelFaceX, pSoldier->sPanelFaceY,
2992 						pSoldier->sPanelFaceX + TM_FACE_WIDTH,
2993 						pSoldier->sPanelFaceY + TM_FACE_HEIGHT);
2994 		}
2995 	}
2996 }
2997 
2998 
RenderSoldierTeamInv(SOLDIERTYPE const & s,INT16 const x,INT16 y,DirtyLevel const dirty_level)2999 static void RenderSoldierTeamInv(SOLDIERTYPE const& s, INT16 const x, INT16 y, DirtyLevel const dirty_level)
3000 {
3001 	if (s.uiStatusFlags & SOLDIER_DEAD) return;
3002 
3003 	SGPVSurface* const buf = guiSAVEBUFFER;
3004 	INT16        const w   = TM_INV_WIDTH;
3005 	INT16        const h   = TM_INV_HEIGHT;
3006 	if (s.uiStatusFlags & SOLDIER_DRIVER)
3007 	{
3008 		BltVideoObject(buf, guiVEHINV, 0, x, y);
3009 		RestoreExternBackgroundRect(x, y, w, h);
3010 	}
3011 	else
3012 	{
3013 		// Look in primary hand
3014 		INVRenderItem(buf, &s, s.inv[HANDPOS], x, y, w, h, dirty_level, 0, SGP_TRANSPARENT);
3015 	}
3016 
3017 	y += TM_INV_HAND_SEPY;
3018 	if (s.uiStatusFlags & (SOLDIER_PASSENGER | SOLDIER_DRIVER))
3019 	{
3020 		BltVideoObject(buf, guiVEHINV, 1, x, y);
3021 		RestoreExternBackgroundRect(x, y, w, h);
3022 	}
3023 	else
3024 	{
3025 		// Do secondary hand
3026 		INVRenderItem(buf, &s, s.inv[SECONDHANDPOS], x, y, w, h, dirty_level, 0, SGP_TRANSPARENT);
3027 	}
3028 }
3029 
3030 
TMClickFirstHandInvCallback(MOUSE_REGION * pRegion,INT32 iReason)3031 static void TMClickFirstHandInvCallback(MOUSE_REGION* pRegion, INT32 iReason)
3032 {
3033 	SOLDIERTYPE* const s = pRegion->GetUserPtr<TeamPanelSlot>()->merc;
3034 	if (!s) return;
3035 
3036 	if (iReason == MSYS_CALLBACK_REASON_LBUTTON_UP )
3037 	{
3038 		// Change to use cursor mode...
3039 		guiPendingOverrideEvent = A_ON_TERRAIN;
3040 	}
3041 
3042 	if (iReason == MSYS_CALLBACK_REASON_RBUTTON_UP )
3043 	{
3044 		if (!AM_A_ROBOT(s))
3045 		{
3046 			const UINT16 usOldHandItem = s->inv[HANDPOS].usItem;
3047 			SwapHandItems(s);
3048 			ReLoadSoldierAnimationDueToHandItemChange(s, usOldHandItem, s->inv[HANDPOS].usItem);
3049 			fInterfacePanelDirty = DIRTYLEVEL2;
3050 		}
3051 	}
3052 }
3053 
3054 
TMClickSecondHandInvCallback(MOUSE_REGION * pRegion,INT32 iReason)3055 static void TMClickSecondHandInvCallback(MOUSE_REGION* pRegion, INT32 iReason)
3056 {
3057 	SOLDIERTYPE* const s = pRegion->GetUserPtr<TeamPanelSlot>()->merc;
3058 	if (!s) return;
3059 
3060 	if (iReason == MSYS_CALLBACK_REASON_LBUTTON_UP )
3061 	{
3062 		if (s->uiStatusFlags & (SOLDIER_PASSENGER | SOLDIER_DRIVER))
3063 		{
3064 			ExitVehicle(s);
3065 		}
3066 	}
3067 
3068 	if (iReason == MSYS_CALLBACK_REASON_RBUTTON_UP )
3069 	{
3070 		if (s->uiStatusFlags & (SOLDIER_PASSENGER | SOLDIER_DRIVER))
3071 		{
3072 		}
3073 		else
3074 		{
3075 			if (!AM_A_ROBOT(s))
3076 			{
3077 				const UINT16 usOldHandItem = s->inv[HANDPOS].usItem;
3078 				SwapHandItems(s);
3079 				ReLoadSoldierAnimationDueToHandItemChange(s, usOldHandItem, s->inv[HANDPOS].usItem);
3080 				fInterfacePanelDirty = DIRTYLEVEL2;
3081 			}
3082 		}
3083 	}
3084 }
3085 
3086 
PlayerExistsInSlot(const SOLDIERTYPE * const s)3087 static BOOLEAN PlayerExistsInSlot(const SOLDIERTYPE* const s)
3088 {
3089 	FOR_EACH_TEAM_PANEL_SLOT(i)
3090 	{
3091 		if (i->merc == s) return TRUE;
3092 	}
3093 	return FALSE;
3094 }
3095 
3096 
3097 static void RemovePlayerFromInterfaceTeamSlot(TeamPanelSlot&);
3098 
3099 
RemovePlayerFromTeamSlot(const SOLDIERTYPE * const s)3100 BOOLEAN RemovePlayerFromTeamSlot(const SOLDIERTYPE* const s)
3101 {
3102 	FOR_EACH_TEAM_PANEL_SLOT(i)
3103 	{
3104 		if (i->merc != s) continue;
3105 		RemovePlayerFromInterfaceTeamSlot(*i);
3106 		return TRUE;
3107 	}
3108 	return FALSE;
3109 }
3110 
3111 
AddPlayerToInterfaceTeamSlot(SOLDIERTYPE * const s)3112 static void AddPlayerToInterfaceTeamSlot(SOLDIERTYPE* const s)
3113 {
3114 	if (PlayerExistsInSlot(s)) return;
3115 
3116 	// Find a free slot
3117 	FOR_EACH_TEAM_PANEL_SLOT(i)
3118 	{
3119 		if (i->merc) continue;
3120 		i->merc = s;
3121 		fInterfacePanelDirty = DIRTYLEVEL2;
3122 		break;
3123 	}
3124 }
3125 
3126 
InitTEAMSlots(void)3127 void InitTEAMSlots(void)
3128 {
3129 	FOR_EACH_TEAM_PANEL_SLOT(i) i->merc = 0;
3130 }
3131 
3132 
GetPlayerFromInterfaceTeamSlot(UINT8 ubPanelSlot)3133 SOLDIERTYPE* GetPlayerFromInterfaceTeamSlot(UINT8 ubPanelSlot)
3134 {
3135 	if (ubPanelSlot >= NUM_TEAM_SLOTS) return NULL;
3136 	return gTeamPanel[ubPanelSlot].merc;
3137 }
3138 
3139 
RemoveAllPlayersFromSlot(void)3140 void RemoveAllPlayersFromSlot(void)
3141 {
3142 	FOR_EACH_TEAM_PANEL_SLOT(i)
3143 	{
3144 		if (!i->merc) continue;
3145 		RemovePlayerFromInterfaceTeamSlot(*i);
3146 	}
3147 }
3148 
3149 
RemovePlayerFromInterfaceTeamSlot(TeamPanelSlot & tp)3150 static void RemovePlayerFromInterfaceTeamSlot(TeamPanelSlot& tp)
3151 {
3152 	SOLDIERTYPE* const s = tp.merc;
3153 	tp.merc = 0;
3154 
3155 	if (!(s->uiStatusFlags & SOLDIER_DEAD))
3156 	{
3157 		// Set Id to close
3158 		s->fUICloseMerc = TRUE;
3159 	}
3160 
3161 	// Set face to inactive...
3162 	if (s->face) SetAutoFaceInActive(*s->face);
3163 
3164 	// DIRTY INTERFACE
3165 	fInterfacePanelDirty = DIRTYLEVEL2;
3166 }
3167 
3168 
RenderTownIDString(void)3169 void RenderTownIDString(void)
3170 {
3171 	INT16 sFontX, sFontY;
3172 
3173 	// Render town, position
3174 	SetFontAttributes(COMPFONT, 183);
3175 	ST::string zTownIDString = GetSectorIDString(gWorldSectorX, gWorldSectorY, gbWorldSectorZ, TRUE);
3176 	zTownIDString = ReduceStringLength(zTownIDString, 80, COMPFONT);
3177 	FindFontCenterCoordinates(548, SCREEN_HEIGHT - 55, 80, 16, zTownIDString, COMPFONT, &sFontX, &sFontY);
3178 	MPrint(sFontX, sFontY, zTownIDString);
3179 }
3180 
3181 
CheckForAndAddMercToTeamPanel(SOLDIERTYPE * const s)3182 void CheckForAndAddMercToTeamPanel(SOLDIERTYPE* const s)
3183 {
3184 	if (!s->bActive) return;
3185 	if (s->bTeam != OUR_TEAM) return;
3186 
3187 	// Are we in the loaded sector?
3188 	if (s->sSectorX == gWorldSectorX &&
3189 		s->sSectorY == gWorldSectorY &&
3190 		s->bSectorZ == gbWorldSectorZ &&
3191 		!s->fBetweenSectors &&
3192 		s->bInSector)
3193 	{
3194 		// IF on duty....
3195 		INT32 const cur_squad = CurrentSquad();
3196 		if (s->bAssignment == cur_squad || SoldierIsDeadAndWasOnSquad(s, cur_squad))
3197 		{
3198 			if (s->bAssignment == ASSIGNMENT_DEAD) s->fUICloseMerc = FALSE;
3199 
3200 			if (s->uiStatusFlags & SOLDIER_VEHICLE)
3201 			{
3202 				VEHICLETYPE const& v = GetVehicle(s->bVehicleID);
3203 				CFOR_EACH_PASSENGER(v, i) AddPlayerToInterfaceTeamSlot(*i);
3204 			}
3205 			else if (s->ubStrategicInsertionCode != INSERTION_CODE_CHOPPER)
3206 			{
3207 				// ATE: If we have the insertion code of helicopter, don't add just yet!
3208 				// (will add in heli code)
3209 				AddPlayerToInterfaceTeamSlot(s);
3210 			}
3211 		}
3212 	}
3213 	else
3214 	{
3215 		// Make sure we are NOT in this world!
3216 		RemoveSoldierFromGridNo(*s);
3217 		RemoveMercSlot(s);
3218 	}
3219 }
3220 
3221 
FindNextMercInTeamPanel(SOLDIERTYPE * const prev)3222 SOLDIERTYPE* FindNextMercInTeamPanel(SOLDIERTYPE* const prev)
3223 {
3224 	bool         seen_prev = false;
3225 	SOLDIERTYPE* before    = 0;
3226 	FOR_EACH_TEAM_PANEL_SLOT(i)
3227 	{
3228 		SOLDIERTYPE* const s = i->merc;
3229 		if (!s) continue;
3230 
3231 		if (s == prev)
3232 		{
3233 			seen_prev = true;
3234 			continue;
3235 		}
3236 
3237 		if (!OK_CONTROLLABLE_MERC(s))            continue;
3238 		if (!OK_INTERRUPT_MERC(s))               continue;
3239 		if (s->bAssignment != prev->bAssignment) continue;
3240 		if (seen_prev) return s;
3241 		if (!before) before = s;
3242 	}
3243 	return seen_prev && before ? before : prev;
3244 }
3245 
3246 
DisableTacticalTeamPanelButtons(BOOLEAN fDisable)3247 void DisableTacticalTeamPanelButtons(BOOLEAN fDisable)
3248 {
3249 	gfDisableTacticalPanelButtons = fDisable;
3250 }
3251 
3252 
BeginKeyPanelFromKeyShortcut(void)3253 void BeginKeyPanelFromKeyShortcut(void)
3254 {
3255 	SOLDIERTYPE *pSoldier = NULL;
3256 	INT16 sStartYPosition = 0;
3257 	INT16 sWidth = 0, sHeight = 0;
3258 
3259 	if ( gsCurInterfacePanel != SM_PANEL )
3260 	{
3261 		return;
3262 	}
3263 
3264 	if ( gpSMCurrentMerc == NULL )
3265 	{
3266 		return;
3267 	}
3268 
3269 	if ( gfInKeyRingPopup )
3270 	{
3271 		return;
3272 	}
3273 
3274 
3275 	sStartYPosition = INV_INTERFACE_START_Y;
3276 	sWidth  = SCREEN_WIDTH;
3277 	sHeight = SCREEN_HEIGHT - INV_INTERFACE_START_Y;
3278 	pSoldier = gpSMCurrentMerc;
3279 
3280 	//if we are in the shop keeper interface
3281 	if (guiCurrentScreen == SHOPKEEPER_SCREEN) return;
3282 
3283 	InitKeyRingPopup( pSoldier, 0, sStartYPosition, sWidth, sHeight );
3284 }
3285 
3286 
KeyRingItemPanelButtonCallback(MOUSE_REGION * pRegion,INT32 iReason)3287 void KeyRingItemPanelButtonCallback(MOUSE_REGION* pRegion, INT32 iReason)
3288 {
3289 	SOLDIERTYPE *pSoldier = NULL;
3290 	INT16 sStartYPosition = 0;
3291 	INT16 sWidth = 0, sHeight = 0;
3292 
3293 	if( guiCurrentScreen == MAP_SCREEN )
3294 	{
3295 		pSoldier = GetSelectedInfoChar();
3296 		if (pSoldier == NULL) return;
3297 
3298 		sStartYPosition = MAP_START_KEYRING_Y;
3299 		sWidth = 261;
3300 		sHeight = ( 359 - 107 );
3301 	}
3302 	else
3303 	{
3304 		if ( gpSMCurrentMerc == NULL )
3305 		{
3306 			return;
3307 		}
3308 
3309 		sStartYPosition = INV_INTERFACE_START_Y;
3310 		sWidth   = SCREEN_WIDTH;
3311 		sHeight  = SCREEN_HEIGHT - INV_INTERFACE_START_Y;
3312 		pSoldier = gpSMCurrentMerc;
3313 	}
3314 
3315 	//if we are in the shop keeper interface
3316 	if (guiCurrentScreen == SHOPKEEPER_SCREEN) return;
3317 
3318 	if (iReason & MSYS_CALLBACK_REASON_LBUTTON_UP)
3319 	{
3320 		if( guiCurrentScreen == MAP_SCREEN )
3321 		{
3322 			// shade the background
3323 			FRAME_BUFFER->ShadowRect(STD_SCREEN_X + 0, STD_SCREEN_Y + 107,
3324 							STD_SCREEN_X + 261, STD_SCREEN_Y + 359);
3325 			InvalidateRegion(STD_SCREEN_X + 0, STD_SCREEN_Y + 107, STD_SCREEN_X + 261, STD_SCREEN_Y + 359);
3326 			InitKeyRingPopup(pSoldier, STD_SCREEN_X + 0, sStartYPosition, sWidth, sHeight);
3327 		}
3328 		else
3329 		{
3330 			InitKeyRingPopup( pSoldier, 0, sStartYPosition, sWidth, sHeight );
3331 		}
3332 	}
3333 }
3334 
KeyRingSlotInvClickCallback(MOUSE_REGION * pRegion,INT32 iReason)3335 void KeyRingSlotInvClickCallback( MOUSE_REGION * pRegion, INT32 iReason )
3336 {
3337 	UINT32 uiKeyRing;
3338 	// Copyies of values
3339 	UINT16 usOldItemIndex;
3340 	static BOOLEAN fRightDown = FALSE;
3341 
3342 	uiKeyRing = MSYS_GetRegionUserData( pRegion, 0 );
3343 
3344 	if (iReason & MSYS_CALLBACK_REASON_LBUTTON_DWN )
3345 	{
3346 		//if we are in the shop keeper interface
3347 		if (guiCurrentScreen == SHOPKEEPER_SCREEN)
3348 		{
3349 			INVENTORY_IN_SLOT InvSlot;
3350 
3351 			if( gMoveingItem.sItemIndex == 0 )
3352 			{
3353 				//Delete the contents of the item cursor
3354 				gMoveingItem = INVENTORY_IN_SLOT{};
3355 			}
3356 			else
3357 			{
3358 				InvSlot = INVENTORY_IN_SLOT{};
3359 
3360 				// Return if empty
3361 				//if ( gpSMCurrentMerc->inv[ uiHandPos ].usItem == NOTHING )
3362 				//	return;
3363 
3364 
3365 				// Fill out the inv slot for the item
3366 				//InvSlot.sItemIndex = gpSMCurrentMerc->inv[ uiHandPos ].usItem;
3367 				//InvSlot.ubNumberOfItems = gpSMCurrentMerc->inv[ uiHandPos ].ubNumberOfObjects;
3368 				//InvSlot.ubItemQuality = gpSMCurrentMerc->inv[ uiHandPos ].bGunStatus;
3369 				//InvSlot.ItemObject = gpSMCurrentMerc->inv[uiHandPos];
3370 				//InvSlot.ubLocationOfObject = PLAYERS_INVENTORY;
3371 
3372 				//InvSlot.ubIdOfMercWhoOwnsTheItem = gpSMCurrentMerc->ubProfile;
3373 
3374 
3375 				//Add the item to the Players Offer Area
3376 				//AddItemToPlayersOfferArea( gpSMCurrentMerc->ubProfile, &InvSlot, (UINT8)uiHandPos );
3377 
3378 				// Dirty
3379 				fInterfacePanelDirty = DIRTYLEVEL2;
3380 			}
3381 			return;
3382 		}
3383 
3384 		// If we do not have an item in hand, start moving it
3385 		if ( gpItemPointer == NULL )
3386 		{
3387 			// Return if empty
3388 			if( ( gpItemPopupSoldier->pKeyRing[ uiKeyRing ].ubKeyID == INVALID_KEY_NUMBER ) || ( gpItemPopupSoldier->pKeyRing[ uiKeyRing ].ubNumber == 0 ) )
3389 				return;
3390 
3391 			// If our flags are set to do this, gofoit!
3392 			if (!fInMapMode)
3393 			{
3394 				SelectSoldier(gpItemPopupSoldier, SELSOLDIER_NONE);
3395 			}
3396 
3397 			usOldItemIndex =  ( UINT16 )uiKeyRing ;
3398 
3399 			BeginKeyRingItemPointer( gpItemPopupSoldier, (UINT8)usOldItemIndex );
3400 			//BeginItemPointer( gpSMCurrentMerc, (UINT8)uiHandPos );
3401 
3402 		}
3403 		else
3404 		{
3405 			BOOLEAN fOKToGo = FALSE;
3406 			BOOLEAN fDeductPoints = FALSE;
3407 
3408 			if( ( gpItemPointer ->usItem < FIRST_KEY ) || ( gpItemPointer ->usItem > KEY_32 ) )
3409 			{
3410 				return;
3411 			}
3412 
3413 			// ATE: OK, get source, dest guy if different... check for and then charge appropriate APs
3414 			if (gpItemPointerSoldier == NULL ||
3415 				gpItemPointerSoldier == GetSelectedInfoChar())
3416 			{
3417 				// We are doing this ourselve, continue
3418 				fOKToGo = TRUE;
3419 			}
3420 			else
3421 			{
3422 				// These guys are different....
3423 				fDeductPoints = TRUE;
3424 
3425 				// First check points for src guy
3426 				if ( gpItemPointerSoldier->bLife >= CONSCIOUSNESS )
3427 				{
3428 					if ( EnoughPoints( gpItemPointerSoldier, 2, 0, TRUE ) )
3429 					{
3430 						fOKToGo = TRUE;
3431 					}
3432 				}
3433 				else
3434 				{
3435 					fOKToGo = TRUE;
3436 				}
3437 
3438 				// Should we go on?
3439 				if ( fOKToGo )
3440 				{
3441 					if ( gpSMCurrentMerc->bLife >= CONSCIOUSNESS )
3442 					{
3443 						if ( EnoughPoints( gpSMCurrentMerc, 2, 0, TRUE ) )
3444 						{
3445 							fOKToGo = TRUE;
3446 						}
3447 						else
3448 						{
3449 							fOKToGo = FALSE;
3450 						}
3451 					}
3452 				}
3453 			}
3454 
3455 			if ( fOKToGo )
3456 			{
3457 				//usOldItemIndex = gpSMCurrentMerc->inv[ uiHandPos ].usItem;
3458 				//usNewItemIndex = gpItemPointer->usItem;
3459 
3460 				if ( gpItemPopupSoldier->pKeyRing[ uiKeyRing ].ubKeyID == INVALID_KEY_NUMBER || gpItemPopupSoldier->pKeyRing[ uiKeyRing ].ubKeyID == gpItemPointer->ubKeyID)
3461 				{
3462 					// Try to place here
3463 					INT32 const iNumberOfKeysTaken = AddKeysToSlot(*gpItemPopupSoldier, (INT8)uiKeyRing, *gpItemPointer);
3464 					if (iNumberOfKeysTaken != 0)
3465 					{
3466 
3467 						if ( fDeductPoints )
3468 						{
3469 							// Deduct points
3470 							if ( gpItemPointerSoldier->bLife >= CONSCIOUSNESS )
3471 							{
3472 								DeductPoints( gpItemPointerSoldier,  2, 0 );
3473 							}
3474 							if ( gpItemPopupSoldier->bLife >= CONSCIOUSNESS )
3475 							{
3476 								DeductPoints( gpItemPopupSoldier,  2, 0 );
3477 							}
3478 						}
3479 
3480 						// Dirty
3481 						fInterfacePanelDirty = DIRTYLEVEL2;
3482 
3483 						gpItemPointer->ubNumberOfObjects -= ( UINT8 )iNumberOfKeysTaken;
3484 
3485 						// Check if it's the same now!
3486 						if ( gpItemPointer->ubNumberOfObjects == 0 )
3487 						{
3488 							if (fInMapMode)
3489 							{
3490 								MAPEndItemPointer();
3491 							}
3492 							else
3493 							{
3494 								EndItemPointer();
3495 							}
3496 						}
3497 
3498 						// Setup a timer....
3499 						//guiMouseOverItemTime = GetJA2Clock( );
3500 						//gfCheckForMouseOverItem = TRUE;
3501 						//gbCheckForMouseOverItemPos = (INT8)uiHandPos;
3502 
3503 					}
3504 				}
3505 				else
3506 				{
3507 					// Swap!
3508 					SwapKeysToSlot(*gpItemPopupSoldier, (INT8)uiKeyRing, *gpItemPointer);
3509 
3510 					if ( fDeductPoints )
3511 					{
3512 						// Deduct points
3513 						if ( gpItemPointerSoldier && gpItemPointerSoldier->bLife >= CONSCIOUSNESS )
3514 						{
3515 							DeductPoints( gpItemPointerSoldier,  2, 0 );
3516 						}
3517 						if ( gpSMCurrentMerc->bLife >= CONSCIOUSNESS )
3518 						{
3519 							DeductPoints( gpSMCurrentMerc,  2, 0 );
3520 						}
3521 					}
3522 
3523 					// Dirty
3524 					fInterfacePanelDirty = DIRTYLEVEL2;
3525 
3526 				}
3527 			}
3528 		}
3529 
3530 		UpdateItemHatches();
3531 	}
3532 	else if (iReason & MSYS_CALLBACK_REASON_RBUTTON_DWN)
3533 	{
3534 		fRightDown = TRUE;
3535 	}
3536 	else if (iReason & MSYS_CALLBACK_REASON_RBUTTON_UP && fRightDown )
3537 	{
3538 		fRightDown = FALSE;
3539 
3540 		// Return if empty
3541 		if( ( gpItemPopupSoldier->pKeyRing[ uiKeyRing ].ubKeyID == INVALID_KEY_NUMBER ) || ( gpItemPopupSoldier->pKeyRing[ uiKeyRing ].ubNumber == 0 ) )
3542 		{
3543 			DeleteKeyRingPopup( );
3544 			fTeamPanelDirty = TRUE;
3545 			return;
3546 		}
3547 		// Some global stuff here - for esc, etc
3548 		// Check for # of slots in item
3549 		if ( !InItemDescriptionBox( ) )
3550 		{
3551 			if (fInMapMode)
3552 			{
3553 				//InitKeyItemDescriptionBox(gpItemPopupSoldier, (UINT8)uiKeyRing, MAP_ITEMDESC_START_X, MAP_ITEMDESC_START_Y);
3554 			}
3555 			else
3556 			{
3557 				InitKeyItemDescriptionBox(gpItemPopupSoldier, (UINT8)uiKeyRing, SM_ITEMDESC_START_X, SM_ITEMDESC_START_Y);
3558 			}
3559 		}
3560 	}
3561 	else if (iReason & MSYS_CALLBACK_REASON_LOST_MOUSE )
3562 	{
3563 		fRightDown = FALSE;
3564 	}
3565 
3566 }
3567 
3568 
ShopKeeperInterface_SetSMpanelButtonsState(bool const enabled)3569 void ShopKeeperInterface_SetSMpanelButtonsState(bool const enabled)
3570 {
3571 	//Go through the buttons that will be under the ShopKeepers ATM panel and disable them
3572 	EnableButton( iSMPanelButtons[ STANCEUP_BUTTON ], enabled );
3573 	EnableButton( iSMPanelButtons[ UPDOWN_BUTTON ], enabled );
3574 	EnableButton( iSMPanelButtons[ CLIMB_BUTTON ], enabled );
3575 	EnableButton( iSMPanelButtons[ STANCEDOWN_BUTTON ], enabled );
3576 	EnableButton( iSMPanelButtons[ HANDCURSOR_BUTTON ], enabled );
3577 	EnableButton( iSMPanelButtons[ BURSTMODE_BUTTON ], enabled );
3578 	EnableButton( iSMPanelButtons[ LOOK_BUTTON ], enabled );
3579 	EnableButton( iSMPanelButtons[ TALK_BUTTON ], enabled );
3580 	EnableButton( iSMPanelButtons[ MUTE_BUTTON ], enabled );
3581 
3582 	EnableButton( giSMStealthButton, enabled );
3583 
3584 	//Make sure the options button is disabled
3585 	EnableButton( iSMPanelButtons[ OPTIONS_BUTTON ], enabled );
3586 
3587 	//Make sure the mapscreen button is disabled
3588 	EnableButton( iSMPanelButtons[ SM_MAP_SCREEN_BUTTON ], enabled );
3589 
3590 	EnableButton( iSMPanelButtons[ STANCEUP_BUTTON ], enabled );
3591 	EnableButton( iSMPanelButtons[ UPDOWN_BUTTON ], enabled );
3592 	EnableButton( iSMPanelButtons[ CLIMB_BUTTON ], enabled );
3593 	EnableButton( iSMPanelButtons[ STANCEDOWN_BUTTON ], enabled );
3594 	EnableButton( iSMPanelButtons[ HANDCURSOR_BUTTON ], enabled );
3595 	EnableButton( iSMPanelButtons[ BURSTMODE_BUTTON ], enabled );
3596 	EnableButton( iSMPanelButtons[ LOOK_BUTTON ], enabled );
3597 	EnableButton( iSMPanelButtons[ TALK_BUTTON ], enabled );
3598 	EnableButton( iSMPanelButtons[ MUTE_BUTTON ], enabled );
3599 
3600 	EnableButton( giSMStealthButton, enabled );
3601 }
3602 
3603 
IsMouseInRegion(MOUSE_REGION const & r)3604 static bool IsMouseInRegion(MOUSE_REGION const& r)
3605 {
3606 	return r.RegionTopLeftX <= gusMouseXPos && gusMouseXPos <= r.RegionBottomRightX &&
3607 		r.RegionTopLeftY <= gusMouseYPos && gusMouseYPos <= r.RegionBottomRightY;
3608 }
3609 
3610 
3611 static void ConfirmationToDepositMoneyToPlayersAccount(MessageBoxReturnValue);
3612 
3613 
SMInvMoneyButtonCallback(MOUSE_REGION * pRegion,INT32 iReason)3614 static void SMInvMoneyButtonCallback(MOUSE_REGION* pRegion, INT32 iReason)
3615 {
3616 	if (iReason == MSYS_CALLBACK_REASON_LBUTTON_DWN )
3617 	{
3618 		//If the current merc is to far away, dont allow anything to be done
3619 		if( gfSMDisableForItems )
3620 			return;
3621 
3622 		//if the player has an item in his hand,
3623 		if( gpItemPointer != NULL )
3624 		{
3625 			//and the item is money
3626 			if( GCM->getItem(gpItemPointer->usItem)->getItemClass() == IC_MONEY )
3627 			{
3628 				ST::string zText;
3629 				ST::string zMoney;
3630 
3631 				// Make sure we go back to movement mode...
3632 				guiPendingOverrideEvent = A_CHANGE_TO_MOVE;
3633 				HandleTacticalUI( );
3634 
3635 				zMoney = SPrintMoney(gpItemPointer->uiMoneyAmount);
3636 
3637 				//ask the user if they are sure they want to deposit the money
3638 				zText = st_format_printf(gzMoneyWithdrawMessageText[ CONFIRMATION_TO_DEPOSIT_MONEY_TO_ACCOUNT ], zMoney);
3639 
3640 				if( guiCurrentScreen == SHOPKEEPER_SCREEN )
3641 				{
3642 					//if we are in the shop keeper interface, free the cursor
3643 					FreeMouseCursor();
3644 					DoMessageBox(MSG_BOX_BASIC_STYLE, zText, SHOPKEEPER_SCREEN, MSG_BOX_FLAG_YESNO, ConfirmationToDepositMoneyToPlayersAccount, NULL);
3645 				}
3646 				else
3647 					DoMessageBox(MSG_BOX_BASIC_STYLE, zText, GAME_SCREEN, MSG_BOX_FLAG_YESNO, ConfirmationToDepositMoneyToPlayersAccount, NULL);
3648 			}
3649 		}
3650 
3651 		//else bring up the money item description box to remove money from the players account
3652 		else
3653 		{
3654 			//set the flag indicating we are removing money from the players account
3655 			gfAddingMoneyToMercFromPlayersAccount = TRUE;
3656 
3657 			//create the temp object from the players account balance
3658 			//if( LaptopSaveInfo.iCurrentBalance > MAX_MONEY_PER_SLOT )
3659 			//	CreateMoney( MAX_MONEY_PER_SLOT, &gItemPointer );
3660 			//else
3661 				CreateMoney( LaptopSaveInfo.iCurrentBalance, &gItemPointer );
3662 
3663 			InternalInitItemDescriptionBox(&gItemPointer, SM_ITEMDESC_START_X, SM_ITEMDESC_START_Y,
3664 							0, gpSMCurrentMerc);
3665 		}
3666 	}
3667 }
3668 
3669 
ConfirmationToDepositMoneyToPlayersAccount(MessageBoxReturnValue const ubExitValue)3670 static void ConfirmationToDepositMoneyToPlayersAccount(MessageBoxReturnValue const ubExitValue)
3671 {
3672 	if ( ubExitValue == MSG_BOX_RETURN_YES )
3673 	{
3674 		//add the money to the players account
3675 		AddTransactionToPlayersBook(MERC_DEPOSITED_MONEY_TO_PLAYER_ACCOUNT, gpSMCurrentMerc->ubProfile,
3676 						GetWorldTotalMin(), gpItemPointer->uiMoneyAmount);
3677 
3678 		EndItemPointer( );
3679 		// remove contents of the moving item because object still is money and usable
3680 		// you could add endlessly money to your bank account if not reset properly
3681 		gMoveingItem = INVENTORY_IN_SLOT{};
3682 		SetSkiCursor( CURSOR_NORMAL );
3683 		// dirty shopkeeper
3684 		gubSkiDirtyLevel = SKI_DIRTY_LEVEL2;
3685 
3686 
3687 	}
3688 }
3689 
3690 
ReEvaluateDisabledINVPanelButtons(void)3691 void ReEvaluateDisabledINVPanelButtons(void)
3692 {
3693 	gfReEvaluateDisabledINVPanelButtons = TRUE;
3694 }
3695 
3696 
CheckForReEvaluateDisabledINVPanelButtons(void)3697 static void CheckForReEvaluateDisabledINVPanelButtons(void)
3698 {
3699 	// OK, if we currently have an item pointer up....
3700 	if ( gfReEvaluateDisabledINVPanelButtons )
3701 	{
3702 		if ( gpItemPointer || gfInItemPickupMenu )
3703 		{
3704 			EnableSMPanelButtons( FALSE, TRUE );
3705 		}
3706 		else
3707 		{
3708 			EnableSMPanelButtons( TRUE, TRUE );
3709 		}
3710 
3711 		gfReEvaluateDisabledINVPanelButtons = FALSE;
3712 	}
3713 }
3714 
3715 
AbandonBoxingCallback(MessageBoxReturnValue const ubExitValue)3716 static void AbandonBoxingCallback(MessageBoxReturnValue const ubExitValue)
3717 {
3718 	if ( ubExitValue == MSG_BOX_RETURN_YES )
3719 	{
3720 		// ok, proceed!
3721 		SetBoxingState( NOT_BOXING );
3722 		gfEnteringMapScreen = TRUE;
3723 	}
3724 	// otherwise do nothing
3725 }
3726 
3727 
GoToMapScreenFromTactical(void)3728 void GoToMapScreenFromTactical(void)
3729 {
3730 	if ( gTacticalStatus.bBoxingState != NOT_BOXING )
3731 	{
3732 		// pop up dialogue asking whether the player wants to abandon the fight
3733 		DoMessageBox(MSG_BOX_BASIC_STYLE, g_langRes->Message[STR_ABANDON_FIGHT], GAME_SCREEN,
3734 				MSG_BOX_FLAG_YESNO, AbandonBoxingCallback, NULL);
3735 		return;
3736 	}
3737 	// ok, proceed!
3738 	gfEnteringMapScreen = TRUE;
3739 }
3740 
3741 
HandleTacticalEffectsOfEquipmentChange(SOLDIERTYPE * pSoldier,UINT32 uiInvPos,UINT16 usOldItem,UINT16 usNewItem)3742 void HandleTacticalEffectsOfEquipmentChange(SOLDIERTYPE* pSoldier, UINT32 uiInvPos, UINT16 usOldItem, UINT16 usNewItem)
3743 {
3744 	// if in attached weapon mode and don't have weapon with GL attached in hand, reset weapon mode
3745 	if (pSoldier->bWeaponMode == WM_ATTACHED &&
3746 		FindAttachment(&(pSoldier->inv[HANDPOS]), UNDER_GLAUNCHER) == NO_SLOT)
3747 	{
3748 		pSoldier->bWeaponMode = WM_NORMAL;
3749 		pSoldier->bDoBurst = FALSE;
3750 	}
3751 
3752 	// if he is loaded tactically
3753 	if ( pSoldier->bInSector )
3754 	{
3755 		// If this is our main hand
3756 		if ( uiInvPos == HANDPOS || uiInvPos == SECONDHANDPOS )
3757 		{
3758 			// check if we need to change animation!
3759 			ReLoadSoldierAnimationDueToHandItemChange( pSoldier, usOldItem, usNewItem );
3760 		}
3761 
3762 		// if this is head gear
3763 		if ( uiInvPos == HEAD1POS || uiInvPos == HEAD2POS )
3764 		{
3765 			// Could be because of GOGGLES change...  Re-create light...
3766 			DeleteSoldierLight( pSoldier );
3767 			PositionSoldierLight( pSoldier );
3768 		}
3769 	}
3770 	else
3771 	{
3772 		// as a minimum
3773 		if ((GCM->getItem(pSoldier->inv[HANDPOS].usItem)->isWeapon()) &&
3774 			GCM->getWeapon(pSoldier->inv[HANDPOS].usItem)->ubShotsPerBurst == 0)
3775 		{
3776 			pSoldier->bDoBurst = FALSE;
3777 			pSoldier->bWeaponMode = WM_NORMAL;
3778 		}
3779 	}
3780 }
3781 
3782 
LoadInterfacePanelGraphics()3783 void LoadInterfacePanelGraphics()
3784 {
3785 	guiCLOSE = AddVideoObjectFromFile(INTERFACEDIR "/p_close.sti");
3786 }
3787 
3788 
DeleteInterfacePanelGraphics()3789 void DeleteInterfacePanelGraphics()
3790 {
3791 	DeleteVideoObject(guiCLOSE);
3792 }
3793