f7efa50b756f1e7214c4a71452b4e494a5c8392a
[vms-empire.git] / util.c
1 /* $Id: util.c,v 1.4 2006/07/25 15:20:30 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 <stdio.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 Report a bug.
53 */
54
55 void
56 assert (expression, file, line)
57 char *expression;
58 char *file;
59 int line;
60 {
61         char buf[STRSIZE];
62
63         (void) move (lines, 0);
64         close_disp ();
65
66         (void) sprintf (buf, "assert failed: file %s line %d: %s",
67                         file, line, expression);
68
69         kill(getpid(), SIGSEGV);        /* core dump */
70 }
71
72 /*
73 End the game by cleaning up the display.
74 */
75
76 void
77 empend ()
78 {
79         close_disp ();
80         exit (0);
81 }
82
83 /*
84  * 03a 01Apr88 aml .Hacked movement algorithms for computer.
85  * 02b 01Jun87 aml .First round of bug fixes.
86  * 02a 01Jan87 aml .Translated to C.
87  * 01b 27May85 cal .Fixed round number update bug. Made truename simple.
88  * 01a 01Sep83 cal .Taken from a Decus tape
89  */
90
91 void
92 version ()
93 {
94         (void) addstr ("EMPIRE, Version 5.00 site Amdahl 1-Apr-1988");
95 }
96
97 /*
98 Here is a little routine to perform consistency checking on the
99 database.  I'm finding that my database is becoming inconsistent,
100 and I've no idea why.  Possibly this will help.
101
102 We perform the following functions:
103
104 1)  Make sure no list contains loops.
105
106 2)  Make sure every object is in either the free list with 0 hits,
107 or it is in the correct object list and a location list with non-zero hits,
108 and an appropriate owner.
109
110 3)  Make sure every city is on the map.
111
112 4)  Make sure every object is in the correct location and that
113 objects on the map have non-zero hits.
114
115 5)  Make sure every object in a cargo list has a ship pointer.
116
117 6)  Make sure every object with a ship pointer is in that ship's
118 cargo list.
119 */
120
121 static int in_free[LIST_SIZE]; /* TRUE if object in free list */
122 static int in_obj[LIST_SIZE]; /* TRUE if object in obj list */
123 static int in_loc[LIST_SIZE]; /* TRUE if object in a loc list */
124 static int in_cargo[LIST_SIZE]; /* TRUE if object in a cargo list */
125
126 void
127 check () {
128         void check_cargo(), check_obj(), check_obj_cargo();
129         
130         long i, j;
131         piece_info_t *p;
132         
133         /* nothing in any list yet */
134         for (i = 0; i < LIST_SIZE; i++) {
135                 in_free[i] = 0;
136                 in_obj[i] = 0;
137                 in_loc[i] = 0;
138                 in_cargo[i] = 0;
139         }
140                 
141         /* Mark all objects in free list.  Make sure objects in free list
142         have zero hits. */
143         
144         for (p = free_list; p != NULL; p = p->piece_link.next) {
145                 i = p - object;
146                 ASSERT (!in_free[i]);
147                 in_free[i] = 1;
148                 ASSERT (p->hits == 0);
149                 if (p->piece_link.prev)
150                         ASSERT (p->piece_link.prev->piece_link.next == p);
151         }
152         
153         /* Mark all objects in the map.
154         Check that cities are in corect location.
155         Check that objects are in correct location,
156         have a good owner, and good hits. */
157         
158         for (i = 0; i < MAP_SIZE; i++) {
159                 if (map[i].cityp) ASSERT (map[i].cityp->loc == i);
160                 
161                 for (p = map[i].objp; p != NULL; p = p->loc_link.next) {
162                         ASSERT (p->loc == i);
163                         ASSERT (p->hits > 0);
164                         ASSERT (p->owner == USER || p->owner == COMP);
165                                 
166                         j = p - object;
167                         ASSERT (!in_loc[j]);
168                         in_loc[j] = 1;
169                         
170                         if (p->loc_link.prev)
171                                 ASSERT (p->loc_link.prev->loc_link.next == p);
172                 }
173         }
174
175         /* make sure all cities are on map */
176
177         for (i = 0; i < NUM_CITY; i++)
178                 ASSERT (map[city[i].loc].cityp == &(city[i]));
179
180         /* Scan object lists. */
181         
182         check_obj (comp_obj, COMP);
183         check_obj (user_obj, USER);
184         
185         /* Scan cargo lists. */
186         
187         check_cargo (user_obj[TRANSPORT], ARMY);
188         check_cargo (comp_obj[TRANSPORT], ARMY);
189         check_cargo (user_obj[CARRIER], FIGHTER);
190         check_cargo (comp_obj[CARRIER], FIGHTER);
191         
192         /* Make sure all objects with ship pointers are in cargo. */
193
194         check_obj_cargo (comp_obj);
195         check_obj_cargo (user_obj);
196         
197         /* Make sure every object is either free or in loc and obj list. */
198
199         for (i = 0; i < LIST_SIZE; i++)
200                 ASSERT (in_free[i] != (in_loc[i] && in_obj[i]));
201 }
202
203 /*
204 Check object lists.  We look for:
205
206 1)  Loops and bad prev pointers.
207
208 2)  Dead objects.
209
210 3)  Invalid types.
211
212 4)  Invalid owners.
213 */
214
215 void
216 check_obj (list, owner)
217 piece_info_t **list;
218 int owner;
219 {
220         long i, j;
221         piece_info_t *p;
222         
223         for (i = 0; i < NUM_OBJECTS; i++)
224         for (p = list[i]; p != NULL; p = p->piece_link.next) {
225                 ASSERT (p->owner == owner);
226                 ASSERT (p->type == i);
227                 ASSERT (p->hits > 0);
228                 
229                 j = p - object;
230                 ASSERT (!in_obj[j]);
231                 in_obj[j] = 1;
232         
233                 if (p->piece_link.prev)
234                         ASSERT (p->piece_link.prev->piece_link.next == p);
235         }
236 }
237
238 /*
239 Check cargo lists.  We assume object lists are valid.
240 as we will place bits in the 'in_cargo' array that are used by
241 'check_obj'.
242
243 Check for:
244
245 1)  Number of items in list is same as cargo count.
246
247 2)  Type of cargo is correct.
248
249 3)  Location of cargo matches location of ship.
250
251 4)  Ship pointer of cargo points to correct ship.
252
253 5)  There are no loops in cargo list and prev ptrs are correct.
254
255 6)  All cargo is alive.
256 */
257
258 void
259 check_cargo (list, cargo_type)
260 piece_info_t *list;
261 int cargo_type;
262 {
263         piece_info_t *p, *q;
264         long j, count;
265         
266         for (p = list; p != NULL; p = p->piece_link.next) {
267                 count = 0;
268                 for (q = p->cargo; q != NULL; q = q->cargo_link.next) {
269                         count += 1; /* count items in list */
270                         ASSERT (q->type == cargo_type);
271                         ASSERT (q->owner == p->owner);
272                         ASSERT (q->hits > 0);
273                         ASSERT (q->ship == p);
274                         ASSERT (q->loc == p->loc);
275                         
276                         j = q - object;
277                         ASSERT (!in_cargo[j]);
278                         in_cargo[j] = 1;
279
280                         if (p->cargo_link.prev)
281                                 ASSERT (p->cargo_link.prev->cargo_link.next == p);
282                 }
283                 ASSERT (count == p->count);
284         }
285 }
286
287 /*
288 Scan through object lists making sure every object with a ship
289 pointer appears in a cargo list.  We assume object and cargo
290 lists are valid.
291 */
292
293 void
294 check_obj_cargo (list)
295 piece_info_t **list;
296 {
297         piece_info_t *p;
298         long i;
299
300         for (i = 0; i < NUM_OBJECTS; i++)
301         for (p = list[i]; p != NULL; p = p->piece_link.next) {
302                 if (p->ship) ASSERT (in_cargo[p-object]);
303         }
304 }