1    | 
2    | /*
3    |  * $Log: ma_build.c,v $
4    |  * Revision 1.14  2004/05/09 19:44:17  millis
5    |  * Fix Bug 303 (crash in build results output)
6    |  *
7    |  * Revision 1.13  2004/05/09 19:02:45  millis
8    |  * Fixed bug 302 (prevent armies being built in Mach2 in Venice)
9    |  *
10   |  * Revision 1.12  2003/10/26 18:39:11  millis
11   |  * Refix bug 224
12   |  *
13   |  * Revision 1.11  2003/09/13 22:59:28  millis
14   |  * Fix bug 224
15   |  *
16   |  * Revision 1.10  2003/05/10 00:46:15  millis
17   |  * Bug 140 fix, display 'orders' when orders and 'results' when results
18   |  *
19   |  * Revision 1.9  2003/05/03 23:33:49  millis
20   |  * Fix bug 150 (NO_GARRISONS flag)
21   |  *
22   |  * Revision 1.8  2003/01/13 18:16:11  millis
23   |  * Merged from ustv
24   |  *
25   |  * Revision 1.7  2003/01/05 11:18:10  millis
26   |  * Fixed bug 87
27   |  *
28   |  * Revision 1.6  2002/10/19 21:39:15  millis
29   |  * Fixed Bug 21: Mach2 games allowing Armies in Venice
30   |  *
31   |  * Revision 1.5  2002/05/31 12:38:28  millis
32   |  * Correct problem not allowing builds in Venice to change mind
33   |  * Also allow first turn to have an over-spend (needed for scenarios)
34   |  *
35   |  * Revision 1.4  2002/02/25 11:51:51  miller
36   |  * Various updates for Machiavelli bug fixes
37   |  *
38   |  * Revision 1.2.2.1  2001/10/19 23:34:03  dema
39   |  * Added missed include
40   |  *
41   |  * Revision 1.2  2001/07/01 23:19:29  miller
42   |  * Unit type limits and predict
43   |  *
44   |  * Revision 1.1  1998/02/28 17:49:42  david
45   |  * Initial revision
46   |  *
47   |  * Revision 1.1  1996/10/20 12:29:45  rpaar
48   |  * Morrolan v9.0
49   |  */
50   | 
51   | #include <stdlib.h>
52   | #include <string.h>
53   | 
54   | #include "dip.h"
55   | #include "porder.h"
56   | #include "mach.h"
57   | #include "functions.h"
58   | 
59   | /*
60   |  *  Process lines of the form:
61   |  *
62   |  *    cmd   ::= <power>: {<order>} <type> <province>
63   |  *    order ::= build | remove | maintain
64   |  *    type  ::= Army | Fleet | Garrison
65   |  */
66   | 
67   | int ma_buildin(char **s, int p)
68   | {
69   | 	char type, stype, order;
70   | 	unsigned char *t;
71   | 	int u, u1, p1, c1;
72   | 
73   | 	*s = get_order(*s, &order);
74   | 	*s = get_stype(*s, &stype);
75   | 	*s = get_type(*s, &type);
76   | 	*s = get_prov(*s, &p1, &c1);
77   | 
78   | 	if (!p1) {
79   | 		errmsg("Unrecognized province -> %s", *s);
80   | 		return E_WARN;
81   | 	}
82   | 	if (p == MASTER) {
83   | 		if (pr[p1].unit) {
84   | 			p = unit[pr[p1].unit].owner;
85   | 		} else {
86   | 			p = pr[p1].home;
87   | 		}
88   | 	}
89   | 	if (order == 'x')
90   | 		order = 'm';
91   | 
92   | 	switch (order) {
93   | 	case 'b':
94   | 		if (pr[p1].home != p) {
95   | 			errmsg("%s is not a home province for %s.\n",
96   | 			       pr[p1].name, powers[p]);
97   | 			return E_WARN;
98   | 		}
99   | 		if (!cityvalue(p1)) {
100  | 			errmsg("%s does not contain a city.\n", pr[p1].name);
101  | 			return E_WARN;
102  | 		}
103  | 		if (pr[p1].owner != p) {
104  | 			errmsg("%s does not control %s.\n", powers[p], pr[p1].name);
105  | 			return E_WARN;
106  | 		}
107  | 		if (is_infected(p1)) {
108  | 			errmsg("You cannot build in a famined province.\n");
109  | 			return E_WARN;
110  | 		}
111  | 		if (has_rebellion(p1)) {
112  | 			errmsg("You cannot build while a rebellion is in a province.\n");
113  | 			return E_WARN;
114  | 		}
115  | 		if (type == 'A') {
116  | 			c1 = MV;
117  | 			if (is_venice(p1) && dipent.xflags & XF_MACH2) {
118  | 			        errmsg("Armies not allowed in %s.\n", pr[p1].name);
119  | 				return E_WARN;
120  | 			}
121  | 
122  | 		} else if (type == 'F') {
123  | 			if (!has_port(p1)) {
124  | 				errmsg("Cannot build a fleet in %s which isn't a port.\n",
125  | 				       pr[p1].name);
126  | 				return E_WARN;
127  | 			}
128  | 			if (!c1)
129  | 				c1 = XC;
130  | 			for (t = (char *) pr[p1].move; *t; t++)
131  | 				if (*++t >> 4 == c1)
132  | 					break;
133  | 			if (!*t) {
134  | 				errmsg("Invalid coast specified for fleet in %s.\n", pr[p1].name);
135  | 				return E_WARN;
136  | 			}
137  | 		} else if (type == 'G') {
138  | 			if (dipent.x2flags & X2F_NOGARRISONS) {
139  | 			        errmsg("This game does not allow garrisons.\n");
140  | 				return E_WARN;
141  | 			}
142  | 			if (!has_fortcity(p1)) {
143  | 				errmsg("Cannot build a garrison in %s which isn't fortified.\n",
144  | 				       pr[p1].name);
145  | 				return E_WARN;
146  | 			}
147  | 			c1 = MV;
148  | 		} else {
149  | 			errmsg("Unit type must be specified for build.\n");
150  | 			return E_WARN;
151  | 		}
152  | 		
153  | 		if ((u = pr[p1].unit)) {
154  | 			if (unit[u].status == 'b' || unit[u].status == 'x') {
155  | 				unit[u].status = 'x';
156  | 				unit[u].owner = 0;
157  | 			} else if (type != 'G') {
158  | 				errmsg("Cannot debuild and build in %s.\n", pr[p1].name);
159  | 				return E_WARN;
160  | 			}
161  | 		}
162  | 		if ((u = pr[p1].gunit)) {
163  | 			if (unit[u].status == 'b' || unit[u].status == 'x') {
164  | 				unit[u].status = 'x';
165  | 				unit[u].owner = 0;
166  | 			} else if (type == 'G') {
167  | 				errmsg("Cannot debuild and build in %s.\n", pr[p1].name);
168  | 				return E_WARN;
169  | 			}
170  | 		}
171  | 
172  |                 /* If Venice, only allow one unit to exist at a time */
173  |                 if (is_venice(p1)) {
174  |                         if ((pr[p1].unit && unit[pr[p1].unit].status != 'b' && unit[pr[p1].unit].status != 'x') ||
175  |                             (pr[p1].gunit && unit[pr[p1].gunit].status != 'b' && unit[pr[p1].gunit].status != 'x' )) {
176  |                             errmsg("Cannot order for more than one unit in %s.\n", pr[p1].name);
177  |                             return E_WARN;
178  |                         }
179  |                 }
180  | 
181  | 		if (stype != 'x') {
182  | 			if (NO_SPECIAL_UNITS) {
183  | 				errmsg("Game %s does not allow special units.\n", dipent.name);
184  | 				return E_WARN;
185  | 			}
186  | 			for (u1 = 1; u1 <= nunit; u1++) {
187  | 				if (unit[u1].status != 'd' &&
188  | 				    unit[u1].owner == p && unit[u1].stype != 'x') {
189  | 					errmsg("You already have %s %s in %s.\n",
190  | 					       astype(unit[u1].stype, unit[u1].type),
191  | 					       utype(unit[u1].type),
192  | 					       pr[unit[u1].loc].name);
193  | 					errmsg("Only one special unit allowed per major power.\n");
194  | 					return E_WARN;
195  | 				}
196  | 			}
197  | 		}
198  |                 /* MLM 19/6/2001 OK, see if unit is allowed */
199  | 		if (!PermittedMachUnit(p,type,stype, PP_BUILD)) {
200  | 		    errmsg("Power is not allowed to build this unit type.\n");
201  | 		    return E_WARN;
202  | 		}
203  | 		
204  | 		for (u = 1; u <= nunit; u++) {
205  | 			if (unit[u].status == 'x') {
206  | 				if (is_garrison(u)) {
207  | 					pr[unit[u].loc].gunit = 0;
208  | 				} else {
209  | 					pr[unit[u].loc].unit = 0;
210  | 				}
211  | 				break;
212  | 			}
213  | 		}
214  | 
215  | 		if (u > nunit)
216  | 			u = ++nunit;
217  | 
218  | 		if (type == 'G')
219  | 			pr[p1].gunit = u;
220  | 		else
221  | 			pr[p1].unit = u;
222  | 		unit[u].owner = p;
223  | 		unit[u].type = type;
224  | 		unit[u].stype = stype;
225  | 		unit[u].loc = p1;
226  | 		unit[u].coast = c1;
227  | 		unit[u].status = 'b';
228  | 		break;
229  | 
230  | 
231  | 	case 'r':
232  | 		if ((!((u = pr[p1].unit) &&
233  | 		       type != 'G') &&
234  | 		     !((u = pr[p1].gunit) &&
235  | 		       (type == 'G' || type == 'x'))) ||
236  | 		    unit[u].owner != p) {
237  | 			errmsg("%s does not own a unit in %s%s to remove.\n",
238  | 			powers[p], water(p1) ? "the " : "", pr[p1].name);
239  | 			return E_WARN;
240  | 		}
241  | 		if (((is_garrison(u) && (u1 = pr[p1].unit)) ||
242  | 		     (is_garrison(u) && (u1 = pr[p1].gunit))) &&
243  | 		    unit[u1].status == 'b' && unit[u1].owner == p) {
244  | 			errmsg("You cannot build and debuild in %s.\n", pr[p1].name);
245  | 			return E_WARN;
246  | 		}
247  | 		if (unit[u].status == 'b') {
248  | 			unit[u].status = 'x';
249  | 			unit[u].owner = 0;
250  | 		} else {
251  | 			unit[u].status = 'd';
252  | 		}
253  | 		break;
254  | 
255  | 	case 'm':
256  | 		if ((!((u = pr[p1].unit) &&
257  | 		       type != 'G') &&
258  | 		!((u = pr[p1].gunit) && (type == 'G' || type == 'x'))) ||
259  | 		    unit[u].owner != p) {
260  | 			errmsg("%s does not own a unit in %s%s to maintain.\n",
261  | 			powers[p], water(p1) ? "the " : "", pr[p1].name);
262  | 			return E_WARN;
263  | 		}
264  | 		if (unit[u].status == 'd' && unit[u].stype != 'x') {
265  | 			for (u1 = 1; u1 <= nunit; u1++) {
266  | 				if (unit[u1].owner == p &&
267  | 				    unit[u1].status != 'd' &&
268  | 				    unit[u1].stype != 'x') {
269  | 					errmsg("You already have %s %s in %s.\n",
270  | 					       astype(unit[u1].stype, unit[u1].type),
271  | 					       utype(unit[u1].type),
272  | 					       pr[unit[u1].loc].name);
273  | 					errmsg("Only one special unit allowed per major power.\n");
274  | 					return E_WARN;
275  | 				}
276  | 			}
277  | 		}
278  | 		unit[u].status = 'm';
279  | 		break;
280  | 
281  | 	case 'w':
282  | 		errmsg("Waive ignored for Machiavelli variant.\n");
283  | 		break;
284  | 
285  | 	default:
286  | 		fprintf(rfp, "Invalid build order encountered (internal error).\n");
287  | 		err++;
288  | 		return E_WARN;
289  | 	}
290  | 	return 0;
291  | }
292  | 
293  | void ma_buildout(int pt)
294  | {
295  | 	int n, u, p, i, c1;
296  | 	char mastrpt_pr[NPOWER+1];
297  | 
298  | 	if (err)
299  | 		fputc('\n', rfp);
300  | 	fprintf(rfp, "Adjustment %s for Winter of %d.  (%s.%s)\n",
301  | 		 pt ? "orders" : "results",
302  | 		atoi(&dipent.phase[1]), dipent.name, dipent.seq);
303  | 
304  | 	n = (int) strlen(powers[AUTONOMOUS]);
305  | 
306  | 	fprintf(rfp, "\n");
307  | 	if (pt == MASTER) {
308  | 		for (u = 0; u < NPOWER+1; u++)
309  | 			mastrpt_pr[u] = 0;
310  | 		for (u = 1; u <= nunit; u++) {
311  | 			if (unit[u].owner <= 0)
312  | 				continue;
313  | 			if (mastrpt_pr[unit[u].owner] != 1) {
314  | 				mastrpt_pr[unit[u].owner] = 1;
315  | 				mast_rpt(unit[u].owner, 1);
316  | 			};
317  | 		};
318  | 		fprintf(rfp, "\n");
319  | 	};
320  | 	for (p = 0, u = 1; u <= nunit; u++) {
321  | 		if (processing || pt == unit[u].owner || pt == MASTER) {
322  | 
323  | 			if (p != unit[u].owner) {
324  | 				fputc('\n', rfp);
325  | 				p = unit[u].owner;
326  | 			}
327  | 			if (p == AUTONOMOUS) {
328  | 				unit[u].status = 'm';
329  | 			}
330  | 			if (unit[u].status == 'b' || unit[u].status == 'm') {
331  | 
332  | 				fprintf(rfp, "%s: ", powers[p = unit[u].owner]);
333  | 				for (i = strlen(powers[p]); i < n; i++)
334  | 					putc(' ', rfp);
335  | 
336  | 				if (unit[u].status == 'b') {
337  | 					fprintf(rfp, "Builds %s %s in %s.", astype(unit[u].stype, unit[u].type),
338  | 						utype(unit[u].type),
339  | 						pr[unit[u].loc].name);
340  | 				} else {
341  | 					fprintf(rfp, "Maintains the %s%s in %s.", bstype(unit[u].stype),
342  | 						utype(unit[u].type),
343  | 						pr[unit[u].loc].name);
344  | 				}
345  | 
346  | 				if ((c1 = unit[u].coast) > XC)
347  | 					fprintf(rfp, " (%s)", mtype[c1]);
348  | 
349  | 				c1 = unit[u].stype == 'x' ? 3 : unit[u].stype == 'p' ? 9 : 6;
350  | 				if (ducats[p].treasury >= c1) {
351  | 					fprintf(rfp, "  (%d ducats)\n", c1);
352  | 					ducats[p].treasury -= c1;
353  | 				} else if (unit[u].owner == AUTONOMOUS) {
354  | 					fprintf(rfp, "  (free)\n");
355  | 				} else if (atoi(dipent.seq) <= 2) {
356  | 				       /* First turn, allow overspend */
357  | 					fprintf(rfp, "  (%d ducats)\n", c1);
358  |                                         ducats[p].treasury = 0;  
359  | 				} else {
360  | 					fprintf(rfp, "  (%d ducats *** NSF)\n", c1);
361  | 					unit[u].owner = 0;
362  | 					if (!processing && pt != MASTER) {
363  | 						more_orders++;
364  | 						err++;
365  | 					}
366  | 				}
367  | 				unit[u].status = ':';
368  | 
369  | 			} else if (unit[u].status == 'd') {
370  | 
371  | 				fprintf(rfp, "%s: ", powers[p = unit[u].owner]);
372  | 				for (i = strlen(powers[p]); i < n; i++)
373  | 					putc(' ', rfp);
374  | 				fprintf(rfp, "Removes the %s in %s%s",
375  | 					utype(unit[u].type),
376  | 					water(unit[u].loc) ? "the " : "",
377  | 					pr[unit[u].loc].name);
378  | 
379  | 				if ((processing || predict) && is_sieged(unit[u].loc)) {
380  | 					remove_siege(unit[u].loc);
381  | 					fprintf(rfp, " (siege lifted).\n");
382  | 				} else {
383  | 					fprintf(rfp, ".\n");
384  | 				}
385  | 
386  | 				unit[u].owner = 0;
387  | 				unit[u].status = ':';
388  | 
389  | 			} else if (unit[u].status == ':') {
390  | 
391  | 				fprintf(rfp, "%s: ", powers[p = unit[u].owner]);
392  | 				for (i = strlen(powers[p]); i < n; i++)
393  | 					putc(' ', rfp);
394  | 				fprintf(rfp, "%s %s", Utype(unit[u].type), pr[unit[u].loc].name);
395  | 				if (!processing && !predict ) {
396  | 					fprintf(rfp, " *** No order received, maintain or remove");
397  | 					if (pt != MASTER) {
398  | 					    more_orders++;
399  | 					    err++;
400  | 					}
401  | 				} else {
402  | 					fprintf(rfp, " *** No order received, removed");
403  | 				}
404  | 
405  | 				fprintf(rfp, ".\n");
406  | 
407  | 				unit[u].owner = 0;
408  | 
409  | 			}
410  | 		}
411  | 	}
412  | }