1 /* pbar.c: handles rate-of-change indicators
2 * This file is part of lincity.
3 * Lincity is copyright (c) I J Peters 1995-1997, (c) Greg Sharp 1997-2001.
4 * Portions copyright (c) 2001 Corey Keasling.
5 * ---------------------------------------------------------------------- */
6 #include "lcconfig.h"
7 #include <math.h>
8 #include "cliglobs.h"
9 #include "lchelp.h"
10 #include "mouse.h"
11 #include "shrglobs.h"
12 #include "pbar.h"
13 #include "lin-city.h"
14 #include "lclib.h"
15 #include "stats.h"
16 #include "engglobs.h"
17
18 struct pbar_st pbars[NUM_PBARS];
19
20 void
init_pbars(void)21 init_pbars (void)
22 {
23 int i, p;
24 for (p = 0; p < NUM_PBARS; p++) {
25 pbars[p].data_size = 0;
26 pbars[p].oldtot = 0;
27 pbars[p].tot = 0;
28 pbars[p].diff = 0;
29 for (i = 0; i < PBAR_DATA_SIZE; i++)
30 pbars[p].data[i] = 0;
31 }
32
33 }
34
35 void
pbars_full_refresh(void)36 pbars_full_refresh (void)
37 {
38 Rect* pba = &scr.pbar_area;
39 draw_small_bezel (pba->x+4, pba->y+4, pba->w-8, pba->h-8, yellow(0));
40 init_pbar_text ();
41 draw_pbars ();
42 }
43
44 void
init_pbar_text(void)45 init_pbar_text (void)
46 {
47 clear_pbar_text (&scr.pbar_pop);
48 clear_pbar_text (&scr.pbar_tech);
49 clear_pbar_text (&scr.pbar_food);
50 clear_pbar_text (&scr.pbar_jobs);
51 clear_pbar_text (&scr.pbar_money);
52 clear_pbar_text (&scr.pbar_coal);
53 clear_pbar_text (&scr.pbar_goods);
54 clear_pbar_text (&scr.pbar_ore);
55 clear_pbar_text (&scr.pbar_steel);
56 }
57
58 /* ---------------------------------------------------------------------- *
59 * Pbar drawing function
60 * ---------------------------------------------------------------------- */
61
62 void
draw_pbar(Rect * b,char * graphic)63 draw_pbar (Rect* b, char* graphic)
64 /* XXX: WCK: why not just make the graphic include the black? */
65 /* GCS: Good idea, but xpicedit is painful to use! */
66 {
67 Fgl_fillbox (b->x, b->y, b->w, b->h, 0);
68 Fgl_putbox (b->x + (b->w / 2) - 8, b->y, 16, 16, graphic);
69 }
70
71 void
draw_pbars(void)72 draw_pbars (void)
73 {
74 draw_pbar (&scr.pbar_pop, pop_pbar_graphic);
75 draw_pbar (&scr.pbar_tech, tech_pbar_graphic);
76 draw_pbar (&scr.pbar_food, food_pbar_graphic);
77 draw_pbar (&scr.pbar_jobs, jobs_pbar_graphic);
78 draw_pbar (&scr.pbar_money, money_pbar_graphic);
79 draw_pbar (&scr.pbar_coal, coal_pbar_graphic);
80 draw_pbar (&scr.pbar_goods, goods_pbar_graphic);
81 draw_pbar (&scr.pbar_ore, ore_pbar_graphic);
82 draw_pbar (&scr.pbar_steel, steel_pbar_graphic);
83 }
84
85 /* Text functions */
86
87 void
clear_pbar_text(Rect * pbar)88 clear_pbar_text (Rect* pbar)
89 {
90 Fgl_fillbox (pbar->x + pbar->w + 1, pbar->y, PBAR_TEXT_W, pbar->h, 0);
91 }
92
93 void
write_pbar_int(Rect * b,int val)94 write_pbar_int (Rect* b, int val)
95 {
96 char s[16];
97 format_number5 (s, pbars[val].data[pbars[val].data_size-1]);
98 Fgl_setfontcolors (0, 255);
99 Fgl_write (b->x + b->w + 25, b->y + 4, s);
100 Fgl_setfontcolors (TEXT_BG_COLOUR, TEXT_FG_COLOUR);
101 }
102
103 void
write_pbar_text(Rect * b,char * s)104 write_pbar_text (Rect* b, char * s)
105 {
106 Fgl_setfontcolors (0, 255);
107 Fgl_write (b->x + b->w + 25, b->y + 4, s);
108 Fgl_setfontcolors (TEXT_BG_COLOUR, TEXT_FG_COLOUR);
109 }
110
111 /* XXX: WCK: Macros anyone? */
112 /* GCS: I thought I might like to change the "sensitivity" of the pbars
113 on a case-by-case basis, but never got around to it. */
114 /* WCK: sure, but the preprocessor can still do some of the work, so: */
115 /* GCS: The new macros look good. I killed the old code. */
116
117 #define pbar_adjust_pop(diff) 2 * diff
118 #define pbar_adjust_tech(diff) diff > 0 ? diff / 4 + 1 : -((-diff+1)/ 2)
119 #define pbar_adjust_food(diff) diff > 0 ? diff / 2 + 1 : diff
120 #define pbar_adjust_jobs(diff) diff > 0 ? diff / 2 + 1 : diff
121 #define pbar_adjust_coal(diff) diff > 0 ? diff / 2 + 1 : diff
122 #define pbar_adjust_goods(diff) diff > 0 ? diff / 2 + 1 : diff
123 #define pbar_adjust_ore(diff) diff > 0 ? diff / 2 + 1 : diff
124 #define pbar_adjust_steel(diff) diff > 0 ? diff / 2 + 1 : diff
125 #define pbar_adjust_money(diff) diff > 0 ? diff / 800 + 1 : diff / 400
126
127
128 /* XXX: wck: write_pbar_* changes font colours every time its called; only
129 need to do this once. Maybe it should be folded in.*/
130
131 void
refresh_population_text(void)132 refresh_population_text (void)
133 {
134 /* GCS: This function is kind of a hack, but I need the population
135 to be refreshed immediately after the rocket is launched.
136 Therefore, this function! */
137 Rect * b;
138 update_pbar (PPOP, housed_population + people_pool, 0);
139 b = &scr.pbar_pop;
140 write_pbar_int (b, PPOP);
141 }
142
143 void
refresh_pbars(void)144 refresh_pbars (void)
145 {
146 Rect * b;
147 char s[10];
148
149 /* Population */
150 b = &scr.pbar_pop;
151 draw_pbar_new (b, pbar_adjust_pop(pbars[PPOP].diff));
152 write_pbar_int (b, PPOP);
153
154 /* Technology */
155 b = &scr.pbar_tech;
156 draw_pbar_new (b, pbar_adjust_tech(pbars[PTECH].diff));
157
158 snprintf (s, 10, "%5.1f",
159 (float) pbars[PTECH].data[pbars[PTECH].data_size - 1] *
160 100.0 / MAX_TECH_LEVEL);
161
162 write_pbar_text (b, s);
163
164 /* Food */
165 b = &scr.pbar_food;
166 draw_pbar_new (b, pbar_adjust_food(pbars[PFOOD].diff));
167 write_pbar_int (b, PFOOD);
168
169 /* Jobs */
170 b = &scr.pbar_jobs;
171 draw_pbar_new (b, pbar_adjust_jobs(pbars[PFOOD].diff));
172 write_pbar_int (b, PJOBS);
173
174 /* Coal */
175 b = &scr.pbar_coal;
176 draw_pbar_new (b, pbar_adjust_coal(pbars[PCOAL].diff));
177 write_pbar_int (b, PCOAL);
178
179 /* Goods */
180 b = &scr.pbar_goods;
181 draw_pbar_new (b, pbar_adjust_goods(pbars[PGOODS].diff));
182 write_pbar_int (b, PGOODS);
183
184 /* Ore */
185 b = &scr.pbar_ore;
186 draw_pbar_new (b, pbar_adjust_ore(pbars[PORE].diff));
187 write_pbar_int (b, PORE);
188
189 /* Steel */
190 b = &scr.pbar_steel;
191 draw_pbar_new (b, pbar_adjust_steel(pbars[PSTEEL].diff));
192 write_pbar_int (b, PSTEEL);
193
194 /* Money */
195 b = &scr.pbar_money;
196 draw_pbar_new (b, pbar_adjust_money(pbars[PMONEY].diff));
197 write_pbar_int (b, PMONEY);
198 }
199
200
201 /*
202 update_pbar: add a new value to the array used to calculate the
203 pbar display. If month_flag is 1, the oldtotal is updated, all
204 values are shifted up (dropping the first one), and the new value
205 is added at the end. If 0, the new value replaces the most recently
206 updated value. The data is summed and the result compared to the
207 old total.
208
209 */
210
211 void
update_pbar(int pbar_num,int value,int month_flag)212 update_pbar (int pbar_num, int value, int month_flag)
213 {
214
215 int i;
216
217 struct pbar_st * pbar = &pbars[pbar_num];
218
219 if (month_flag) {
220 pbar->oldtot = pbar->tot;
221
222 /* If the dataset isn't full, just add it and forget month_flag */
223 if (pbar->data_size < PBAR_DATA_SIZE) {
224 pbar->data_size++;
225 month_flag = 0;
226 }
227 }
228
229 pbar->tot = 0;
230
231 for (i = 0; i < (pbar->data_size - 1); i++) {
232 if (month_flag)
233 pbar->tot += (pbar->data[i] = pbar->data[i+1]);
234 else
235 pbar->tot += pbar->data[i];
236 }
237
238
239 pbar->tot += pbar->data[i] = value;
240 pbar->diff = pbar->tot - pbar->oldtot;
241 }
242
243 void
update_pbars_daily()244 update_pbars_daily()
245 {
246 update_pbar (PPOP, housed_population + people_pool, 0);
247 update_pbar (PTECH, tech_level, 0);
248 update_pbar (PFOOD, food_in_markets / 1000, 0);
249 update_pbar (PJOBS, jobs_in_markets / 1000, 0);
250 update_pbar (PCOAL, coal_in_markets / 250, 0);
251 update_pbar (PGOODS, goods_in_markets / 500, 0);
252 update_pbar (PORE, ore_in_markets / 500, 0);
253 update_pbar (PSTEEL, steel_in_markets / 25, 0);
254 update_pbar (PMONEY, total_money, 0);
255 }
256
257 void
update_pbars_monthly()258 update_pbars_monthly()
259 {
260 update_pbar (PPOP, housed_population + people_pool, 1);
261 update_pbar (PTECH, tech_level, 1);
262 update_pbar (PFOOD, tfood_in_markets / data_last_month, 1);
263 update_pbar (PJOBS, tjobs_in_markets / data_last_month, 1);
264 update_pbar (PCOAL, tcoal_in_markets / data_last_month, 1);
265 update_pbar (PGOODS, tgoods_in_markets / data_last_month, 1);
266 update_pbar (PORE, tore_in_markets / data_last_month, 1);
267 update_pbar (PSTEEL, tsteel_in_markets / data_last_month, 1);
268 update_pbar (PMONEY, total_money, 1);
269 }
270
271 int
compute_pbar_offset(Rect * b,int val)272 compute_pbar_offset (Rect* b, int val)
273 {
274 int offset;
275 int val_abs = val > 0 ? val : -val;
276
277 if (!val)
278 return 0;
279
280 offset = (int) log (val_abs);
281 if (offset > (b->w / 2) - 8) {
282 offset = (b->w / 2) - 8;
283 }
284 offset = val > 0 ? offset : -offset;
285
286 return offset;
287 }
288
289 void
draw_pbar_new(Rect * b,int val)290 draw_pbar_new (Rect* b, int val)
291 {
292
293 int offset;
294 int spike_start, spike_end;
295
296 /* offset, oldoffset are the size of spike in pixels */
297 offset = compute_pbar_offset (b, val);
298
299 /* Clear both sides of the pbar */
300 Fgl_fillbox (b->x, b->y, b->w / 2 - 8, b->h, 0);
301 Fgl_fillbox (b->x + (b->w / 2) + 8, b->y, b->w / 2 - 8, b->h, 0);
302
303
304 /* Figure out pos/neg and length and draw */
305 if (offset > 0) {
306 /* Right/Positive */
307 spike_start = b->x + (b->w / 2) + 8;
308 spike_end = spike_start + offset;
309 Fgl_fillbox (spike_start, b->y+2, spike_end - spike_start, b->h-4,
310 (green(12)));
311 } else if (offset < 0) {
312 /* Left/Negative */
313 spike_end = b->x + (b->w / 2) - 8;
314 spike_start = spike_end + offset;
315 Fgl_fillbox (spike_start, b->y+2, spike_end - spike_start, b->h-4,
316 (red(12)));
317 }
318 }
319
320
321
322 void
pbar_mouse(int rawx,int rawy,int button)323 pbar_mouse(int rawx, int rawy, int button)
324 {
325 if (button != LC_MOUSE_RIGHTBUTTON)
326 return;
327
328 /* check for help with pbars */
329 activate_help ("pbar.hlp");
330
331 #if defined (commentout)
332 if (mouse_in_rect (&scr.pbar_pop,x,y)) {
333 activate_help ("pbar-pop.hlp");
334 return;
335 }
336 else if (mouse_in_rect (&scr.pbar_tech,x,y)) {
337 activate_help ("pbar-tech.hlp");
338 return;
339 }
340 else if (mouse_in_rect (&scr.pbar_food,x,y)) {
341 activate_help ("pbar-food.hlp");
342 return;
343 }
344 else if (mouse_in_rect (&scr.pbar_jobs,x,y)) {
345 activate_help ("pbar-jobs.hlp");
346 return;
347 }
348 else if (mouse_in_rect (&scr.pbar_money,x,y)) {
349 activate_help ("pbar-money.hlp");
350 return;
351 }
352 else if (mouse_in_rect (&scr.pbar_coal,x,y)) {
353 activate_help ("pbar-coal.hlp");
354 return;
355 }
356 else if (mouse_in_rect (&scr.pbar_goods,x,y)) {
357 activate_help ("pbar-goods.hlp");
358 return;
359 }
360 else if (mouse_in_rect (&scr.pbar_ore,x,y)) {
361 activate_help ("pbar-ore.hlp");
362 return;
363 }
364 else if (mouse_in_rect (&scr.pbar_steel,x,y)) {
365 activate_help ("pbar-steel.hlp");
366 return;
367 }
368 #endif
369 }
370