Use bool for clarity.
[vms-empire.git] / edit.c
1 /*
2  *    Copyright (C) 1987, 1988 Chuck Simmons
3  * 
4  * See the file COPYING, distributed with empire, for restriction
5  * and warranty information.
6  */
7
8 /*
9 edit.c -- Routines to handle edit mode commands.
10 */
11
12 #include <stdio.h>
13 #include <string.h>
14 #include <curses.h>
15 #include <ctype.h>
16 #include "empire.h"
17 #include "extern.h"
18
19 void e_move(loc_t *path_start, loc_t loc);
20 extern int get_piece_name(void);
21
22 void
23 edit(loc_t edit_cursor)
24 {
25         char e_cursor();
26         void e_leave(), e_print(), e_random();
27         void e_stasis(), e_end(), e_wake(), e_sleep();
28         void e_info(), e_prod(), e_help(), e_explore();
29         void e_fill(), e_land(), e_city_func(), e_transport();
30         void e_attack(), e_repair();
31
32         loc_t path_start;
33         int path_type;
34         char e;
35         
36         path_start = -1; /* not building a path yet */
37         
38         for (;;) { /* until user gives command to leave */
39                 display_loc_u (edit_cursor); /* position cursor */
40                 e = e_cursor (&edit_cursor); /* handle cursor movement */
41
42                 switch (e) {
43                 case 'B': /* change city production */
44                         e_prod (edit_cursor);
45                         break;
46                 case 'F': /* fill */
47                         e_fill (edit_cursor);
48                         break;
49                 case 'G': /* explore */
50                         e_explore (edit_cursor);
51                         break;
52                 case 'H': /* help */
53                         e_help ();
54                         break;
55                 case 'I': /* directional stasis */
56                         e_stasis (edit_cursor);
57                         break;
58                 case 'K': /* wake up anything and everything */
59                         e_wake (edit_cursor);
60                         break;
61                 case 'L': /* land plane */
62                         e_land (edit_cursor);
63                         break;
64                 case 'M': /* start move to location */
65                         path_type = NOPIECE;
66                         e_move (&path_start, edit_cursor);
67                         break;
68                 case 'N': /* end move to location */
69                         e_end (&path_start, edit_cursor, path_type);
70                         break;
71                 case 'O': /* leave display mode */
72                         e_leave ();
73                         return;
74                 case 'P': /* print new sector */
75                         e_print (&edit_cursor);
76                         break;
77                 case 'R': /* make piece move randomly */
78                         e_random (edit_cursor);
79                         break;
80                 case 'S': /* sleep */
81                         e_sleep (edit_cursor);
82                         break;
83                 case 'T': /* transport army */
84                         e_transport (edit_cursor);
85                         break;
86                 case 'U': /* repair ship */
87                         e_repair (edit_cursor);
88                         break;
89                 case 'V': /* set city function */
90                         e_city_func (&path_start, edit_cursor, &path_type);
91                         break;
92                 case 'Y': /* set army func to attack */
93                         e_attack (edit_cursor);
94                         break;
95                 case '?': /* request info */
96                         e_info (edit_cursor);
97                         break;
98                 case '\014': /* control-L */
99                         redraw ();
100                         break;
101                 default: /* bad command? */
102                         huh ();
103                         break;
104                 }
105         }
106 }
107
108 /*
109 Get the next command.  We handle cursor movement here.
110 This routine is an attempt to make cursor movement reasonably
111 fast.
112 */
113
114 char
115 e_cursor(loc_t *edit_cursor)
116 {
117         chtype e;
118         int p;
119         
120         /* set up terminal */
121         (void) crmode ();
122         (void) refresh ();
123         e = getch ();
124         topini (); /* clear any error messages */
125
126         for (;;) {
127                 p = direction (e);
128                 if (p == -1) break;
129
130                 if (!move_cursor (edit_cursor, dir_offset[p]))
131                         (void) beep ();
132                 
133                 (void) refresh ();
134                 e = getch ();
135         }
136         (void) nocrmode (); /* reset terminal */
137         if (islower (e)) e = upper (e);
138         return e;
139 }
140
141 /*
142 Leave edit mode.
143 */
144
145 void
146 e_leave(void) {
147 }
148
149 /*
150 Print new sector.
151 */
152
153 void
154 e_print(loc_t *edit_cursor)
155 {
156         int sector;
157         
158         sector = get_range ("New Sector? ", 0, NUM_SECTORS-1);
159
160         /* position cursor at center of sector */
161         *edit_cursor = sector_loc (sector);
162         sector_change (); /* allow change of sector */
163 }
164
165 /*
166 Set the function of a piece.
167 */
168
169 void
170 e_set_func(loc_t loc, long func)
171 {
172         piece_info_t *obj;
173         obj = find_obj_at_loc (loc);
174         if (obj != NULL && obj->owner == USER) {
175                 obj->func = func;
176                 return;
177         }
178         huh (); /* no object here */
179 }
180         
181 /* Set the function of a city for some piece. */
182
183 void
184 e_set_city_func(city_info_t *cityp, int type, long func)
185 {
186         cityp->func[type] = func;
187 }
188
189 /*
190 Set a piece to move randomly.
191 */
192
193 void
194 e_random(loc_t loc)
195 {
196         e_set_func (loc, RANDOM);
197 }
198
199 void
200 e_city_random(city_info_t *cityp, int type)
201 {
202         e_set_city_func (cityp, type, RANDOM);
203 }
204
205 /*
206 Put a ship in fill mode.
207 */
208
209 void
210 e_fill(loc_t loc)
211 {
212         if (user_map[loc].contents == 'T' || user_map[loc].contents == 'C')
213                 e_set_func (loc, FILL);
214         else huh ();
215 }
216
217 void
218 e_city_fill(city_info_t *cityp, int type)
219 {
220         if (type == TRANSPORT || type == CARRIER)
221                 e_set_city_func (cityp, type, FILL);
222         else huh ();
223 }
224
225 /*
226 Set a piece to explore.
227 */
228
229 void
230 e_explore(loc_t loc)
231 {
232         e_set_func (loc, EXPLORE);
233 }
234
235 void
236 e_city_explore(city_info_t *cityp, loc_t type)
237 {
238         e_set_city_func (cityp, type, EXPLORE);
239 }
240
241 /*
242 Set a fighter to land.
243 */
244
245 void
246 e_land(loc_t loc)
247 {
248         if (user_map[loc].contents == 'F')
249                 e_set_func (loc, LAND);
250         else huh ();
251 }
252
253 /*
254 Set an army's function to TRANSPORT.
255 */
256
257 void
258 e_transport(loc_t loc)
259 {
260         if (user_map[loc].contents == 'A')
261                 e_set_func (loc, WFTRANSPORT);
262         else huh ();
263 }
264
265 /*
266 Set an army's function to ATTACK.
267 */
268
269 void
270 e_attack(loc_t loc)
271 {
272         if (user_map[loc].contents == 'A')
273                 e_set_func (loc, ARMYATTACK);
274         else huh ();
275 }
276
277 void
278 e_city_attack(city_info_t *cityp, int type)
279 {
280         if (type == ARMY)
281                 e_set_city_func (cityp, type, ARMYATTACK);
282         else huh ();
283 }
284
285 /*
286 Set a ship's function to REPAIR.
287 */
288
289 void
290 e_repair(loc_t loc)
291 {
292         if (strchr ("PDSTBC", user_map[loc].contents))
293                 e_set_func (loc, REPAIR);
294         else huh ();
295 }
296
297 void
298 e_city_repair(city_info_t *cityp, int type)
299 {
300         if (type == ARMY || type == FIGHTER || type == SATELLITE)
301                 huh ();
302         else e_set_city_func (cityp, type, REPAIR);
303 }
304
305 /*
306 Set object to move in a direction.
307 */
308
309 static char dirs[] = "WEDCXZAQ";
310  
311 void
312 e_stasis(loc_t loc)
313 {
314         char e;
315         char *p;
316         
317         if (!isupper (user_map[loc].contents)) huh (); /* no object here */
318         else if (user_map[loc].contents == 'X') huh ();
319         else {
320                 e = get_chx(); /* get a direction */
321                 p = strchr (dirs, e);
322
323                 if (p == NULL) huh ();
324                 else e_set_func (loc, (long)(MOVE_N - (p - dirs)));
325         }
326 }
327
328 void
329 e_city_stasis(city_info_t *cityp, int type)
330 {
331         char e;
332         char *p;
333         
334         e = get_chx(); /* get a direction */
335         p = strchr (dirs, e);
336
337         if (p == NULL) huh ();
338         else e_set_city_func (cityp, type, (long)(MOVE_N - (p - dirs)));
339 }
340
341 /*
342 Wake up anything and everything.
343 */
344
345 void
346 e_wake(loc_t loc)
347 {
348         city_info_t *cityp;
349         piece_info_t *obj;
350         int i;
351
352         cityp = find_city (loc);
353         if (cityp != NULL) {
354                 for (i = 0; i < NUM_OBJECTS; i++)
355                         cityp->func[i] = NOFUNC;
356         }
357         for (obj = map[loc].objp; obj != NULL; obj = obj->loc_link.next)
358                 obj->func = NOFUNC;
359 }
360
361 void
362 e_city_wake(city_info_t *cityp, int type)
363 {
364         e_set_city_func (cityp, type, NOFUNC);
365 }
366
367 /*
368 Set a city's function.  We get the piece type to set, then
369 the function itself.
370 */
371
372 void
373 e_city_func(loc_t *path_start, loc_t loc, int *path_type)
374 {
375         int type;
376         char e;
377         city_info_t *cityp;
378
379         cityp = find_city (loc);
380         if (!cityp || cityp->owner != USER) {
381                 huh ();
382                 return;
383         }
384
385         type = get_piece_name();
386         if (type == NOPIECE) {
387                 huh ();
388                 return;
389         }
390         
391         e = get_chx ();
392         
393         switch (e) {
394         case 'F': /* fill */
395                 e_city_fill (cityp, type);
396                 break;
397         case 'G': /* explore */
398                 e_city_explore (cityp, type);
399                 break;
400         case 'I': /* directional stasis */
401                 e_city_stasis (cityp, type);
402                 break;
403         case 'K': /* turn off function */
404                 e_city_wake (cityp, type);
405                 break;
406         case 'M': /* start move to location */
407                 *path_type = type;
408                 e_move (path_start, loc);
409                 break;
410         case 'R': /* make piece move randomly */
411                 e_city_random (cityp, type);
412                 break;
413         case 'U': /* repair ship */
414                 e_city_repair (cityp, type);
415                 break;
416         case 'Y': /* set army func to attack */
417                 e_city_attack (cityp, type);
418                 break;
419         default: /* bad command? */
420                 huh ();
421                 break;
422         }
423 }
424
425 /*
426 Beginning of move to location.
427 */
428
429 void
430 e_move(loc_t *path_start, loc_t loc)
431 {
432         if (!isupper(user_map[loc].contents)) huh (); /* nothing there? */
433         else if (user_map[loc].contents == 'X') huh (); /* enemy city? */
434         else *path_start = loc;
435 }
436
437 /*
438 End of move to location.
439 */
440
441 void
442 e_end(loc_t *path_start, loc_t loc, int path_type)
443 {
444         city_info_t *cityp;
445         
446         if (*path_start == -1) huh (); /* no path started? */
447         else if (path_type == NOPIECE) e_set_func (*path_start, loc);
448         else {
449                 cityp = find_city (*path_start);
450                 ASSERT (cityp);
451                 e_set_city_func (cityp, path_type, loc);
452         }
453
454         *path_start = -1; /* remember no path in progress */
455 }
456
457 /*
458 Put a piece to sleep.
459 */
460
461 void
462 e_sleep(loc_t loc)
463 {
464         if (user_map[loc].contents == 'O') huh (); /* can't sleep a city */
465         else e_set_func (loc, SENTRY);
466 }
467
468 /*
469 Print out information about a piece.
470 */
471
472 void
473 e_info(loc_t edit_cursor)
474 {
475         void e_city_info(loc_t), e_piece_info(loc_t edit_cursor, char ab);
476
477         char ab;
478
479         ab = user_map[edit_cursor].contents;
480
481         if (ab == 'O') e_city_info (edit_cursor);
482         else if (ab == 'X' && debug) e_city_info (edit_cursor);
483         else if ((ab >= 'A') && (ab <= 'T'))
484                 e_piece_info (edit_cursor, ab);
485         else if ((ab >= 'a') && (ab <= 't') && (debug))
486                 e_piece_info (edit_cursor, ab);
487         else huh ();
488 }
489
490 /*
491 Print info about a piece.
492 */
493
494 void
495 e_piece_info(loc_t edit_cursor, char ab)
496 {
497         piece_info_t *obj;
498         int type;
499         char *p;
500
501         ab = upper (ab);
502         p = strchr (type_chars, ab);
503         type = p - type_chars;
504
505         obj = find_obj (type, edit_cursor);
506         ASSERT (obj != NULL);
507         describe_obj (obj);
508 }
509
510 /*
511 Display info on a city.
512 */
513
514 void
515 e_city_info(loc_t edit_cursor)
516 {
517         piece_info_t *obj;
518         city_info_t *cityp;
519         int f, s;
520         char func_buf[STRSIZE];
521         char temp_buf[STRSIZE];
522         char junk_buf2[STRSIZE];
523
524         error (0,0,0,0,0,0,0,0,0); /* clear line */
525
526         f = 0; /* no fighters counted yet */
527         for (obj = map[edit_cursor].objp; obj != NULL;
528                 obj = obj->loc_link.next)
529                         if (obj->type == FIGHTER) f++;
530
531         s = 0; /* no ships counted yet */
532         for (obj = map[edit_cursor].objp; obj != NULL;
533                 obj = obj->loc_link.next)
534                         if (obj->type >= DESTROYER) s++;
535
536         if (f == 1 && s == 1) 
537                 (void) sprintf (jnkbuf, "1 fighter landed, 1 ship docked");
538         else if (f == 1)
539                 (void) sprintf (jnkbuf, "1 fighter landed, %d ships docked", s);
540         else if (s == 1)
541                 (void) sprintf (jnkbuf, "%d fighters landed, 1 ship docked", f);
542         else (void) sprintf (jnkbuf, "%d fighters landed, %d ships docked", f, s);
543
544         cityp = find_city (edit_cursor);
545         ASSERT (cityp != NULL);
546
547         *func_buf = 0; /* nothing in buffer */
548         for (s = 0; s < NUM_OBJECTS; s++) { /* for each piece */
549                 if (cityp->func[s] < 0)
550                         (void) sprintf (temp_buf, "%c:%s; ",
551                                 piece_attr[s].sname,
552                                 func_name[FUNCI(cityp->func[s])]);
553                 else (void) sprintf (temp_buf, "%c: %d;",
554                                 piece_attr[s].sname,
555                                 loc_disp(cityp->func[s]));
556                 
557                 (void) strcat (func_buf, temp_buf);
558         }
559
560         (void) sprintf (junk_buf2,
561                 "City at location %d will complete %s on round %ld",
562                 loc_disp(cityp->loc),
563                 piece_attr[(int)cityp->prod].article,
564                 date + piece_attr[(int)cityp->prod].build_time - cityp->work);
565
566         info (junk_buf2, jnkbuf, func_buf);
567 }
568
569 /*
570 Change city production.
571 */
572
573 void
574 e_prod(loc_t loc)
575 {
576         city_info_t *cityp;
577         
578         cityp = find_city (loc);
579
580         if (cityp == NULL) huh (); /* no city? */
581         else set_prod (cityp);
582 }
583
584 /*
585 get help
586 */
587
588 void
589 e_help(void) {
590         help (help_edit, edit_lines);
591         prompt ("Press any key to continue: ",0,0,0,0,0,0,0,0);
592         (void) get_chx ();
593 }