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 "../controls.h"
21 #include "../gamestr.h"
22 #include "../shipcont.h"
23 #include "../setup.h"
24 #include "../sounds.h"
25 #include "../util.h"
26 #include "../sis.h"
27 		// for ClearSISRect(), DrawStatusMessage()
28 #include "planets.h"
29 #include "libs/graphics/drawable.h"
30 		// for GetFrameBounds()
31 
32 
33 #define ELEMENT_ORG_Y      35
34 #define FREE_ORG_Y         (ELEMENT_ORG_Y + (NUM_ELEMENT_CATEGORIES \
35 							* ELEMENT_SPACING_Y))
36 #define BIO_ORG_Y          119
37 #define ELEMENT_SPACING_Y  9
38 
39 #define ELEMENT_COL_0      7
40 #define ELEMENT_COL_1      32
41 #define ELEMENT_COL_2      58
42 
43 #define ELEMENT_SEL_ORG_X  (ELEMENT_COL_0 + 7 + 5)
44 #define ELEMENT_SEL_WIDTH  (ELEMENT_COL_2 - ELEMENT_SEL_ORG_X + 1)
45 
46 #define TEXT_BASELINE      6
47 
48 
49 void
ShowRemainingCapacity(void)50 ShowRemainingCapacity (void)
51 {
52 	RECT r;
53 	TEXT t;
54 	CONTEXT OldContext;
55 	UNICODE buf[40];
56 
57 	OldContext = SetContext (StatusContext);
58 	SetContextFont (TinyFont);
59 
60 	r.corner.x = 40;
61 	r.corner.y = FREE_ORG_Y;
62 
63 	snprintf (buf, sizeof buf, "%u",
64 			GetStorageBayCapacity () - GLOBAL_SIS (TotalElementMass));
65 	t.baseline.x = ELEMENT_COL_2 + 1;
66 	t.baseline.y = r.corner.y + TEXT_BASELINE;
67 	t.align = ALIGN_RIGHT;
68 	t.pStr = buf;
69 	t.CharCount = (COUNT)~0;
70 
71 	r.extent.width = t.baseline.x - r.corner.x + 1;
72 	r.extent.height = ELEMENT_SPACING_Y - 2;
73 
74 	BatchGraphics ();
75 	// erase previous free amount
76 	SetContextForeGroundColor (CARGO_BACK_COLOR);
77 	DrawFilledRectangle (&r);
78 	// print the new free amount
79 	SetContextForeGroundColor (CARGO_WORTH_COLOR);
80 	font_DrawText (&t);
81 	UnbatchGraphics ();
82 
83 	SetContext (OldContext);
84 }
85 
86 static void
DrawElementAmount(COUNT element,bool selected)87 DrawElementAmount (COUNT element, bool selected)
88 {
89 	RECT r;
90 	TEXT t;
91 	UNICODE buf[40];
92 
93 	r.corner.x = ELEMENT_SEL_ORG_X;
94 	r.extent.width = ELEMENT_SEL_WIDTH;
95 	r.extent.height = ELEMENT_SPACING_Y - 2;
96 
97 	if (element == NUM_ELEMENT_CATEGORIES)
98 		r.corner.y = BIO_ORG_Y;
99 	else
100 		r.corner.y = ELEMENT_ORG_Y + (element * ELEMENT_SPACING_Y);
101 
102 	// draw line background
103 	SetContextForeGroundColor (selected ?
104 			CARGO_SELECTED_BACK_COLOR : CARGO_BACK_COLOR);
105 	DrawFilledRectangle (&r);
106 
107 	t.align = ALIGN_RIGHT;
108 	t.pStr = buf;
109 	t.baseline.y = r.corner.y + TEXT_BASELINE;
110 
111 	if (element == NUM_ELEMENT_CATEGORIES)
112 	{	// Bio
113 		snprintf (buf, sizeof buf, "%u", GLOBAL_SIS (TotalBioMass));
114 	}
115 	else
116 	{	// Element
117 		// print element's worth
118 		SetContextForeGroundColor (selected ?
119 				CARGO_SELECTED_WORTH_COLOR : CARGO_WORTH_COLOR);
120 		t.baseline.x = ELEMENT_COL_1;
121 		snprintf (buf, sizeof buf, "%u", GLOBAL (ElementWorth[element]));
122 		t.CharCount = (COUNT)~0;
123 		font_DrawText (&t);
124 
125 		snprintf (buf, sizeof buf, "%u", GLOBAL_SIS (ElementAmounts[element]));
126 	}
127 
128 	// print the element/bio amount
129 	SetContextForeGroundColor (selected ?
130 			CARGO_SELECTED_AMOUNT_COLOR : CARGO_AMOUNT_COLOR);
131 	t.baseline.x = ELEMENT_COL_2;
132 	t.CharCount = (COUNT)~0;
133 	font_DrawText (&t);
134 }
135 
136 static void
DrawCargoDisplay(void)137 DrawCargoDisplay (void)
138 {
139 	STAMP s;
140 	TEXT t;
141 	RECT r;
142 	COORD cy;
143 	COUNT i;
144 
145 	r.corner.x = 2;
146 	r.extent.width = FIELD_WIDTH + 1;
147 	r.corner.y = 20;
148 	// XXX: Shouldn't the height be 1 less? This draws the bottom border
149 	//   1 pixel too low. Or if not, why do we need another box anyway?
150 	r.extent.height = 129 - r.corner.y;
151 	DrawStarConBox (&r, 1,
152 			SHADOWBOX_MEDIUM_COLOR, SHADOWBOX_DARK_COLOR,
153 			TRUE, CARGO_BACK_COLOR);
154 
155 	// draw the "CARGO" title
156 	SetContextFont (StarConFont);
157 	t.baseline.x = (STATUS_WIDTH >> 1) - 1;
158 	t.baseline.y = 27;
159 	t.align = ALIGN_CENTER;
160 	t.pStr = GAME_STRING (CARGO_STRING_BASE);
161 	t.CharCount = (COUNT)~0;
162 	SetContextForeGroundColor (CARGO_SELECTED_AMOUNT_COLOR);
163 	font_DrawText (&t);
164 
165 	SetContextFont (TinyFont);
166 
167 	s.frame = SetAbsFrameIndex (MiscDataFrame,
168 			(NUM_SCANDOT_TRANSITIONS * 2) + 3);
169 	r.corner.x = ELEMENT_COL_0;
170 	r.extent = GetFrameBounds (s.frame);
171 	s.origin.x = r.corner.x + (r.extent.width >> 1);
172 
173 	cy = ELEMENT_ORG_Y;
174 
175 	// print element column headings
176 	t.align = ALIGN_RIGHT;
177 	t.baseline.y = cy - 1;
178 	t.CharCount = (COUNT)~0;
179 
180 	SetContextForeGroundColor (CARGO_WORTH_COLOR);
181 	t.baseline.x = ELEMENT_COL_1;
182 	t.pStr = "$";
183 	font_DrawText (&t);
184 
185 	t.baseline.x = ELEMENT_COL_2;
186 	t.pStr = "#";
187 	font_DrawText (&t);
188 
189 	// draw element icons and print amounts
190 	for (i = 0; i < NUM_ELEMENT_CATEGORIES; ++i, cy += ELEMENT_SPACING_Y)
191 	{
192 		// erase background under an element icon
193 		SetContextForeGroundColor (BLACK_COLOR);
194 		r.corner.y = cy;
195 		DrawFilledRectangle (&r);
196 
197 		// draw an element icon
198 		s.origin.y = r.corner.y + (r.extent.height >> 1);
199 		DrawStamp (&s);
200 		s.frame = SetRelFrameIndex (s.frame, 5);
201 
202 		DrawElementAmount (i, false);
203 	}
204 
205 	// erase background under the Bio icon
206 	SetContextForeGroundColor (BLACK_COLOR);
207 	r.corner.y = BIO_ORG_Y;
208 	DrawFilledRectangle (&r);
209 
210 	// draw the Bio icon
211 	s.origin.y = r.corner.y + (r.extent.height >> 1);
212 	s.frame = SetAbsFrameIndex (s.frame, 68);
213 	DrawStamp (&s);
214 
215 	// print the Bio amount
216 	DrawElementAmount (NUM_ELEMENT_CATEGORIES, false);
217 
218 	// draw the line over the Bio amount
219 	r.corner.x = 4;
220 	r.corner.y = BIO_ORG_Y - 2;
221 	r.extent.width = FIELD_WIDTH - 3;
222 	r.extent.height = 1;
223 	SetContextForeGroundColor (CARGO_SELECTED_BACK_COLOR);
224 	DrawFilledRectangle (&r);
225 
226 	// print "Free"
227 	t.baseline.x = 5;
228 	t.baseline.y = FREE_ORG_Y + TEXT_BASELINE;
229 	t.align = ALIGN_LEFT;
230 	t.pStr = GAME_STRING (CARGO_STRING_BASE + 1);
231 	t.CharCount = (COUNT)~0;
232 	font_DrawText (&t);
233 
234 	ShowRemainingCapacity ();
235 }
236 
237 void
DrawCargoStrings(BYTE OldElement,BYTE NewElement)238 DrawCargoStrings (BYTE OldElement, BYTE NewElement)
239 {
240 	CONTEXT OldContext;
241 
242 	OldContext = SetContext (StatusContext);
243 	SetContextFont (TinyFont);
244 
245 	BatchGraphics ();
246 
247 	if (OldElement > NUM_ELEMENT_CATEGORIES)
248 	{	// Asked for the initial display
249 		DrawCargoDisplay ();
250 
251 		// do not draw unselected again this time
252 		OldElement = NewElement;
253 	}
254 
255 	if (OldElement != NewElement)
256 	{	// unselect the previous element
257 		DrawElementAmount (OldElement, false);
258 	}
259 
260 	if (NewElement != (BYTE)~0)
261 	{	// select the new element
262 		DrawElementAmount (NewElement, true);
263 	}
264 
265 	UnbatchGraphics ();
266 	SetContext (OldContext);
267 }
268 
269 static void
DrawElementDescription(COUNT element)270 DrawElementDescription (COUNT element)
271 {
272 	DrawStatusMessage (GAME_STRING (element + (CARGO_STRING_BASE + 2)));
273 }
274 
275 static BOOLEAN
DoDiscardCargo(MENU_STATE * pMS)276 DoDiscardCargo (MENU_STATE *pMS)
277 {
278 	BYTE NewState;
279 	BOOLEAN select, cancel, back, forward;
280 
281 	select = PulsedInputState.menu[KEY_MENU_SELECT];
282 	cancel = PulsedInputState.menu[KEY_MENU_CANCEL];
283 	back = PulsedInputState.menu[KEY_MENU_UP] || PulsedInputState.menu[KEY_MENU_LEFT];
284 	forward = PulsedInputState.menu[KEY_MENU_DOWN] || PulsedInputState.menu[KEY_MENU_RIGHT];
285 
286 	if (GLOBAL (CurrentActivity) & CHECK_ABORT)
287 		return FALSE;
288 
289 	if (cancel)
290 	{
291 		return FALSE;
292 	}
293 	else if (select)
294 	{
295 		if (GLOBAL_SIS (ElementAmounts[pMS->CurState]))
296 		{
297 			--GLOBAL_SIS (ElementAmounts[pMS->CurState]);
298 			DrawCargoStrings (pMS->CurState, pMS->CurState);
299 
300 			--GLOBAL_SIS (TotalElementMass);
301 			ShowRemainingCapacity ();
302 		}
303 		else
304 		{	// no element left in cargo hold
305 			PlayMenuSound (MENU_SOUND_FAILURE);
306 		}
307 	}
308 	else
309 	{
310 		NewState = pMS->CurState;
311 		if (back)
312 		{
313 			if (NewState == 0)
314 				NewState += NUM_ELEMENT_CATEGORIES;
315 			--NewState;
316 		}
317 		else if (forward)
318 		{
319 			++NewState;
320 			if (NewState == NUM_ELEMENT_CATEGORIES)
321 				NewState = 0;
322 		}
323 
324 		if (NewState != pMS->CurState)
325 		{
326 			DrawCargoStrings (pMS->CurState, NewState);
327 			DrawElementDescription (NewState);
328 			pMS->CurState = NewState;
329 		}
330 	}
331 
332 	SleepThread (ONE_SECOND / 30);
333 
334 	return (TRUE);
335 }
336 
337 void
CargoMenu(void)338 CargoMenu (void)
339 {
340 	MENU_STATE MenuState;
341 
342 	memset (&MenuState, 0, sizeof MenuState);
343 
344 	// draw the initial cargo display
345 	DrawCargoStrings ((BYTE)~0, MenuState.CurState);
346 	DrawElementDescription (MenuState.CurState);
347 
348 	SetMenuSounds (MENU_SOUND_ARROWS, MENU_SOUND_SELECT);
349 
350 	MenuState.InputFunc = DoDiscardCargo;
351 	DoInput (&MenuState, TRUE);
352 
353 	// erase the cargo display
354 	ClearSISRect (DRAW_SIS_DISPLAY);
355 }
356 
357