1 /*
2  *   XFrisk - The classic board game for X
3  *   Copyright (C) 1993-1999 Elan Feingold (elan@aetherworks.com)
4  *
5  *   This program is free software; you can redistribute it and/or modify
6  *   it under the terms of the GNU General Public License as published by
7  *   the Free Software Foundation; either version 2 of the License, or
8  *   (at your option) any later version.
9  *
10  *   This program is distributed in the hope that it will be useful,
11  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
12  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  *   GNU General Public License for more details.
14  *
15  *   You should have received a copy of the GNU General Public License
16  *   along with this program; if not, write to the Free Software
17  *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18  *
19  *   $Id: game.c,v 1.13 2000/01/18 20:07:26 morphy Exp $
20  *
21  *   $Log: game.c,v $
22  *   Revision 1.13  2000/01/18 20:07:26  morphy
23  *   Made middle button (drop all armies) obey DROP_ARMIES limitation
24  *
25  *   Revision 1.12  2000/01/18 19:56:43  morphy
26  *   Prevention of dropping all armies works now
27  *
28  *   Revision 1.11  2000/01/18 09:25:47  tony
29  *   oops, little braino in "dropping armies" code
30  *
31  *   Revision 1.10  2000/01/17 21:09:03  tony
32  *   small fix on dropping armies during fortification, optional number
33  *
34  */
35 
36 #include <stdlib.h>
37 #include <stdio.h>
38 #include <unistd.h>
39 
40 #include "registerPlayers.h"
41 #include "callbacks.h"
42 #include "utils.h"
43 #include "dice.h"
44 #include "game.h"
45 #include "debug.h"
46 #include "riskgame.h"
47 #include "types.h"
48 #include "colormap.h"
49 #include "client.h"
50 
51 
52 /* Globals */
53 static MsgNetMessage mess;
54 
55 static Int32         iAttackDst=-1;
56 static Int32         iMoveDst=-1;
57 
58 /*iAttackSrc is used by callbacks.c */
59 static Int32         iAttackSrc=-1;
60 
61 Int32         iLastAttackSrc=-1, iLastAttackDst=-1;
62 Int32         iMoveSrc=-1;
63 
64 Flag          fGetsCard=FALSE;
65 Flag          fCanExchange=TRUE;
66 
67 /* max number of armies to allow when not using DROP_ALL */
68 #define DROP_ARMIES 3
69 
70 /************************************************************************
71  *  FUNCTION: GAME_AttackFrom
72  *  HISTORY:  291099  Tdh
73  *  PURPOSE:  Return value of iAttackSrc
74  *  NOTES: to make iAttackSrc private to game.c
75  */
GAME_AttackFrom()76 Int32 GAME_AttackFrom() {
77     return iAttackSrc;
78 }
79 
80 /************************************************************************
81  *  FUNCTION: GAME_SetAttackSrc
82  *  HISTORY:  291099  Tdh
83  *  PURPOSE:  Set value of iAttackSrc
84  *  NOTES:    to make iAttackSrc private to game.c
85  */
86 
GAME_SetAttackSrc(Int32 src)87 void GAME_SetAttackSrc(Int32 src) {
88     iAttackSrc = src;
89 }
90 
91 
92 /************************************************************************
93  *  FUNCTION: GAME_CanAttack
94  *  HISTORY:
95  *     03.04.94  ESF  Created.
96  *  PURPOSE: Check if this attack is possible
97  *  NOTES:
98  ************************************************************************/
GAME_CanAttack(Int32 AttackSrc,Int32 iAttackDst)99 Flag GAME_CanAttack(Int32 AttackSrc, Int32 iAttackDst)
100 {
101   Int32 i;
102 
103   for (i=0; i!=6 && RISK_GetAdjCountryOfCountry(AttackSrc, i)!=-1; i++)
104     if (RISK_GetAdjCountryOfCountry(AttackSrc, i) == iAttackDst)
105       return TRUE;
106 
107   return FALSE;
108 }
109 
110 
111 /************************************************************************
112  *  FUNCTION: GAME_SetTurnArmiesOfPlayer
113  *  HISTORY:
114  *     04.23.95  ESF  Created.
115  *  PURPOSE:
116  *  NOTES:
117  ************************************************************************/
GAME_SetTurnArmiesOfPlayer(Int32 iCurrentPlayer)118 void GAME_SetTurnArmiesOfPlayer(Int32 iCurrentPlayer)
119 {
120   Int32 iNumArmies=0;
121 
122   /* Add the continent bonus */
123   iNumArmies += GAME_GetContinentBonus(iCurrentPlayer);
124 
125   /* Add the standard "at-least-three-and-at-most-one-per-three-countries" */
126   iNumArmies += MAX(RISK_GetNumCountriesOfPlayer(iCurrentPlayer)/3, 3);
127 
128   RISK_SetNumArmiesOfPlayer(iCurrentPlayer, iNumArmies);
129 }
130 
131 
132 /************************************************************************
133  *  FUNCTION: GAME_MoveArmies
134  *  HISTORY:
135  *     03.04.94  ESF  Created.
136  *     03.18.94  ESF  Added server update.
137  *     05.19.94  ESF  Added verbose message across network.
138  *  PURPOSE:
139  *  NOTES:
140  ************************************************************************/
GAME_MoveArmies(Int32 iSrcCountry,Int32 iDstCountry,Int32 iNumArmies)141 void GAME_MoveArmies(Int32 iSrcCountry, Int32 iDstCountry, Int32 iNumArmies)
142 {
143   MsgMoveNotify msgMoveNotify;
144   char buf[256];
145 
146   /* Notify the server */
147   msgMoveNotify.iSrcCountry = iSrcCountry;
148   msgMoveNotify.iDstCountry = iDstCountry;
149   (void)RISK_SendMessage(CLNT_GetCommLinkOfClient(CLNT_GetThisClientID()),
150 			 MSG_MOVENOTIFY, &msgMoveNotify);
151 
152   /* send a verbose message */
153 #ifdef ENGLISH
154   snprintf(buf, sizeof(buf), "%s moved %d armies from %s to %s",
155 #endif
156 #ifdef FRENCH
157   snprintf(buf, sizeof(buf), "%s d�place %d arm�e(s) de %s � %s",
158 #endif
159 	  RISK_GetNameOfPlayer(iCurrentPlayer),
160 	  iNumArmies,
161 	  RISK_GetNameOfCountry(iSrcCountry),
162 	  RISK_GetNameOfCountry(iDstCountry));
163   mess.strMessage = buf;
164   (void)RISK_SendMessage(CLNT_GetCommLinkOfClient(CLNT_GetThisClientID()),
165 			 MSG_NETMESSAGE, &mess);
166 
167   /* Update date structures */
168   RISK_SetNumArmiesOfCountry(iDstCountry,
169 		   RISK_GetNumArmiesOfCountry(iDstCountry) + iNumArmies);
170   RISK_SetNumArmiesOfCountry(iSrcCountry,
171 		   RISK_GetNumArmiesOfCountry(iSrcCountry) - iNumArmies);
172 }
173 
174 
175 /************************************************************************
176  *  FUNCTION: GAME_PlaceArmies
177  *  HISTORY:
178  *     03.04.94  ESF  Stubbed.
179  *     05.19.94  ESF  Coded and added verbose message across network.
180  *     10.02.94  ESF  Added support for PLACE_ALL.
181  *     04.30.95  ESF  Moved the dialog code from to PlaceClick.
182  *  PURPOSE:
183  *  NOTES:
184  ************************************************************************/
185 void GAME_PlaceArmies(Int32 iCountry, Int32 iArmies)
186 {
187   MsgPlaceNotify  msgPlaceNotify;
188   char buf[256];
189 
190   /* Send a message to the server about this */
191   msgPlaceNotify.iCountry = iCountry;
192   (void)RISK_SendMessage(CLNT_GetCommLinkOfClient(CLNT_GetThisClientID()),
193 			 MSG_PLACENOTIFY, &msgPlaceNotify);
194 
195   /* Send a verbose message */
196 #ifdef ENGLISH
197   snprintf(buf, sizeof(buf), "%s placing %d %s on %s",
198 #endif
199 #ifdef FRENCH
200   snprintf(buf, sizeof(buf), "%s place %d %s en %s",
201 #endif
202 	  RISK_GetNameOfPlayer(iCurrentPlayer),
203 	  iArmies,
204 	  iArmies == 1 ? "army" : "armies",
205 	  RISK_GetNameOfCountry(iCountry));
206   mess.strMessage = buf;
207   (void)RISK_SendMessage(CLNT_GetCommLinkOfClient(CLNT_GetThisClientID()),
208 			 MSG_NETMESSAGE, &mess);
209 
210   /* Once we've placed, can't exchange cards anymore */
211   fCanExchange = FALSE;
212 
213   /* Update the data structures */
214   RISK_SetNumArmiesOfPlayer(iCurrentPlayer,
215 			    RISK_GetNumArmiesOfPlayer(iCurrentPlayer)
216 			    - iArmies);
217   RISK_SetNumArmiesOfCountry(iCountry,
218 			     RISK_GetNumArmiesOfCountry(iCountry)+iArmies);
219 
220   /* If we're out of armies, jump into attack mode */
221   if (!RISK_GetNumArmiesOfPlayer(iCurrentPlayer) && iState == STATE_PLACE)
222     {
223       iState = STATE_ATTACK;
224       UTIL_ServerEnterState(iState);
225       UTIL_DisplayActionCString(iState, iCurrentPlayer);
226     }
227 
228   UTIL_DisplayActionCString(iState, iCurrentPlayer);
229 }
230 
231 
232 /************************************************************************
233  *  FUNCTION: GAME_Attack
234  *  HISTORY:
235  *     04.23.95  ESF  Created.
236  *  PURPOSE:
237  *  NOTES:
238  ************************************************************************/
239 void GAME_Attack(Int32 iSrcCountry, Int32 iDstCountry)
240 {
241   Int32 iActionState = RISK_GetAttackModeOfPlayer(iCurrentPlayer);
242   Int32 iDice        = RISK_GetDiceModeOfPlayer(iCurrentPlayer);
243 
244   /* Keep these so as to be able to repeat attack */
245   iLastAttackSrc = iSrcCountry;
246   iLastAttackDst = iDstCountry;
247 
248   if (iActionState == ACTION_ATTACK)
249     {
250       if (GAME_ValidAttackSrc(iSrcCountry, TRUE) &&
251 	  GAME_ValidAttackDst(iSrcCountry, iDstCountry, TRUE) &&
252 	  GAME_ValidAttackDice(iDice, iSrcCountry))
253 	{
254 	  GAME_DoAttack(iSrcCountry, iDstCountry, TRUE);
255 	  UTIL_DisplayActionCString(iState, iCurrentPlayer);
256 	}
257     }
258   else if (iActionState == ACTION_DOORDIE)
259     {
260       Flag  fNotify = TRUE;
261 
262       while (GAME_ValidAttackSrc(iSrcCountry, FALSE) &&
263 	     GAME_ValidAttackDst(iSrcCountry, iDstCountry, FALSE) &&
264 	     GAME_ValidAttackDice(iDice, iSrcCountry))
265 	{
266 	  GAME_DoAttack(iSrcCountry, iDstCountry, fNotify);
267 
268 	  /* Only True the first time around */
269 	  fNotify = FALSE;
270 	}
271     }
272 }
273 
274 
275 /************************************************************************
276  *  FUNCTION: GAME_DoAttack
277  *  HISTORY:
278  *     03.04.94  ESF  Created.
279  *     03.06.94  ESF  Added missing pieces.
280  *     03.07.94  ESF  Fixed owner update bug & army subtraction bug.
281  *     03.18.94  ESF  Added server notification.
282  *     03.28.94  ESF  Added message when country is taken.
283  *     03.29.94  ESF  Added more informative moving message.
284  *     04.02.94  ESF  Fixed bug, darken country if wrong number of die.
285  *     04.02.94  ESF  Only notify server if fCacheNotify == FALSE.
286  *     05.04.94  ESF  Fixed bug, changed location of call to GAME_PlayerDied().
287  *     05.04.94  ESF  Fixed bug, when end of game occurs.
288  *     05.19.94  ESF  Added verbose notification when player takes country.
289  *     05.19.94  ESF  Moved calculation of dice correctness to ValidDice.
290  *     11.06.94  ESF  Cached results, so that Do-or-die runs quicker.
291  *     11.06.94  ESF  Added attack notification.
292  *     01.17.95  ESF  Changed fCacheNotify to fNotify.
293  *     07.09.95  JC   Fixed a bug with ENDOFMISSION and FORCEEXCHANGECARDS.
294  *  PURPOSE:
295  *  NOTES:
296  ************************************************************************/
297 void GAME_DoAttack(Int32 iSrcCountry, Int32 iDstCountry, Flag fNotify)
298 {
299   MsgAttackNotify  msgAttackNotify;
300   Int32            iAttackDie, iDefendDie, iArmiesWon, iArmiesMove;
301   Int32            iSrc, iDst, iPlayerAttackDie;
302   char buf[256];
303 
304   /* Cached values */
305   static Int32 iCachedSrcCountry=-1;
306   static Int32 iCachedDstCountry=-1;
307 
308   iPlayerAttackDie = RISK_GetDiceModeOfPlayer(iCurrentPlayer);
309 
310   /* If the dice have been selected automatically, calculate them */
311   if (iPlayerAttackDie != ATTACK_AUTO)
312     iAttackDie = iPlayerAttackDie+1;
313   else
314     iAttackDie = MIN(RISK_GetNumArmiesOfCountry(iSrcCountry)-1, 3);
315 
316   iDefendDie = MIN(RISK_GetNumArmiesOfCountry(iDstCountry), 2);
317 
318   /* Set the color of the dice if the attack has changed */
319   if (iCachedSrcCountry != iSrcCountry)
320       COLOR_CopyColor(COLOR_PlayerToColor(RISK_GetOwnerOfCountry(iSrcCountry)),
321 		      COLOR_DieToColor(0));
322   if (iCachedDstCountry != iDstCountry)
323       COLOR_CopyColor(COLOR_PlayerToColor(RISK_GetOwnerOfCountry(iDstCountry)),
324 		      COLOR_DieToColor(1));
325 
326   /* Get the number of armies that the attacker won */
327   iArmiesWon = DICE_Attack(iAttackDie, iDefendDie,
328 			   RISK_GetOwnerOfCountry(iSrcCountry),
329 			   RISK_GetOwnerOfCountry(iDstCountry));
330 
331   RISK_SetNumArmiesOfCountry(iDstCountry,
332 	      RISK_GetNumArmiesOfCountry(iDstCountry) - iArmiesWon);
333   RISK_SetNumArmiesOfCountry(iSrcCountry,
334 	      RISK_GetNumArmiesOfCountry(iSrcCountry) -
335 	      (MIN(iDefendDie, iAttackDie) - iArmiesWon));
336 
337   /* Country was taken */
338   if (!RISK_GetNumArmiesOfCountry(iDstCountry))
339     {
340       /* The attacking player gets a card */
341       fGetsCard = TRUE;
342 
343       /* Send a verbose message */
344 #ifdef ENGLISH
345       snprintf(buf, sizeof(buf), "%s captured %s from %s",
346 #endif
347 #ifdef FRENCH
348       snprintf(buf, sizeof(buf), "%s capture %s � partir de %s",
349 #endif
350 	      RISK_GetNameOfPlayer(iCurrentPlayer),
351 	      RISK_GetNameOfCountry(iDstCountry),
352 	      RISK_GetNameOfCountry(iSrcCountry));
353       mess.strMessage = buf;
354       (void)RISK_SendMessage(CLNT_GetCommLinkOfClient(CLNT_GetThisClientID()),
355 			     MSG_NETMESSAGE, &mess);
356 
357       /* Display informative message telling of victory */
358 #ifdef ENGLISH
359       snprintf(buf, sizeof(buf), "%s moving armies from %s to %s.",
360 	      RISK_GetNameOfPlayer(iCurrentPlayer),
361 	      RISK_GetNameOfCountry(iSrcCountry),
362 	      RISK_GetNameOfCountry(iDstCountry));
363 #endif
364 #ifdef FRENCH
365       snprintf(buf, sizeof(buf), "%s conqui�re %s � partir de %s.",
366 	      RISK_GetNameOfPlayer(iCurrentPlayer),
367 	      RISK_GetNameOfCountry(iDstCountry),
368 	      RISK_GetNameOfCountry(iSrcCountry));
369 #endif
370       UTIL_DisplayComment(buf);
371 
372       /* Update data structures */
373       iSrc = RISK_GetOwnerOfCountry(iSrcCountry);
374       RISK_SetNumCountriesOfPlayer(iSrc, RISK_GetNumCountriesOfPlayer(iSrc)+1);
375       iDst = RISK_GetOwnerOfCountry(iDstCountry);
376       RISK_SetNumCountriesOfPlayer(iDst, RISK_GetNumCountriesOfPlayer(iDst)-1);
377 
378       /* New owner */
379       RISK_SetOwnerOfCountry(iDstCountry, RISK_GetOwnerOfCountry(iSrcCountry));
380 
381       /* See if this victory signalled a _MSG_ENDOFMISSION condition */
382       if (GAME_IsMissionAccomplied(iCurrentPlayer, iDst))
383         {
384           MsgEndOfMission msg;
385 
386           msg.iWinner = iCurrentPlayer;
387           msg.iTyp  = RISK_GetMissionTypeOfPlayer(iCurrentPlayer);
388           msg.iNum1 = RISK_GetMissionContinent1OfPlayer(iCurrentPlayer);
389           msg.iNum2 = RISK_GetMissionContinent2OfPlayer(iCurrentPlayer);
390           RISK_SetMissionTypeOfPlayer(iCurrentPlayer, NO_MISSION);
391           (void)RISK_SendSyncMessage(CLNT_GetCommLinkOfClient(CLNT_GetThisClientID()),
392 			             MSG_ENDOFMISSION, &msg,
393 			             MSG_ENDOFMISSION, CBK_IncomingMessage);
394           /* If the winner stop the game ... */
395           if (iState == STATE_REGISTER)
396               return;
397         }
398 
399       /* Move the desired number of armies if it isn't end of game */
400       if (RISK_GetNumCountriesOfPlayer(iDst) != 0 ||
401 	  RISK_GetNumLivePlayers() != 2)
402 	{
403 	  iArmiesMove = UTIL_GetArmyNumber(iAttackDie,
404 				     RISK_GetNumArmiesOfCountry(iSrcCountry)-1,
405 				     FALSE);
406 	  RISK_SetNumArmiesOfCountry(iSrcCountry,
407 				     RISK_GetNumArmiesOfCountry(iSrcCountry) -
408 				     iArmiesMove);
409 	  RISK_SetNumArmiesOfCountry(iDstCountry,
410 				     RISK_GetNumArmiesOfCountry(iDstCountry) +
411 				     iArmiesMove);
412 	}
413 
414       /* See if this victory signalled a _DEADPLAYER or _ENDOFGAME condition */
415       if (RISK_GetNumCountriesOfPlayer(iDst) == 0)
416 	GAME_PlayerDied(iDst);
417     }
418   else
419     {
420       /* If a new attack and not do-or-die, notify the server */
421       if (!(iCachedSrcCountry == iSrcCountry &&
422 	    iCachedDstCountry == iDstCountry))
423 	{
424 	  /* Send a verbose message */
425 #ifdef ENGLISH
426 	  snprintf(buf, sizeof(buf), "%s is attacking from %s to %s",
427 		  RISK_GetNameOfPlayer(iCurrentPlayer),
428 		  RISK_GetNameOfCountry(iSrcCountry),
429 		  RISK_GetNameOfCountry(iDstCountry));
430 #endif
431 #ifdef FRENCH
432 	  snprintf(buf, sizeof(buf), "%s attaque %s � partir de %s",
433 		  RISK_GetNameOfPlayer(iCurrentPlayer),
434 		  RISK_GetNameOfCountry(iDstCountry),
435 		  RISK_GetNameOfCountry(iSrcCountry));
436 #endif
437 	  mess.strMessage = buf;
438 	  (void)RISK_SendMessage(CLNT_GetCommLinkOfClient(CLNT_GetThisClientID()),
439 				 MSG_NETMESSAGE, &mess);
440 	  UTIL_DisplayComment(buf);
441 	}
442     }
443 
444   /* If we are told to notify, then notify */
445   if (fNotify == TRUE)
446     {
447       msgAttackNotify.iSrcCountry = iSrcCountry;
448       msgAttackNotify.iDstCountry = iDstCountry;
449       (void)RISK_SendMessage(CLNT_GetCommLinkOfClient(CLNT_GetThisClientID()),
450 			     MSG_ATTACKNOTIFY, &msgAttackNotify);
451     }
452 
453   /* Update cached values */
454   iCachedSrcCountry = iSrcCountry;
455   iCachedDstCountry = iDstCountry;
456 }
457 
458 
459 /************************************************************************
460  *  FUNCTION: GAME_IsEnemyAdjacent
461  *  HISTORY:
462  *     03.05.94  ESF  Created.
463  *  PURPOSE:
464  *  NOTES:
465  ************************************************************************/
466 Flag GAME_IsEnemyAdjacent(Int32 iCountry)
467 {
468   Int32 i, iPlayer;
469 
470   iPlayer = RISK_GetOwnerOfCountry(iCountry);
471   for (i=0; i!=6 && RISK_GetAdjCountryOfCountry(iCountry, i)!=-1; i++)
472     if (RISK_GetOwnerOfCountry(RISK_GetAdjCountryOfCountry(iCountry, i)) !=
473 	iPlayer)
474       return TRUE;
475 
476   return FALSE;
477 }
478 
479 
480 /************************************************************************
481  *  FUNCTION: GAME_IsFrontierAdjacent
482  *  HISTORY:
483  *     03.08.95  JC  Created.
484  *  PURPOSE:
485  *  NOTES:
486  ************************************************************************/
487 Flag GAME_IsFrontierAdjacent(Int32 srcCountry, Int32 destCountry)
488 {
489   Int32 iPlayer, iContinent, iCountry, i;
490 
491   iPlayer = RISK_GetOwnerOfCountry(srcCountry);
492   iContinent = RISK_GetContinentOfCountry(srcCountry);
493   if (RISK_GetContinentOfCountry(destCountry) != iContinent)
494       return GAME_IsEnemyAdjacent(destCountry);
495   for (i=0; i!=6 && RISK_GetAdjCountryOfCountry(destCountry, i)!=-1; i++)
496     {
497       iCountry = RISK_GetAdjCountryOfCountry(destCountry, i);
498       if (RISK_GetContinentOfCountry(iCountry) != iContinent)
499           return TRUE;
500     }
501 
502   return FALSE;
503 }
504 
505 
506 /************************************************************************
507  *  FUNCTION: FindEnemyAdjacent
508  *  HISTORY:
509  *     11.08.95  JC  Created.
510  *  PURPOSE:
511  *  NOTES:
512  ************************************************************************/
513 Int32 FindEnemyAdjacent(Int32 iCountry, Int32 distance)
514 {
515   Int32 i, min, res, iPlayer, dest;
516 
517   iPlayer = RISK_GetOwnerOfCountry(iCountry);
518   min = 100000;
519   for (i=0; i!=6 && RISK_GetAdjCountryOfCountry(iCountry, i)!=-1; i++)
520     {
521       dest = RISK_GetAdjCountryOfCountry(iCountry, i);
522       if (RISK_GetOwnerOfCountry(dest) == iPlayer)
523         {
524           if (distance <= 3)
525             {
526               res = FindEnemyAdjacent(dest, distance + 1);
527               if (res < min)
528                   min = res;
529             }
530         }
531       else
532           min = 0;
533     }
534 
535   return (min + 1);
536 }
537 
538 
539 /************************************************************************
540  *  FUNCTION: GAME_FindEnemyAdjacent
541  *  HISTORY:
542  *     11.08.95  JC  Created.
543  *  PURPOSE:
544  *  NOTES:
545  ************************************************************************/
546 Int32 GAME_FindEnemyAdjacent(Int32 iCountry)
547 {
548   Int32 i, min, res, iPlayer, dest, destCountry;
549 
550   iPlayer = RISK_GetOwnerOfCountry(iCountry);
551   destCountry = -1;
552   min = 100000;
553   for (i=0; i!=6 && RISK_GetAdjCountryOfCountry(iCountry, i)!=-1; i++)
554     {
555       dest = RISK_GetAdjCountryOfCountry(iCountry, i);
556       if (RISK_GetOwnerOfCountry(dest) == iPlayer)
557         {
558           res = FindEnemyAdjacent(dest, 0);
559           if (res < min)
560             {
561               min = res;
562               destCountry = dest;
563             }
564         }
565       else
566           min = 0;
567     }
568 
569   return (destCountry);
570 }
571 
572 
573 /************************************************************************
574  *  FUNCTION: GAME_AttackClick
575  *  HISTORY:
576  *     03.06.94  ESF  Created.
577  *     04.02.94  ESF  Added notification of server after Do-or-Die.
578  *     05.19.94  ESF  Added verbose message across network.
579  *     05.19.94  ESF  Fixed for fixed attack dice do-or-die.
580  *     07.14.94  ESF  Fixed bug, bot checking attack dice on dest country.
581  *     10.15.94  ESF  Added printing of "Attacking from foo to bar" locally.
582  *  PURPOSE:
583  *  NOTES:
584  ************************************************************************/
585 void GAME_AttackClick(Int32 iCountry)
586 {
587   char buf[256];
588   if (iAttackSrc < 0)
589     {
590       if (GAME_ValidAttackSrc(iCountry, TRUE) &&
591 	  GAME_ValidAttackDice(RISK_GetDiceModeOfPlayer(iCurrentPlayer),
592 			       iCountry))
593 	{
594 	  iAttackSrc = iCountry;
595 
596 #ifdef ENGLISH
597 	  snprintf(buf, sizeof(buf), "%s is attacking from %s to"
598 		  " <click on territory>",
599 #endif
600 #ifdef FRENCH
601 	  snprintf(buf, sizeof(buf), "%s attaque � partir de %s ",
602 #endif
603 		  RISK_GetNameOfPlayer(iCurrentPlayer),
604 		  RISK_GetNameOfCountry(iAttackSrc));
605 	  UTIL_DisplayComment(buf);
606 	  UTIL_LightCountry(iAttackSrc);
607 	}
608     }
609   else if (GAME_ValidAttackDst(iAttackSrc, iCountry, TRUE) &&
610 	   GAME_ValidAttackDice(RISK_GetDiceModeOfPlayer(iCurrentPlayer),
611 				iAttackSrc))
612     {
613       iAttackDst = iCountry;
614       GAME_Attack(iAttackSrc, iAttackDst);
615 
616       iAttackSrc = iAttackDst = -1;
617       UTIL_DisplayActionCString(iState, iCurrentPlayer);
618     }
619 }
620 
621 
622 /************************************************************************
623  *  FUNCTION: GAME_ValidAttackDice
624  *  HISTORY:
625  *     05.19.94  ESF  Created.
626  *  PURPOSE:
627  *  NOTES:
628  ************************************************************************/
629 Flag GAME_ValidAttackDice(Int32 iAttackDice, Int32 iCountry)
630 {
631   char buf[256];
632   /* If the dice have been selected manually, check them */
633   if (iAttackDice != ATTACK_AUTO)
634     {
635       if (RISK_GetNumArmiesOfCountry(iCountry) <= iAttackDice+1)
636 	{
637 #ifdef ENGLISH
638 	  snprintf(buf, sizeof(buf), "You can't attack with %d dice, dummy.",
639 #endif
640 #ifdef FRENCH
641 	  snprintf(buf, sizeof(buf), "Attaque impossible avec %d d�(s).",
642 #endif
643 		  iAttackDice+1);
644 	  UTIL_DarkenCountry(iCountry);
645 	  UTIL_DisplayError(buf);
646 	  return FALSE;
647 	}
648     }
649   return TRUE;
650 }
651 
652 
653 /************************************************************************
654  *  FUNCTION: GAME_ValidAttackSrc
655  *  HISTORY:
656  *     03.06.94  ESF  Created.
657  *     03.07.94  ESF  Added verbose option
658  *  PURPOSE:
659  *  NOTES:
660  ************************************************************************/
661 Flag GAME_ValidAttackSrc(Int32 iAttackSrc, Flag fVerbose)
662 {
663   char buf[256];
664   if (iAttackSrc < 0)
665     {
666       if (fVerbose)
667 #ifdef ENGLISH
668 	UTIL_DisplayError("Where the hell are you trying to attack from?");
669 #endif
670 #ifdef FRENCH
671 	UTIL_DisplayError("D'o� voulez-vous attaquer?");
672 #endif
673     }
674   else if (iAttackSrc >= NUM_COUNTRIES)
675     {
676       if (fVerbose)
677 #ifdef ENGLISH
678 	UTIL_DisplayError("You can't attack from the ocean!");
679 #endif
680 #ifdef FRENCH
681 	UTIL_DisplayError("Attaque impossible � partir de l'oc�an!");
682 #endif
683     }
684   else if (RISK_GetOwnerOfCountry(iAttackSrc) != iCurrentPlayer)
685     {
686       if (fVerbose)
687 	{
688 #ifdef ENGLISH
689 	  snprintf(buf, sizeof(buf), "You can't attack from %s -- you don't own it.",
690 #endif
691 #ifdef FRENCH
692 	  snprintf(buf, sizeof(buf), "Attaque impossible � partir de %s.",
693 #endif
694 		  RISK_GetNameOfCountry(iAttackSrc));
695 	  UTIL_DisplayError(buf);
696 	}
697     }
698   else if (!GAME_IsEnemyAdjacent(iAttackSrc))
699     {
700       if (fVerbose)
701 	{
702 #ifdef ENGLISH
703 	  snprintf(buf, sizeof(buf), "There are no enemy territories you can attack from %s.",
704 #endif
705 #ifdef FRENCH
706 	  snprintf(buf, sizeof(buf), "Pas de territoire � attaquer � partir de %s.",
707 #endif
708 		  RISK_GetNameOfCountry(iAttackSrc));
709 	  UTIL_DisplayError(buf);
710 	}
711     }
712   else if (RISK_GetNumArmiesOfCountry(iAttackSrc) == 1)
713     {
714       if (fVerbose)
715 #ifdef ENGLISH
716 	UTIL_DisplayError("You can't attack with 1 army.");
717 #endif
718 #ifdef FRENCH
719 	UTIL_DisplayError("Attaque impossible avec une seule arm�e.");
720 #endif
721     }
722   else
723     return TRUE;
724 
725   return FALSE;
726 }
727 
728 
729 /************************************************************************
730  *  FUNCTION: GAME_ValidAttackDst
731  *  HISTORY:
732  *     03.06.94  ESF  Created.
733  *     03.07.94  ESF  Added verbose option
734  *  PURPOSE:
735  *  NOTES:
736  ************************************************************************/
737 Flag GAME_ValidAttackDst(Int32 iAttackSrc, Int32 iAttackDst, Flag fVerbose)
738 {
739   char buf[256];
740   if (iAttackDst < 0)
741     {
742       if (fVerbose)
743 #ifdef ENGLISH
744 	UTIL_DisplayError("Where the hell are you trying to attack from?");
745 #endif
746 #ifdef FRENCH
747 	UTIL_DisplayError("O� voulez-vous attaquer?");
748 #endif
749     }
750   else if (iAttackDst >= NUM_COUNTRIES)
751     {
752       if (fVerbose)
753 #ifdef ENGLISH
754 	UTIL_DisplayError("You can't attack the ocean!");
755 #endif
756 #ifdef FRENCH
757 	UTIL_DisplayError("Impossible d'attaquer l'oc�an!");
758 #endif
759     }
760   else
761     {
762       if (!GAME_CanAttack(iAttackSrc, iAttackDst))
763 	{
764 	  if (fVerbose)
765 	    {
766 #ifdef ENGLISH
767 	      snprintf(buf, sizeof(buf), "You can't attack %s from %s!",
768 #endif
769 #ifdef FRENCH
770 	      snprintf(buf, sizeof(buf), "Attaque impossible de %s � partir de %s!",
771 #endif
772 		      RISK_GetNameOfCountry(iAttackDst),
773 		      RISK_GetNameOfCountry(iAttackSrc));
774 	      UTIL_DisplayError(buf);
775 	    }
776 	}
777       else if (RISK_GetOwnerOfCountry(iAttackDst) == iCurrentPlayer)
778 	{
779 	  if (fVerbose)
780 	    {
781 #ifdef ENGLISH
782 	      snprintf(buf, sizeof(buf), "You can't attack %s -- you own it.",
783 #endif
784 #ifdef FRENCH
785 	      snprintf(buf, sizeof(buf), "Attaque impossible de son propre territoire (%s).",
786 #endif
787 		      RISK_GetNameOfCountry(iAttackDst));
788 	      UTIL_DisplayError(buf);
789 	    }
790 	}
791       else
792 	return TRUE;
793     }
794 
795   return FALSE;
796 }
797 
798 
799 /************************************************************************
800  *  FUNCTION: GAME_PlaceClick
801  *  HISTORY:
802  *     03.07.94  ESF  Created.
803  *     03.16.94  ESF  Added support for placing multiple armies.
804  *     05.19.94  ESF  Factored out code to GAME_PlaceArmies.
805  *     04.30.95  ESF  Brought the dialog code from PlaceArmies here.
806  *  PURPOSE:
807  *  NOTES:
808  ************************************************************************/
809 void GAME_PlaceClick(Int32 iCountry, Int32 iPlaceType)
810 {
811     Int32 maxN;
812   /* Is the country picked the player's? */
813   if (GAME_ValidPlaceDst(iCountry))  {
814       Int32 iArmies;
815 
816       maxN = RISK_GetNumArmiesOfPlayer(iCurrentPlayer);
817 #ifndef DROPALL
818       if ( iState == STATE_FORTIFY )
819 	maxN = (maxN > DROP_ARMIES) ? DROP_ARMIES : maxN;
820 #endif
821 
822       /* Depending on the type of placement, popup a dialog or not */
823       if (iPlaceType == PLACE_MULTIPLE)
824       {
825 	  iArmies = UTIL_GetArmyNumber(1, maxN, TRUE);
826 	  if (!iArmies)
827 	    return;
828 	}
829       else if (iPlaceType == PLACE_ALL)
830 	iArmies = maxN;
831       else
832 	iArmies = 1;
833 
834       GAME_PlaceArmies(iCountry, iArmies);
835 
836       /* If we're fortifying, we're done. */
837       if (iState == STATE_FORTIFY)
838 	GAME_EndTurn();
839     }
840 }
841 
842 
843 /************************************************************************
844  *  FUNCTION: GAME_ValidPlaceDst
845  *  HISTORY:
846  *     03.07.94  ESF  Created.
847  *  PURPOSE:
848  *  NOTES:
849  ************************************************************************/
850 Flag GAME_ValidPlaceDst(Int32 iPlaceDst)
851 {
852   if (iPlaceDst < 0)
853 #ifdef ENGLISH
854     UTIL_DisplayError("What the hell country is that!");
855 #endif
856 #ifdef FRENCH
857     UTIL_DisplayError("What the hell country is that!");
858 #endif
859   else if (iPlaceDst >= NUM_COUNTRIES)
860 #ifdef ENGLISH
861     UTIL_DisplayError("Ahhh...That's the ocean, buddy...");
862 #endif
863 #ifdef FRENCH
864     UTIL_DisplayError("Ahhh...C'est l'oc�an, plouf...");
865 #endif
866   else if (RISK_GetOwnerOfCountry(iPlaceDst) != iCurrentPlayer)
867 #ifdef ENGLISH
868     UTIL_DisplayError("You cannot place armies on opponent's territories.");
869 #endif
870 #ifdef FRENCH
871     UTIL_DisplayError("Donner des arm�es � un autre joueur?");
872 #endif
873   else
874     return TRUE;
875 
876   return FALSE;
877 }
878 
879 
880 /************************************************************************
881  *  FUNCTION: GAME_MoveClick
882  *  HISTORY:
883  *     03.07.94  ESF  Created.
884  *     03.29.94  ESF  Added a message when iMoveDst is verified.
885  *     03.29.94  ESF  Fixed lack of UTIL_DisplayComment() bug.
886  *     01.09.95  JC   End turn only if iState asn't moved to STATE_REGISTER.
887  *  PURPOSE:
888  *  NOTES:
889  ************************************************************************/
890 void GAME_MoveClick(Int32 iCountry)
891 {
892   Int32 iNumArmies;
893   char buf[256];
894 
895   if (iMoveSrc < 0)
896     {
897       if (GAME_ValidMoveSrc(iCountry))
898 	{
899 	  iMoveSrc = iCountry;
900 
901 #ifdef ENGLISH
902 	  snprintf(buf, sizeof(buf), "%s moving armies from %s to"
903 		  " <click on territory>",
904 #endif
905 #ifdef FRENCH
906 	  snprintf(buf, sizeof(buf), "%s d�place des arm�es de %s en"
907 		  " <click on territory>",
908 #endif
909 		  RISK_GetNameOfPlayer(iCurrentPlayer),
910 		  RISK_GetNameOfCountry(iMoveSrc));
911 	  UTIL_DisplayComment(buf);
912 	  UTIL_LightCountry(iMoveSrc);
913 	}
914     }
915   else if (GAME_ValidMoveDst(iMoveSrc, iCountry))
916     {
917       iMoveDst = iCountry;
918 
919 #ifdef ENGLISH
920       snprintf(buf, sizeof(buf), "%s moving armies from %s to %s.",
921 #endif
922 #ifdef FRENCH
923       snprintf(buf, sizeof(buf), "%s d�place des arm�es de %s en %s.",
924 #endif
925 	      RISK_GetNameOfPlayer(iCurrentPlayer),
926 	      RISK_GetNameOfCountry(iMoveSrc),
927 	      RISK_GetNameOfCountry(iMoveDst));
928       UTIL_DisplayComment(buf);
929 
930       iNumArmies = UTIL_GetArmyNumber(1,
931 				      RISK_GetNumArmiesOfCountry(iMoveSrc)-1,
932 				      TRUE);
933       if (iNumArmies>0)
934 	{
935 	  GAME_MoveArmies(iMoveSrc, iMoveDst, iNumArmies);
936 
937           if (iState != STATE_REGISTER)
938 	      /* Turn over, man! */
939 	      GAME_EndTurn();
940 	}
941       else
942 	{
943 	  UTIL_DarkenCountry(iMoveSrc);
944 	  iMoveSrc = iMoveDst = -1;
945 	}
946     }
947 }
948 
949 
950 /************************************************************************
951  *  FUNCTION: GAME_ValidMoveSrc
952  *  HISTORY:
953  *     03.07.94  ESF  Created.
954  *     03.29.94  ESF  fixed a small bug, inserted "else".
955  *  PURPOSE:
956  *  NOTES:
957  ************************************************************************/
958 Flag GAME_ValidMoveSrc(Int32 iMoveSrc)
959 {
960   if (iMoveSrc < 0)
961 #ifdef ENGLISH
962     UTIL_DisplayError("Where the hell are you trying to move from?");
963 #endif
964 #ifdef FRENCH
965     UTIL_DisplayError("Where the hell are you trying to move from?");
966 #endif
967   else if (iMoveSrc >= NUM_COUNTRIES)
968 #ifdef ENGLISH
969     UTIL_DisplayError("You can't move armies from the ocean.");
970 #endif
971 #ifdef FRENCH
972     UTIL_DisplayError("Impossible de d�placer des arm�es � partir de l'oc�an.");
973 #endif
974   else if (RISK_GetOwnerOfCountry(iMoveSrc) != iCurrentPlayer)
975 #ifdef ENGLISH
976     UTIL_DisplayError("You cannot move armies from an opponent's"
977 			" territories.");
978 #endif
979 #ifdef FRENCH
980     UTIL_DisplayError("Impossible de prendre les arm�es d'un autre joueur.");
981 #endif
982   else if (RISK_GetNumArmiesOfCountry(iMoveSrc) == 1)
983 #ifdef ENGLISH
984     UTIL_DisplayError("You cannot move from territories that"
985 		      " have one army to begin with.");
986 #endif
987 #ifdef FRENCH
988     UTIL_DisplayError("Impossible de d�placer la seule arm�e d'un territoire.");
989 #endif
990   else
991     return TRUE;
992 
993   return FALSE;
994 }
995 
996 
997 /************************************************************************
998  *  FUNCTION: GAME_ValidMoveDst
999  *  HISTORY:
1000  *     03.07.94  ESF  Created.
1001  *  PURPOSE:
1002  *  NOTES:  used to get iMoveDst passed, which is a global static in game.c
1003  ************************************************************************/
1004 Flag GAME_ValidMoveDst(Int32 iMoveSrc, Int32 iMoveDst)
1005 {
1006   char buf[256];
1007   if (iMoveDst < 0)
1008 #ifdef ENGLISH
1009     UTIL_DisplayError("Where the hell are you trying to move from?");
1010 #endif
1011 #ifdef FRENCH
1012     UTIL_DisplayError("Where the hell are you trying to move from?");
1013 #endif
1014   else if (iMoveDst >= NUM_COUNTRIES)
1015 #ifdef ENGLISH
1016     UTIL_DisplayError("You can't move armies into the ocean -- they'd drown.");
1017 #endif
1018 #ifdef FRENCH
1019     UTIL_DisplayError("Impossible de placer des arm�es dans l'oc�an.");
1020 #endif
1021   else if (RISK_GetOwnerOfCountry(iMoveDst) != iCurrentPlayer)
1022 #ifdef ENGLISH
1023     UTIL_DisplayError("You cannot move armies to an opponent's"
1024 		      " territories.");
1025 #endif
1026 #ifdef FRENCH
1027     UTIL_DisplayError("Impossible de placer des arm�es sur un territoire ennemi.");
1028 #endif
1029   else if (!GAME_CanAttack(iMoveSrc, iMoveDst))
1030     {
1031 #ifdef ENGLISH
1032       snprintf(buf, sizeof(buf), "Armies can't get to %s from %s",
1033 #endif
1034 #ifdef FRENCH
1035       snprintf(buf, sizeof(buf), "D�placement impossible de %s en %s",
1036 #endif
1037 	      RISK_GetNameOfCountry(iMoveDst),
1038 	      RISK_GetNameOfCountry(iMoveSrc));
1039       UTIL_DisplayError(buf);
1040     }
1041   else
1042     return TRUE;
1043 
1044   return FALSE;
1045 }
1046 
1047 
1048 /************************************************************************
1049  *  FUNCTION: GAME_GetContinentBonus
1050  *  HISTORY:
1051  *     03.16.94  ESF  Created.
1052  *     01.09.95  ESF  Changed an if..else to an assertion.
1053  *  PURPOSE:
1054  *  NOTES:
1055  ************************************************************************/
1056 Int32 GAME_GetContinentBonus(Int32 iPlayer)
1057 {
1058   Int32  piCount[NUM_CONTINENTS];
1059   Int32  i, iArmies=0;
1060 
1061   /* Init. */
1062   for (i=0; i!=NUM_CONTINENTS; i++)
1063     piCount[i] = 0;
1064 
1065   /* Count up how many countries the player has in each of the continents */
1066   for (i=0; i!=NUM_COUNTRIES; i++)
1067     if (RISK_GetOwnerOfCountry(i) == iPlayer)
1068       {
1069 	/* Sanity check */
1070 	D_Assert(RISK_GetContinentOfCountry(i) >= 0 &&
1071 		 RISK_GetContinentOfCountry(i) < NUM_CONTINENTS,
1072 		 "Country has messed up number of armies.");
1073 
1074 	piCount[RISK_GetContinentOfCountry(i)]++;
1075       }
1076 
1077   /* If the player has the total number of countries, give him or her bonus */
1078   for (i=0; i!=NUM_CONTINENTS; i++)
1079     if (RISK_GetNumCountriesOfContinent(i) == piCount[i])
1080       iArmies += RISK_GetValueOfContinent(i);
1081 
1082   return(iArmies);
1083 }
1084 
1085 
1086 /************************************************************************
1087  *  FUNCTION: GAME_PlayerDied
1088  *  HISTORY:
1089  *     03.28.94  ESF  Created.
1090  *     03.29.94  ESF  Fixed off-by-one bug in end of game detection.
1091  *     04.11.94  ESF  Added iKillerPlayer parameter.
1092  *     05.04.94  ESF  Fixed bugs and exhanced.
1093  *     05.12.94  ESF  Fixed bug, reset dead player's cards to 0.
1094  *     09.31.94  ESF  Changed because of new ENDOFGAME contents.
1095  *     10.02.94  ESF  Changed to set number of live players == 0.
1096  *     10.30.94  ESF  Fixed bug, shouldn't be setting iNumLivePlayers to 0.
1097  *     01.09.95  ESF  Changed to be more verbose.
1098  *     30.08.95  JC   Talk the server: "force exchange of cards?".
1099  *  PURPOSE:
1100  *  NOTES:
1101  ************************************************************************/
1102 void GAME_PlayerDied(Int32 iDeadPlayer)
1103 {
1104   MsgMessagePacket msg;
1105   char buf[256];
1106 
1107   /* Notify everybody */
1108 #ifdef ENGLISH
1109   snprintf(buf, sizeof(buf), "%s was destroyed by %s (who gained %d card%s).",
1110 #endif
1111 #ifdef FRENCH
1112   snprintf(buf, sizeof(buf), "%s est d�truit par %s (qui gagne %d carte%s).",
1113 #endif
1114 	  RISK_GetNameOfPlayer(iDeadPlayer),
1115 	  RISK_GetNameOfPlayer(iCurrentPlayer),
1116 	  RISK_GetNumCardsOfPlayer(iDeadPlayer),
1117 	  (RISK_GetNumCardsOfPlayer(iDeadPlayer)>1)?"s":"");
1118   msg.strMessage = buf;
1119   msg.iFrom = FROM_SERVER;
1120   msg.iTo = DST_ALLPLAYERS;
1121   (void)RISK_SendMessage(CLNT_GetCommLinkOfClient(CLNT_GetThisClientID()),
1122 			 MSG_MESSAGEPACKET, &msg);
1123 
1124   /* Kill the player  */
1125   RISK_SetStateOfPlayer(iDeadPlayer, PLAYER_DEAD);
1126 
1127   /* Is there only one player left?  If so, end of game... */
1128   if (RISK_GetNumLivePlayers() == 1)
1129     {
1130       MsgVictory  msgVictory;
1131 
1132       msgVictory.iWinner = iCurrentPlayer;
1133       (void)RISK_SendMessage(CLNT_GetCommLinkOfClient(CLNT_GetThisClientID()),
1134 			     MSG_VICTORY, &msgVictory);
1135     }
1136   else
1137     {
1138       MsgForceExchangeCards msg;
1139       Int32 i, n, m;
1140 
1141       /* Give the killer player all of the cards */
1142       n = RISK_GetNumCardsOfPlayer(iCurrentPlayer);
1143       m = RISK_GetNumCardsOfPlayer(iDeadPlayer);
1144 
1145       /* Let the player know how many cards he or she got. */
1146       if (m>0)
1147 	{
1148 #ifdef ENGLISH
1149 	  snprintf(buf, sizeof(buf), "%s got %d card%s from %s.",
1150 #endif
1151 #ifdef FRENCH
1152 	  snprintf(buf, sizeof(buf), "%s prend %d carte%s de %s.",
1153 #endif
1154 		  RISK_GetNameOfPlayer(iCurrentPlayer),
1155 		  m, m==1?"":"s", RISK_GetNameOfPlayer(iDeadPlayer));
1156 	  mess.strMessage = buf;
1157 	  (void)RISK_SendMessage(CLNT_GetCommLinkOfClient(CLNT_GetThisClientID()),
1158 				 MSG_NETMESSAGE, &mess);
1159 	}
1160 
1161       for (i=0; i!=m; i++)
1162 	RISK_SetCardOfPlayer(iCurrentPlayer, n+i,
1163 			     RISK_GetCardOfPlayer(iDeadPlayer, i));
1164       RISK_SetNumCardsOfPlayer(iCurrentPlayer, n+m);
1165       RISK_SetNumCardsOfPlayer(iDeadPlayer, 0);
1166 
1167       if (m>0)
1168 	{
1169           /* Force the player to exchange if he or she possesses
1170            * too many cards.
1171            */
1172           msg.iPlayer = iCurrentPlayer;
1173           (void)RISK_SendMessage(CLNT_GetCommLinkOfClient(CLNT_GetThisClientID()),
1174                                  MSG_FORCEEXCHANGECARDS, &msg);
1175 	}
1176     }
1177 }
1178 
1179 
1180 /************************************************************************
1181  *  FUNCTION: GAME_MissionToStr
1182  *  HISTORY:
1183  *     29.08.95  JC  Created (copy of GAME_ShowMission).
1184  *  PURPOSE: Put in strScratch a description of the mission
1185  *  NOTES:
1186  ************************************************************************/
1187 void GAME_MissionToStr(Int32 iPlayer, Int16 iTyp, Int32 iNum1, Int32 iNum2, Flag fVict, char *buf, size_t bufsize)
1188 {
1189   UNUSED(iPlayer);
1190 
1191 #ifdef FRENCH
1192   switch (iTyp)
1193     {
1194     case NO_MISSION:
1195       snprintf(buf, bufsize, "Plus de mission -> Conquerir le monde");
1196       break;
1197     case CONQUIER_WORLD:
1198       if (fVict)
1199           snprintf(buf, bufsize, "Mission accomplie: le monde est conquit");
1200       else
1201           snprintf(buf, bufsize, "Mission: Conquerir le monde");
1202       break;
1203     case CONQUIER_Nb_COUNTRY:
1204       if (fVict)
1205           snprintf(buf, bufsize, "Mission accomplie: %d territoires conquis",
1206                               iNum1);
1207       else
1208           snprintf(buf, bufsize, "Mission: Conquerir %d territoires",
1209                               iNum1);
1210       break;
1211     case CONQUIER_TWO_CONTINENTS:
1212       if (fVict)
1213           snprintf(buf, bufsize, "Mission accomplie: Conquerir %s et %s",
1214               RISK_GetNameOfContinent(iNum1),
1215               RISK_GetNameOfContinent(iNum2));
1216       else
1217           snprintf(buf, bufsize, "Mission: Conquerir %s et %s",
1218               RISK_GetNameOfContinent(iNum1),
1219               RISK_GetNameOfContinent(iNum2));
1220       break;
1221     case KILL_A_PLAYER:
1222       if (fVict || iNum2)
1223           snprintf(buf, bufsize, "Mission accomplie: %s est mort",
1224               RISK_GetNameOfPlayer(iNum1));
1225       else if (RISK_GetNumCountriesOfPlayer(iNum1) <= 0)
1226           snprintf(buf, bufsize, "Mission impossible: Tuer %s qui est d�j� mort",
1227               RISK_GetNameOfPlayer(iNum1));
1228       else
1229           snprintf(buf, bufsize, "Mission: Tuer %s",
1230               RISK_GetNameOfPlayer(iNum1));
1231       break;
1232     }
1233 #endif
1234 #ifdef ENGLISH
1235   switch (iTyp)
1236     {
1237     case NO_MISSION:
1238       snprintf(buf, bufsize, "Additional mission -> Conquer the world");
1239       break;
1240     case CONQUIER_WORLD:
1241       if (fVict)
1242           snprintf(buf, bufsize, "Mission accomplished: the world is conquered");
1243       else
1244           snprintf(buf, bufsize, "Mission: Conquer the world");
1245       break;
1246     case CONQUIER_Nb_COUNTRY:
1247       if (fVict)
1248           snprintf(buf, bufsize, "Mission accomplished: %d countries conquered",
1249                               iNum1);
1250       else
1251           snprintf(buf, bufsize, "Mission: Conquer %d countries",
1252                               iNum1);
1253       break;
1254     case CONQUIER_TWO_CONTINENTS:
1255       if (fVict)
1256           snprintf(buf, bufsize, "Mission accomplished: Conquer %s and %s",
1257               RISK_GetNameOfContinent(iNum1),
1258               RISK_GetNameOfContinent(iNum2));
1259       else
1260           snprintf(buf, bufsize, "Mission: Conquer %s and %s",
1261               RISK_GetNameOfContinent(iNum1),
1262               RISK_GetNameOfContinent(iNum2));
1263       break;
1264     case KILL_A_PLAYER:
1265       if (fVict || iNum2)
1266           snprintf(buf, bufsize, "Mission accomplished: %s is dead",
1267               RISK_GetNameOfPlayer(iNum1));
1268       else if (RISK_GetNumCountriesOfPlayer(iNum1) <= 0)
1269           snprintf(buf, bufsize, "Mission impossible: kill %s who's already dead",
1270               RISK_GetNameOfPlayer(iNum1));
1271       else
1272           snprintf(buf, bufsize, "Mission: Kill %s",
1273               RISK_GetNameOfPlayer(iNum1));
1274       break;
1275     }
1276 #endif
1277 }
1278 
1279 
1280 /************************************************************************
1281  *  FUNCTION: GAME_MissionAccomplied
1282  *  HISTORY:
1283  *     25.08.95  JC   Created from different pieces.
1284  *  PURPOSE:
1285  *  NOTES:
1286  ************************************************************************/
1287 void GAME_MissionAccomplied(Int32 iWinner, Int16 iTyp, Int32 iNum1, Int32 iNum2)
1288 {
1289   Char  str[256];
1290   Int32 iChoice;
1291   char buf[256];
1292 
1293   GAME_MissionToStr(iWinner, iTyp, iNum1, iNum2, TRUE, buf, sizeof(buf));
1294   if (RISK_GetClientOfPlayer(iWinner) != CLNT_GetThisClientID())
1295     {
1296       /* Player that has won is non-local */
1297 #ifdef ENGLISH
1298       snprintf(str, sizeof(str),
1299 	       "%s has accomplied his mission!\n%s\n",
1300 	       RISK_GetNameOfPlayer(iCurrentPlayer),
1301 	       buf);
1302       (void)UTIL_PopupDialog("End of Mission", str, 2, "Cool!",
1303                              "So What?", NULL);
1304 #endif
1305 #ifdef FRENCH
1306       snprintf(str, sizeof(str),
1307 	       "%s a termin� sa mission!\n%s\n",
1308 	       RISK_GetNameOfPlayer(iCurrentPlayer),
1309 	       buf);
1310       (void)UTIL_PopupDialog("Mission termin�e", str, 2, "Cool!",
1311                              "Et alors?", NULL);
1312 #endif
1313       return;
1314     }
1315 
1316   /* Winning player is local, congratulate him or her */
1317 #ifdef ENGLISH
1318   (void)UTIL_PopupDialog(RISK_GetNameOfPlayer(iCurrentPlayer),
1319                          "You WON!!!", 2, "Cool!",
1320                          "So What?", NULL);
1321 #endif
1322 #ifdef FRENCH
1323   (void)UTIL_PopupDialog(RISK_GetNameOfPlayer(iCurrentPlayer),
1324                          "Victoire!!!", 2, "Cool!",
1325                          "Et alors?", NULL);
1326 #endif
1327 
1328   /* See if the player wants to continue or play again */
1329 #ifdef ENGLISH
1330   if (RISK_GetNumLivePlayers () > 1)
1331       iChoice = UTIL_PopupDialog("Game over", "Play again?",
1332                                  3, "Yes", "No", "Continue");
1333   else
1334       iChoice = UTIL_PopupDialog("Game over", "Play again?",
1335                                  2, "Yes", "No", NULL);
1336 #endif
1337 #ifdef FRENCH
1338   if (RISK_GetNumLivePlayers () > 1)
1339       iChoice = UTIL_PopupDialog("Partie termin�e", "Jouer une autre partie?",
1340                                  3, "Oui", "Non", "Continuer");
1341   else
1342       iChoice = UTIL_PopupDialog("Partie termin�e", "Jouer une autre partie?",
1343                                  2, "Oui", "Non", NULL);
1344 #endif
1345   if (iChoice == QUERY_NO)
1346     {
1347       /* Leave the game */
1348       UTIL_ExitProgram(0);
1349     }
1350   if (iChoice == QUERY_CANCEL)
1351       return;
1352 
1353   iState = STATE_REGISTER;
1354   (void)RISK_SendMessage(CLNT_GetCommLinkOfClient(CLNT_GetThisClientID()),
1355 			 MSG_ENDOFGAME, NULL);
1356 }
1357 
1358 
1359 /************************************************************************
1360  *  FUNCTION: GAME_Victory
1361  *  HISTORY:
1362  *     28.08.95  JC   Created from different pieces.
1363  *  PURPOSE:
1364  *  NOTES:
1365  ************************************************************************/
1366 void GAME_Victory(Int32 iWinner)
1367 {
1368   Int32 iChoice;
1369   char buf[256];
1370 
1371   if (RISK_GetClientOfPlayer(iWinner) != CLNT_GetThisClientID())
1372     {
1373       /* Player that has won is non-local */
1374 #ifdef ENGLISH
1375       snprintf(buf, sizeof(buf), "%s has won!", RISK_GetNameOfPlayer(iCurrentPlayer));
1376       (void)UTIL_PopupDialog("End of Game", buf, 2, "Cool!",
1377                              "So What?", NULL);
1378 #endif
1379 #ifdef FRENCH
1380       snprintf(buf, sizeof(buf), "%s a gagn�!", RISK_GetNameOfPlayer(iCurrentPlayer));
1381       (void)UTIL_PopupDialog("Fin du jeu", buf, 2, "Cool!",
1382                              "Et alors?", NULL);
1383 #endif
1384       return;
1385     }
1386 
1387   /* Winning player is local, congratulate him or her */
1388 #ifdef ENGLISH
1389   (void)UTIL_PopupDialog(RISK_GetNameOfPlayer(iCurrentPlayer),
1390                          "You WON!!!", 2, "Cool!",
1391                          "So What?", NULL);
1392 #endif
1393 #ifdef FRENCH
1394   (void)UTIL_PopupDialog(RISK_GetNameOfPlayer(iCurrentPlayer),
1395                          "Victoire!!!", 2, "Cool!",
1396                          "Et alors?", NULL);
1397 #endif
1398 
1399   /* See if the player wants to continue or play again */
1400 #ifdef ENGLISH
1401   iChoice = UTIL_PopupDialog("Game over", "Play again?",
1402                              2, "Yes", "No", NULL);
1403 #endif
1404 #ifdef FRENCH
1405   iChoice = UTIL_PopupDialog("Partie termin�e", "Jouer une autre partie?",
1406                              2, "Oui", "Non", NULL);
1407 #endif
1408   if (iChoice == QUERY_NO)
1409     {
1410       /* Leave the game */
1411       UTIL_ExitProgram(0);
1412     }
1413 
1414   iState = STATE_REGISTER;
1415   (void)RISK_SendMessage(CLNT_GetCommLinkOfClient(CLNT_GetThisClientID()),
1416 			 MSG_ENDOFGAME, NULL);
1417 }
1418 
1419 
1420 /************************************************************************
1421  *  FUNCTION: GAME_GameOverMan
1422  *  HISTORY:
1423  *     03.28.94  ESF  Created.
1424  *     05.10.94  ESF  Completed.
1425  *     05.12.94  ESF  Added more functionality.
1426  *     01.05.95  DFE  Fixed "Free Card" bug -- gave 1st person free card.
1427  *     02.13.95  ESF  Updated to reflect new registration interface.
1428  *  PURPOSE:
1429  *  NOTES:
1430  ************************************************************************/
1431 void GAME_GameOverMan(void)
1432 {
1433   /* There will be another game */
1434   fGameStarted = FALSE;
1435 
1436   /* Since EndTurn isn't called, need to reset this so that first player
1437    * doesn't get a free card next game.
1438    */
1439   fGetsCard    = FALSE;
1440 
1441   /* The state will be one of registering */
1442   if (iState != STATE_REGISTER)
1443     {
1444       iState = STATE_REGISTER;
1445       UTIL_ServerEnterState(iState);
1446     }
1447 
1448   UTIL_DisplayError("");
1449   UTIL_DisplayComment("");
1450 
1451   /* Set the colors to be of the initial setup */
1452   COLOR_SetWorldColors();
1453 
1454   /* Erase the dice roll */
1455   DICE_Hide();
1456 
1457   /* Get the new players */
1458   REG_PopupDialog();
1459 }
1460 
1461 
1462 /************************************************************************
1463  *  FUNCTION: GAME_ExchangeCards
1464  *  HISTORY:
1465  *     03.29.94  ESF  Created.
1466  *     04.23.95  ESF  Fixed (terrible) card take-away bug.
1467  *     05.13.95  ESF  Fixed (horrible) country bonus bug -- thanks Alan!
1468  *     22.08.95  JC   Fixed a bug with computerized player
1469  *                    (piCards not ordered).
1470  *  PURPOSE:
1471  *  NOTES:
1472  ************************************************************************/
1473 void GAME_ExchangeCards(Int32 *piCards)
1474 {
1475   Int32             i, j, k, piOldCards[3];
1476   MsgExchangeCards  msgCards;
1477   MsgNetMessage     msgNetMessage;
1478   char buf[256];
1479 
1480   /* only 3 cards because we're handling selected cards */
1481   /* Save a copy and transform array indices into card indices */
1482   for (i=0; i!=3; i++)
1483     {
1484       piOldCards[i] = piCards[i];
1485       piCards[i] = RISK_GetCardOfPlayer(iCurrentPlayer, piCards[i]);
1486     }
1487 
1488   /* Send the cards to the server -- this will generate an _REPLYPACKET */
1489   for (i=0; i!=3; i++)
1490     msgCards.piCards[i] = piCards[i];
1491   (void)RISK_SendSyncMessage(CLNT_GetCommLinkOfClient(CLNT_GetThisClientID()),
1492 			     MSG_EXCHANGECARDS, &msgCards,
1493 			     MSG_REPLYPACKET, CBK_IncomingMessage);
1494 
1495   /* Update the date structures (bonus + countries on cards) */
1496   RISK_SetNumArmiesOfPlayer(iCurrentPlayer,
1497 			    RISK_GetNumArmiesOfPlayer(iCurrentPlayer)+iReply);
1498 
1499   /* See if any of the cards match countries that the player has */
1500   for (i=0; i!=3; i++)
1501     if (piCards[i] < NUM_COUNTRIES && /* Not a joker! */
1502 	RISK_GetOwnerOfCountry(piCards[i]) == iCurrentPlayer)
1503       RISK_SetNumArmiesOfCountry(piCards[i],
1504 				 RISK_GetNumArmiesOfCountry(piCards[i])+2);
1505 
1506   /* Take the cards away from the player */
1507   for (i=0; i!=3; i++)
1508     {
1509       for (j=piOldCards[i]; j<MAX_CARDS-1; j++)
1510 	RISK_SetCardOfPlayer(iCurrentPlayer, j,
1511 			     RISK_GetCardOfPlayer(iCurrentPlayer, j+1));
1512 
1513       /* Now that we've moved all the cards down, we have to move the
1514        * pointers to the selected cards down as well.  This was a bug.
1515        */
1516 
1517       for (k=i+1; k<3; k++)
1518         if (piOldCards[k]>piOldCards[i])
1519 	  piOldCards[k] = piOldCards[k]-1;
1520     }
1521 
1522   RISK_SetNumCardsOfPlayer(iCurrentPlayer,
1523 			   RISK_GetNumCardsOfPlayer(iCurrentPlayer)-3);
1524 
1525   /* Display a message */
1526 #ifdef ENGLISH
1527   snprintf(buf, sizeof(buf), "%s got %d armies from exchanging cards.",
1528 #endif
1529 #ifdef FRENCH
1530   snprintf(buf, sizeof(buf), "%s gagne %d arm�es en �changeant des cartes.",
1531 #endif
1532 	  RISK_GetNameOfPlayer(iCurrentPlayer),
1533 	  iReply);
1534   UTIL_DisplayError(buf);
1535   msgNetMessage.strMessage = buf;
1536   (void)RISK_SendMessage(CLNT_GetCommLinkOfClient(CLNT_GetThisClientID()), MSG_NETMESSAGE,
1537 			 &msgNetMessage);
1538 }
1539 
1540 
1541 /************************************************************************
1542  *  FUNCTION: GAME_EndTurn
1543  *  HISTORY:
1544  *     03.17.94  ESF  Created.
1545  *     03.28.94  ESF  Added card code, do we need Sync on the call?
1546  *     03.28.94  ESF  Moved iAttack/iDefend stuff here.
1547  *     03.29.94  ESF  Added iMove stuff.
1548  *     04.11.94  ESF  Added clear dice call.
1549  *     04.11.94  ESF  Move message call to end.
1550  *     02.20.95  ESF  Moved to game.c from utils.c
1551  *  PURPOSE:
1552  *  NOTES:
1553  ************************************************************************/
1554 void GAME_EndTurn(void)
1555 {
1556   /* Get the player a card if he or she needs one */
1557   if (fGetsCard)
1558     {
1559       MsgRequestCard msg;
1560 
1561       fGetsCard = FALSE;
1562       msg.iPlayer = iCurrentPlayer;
1563       (void)RISK_SendMessage(CLNT_GetCommLinkOfClient(CLNT_GetThisClientID()),
1564 			     MSG_REQUESTCARD, &msg);
1565     }
1566 
1567   /* Darken the country if the player was attacking or moving */
1568   if (iAttackSrc >= 0)
1569     UTIL_DarkenCountry(iAttackSrc);
1570   if (iMoveSrc >= 0)
1571     UTIL_DarkenCountry(iMoveSrc);
1572 
1573   /* Clear the dice box */
1574   DICE_Hide();
1575 
1576   /* Init. variables for next turn */
1577   fCanExchange = TRUE;
1578   iAttackSrc = iAttackDst = iLastAttackSrc = iLastAttackDst = -1;
1579   iMoveSrc = iMoveDst = -1;
1580 
1581   /* Notify the server of the end-of-turn condition and wait for a response */
1582   (void)RISK_SendSyncMessage(CLNT_GetCommLinkOfClient(CLNT_GetThisClientID()),
1583 			     MSG_ENDTURN, NULL,
1584 			     MSG_TURNNOTIFY, CBK_IncomingMessage);
1585 }
1586 
1587 
1588 /************************************************************************
1589  *  FUNCTION: GAME_IsMissionAccomplied
1590  *  HISTORY:
1591  *     16.08.95  JC  Created.
1592  *     23.08.95  JC  added iKilledPlayer.
1593  *  PURPOSE:
1594  *  NOTES:
1595  ************************************************************************/
1596 Flag GAME_IsMissionAccomplied(Int32 iPlayer, Int32 iKilledPlayer)
1597 {
1598   Int32 piCount [NUM_CONTINENTS];
1599   Int32 i, cont, n1, n2;
1600 
1601   switch (RISK_GetMissionTypeOfPlayer(iPlayer))
1602     {
1603     case CONQUIER_WORLD:
1604       if (RISK_GetNumCountriesOfPlayer(iPlayer) >= NUM_COUNTRIES)
1605           return TRUE;
1606       break;
1607     case CONQUIER_Nb_COUNTRY:
1608       n1 = RISK_GetMissionNumberOfPlayer(iPlayer);
1609       if (RISK_GetNumCountriesOfPlayer(iPlayer) >= n1)
1610           return TRUE;
1611       break;
1612     case CONQUIER_TWO_CONTINENTS:
1613       for (cont=0; cont<NUM_CONTINENTS; cont++)
1614           piCount[cont] = 0;
1615       for (i=0; i<NUM_COUNTRIES; i++)
1616           if (RISK_GetOwnerOfCountry(i) == iPlayer)
1617               piCount[RISK_GetContinentOfCountry(i)]++;
1618       n1 = RISK_GetMissionContinent1OfPlayer(iPlayer);
1619       n2 = RISK_GetMissionContinent2OfPlayer(iPlayer);
1620       if (    (piCount[n1] == RISK_GetNumCountriesOfContinent(n1))
1621            && (piCount[n2] == RISK_GetNumCountriesOfContinent(n2)))
1622           return TRUE;
1623       break;
1624     case KILL_A_PLAYER:
1625       n1 = RISK_GetMissionPlayerToKillOfPlayer(iPlayer);
1626       if (    (RISK_GetNumCountriesOfPlayer(n1) <= 0)
1627            && (n1 == iKilledPlayer))
1628         {
1629           RISK_SetMissionPlayerIsKilledOfPlayer(iPlayer, TRUE);
1630           return TRUE;
1631         }
1632       else if (RISK_GetMissionIsPlayerKilledOfPlayer(iPlayer))
1633           return TRUE;
1634       break;
1635     }
1636   return FALSE;
1637 }
1638 
1639 
1640 /************************************************************************
1641  *  FUNCTION: GAME_ShowMission
1642  *  HISTORY:
1643  *     16.08.95  JC  Created.
1644  *  PURPOSE:
1645  *  NOTES:
1646  ************************************************************************/
1647 void GAME_ShowMission(Int32 iPlayer)
1648 {
1649   char buf[256];
1650   GAME_MissionToStr(iPlayer, RISK_GetMissionTypeOfPlayer(iPlayer),
1651                              RISK_GetMissionContinent1OfPlayer(iPlayer),
1652                              RISK_GetMissionContinent2OfPlayer(iPlayer),
1653                              GAME_IsMissionAccomplied(iPlayer, -1),
1654 		    buf, sizeof(buf));
1655   UTIL_DisplayError(buf);
1656 }
1657