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 | }