1 //Copyright Paul Reiche, Fred Ford. 1992-2002
2
3 /*
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
17 */
18
19 #include "colors.h"
20 #include "globdata.h"
21 #include "options.h"
22 #include "status.h"
23 #include "setup.h"
24 #include "libs/gfxlib.h"
25
26
27 void
DrawCrewFuelString(COORD y,SIZE state)28 DrawCrewFuelString (COORD y, SIZE state)
29 {
30 STAMP Stamp;
31
32 Stamp.origin.y = y + GAUGE_YOFFS + STARCON_TEXT_HEIGHT;
33 if (state == 0)
34 {
35 Stamp.origin.x = CREW_XOFFS + (STAT_WIDTH >> 1) + 6;
36 if (optWhichMenu == OPT_PC)
37 Stamp.frame = SetAbsFrameIndex (StatusFrame, 4);
38 else
39 Stamp.frame = SetAbsFrameIndex (StatusFrame, 0);
40 DrawStamp (&Stamp);
41 }
42
43 Stamp.origin.x = ENERGY_XOFFS + (STAT_WIDTH >> 1) - 5;
44 if (optWhichMenu == OPT_PC)
45 Stamp.frame = SetAbsFrameIndex (StatusFrame, 5);
46 else
47 Stamp.frame = SetAbsFrameIndex (StatusFrame, 1);
48 if (state >= 0)
49 DrawStamp (&Stamp);
50 else
51 {
52 #define LOW_FUEL_COLOR BUILD_COLOR (MAKE_RGB15 (0x1F, 0x1F, 0x0A), 0x0E)
53 SetContextForeGroundColor (LOW_FUEL_COLOR);
54 DrawFilledStamp (&Stamp);
55 }
56 }
57
58 static void
DrawShipNameString(UNICODE * pStr,COUNT CharCount,COORD y)59 DrawShipNameString (UNICODE *pStr, COUNT CharCount, COORD y)
60 {
61 TEXT Text;
62 FONT OldFont;
63
64 OldFont = SetContextFont (StarConFont);
65
66 Text.pStr = pStr;
67 Text.CharCount = CharCount;
68 Text.align = ALIGN_CENTER;
69
70 Text.baseline.y = STARCON_TEXT_HEIGHT + 3 + y;
71 Text.baseline.x = STATUS_WIDTH >> 1;
72
73 SetContextForeGroundColor (
74 BUILD_COLOR (MAKE_RGB15 (0x10, 0x10, 0x10), 0x19));
75 font_DrawText (&Text);
76 --Text.baseline.y;
77 SetContextForeGroundColor (BLACK_COLOR);
78 font_DrawText (&Text);
79
80 SetContextFont (OldFont);
81 }
82
83 void
ClearShipStatus(COORD y)84 ClearShipStatus (COORD y)
85 {
86 RECT r;
87
88 SetContextForeGroundColor (
89 BUILD_COLOR (MAKE_RGB15 (0x0A, 0x0A, 0x0A), 0x08));
90 r.corner.x = 2;
91 r.corner.y = 3 + y;
92 r.extent.width = STATUS_WIDTH - 4;
93 r.extent.height = SHIP_INFO_HEIGHT - 3;
94 DrawFilledRectangle (&r);
95 }
96
97 void
OutlineShipStatus(COORD y)98 OutlineShipStatus (COORD y)
99 {
100 RECT r;
101
102 SetContextForeGroundColor (
103 BUILD_COLOR (MAKE_RGB15 (0x08, 0x08, 0x08), 0x1F));
104 r.corner.x = 0;
105 r.corner.y = 1 + y;
106 r.extent.width = STATUS_WIDTH;
107 r.extent.height = 1;
108 DrawFilledRectangle (&r);
109 ++r.corner.y;
110 --r.extent.width;
111 DrawFilledRectangle (&r);
112 r.extent.width = 1;
113 r.extent.height = SHIP_INFO_HEIGHT - 2;
114 DrawFilledRectangle (&r);
115 ++r.corner.x;
116 DrawFilledRectangle (&r);
117
118 SetContextForeGroundColor (
119 BUILD_COLOR (MAKE_RGB15 (0x10, 0x10, 0x10), 0x19));
120 r.corner.x = STATUS_WIDTH - 1;
121 DrawFilledRectangle (&r);
122 r.corner.x = STATUS_WIDTH - 2;
123 ++r.corner.y;
124 --r.extent.height;
125 DrawFilledRectangle (&r);
126
127 SetContextForeGroundColor (BLACK_COLOR);
128 r.corner.x = 0;
129 r.corner.y = y;
130 r.extent.width = STATUS_WIDTH;
131 r.extent.height = 1;
132 DrawFilledRectangle (&r);
133 }
134
135 void
InitShipStatus(SHIP_INFO * SIPtr,STARSHIP * StarShipPtr,RECT * pClipRect)136 InitShipStatus (SHIP_INFO *SIPtr, STARSHIP *StarShipPtr, RECT *pClipRect)
137 {
138 RECT r;
139 COORD y = 0; // default, for Melee menu
140 STAMP Stamp;
141 CONTEXT OldContext;
142 RECT oldClipRect;
143 POINT oldOrigin = {0, 0};
144
145 if (StarShipPtr) // set during battle
146 {
147 assert (StarShipPtr->playerNr >= 0);
148 y = status_y_offsets[StarShipPtr->playerNr];
149 }
150
151 OldContext = SetContext (StatusContext);
152 if (pClipRect)
153 {
154 GetContextClipRect (&oldClipRect);
155 r = oldClipRect;
156 r.corner.x += pClipRect->corner.x;
157 r.corner.y += (pClipRect->corner.y & ~1);
158 r.extent = pClipRect->extent;
159 r.extent.height += pClipRect->corner.y & 1;
160 SetContextClipRect (&r);
161 // Offset the origin so that we draw into the cliprect
162 oldOrigin = SetContextOrigin (MAKE_POINT (-pClipRect->corner.x,
163 -(pClipRect->corner.y & ~1)));
164 }
165
166 BatchGraphics ();
167
168 OutlineShipStatus (y);
169 ClearShipStatus (y);
170
171 Stamp.origin.x = (STATUS_WIDTH >> 1);
172 Stamp.origin.y = 31 + y;
173 Stamp.frame = IncFrameIndex (SIPtr->icons);
174 DrawStamp (&Stamp);
175
176 {
177 SIZE crew_height, energy_height;
178
179 #define MIN(a, b) (((a) <= (b)) ? (a) : (b))
180 crew_height = ((MIN(SIPtr->max_crew, MAX_CREW_SIZE) + 1) & ~1) + 1;
181 #undef MIN
182 energy_height = (((SIPtr->max_energy + 1) >> 1) << 1) + 1;
183
184 SetContextForeGroundColor (
185 BUILD_COLOR (MAKE_RGB15 (0x08, 0x08, 0x08), 0x1F));
186 r.corner.x = CREW_XOFFS - 1;
187 r.corner.y = GAUGE_YOFFS + 1 + y;
188 r.extent.width = STAT_WIDTH + 2;
189 r.extent.height = 1;
190 DrawFilledRectangle (&r);
191 r.corner.x = ENERGY_XOFFS - 1;
192 DrawFilledRectangle (&r);
193 r.corner.x = ENERGY_XOFFS + STAT_WIDTH;
194 r.corner.y -= energy_height;
195 r.extent.width = 1;
196 r.extent.height = energy_height;
197 DrawFilledRectangle (&r);
198 r.corner.x = CREW_XOFFS + STAT_WIDTH;
199 r.corner.y = (GAUGE_YOFFS + 1 + y) - crew_height;
200 r.extent.width = 1;
201 r.extent.height = crew_height;
202 DrawFilledRectangle (&r);
203 SetContextForeGroundColor (
204 BUILD_COLOR (MAKE_RGB15 (0x10, 0x10, 0x10), 0x19));
205 r.corner.x = CREW_XOFFS - 1;
206 r.corner.y = GAUGE_YOFFS - crew_height + y;
207 r.extent.width = STAT_WIDTH + 2;
208 r.extent.height = 1;
209 DrawFilledRectangle (&r);
210 r.corner.x = ENERGY_XOFFS - 1;
211 r.corner.y = GAUGE_YOFFS - energy_height + y;
212 DrawFilledRectangle (&r);
213 r.extent.width = 1;
214 r.extent.height = energy_height + 1;
215 DrawFilledRectangle (&r);
216 r.corner.x = CREW_XOFFS - 1;
217 r.corner.y = GAUGE_YOFFS - crew_height + y;
218 r.extent.height = crew_height + 1;
219 DrawFilledRectangle (&r);
220
221 SetContextForeGroundColor (BLACK_COLOR);
222
223 r.extent.width = STAT_WIDTH;
224 r.corner.x = CREW_XOFFS;
225 r.extent.height = crew_height;
226 r.corner.y = y - r.extent.height + GAUGE_YOFFS + 1;
227 DrawFilledRectangle (&r);
228 r.corner.x = ENERGY_XOFFS;
229 r.extent.height = energy_height;
230 r.corner.y = y - r.extent.height + GAUGE_YOFFS + 1;
231 DrawFilledRectangle (&r);
232 }
233
234 if (!StarShipPtr || StarShipPtr->captains_name_index)
235 { // Any regular ship. SIS and Sa-Matra are separate.
236 // This includes Melee menu.
237 STRING locString;
238
239 DrawCrewFuelString (y, 0);
240
241 locString = SetAbsStringTableIndex (SIPtr->race_strings, 1);
242 DrawShipNameString (
243 (UNICODE *)GetStringAddress (locString),
244 GetStringLength (locString), y);
245
246 {
247 UNICODE buf[30];
248 TEXT Text;
249 FONT OldFont;
250
251 OldFont = SetContextFont (TinyFont);
252
253 if (!StarShipPtr)
254 { // In Melee menu
255 sprintf (buf, "%d", SIPtr->ship_cost);
256 Text.pStr = buf;
257 Text.CharCount = (COUNT)~0;
258 }
259 else
260 {
261 locString = SetAbsStringTableIndex (SIPtr->race_strings,
262 StarShipPtr->captains_name_index);
263 Text.pStr = (UNICODE *)GetStringAddress (locString);
264 Text.CharCount = GetStringLength (locString);
265 }
266 Text.align = ALIGN_CENTER;
267
268 Text.baseline.x = STATUS_WIDTH >> 1;
269 Text.baseline.y = y + GAUGE_YOFFS + 3;
270
271 SetContextForeGroundColor (BLACK_COLOR);
272 font_DrawText (&Text);
273
274 SetContextFont (OldFont);
275 }
276 }
277 else if (StarShipPtr->playerNr == RPG_PLAYER_NUM)
278 { // This is SIS
279 DrawCrewFuelString (y, 0);
280 DrawShipNameString (GLOBAL_SIS (ShipName), (COUNT)~0, y);
281 }
282
283 {
284 SIZE crew_delta, energy_delta;
285
286 crew_delta = SIPtr->crew_level;
287 energy_delta = SIPtr->energy_level;
288 // DeltaStatistics() below will add specified values to these
289 SIPtr->crew_level = 0;
290 SIPtr->energy_level = 0;
291 DeltaStatistics (SIPtr, y, crew_delta, energy_delta);
292 }
293
294 UnbatchGraphics ();
295
296 if (pClipRect)
297 {
298 SetContextOrigin (oldOrigin);
299 SetContextClipRect (&oldClipRect);
300 }
301
302 SetContext (OldContext);
303 }
304
305 // Pre: -crew_delta <= ShipInfoPtr->crew_level
306 // crew_delta <= ShipInfoPtr->max_crew - ShipInfoPtr->crew_level
307 void
DeltaStatistics(SHIP_INFO * ShipInfoPtr,COORD y_offs,SIZE crew_delta,SIZE energy_delta)308 DeltaStatistics (SHIP_INFO *ShipInfoPtr, COORD y_offs,
309 SIZE crew_delta, SIZE energy_delta)
310 {
311 COORD x, y;
312 RECT r;
313
314 if (crew_delta == 0 && energy_delta == 0)
315 return;
316
317 x = 0;
318 y = GAUGE_YOFFS + y_offs;
319
320 r.extent.width = UNIT_WIDTH;
321 r.extent.height = UNIT_HEIGHT;
322
323 if (crew_delta != 0)
324 {
325 COUNT oldNumBlocks, newNumBlocks, blockI;
326 COUNT newCrewLevel;
327
328 #define MIN(a, b) (((a) <= (b)) ? (a) : (b))
329 oldNumBlocks = MIN(ShipInfoPtr->crew_level, MAX_CREW_SIZE);
330 newCrewLevel = ShipInfoPtr->crew_level + crew_delta;
331 newNumBlocks = MIN(newCrewLevel, MAX_CREW_SIZE);
332 #undef MIN
333
334 if (crew_delta > 0)
335 {
336 r.corner.y = (y + 1) -
337 (((oldNumBlocks + 1) >> 1) * (UNIT_HEIGHT + 1));
338 #define CREW_UNIT_COLOR BUILD_COLOR (MAKE_RGB15 (0x00, 0x14, 0x00), 0x02)
339 #define ROBOT_UNIT_COLOR BUILD_COLOR (MAKE_RGB15 (0x0A, 0x0A, 0x0A), 0x08)
340 SetContextForeGroundColor (
341 (ShipInfoPtr->ship_flags & CREW_IMMUNE) ?
342 ROBOT_UNIT_COLOR : CREW_UNIT_COLOR);
343 for (blockI = oldNumBlocks; blockI < newNumBlocks; blockI++)
344 {
345 r.corner.x = x + (CREW_XOFFS + 1);
346 if (!(blockI & 1))
347 {
348 r.corner.x += UNIT_WIDTH + 1;
349 r.corner.y -= UNIT_HEIGHT + 1;
350 }
351 DrawFilledRectangle (&r);
352 }
353 }
354 else /* crew_delta < 0 */
355 {
356 SetContextForeGroundColor (BLACK_COLOR);
357 r.corner.y = (y + 1) -
358 (((oldNumBlocks + 2) >> 1) * (UNIT_HEIGHT + 1));
359 for (blockI = oldNumBlocks; blockI > newNumBlocks; blockI--)
360 {
361 r.corner.x = x + (CREW_XOFFS + 1 + UNIT_WIDTH + 1);
362 if (!(blockI & 1))
363 {
364 r.corner.x -= UNIT_WIDTH + 1;
365 r.corner.y += UNIT_HEIGHT + 1;
366 }
367 DrawFilledRectangle (&r);
368 }
369 }
370
371 if (ShipInfoPtr->ship_flags & PLAYER_CAPTAIN) {
372 if (((ShipInfoPtr->crew_level > MAX_CREW_SIZE) !=
373 (newCrewLevel > MAX_CREW_SIZE) ||
374 ShipInfoPtr->crew_level == 0) && newCrewLevel != 0)
375 {
376 // The block indicating the captain needs to change color.
377 #define PLAYER_UNIT_COLOR BUILD_COLOR (MAKE_RGB15 (0x0A, 0x0A, 0x1F), 0x09)
378 SetContextForeGroundColor (
379 (newCrewLevel > MAX_CREW_SIZE) ?
380 CREW_UNIT_COLOR : PLAYER_UNIT_COLOR);
381 r.corner.x = x + (CREW_XOFFS + 1) + (UNIT_WIDTH + 1);
382 r.corner.y = y - UNIT_HEIGHT;
383 DrawFilledRectangle (&r);
384 }
385 }
386
387 ShipInfoPtr->crew_level = newCrewLevel;
388 if (ShipInfoPtr->max_crew > MAX_CREW_SIZE ||
389 ShipInfoPtr->ship_flags & PLAYER_CAPTAIN)
390 {
391 // All crew doesn't fit in the graphics; print a number.
392 // Always print a number for the SIS in the full game.
393 DrawBattleCrewAmount (ShipInfoPtr, y_offs);
394 }
395 }
396
397 if (energy_delta != 0)
398 {
399 if (energy_delta > 0)
400 {
401 #define FUEL_UNIT_COLOR BUILD_COLOR (MAKE_RGB15 (0x14, 0x00, 0x00), 0x04)
402 SetContextForeGroundColor (FUEL_UNIT_COLOR);
403 r.corner.y = (y + 1) -
404 (((ShipInfoPtr->energy_level + 1) >> 1) * (UNIT_HEIGHT + 1));
405 do
406 {
407 r.corner.x = x + (ENERGY_XOFFS + 1);
408 if (!(ShipInfoPtr->energy_level & 1))
409 {
410 r.corner.x += UNIT_WIDTH + 1;
411 r.corner.y -= UNIT_HEIGHT + 1;
412 }
413 DrawFilledRectangle (&r);
414 ++ShipInfoPtr->energy_level;
415 } while (--energy_delta);
416 }
417 else
418 {
419 SetContextForeGroundColor (BLACK_COLOR);
420 r.corner.y = (y + 1) -
421 (((ShipInfoPtr->energy_level + 2) >> 1) * (UNIT_HEIGHT + 1));
422 do
423 {
424 r.corner.x = x + (ENERGY_XOFFS + 1 + UNIT_WIDTH + 1);
425 if (!(ShipInfoPtr->energy_level & 1))
426 {
427 r.corner.x -= UNIT_WIDTH + 1;
428 r.corner.y += UNIT_HEIGHT + 1;
429 }
430 DrawFilledRectangle (&r);
431 --ShipInfoPtr->energy_level;
432 } while (++energy_delta);
433 }
434 }
435 }
436
437
438