38d52b8bb14a945a6a0c48b00bd872908498e5fd
[vms-empire.git] / util.c
1 /* $Id: util.c,v 1.2 1990/03/29 23:21:50 eric Exp esr $  - (c) Copyright 1987, 1988 Chuck Simmons */
2
3 /*
4  *    Copyright (C) 1987, 1988 Chuck Simmons
5  * 
6  * See the file COPYING, distributed with empire, for restriction
7  * and warranty information.
8  */
9
10 /*
11 util.c -- various utility routines.
12 */
13
14 #include <curses.h>
15 #include <ctype.h>
16 #include "empire.h"
17 #include "extern.h"
18
19
20 /*
21 Convert a string to uppercase.
22 Shirley this is defined elsewhere?
23 */
24
25 #include <ctype.h>
26
27 void
28 tupper (str)
29 char    *str;
30 {
31         while (*str) {
32                 if (islower (*str)) *str = upper (*str);
33                 str++;
34         }
35 }
36
37 /*
38 Convert a character to uppercase (if it is lowercase)
39 */
40
41 char
42 upper (c)
43 char c;
44 {
45         if (islower (c))
46                 return toupper (c);
47         else return c;
48 }
49
50 /*
51 Clear the end of a specified line starting at the specified column.
52 */
53
54 void
55 clreol(linep, colp)
56 int linep, colp;
57 {
58         (void) move (linep, colp);
59         (void) clrtoeol();
60 }
61
62 /*
63 Initialize the terminal.
64 */
65
66 void
67 ttinit()
68 {
69         (void) initscr();
70         (void) noecho();
71         (void) crmode();
72 #ifdef A_COLOR
73         init_colors();
74 #endif /* A_COLOR */
75         lines = LINES;
76         cols = COLS;
77         if (lines > MAP_HEIGHT + NUMTOPS + 1)
78                 lines = MAP_HEIGHT + NUMTOPS + 1;
79         if (cols > MAP_WIDTH + NUMSIDES)
80                 cols = MAP_WIDTH + NUMSIDES;
81 }
82
83
84 /*
85 Clear the screen.  We must also kill information maintained about the
86 display.
87 */
88
89 void
90 clear_screen () {
91         (void) clear ();
92         (void) refresh ();
93         kill_display ();
94 }
95
96 /*
97 Redraw the screen.
98 */
99
100 void
101 redraw () {
102         (void) clearok (curscr, TRUE);
103         (void) refresh ();
104 }
105
106 /*
107 Wait a little bit to give user a chance to see a message.  We refresh
108 the screen and pause for a few milliseconds.
109 */
110
111 void
112 delay () {
113         (void) refresh ();
114         (void) napms (delay_time); /* pause a bit */
115 }
116
117
118 /*
119 Clean up the display.  This routine gets called as we leave the game.
120 */
121
122 void
123 close_disp()
124 {
125         (void) move (LINES - 1, 0);
126         (void) clrtoeol ();
127         (void) refresh ();
128         (void) endwin ();
129 }
130
131 /*
132 Position the cursor and output a string.
133 */
134
135 void
136 pos_str1 (row, col, str, a, b, c, d, e, f, g, h)
137 int row, col;
138 char *str, *a;
139 int b, c, d, e, f, g, h;
140 {
141         (void) move (row, col);
142         addprintf1 (str, a, b, c, d, e, f, g, h);
143 }
144 void
145 pos_str (row, col, str, a, b, c, d, e, f, g, h)
146 int row, col;
147 char *str;
148 int a, b, c, d, e, f, g, h;
149 {
150         (void) move (row, col);
151         addprintf (str, a, b, c, d, e, f, g, h);
152 }
153
154 void
155 /* VARARGS1 */
156 addprintf (str, a, b, c, d, e, f, g, h)
157 char *str;
158 int a, b, c, d, e, f, g, h;
159 {
160         char junkbuf[STRSIZE];
161         
162         (void) sprintf (junkbuf, str, a, b, c, d, e, f, g, h);
163         (void) addstr (junkbuf);
164 }
165 void
166 /* VARARGS1 */
167 addprintf1 (str, a, b, c, d, e, f, g, h)
168 char *str;
169 char *a;
170 int b, c, d, e, f, g, h;
171 {
172         char junkbuf[STRSIZE];
173         
174         (void) sprintf (junkbuf, str, a, b, c, d, e, f, g, h);
175         (void) addstr (junkbuf);
176 }
177 void
178 /* VARARGS1 */
179 addprintf2 (str, a, b, c, d, e, f, g, h)
180 char *str;
181 char *a, *e, *f;
182 int b, c, d, g, h;
183 {
184         char junkbuf[STRSIZE];
185         
186         (void) sprintf (junkbuf, str, a, b, c, d, e, f, g, h);
187         (void) addstr (junkbuf);
188 }
189
190 /*
191 Report a bug.
192 */
193
194 void
195 assert (expression, file, line)
196 char *expression;
197 char *file;
198 int line;
199 {
200         char buf[STRSIZE];
201         int a;
202
203         (void) move (lines, 0);
204         close_disp ();
205
206         (void) sprintf (buf, "assert failed: file %s line %d: %s",
207                         file, line, expression);
208
209         a = 1; /* keep lint quiet */
210         a /= 0; /* force a core dump */
211         a = a; /* keep lint quiet */
212 }
213
214 /*
215 End the game by cleaning up the display.
216 */
217
218 void
219 empend ()
220 {
221         close_disp ();
222         exit (0);
223 }
224
225 /*
226  * 03a 01Apr88 aml .Hacked movement algorithms for computer.
227  * 02b 01Jun87 aml .First round of bug fixes.
228  * 02a 01Jan87 aml .Translated to C.
229  * 01b 27May85 cal .Fixed round number update bug. Made truename simple.
230  * 01a 01Sep83 cal .Taken from a Decus tape
231  */
232
233 void
234 ver ()
235 {
236         (void) addstr ("EMPIRE, Version 5.00 site Amdahl 1-Apr-1988");
237 }
238
239 /*
240 Here is a little routine to perform consistency checking on the
241 database.  I'm finding that my database is becoming inconsistent,
242 and I've no idea why.  Possibly this will help.
243
244 We perform the following functions:
245
246 1)  Make sure no list contains loops.
247
248 2)  Make sure every object is in either the free list with 0 hits,
249 or it is in the correct object list and a location list with non-zero hits,
250 and an appropriate owner.
251
252 3)  Make sure every city is on the map.
253
254 4)  Make sure every object is in the correct location and that
255 objects on the map have non-zero hits.
256
257 5)  Make sure every object in a cargo list has a ship pointer.
258
259 6)  Make sure every object with a ship pointer is in that ship's
260 cargo list.
261 */
262
263 static int in_free[LIST_SIZE]; /* TRUE if object in free list */
264 static int in_obj[LIST_SIZE]; /* TRUE if object in obj list */
265 static int in_loc[LIST_SIZE]; /* TRUE if object in a loc list */
266 static int in_cargo[LIST_SIZE]; /* TRUE if object in a cargo list */
267
268 void
269 check () {
270         void check_cargo(), check_obj(), check_obj_cargo();
271         
272         long i, j;
273         piece_info_t *p;
274         
275         /* nothing in any list yet */
276         for (i = 0; i < LIST_SIZE; i++) {
277                 in_free[i] = 0;
278                 in_obj[i] = 0;
279                 in_loc[i] = 0;
280                 in_cargo[i] = 0;
281         }
282                 
283         /* Mark all objects in free list.  Make sure objects in free list
284         have zero hits. */
285         
286         for (p = free_list; p != NULL; p = p->piece_link.next) {
287                 i = p - object;
288                 ASSERT (!in_free[i]);
289                 in_free[i] = 1;
290                 ASSERT (p->hits == 0);
291                 if (p->piece_link.prev)
292                         ASSERT (p->piece_link.prev->piece_link.next == p);
293         }
294         
295         /* Mark all objects in the map.
296         Check that cities are in corect location.
297         Check that objects are in correct location,
298         have a good owner, and good hits. */
299         
300         for (i = 0; i < MAP_SIZE; i++) {
301                 if (map[i].cityp) ASSERT (map[i].cityp->loc == i);
302                 
303                 for (p = map[i].objp; p != NULL; p = p->loc_link.next) {
304                         ASSERT (p->loc == i);
305                         ASSERT (p->hits > 0);
306                         ASSERT (p->owner == USER || p->owner == COMP);
307                                 
308                         j = p - object;
309                         ASSERT (!in_loc[j]);
310                         in_loc[j] = 1;
311                         
312                         if (p->loc_link.prev)
313                                 ASSERT (p->loc_link.prev->loc_link.next == p);
314                 }
315         }
316
317         /* make sure all cities are on map */
318
319         for (i = 0; i < NUM_CITY; i++)
320                 ASSERT (map[city[i].loc].cityp == &(city[i]));
321
322         /* Scan object lists. */
323         
324         check_obj (comp_obj, COMP);
325         check_obj (user_obj, USER);
326         
327         /* Scan cargo lists. */
328         
329         check_cargo (user_obj[TRANSPORT], ARMY);
330         check_cargo (comp_obj[TRANSPORT], ARMY);
331         check_cargo (user_obj[CARRIER], FIGHTER);
332         check_cargo (comp_obj[CARRIER], FIGHTER);
333         
334         /* Make sure all objects with ship pointers are in cargo. */
335
336         check_obj_cargo (comp_obj);
337         check_obj_cargo (user_obj);
338         
339         /* Make sure every object is either free or in loc and obj list. */
340
341         for (i = 0; i < LIST_SIZE; i++)
342                 ASSERT (in_free[i] != (in_loc[i] && in_obj[i]));
343 }
344
345 /*
346 Check object lists.  We look for:
347
348 1)  Loops and bad prev pointers.
349
350 2)  Dead objects.
351
352 3)  Invalid types.
353
354 4)  Invalid owners.
355 */
356
357 void
358 check_obj (list, owner)
359 piece_info_t **list;
360 int owner;
361 {
362         long i, j;
363         piece_info_t *p;
364         
365         for (i = 0; i < NUM_OBJECTS; i++)
366         for (p = list[i]; p != NULL; p = p->piece_link.next) {
367                 ASSERT (p->owner == owner);
368                 ASSERT (p->type == i);
369                 ASSERT (p->hits > 0);
370                 
371                 j = p - object;
372                 ASSERT (!in_obj[j]);
373                 in_obj[j] = 1;
374         
375                 if (p->piece_link.prev)
376                         ASSERT (p->piece_link.prev->piece_link.next == p);
377         }
378 }
379
380 /*
381 Check cargo lists.  We assume object lists are valid.
382 as we will place bits in the 'in_cargo' array that are used by
383 'check_obj'.
384
385 Check for:
386
387 1)  Number of items in list is same as cargo count.
388
389 2)  Type of cargo is correct.
390
391 3)  Location of cargo matches location of ship.
392
393 4)  Ship pointer of cargo points to correct ship.
394
395 5)  There are no loops in cargo list and prev ptrs are correct.
396
397 6)  All cargo is alive.
398 */
399
400 void
401 check_cargo (list, cargo_type)
402 piece_info_t *list;
403 int cargo_type;
404 {
405         piece_info_t *p, *q;
406         long j, count;
407         
408         for (p = list; p != NULL; p = p->piece_link.next) {
409                 count = 0;
410                 for (q = p->cargo; q != NULL; q = q->cargo_link.next) {
411                         count += 1; /* count items in list */
412                         ASSERT (q->type == cargo_type);
413                         ASSERT (q->owner == p->owner);
414                         ASSERT (q->hits > 0);
415                         ASSERT (q->ship == p);
416                         ASSERT (q->loc == p->loc);
417                         
418                         j = q - object;
419                         ASSERT (!in_cargo[j]);
420                         in_cargo[j] = 1;
421
422                         if (p->cargo_link.prev)
423                                 ASSERT (p->cargo_link.prev->cargo_link.next == p);
424                 }
425                 ASSERT (count == p->count);
426         }
427 }
428
429 /*
430 Scan through object lists making sure every object with a ship
431 pointer appears in a cargo list.  We assume object and cargo
432 lists are valid.
433 */
434
435 void
436 check_obj_cargo (list)
437 piece_info_t **list;
438 {
439         piece_info_t *p;
440         long i;
441
442         for (i = 0; i < NUM_OBJECTS; i++)
443         for (p = list[i]; p != NULL; p = p->piece_link.next) {
444                 if (p->ship) ASSERT (in_cargo[p-object]);
445         }
446 }