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: aiClientMain.c,v 1.8 1999/11/27 18:19:33 tony Exp $
20 */
21
22 #include <sys/param.h>
23 #include <sys/time.h>
24 #include <sys/types.h>
25 #include <sys/socket.h>
26 #ifdef _AIX
27 #include <sys/select.h>
28 #endif
29 #include <netinet/in.h>
30 #include <netdb.h>
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <unistd.h>
34 #include <string.h>
35 #include <time.h>
36 #include <signal.h>
37
38 #include "types.h"
39 #include "utils.h"
40 #include "client.h"
41 #include "version.h"
42 #include "network.h"
43 #include "riskgame.h"
44 #include "game.h"
45 #include "debug.h"
46 #include "aiClient.h"
47 #include "aiController.h"
48
49 /* Private functions */
50 void AI_Start(Int32 argc, CString *argv);
51 void AI_RecoverFailure(CString strReason, Int32 iNumFailures);
52 void AI_MainLoop(void);
53 void AI_Replicate(Int32 iMessType, void *pvMess, Int32 iType, Int32 iSource);
54
55 /* Dummies or stubs or fill-ins */
56 Int32 CLNT_GetCommLinkOfClient(Int32 iThisClient);
57 /* EEEK!!! this same function(name) has been defined in callbacks.c
58 * callbacks is included, what is going on? which one called?
59 */
60 void CBK_IncomingMessage(Int32 iMessType, void *pvMess);
61 void FatalError(CString strError, Int32 iExitValue);
62 CString strClientName;
63
64 Int32 iCommLink, iReply;
65 Int32 iSpeciesID, iCurrentClient, iCurrentPlayer, iState;
66 Flag fGameInitialized = FALSE;
67 Flag fGameStarted = FALSE;
68
69
70 extern CString __strName;
71 extern CString __strAuthor;
72 extern CString __strVersion;
73 extern CString __strDesc;
74 extern void *(*__AI_Callback)(void *, Int32, void *);
75
76 void *pvContext[MAX_PLAYERS];
77
78 /* Move this to the Imakefile!! */
79 #ifdef __hpux
80 #define FDSET int
81 #else
82 #define FDSET fd_set
83 #endif
84
85
86 /************************************************************************
87 * FUNCTION: main
88 * HISTORY:
89 * 02.20.95 ESF Created from clientMain.c`main
90 * PURPOSE:
91 * NOTES:
92 ************************************************************************/
main(int argc,char ** argv)93 int main(int argc, char **argv)
94 {
95 Int32 i;
96
97 /* Check args */
98 if (argc != 2)
99 {
100 printf("Usage: %s <server_host>\n", argv[0]);
101 exit(-1);
102 }
103
104 for (i=0; i!=MAX_PLAYERS; i++)
105 pvContext[i] = (void *)NULL;
106
107 /* Setup memory debugging library */
108 MEM_BootStrap("aiClient-memory.log");
109
110 /* Initialize everything */
111 RISK_InitObject(AI_Replicate, NULL, NULL, AI_RecoverFailure, NULL);
112 AI_Start(argc, argv);
113
114 /* Let the server know that we're ready to go as soon as it is... */
115 (void)RISK_SendMessage(CLNT_GetCommLinkOfClient(CLNT_GetThisClientID()),
116 MSG_STARTGAME, NULL);
117 iState = STATE_FORTIFY;
118
119 /* And we're off */
120 AI_MainLoop();
121 return(0);
122 }
123
124
125 /************************************************************************
126 * FUNCTION: AI_Start
127 * HISTORY:
128 * 02.20.95 ESF Created from CLNT_Init.
129 * PURPOSE:
130 * NOTES:
131 ************************************************************************/
AI_Start(Int32 argc,CString * argv)132 void AI_Start(Int32 argc, CString *argv)
133 {
134 struct sockaddr_in server;
135 struct hostent *hp;
136 char strHostName[MAXHOSTNAMELEN + 1];
137 Int32 iMessageType, i;
138 void *pvMessage;
139 MsgRegisterClient msgRegisterClient;
140
141 UNUSED(argc);
142
143 /*
144 * We want to ignore this signal, because we don't want a I/O
145 * failure to terminate the program.
146 */
147
148 signal(SIGPIPE, SIG_IGN);
149
150 /* Create sockets */
151 if ((iCommLink = socket(AF_INET, SOCK_STREAM, 0)) < 0)
152 #ifdef ENGLISH
153 FatalError("Cannot create CommLink.", 1);
154 #endif
155 #ifdef FRENCH
156 FatalError("CLIENT: Ne peut cr�er la liaison.", 1);
157 #endif
158
159 /* Connect socket using name specified by command line */
160 server.sin_family = AF_INET;
161
162 if ((hp = gethostbyname(argv[1])) == 0)
163 {
164 char buf[256];
165 #ifdef ENGLISH
166 snprintf(buf, sizeof(buf),
167 "AI-CLIENT: The host `%s' is unknown.", argv[1]);
168 #endif
169 #ifdef FRENCH
170 snprintf(buf, sizeof(buf),
171 "IA-CLIENT: La machine `%s' est inconnue.", argv[1]);
172 #endif
173 FatalError(buf, 1);
174 }
175
176 memcpy(&server.sin_addr, hp->h_addr, hp->h_length);
177 server.sin_port = htons(RISK_PORT);
178
179 /* Send the server name information through the sockets so it can ID
180 * the sending clients, and discover the pair of sockets that belong
181 * to each client. The server sends back the client ID.
182 */
183
184 gethostname(strHostName, sizeof(strHostName));
185 msgRegisterClient.strClientAddress =
186 (CString)MEM_Alloc(strlen(strHostName)+32);
187 snprintf(msgRegisterClient.strClientAddress, strlen(strHostName)+32,
188 "%s[%lu]", strHostName, (unsigned long)getpid());
189 strClientName = msgRegisterClient.strClientAddress;
190 msgRegisterClient.iClientType = CLIENT_AI;
191
192 /* The Protocol:
193 *
194 * Connect to the server. Then do the following:
195 *
196 * Send MSG_HELLO.
197 * Receive MSG_VERSION --> OK!
198 * Other --> Protocol bogosity.
199 * Send MSG_REGISTERCLIENT if version is correct.
200 * Receive MSG_CLIENTIDENT --> OK!
201 * MSG_CLIENTEXIT --> Server is full.
202 * Other --> Protocol bogosity.
203 * Send MSG_VERSION if version is incorrect.
204 */
205
206 if (connect(iCommLink, (struct sockaddr *)&server, sizeof(server)) < 0)
207 {
208 #ifdef ENGLISH
209 printf("AI-CLIENT: Cannot connect to a Frisk server on `%s'.\n"
210 " One probably needs to be started by running\n"
211 " `friskserver' on the machine.\n", argv[1]);
212 #endif
213 #ifdef FRENCH
214 printf("IA-CLIENT: Impossible de se connecter au serveur Frisk sur `%s'.\n"
215 " Quelqu'un doit commencer par lancer `friskserver' \n"
216 " sur cette machine.\n", argv[1]);
217 #endif
218 FatalError(NULL, 0);
219 }
220
221 /* Send the greeting */
222 #ifdef ENGLISH
223 printf("AI-CLIENT: Establishing CommLink to server.\n");
224 #endif
225 #ifdef FRENCH
226 fflush(stdout);
227 printf("IA-CLIENT: �tablissement d'une communication avec le serveur.\n");
228 #endif
229 (void)RISK_SendMessage(iCommLink, MSG_HELLO, NULL);
230
231 /* Get the version and check it. */
232 (void)RISK_ReceiveMessage(iCommLink, &iMessageType, &pvMessage);
233
234 if (iMessageType != MSG_VERSION)
235 {
236 #ifdef ENGLISH
237 printf("AI-CLIENT: Server is not following protocol (%d)! Exiting.\n",
238 #endif
239 #ifdef FRENCH
240 printf("IA-CLIENT: Le serveur n'utilise pas le m�me protocol (%d)! Quit.\n",
241 #endif
242 iMessageType);
243 FatalError(NULL, 0);
244 }
245
246 if (strcmp(((MsgVersion *)pvMessage)->strVersion, VERSION))
247 {
248 #ifdef ENGLISH
249 printf("AI-CLIENT: Version mismatch (server running %s)! Exiting.\n",
250 #endif
251 #ifdef FRENCH
252 printf("IA-CLIENT: Mauvaise version (le server utilise %s)! Quit.\n",
253 #endif
254 ((MsgVersion *)pvMessage)->strVersion);
255 FatalError(NULL, 0);
256 }
257
258 NET_DeleteMessage(iMessageType, pvMessage);
259
260 /* Send back the registration message */
261 (void)RISK_SendMessage(iCommLink, MSG_REGISTERCLIENT, &msgRegisterClient);
262
263 /* Get the species ID */
264 #ifdef ENGLISH
265 printf("AI-CLIENT: Waiting for server to send species ID...");
266 #endif
267 #ifdef FRENCH
268 printf("IA-CLIENT: Attente du server pour obtenir l'ID de l'esp�ce...");
269 #endif
270 (void)RISK_ReceiveMessage(iCommLink, &iMessageType, &pvMessage);
271
272 if (iMessageType != MSG_SPECIESIDENT)
273 {
274 #ifdef ENGLISH
275 printf("Server is not following protocol (%d)!", iMessageType);
276 FatalError("Protocol error.", -1);
277 #endif
278 #ifdef FRENCH
279 printf("IA-CLIENT: Le serveur n'utilise pas le m�me protocol (%d)!\n",
280 iMessageType);
281 FatalError("Erreur de protocol.", -1);
282 #endif
283 }
284 else
285 #ifdef ENGLISH
286 printf("Done.\n");
287 #endif
288 #ifdef FRENCH
289 printf("Re�u.\n");
290 #endif
291
292 iSpeciesID = ((MsgSpeciesIdent *)pvMessage)->iSpeciesID;
293 NET_DeleteMessage(iMessageType, pvMessage);
294
295 /* Wait for the response */
296 #ifdef ENGLISH
297 printf("AI-CLIENT: Waiting for server to send client ID...");
298 #endif
299 #ifdef FRENCH
300 printf("IA-CLIENT: Attend que le serveur �mette l'ID client...");
301 #endif
302 (void)RISK_ReceiveMessage(iCommLink, &iMessageType, &pvMessage);
303
304 if (iMessageType == MSG_EXIT)
305 FatalError("Can't connect, server is full -- I'm impressed!", -1);
306 else if (iMessageType == MSG_CLIENTIDENT)
307 {
308 #ifdef ENGLISH
309 printf("Done.\n");
310 #endif
311 #ifdef FRENCH
312 printf("Re�u.\n");
313 #endif
314
315 /* Set the ID of the client, and then set the sockets of the client */
316 iCurrentClient = ((MsgClientIdent *)pvMessage)->iClientID;
317 }
318 else
319 {
320 #ifdef ENGLISH
321 printf("Server is not following protocol (%d)!", iMessageType);
322 FatalError("Protocol error!", -1);
323 #endif
324 #ifdef FRENCH
325 printf("IA-CLIENT: Le serveur n'utilise pas le m�me protocol (%d)!\n",
326 iMessageType);
327 FatalError("Erreur de protocol.", -1);
328 #endif
329 }
330
331 /* Free up memory */
332 NET_DeleteMessage(MSG_CLIENTIDENT, pvMessage);
333
334 /* Get the species ID */
335 i = iSpeciesID;
336 #ifdef ENGLISH
337 printf("AI-CLIENT: Me species #%d. You Jane.\n", i);
338 #endif
339 #ifdef FRENCH
340 printf("IA-CLIENT: Mon esp�ce est %d.\n", i);
341 #endif
342
343 /* Init the species; afterwards, indicate the species is finished. */
344 RISK_SetNameOfSpecies(i, __strName);
345 RISK_SetClientOfSpecies(i, CLNT_GetThisClientID());
346 RISK_SetAuthorOfSpecies(i, __strAuthor);
347 RISK_SetVersionOfSpecies(i, __strVersion);
348 RISK_SetDescriptionOfSpecies(i, __strDesc);
349 RISK_SetAllocationStateOfSpecies(i, ALLOC_COMPLETE);
350
351 /* Let the player do one-time initializations */
352 __AI_Callback(NULL, AI_INIT_ONCE, (void *)iSpeciesID);
353 }
354
355
356
357 /************************************************************************
358 * FUNCTION: CLNT_GetThisClientID
359 * HISTORY:
360 * 30.10.99 MSH Created.
361 * PURPOSE:
362 * Returns client ID of 'this' client
363 * NOTES: See below
364 ************************************************************************/
365 Int32 CLNT_GetThisClientID(void)
366 {
367 return iCurrentClient;
368 }
369
370
371 /************************************************************************
372 * FUNCTION: CLNT_GetCommLinkOfClient
373 * HISTORY:
374 * 02.20.95 ESF Created.
375 * PURPOSE:
376 * NOTES: DUMMY!!
377 ************************************************************************/
378 Int32 CLNT_GetCommLinkOfClient(Int32 iThisClient)
379 {
380 UNUSED(iThisClient);
381 return iCommLink;
382 }
383
384
385 /************************************************************************
386 * FUNCTION: AI_RecoverFailure
387 * HISTORY:
388 * 02.21.95 ESF Created.
389 * PURPOSE:
390 * NOTES:
391 ************************************************************************/
392 void AI_RecoverFailure(CString strReason, Int32 iFailureCommlink)
393 {
394 #ifdef ENGLISH
395 printf("AI-CLIENT: Fatal Error (%s) on CommLink %d. Not equipped to\n"
396 "recover from failure yet. I'm exiting.\n",
397 #endif
398 #ifdef FRENCH
399 printf("IA-CLIENT: Erreur fatale (%s) sur la ligne %d.\n"
400 " Pas equipp� pour r�cup�rer cette erreur.\n"
401 " Je quitte.\n",
402 #endif
403 strReason, iFailureCommlink);
404 exit(-1);
405 }
406
407
408 /************************************************************************
409 * FUNCTION: FatalError
410 * HISTORY:
411 * 02.21.95 ESF Created.
412 * PURPOSE:
413 * NOTES:
414 ************************************************************************/
415 void FatalError(CString strError, Int32 iExitValue)
416 {
417 if (strError)
418 #ifdef ENGLISH
419 printf("AI-CLIENT: Fatal error (%s)\n", strError);
420 #endif
421 #ifdef ENGLISH
422 printf("IA-CLIENT: Erreur fatale (%s)\n", strError);
423 #endif
424 exit(iExitValue);
425 }
426
427
428 /************************************************************************
429 * FUNCTION: AI_MainLoop
430 * HISTORY:
431 * 02.21.95 ESF Created from CLNT_Init.
432 * PURPOSE:
433 * NOTES:
434 ************************************************************************/
435 void AI_MainLoop(void)
436 {
437 void *pvMessage;
438 Int32 iMessageType;
439 fd_set fdSet, fdBackup;
440
441 FD_ZERO(&fdBackup);
442 FD_SET(CLNT_GetCommLinkOfClient(CLNT_GetThisClientID()), &fdBackup);
443
444 /* Initialize everything */
445 AI_Init();
446
447 /* Loop forever */
448 for(;;)
449 {
450 fdSet = fdBackup;
451
452 /* Wait for a message */
453 if (select(CLNT_GetCommLinkOfClient(CLNT_GetThisClientID())+1,
454 (FDSET *)&fdSet, (FDSET *)0, (FDSET *)0,
455 NULL) < 0)
456 perror("Select");
457
458 /* Receive the message */
459 if (!RISK_ReceiveMessage(CLNT_GetCommLinkOfClient(CLNT_GetThisClientID()),
460 &iMessageType, &pvMessage))
461 AI_RecoverFailure("Server failed.", -1);
462
463 /* Process it */
464 CBK_IncomingMessage(iMessageType, pvMessage);
465 }
466 }
467
468
469 /************************************************************************
470 * FUNCTION: CBK_IncomingMessage
471 * HISTORY:
472 * 04.30.95 ESF Created.
473 * 25.08.95 JC Added MSG_EXIT.
474 * 25.08.95 JC Modified MSG_ENDOFGAME, if computer is the winner and
475 * if more than one player, then the computer decide to
476 * continue.
477 * 25.08.95 JC Start the game only after a fortification.
478 * 28.08.95 JC Added MSG_ENDOFMISSION and MSG_VICTORY.
479 * 30.08.95 JC Added MSG_FORCEEXCHANGECARDS.
480 * 04.09.95 JC Added AI_SERVER_MESSAGE.
481 * PURPOSE:
482 * NOTES:
483 ************************************************************************/
484 void CBK_IncomingMessage(Int32 iMessType, void *pvMessage)
485 {
486 switch(iMessType)
487 {
488 case MSG_TURNNOTIFY:
489 {
490 MsgTurnNotify *pvMess = (MsgTurnNotify *)pvMessage;
491
492 /* Set the current player */
493 iCurrentPlayer = pvMess->iPlayer;
494
495 if (!fGameInitialized)
496 {
497 fGameInitialized = TRUE;
498 /* Let the player do initializations of game */
499 __AI_Callback(NULL, AI_INIT_GAME, (void *)iSpeciesID);
500 }
501
502 /* Check to see if it's this client. */
503 if (pvMess->iClient == CLNT_GetThisClientID())
504 {
505 pvContext[iCurrentPlayer] =
506 __AI_Callback(pvContext[iCurrentPlayer], AI_INIT_TURN, NULL);
507
508 /* See if the fortification is done */
509 if (!fGameStarted && (iState == STATE_FORTIFY) &&
510 (RISK_GetNumArmiesOfPlayer(iCurrentPlayer) == 0))
511 fGameStarted = TRUE;
512
513 if (fGameStarted)
514 {
515 if (RISK_GetNumCardsOfPlayer(iCurrentPlayer) >= 3)
516 {
517 pvContext[iCurrentPlayer] =
518 __AI_Callback(pvContext[iCurrentPlayer],
519 AI_EXCHANGE_CARDS,
520 NULL);
521 AI_CheckCards();
522 }
523
524 /* Give the players the initial armies */
525 GAME_SetTurnArmiesOfPlayer(iCurrentPlayer);
526 if (iState == STATE_REGISTER)
527 return;
528
529 iState = STATE_PLACE;
530 do
531 {
532 /* Send the commands */
533 pvContext[iCurrentPlayer] =
534 __AI_Callback(pvContext[iCurrentPlayer],
535 AI_PLACE,
536 NULL);
537 if (iState == STATE_ATTACK)
538 {
539 AI_CheckPlacement();
540 pvContext[iCurrentPlayer] =
541 __AI_Callback(pvContext[iCurrentPlayer],
542 AI_ATTACK,
543 NULL);
544 }
545 }
546 while (iState == STATE_PLACE);
547
548 if (iState == STATE_ATTACK)
549 {
550 iState = STATE_MOVE;
551 pvContext[iCurrentPlayer] =
552 __AI_Callback(pvContext[iCurrentPlayer],
553 AI_MOVE,
554 NULL);
555 }
556 }
557 else if (iState == STATE_FORTIFY)
558 {
559 pvContext[iCurrentPlayer] =
560 __AI_Callback(pvContext[iCurrentPlayer],
561 AI_FORTIFY,
562 (void *)1);
563 AI_CheckFortification();
564 }
565
566 if (iState != STATE_REGISTER)
567 {
568 /* End the turn */
569 AI_EndTurn();
570 }
571 }
572 }
573 break;
574
575 case MSG_MESSAGEPACKET:
576 {
577 MsgMessagePacket *msgMessagePacket = (MsgMessagePacket *)pvMessage;
578
579 if (msgMessagePacket->iFrom >= FROM_SERVER)
580 {
581 Int32 iOldPlayer = iCurrentPlayer;
582
583 if (msgMessagePacket->iTo >= 0)
584 iCurrentPlayer = msgMessagePacket->iTo;
585 else
586 iCurrentPlayer = RISK_GetNthPlayerAtClient(CLNT_GetThisClientID(), 0);
587 (void)__AI_Callback(NULL, AI_SERVER_MESSAGE,
588 (void *)(msgMessagePacket->strMessage));
589 iCurrentPlayer = iOldPlayer;
590 }
591 else if ( (msgMessagePacket->iFrom >= 0)
592 && (msgMessagePacket->iTo >= 0))
593 {
594 Int32 iOldPlayer = iCurrentPlayer;
595
596 iCurrentPlayer = msgMessagePacket->iTo;
597 pvContext[iCurrentPlayer] =
598 __AI_Callback(pvContext[iCurrentPlayer],
599 AI_MESSAGE,
600 (void *)msgMessagePacket);
601 iCurrentPlayer = iOldPlayer;
602 }
603 }
604 break;
605
606 case MSG_FORCEEXCHANGECARDS:
607 {
608 MsgForceExchangeCards *msg = (MsgForceExchangeCards *)pvMessage;
609
610 if (msg->iPlayer >= 0)
611 {
612 if (iState != STATE_ATTACK)
613 return;
614 iCurrentPlayer = msg->iPlayer;
615 pvContext[iCurrentPlayer] =
616 __AI_Callback(pvContext[iCurrentPlayer],
617 AI_EXCHANGE_CARDS, NULL);
618 AI_CheckCards();
619 if (iState != STATE_ATTACK)
620 return;
621 iState = STATE_PLACE;
622 }
623 }
624 break;
625
626 case MSG_ENDOFMISSION:
627 {
628 Int32 iWinner = ((MsgEndOfMission *)pvMessage)->iWinner;
629
630 D_Assert(iWinner >= -1 && iWinner < MAX_PLAYERS, "Bogus Winner!");
631
632 if (RISK_GetClientOfPlayer(iWinner) == CLNT_GetThisClientID())
633 {
634 if (RISK_GetNumLivePlayers() <= 1)
635 {
636 fGameStarted = FALSE;
637 iState = STATE_REGISTER;
638 (void)RISK_SendMessage(CLNT_GetCommLinkOfClient(CLNT_GetThisClientID()),
639 MSG_ENDOFGAME, NULL);
640 }
641 }
642 }
643 break;
644
645 case MSG_VICTORY:
646 {
647 Int32 iWinner = ((MsgVictory *)pvMessage)->iWinner;
648
649 D_Assert(iWinner >= -1 && iWinner < MAX_PLAYERS, "Bogus Winner!");
650
651 if (RISK_GetClientOfPlayer(iWinner) == CLNT_GetThisClientID())
652 {
653 fGameStarted = FALSE;
654 iState = STATE_REGISTER;
655 (void)RISK_SendMessage(CLNT_GetCommLinkOfClient(CLNT_GetThisClientID()),
656 MSG_ENDOFGAME, NULL);
657 }
658 }
659 break;
660
661 case MSG_ENDOFGAME:
662 {
663 fGameStarted = FALSE;
664 iState = STATE_FORTIFY;
665
666 /* Let the server know that this client is ready to play */
667 (void)RISK_SendMessage(CLNT_GetCommLinkOfClient(CLNT_GetThisClientID()),
668 MSG_STARTGAME, NULL);
669
670 fGameInitialized = FALSE;
671 AI_Init();
672 }
673
674 case MSG_NOMESSAGE:
675 break;
676
677 case MSG_REPLYPACKET:
678 iReply = ((MsgReplyPacket *)pvMessage)->iReply;
679 break;
680
681 case MSG_EXIT:
682 UTIL_ExitProgram(0);
683 break;
684 default:
685 ; /* Nothing... */
686 }
687 }
688
689
690 /************************************************************************
691 * FUNCTION: UTIL_GetArmyNumber
692 * HISTORY:
693 * 02.25.95 ESF Created.
694 * 30.08.95 JC Computer can play like a human.
695 * 31.08.95 JC if (ARMIES_MOVE_MIN == ARMIES_MOVE_MAX) ->
696 * if (iMoveMode == ARMIES_MOVE_MIN).
697 * PURPOSE:
698 * NOTES:
699 ************************************************************************/
700 Int32 UTIL_GetArmyNumber(Int32 iMin, Int32 iMax, Flag fLetCancel)
701 {
702 extern Int32 iMoveMode;
703 UNUSED(fLetCancel);
704
705 if (iMoveMode == ARMIES_MOVE_MAX)
706 return iMax;
707 if (iMoveMode == ARMIES_MOVE_MIN)
708 return iMin;
709 if (iMoveMode == ARMIES_MOVE_MANUAL)
710 {
711 Int32 iNumArmies = iMax-iMin;
712
713 pvContext[iCurrentPlayer] =
714 __AI_Callback(pvContext[iCurrentPlayer], AI_MOVE_MANUAL,
715 (void *)&iNumArmies);
716 return iNumArmies+iMin;
717 }
718 return (iMax-iMin)/2;
719 }
720
721
722 /************************************************************************
723 * FUNCTION:
724 * HISTORY:
725 * 02.25.95 ESF Created.
726 * PURPOSE:
727 * NOTES:
728 ************************************************************************/
729 void AI_RegisterPreObserver(void (*PreCallback)(Int32, void *))
730 {
731 UNUSED(PreCallback);
732 /* A bit of a hack, for now... */
733
734 }
735
736
737 /************************************************************************
738 * FUNCTION:
739 * HISTORY:
740 * 02.25.95 ESF Created.
741 * PURPOSE:
742 * NOTES:
743 ************************************************************************/
744 void AI_RegisterPostObserver(void (*PostCallback)(Int32, void *))
745 {
746 UNUSED(PostCallback);
747 /* A bit of a hack, for now... */
748
749 }
750
751
752 /************************************************************************
753 * FUNCTION: AI_Replicate
754 * HISTORY:
755 * 02.25.95 ESF Created.
756 * PURPOSE:
757 * NOTES:
758 ************************************************************************/
759 void AI_Replicate(Int32 iMessType, void *pvMess, Int32 iType, Int32 iSource)
760 {
761 UNUSED(iSource);
762 /*
763 * Do the physical replication (the server will broadcast it),
764 * but only if this callback is being called for an outgoing
765 * message (i.e. a replication). Otherwise, a message just
766 * came in.
767 */
768
769 if (iType == MESS_OUTGOING)
770 {
771 (void)RISK_SendMessage(CLNT_GetCommLinkOfClient(CLNT_GetThisClientID()),
772 iMessType, pvMess);
773 }
774 }
775