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