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: aiController.c,v 1.4 1999/11/13 21:58:30 morphy Exp $
20 */
21
22 #include "aiController.h"
23 #include "aiClient.h"
24 #include "client.h"
25 #include "riskgame.h"
26 #include "game.h"
27 #include "debug.h"
28
29 /* Prototypes */
30 Int32 CLNT_GetCommLinkOfClient(Int32 iThisClient);
31
32 /* Externs */
33 extern void *(*__AI_Callback)(void *, Int32, void *);
34 extern void *pvContext[MAX_PLAYERS];
35 extern Int32 iState, iCurrentPlayer;
36 extern Flag fGameStarted;
37
38 /* Globals */
39 Flag fPlayerFortified;
40
41
42 /************************************************************************
43 * FUNCTION: AI_Init
44 * HISTORY:
45 * 04.23.95 ESF Created.
46 * PURPOSE:
47 * NOTES:
48 ************************************************************************/
AI_Init(void)49 void AI_Init(void)
50 {
51 fPlayerFortified=FALSE;
52 fGameStarted = FALSE;
53 fGetsCard=FALSE;
54 }
55
56
57 /************************************************************************
58 * FUNCTION: AI_CheckCards
59 * HISTORY:
60 * 03.31.95 ESF Created.
61 * 28.08.95 JC If the computerized must exchange cards then do.
62 (copy of ExchangeCards)
63 * PURPOSE:
64 * NOTES:
65 ************************************************************************/
AI_CheckCards(void)66 void AI_CheckCards(void)
67 {
68 Int32 i, j, nb, typ, piCards[4], nbCards[4], piCardValues[MAX_CARDS];
69 Flag fOptimal;
70
71 if (RISK_GetNumCardsOfPlayer (iCurrentPlayer) <= 4)
72 return;
73 #ifdef ENGLISH
74 printf("AI: Error -- Checking cards.\n");
75 #endif
76 #ifdef FRENCH
77 printf("IA: Erreur -- V�rification des cartes.\n");
78 #endif
79
80 nb = RISK_GetNumCardsOfPlayer(iCurrentPlayer);
81 do
82 {
83 piCards[0]=piCards[1]=piCards[2]=piCards[3]=-1;
84 nbCards[0]=nbCards[1]=nbCards[2]=nbCards[3]=0;
85 fOptimal = FALSE;
86 for (i=0; i<nb; i++)
87 {
88 piCardValues[i] = RISK_GetCardOfPlayer(iCurrentPlayer, i);
89 /* Set the type of the card */
90 if (piCardValues[i]<NUM_COUNTRIES)
91 {
92 typ = piCardValues[i] % 3;
93 nbCards[typ]++;
94 if (RISK_GetOwnerOfCountry(piCardValues[i]) == iCurrentPlayer)
95 piCards[typ] = i;
96 else if (piCards[typ] == -1)
97 piCards[typ] = i;
98 }
99 else /* Joker */
100 {
101 piCards[3] = i;
102 nbCards[3]++;
103 }
104 }
105 if ((nbCards[0]>0)&&(nbCards[1]>0)&&(nbCards[2]>0))
106 {
107 AI_ExchangeCards(piCards);
108 fOptimal = TRUE;
109 }
110 else if (nb >= 5)
111 {
112 if ((nbCards[0]>0)&&(nbCards[1]>0)&&(nbCards[3]>0))
113 piCards[2] = piCards[3];
114 else if ((nbCards[0]>0)&&(nbCards[3]>0)&&(nbCards[2]>0))
115 piCards[1] = piCards[3];
116 else if ((nbCards[3]>0)&&(nbCards[1]>0)&&(nbCards[2]>0))
117 piCards[0] = piCards[3];
118 else if (nbCards[0]>=3)
119 {
120 j = 0;
121 for (i=0; i<nb; i++)
122 if ((piCardValues[i] % 3) == 0)
123 piCards[j++]=i;
124 }
125 else if (nbCards[1]>=3)
126 {
127 j = 0;
128 for (i=0; i<nb; i++)
129 if ((piCardValues[i] % 3) == 1)
130 piCards[j++]=i;
131 }
132 else if (nbCards[2]>=3)
133 {
134 j = 0;
135 for (i=0; i<nb; i++)
136 if ((piCardValues[i] % 3) == 2)
137 piCards[j++]=i;
138 }
139 else
140 {
141 piCards[0] = 0;
142 piCards[1] = 1;
143 piCards[2] = 2;
144 }
145 AI_ExchangeCards(piCards);
146 }
147 nb = RISK_GetNumCardsOfPlayer(iCurrentPlayer);
148 }
149 while ((fOptimal && (nb >= 3)) || (nb >= 5));
150 }
151
152
153 /************************************************************************
154 * FUNCTION: AI_CheckFortification
155 * HISTORY:
156 * 03.31.95 ESF Created.
157 * PURPOSE:
158 * NOTES:
159 ************************************************************************/
AI_CheckFortification(void)160 void AI_CheckFortification(void)
161 {
162 /* If the player hasn't fortified yet, do it */
163 if (!fPlayerFortified)
164 {
165 Int32 i;
166
167 #ifdef ENGLISH
168 printf("AI: Error -- Checking fortification.\n");
169 #endif
170 #ifdef FRENCH
171 printf("IA: Erreur -- V�rification de la fortification.\n");
172 #endif
173
174 /* Place an army in the first country we find */
175 for (i=0; i!=NUM_COUNTRIES; i++)
176 if (RISK_GetOwnerOfCountry(i) == iCurrentPlayer)
177 {
178 AI_Place(i, 1);
179 return;
180 }
181
182 D_Assert(FALSE, "Player didn't own any countries??");
183 }
184 }
185
186
187 /************************************************************************
188 * FUNCTION: AI_CheckPlacement
189 * HISTORY:
190 * 03.31.95 ESF Created.
191 * PURPOSE:
192 * NOTES:
193 ************************************************************************/
AI_CheckPlacement(void)194 void AI_CheckPlacement(void)
195 {
196 if (RISK_GetNumArmiesOfPlayer(iCurrentPlayer) != 0)
197 {
198 Int32 i;
199
200 #ifdef ENGLISH
201 printf("AI: Error -- Checking placement.\n");
202 #endif
203 #ifdef FRENCH
204 printf("IA: Erreur -- V�rification du placement.\n");
205 #endif
206 /* Dump the armies on the first country */
207 for (i=0; i!=NUM_COUNTRIES; i++)
208 if (RISK_GetOwnerOfCountry(i) == iCurrentPlayer)
209 {
210 AI_Place(i, RISK_GetNumArmiesOfPlayer(iCurrentPlayer));
211 return;
212 }
213
214 D_Assert(FALSE, "Player didn't own any countries??");
215 }
216 }
217
218
219 /************************************************************************
220 * FUNCTION: AI_Place
221 * HISTORY:
222 * 03.31.95 ESF Created.
223 * 21.08.95 JC AI_CheckCards if game is started.
224 * 28.08.95 JC No AI_CheckCards.
225 * PURPOSE:
226 * NOTES:
227 ************************************************************************/
AI_Place(Int32 iCountry,Int32 iNumArmies)228 Flag AI_Place(Int32 iCountry, Int32 iNumArmies)
229 {
230 if (GAME_ValidPlaceDst(iCountry) &&
231 iNumArmies <= RISK_GetNumArmiesOfPlayer(iCurrentPlayer) &&
232 ((iState == STATE_FORTIFY && iNumArmies == 1) ||
233 iState != STATE_FORTIFY))
234 {
235 GAME_PlaceArmies(iCountry, iNumArmies);
236
237 /* Player has fortified if in fortification stage */
238 fPlayerFortified = TRUE;
239
240 return TRUE;
241 }
242 else
243 {
244 #ifdef ENGLISH
245 printf("AI: Error -- illegal place (%d, %d)\n", iCountry, iNumArmies);
246 #endif
247 #ifdef FRENCH
248 printf("IA: Erreur -- placement ill�gal (%d, %d)\n", iCountry, iNumArmies);
249 #endif
250 return FALSE;
251 }
252 }
253
254
255 /************************************************************************/
256
257 Int32 iMoveMode;
258
259
260 /************************************************************************
261 * FUNCTION: AI_Attack
262 * HISTORY:
263 * 03.31.95 ESF Created.
264 * 23.08.95 JC Corrected a bug if iSrcCountry or iDstCountry are
265 * totally invalid.
266 * If ARMIES_MOVE_MANUAL, conserve NumArmiesOfPlayer.
267 * 30.08.95 JC Do the move immediatly.
268 * PURPOSE:
269 * NOTES:
270 ************************************************************************/
AI_Attack(Int32 iSrcCountry,Int32 iDstCountry,Int32 iAttack,Int32 iDice,Int32 iMoveSelectMode)271 Flag AI_Attack(Int32 iSrcCountry, Int32 iDstCountry, Int32 iAttack,
272 Int32 iDice, Int32 iMoveSelectMode)
273 {
274 Int32 iAttackMode, iDiceMode;
275 char *srcName, *dstName;
276
277 iMoveMode = iMoveSelectMode;
278 /* Set the modes for the attack */
279 switch (iDice)
280 {
281 case DICE_ONE:
282 iDiceMode = ATTACK_ONE;
283 break;
284 case DICE_TWO:
285 iDiceMode = ATTACK_TWO;
286 break;
287 case DICE_THREE:
288 iDiceMode = ATTACK_THREE;
289 break;
290 case DICE_MAXIMUM:
291 iDiceMode = ATTACK_AUTO;
292 break;
293 default:
294 #ifdef ENGLISH
295 printf("AI: Error -- choosing dice mode for attack.\n");
296 #endif
297 #ifdef FRENCH
298 printf("IA: Erreur -- choix du mode des d�s pour combattre.\n");
299 #endif
300 return FALSE;
301 }
302
303 switch (iAttack)
304 {
305 case ATTACK_ONCE:
306 iAttackMode = ACTION_ATTACK;
307 break;
308 case ATTACK_DOORDIE:
309 iAttackMode = ACTION_DOORDIE;
310 break;
311 default:
312 #ifdef ENGLISH
313 printf("AI: Error -- choosing attack mode for attack.\n");
314 #endif
315 #ifdef FRENCH
316 printf("IA: Erreur -- choix du mode d'attaque pour combattre.\n");
317 #endif
318 return FALSE;
319 }
320
321 RISK_SetAttackModeOfPlayer(iCurrentPlayer, iAttackMode);
322 RISK_SetDiceModeOfPlayer(iCurrentPlayer, iDiceMode);
323
324 /* BUG -- return true if victory? */
325
326 if (GAME_ValidAttackSrc(iSrcCountry, TRUE) &&
327 GAME_ValidAttackDst(iSrcCountry, iDstCountry, TRUE) &&
328 GAME_ValidAttackDice(iDiceMode, iSrcCountry))
329 {
330 GAME_Attack(iSrcCountry, iDstCountry);
331 return TRUE;
332 }
333 else
334 {
335 if ((iSrcCountry>=0) && (iSrcCountry<NUM_COUNTRIES))
336 srcName = RISK_GetNameOfCountry(iSrcCountry);
337 else
338 srcName = "";
339 if ((iDstCountry>=0) && (iDstCountry<NUM_COUNTRIES))
340 dstName = RISK_GetNameOfCountry(iDstCountry);
341 else
342 dstName = "";
343 #ifdef ENGLISH
344 printf("AI: Error -- illegal attack (%s --> %s)\n",
345 #endif
346 #ifdef FRENCH
347 printf("IA: Erreur -- ill�gall attaque (%s --> %s)\n",
348 #endif
349 srcName, dstName);
350 return FALSE;
351 }
352 }
353
354
355 /************************************************************************
356 * FUNCTION: AI_Move
357 * HISTORY:
358 * 03.31.95 ESF Created.
359 * 23.08.95 JC Don't check Cards and placement
360 * if state <> STATE_MOVE.
361 * PURPOSE:
362 * NOTES:
363 ************************************************************************/
364 Flag AI_Move(Int32 iSrcCountry, Int32 iDstCountry, Int32 iNumArmies)
365 {
366 if (GAME_ValidMoveSrc(iSrcCountry) &&
367 GAME_ValidMoveDst(iSrcCountry, iDstCountry) &&
368 RISK_GetNumArmiesOfCountry(iSrcCountry) >= iNumArmies+1)
369 {
370 GAME_MoveArmies(iSrcCountry, iDstCountry, iNumArmies);
371 return TRUE;
372 }
373 else
374 {
375 #ifdef ENGLISH
376 printf("AI: Error -- illegal move (%s --> %s)\n",
377 #endif
378 #ifdef FRENCH
379 printf("IA: Erreur -- mouvement ill�gal (%s --> %s)\n",
380 #endif
381 RISK_GetNameOfCountry(iSrcCountry),
382 RISK_GetNameOfCountry(iDstCountry));
383 return FALSE;
384 }
385 }
386
387
388 /************************************************************************
389 * FUNCTION: AI_ExchangeCards
390 * HISTORY:
391 * 03.31.95 ESF Created.
392 * PURPOSE:
393 * NOTES:
394 ************************************************************************/
395 Flag AI_ExchangeCards(Int32 *piCards)
396 {
397 GAME_ExchangeCards(piCards);
398 return TRUE;
399 }
400
401
402 /************************************************************************
403 * FUNCTION: AI_SendMessage
404 * HISTORY:
405 * 03.31.95 ESF Created.
406 * PURPOSE:
407 * NOTES:
408 ************************************************************************/
409 Flag AI_SendMessage(Int32 iMessDest, CString strMessage)
410 {
411 MsgMessagePacket mess;
412
413 mess.strMessage = strMessage;
414 mess.iFrom = iCurrentPlayer;
415 mess.iTo = iMessDest;
416 (void)RISK_SendMessage(CLNT_GetCommLinkOfClient(CLNT_GetThisClientID()),
417 MSG_MESSAGEPACKET, &mess);
418 return TRUE;
419 }
420
421
422 /************************************************************************
423 * FUNCTION: AI_EndTurn
424 * HISTORY:
425 * 03.31.95 ESF Created.
426 * 21.08.95 JC Added fGetsCard.
427 * 23.08.95 JC Added test the mission.
428 * PURPOSE:
429 * NOTES:
430 ************************************************************************/
431 Flag AI_EndTurn(void)
432 {
433 /* Get the player a card if he or she needs one */
434 if (fGetsCard)
435 {
436 MsgRequestCard msg;
437
438 fGetsCard = FALSE;
439 msg.iPlayer = iCurrentPlayer;
440 (void)RISK_SendMessage(CLNT_GetCommLinkOfClient(CLNT_GetThisClientID()),
441 MSG_REQUESTCARD, &msg);
442 }
443
444 if (fGameStarted)
445 fCanExchange = TRUE;
446 else
447 fPlayerFortified = FALSE;
448
449 /* Actually end the turn */
450 (void)RISK_SendMessage(CLNT_GetCommLinkOfClient(CLNT_GetThisClientID()),
451 MSG_ENDTURN, NULL);
452
453 return TRUE;
454 }
455