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