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