1    | /*
2    |  * $Log: ma_movement.c,v $
3    |  * Revision 1.28  2004/12/28 10:04:40  millis
4    |  * Fixed Bug 393 (Mach2 siege break failed)
5    |  *
6    |  * Revision 1.27  2004/10/23 21:08:59  millis
7    |  * Fix Bug 375, Mach2 allow besieged to dislodge
8    |  *
9    |  * Revision 1.26  2004/05/22 08:58:22  millis
10   |  * Bug 297: Add Intimate Diplomacy
11   |  *
12   |  * Revision 1.25  2003/12/07 00:04:04  millis
13   |  * Fix Bug 249, so that disbanding garrisons prevent setting siege state
14   |  *
15   |  * Revision 1.24  2003/10/08 12:28:08  millis
16   |  * Fix bug 236
17   |  *
18   |  * Revision 1.23  2003/09/14 08:25:13  millis
19   |  * Fix bug 225
20   |  *
21   |  * Revision 1.22  2003/08/09 23:05:52  millis
22   |  * Fixed bug 213
23   |  *
24   |  * Revision 1.21  2003/07/23 22:42:41  millis
25   |  * Fix bug 172
26   |  *
27   |  * Revision 1.20  2003/07/20 15:45:28  millis
28   |  * Bug 195 fix
29   |  *
30   |  * Revision 1.19  2003/05/16 21:13:42  millis
31   |  * Bug 155 fix, moved Bug 126 fix to end (as otherwise, does not know of where units were).
32   |  *
33   |  * Revision 1.18  2003/05/10 00:22:39  millis
34   |  * Fix bug 126, not always correctly registering province ownership changes
35   |  *
36   |  * Revision 1.17  2003/05/03 23:33:49  millis
37   |  * Fix bug 150 (NO_GARRISONS flag)
38   |  *
39   |  * Revision 1.16  2003/01/13 18:19:41  millis
40   |  * Merge from ustv
41   |  *
42   |  * Revision 1.15  2002/12/28 21:25:25  millis
43   |  * Fixed typo
44   |  *
45   |  * Revision 1.14  2002/12/28 00:11:36  millis
46   |  * Fixed bug 2, so that disbands can happen even if under siege
47   |  *
48   |  * Revision 1.13  2002/12/23 01:43:31  millis
49   |  * Really fixed Bug 69 (incorrect change)
50   |  *
51   |  * Revision 1.12  2002/12/22 02:13:25  millis
52   |  * Fixed bugs 54, 67 & 69
53   |  *
54   |  * Revision 1.11  2002/12/04 23:33:14  millis
55   |  * Fixed Bug 47 (incorrect ownership change for proxied orders)
56   |  *
57   |  * Revision 1.10  2002/11/13 22:30:33  millis
58   |  * Bug 30, correctly calculate support on assasination
59   |  *
60   |  * Revision 1.9  2002/10/19 21:39:16  millis
61   |  * Fixed Bug 21: Mach2 games allowing Armies in Venice
62   |  *
63   |  * Revision 1.8  2002/05/14 23:05:49  miller
64   |  * Allow signalling convoys in Mach2 games
65   |  *
66   |  * Revision 1.7  2002/04/22 21:27:40  miller
67   |  * Small bug that allowed illegal converts
68   |  *
69   |  * Revision 1.6  2002/03/05 23:19:49  miller
70   |  * Fix special bleagured garisson bug
71   |  *
72   |  * Revision 1.3.2.1  2001/10/19 23:37:01  dema
73   |  * Added NoMoney handling, and correct calculatinos for lifting sieges
74   |  *
75   |  * Revision 1.3  2001/07/08 22:58:24  miller
76   |  * Preliminary check for XF_NOMENY
77   |  *
78   |  * Revision 1.2  2001/07/01 23:19:29  miller
79   |  * Many fixes
80   |  *
81   |  * Revision 1.1  1998/02/28 17:49:42  david
82   |  * Initial revision
83   |  *
84   |  * Revision 1.1  1996/10/20 12:29:45  rpaar
85   |  * Morrolan v9.0
86   |  */
87   | 
88   | /*  po_movechk.c
89   |  *  Copyright 1987, Lowe.
90   |  *
91   |  *  Diplomacy is a trademark of the Avalon Hill Game Company, Baltimore,
92   |  *  Maryland, all rights reserved; used with permission.
93   |  *
94   |  *  Redistribution and use in source and binary forms are permitted
95   |  *  provided that it is for non-profit purposes, that this and the
96   |  *  above notices are preserved and that due credit is given to Mr.
97   |  *  Lowe.
98   |  */
99   | 
100  | #include <stdlib.h>
101  | #include <string.h>
102  | 
103  | #include "dip.h"
104  | #include "porder.h"
105  | #include "mach.h"
106  | #include "functions.h"
107  | 
108  | #define convoyable(p) (water(p) | (dipent.xflags & XF_COASTAL_CONVOYS))
109  | 
110  | static int result[MAXUNIT];
111  | static int support[MAXUNIT];
112  | static int supportvalue[MAXUNIT];
113  | 
114  | 
115  | /*
116  |  * Input processing of the regular movement orders
117  |  */
118  | int ma_movein(char **s, int p)
119  | {
120  | 	/* char **s; Input stream */
121  | 	/* int p; Power specification */
122  | 
123  | 	char c, order;
124  | 	unsigned char *t;
125  | 	char target_type;
126  | 	char cc; /* MLM 12/06/2001 remember unit type for convert order */
127  | 	int i, j, p1, p2, u, u1, u2, c1, c2, bl;
128  | 	unsigned char *bp;
129  | 
130  | /*  Process lines of the form:
131  | 
132  |  *    cmd ::= <power>: <move list>
133  |  *    move list ::= <move>{; <move list>}
134  |  *    move ::= <type> <province> - <province>
135  |  *      | <type> <province> holds
136  |  *      | <type> <province> support {<power>:} <type> <province> {-<province>}
137  |  *      | <type> <province> convoy  {<power>:} <type> <province> {-<province>}
138  |  *    type ::= Army | Fleet
139  |  */
140  | 
141  | 	*s = get_type(*s, &c);
142  | 	*s = get_prov(*s, &p1, &c1);
143  | 	if (!p1) {
144  | 		errmsg("Unrecognized source province -> %s", *s);
145  | 		return E_WARN;
146  | 	}
147  | 	u1 = pr[p1].unit;
148  | 	u2 = pr[p1].gunit;
149  | 
150  | 	u = c == 'G' ? u2 :
151  | 	    c != 'x' ? u1 :
152  | 	    u1 && unit[u1].owner == p ? u1 :
153  | 	    u2 && unit[u2].owner == p ? u2 :
154  | 	    u1 ? u1 : u2;
155  | 
156  | 	if (!u) {
157  | 		errmsg("No %s present %s %s.\n", utype(c),
158  | 		       water(p1) ? "in the" : "in", pr[p1].name);
159  | 		return E_WARN;
160  | 	}
161  | 	if (p != unit[u].owner && p != MASTER) {
162  | 		for (u2 = 1; u2 <= nunit; u2++) {
163  | 			if (unit[u2].owner == p && unit[u2].proxy == u)
164  | 				break;
165  | 		}
166  | 		if (u2 > nunit) {
167  | 			if (nunit > MAXUNIT - 2) {
168  | 				fprintf(rfp, "Too many units in %s.\n", dipent.name);
169  | 				fprintf(log_fp, "Too many units in %s.\n", dipent.name);
170  | 				bailout(1);
171  | 			}
172  | 			++nunit;
173  | 		}
174  | 		memcpy(&unit[u2], &unit[u], sizeof(unit[0]));
175  | 		if (u2 == nunit)
176  |                 	unit[nunit].exists = 0; /* Unit does not yet exist */
177  | 		unit[u2].owner = p;
178  | 		unit[u2].proxy = u;
179  | 		unit[u2].order = 'n';
180  | 		u = u2;
181  | 	}
182  | 	if (c != 'x' && c != unit[u].type) {
183  | 		errmsg("The unit %s %s is %s, not %s.\n",
184  | 		       water(p1) ? "in the" : "in", pr[p1].name,
185  | 		       autype(unit[u].type), autype(c));
186  | 		return E_WARN;
187  | 	}
188  | 	p2 = unit[u].loc;
189  | 	c2 = unit[u].coast;
190  | 	u2 = 0;
191  | 	bp = NULL;
192  | 	bl = 0;
193  | 
194  | 	*s = get_action(*s, &order);
195  | 	switch (order) {
196  | 
197  | 	case 'b':		/* besiege */
198  | 		if (unit[u].type == 'G') {
199  | 			errmsg("Invalid order for garrison.\n");
200  | 			return E_WARN;
201  | 		}
202  | 		if (!has_fortress(p1)) {
203  | 			errmsg("%s has no fortress to siege.\n", pr[p1].name);
204  | 			return E_WARN;
205  | 		}
206  | 		if (unit[u].type == 'F' && !has_port(p1)) {
207  | 			errmsg("A fleet can only besiege ports.\n");
208  | 			return E_WARN;
209  | 		}
210  | 		if (!has_crebellion(p1) && pr[p1].gunit == 0) {
211  | 			errmsg("%s has no garrison or rebellion to siege.\n", pr[p1].name);
212  | 			return E_WARN;
213  | 		}
214  | 		*s = get_type(*s, &c);
215  | 		if (!strncasecmp(*s, "rebellion", 9))
216  | 			*s += 9;
217  | 		break;
218  | 
219  | 	case 'd':
220  |                 if (!(dipent.xflags & XF_MOVEDISBAND)) {
221  |                     errmsg("This game does not allow disband orders in movement phases.");
222  |                     return E_WARN;
223  |                 }
224  |                 break;
225  | 
226  | 	case 'c':
227  | 	case 's':
228  | 		*s = get_type(*s, &c);
229  | 		target_type = c;  /* Remember type of unit being convoyed/supported */
230  | 		*s = get_prov(*s, &p2, &c2);
231  | 		if (!p2) {
232  | 			errmsg("Unrecognized source province for support/convoy -> %s", *s);
233  | 			return E_WARN;
234  | 		}
235  | 		if (c == 'G') {
236  | 			u2 = has_garrison(p2);
237  | 			if (!u2) {
238  | 				errmsg("No garrison present %s %s.\n",
239  | 				water(p2) ? "in the" : "in", pr[p2].name);
240  | 				return E_WARN;
241  | 			}
242  | 		} else {
243  | 			u2 = pr[p2].unit;
244  | 			if (!u2) {
245  | 				errmsg("No unit present %s %s.\n",
246  | 				water(p2) ? "in the" : "in", pr[p2].name);
247  | 				return E_WARN;
248  | 			}
249  | 		}
250  | 
251  | 		if (order == 'c' && unit[u2].type != 'A') {
252  | 			if (is_garrison(u))
253  | 				errmsg("Invalid order for garrison.\n");
254  | 			else
255  | 				errmsg("The convoy order should specify source %s\n",
256  | 				    "and final destination of an army.");
257  | 			return E_WARN;
258  | 		}
259  | 		if (c != 'x' && c != unit[u2].type) {
260  | 			errmsg("The unit %s %s is %s, not %s.\n",
261  | 			       water(p2) ? "in the" : "in", pr[p2].name,
262  | 			       autype(unit[u2].type), autype(c));
263  | 			return E_WARN;
264  | 		}
265  | 		t = get_action(*s, &c);
266  | 
267  | 		if (c == 'm') {
268  | 			*s = get_prov(t, &p2, &c2);
269  | 			if (!p2) {
270  | 				errmsg("Support/convoy movement to unrecognized province -> %s",
271  | 				       *s);
272  | 				return E_WARN;
273  | 			}
274  | 			if (pr[p2].flags & PF_VENICE && 
275  | 			    dipent.xflags & XF_MACH2 &&
276  | 			    target_type == 'A') {
277  | 				errmsg("Armies not allowed in %s.\n", *s);
278  | 				return E_WARN;
279  | 			}
280  | 		}
281  | 		if (order == 's' && c == 'v') {
282  | 			if (!is_garrison(u2)) {
283  | 				errmsg("Can only support conversions from Garrison.\n");
284  | 				return E_WARN;
285  | 			}
286  | 			*s = get_type(t, &c);
287  | 		}
288  | 		if (order == 'c' && unit[u].type != 'F') {
289  | 			errmsg("The %s in %s can't convoy anything!!\n",
290  | 			       utype(unit[u].type), pr[p1].name);
291  | 			return E_WARN;
292  | 		}
293  | 		if (order == 'c' && water(p2)) {
294  | 			errmsg("The convoy order should specify source %s\n",
295  | 			       "and final destination of an army.");
296  | 			return E_WARN;
297  | 		}
298  | 
299  | 		c1 = 0;
300  | 		if (order == 's' &&
301  | 		    ((is_garrison(u) && p1 != p2) ||
302  | 		     (!is_garrison(u) && (!valid_move(u, p2, &c1, &bl)
303  | 					  || c1 == MX)))) {
304  | 			errmsg("The %s %s %s can't get to %s%s to support.\n",
305  | 			       utype(unit[u].type),
306  | 			       water(p1) ? "in the" : "in", pr[p1].name,
307  | 			       water(p2) ? "the " : "", pr[p2].name);
308  | 			return E_WARN;
309  | 		}
310  | 		if (dipent.phase[0] == 'F' && pr[p1].type == 'v') {
311  | 			errmsg("Invalid order for fall in the %s.\n", pr[p1].name);
312  | 			return E_WARN;
313  | 		}
314  | 		if (dipent.phase[0] == 'F' && pr[p2].type == 'v') {
315  | 			errmsg("Invalid order for fall in the %s.\n", pr[p2].name);
316  | 			return E_WARN;
317  | 		}
318  | 		if (!c2 && unit[u2].type == 'F')
319  | 			valid_move(u2, p2, &c2, &i);	/* set c2 */
320  | 		break;
321  | 
322  | 
323  | 	case 'h':
324  | 	case 'n':
325  | 		break;
326  | 
327  | 
328  | 	case 'l':		/* lift siege */
329  | 		if (is_garrison(u)) {
330  | 			errmsg("Invalid order for garrison.\n");
331  | 			return E_WARN;
332  | 		}
333  | 		if (!is_sieged(p1)) {
334  | 			errmsg("No siege in progress in %s.\n", pr[p1].name);
335  | 			return E_WARN;
336  | 		}
337  | 		if (dipent.xflags & XF_NOLIFT_SIEGE) {
338  | 			errmsg("No need: any non-besiege order will lift siege in this game.\n");
339  | 			return E_WARN;
340  | 		}
341  | 		break;
342  | 
343  | 
344  | 	case 'm':
345  | 		if (is_garrison(u)) {
346  | 			errmsg("Invalid order for garrison.\n");
347  | 			return E_WARN;
348  | 		}
349  | 		*s = get_prov(*s, &p2, &c2);
350  | 		if (!p2) {
351  | 			errmsg("Movement from %s%s to unrecognized province -> %s",
352  | 			       water(p1) ? "the " : "", pr[p1].name, *s);
353  | 			return E_WARN;
354  | 		}
355  | 		if (pr[p2].flags & PF_VENICE && unit[u].type == 'A' &&
356  | 		    dipent.xflags & XF_MACH2)
357  | 		{
358  | 			errmsg("Armies not allowed in %s.\n", *s);
359  | 			return E_WARN;
360  | 		}
361  | 		t = get_action(*s, &c);
362  | 
363  | 		if (c == 'm') {
364  | 			if (unit[u].type == 'A') {
365  | 				i = nunit + 1;
366  | 				unit[i].loc = unit[u].loc;
367  | 				unit[i].coast = XC;
368  | 				bp = &heap[hp];
369  | 				while (c == 'm') {
370  | 					if (!valid_move(i, p2, &c2, &j) ||
371  | 					    !convoyable(p2) ||
372  | 					    (!(u2 = pr[p2].unit) || unit[u2].type != 'F') ||
373  | 					    (pr[p2].flags & PF_VENICE && dipent.xflags & XF_MACH2)) {
374  | 						errmsg("The army in %s can't convoy through %s%s.\n",
375  | 						       pr[p1].name, water(p2) ? "the " : "", pr[p2].name);
376  | 						return E_WARN;
377  | 					}
378  | 					if (j && !bl)
379  | 						bl = j;
380  | 
381  | 					heap[hp++] = pr[p2].unit;
382  | 					unit[i].loc = p2;
383  | 
384  | 					*s = get_prov(t, &p2, &c2);
385  | 					if (!p2) {
386  | 						errmsg("Movement from %s%s to unrecognized province -> %s",
387  | 						       water(p1) ? "the " : "", pr[p1].name, *s);
388  | 						return E_WARN;
389  | 					}
390  | 					t = get_action(*s, &c);
391  | 				}
392  | 
393  | 				if (!valid_move(i, p2, &c2, &j)) {
394  | 					errmsg("The army in %s can't convoy from %s to %s.\n",
395  | 					       pr[p1].name, pr[unit[i].loc].name, pr[p2].name);
396  | 					return E_WARN;
397  | 				}
398  | 				if (water(p2)) {
399  | 					errmsg("The army in %s can't convoy into the %s.\n",
400  | 					       pr[p1].name, pr[p2].name);
401  | 					return E_WARN;
402  | 				}
403  | 				heap[hp++] = 0;
404  | 				c2 = MV;
405  | 
406  | 			} else {
407  | 				errmsg("Invalid order syntax for the fleet in %s%s.\n",
408  | 				   water(p1) ? "the " : "", pr[p1].name);
409  | 				return E_WARN;
410  | 			}
411  | 		} else {
412  | 			if (!valid_move(u, p2, &c2, &bl)) {
413  | 				errmsg("The %s %s %s can't get to %s%s.\n", utype(unit[u].type),
414  | 				water(p1) ? "in the" : "in", pr[p1].name,
415  | 				   water(p2) ? "the " : "", pr[p2].name);
416  | 				return E_WARN;
417  | 			}
418  | 		}
419  | 
420  | 		if (dipent.phase[0] == 'F' && pr[p1].type == 'v') {
421  | 			errmsg("Invalid order for fall in the %s.\n", pr[p1].name);
422  | 			return E_WARN;
423  | 		}
424  | 		if (dipent.phase[0] == 'F' && pr[p2].type == 'v') {
425  | 			errmsg("Invalid order for fall in the %s.\n", pr[p2].name);
426  | 			return E_WARN;
427  | 		}
428  | 		break;
429  | 
430  | 	case 'p':		/* proxy */
431  | 		*s = get_power(*s, &i);
432  | 		if (i == 0 || i >= WILD_PLAYER) {
433  | 			errmsg("Valid power must be specified for proxy order.\n");
434  | 			return E_WARN;
435  | 		}
436  | 		if (!(dipent.x2flags & X2F_PROXY)) {
437  | 			errmsg("Game %s does not allow proxy orders.\n", dipent.name);
438  | 			return E_WARN;
439  | 		}
440  | 		u2 = i;
441  | 		break;
442  | 
443  | 
444  | 	case 'v':		/* convert */
445  | 		if (dipent.x2flags & X2F_NOGARRISONS) {
446  | 			errmsg("No garrisons allowed in this game, so conversions are illegal.\n");
447  | 			return E_WARN;
448  | 		}
449  | 		*s = get_type(*s, &cc);
450  | 		if (is_garrison(u) && cc == 'x') {
451  | 			if (has_port(p1)) {
452  | 				errmsg("Conversion must specify army or fleet in port.\n");
453  | 				return E_WARN;
454  | 			} else {
455  | 				cc = 'A';
456  | 			}
457  | 		} else if (!is_garrison(u) && cc != 'x' && cc != 'G') {
458  | 			errmsg("Fleets and armies can only convert to garrisons.\n");
459  | 			return E_WARN;
460  | 		}
461  | 		if (unit[u].type == cc) {
462  | 			errmsg("The %s in %s already is %s.\n", utype(unit[u].type),
463  | 			       pr[p1].name, autype(cc));
464  | 			return E_WARN;
465  | 		}
466  | 		if (cc == 'x')
467  | 			cc = 'G';
468  | 
469  | 		if (cc == 'F') {
470  | 			/* Bug 225, enforce coast on convert to fleet */
471  |                        *s = get_coast(*s, &c1);
472  |                        for (t = (char *) pr[unit[u].loc].move; *t; t++)
473  |                                 if (*++t >> 4 == c1)
474  |                                         break;
475  |                         if (!*t) {
476  |                                 errmsg("Invalid coast specified for fleet in %s.\n",
477  |                                        pr[unit[u].loc].name);
478  |                                 return E_WARN;
479  |                         }
480  |                 }
481  | 
482  | 
483  | 		if (!has_fortress(p1)) {
484  | 			errmsg("No fortress or fortified city in %s.\n", pr[p1].name);
485  | 			return E_WARN;
486  | 		}
487  | 		if (cc == 'F' && !has_port(p1)) {
488  | 			errmsg("%s is not a port.  Can only convert to an army.\n",
489  | 			       pr[p1].name);
490  | 			return E_WARN;
491  | 		}
492  | 		if (cc == 'A' && 
493  | 		    pr[p1].flags & PF_VENICE && 
494  | 		    dipent.xflags & XF_MACH2) {
495  | 			errmsg("Armies not allowed in %s.\n", pr[p1].name);
496  | 			return E_WARN;
497  | 		}
498  | 
499  |                 if (c == 'x')
500  |                         c = unit[u].type;
501  | 
502  | 		/* MLM 12/06/2001 do not allow fleets to convert if not a port */
503  | 		if (c== 'F' && !has_port(p1)) {
504  | 			errmsg("%s is not a port.  Cannot convert.\n",
505  | 				pr[p1].name);
506  | 			return E_WARN;
507  | 		}
508  | 		/* MLM 21/6/2001 check if allowed to convert */
509  | 		if (!PermittedMachUnit(p, cc, unit[u].stype, PP_BUILD)) {
510  | 			errmsg("Conversion is not permitted for this power.\n");
511  | 			return E_WARN;
512  | 		}
513  | 
514  | 		p2 = p1;
515  | 		u2 = cc;
516  | 		c2 = cc == 'F' ? c1 : MV;
517  | 		break;
518  | 
519  | 
520  | 	default:
521  | 		errmsg("Invalid order for the %s %s %s.\n",
522  | 		       utype(unit[u].type),
523  | 		       water(p1) ? "in the" : "in", pr[p1].name);
524  | 		return E_WARN;
525  | 	}
526  | 
527  | 	unit[u].order = order;
528  | 	unit[u].unit = u2;
529  | 	unit[u].dest = p2;
530  | 	unit[u].dcoast = c2;
531  | 	unit[u].convoy = bp;
532  | 	unit[u].bloc = bl;
533  | 
534  | 	return 0;
535  | }
536  | 
537  | #define supval(u)   (unit[u].stype == 'm' || unit[u].stype == 'p' ? 2 : 1)
538  | 
539  | 
540  | /* Function to only cut one support of special units if Mach2 */
541  | void SupportCut(int u, int value)
542  | {
543  |     if (dipent.xflags & XF_MACH2) {
544  | 	support[unit[u].unit]--;
545  | 	supportvalue[u]--; /* Registers amount of support unit was last giving */
546  |         /* See if any support left: if not, mark as cut */
547  | 	if (!supportvalue[u])  
548  | 	    result[u] = value;
549  |     } else {
550  | 	/* Normal game, cuts always full support */
551  | 	 result[u] = value;
552  |          support[unit[u].unit] -= supval(u);
553  |     }
554  | }
555  | 
556  | int ma_moveout(int pt)
557  | {
558  | 
559  | /*  Process movement orders.  */
560  | 
561  | 	int u, u2, u3, u4,  bounce = 0, i, index, p, c1;
562  | 	unsigned char *s, *t, c, contest[NPROV + 1], converted[NPROV+1];
563  | 	int unit_dislodged;
564  | 	char cbuffer[1024];
565  | 
566  | /*	int result[MAXUNIT];
567  | 	int support[MAXUNIT];
568  | 	int supportvalue[MAXUNIT];
569  |  */	int has_other_retreat = 0; 
570  | 
571  | 	int had_rebellion[NPROV+1];  /* Remember if a province had a rebellion */
572  | 
573  | #define VOID        1
574  | #define NO_CONVOY   2
575  | #define CUT         3
576  | #define BOUNCE      4
577  | #define NO_SUPPORT  5
578  | #define BESIEGE     6
579  | #define DOSIEGE	    7
580  | #define BLOCKED	    8
581  | #define BAD_CONVOY  9
582  | #define SELF_BESIEGE 10
583  | #define VENICE_REBEL 11		/* Venice in rebellion fails movement in */
584  | #define DISLODGED       32	/* added on */
585  | #define MAYBE_NO_CONVOY 33	/* no message */
586  | 
587  | 	static char *results[] =
588  | 	{"dislodged",
589  | 	 "void",
590  | 	 "no convoy",
591  | 	 "cut",
592  | 	 "bounce",
593  | 	 "no support",
594  | 	 "siege in progress",
595  | 	 "siege required",
596  | 	 "blocked",
597  | 	 "WARN: check convoy",
598  | 	 "self-besiege, siege lifted",
599  | 	 "failed, destination in rebellion"};
600  | 
601  | 
602  | 	for (p = 1; p <= npr; p++) {
603  | 		contest[p] = 0;
604  | 		converted[p] = 0;
605  | 		had_rebellion[p] = 0;
606  | 	}
607  | 
608  | 	if (err)
609  | 		fprintf(rfp, "\n");
610  | 	fprintf(rfp, "Movement %s for %s of %d.", pt ? "orders" : "results",
611  | 		dipent.phase[0] == 'F' ? "Fall" :
612  | 		dipent.phase[0] == 'U' ? "Summer" : "Spring",
613  | 		atoi(&dipent.phase[1]));
614  | 
615  | 	/* Needed to say which turn no. for mapit */
616  | 	if (dipent.xflags & XF_NOMONEY)
617  | 	    fprintf(rfp, " (%s.%s)\n", dipent.name, dipent.seq); 
618  | 	else
619  | 	    fputc('\n', rfp);
620  | 
621  | 	/*
622  | 	   **  Flag bogus orders, initialize support.
623  | 	 */
624  | 
625  | 	for (u = 1; u <= nunit; u++) {
626  | 		result[u] = 0;
627  | 
628  | 		support[u] = unit[u].dcoast == MX ? -1 : supval(u) - 1;
629  | 		supportvalue[u] = supval(u);
630  | 
631  | 		/*
632  | 		   **  You get an extra support moving/converting into a rebelling province
633  | 		   **  as long as no one else is trying it at the same time.
634  | 		 */
635  | 
636  | 		if ((unit[u].order == 'm' || (unit[u].order == 'v' && unit[u].type == 'G')) &&
637  | 		    pr[p = unit[u].dest].owner != unit[u].owner &&
638  | 		    has_rebellion(p)) {
639  | 			for (u2 = 1; u2 <= nunit; u2++) {
640  | 				if (u2 != u &&
641  | 				    unit[u2].owner != pr[p].owner &&
642  | 				    unit[u2].order == 'm' &&
643  | 				    unit[u2].dest == p)
644  | 					break;
645  | 			}
646  | 			if (u2 == nunit + 1)
647  | 				support[u]++;
648  | 		}
649  | 		/*
650  | 		   **  Verify that besiege orders are valid.
651  | 		 */
652  | 
653  | 		p = unit[u].loc;
654  | 		switch (unit[u].order) {
655  | 		case 'b':	/* BESIEGE ORDER */
656  | 			if ((!has_garrison(p) && !has_crebellion(p)))
657  | 				result[u] = VOID;
658  | 			if ((has_garrison(p) && unit[pr[p].gunit].owner == unit[u].owner))
659  | 				result[u] = SELF_BESIEGE;
660  | 			break;
661  | 		case 'v':	/* CONVERT ORDER */
662  | 			/* A besieged unit can not convert */
663  | 			if (is_garrison(u)) {
664  | 				if (is_sieged(p) && unit[pr[p].gunit].owner != unit[u].owner)
665  | 					result[u] = BESIEGE;
666  | 			} else {
667  | 				/* 
668  | 				   ** A city with a garrison or rebellion 
669  | 				   ** can't be entered 
670  | 				 */
671  | 				if (has_garrison(p) || has_crebellion(p)) {
672  | 					result[u] = DOSIEGE;
673  | 				}
674  | 			}
675  | 			break;
676  | 		case 'd':
677  | 			/* Bug 2, can disband at any time */
678  | 			break;
679  | 		default:
680  | 			/* All other commands */
681  | 			if (is_sieged(p) && !is_garrison(u) && unit[u].order != 'l'
682  | 			    && unit[pr[p].gunit].owner != unit[u].owner)
683  | 				if (!(dipent.xflags & XF_NOLIFT_SIEGE))
684  | 					result[u] = BESIEGE;
685  | 		}
686  | 	}
687  | 
688  | 	/*
689  | 	   **  If we're not really processing, clear all the bogus proxy orders and
690  | 	   **  skip to the report generation.
691  | 	 */
692  | 
693  | 	if (!processing && !predict) {
694  | 		for (u = 1; u <= nunit; u++) {
695  | 			if (unit[u].proxy != 0 && unit[u].order == 'n')
696  | 				unit[u].owner = 0;
697  | 		}
698  | 	} else {
699  | 
700  | /*  Pass 0: Substitute all proxy orders. */
701  | 
702  | 		for (p = 0, u = 1; u <= nunit; u++) {
703  | 			if (unit[u].owner <= 0)
704  | 				continue;
705  | 			if (unit[u].order == 'p') {
706  | 				if (unit[u].owner != p)
707  | 					fprintf(rfp, "\n");
708  | 				fprintf(rfp, "%s: %s%s %s", powers[p = unit[u].owner], Stype(unit[u].stype),
709  | 					Utype(unit[u].type), pr[unit[u].loc].name);
710  | 				if (unit[u].coast > XC)
711  | 					fprintf(rfp, " (%s)", mtype[unit[u].coast]);
712  | 
713  | 				fprintf(rfp, " Proxy given to %s.\n", powers[unit[u].unit]);
714  | 
715  | 				unit[u].order = 'n';
716  | 				for (u2 = 1; u2 <= nunit; u2++) {
717  | 					if (unit[u2].proxy == u && unit[u2].owner == unit[u].unit) {
718  | 						unit[u].order = unit[u2].order;
719  | 						unit[u].unit = unit[u2].unit;
720  | 						unit[u].dest = unit[u2].dest;
721  | 						unit[u].dcoast = unit[u2].dcoast;
722  | 						unit[u].convoy = unit[u2].convoy;
723  | 						unit[u2].owner = 0;
724  | 					}
725  | 				}
726  | 			}
727  | 			/*
728  | 			   **  All the proxy orders will be at the end so we can safely delete
729  | 			   **  the extra ones here on a single pass.
730  | 			 */
731  | 
732  | 			if (unit[u].proxy != 0) {
733  | 				unit[u].owner = 0;
734  | 				unit[u].order = 'n';
735  | 			}
736  | 		}
737  | 		if (p)
738  | 			fprintf(rfp, "\n");
739  | 
740  | 
741  | /*  Pass 1: Tally up all the support orders, verify convoys. */
742  | 
743  | 
744  | 		for (u = 1; u <= nunit; u++) {
745  | 			if (unit[u].owner <= 0)
746  | 				continue;
747  | 
748  | 			if ((p = unit[u].bloc) && (u2 = pr[p].unit) && unit[u2].type == 'F'
749  | 			    && !allies[unit[u2].owner][unit[u].owner]) {
750  | 				result[u] = BLOCKED;
751  | 			}
752  | 			if (unit[u].order == 's' && !result[u]) {
753  | 				if (unit[u2 = unit[u].unit].order == 'm') {
754  | 					if (unit[u2].dest == unit[u].dest &&
755  | 					    (unit[u2].dcoast == unit[u].dcoast || unit[u2].dcoast <= XC)) {
756  | 						if (!result[u2])
757  | 							support[u2] += supval(u);
758  | 					} else {
759  | 						result[u] = VOID;
760  | 					}
761  | 				} else {
762  | 					if (unit[u2].loc == unit[u].dest)
763  | 						support[u2] += supval(u);
764  | 					else {
765  | 						result[u] = VOID;
766  | 					}
767  | 				}
768  | 			} else if (unit[u].order == 'm' && unit[u].convoy != NULL) {
769  | 				for (s = unit[u].convoy; *s; s++) {
770  | 					if (unit[*s].order != 'c' || unit[*s].unit != u ||
771  | 					(unit[*s].dest != unit[u].dest &&
772  | 					 unit[*s].dest != unit[*(s + 1)].loc)) {
773  | 						result[u] = NO_CONVOY;
774  | 						support[u] = supval(u) - 1;
775  | 						break;
776  | 					}
777  | 				}
778  | 			}
779  | 		}
780  | 
781  | /*  Pass 2a: Check for support cut from non-convoyed units */
782  | 
783  | 		for (u = 1; u <= nunit; u++) {
784  | 			if (unit[u].owner <= 0 || result[u])
785  | 				continue;
786  | 			if (((unit[u].order == 'm' && !unit[u].convoy && unit[u].dcoast != MX) ||
787  | 			     unit[u].order == 'v')
788  | 			    && (u2 = pr[unit[u].dest].unit)
789  | 			    && unit[u2].order == 's' && !result[u2]
790  | 			    && unit[u2].dest != unit[u].loc	/* X */
791  | 			    && unit[u2].owner != unit[u].owner) {	/* IX.6.note */
792  | 				SupportCut(u2,CUT);
793  | 			}
794  | 			/* MLM 22/6/2001 Also block moves on attempt to enter 
795  | 			   rebelling Venice */
796  | 			if (unit[u].order == 'm' && 
797  | 			    pr[unit[u].dest].flags & PF_VENICE &&
798  | 			    has_rebellion(unit[u].dest) && 
799  | 			     pr[unit[u].dest].owner == unit[u].owner)
800  | 				result[u]= VENICE_REBEL;
801  | 		}
802  | 
803  | /*  Pass 2a.1: Check for support cut from "support needed" units */
804  | 
805  | 		for (u = 1; u <= nunit; u++) {
806  | 			if (unit[u].owner <= 0 || result[u])
807  | 				continue;
808  | 			if (unit[u].dcoast == MX) {
809  | 				unit[u].dcoast = MV;
810  | 				if (unit[u].order == 'm' && !unit[u].convoy && support[u] >= 0
811  | 				    && (u2 = pr[unit[u].dest].unit)
812  | 				  && unit[u2].order == 's' && !result[u2]
813  | 				    && unit[u2].dest != unit[u].loc	/* X */
814  | 				    && unit[u2].owner != unit[u].owner) {	/* IX.6.note */
815  | 					SupportCut(u2, CUT);
816  | 				}
817  | 			}
818  | 		}
819  | /* Pass 2a.2: Check again if any partially cut special units are fully cut, only for Mach2 */
820  |     if (dipent.xflags & XF_MACH2) {
821  | 	for (u = 1; u <= nunit; u++) {
822  | 		/* Only interested in special units */
823  | 		if (supval(u) < 2) continue; 
824  | 		if (unit[u].order != 's') continue; /* Only want units ordering support */
825  | 		/* OK, identifier a full cut by an attack with > 0 support */
826  |                  for (u2 = 1; u2<= nunit; u2++) {
827  | 		     /* Ok, see if a unit is attacking this special unit and,
828  | 			if the unit attacking is a special too, or has support
829  |                         it will fully cut the unit[u] support
830  | 		      */
831  | 		     if (unit[u2].order == 'm' && 
832  | 			 unit[u2].dest == unit[u].loc && 
833  | 			 (support[u2] || supval(u2) > 1) && 
834  | 			 unit[u2].owner != unit[u].owner) {
835  | 		     result[u] = CUT;
836  | 		     support[u] -= (supval(u) -1); /* -1 as already reduced by one before */
837  | 		     break;
838  | 		    }
839  | 		}
840  |         }
841  |     }
842  | 
843  | /*  Pass 3a: Check for dislodged convoys. XII.3 */
844  | 
845  | 		for (u = 1; u <= nunit; u++) {
846  | 			if (unit[u].owner <= 0)
847  | 				continue;
848  | 			if (unit[u].order == 'c' && !result[u2 = unit[u].unit]) {
849  | 				for (s = unit[u2].convoy; s != NULL && *s; s++) {
850  | 					if (*s == u) {
851  | 						for (u3 = 1; u3 <= nunit; u3++) {
852  | 							if (unit[u3].owner <= 0)
853  | 								continue;
854  | 							if (unit[u3].order == 'm' && !result[u3] &&
855  | 							    unit[u3].owner != unit[u].owner &&
856  | 							    unit[u3].dest == unit[u].loc && support[u3] > support[u]) {
857  | 								result[u2] = MAYBE_NO_CONVOY;
858  | 								goto nextp3a;
859  | 							}
860  | 						}
861  | 					}
862  | 				}
863  | 			}
864  | 		      nextp3a:;
865  | 		}
866  | 
867  | /*  Pass 2b: Check for support cut from convoyed units */
868  | 
869  | 		for (u = 1; u <= nunit; u++) {
870  | 			if (unit[u].owner <= 0)
871  | 				continue;
872  | 			if (unit[u].order == 'm' && unit[u].convoy && !result[u]
873  | 			    && (u2 = pr[unit[u].dest].unit)
874  | 			    && unit[u2].order == 's' && !result[u2]
875  | 			    && unit[u2].dest != unit[u].loc	/* X */
876  | 			    && unit[u2].owner != unit[u].owner) {	/* IX.6.note */
877  | 
878  | /*  XII.5: You can't cut support of attacks against your convoy */
879  | 
880  | 				for (s = unit[u].convoy; s != NULL && *s; s++)
881  | 					if (unit[u2].unit == *s)
882  | 						goto nextp2b;
883  | 
884  | 				SupportCut(u2,CUT);
885  | 			}
886  | 		      nextp2b:;
887  | 		}
888  | 
889  | /*  Pass 3b: Recheck for dislodged convoys. XII.3 */
890  | 
891  | 		for (u = 1; u <= nunit; u++) {
892  | 			if (unit[u].owner <= 0)
893  | 				continue;
894  | 			if (unit[u].order == 'c' && result[u2 = unit[u].unit] == MAYBE_NO_CONVOY) {
895  | 				for (s = unit[u2].convoy; s != NULL && *s; s++) {
896  | 					if (*s == u) {
897  | 						for (u3 = 1; u3 <= nunit; u3++) {
898  | 							if (unit[u3].owner <= 0)
899  | 								continue;
900  | 							if (unit[u3].order == 'm' && !result[u3] &&
901  | 							    unit[u3].owner != unit[u].owner &&
902  | 							    unit[u3].dest == unit[u].loc && support[u3] > support[u]) {
903  | 								result[u] = DISLODGED;
904  | 								result[u2] = NO_CONVOY;
905  | 								support[u2] = supval(u2) - 1;
906  | 								goto nextp3b;
907  | 							}
908  | 						}
909  | 					}
910  | 				}
911  | 			}
912  | 		      nextp3b:;
913  | 		}
914  | 
915  | /*  Pass 2c: Check for support cut from convoyed units */
916  | 
917  | 		for (u = 1; u <= nunit; u++) {
918  | 			if (unit[u].owner <= 0)
919  | 				continue;
920  | 			if (result[u] == MAYBE_NO_CONVOY) {
921  | 				result[u] = 0;
922  | 				if ((u2 = pr[unit[u].dest].unit)
923  | 				  && unit[u2].order == 's' && !result[u2]
924  | 				    && unit[u2].dest != unit[u].loc	/* X */
925  | 				    && unit[u2].owner != unit[u].owner) {	/* IX.6.note */
926  | 
927  | /*  XII.5: You can't cut support of attacks against your convoy */
928  | 
929  | 					for (s = unit[u].convoy; s != NULL && *s; s++)
930  | 						if (unit[u2].unit == *s)
931  | 							goto nextp2c;
932  | 
933  | 					SupportCut(u2,CUT);
934  | 				}
935  | 			}
936  | 		      nextp2c:;
937  | 		}
938  | 
939  | /*  Pass 4a: Check for conditional movement blocked by an incoming or converting fleet. */
940  | 		for (u = 1; u <= nunit; u++) {
941  | 			if (unit[u].owner <= 0 || result[u])
942  | 				continue;
943  | 			if ((p = unit[u].bloc)) {
944  | 				int j;
945  | 				i = -1;
946  | 				u3 = 0;
947  | 				for (u2 = 1; u2 <= nunit; u2++) {
948  | 					j = -1;
949  | 					if (unit[u2].order == 'm' ||
950  | 					    (unit[u2].order == 'v' && unit[u2].type == 'G')) {
951  | 						if (!result[u2]) {
952  | 							if (unit[u2].dest == p) {
953  | 								j = support[u2];
954  | 							}
955  | 						} else {
956  | 							if (unit[u2].loc == p && unit[u2].type != 'G') {
957  | 								j = supval(u2);
958  | 							}
959  | 						}
960  | 					} else {
961  | 						if (unit[u2].loc == p && unit[u2].type != 'G') {
962  | 							j = support[u2];
963  | 						}
964  | 					}
965  | 
966  | 					if (j > i) {	/* The one with more support makes it?  */
967  | 						i = j;
968  | 						u3 = u2;
969  | 					} else if (j == i) {	/* If the same, neither makes it        */
970  | 						u3 = 0;
971  | 					}
972  | 				}
973  | 
974  | 				if (u3 && ((unit[u3].type == 'F' && !(dipent.xflags & XF_MACH2)) ||
975  | 					   (unit[u3].type == 'G' && unit[u3].unit == 'F')) &&
976  | 				!allies[unit[u3].owner][unit[u].owner]) {
977  | 					result[u] = BLOCKED;
978  | 					if (unit[u].order == 's' && unit[u].unit) {
979  | 					   /* Bug 195
980  | 					    * Blocked units cannot give support, so remove it */
981  | 					   support[unit[u].unit] -= supval(u);
982  | 					}
983  | 				}
984  | 			}
985  | 		}
986  | 
987  | /*  Pass 4b: Check for dislodged support. X */
988  | 
989  | 		for (u = 1; u <= nunit; u++) {
990  | 			if (unit[u].owner <= 0)
991  | 				continue;
992  | 			if (unit[u].order == 'm' && (u2 = pr[unit[u].dest].unit)
993  | 			    && unit[u2].order == 's' && !result[u] && !result[u2]
994  | 			    && unit[u2].dest == unit[u].loc) {
995  | 
996  | /*  Your support cannot dislodge your own unit.  IX.3  */
997  | 
998  | 				for (u3 = 1, p = 0; u3 <= nunit; u3++) {
999  | 					if (unit[u3].owner <= 0)
1000 | 						continue;
1001 | 					if (!result[u3] && unit[u3].order == 's' &&
1002 | 					    unit[u3].unit == u && unit[u3].owner == unit[u2].owner)
1003 | 						p += supval(u3);
1004 | 				}
1005 | 
1006 | 				if (support[u] - p > support[u2]) {
1007 | 				   for (u4=1, unit_dislodged=1; u4<=nunit; u4++ ) {
1008 |                                         if ( ( u != u4 )
1009 |                                         && ( unit[ u4 ].order == 'm' )
1010 |                                         && ( !result[ u4 ] )
1011 |                                         && ( unit[ u4 ].dest == unit[ u ].dest )
1012 |                                         && ( support[ u4 ] >= support[u]-p ) )
1013 |                                             unit_dislodged = 0;
1014 |                                     }
1015 | 
1016 |                                     if ( unit_dislodged == 1 ) {
1017 |                                     result[u2] = DISLODGED;
1018 |                                     support[unit[u2].unit] -= supval(u2);
1019 |                                     }
1020 |                                 }
1021 | 			}
1022 | 		}
1023 | 
1024 | /* Pass 5aa: Disband requested disband units */
1025 |                 for (u = 1; u <= nunit; u++) {
1026 |                         if (unit[u].owner <= 0)
1027 |                                 continue;
1028 |                         if (unit[u].order == 'd') {
1029 |                             result[u] = 0; /* Disbands never fail */
1030 |                         }
1031 |                 }
1032 | 
1033 | /*  Pass 5: Check for movement bounces */
1034 | 
1035 | 		do {
1036 | 			bounce = 0;
1037 | 			for (u = 1; u <= nunit; u++) {
1038 | 				if (unit[u].owner <= 0)
1039 | 					continue;
1040 | 				if ((unit[u].order == 'm' ||
1041 |                                      (unit[u].order == 'v' && (unit[u].type == 'G' || is_venice(unit[u].loc)))) && !result[u]) {
1042 | 
1043 | 					/*
1044 | 					   **  The destination is contested by unit u unless there is a
1045 | 					   **  unit there moving into unit u's starting location.
1046 | 					 */
1047 | 
1048 | 					/* u2 is set to garrison unit if none in province 
1049 | 					   and we're talking about venice */
1050 | 
1051 | 					u2 = pr[unit[u].dest].unit;
1052 | 					if (!u2 && pr[unit[u].dest].flags & PF_VENICE) {
1053 | 						u2 = pr[unit[u].dest].gunit;
1054 | 					}
1055 | 					 if (u2 == u)
1056 |                                                 u2 = 0;  /* Can't bounce with myself! */
1057 | 
1058 | 					if (!((u2) && !result[u2]	/* IX.7.note */
1059 | 					      &&unit[u2].order == 'm'
1060 | 					  && unit[u2].dest == unit[u].loc
1061 | 					      && !unit[u2].convoy && !unit[u].convoy)) {	/* XIV.6 */
1062 | 						contest[unit[u].dest]++;
1063 | 					}
1064 | 					p = 0;
1065 | 					if (u2) {
1066 | 
1067 | 						/*
1068 | 						   **  Your support cannot dislodge your own unit.  IX.3
1069 | 						 */
1070 | 
1071 | 						if (result[u2] || (unit[u2].order != 'm' &&
1072 | 						unit[u2].order != 'v')) {
1073 | 							for (u3 = 1; u3 <= nunit; u3++) {
1074 | 								if (unit[u3].owner <= 0)
1075 | 									continue;
1076 | 								if (!result[u3] && unit[u3].order == 's' &&
1077 | 								    unit[u3].unit == u && unit[u3].owner == unit[u2].owner)
1078 | 									p += supval(u3);
1079 | 							}
1080 | 						}
1081 | 						/*
1082 | 						   **  Unit u bounces if the unit there is holding with more support
1083 | 						   ** or trying to go to Venice with a garrison.
1084 | 						 */
1085 | 
1086 | 						if ((unit[u2].order != 'm' && unit[u2].order != 'v' && unit[u2].order != 'd')
1087 | 						    || (unit[u2].dest == unit[u].loc
1088 | 							&& !unit[u2].convoy && !unit[u].convoy)) {	/* XIV.6 */
1089 | 							if (support[u] - p <= support[u2] 
1090 | 							    || (unit[u2].type == 'G' && is_venice(unit[u2].loc))
1091 | 							    || unit[u].owner == unit[u2].owner  ) {	/* IX.3 */
1092 | 								bounce++;
1093 | 								result[u] = BOUNCE;
1094 | 								goto nextp5;
1095 | 							}
1096 | 							/*
1097 | 							   **  ...or if the unit's movement bounced and we have no support.
1098 | 							 */
1099 | 
1100 | 						} else if (result[u2]
1101 | 							   && ((support[u] - p < supval(u2))
1102 | 							       || unit[u].owner == unit[u2].owner)) {	/* IX.3 */
1103 | 							bounce++;
1104 | 							result[u] = BOUNCE;
1105 | 							goto nextp5;
1106 | 						}
1107 | 					}
1108 | 					/*
1109 | 					   **  Unit bounces if another unit is moving to the same spot with
1110 | 					   **  the same amount or more support.
1111 | 					 */
1112 | 
1113 | 					for (u3 = 1; u3 <= nunit; u3++) {
1114 | 						if (unit[u3].owner <= 0)
1115 | 							continue;
1116 | 						if (u != u3 && unit[u].dest == unit[u3].dest &&
1117 |                                                 ((unit[u3].order == 'm' ||
1118 |                                                   (unit[u3].order == 'v' && (unit[u3].type == 'G' || is_venice(unit[u3].loc)))) &&
1119 |                                                  (!result[u3] || result[u3] == BOUNCE)) &&
1120 |                                                     support[u] - p <= support[u3]) {
1121 | 
1122 | 							/*
1123 | 							   **  Won't bounce if unit there dislodges other unit.  IX.7.note
1124 | 							 */
1125 | 
1126 | 							if (!(u2 && unit[u2].order == 'm' && !result[u2]
1127 | 							      && unit[u2].dest == unit[u3].loc
1128 | 							      && !unit[u2].convoy && !unit[u3].convoy)) {
1129 | 								bounce++;
1130 | 								result[u] = BOUNCE;
1131 | 								goto nextp5;
1132 | 							}
1133 | 						}
1134 | 					}
1135 | 				}
1136 | 			      nextp5:;
1137 | 			}
1138 | 		} while (bounce);
1139 | 
1140 | /*  Pass 5a: flag dislodgements */
1141 | 
1142 | 		bounce = 0;
1143 | 		for (u = 1; u <= nunit; u++) {
1144 | 			if (unit[u].owner <= 0)
1145 | 				continue;
1146 | 			if ((unit[u].order == 'm' ||
1147 | 			(unit[u].order == 'v' && unit[u].type == 'G')) &&
1148 | 			    !result[u]) {
1149 | 				if ((u2 = pr[unit[u].dest].unit) &&
1150 | 				    ((unit[u2].order != 'm' && unit[u2].order != 'v' && unit[u2].order != 'd') ||
1151 | 				     result[u2]) &&
1152 | 				     (dipent.xflags & XF_MACH2 || !(unit[u2].type == 'G' && is_sieged(unit[u2].loc)))) {
1153 | /*                fprintf(rfp, "First part: Dislodge in %s unit %d by %d\n",
1154 |  */
1155 | /*                              pr[unit[u2].loc].name, u2, u); */
1156 | 					if (result[u2] < DISLODGED)
1157 | 						result[u2] += DISLODGED;
1158 | 					unit[u2].status = 'r';
1159 | 					bounce++;
1160 | 				}
1161 | 			} else if (unit[u].order == 'b' && !result[u]) {
1162 | 				if ((u2 = has_garrison(unit[u].loc))) {
1163 | 					for (u3 = 1; u3 <= nunit; u3++) {
1164 | 						if (unit[u3].order == 'm'
1165 | 						    && unit[u3].dest == unit[u].loc
1166 | 						    && !result[u3]) {
1167 | 							break;
1168 | 						}
1169 | 					}
1170 | 					if (u3 > nunit) {
1171 | /*                fprintf(rfp, "Second part: Dislodge in %s unit %d by %d\n",
1172 |  */
1173 | /*                              pr[unit[u2].loc].name, u2, u); */
1174 | 					    if (is_sieged(unit[u].loc)) {
1175 | 					        if (!(dipent.xflags & XF_BESEIGED_CAN_DISLODGE) ||
1176 | 						    (support[u] >= support[u2])) {
1177 | 						    if (result[u2] < DISLODGED)
1178 | 							result[u2] += DISLODGED;
1179 | 						    unit[u2].status = 'r';
1180 | 						    bounce++;
1181 | 						}
1182 | 					    } else {
1183 | 					         if (!result[u2] && unit[u2].order != 'd' &&
1184 |                                                      !(dipent.xflags & XF_BESEIGED_CAN_DISLODGE))
1185 |                                                    result[u2] = BESIEGE; /* Bug2, must not be disbanding */
1186 | 									 /* Bug375, Mach2 cannot prevent besieger dislodging */
1187 | 					    }
1188 | 					}
1189 | 				}
1190 | 			}
1191 | 		}
1192 | /*   fprintf(rfp, "%s : %d\n", pr[unit[1].loc].name, result[1]); */
1193 | 	}
1194 | 
1195 | /*  Pass 6: Process movement, print report */
1196 | 
1197 | 	for (p = 0, u = 1; u <= nunit; u++) {
1198 | 		if (unit[u].owner <= 0)
1199 | 			continue;
1200 | 		if (processing || pt == unit[u].owner || pt == MASTER) {
1201 | 			if (unit[u].owner != p)
1202 | 				fprintf(rfp, "\n");
1203 | 			if ((unit[u].owner != p) && (pt == MASTER)) {
1204 | 				mast_rpt(unit[u].owner, 0);
1205 | 			};
1206 | 
1207 | 			fprintf(rfp, "%s: ", powers[p = unit[u].owner]);
1208 | 
1209 | 			if (unit[u].proxy != 0)
1210 | 				fprintf(rfp, "%s ", owners[unit[unit[u].proxy].owner]);
1211 | 
1212 | 			fprintf(rfp, "%s%s %s", Stype(unit[u].stype),
1213 | 			      Utype(unit[u].type), pr[unit[u].loc].name);
1214 | 			if (unit[u].coast > XC)
1215 | 				fprintf(rfp, " (%s)", mtype[unit[u].coast]);
1216 | 
1217 | 			switch (unit[u].order) {
1218 | 			case 'b':
1219 | 				fprintf(rfp, " BESIEGE");
1220 | 				if ((u2 = has_garrison(unit[u].loc))) {
1221 | 					fprintf(rfp, " %s %s", owners[unit[u2].owner], Utype(unit[u2].type));
1222 | 				} else if (has_crebellion(unit[u].loc)) {
1223 | 					fprintf(rfp, " Rebellion");
1224 | 				}
1225 | 				break;
1226 | 
1227 | 			case 'c':
1228 | 				fprintf(rfp, " CONVOY ");
1229 | 				if ((i = unit[u2 = unit[u].unit].owner) != p)
1230 | 					fprintf(rfp, "%s ", owners[i]);
1231 | 				else if (!processing && !predict && unit[u2].dest != unit[u].dest)
1232 | 					result[u] = BAD_CONVOY;
1233 | 				fprintf(rfp, "Army %s -> %s", pr[unit[u2].loc].name,
1234 | 					pr[unit[u].dest].name);
1235 | 				break;
1236 | 
1237 | 			case 'h':
1238 | 				fprintf(rfp, " HOLD");
1239 | 				break;
1240 | 
1241 | 			case 'd':
1242 |                                 fprintf(rfp, " DISBAND");
1243 |                                 break;
1244 | 
1245 |                        case 'l':
1246 |                                 fprintf(rfp, " LIFT SIEGE");
1247 |                                 break;
1248 | 
1249 | 			case 'm':
1250 | 				if ((s = unit[u].convoy)) {
1251 | 					while (*s) {
1252 | 						if (!processing && !predict && unit[*s].owner == unit[u].owner &&
1253 | 						    (unit[*s].order != 'c' || unit[*s].unit != u ||
1254 | 						     unit[*s].dest != unit[u].dest)) {
1255 | 							result[u] = BAD_CONVOY;
1256 | 						}
1257 | 						fprintf(rfp, " -> %s", pr[unit[*s++].loc].name);
1258 | 					}
1259 | 				}
1260 | 				fprintf(rfp, " -> %s", pr[unit[u].dest].name);
1261 | 				if (unit[u].dcoast > XC)
1262 | 					fprintf(rfp, " (%s)", mtype[unit[u].dcoast]);
1263 | 				break;
1264 | 
1265 | 			case 'n':
1266 | 				if (unit[u].owner != AUTONOMOUS) {
1267 | 					fprintf(rfp, ", No Order Processed");
1268 | 					if (dipent.phase[0] != 'F' || pr[unit[u].loc].type != 'v')
1269 | 						more_orders++;
1270 | 				}
1271 | 				break;
1272 | 
1273 | 			case 'p':
1274 | 				fprintf(rfp, " PROXY TO %s", powers[unit[u].unit]);
1275 | 				break;
1276 | 
1277 | 			case 's':
1278 | 				fprintf(rfp, " SUPPORT ");
1279 | 				if ((i = unit[u2 = unit[u].unit].owner) != p)
1280 | 					fprintf(rfp, "%s ", owners[i]);
1281 | 				fprintf(rfp, "%s %s", Utype(unit[u2].type), pr[unit[u2].loc].name);
1282 | 				if (unit[u2].coast > XC)
1283 | 					fprintf(rfp, " (%s)", mtype[unit[u2].coast]);
1284 | 
1285 | 				if (unit[u2].loc != unit[u].dest) {
1286 | 					fprintf(rfp, " -> %s", pr[unit[u].dest].name);
1287 | 					if (unit[u].dcoast > XC)
1288 | 						fprintf(rfp, " (%s)", mtype[unit[u].dcoast]);
1289 | 				}
1290 | 				if (unit[u2].type == 'G') {
1291 | 					fprintf(rfp, " CONVERSION");
1292 | 				}
1293 | 				break;
1294 | 
1295 | 			case 'v':
1296 | 				fprintf(rfp, " CONVERT TO %s", Utype(unit[u].unit));
1297 | 				if ((c1 = unit[u].dcoast) > XC)
1298 |                                 	fprintf(rfp, " (%s)", mtype[c1]);
1299 | 
1300 | 				break;
1301 | 
1302 | 			default:
1303 | 				fprintf(rfp, " INVALID ORDER (internal error)");
1304 | 			}
1305 | 
1306 | 			if (result[u]) {
1307 | 				fprintf(rfp, ".  (*%s%s*)\n", results[result[u] % DISLODGED],
1308 | 					result[u] > DISLODGED ? ", dislodged" : "");
1309 | 			} else {
1310 | 				fprintf(rfp, ".\n");
1311 | 			}
1312 | 		}
1313 | 	}
1314 | 
1315 | /*  Pass 7: Print out retreats.  */
1316 | 
1317 | 	if (processing || predict) {
1318 | 		i = 0;
1319 | 		for (u = 1; u <= nunit; u++) {
1320 | 		    /* Bug 249, reset disbanding owners to zero */	
1321 | 		    if (unit[u].owner > 0 && unit[u].order == 'd')
1322 | 			    unit[u].owner = 0;
1323 | 		}
1324 | 
1325 | 		for (u = 1; u <= nunit; u++) {
1326 | 			if (unit[u].owner <= 0)
1327 | 				continue;
1328 | 
1329 | 			/*
1330 | 			   **  Advance moving unit into the destination province.
1331 | 			 */
1332 | 
1333 | 			if (unit[u].order == 'm' && !result[u]) {
1334 | 				unit[u].loc = p = unit[u].dest;
1335 | 				unit[u].coast = unit[u].dcoast;
1336 | 				/*
1337 | 				   ** Moving into anothers power province which is in rebellion or
1338 | 				   ** which city is in rebellion liberates the rebellion.
1339 | 				 */
1340 | 				if (has_rebellion(p) &&
1341 | 				    pr[p].owner != unit[u].owner) {
1342 | 					if (!i++)
1343 | 						fprintf(rfp, "\n");
1344 | 					fprintf(rfp, "Rebellion in %s liberated.\n", pr[p].name);
1345 | 					remove_rebellion(p);
1346 | 					had_rebellion[p] = 1; /* Remember had a rebellion */
1347 | 				}
1348 | 			}
1349 | 			/*
1350 | 			   **  Holding in a province will put down a rebellion.
1351 | 			 */
1352 | 
1353 | 			if (unit[u].order == 'h' && !result[u]) {
1354 | 				if (has_prebellion(p = unit[u].loc)) {
1355 | 					if (!i++)
1356 | 						fprintf(rfp, "\n");
1357 | 					fprintf(rfp, "Rebellion in %s put down.\n", pr[p].name);
1358 | 					remove_prebellion(p);
1359 | 				}
1360 | 			}
1361 | 			/*
1362 | 			   **  Change the type of units who are converting.
1363 | 			 */
1364 | 
1365 | 			else if (unit[u].order == 'v' && !result[u]) {
1366 | 				unit[u].type = unit[u].unit;
1367 | 				unit[u].coast = unit[u].dcoast;
1368 | 				p = unit[u].loc;
1369 | 				/*
1370 | 				   ** Adjust the gunit flag
1371 | 				 */
1372 | 				if (is_garrison(u))
1373 | 					pr[unit[u].loc].gunit = u;
1374 | 					if (pr[unit[u].loc].unit == u)
1375 | 					   pr[unit[u].loc].unit = 0; /* If I converted, mark my province as empty */
1376 | 				else
1377 | 					pr[unit[u].loc].gunit = 0;
1378 | 					converted[unit[u].loc] = u; /* remember that a conversion occured */
1379 | 
1380 | 				if (has_rebellion(p) &&
1381 | 				    pr[p].owner != unit[u].owner) {
1382 | 					if (!i++)
1383 | 						fprintf(rfp, "\n");
1384 | 					fprintf(rfp, "Rebellion in %s liberated.\n", pr[p].name);
1385 | 					remove_rebellion(p);
1386 | 				}
1387 | 			}
1388 | 			/*
1389 | 			   **  A besiege sets the flag, or if already set, clears it.
1390 | 			 */
1391 | 
1392 | 			else if (unit[u].order == 'b' && !result[u]) {
1393 | 				if (is_sieged(p = unit[u].loc)) {
1394 | 					if (has_crebellion(p)) {
1395 | 						if (!i++)
1396 | 							fprintf(rfp, "\n");
1397 | 						fprintf(rfp, "Rebellion in %s put down.\n", pr[p].name);
1398 | 					}
1399 | 					remove_siege(p);
1400 | 					remove_rebellion(p);
1401 | 				} else {
1402 | 					/* Bug 249, only set siege if garrison is not disbanding */
1403 | 					if (!(pr[p].gunit != 0 && unit[pr[p].gunit].order == 'd')) {
1404 | 					    set_siege(p);
1405 | 					}
1406 | 				}
1407 | 			}
1408 | 			/*
1409 | 			   **  Clear the siege in process flag if lifted.
1410 | 			 */
1411 | 
1412 | 			else if ((unit[u].order == 'l' && !result[u]) || 
1413 | 				(result[u] == SELF_BESIEGE) ||
1414 | 				(unit[u].type != 'G' && (dipent.xflags & XF_NOLIFT_SIEGE) )) {
1415 | 				remove_siege(unit[u].loc);
1416 | 			}
1417 | 		}
1418 | 
1419 | 		if (bounce)
1420 | 			fprintf(rfp, "\n\nThe following units were dislodged:\n\n");
1421 | 		bounce = 0;
1422 | 
1423 | 		for (u = 1; u <= nunit; u++) {
1424 | 			if (unit[u].owner <= 0)
1425 | 				continue;
1426 | 			if (unit[u].status == 'r') {
1427 | 				unsigned char buffer[1024];
1428 | 				unit[u].convoy = &heap[hp];
1429 | 				t = buffer;
1430 | 				sprintf(t, "The %s %s in %s%s", owners[unit[u].owner],
1431 | 					Utype(unit[u].type),
1432 | 					water(unit[u].loc) ? "the " : "",
1433 | 					pr[unit[u].loc].name);
1434 | 				remove_siege(unit[u].loc);
1435 | 				while (*t)
1436 | 					t++;
1437 | 				if (unit[u].coast > XC) {
1438 | 					sprintf(t, " (%s)", mtype[unit[u].coast]);
1439 | 					while (*t)
1440 | 						t++;
1441 | 				}
1442 | 				i = 0;
1443 | 				has_other_retreat = 0;
1444 | 				if (!is_garrison(u) && !(dipent.xflags & XF_AUTODISBAND)) {
1445 | 					for (s = pr[unit[u].loc].move; (p = *s++); s++) {
1446 | 						if (!contest[p] && (((unsigned char) *s) >> 4) == unit[u].coast && (*s & 0x0f) != MX
1447 | 						    && (!(u2 = pr[p].unit)	/* XI: can't retreat to */
1448 | 						     ||(unit[u2].loc != p	/* attackers origin.    */
1449 | 							&& unit[u2].loc != unit[u].loc))
1450 | 						    && (dipent.phase[0] != 'F' || pr[p].type != 'v')) {
1451 | 							has_other_retreat = 1;
1452 | 
1453 | 							if (!i++)
1454 | 								sprintf(t, " can retreat to ");
1455 | 							else
1456 | 								sprintf(t, " or ");
1457 | 							while (*t)
1458 | 								t++;
1459 | 
1460 | 							heap[hp++] = p;
1461 | 							sprintf(t, "%s", pr[p].name);
1462 | 							while (*t)
1463 | 								t++;
1464 | 							if ((c = *s & 0x0f) > XC) {
1465 | 								sprintf(t, " (%s)", mtype[c]);
1466 | 								while (*t)
1467 | 									t++;
1468 | 								cbuffer[i - 1] = c;
1469 | 							} else
1470 | 								cbuffer[i - 1] = 0;
1471 | 							bounce++;
1472 | 						}
1473 | 					}
1474 | 
1475 | 					/*
1476 | 					   ** The rules to retreat to a garrison are:
1477 | 					   ** 1a) There was no conversion FROM garrison made
1478 | 					   ** 1) There should be a fortress.
1479 | 					   ** 2) It should be unoccupied.
1480 | 					   ** 3) Free of rebellion.
1481 | 					   ** 3aa) Didn't have a rebellion against unit's onwer
1482 | 					   ** 3a) not Venice
1483 | 					   ** 4) And if we are a fleet, it should have a port.
1484 | 					 */
1485 | 					if (!converted[unit[u].loc] &&
1486 | 					    has_fortress(unit[u].loc) &&
1487 | 					    !has_garrison(unit[u].loc) &&
1488 | 					  !has_crebellion(unit[u].loc) &&
1489 | 				          !(had_rebellion[unit[u].loc] && pr[unit[u].loc].owner == unit[u].owner) &&
1490 | 					  !is_venice(unit[u].loc) &&
1491 | 					    (has_port(unit[u].loc) || unit[u].type == 'A')) {
1492 | 						if (!i++ || dipent.xflags & XF_GCONVERT_ANYTIME) {
1493 | 							sprintf(t, "%s can convert to a Garrison",
1494 | 							has_other_retreat ? " or" : "");
1495 | 							while (*t)
1496 | 								t++;
1497 | 							heap[hp++] = unit[u].loc;
1498 | 							bounce++;
1499 | 						}
1500 | 					}
1501 | 				} else {
1502 | 					/*
1503 | 					   ** The garrison was eliminated.
1504 | 					 */
1505 | 					pr[unit[u].loc].gunit = 0;
1506 | 				}
1507 | 
1508 | 				if (!i) {
1509 | 					sprintf(t, " with no valid retreats was destroyed.\n");
1510 | 					unit[u].owner = 0;
1511 | 				} else {
1512 | 					sprintf(t, ".\n");
1513 | 				}
1514 | 				heap[hp++] = 0;
1515 | 
1516 | 				/* put the coasts on the heap */
1517 | 				unit[u].rcoast = &heap[hp];
1518 | 				for (index = 0; index < i; index++)
1519 | 					heap[hp++] = cbuffer[index];
1520 | 				heap[hp++] = 0;
1521 | 
1522 | 				for (t = s = buffer, p = 0; *s; s++, p++) {
1523 | 					if (p > 78) {
1524 | 						while (*--s != ' ');
1525 | 						*s++ = '\0';
1526 | 						fprintf(rfp, "%s\n", t);
1527 | 						t = s;
1528 | 						p = 0;
1529 | 					}
1530 | 				}
1531 | 				fprintf(rfp, "%s", t);
1532 | 			}
1533 | 		}
1534 | 	}
1535 | 
1536 | 	 /* Bug 126, correct the units in province, setting to zero if unit is not really there */
1537 | 	if (processing)
1538 | 	        for (p = 1; p <= npr; p++)
1539 | 		    if (unit[pr[p].unit].loc != p)
1540 |                         pr[p].unit = 0;
1541 | 		    if (unit[pr[p].gunit].loc != p)
1542 | 		        pr[p].gunit = 0;
1543 | 
1544 | 	return bounce;		/* return true if retreats are needed */
1545 | }