1 #include "Interface_Utils.h"
2 #include "ContentManager.h"
3 #include "Directories.h"
4 #include "Faces.h"
5 #include "GameInstance.h"
6 #include "HImage.h"
7 #include "JAScreens.h"
8 #include "Line.h"
9 #include "MagazineModel.h"
10 #include "Overhead.h"
11 #include "Render_Dirty.h"
12 #include "Soldier_Macros.h"
13 #include "SysUtil.h"
14 #include "UILayout.h"
15 #include "Vehicles.h"
16 #include "Video.h"
17 #include "VObject.h"
18 #include "VSurface.h"
19 #include <stdexcept>
20 #include <string_theory/format>
21 #include <string_theory/string>
22
23
24 #define LIFE_BAR_SHADOW FROMRGB(108, 12, 12)
25 #define LIFE_BAR FROMRGB(200, 0, 0)
26 #define BANDAGE_BAR_SHADOW FROMRGB(156, 60, 60)
27 #define BANDAGE_BAR FROMRGB(222, 132, 132)
28 #define BLEEDING_BAR_SHADOW FROMRGB(128, 128, 60)
29 #define BLEEDING_BAR FROMRGB(240, 240, 20)
30 #define CURR_BREATH_BAR_SHADOW FROMRGB(8, 12, 118) // the MAX max breatth, always at 100%
31 #define CURR_BREATH_BAR FROMRGB(8, 12, 160)
32 #define CURR_MAX_BREATH FROMRGB(0, 0, 0) // the current max breath, black
33 #define CURR_MAX_BREATH_SHADOW FROMRGB(0, 0, 0)
34 #define MORALE_BAR_SHADOW FROMRGB(8, 112, 12)
35 #define MORALE_BAR FROMRGB(8, 180, 12)
36 #define BREATH_BAR_SHADOW FROMRGB(60, 108, 108) // the lt blue current breath
37 #define BREATH_BAR FROMRGB(113, 178, 218)
38 #define BREATH_BAR_SHAD_BACK FROMRGB(1, 1, 1)
39 #define FACE_WIDTH 48
40 #define FACE_HEIGHT 43
41
42
43 // car portraits
44 enum
45 {
46 ELDORADO_PORTRAIT = 0,
47 HUMMER_PORTRAIT,
48 ICE_CREAM_TRUCK_PORTRAIT,
49 JEEP_PORTRAIT,
50 NUMBER_CAR_PORTRAITS
51 };
52
53 // the ids for the car portraits
54 static SGPVObject* giCarPortraits[NUMBER_CAR_PORTRAITS];
55
56 static SGPVObject* guiBrownBackgroundForTeamPanel; // backgrounds for breath max background
57
58
59 // Load in the portraits for the car faces that will be use in mapscreen
LoadCarPortraitValues(void)60 void LoadCarPortraitValues(void)
61 {
62 // the car portrait file names
63 static char const* const pbCarPortraitFileNames[] =
64 {
65 INTERFACEDIR "/eldorado.sti",
66 INTERFACEDIR "/hummer.sti",
67 INTERFACEDIR "/ice cream truck.sti",
68 INTERFACEDIR "/jeep.sti"
69 };
70
71 if (giCarPortraits[0]) return;
72 for (INT32 i = 0; i != NUMBER_CAR_PORTRAITS; ++i)
73 {
74 giCarPortraits[i] = AddVideoObjectFromFile(pbCarPortraitFileNames[i]);
75 }
76 }
77
78
79 // get rid of the images we loaded for the mapscreen car portraits
UnLoadCarPortraits(void)80 void UnLoadCarPortraits(void)
81 {
82 // car protraits loaded?
83 if (!giCarPortraits[0]) return;
84 for (INT32 i = 0; i != NUMBER_CAR_PORTRAITS; ++i)
85 {
86 DeleteVideoObject(giCarPortraits[i]);
87 giCarPortraits[i] = 0;
88 }
89 }
90
91
DrawBar(UINT32 const XPos,UINT32 const YPos,UINT32 const Height,UINT16 const Color,UINT16 const ShadowColor,UINT16 * const DestBuf)92 static void DrawBar(UINT32 const XPos, UINT32 const YPos, UINT32 const Height, UINT16 const Color, UINT16 const ShadowColor, UINT16* const DestBuf)
93 {
94 LineDraw(TRUE, XPos + 0, YPos, XPos + 0, YPos - Height, ShadowColor, DestBuf);
95 LineDraw(TRUE, XPos + 1, YPos, XPos + 1, YPos - Height, Color, DestBuf);
96 LineDraw(TRUE, XPos + 2, YPos, XPos + 2, YPos - Height, ShadowColor, DestBuf);
97 }
98
99
DrawLifeUIBar(SOLDIERTYPE const & s,UINT32 const XPos,UINT32 YPos,UINT32 const MaxHeight,UINT16 * const pDestBuf)100 static void DrawLifeUIBar(SOLDIERTYPE const& s, UINT32 const XPos, UINT32 YPos, UINT32 const MaxHeight, UINT16* const pDestBuf)
101 {
102 UINT32 Height;
103
104 // FIRST DO MAX LIFE
105 Height = MaxHeight * s.bLife / 100;
106 DrawBar(XPos, YPos, Height, Get16BPPColor(LIFE_BAR), Get16BPPColor(LIFE_BAR_SHADOW), pDestBuf);
107
108 // NOW DO BANDAGE
109 // Calculate bandage
110 UINT32 Bandage = s.bLifeMax - s.bLife - s.bBleeding;
111 if (Bandage != 0)
112 {
113 YPos -= Height;
114 Height = MaxHeight * Bandage / 100;
115 DrawBar(XPos, YPos, Height, Get16BPPColor(BANDAGE_BAR), Get16BPPColor(BANDAGE_BAR_SHADOW), pDestBuf);
116 }
117
118 // NOW DO BLEEDING
119 if (s.bBleeding != 0)
120 {
121 YPos -= Height;
122 Height = MaxHeight * s.bBleeding / 100;
123 DrawBar(XPos, YPos, Height, Get16BPPColor(BLEEDING_BAR), Get16BPPColor(BLEEDING_BAR_SHADOW), pDestBuf);
124 }
125 }
126
127
DrawBreathUIBar(SOLDIERTYPE const & s,UINT32 const XPos,UINT32 const sYPos,UINT32 const MaxHeight,UINT16 * const pDestBuf)128 static void DrawBreathUIBar(SOLDIERTYPE const& s, UINT32 const XPos, UINT32 const sYPos, UINT32 const MaxHeight, UINT16* const pDestBuf)
129 {
130 UINT32 Height;
131
132 if (s.bBreathMax <= 97)
133 {
134 Height = MaxHeight * (s.bBreathMax + 3) / 100;
135 // the old background colors for breath max diff
136 DrawBar(XPos, sYPos, Height, Get16BPPColor(BREATH_BAR_SHAD_BACK), Get16BPPColor(BREATH_BAR_SHAD_BACK), pDestBuf);
137 }
138
139 Height = MaxHeight * s.bBreathMax / 100;
140 DrawBar(XPos, sYPos, Height, Get16BPPColor(CURR_MAX_BREATH), Get16BPPColor(CURR_MAX_BREATH_SHADOW), pDestBuf);
141
142 // NOW DO BREATH
143 Height = MaxHeight * s.bBreath / 100;
144 DrawBar(XPos, sYPos, Height, Get16BPPColor(CURR_BREATH_BAR), Get16BPPColor(CURR_BREATH_BAR_SHADOW), pDestBuf);
145 }
146
147
DrawMoraleUIBar(SOLDIERTYPE const & s,UINT32 const XPos,UINT32 const YPos,UINT32 const MaxHeight,UINT16 * const pDestBuf)148 static void DrawMoraleUIBar(SOLDIERTYPE const& s, UINT32 const XPos, UINT32 const YPos, UINT32 const MaxHeight, UINT16* const pDestBuf)
149 {
150 UINT32 const Height = MaxHeight * s.bMorale / 100;
151 DrawBar(XPos, YPos, Height, Get16BPPColor(MORALE_BAR), Get16BPPColor(MORALE_BAR_SHADOW), pDestBuf);
152 }
153
154
DrawSoldierUIBars(SOLDIERTYPE const & s,INT16 const sXPos,INT16 const sYPos,BOOLEAN const fErase,SGPVSurface * const uiBuffer)155 void DrawSoldierUIBars(SOLDIERTYPE const& s, INT16 const sXPos, INT16 const sYPos, BOOLEAN const fErase, SGPVSurface* const uiBuffer)
156 {
157 const UINT32 BarWidth = 3;
158 const UINT32 BarHeight = 42;
159 const UINT32 BreathOff = 6;
160 const UINT32 MoraleOff = 12;
161
162 // Erase what was there
163 if (fErase)
164 {
165 RestoreExternBackgroundRect(sXPos, sYPos - BarHeight, MoraleOff + BarWidth, BarHeight + 1);
166 }
167
168 if (s.bLife == 0) return;
169
170 if (!(s.uiStatusFlags & SOLDIER_ROBOT))
171 {
172 // DO MAX BREATH
173 // brown guy
174 UINT16 Region;
175 if (guiCurrentScreen != MAP_SCREEN &&
176 GetSelectedMan() == &s &&
177 gTacticalStatus.ubCurrentTeam == OUR_TEAM &&
178 OK_INTERRUPT_MERC(&s))
179 {
180 Region = 1; // gold, the second entry in the .sti
181 }
182 else
183 {
184 Region = 0; // brown, first entry
185 }
186 BltVideoObject(uiBuffer, guiBrownBackgroundForTeamPanel, Region, sXPos + BreathOff, sYPos - BarHeight);
187 }
188
189 SGPVSurface::Lock l(uiBuffer);
190 SetClippingRegionAndImageWidth(l.Pitch(), 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);
191 UINT16* const pDestBuf = l.Buffer<UINT16>();
192
193 DrawLifeUIBar(s, sXPos, sYPos, BarHeight, pDestBuf);
194 if (!(s.uiStatusFlags & SOLDIER_ROBOT))
195 {
196 DrawBreathUIBar(s, sXPos + BreathOff, sYPos, BarHeight, pDestBuf);
197 if (!(s.uiStatusFlags & SOLDIER_VEHICLE))
198 {
199 DrawMoraleUIBar(s, sXPos + MoraleOff, sYPos, BarHeight, pDestBuf);
200 }
201 }
202 }
203
204
DrawItemUIBarEx(OBJECTTYPE const & o,const UINT8 ubStatus,const INT16 x,const INT16 y,INT16 max_h,const INT16 sColor1,const INT16 sColor2,SGPVSurface * const uiBuffer)205 void DrawItemUIBarEx(OBJECTTYPE const& o, const UINT8 ubStatus, const INT16 x, const INT16 y, INT16 max_h, const INT16 sColor1, const INT16 sColor2, SGPVSurface* const uiBuffer)
206 {
207 INT16 value;
208 // Adjust for ammo, other things
209 const ItemModel * item = GCM->getItem(o.usItem);
210 if (ubStatus >= DRAW_ITEM_STATUS_ATTACHMENT1)
211 {
212 value = o.bAttachStatus[ubStatus - DRAW_ITEM_STATUS_ATTACHMENT1];
213 }
214 else if (item->isKey())
215 {
216 value = 100;
217 }
218 else
219 {
220 if (ubStatus >= MAX_OBJECTS_PER_SLOT)
221 throw std::runtime_error(ST::format("invalid ubStatus value: {}", ubStatus).to_std_string());
222
223 if (item->isAmmo())
224 {
225 value = 100 * o.ubShotsLeft[ubStatus] / (item->asAmmo()->capacity ? item->asAmmo()->capacity : 1);
226 if (value > 100) value = 100;
227 }
228 else
229 {
230 value = o.bStatus[ubStatus];
231 }
232 }
233
234 { SGPVSurface::Lock l(uiBuffer);
235 SetClippingRegionAndImageWidth(l.Pitch(), 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);
236 UINT16* const pDestBuf = l.Buffer<UINT16>();
237
238 --max_h; // LineDraw() includes the end point
239 const INT h = max_h * value / 100;
240 LineDraw(TRUE, x, y, x, y - h, sColor1, pDestBuf);
241 LineDraw(TRUE, x + 1, y, x + 1, y - h, sColor2, pDestBuf);
242 }
243
244 if (uiBuffer == guiSAVEBUFFER)
245 {
246 RestoreExternBackgroundRect(x, y - max_h, 2, max_h + 1);
247 }
248 else
249 {
250 InvalidateRegion(x, y - max_h, x + 2, y + 1);
251 }
252 }
253
254
RenderSoldierFace(SOLDIERTYPE const & s,INT16 const sFaceX,INT16 const sFaceY)255 void RenderSoldierFace(SOLDIERTYPE const& s, INT16 const sFaceX, INT16 const sFaceY)
256 {
257 if (s.uiStatusFlags & SOLDIER_VEHICLE)
258 {
259 // just draw the vehicle
260 const UINT8 vehicle_type = pVehicleList[s.bVehicleID].ubVehicleType;
261 BltVideoObject(guiSAVEBUFFER, giCarPortraits[vehicle_type], 0, sFaceX, sFaceY);
262 RestoreExternBackgroundRect(sFaceX, sFaceY, FACE_WIDTH, FACE_HEIGHT);
263 }
264 else if (s.face->uiFlags & FACE_INACTIVE_HANDLED_ELSEWHERE) // OK, check if this face actually went active
265 {
266 ExternRenderFace(guiSAVEBUFFER, *s.face, sFaceX, sFaceY);
267 }
268 else
269 {
270 SetAutoFaceActive(FRAME_BUFFER, guiSAVEBUFFER, *s.face, sFaceX, sFaceY);
271 RenderAutoFace(*s.face);
272 }
273 }
274
275
LoadInterfaceUtilsGraphics()276 void LoadInterfaceUtilsGraphics()
277 {
278 guiBrownBackgroundForTeamPanel = AddVideoObjectFromFile(INTERFACEDIR "/bars.sti");
279 }
280
281
DeleteInterfaceUtilsGraphics()282 void DeleteInterfaceUtilsGraphics()
283 {
284 DeleteVideoObject(guiBrownBackgroundForTeamPanel);
285 }
286