xfrisk-1.2/0042755000175000017500000000000007043137312011704 5ustar johnojohnoxfrisk-1.2/Aide.risk0100644000175000017500000003345307000075544013444 0ustar johnojohno%À propos de Frisk et de ses auteurs Frisk a été conçu et écrit par Elan Feingold en 1994. That's me. I got bored during the Christmas break of my senior year and designed Frisk, on paper, since I didn't have any hardware with me. Upon returning to school, I spent about three months working on it, between classes and general beer drinking, before getting a playable version. Since then I graduated from Cornell with a BS in Computer Science (what else?), and am now working for Digital Equipment Corporation on their DECladebug debugger. Frisk stands for Free Risk or Feingold Risk, depending on whether I'm feeling philanthropical or egotistical. It is based on the Parker Brothers classic game, and I assume that they hold all the rights to the game. If you people are reading this, please don't sue me... Frisk is my programming magnum opus in many respects. It is the first full-length Xt/Xaw program I have written, and also the first to use UNIX network primitives. Because of this, I am sure that in some places my code will be non-optimal. I would greatly appreciate feedback on it, either in the form of suggestions for improvements, or "Man, your code sucks..." (although the latter might cause psychological damage). La traduction en français a été effectuée par Jean-Claude Colson. %% %Remerciements I wish to express my profound gratitude to the following people, without whom Frisk could have never come into existence: - Kirsten Mecklenburg: For her love and understanding. It isn't easy to be the girlfriend of a CS major. I'll be the first to recognize that. Thanks for being there (and for the coconut macaroons)! - Will Kling: For hiring me and being infinitely helpful during my migration up to NH. He actually inspired me to write the game, since I thought he and my other future co-workers would need a fun network game to increase productivity. - Robert Watts: For his infinite patience in play-testing Frisk. Even though he had nasty Quantum problem sets due, he would never refuse a good game of Frisk. Also for the acoustic versions of Layla while I programmed. Music calms the savage CS major. - Michael Plochocki: For being my token Macintosh user friend. His general ineptness with user interfaces helped me improve the ergonomics and user-friendliness of Frisk. But seriously, his invaluable suggestions helped mold Frisk into the game that it is. Thanks also for the late night chats about politics, religion, and of course, girls. - Darrin Edelman: For his encouragement and suggestions. If he had been living here instead of working for IBM like the loser that he is, I'm sure he would have been a great help to the project. Here's to keeping in touch after college. - Philip Soo: For letting me drag him in to see the latest improvements in the game. Phil has a knack for crashing anything in very little time. You can be assured that this program is Phil-proof. - Steve Thompson: For his feedback, and for hiring me to work in his lab, which gave me access to all sorts of platforms to test Frisk on. For his sense of humor, even though the HP's were down more than they were up. %% %Crédits This section holds all of the people who have submitted bug reports and new features for Frisk, along with people who have contributed in other ways (new ports, suggestions, etc.) It may not be exactly up to date, so if you submitted a report and don't see your name on here, don't panic. - Port to HPUX: Richard Lloyd - Port to SunOS/Solaris: Michael Davies, Matthew D. Stock - Port to AIX: Miguel Alvarez Blanco - Bug reports, testing, encouragement, help: David La Croix, CyberDrunk, Bruno Levy, Sam Louken, Al Longyear, Miguel Alvarez Blanco, Matthew D. Stock (thanks for the patch and the suggestions!), Andy Tefft, Bob Willmot, Martin Schulze, Charles Henrich, Glenn Rysko, John Kilburg, Michael Davies, Nicolaus Christiaan Thirion, Tom Tromey, Jeffrey David Cohen, Martin Wunderli, Mark Phillips, Robert Seals (thanks for all the help!), Craig Humphrey, Dave Lemke, Mario Antonioletti, Erik deRomph, Joel Fine, Bart Massey, Rick Niles, Davin Milun, James J Richmond, Joshua R. Poulson, Darin Johnson, Andrew R. Tefft, Clayton Haapala, Sydnor Francis, Ken DeMerchant, Bob Tanner, Marco Choi. %% %Plateforme de développement Frisk a été écrit sur un i386SX/16, avec 8 Mb de mémoire, sous Linux. The only thing saving me from insanity was my S3 video card, which made X quite usable. Having another 8 Mb of memory would have been great too, except that my motherboard only supports 8Mb! %% %Joindre l'auteur L'auter peut être joint par courrier électronique à elan@jeeves.net, et par courrier papier à: Elan Feingold 24 Newcastle Dr. #10 Nashua, NH 03060 Envoyez lui une carte postale si vous voulez! %% %Droits d'auteur The source code is Copyright (c) Elan Feingold 1993-1995. You may use it, abuse it, or improve it, under the following, vernacular conditions (the official sounding copyright notice appears at the top of all of the source files and at the bottom of this help item): (1) You leave the Copyright notice intact on the source files. (2) You credit me for any of my code that you use for any purpose. (3) You not release altered versions of Frisk in any form. (4) You don't use any of my code in any for-profit venture, without my explicit permission. Frisk is released as Poor-Engineer-ware. That means that the program is free, but if you like it you are welcome to send me cookies, money, or other donations that might improve my engineering career. If anyone has a spare Porsche 928, I could use it. Beer is fine, too. This is the Copyright notice that appears in each of the source files: PERMISSION TO USE, COPY, MODIFY, AND TO DISTRIBUTE THIS SOFTWARE AND ITS DOCUMENTATION FOR ANY PURPOSE IS HEREBY GRANTED WITHOUT FEE, PROVIDED THAT THE ABOVE COPYRIGHT NOTICE APPEAR IN ALL COPIES AND MODIFIED COPIES AND THAT BOTH THAT COPYRIGHT NOTICE AND THIS PERMISSION NOTICE APPEAR IN SUPPORTING DOCUMENTATION. THERE IS NO REPRESENTATIONS ABOUT THE SUITABILITY OF THIS SOFTWARE FOR ANY PURPOSE. THIS SOFTWARE IS PROVIDED "AS IS" WITHOUT EXPRESS OR IMPLIED WARRANTY. %% %Notes sur l'interface There are two message boxes where messages can appear, notifying you of some event or error. These two long rectangular boxes are located above and below the row of buttons. The upper box normally holds comments related to what you are doing, i.e. what country you have selected, or what you are expected to type into a pop-up box. The lower box generally holds error messages, although it can also contain informative messages, too. The number of attack die, as well as the default attack style (Single or Do-or-Die) is saved for each player, and restored when the player starts his or her next turn. %% %Le jeu The rules of Frisk are identical to the rules of Parker Brother's Risk game. The style of the game defaults to the server selecting the initial allocation of countries, and card exchanges being performed on a static basic (i.e. 3 different cards = 10 armies, 3 cavalry = 8 armies, 3 infantry = 6 armies, and 3 artillery = 4 armies). In this version, this is the only style of game supported. If you are not familiar with the rules of Risk, you are advised to learn them from another source, as this help does not attempt to fully explain all of the nuances of these. %% % Enregistrement des joueurs Avant de commencer à joueur, les joueurs doivent être enregistrés auprès du serveur Frisk. You do this by typing a name and a color for the player, and then clicking on "Register Player." The color can by anyone recognized by the X11 server, which comprise the colors listed in rgb.txt, normally located in /usr/lib/X11. All normal colors are there, i.e. yellow, green, pink, orange, along with some rather interesting others, such as gold, forest green, turquoise, and others. For most colors, a digit from 1 to 4 can be appended to the color name to generate successively darker tones of the color. At this time, if the game is being played over the network, other players may register simultaneously. Is the case that a player registers from a remote computer, the server will send all clients a message informing of this. When you are done registering players, click on "End Registration." At this point, if there are a total of two or more players, and all other clients have finished registering, play will commence. If all clients finish registering and the total number of players is less than two, the game will not be able to start, and the registration will have to begin again, after each client exits and restarts. %% % Fortification des pays You may reinforce a country by clicking on the country that you wish to place an army on. In styles of games that support reinforcing countries, reinforcing is staggered between players, with each player being able to reinforce one country with one army in one turn. %% % Positionnement des armées To place an single army, click the left mouse button on the country that you wish to place the army on. To place multiple armies, instead click on the country with the right mouse button, and a dialog will pop up asking you to specify how many armies to place. The text widget grabs the keyboard, so that you need not move the mouse to the dialog, and if the default number of armies is to your satisfaction, you need only hit . To place your all armies on a country, press the middle mouse button when you are on the country (the middle mouse button is usually emulated by pressing both mouse buttons on a two-button mouse). %% % Attaquer First click on the country to attack from, and then click on the country you wish to attack. The appropriate error messages for either of these two country selections will appear in the lower message box. If the country you have selected to attack from is valid, the text containing the number of armies in the country will light up. If your attack removes all of the enemy armies from the country you are attacking, you will be prompted with a dialog asking you how many armies to move into the country. If you wish to cancel an attack, you may click on "Cancel Action." If you had selected a country to attack from, this will be unselected. %% % Déplacer des armées First click on the country you wish to move armies from, and then click on the country you wish to move them to. If the source and destination countries are valid, a dialog will be presented to you, in which you can enter the number of armies to move. If you decide that you want to do more attacking, simply click on one of the attack actions and if you haven't moved armies, you can continue to attack. Once you have completed a valid move, your turn is ended, and Frisk notifies the server and the next player is now allowed to go. %% % Nombre de dés pour l'attaque This parameter is set by selecting an entry in the list-box in the lower left hand corner of the screen. If you select "Auto," then the maximum number of dice will be used. %% % Action This list-box, to the right of the Attack Die list-box, serves to select the action that you wish to perform. Appropriate error messages will be issued if you try to enter into illegal actions. %% % Placer des armées Upon beginning your turn, this is the state that Frisk enters. You will remain in this state until you finish placing all of your armies. %% % Attaquer This state specifies that when you select a source and destination country, only one attack is to be performed. You may repeat the attack by clicking on "Repeat Attack." %% % Attaquer à mort If you select this attack mode, then when you specify a valid attack, the computer will continue to attack until the territory has been conquered, or you don't have enough armies to continue attacking. N.B. There is no way to stop the attack once you have initiated it! %% % Déplacer This action has an identical interface to an attack. Select the source country by clicking on it. Then click on the destination country. A pop-up dialog will appear asking you how many armies to move. If you are satisfied with the amount (by default all but one), simply hit or click on OK. If you are not, move the mouse to the edit widget, and edit the number. When you are finished hit or click on OK. %% % Envoyer des messages Click on a player in the Message Destination list-box, or on "All Players" to broadcast the message. Type in your message in the long message entry widget above the box that displays messages from the server, and then hit . Your message will be sent immediately. You could use the feature to send covert messages, or establish secret alliances! You could just use it to insult other players, of course. %% %Futurs développements Look in the file TODO for features/bugfixes in the works. Look in the file ChangeLog for features implemented/bugs fixed. There are the enhancements I want to make for version 1.0 (in no real order): o Computer Players. Simple player. o New statistics and logging dialogs. o New registration dialogs (grabs focus, better color selection). o Change the scheme of all big dialogs to use message passing only. o A graphical toolbar with tooltips. o Save/Load. o Join Game/Leave Game. o Restart game (calls for voting protocall). o Change "Repeat Attack" to "Repeat Action" o Add game options (distributing countries, missions). o Dynamic (and optionally persistant) player color editing. There are my longer term goals (version 2.0?), in no particular order: o Increase the aesthetic value of the game (3D map, new NeXTStep-like widgets?). o Genetic Programming computer player. o Drag 'n Drop for armies from dice window like MAC-Risk? o Nicer color selection (color cube (square))? o Port to Windows 95! o Menu bar instead of the widgets at the bottom of the screen? o Make the whole thing better abstracted in terms of OS and GUI. o Undo feature. o GUI for server, to pick game options, show statistics? %% xfrisk-1.2/BUGS0100644000175000017500000000260107000076347012364 0ustar johnojohnoo Sometimes the card list seems to get corrupted, which results in an infinite stream of dialogs saying "Bogus request to CARD_RenderCard" and trashes the game in progress. One time some wrong country counts were observed in the stats window shortly before hand, but this may not be related. o Sometimes if you remove a player and add a new one, particularly if the old player had played in a game already, it doesn't fully go away, and your messages get reported as coming from it instead of you. o Should report FQDNs of people connecting. Should also be able to work out who people are during a game. o If you kill somebody off and end up with more than 9 cards (so you'd need to exchange two sets to get to 5 or under) it doesn't let you, and then you end up with six cards and things go rapidly downhill as you exchange cards during other people's turns. (Later note: this situation came up for me recently and didn't break things, so maybe the problem went away or only occurs some of the time.) o Focus gets grabbed by Frisk when adding a player after popping down color editing box. o Focus doesn't always get set right for the armies popup. Doesn't get set from main window to armies. o Two computers playing against each other dying doesn't restart the game -- server bug? o Clients appearing after a new species registers are not notified of the species. xfrisk-1.2/COPYING0100644000175000017500000004312707011644031012735 0ustar johnojohno GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc. 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Library General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) 19yy This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) 19yy name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Library General Public License instead of this License. xfrisk-1.2/ChangeLog0100644000175000017500000007223107041170237013457 0ustar johnojohno VERSION LIST: ============= o v1.2 Fixed: o colormapping in truecolor, especially the world mapanciq o fixes in color dialog, color player in dialogs o speedup in colormapping/gui o dice were not correct o graph shows more now o greenland card now shows o options for number of armies to drop during fortify o restructuring/cleaning up code o a start with using doxygen for documentation o moving language stuff to language.h o using cvs now Known bugs: o scrollbars in colordialog don't get initiated right they receive wrong values, and thus ignore these (Xaw code) o gui may load in bad colors in 8bpp o v1.1 MAJOR CHANGE: o License changed to GNU GPL version 2, see file COPYING for details o v1.00+efnet10 Added: o ChangeLog entry for v1.00, which apparently got forgotten in the 1.00 release. o Merged v1.00 with +bpk2+pac3+argon5. "efnet10" is this patch collection. (efnet is an irc network.) The version names have been altogether too long lately. Fixed: o Some minor glitches in v1.00. o Report the version string correctly. o v1.00 Added: o Merged the +argon1 patch. Fixed: o Cleaned up rgb handling. o Some fixes to non-pseudocolor mode operation. o Other minor cleanup. o v0.99c0-pl9+bpk2+pac3+argon5 Fixed: o Cleaned up makefiles a bit. Include hack version of snprintf for use when necessary. o v0.99c0-pl9+bpk2+pac3+argon4 Added: o Removed diceAI.c; it was an extraneous copy of aiDice.c. o Assorted cleanup, abolition of globals, etc. Fixed: o Still more language fixes. o sprintf -> snprintf. o v0.99c0-pl9+bpk2+pac3+argon3 Fixed: bug in +pac2. o v0.99c0-pl9+bpk2+pac2+argon3 Fixed: o Fixed makefile lossage in +argon2. o Don't install app-defaults since they seem to disable some features. (!) o Fixed conflict between two global "hFile" vars. o More language fixes. o Include alternate makefile for pmake on BSD boxes. o v0.99c0-pl9+bpk2+pac2+argon2 Fixed: o The server was making an assumption about turn order, which turns out to be false when bpk's multiple-fortify feature is used. Server no longer makes this assumption. o Another bogus assertion patched ("player has cards and shouldn't") o Added bounds checking on a certain XGetPixel in colormap.c (patch-dossy1) o v0.99c0-pl9+bpk2+pac1+argon2 Added: o Merged pl9 and pac1 (and thus bpk2) fixes. Fixed: o Updated install docs to reflect absence of imake. o v0.99c0-pl9.pac1: Added: o 15- and 16-bit colormap support from argon. o Merged pl9 changes with pl8.bpk2. Fixed: o Fixed it so -DDEBUGGING doesn't make it bomb out from bogus assertions! o v0.99c0-pl9: Fixed: o Imakefile: added -I/usr/openwin/include to CCOPTIONS in #ifdef SunArchitecture o Fixed some English/French #ifdef oopses, result: more English comes through o v0.99c0-pl8.bpk2: Fixed: o Fixed an infinite loop bug in aiConway. o v0.99c0-pl8.bpk1: Fixed: o Place multiple armies during fortification. o Made a few grammar corrections. o v0.99c0-pl8+argon2 Fixed: o Spelling and language fixes ("Infantery", "Cavalery", etc.) o 'bool' is a reserved word in C++, don't use it. o Use random/srandom instead of rand/srand. o Fix assorted compiler warnings. Compile with -Wall -W. o v0.99c0-pl8+argon1 Added: o Support for 16-bit and 15-bit truecolor. Fixed: o Got rid of Imakefile, use real makefile. o v0.99c0-pl8: Fixed: o Doling out of initial armies was incorrect -- too many armies were being given (12.7.95) o Color editing was broken -- fixed it (12.7.95) o v0.99c0 - Added: o Computer players!!! (3.30.95) o The first MVC view -- the Statistics View. (2.19.95) o A new registration procedure, with 2 new dialogs. Supports computer players, new color editing procedure, etc. (1.29.95) o A README.NEW files to describe from a user's standpoint what has changed. (1.26.95) o Moved all of the Xt translation tables to the X resource file. (1.24.95) o A Color section dialog for editing colors and selecting colors at the beginning of the game. (1.23.95) o Set TCP_NODELAY option on sockets, in hopes of making game snappier. (1.22.95) o Added versioning control to the connect protocol. Client and server must have the same version. If this is too strict I can change it later. (1.23.95) o Began design of general distributed object framework, based on a subset of the CORBA IDL, possibly with extensions. Will support transparent distributed objects (i.e. they can be local or remote, client invocation is identical). Will facilitate directory services, acting as a meta-server for games going on, and for clients. i.e. dir->getListOfGames("Risk*\\|Mono*", CurrentlyPlaying); dir->registerGame("Risk", "avette.zko.dec.com"); If it wasn't clear already, the bindings will be C++ based, with possibly future bindings for Eiffel and Smalltalk. This all implies quite a large rewrite of Frisk. Fixed: o Added an #include to debug.h. Thanks to Jarno Kokko for pointing this out! (6.14.95) o Simplified handling of players & clients leaving the game. (5.20.95) o A bug where the "add player" dialog wasn't checking if SpeciesToSlot was returning -1 ==> Core dump. (5.13.95) o A terrible bug when exchanging a set of cards including a joker, it would try to fortify to corresponding territory (which doesn't exist, of course!) Thanks to Alan Bowsher for finding this one!! (5.13.95) o Fixed a retarded bug in UTIL_NumPlayersAtClient, which wasn't checking to see if the players were allocated. This resulted in a segfault when sending a message from a client that used to have a player but now didn't. (5.13.95) ------ o ------ o A bug where the wrong species was being selected (5.6.95) o An obnoxious bug where the label in the popups wouldn't be big enough. (4.30.95) o Multiline messages get handled better -- the whole message gets displayed. It's not perfect, but it's much better than before. Xaw widgets suck. (4.30.95) o Fixed an assertion failure in the server. (4.30.95) o Cleaned up some of the code in the server. The game was being reset more than once in some cases. (4.30.95) o A heinous card bug whereas the right cards would be exchanged, but a different set would be removed from the player! Thanks to Jarno Kokko for pointing this one out. (4.23.95) o Armies popup no longer grabs keyboard. (4.11.95) o Better and more consistant messages upon startup of clients. (4.11.95) o Fixed repeating "Game is over..." message. (4.11.95) o A few more bugs in the server related to games starting. (4.11.95) o Fixed a bug where a color on one client might not be displayable on another -- the new code gets the closest displayable color on each client (4.6.95) o A few bugs related to games restarting after a client crashed or exited. (4.4.95) o A problem with the dist. obj. It had some data members (iNumPlayers, iNumLivePlayers, etc.) that were distributed the same as the other data members. However, they weren't minimal (intrinsic) data -- it could be calculated. And when a client called RISK_SetAllocationStateOfPlayer(iPlayer, ALLOC_COMPLETE), before it called RISK_SetNumPlayers, there was an inconsistancy, which led to a race condition. (4.1.95) o Added SO_REUSEADDR as an option to the server socket. This prevents the server not being able to start because of a crashed client, I think. It should help at the very least. (2.27.95) o Moved the dist. obj. messages MSG_OBJ[INT|STR]UPDATE into riskgame.c, for better encapsulation. (2.25.95) o Cleaned up the registration phase in the server, fixed some minor bugs, not of much interest. (1.22.94) o Fixed another card bug, which was letting players on other clients exchange cards, to the detriment of the game. This caused core dumps, and wierd card behavior. (2.21.95) o Fixed the invariant "RISK_[Set/Get] should only be set on valid players or countries." which means that before while loops ran to MAX_PLAYERS, now they run to RISK_GetNumPlayers... (2.19.95) o Strengthened the semantics of object callbacks to occur _before_ or _after_ the state of the distributed object has been updated (so that the before/after values can be seen). (2.15.95) o A bug in the server that caused an assertion to trigger because iServerMode wasn't equal to SERVER_REGISTERING when it should have been. (1.24.95) o Pointer arithmetic that wasn't ANSI-C in network.c (1.21.95) o Changed the "developer's configuration" to not include gcc-specific flags. (1.23.95) o v0.99b4 - Added: o More comments in the Imakefile. (1.10.95) o Long and short term goals for Frisk in TODO better organized and prioritized. (1.17.95) Fixed: o The elusive card related bug that caused core dumps mostly on SunOS/Solaris machines. I'm positive that this one is finally dead :) (1.15.95) o A bug in the code that deleted old message destinations when clients exited. New code works like new windows (cards, stats, etc.) will, by receiving messages (events) and acting on them. (1.15.95) o Got rid of most remaining memory leaks. (1.15.95) o Initialized `iTo' field in a few places to avoid uninitialized memory (even though the field was not being used.) (1.15.95) o `make install' now installs `risk'. (1.10.95) o Rules in the Imakefile to install date files and programs changed to obey LIBDIR and BINDIR. (1.10.95) -- thanks to Rick Niles for suggesting this. o INSTALL updated to reflect changes. (1.10.95) o Changed the exit values of findtypes to be -1 for cases in which the program couldn't find the needed types. (1.10.95) o v0.99b3 - Added: o Fallback resources. No more resource woes!! (many people had mentioned this). (12.31.94) o When loading one of the data files, the client now checks in the current directory, as well as the one specified by FRISKPATH, to make users lives' easier. (12.31.94) o The year 1995 to the Copyright. Hopefully it will be a good year for Frisk :) (12.31.94) o Checks in _NET_Recv* to make sure that the number of bytes read was the number expected. (1.1.95) Fixed: o Changed player message sending so that if the message is coming from a client with more than one player, if the current player is at the client, the message comes from him or her. This seemed to make more sense, since the person who's turn it is would seem to have control of the keyboard/mouse. (1.9.95) o Changed an if..else to assert. (1.9.95) o A vulgar error message was made less so. (1.8.95) o A "free" card was being given to the first player at the client that won the previous game. (Thus, the problem would not occur in very first game that the client is involved in.) This was a result of UTIL_EndTurn not being called when a player wins, and the global "player gets card at the end of turn" flag not getting reset. (1.5.95 -- DFE) o Some arg/format mismatches in debug.c. (1.2.95) o Some dependencies in the Imakefile so that one can type `make friskserver' or `make xfrisk' and have it work. (1.2.95) o Updated the Help file to be more up-to-date. (1.2.95) o The color coded player turn indicator no longer starts out as a random color -- it's set to black. (1.1.95) o _NET_Recv* and _NET_Send* (the backbone of Frisk communications) now correctly handle cases in which the read()/write() calls do not read/write the entire block of data. This fixes the obscure, nondeterministic, and quite hard to track down problem of bogus messages when I was running Frisk over a 9600 baud SLIP link. It could conceivably be the cause of many little problems, but 99.9% of them would lead to a bogus message, which would have resulted in the termination of the client (or server). I'm _really_ glad to lay this one to rest! (1.1.95) o Fixed a memory leak in riskgame.c, which happened whenever replication was done. (1.1.95) o Fixed an assertion trigger when notifying a new client of who's turn it was -- the invariant for iTurn had changed, and I hadn't updated the code. (1.1.95) o Clarified some more things in INSTALL. (1.1.95) o Delinted sources. Nothing major discovered. (12.31.94) o Made the whole app a little bit wider, so that the total size sans WM is 800 pixels (it was a few pixels less). Also fixed a few other off-by-one errors in other widgets. (12.31.94) o Changed the comments in the resource file to be "!" comments, and not C comments. (12.31.94) o Stopped the Makefile from installing buildmap, which seemed pointless. (12.31.94) o Corrected the declaration of GUI_GetNumColorsInMap to be static. (12.31.94) o Grammar correction -- "1 die, 2 _dice_, etc." (12.31.94) o Cleared up error mesages to make them more helpful and precise. (12.31.94) o A bug in the card scaling that probably caused the elusive SEGVs reported by various people. The card scaling now uses a slick version of Bresenham's algorithm to scale the country images using only integer arithmetic. (12.31.94) o A bug in the die coloring, I wasn't updating enough with my caching scheme, so the die colors weren't always right. (11.27.94) o A serious bug I introduced fixing another, that would trigger an assertion failure or mess things up in some cases when a player killed another. The bug was in SRV_IterateTurn(). (11.27.94) o Added a step to the INSTALL procedure that describes setting the XAPPLRESDIR environment variable (thanks, Martin!) (11.27.94) o Changed to , since in general, most platforms' strings.h simply includes string.h. This should help the compile on some machines, and hopefully not break it on others :) (11.27.94) o v0.99b2 - Added: o The server now warns when another server is running, instead of exiting with a cryptic message. o Code in MEM_Free that NULLs the pointer that is being freed, so as to catch references to bogus pointers. o Some code in colormap.c that copies over colors from the window manager to Frisk's colormap, if it allocates a private one. This makes Frisk with a private colormap a bit prettier, and reduces the flicker when entering and exiting the window. o A question to the FAQ. o Clients now broadcast a message out when one of its players exchange cards. o A shutdown call to hopefully help out the server port hanging out after the server exits. Not sure it will though. SO_REUSEADDR isn't good because it lets there be more than one server around. SO_[NO]LINGER didn't seem to be doing anything. o A thicker border between Asia and Europe as requested, to be able to differentiate the continents, as per requested by many. o The option to display remote dice rolls. Each dice roll takes exactly 3x2x4+4 = 28 bytes. Eventually there should be an option to not send this information. o Made the TEST_GAME mode more intelligent. It gives all of the countries to one player, and then one country each to the rest. Each player is given two armies to place after the country distribution. o Changed the "A new client, xxx, has registered" to add quotes around the name of the client, to be consistant. o Graphical notification of moves, attacks, and placements by players at remote clients. If one country is involved (place), the country lights up for a defined amount of time (if further actions take place with that country, the country simply remains lit longer. If there are two countries involved, then the source country lights up and a line a drawn from the source country to the destination country. The line is left up for the same amount of time as the country, currently. This makes remote play much friendlier, IMHO. It's much clearer who's doing what, and where. Comments are more than welcome. The line only appears for the first attack if multiple attacks are performed on the same country, a la do-or-die. o Added verbose notification of remote players changing state (i.e. "xxx is attacking.", "xxx is moving armies.", etc.). N.B. With this change, and the remote dice rolls, I'm ready to do computer players. The scoop is, they will be linked against a library that resembles a client. Thus, computer players have their own clients and communicate with the server the same way other players do. This way, the development cycle for computer players is simplified, and they can't crash or hold up the server. They algorithms that play will call GAME_PlaceArmies, GAME_MoveArmies, and GAME_Attack, just as clients do now, and will have full (read-only) access to the distributed object. I'd like to do a computer player that uses a genetic algorithm (heuristic encodes as bitstring that represents "Risk assembly language"?) Fixed: o Fix "move armies" --> "do or die" transition. It was jumping to whatever the player's default was. (11.19.94) o Fixed so that new player information wasn't printed at remote clients twice. (11.16.94) o A bug where cards of freed players weren't being returned to the deck. It didn't really matter because a new deck is being used for each new game anyway. (11.6.94) o A bug where the number of live players would not be kept correctly, and the number would end up as -1 at the end (caught by an assertion failure). (10.30.94) o Fixed a bug where I wasn't initializing the distributed object for the client soon enough. (10.30.94) o Set default color for foreground as black. (10.8.94) o Changed TESTGAME to be TEST_GAME, made more sensible. (10.8.94) o Changed finite state machine in server to have one extra state, SERVER_FORTIFYING, and added support code, to fix a bug related to fortification when the number of countries doesn't distribute evenly among the players (e.g. 4 players, 5 players, 8 players and 10 players). (10.8.94) o The bad color for army number bug (the army number on the countries was being printing in a wierd color when Frisk was using a private colormap). (10.8.94) o A bug where I was freeing a client that I didn't allocate. (10.15.94) o A bug where exchanging 3 jokers wouldn't give you 10 armies, as it should. (10.15.94) o A bug where an assertion failure would trigger, because the server was trying to SetNumLivePlayers on a player who was dead already. (10.15.94) o A bug that occurs when the last player kills another player, iTurn gets messed up and goes to the 1st and not 0th player. This bug would appear in other cases where a player killed another (not the last). (10.29.94) o v0.99b1 - Added: o Architecture detection utility (which generates types.h file with Int32, UInt32, etc. definitions. o Cleaner definitions of derived types that don't clash with the ubiquitous Xt types. Changed all 'String's to 'CString's and all 'Boolean's to 'Flag's -- cause gcc defines Bool, I believe? Phooey... o Cleaned up debug.[c|h] for other architectures. Fixed: o Bug in the server, wasn't handling a player allocation correctly (like a transaction). (10.4.94) o Bug in the server, wasn't breaking out of handling MSG_DEREGISTERCLIENT when mode was SERVER_PLAYING. (10.3.94) o lack of check for hFile being NULL. (10.3.94) o Data type of pointer data in debug.c (10.3.94) o Prototype of CLNT_Init. (10.3.94) o Added semicolons to default case in order to compile with Alpha OSF/1 cc. (10.3.94) o Patches to compile on OSF/1 (and hopefully other 64 bit machines). (10.3.94) o Changed Int to be Int32, and so forth, in an effort to make Frisk more portable between different compilers and architectures. (10.3.94) o v0.99b0 - Added: o Patches to compile on AIXv3. o Patches to compile on SunOS 4.1.x. o Patches to compile on HP-UX 9.x. o Cleaned up riskgame constructors. o Many assertions to catch mistakes. o Signal handlers to help server clean up, and tell clients when killed. o Error handling improved, server MUCH more robust. o Handling of client/server failures. o Separated specific parts of the riskgame object into client and server modules. o Redesigned the riskgame interface a bit to make more consistant and robust. o First hooks for computer players. o SO_LINGER option for server socket so that it doesn't hang around (I hope). o MSG_NETPOPUP for sending messages that result in a popup dialog box. o MSG_POPUPREGISTERBOX for telling client to do exactly that. o Assertion failures dump core so that one can obtain a call stack of when the assertion failed, and print out the assertion that failed, as well as the message. o Any clients that show up after the game starts are taken as observers. Their local copy of the Distributed object is updated when they connect. They can, of course, register players the next game. o Cleaned up the server. It now only has one case statement to handle all incoming messages. o Each client now uses only one socket (what was I thinking? :) o If there aren't enough free colors, Frisk allocates its own colormap. o Middle mouse button now places all armies, per request of Michael Davies. Fixed: o Missing parameter in debug.h macro. (7.14.94) o Change RISK_[Send|Receive] to return Boolean "Failure occured." (10.1.94) o Not double-checking attack dice. (8.27.94) o Bug in RISKGAME_SelectiveReplicate. (7.16.94) o File descriptor problem (HPs). (7.27.94) o Off by one bug in checking max clients. (7.27.94) o Color indices of players (make them per-client -- oops :). (8.28.94) o World colors show up at the beginning, instead of whatever was there in the colormap before. (8.28.94) o Fixed (rewrote) the end of game code. (8.28.94) o The card window crashing the client bug. (9.2.94) o Armies == -1 bug with new game. (9.1.94) o Set the default border color to be black. (9.28.94) o Fixed the message sending. Private messages now work correctly. (10.02.94) o Numerous other little bugs. o v0.99a - Added: o Memory debugging library. o Cleaned up exiting method. Fixed: o Most memory leaks. o Card rendering bug. (6.25.94) o v0.99 - The first version ready for distribution. Before release... o Speed up the map loading (2.21.94) o Build a routine NET_SendSyncMess that handles incoming messages, dispatches those not == to the type waited for, and then returns!!!! (3.4.94) o Factor out the UPDATE code so that it can be used in a local case and a remote case, into a RISK_ file. RISK_MoveArmies(), RISK_PlaceArmies(), RISK_Attack(), etc... (3.4.94) o Optimize for the local case, so that data is kept, and server messages coming from client that receives them is ignored. (3.4.94 -- Server doesn't send msg to client that it got it from) o See if in the vector of attackable countries there are any that are attackable from the selected country. Also check to see that there are enough armies to attack. (3.5.94) o Make the square to the left of the message turn the color of the current player. (3.6.94) o Create the "Number of armies?" popup. (3.7.94) o Make the dice change to the color of the dice rolling players. (3.4.94) o Vectors of attackable countries. (3.4.94) o Glue for registration (translation, Enter, etc...). (3.14.94) o Fix deck so that it works like a real deck of cards. (3.17.94) o Fix a possible placement bug (==> -1). Two clicks close together can result in two armies being placed for one player. PROBLEM is when player clicks after message is sent, and before new TURN_NOTIFY message arrives -- does this call for my first use of SendSyncMessage ?!?!? Yes. (3.17.94) o Bonuses for owning whole continents. o Make the text showing the # of armies text turn white when the country is selected for something! o Detect winning/losing. o Cards for taking a country. o Fix the joker crashing problem. o Fix the problem that calculates wrong Card Types. o XtGrabKeyboard for the popup -- can't seem to do it. o Help system. (4.1.94) o Make the text widget resize itself depending on the text length in the help popup. o Make the game start on a random player, instead of the first that connects. o Fix the centering of the name for the cards. o Fix the parts of Frisk specific to network play (it's broken right now). o Design dialog box (Yes/No, etc.) ==> Quit confirm box. o Detect end of game. o New game option --> More players, Same players, New players. o Change CARDPACKET to include a player. >=5 cards forces exchange rule. Implement getting cards just through callbacks. (4.11.94) o Dead player gives player cards rule. (4.11.94) o Do the exposure handling for the dice. (4.11.94) o Clean up RiskGame to be a clean distributed object. (5.3.94) o Sending messages to each other (glue, translations). (5.3.94) o Translations for , , etc. (5.3.94) o Fix that players put one too many armies down at start. (5.3.94) o Fix that size of message popup box buttons don't change. (5.4.94) o Fix two cards come out identical bug? (5.5.94) [Haven't seen it...] o Draw the lines between countries. (5.5.94) o Do the colormap stuff, check for black/white, reserve them. (5.5.94) o Fix player's deaths. (5.6.94) o Fix end of game condition. (5.6.94) o Handle the case that too many players/clients register. (5.6.94) o Add message(s)/functions that allow server to reset/restart. (5.6.94) o Add message(s), etc. to update client who is joining late. (5.6.94) o Integrate error handling, add X popup support, global Exit func. (5.10.94) o Fix bugs in giving dead player's cards away (more than one exchange). (5.10.94) o Fix you seeing the other person's cards... (5.12.94) o Change fdMin/Max to be a map of descriptors. (5.13.94) o Implement voting for restarting. (5.13.94) o Fix race condition when 2+ players register at once. This only occurs in Registration, since at other times, only one player is active. Move AllocPlayer/FreePlayer into server... (5.15.94) o Fix game restarting. (5.16.94) o fix message destinations, (not appearing on dest. machine). (5.16.94) o Keep track of the info that passes through (_UPDATEs), so that in case of a client failure, it can be revived. (5.3.94) (Through RiskGame distributed object.) o Finish Help. (5.16.94) o Finishing touches to Map. (5.17.94) o Fix so that 24 bit X servers work (incorporate patches). (5.19.94) o Add message so that network play is more verbose for player. (5.19.94) o Warning message when you select start registration with nonempty dialog. (5.19.94) o Clean up debug.c/h. (5.19.94) o Add keeping track of the attack die & msg dest just like attack mode. (5.19.94) o Fix Do-or-Die with a set attack die. (5.19.94) o Draw line betwen Japan and mainland. (5.19.94) o Dotted line between Britain and Northern Europe. (5.19.94) o Write an Imakefile. (5.20.94) o XFlush to speed up army placement? (5.20.94) o Clean up debug.h/c and integrate into project. o Destroy messages when finished with them ==> NET_DestroyMessage(). (6.24.94) o Add a uniform way to exit, i.e. UTIL_FatalError(str) xfrisk-1.2/FAQ0100644000175000017500000001054007041646062012236 0ustar johnojohnoFrequently asked Questions (with answers): ========================================== 0. WHAT DOES "Error: Widget wDiceBox has zero width and/or height" MEAN? 1. WHY IS MY DISPLAY ALL SCREWED UP/HOSED/POKED? 2. I CAN'T GET XFRISK TO START. WHY? 3. HOW DO I START A MULTICLIENT GAME? 4. WHAT ABOUT COMPUTER PLAYERS? 5. IT SAYS "Assertion Failure" AND THEN DUMPS CORE. WHAT DO I DO? 6. I AM FROM PARKER BROTHER AND WANT TO SUE YOU. WHAT DO I DO? 7. IS THERE ANY WAY I CAN BUILD XFRISK WITH MORE DEBUGGING INFORMATION? 8. HOW CAN I HELP? 9. WHAT IS THE URL FOR XFRISK WEBSITE? ******************************************************************** 0. WHAT DOES "Error: Widget wDiceBox has zero width and/or height" MEAN? See question 1, the same solution applies. IT SHOULDN'T HAPPEN AS OF 0.99b3, WHICH HAS DEFAULT RESOURCES! 1. WHY IS MY DISPLAY ALL SCREWED UP/HOSED/POKED? Is the app resource file XFrisk.ad installed in the right place? You can change the XAPPLRESDIR environment variable to check in the current directory by typing something like: setenv XAPPLRESDIR /usr/lib/X11/app-defaults:./ IT SHOULDN'T HAPPEN AS OF 0.99b3, WHICH HAS DEFAULT RESOURCES! 2. I CAN'T GET XFRISK TO START. WHY? If XFrisk is unable to find some of its files, "make install" again in the XFrisk source directory to reinstall the data files and programs. 3. HOW DO I START A MULTICLIENT GAME? In order to set up a multiclient game, run friskserver on one machine, and then run the clients on the remote machines as follows: kashmir > friskserver & ... silk > xfrisk kashmir & ... cotton > xfrisk kashmir & Clients may register players while the other clients join. The game starts when all clients that have registered players have pressed the start button (be careful about this, you might accidentally leave out someone who is still registering a player or just connecting!). Clients can connect at any time during a game to watch it, and register players after the game has ended. Also note: there can be more than one human player on the same client. 4. WHAT ABOUT COMPUTER PLAYERS? Computer players come as separate clients, named eg. aiColson and aiConway. They get installed with the rest of the package in the same directory as the xfrisk and friskserver binaries (BINDIR in Makefile). Once you have a server running, you need to connect them like this (assuming you are running the server on your local system): aiColson localhost & When you select Add Player, you should see multiple entries in the Species box. Select a non-Human one (Ordinateur for aiColson), and edit player info normally. You now have a computer player in your game. You can add more than one AI species by repeating the above procedure with another AI client program. Also note that once an AI species is registered in the game anyone connecting to the server can add AI players to the game. Anyone can also remove them. 5. IT SAYS "Assertion Failure" AND THEN DUMPS CORE. WHAT DO I DO? In general, whenever you get a core dump, it would be greatly appreciated if you sent details to the developers -- it will result in a more robust game for you. In order to send info, run a debugger on the core file as follows (stuff in [] are comments): $ dbx [or gdb] server [or client] core dbx> where If you send the output of the "where", along with a description of how it happened, then we'll probably have a fix ready within a few days N.B. You have to have compiled XFrisk with debugging in, see question 8. 6. I AM FROM PARKER BROTHER AND WANT TO SUE YOU. WHAT DO I DO? Yo no hablo ingles... Sue not here! 7. IS THERE ANY WAY I CAN BUILD FRISK WITH MORE DEBUGGING INFORMATION? Yes. Look in Makefile, and leave the developer's CDEBUGFLAGS uncommented. Then remake XFrisk. 8. HOW CAN I HELP? If you find a bug you can send us a bug report. Patches that improve the game will be considered also, based upon their quality and desirability. Patches that are included will be credited. You can find contact information for sending patches on the XFrisk website (see next question). 9. WHAT IS THE URL FOR THE XFRISK WEBSITE? http://www.iki.fi/morphy/xfrisk/ The URL redirects you to another site but please bookmark and/or link only to the above URL as it is the official one. xfrisk-1.2/Help.risk0100644000175000017500000003533707041653611013477 0ustar johnojohno%About Frisk and its original author Frisk was designed and written by Elan Feingold in 1994. That's me. I got bored during the Christmas break of my senior year and designed Frisk, on paper, since I didn't have any hardware with me. Upon returning to school, I spent about three months working on it, between classes and general beer drinking, before getting a playable version. Since then I graduated from Cornell with a BS in Computer Science (what else?), and worked for Digital Equipment Corporation on their DECladebug debugger, which continuing to improve the game. Currently I work at AetherWorks Corporation (http://www.aetherworks.com), on a project called Jeeves. Frisk stands for Free Risk or Feingold Risk, depending on whether I'm feeling philanthropical or egotistical. It is based on the Parker Brothers classic game, and I assume that they hold all the rights to the game. If you people are reading this, please don't sue me... Frisk is my programming magnum opus in many respects. It is the first full-length Xt/Xaw program I have written, and also the first to use UNIX network primitives. Because of this, I am sure that in some places my code will be non-optimal. I would greatly appreciate feedback on it, either in the form of suggestions for improvements, or "Man, your code sucks..." (although the latter might cause psychological damage). Note: XFrisk is currently maintained by a different team of developers, so be easy on Elan. It might not be his bugs. See file "FAQ" in sources for maintainer contact info. %% %Acknowledgements I wish to express my profound gratitude to the following people, without whom Frisk could have never come into existence: - Kirsten Mecklenburg: For her love and understanding. It isn't easy to be the girlfriend of a CS major. I'll be the first to recognize that. Thanks for being there (and for the coconut macaroons)! [Update: Hum, she's actually my ex-girlfriend now, but still my best friend!] - Will Kling: For hiring me and being infinitely helpful during my migration up to NH. He actually inspired me to write the game, since I thought he and my other future co-workers would need a fun network game to increase productivity. - Robert Watts: For his infinite patience in play-testing Frisk. Even though he had nasty Quantum problem sets due, he would never refuse a good game of Frisk. Also for the acoustic versions of Layla while I programmed. Music calms the savage CS major. - Michael Plochocki: For being my token Macintosh user friend. His general ineptness with user interfaces helped me improve the ergonomics and user-friendliness of Frisk. But seriously, his invaluable suggestions helped mold Frisk into the game that it is. Thanks also for the late night chats about politics, religion, and of course, girls. - Darrin Edelman: For his encouragement and suggestions. If he had been living here instead of working for IBM like the loser that he is, I'm sure he would have been a great help to the project. Here's to keeping in touch after college. [Update: we now work together at AetherWorks!] - Philip Soo: For letting me drag him in to see the latest improvements in the game. Phil has a knack for crashing anything in very little time. You can be assured that this program is Phil-proof. - Steve Thompson: For his feedback, and for hiring me to work in his lab, which gave me access to all sorts of platforms to test Frisk on. For his sense of humor, even though the HP's were down more than they were up. %% %Credits This section holds all of the people who have submitted bug reports and new features for Frisk, along with people who have contributed in other ways (new ports, suggestions, etc.) It may not be exactly up to date, so if you submitted a report and don't see your name on here, don't panic. - Port to HPUX: Richard Lloyd - Port to SunOS/Solaris: Michael Davies, Matthew D. Stock - Port to AIX: Miguel Alvarez Blanco - Bug reports, testing, encouragement, help: David La Croix, CyberDrunk, Bruno Levy, Sam Louken, Al Longyear, Miguel Alvarez Blanco, Matthew D. Stock (thanks for the patch and the suggestions!), Andy Tefft, Bob Willmot, Martin Schulze, Charles Henrich, Glenn Rysko, John Kilburg, Michael Davies, Nicolaus Christiaan Thirion, Tom Tromey, Jeffrey David Cohen, Martin Wunderli, Mark Phillips, Robert Seals (thanks for all the help!), Craig Humphrey, Dave Lemke, Mario Antonioletti, Erik deRomph, Joel Fine, Bart Massey, Rick Niles, Davin Milun, James J Richmond, Joshua R. Poulson, Darin Johnson, Andrew R. Tefft, Clayton Haapala, Sydnor Francis, Ken DeMerchant, Bob Tanner, Marco Choi. %% %Development Platform Frisk was written on an i386SX/16, with 8 Mb of memory, running Linux. The only thing saving me from insanity was my S3 video card, which made X quite usable. Having another 8 Mb of memory would have been great too, except that my motherboard only supports 8Mb! [Update: Now I work on a dual PPro 200Mhz with 256Mb of RAM -- times change...] %% %Reaching the Author I can be reached via e-mail as elan@jeeves.net, and via snail-mail as: Elan Feingold 6434 City West Pkwy. (6301) Eden Prarie, MN 55344 Send me a postcard if you like! For issues concerning XFrisk development, like bug reports, patches and suggestions, you are advised to contact the development team. See file FAQ in sources for contact info. %% %Copyright The source code is Copyright (c) Elan Feingold 1993-1999. XFrisk was placed under the GNU General Public License (GPL) November 8th 1999. See file COPYING for license conditions. Frisk was originally released as Poor-Engineer-ware. That means that the program is free, but if you like it you are welcome to send me cookies, money, or other donations that might improve my engineering career. If anyone has a spare Porsche 928, I could use it. Beer is fine, too. This is the Copyright notice that appears in each of the source files: This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA %% %Interface Notes There are two message boxes where messages can appear, notifying you of some event or error. These two long rectangular boxes are located above and below the row of buttons. The upper box normally holds comments related to what you are doing, i.e. what country you have selected, or what you are expected to type into a pop-up box. The lower box generally holds error messages, although it can also contain informative messages, too. The number of attack die, as well as the default attack style (Single or Do-or-Die) is saved for each player, and restored when the player starts his or her next turn. %% %The Game The rules of Frisk are identical to the rules of Parker Brother's Risk game. The style of the game defaults to the server selecting the initial allocation of countries, and card exchanges being performed on a static basic (i.e. 3 different cards = 10 armies, 3 cavalry = 8 armies, 3 infantry = 6 armies, and 3 artillery = 4 armies). In this version, this is the only style of game supported. If you are not familiar with the rules of Risk, you are advised to learn them from another source, as this help does not attempt to fully explain all of the nuances of these. See the XFrisk website (URL for it is in file FAQ of sources) for helpful links. %% % Registering Players Before beginning the game, you must register players with the Frisk server. You do this by typing a name and a color for the player, and then clicking on "Register Player." The color can by any one recognized by the X11 server, which comprise the colors listed in rgb.txt, normally located in /usr/lib/X11. All normal colors are there, i.e. yellow, green, pink, orange, along with some rather interesting others, such as gold, forest green, turquoise, and others. For most colors, a digit from 1 to 4 can be appended to the color name to generate successively darker tones of the color. Press the return key after typing in the color name to update the color scrollbars and example country image - this does not close the dialog. If you have connected an AI client to the server, there will be several options in the Species box. Select one of the non-Human options to create a computer player. (See the file FAQ for more info on computer players) At this time, if the game is being played over the network, other players may register simultaneously. Is the case that a player registers from a remote computer, the server will send all clients a message informing of this. When you are done registering players, click on "End Registration." At this point, if there are a total of two or more players, and all other clients have finished registering, play will commence. If all clients finish registering and the total number of players is less than two, the game will not be able to start, and the registration will have to begin again, after each client exits and restarts. %% % Reinforcing Countries You may reinforce a country by clicking on the country that you wish to place an army on. In styles of games that support reinforcing countries, reinforcing is staggered between players, with each player being able to reinforce one country with one army in one turn. %% % Placing Armies To place an single army, click the left mouse button on the country that you wish to place the army on. To place multiple armies, instead click on the country with the right mouse button, and a dialog will pop up asking you to specify how many armies to place. The text widget grabs the keyboard, so that you need not move the mouse to the dialog, and if the default number of armies is to your satisfaction, you need only hit . To place your all armies on a country, press the middle mouse button when you are on the country (the middle mouse button is usually emulated by pressing both mouse buttons on a two-button mouse). %% % Attacking First click on the country to attack from, and then click on the country you wish to attack. The appropriate error messages for either of these two country selections will appear in the lower message box. If the country you have selected to attack from is valid, the text containing the number of armies in the country will light up. If your attack removes all of the enemy armies from the country you are attacking, you will be prompted with a dialog asking you how many armies to move into the country. If you wish to cancel an attack, you may click on "Cancel Action." If you had selected a country to attack from, this will be unselected. %% % Moving Armies First click on the country you wish to move armies from, and then click on the country you wish to move them to. If the source and destination countries are valid, a dialog will be presented to you, in which you can enter the number of armies to move. If you decide that you want to do more attacking, simply click on one of the attack actions and if you haven't moved armies, you can continue to attack. Once you have completed a valid move, your turn is ended, and Frisk notifies the server and the next player is now allowed to go. %% % Attack Die This parameter is set by selecting an entry in the list-box in the lower left hand corner of the screen. If you select "Auto," then the maximum number of dice will be used. %% % Action This list-box, to the right of the Attack Die list-box, serves to select the action that you wish to perform. Appropriate error messages will be issued if you try to enter into illegal actions. %% % Place Armies Upon beginning your turn, this is the state that Frisk enters. You will remain in this state until you finish placing all of your armies. %% % Single Attack This state specifies that when you select a source and destination country, only one attack is to be performed. You may repeat the attack by clicking on "Repeat Attack." %% % Do-or-Die Attack If you select this attack mode, then when you specify a valid attack, the computer will continue to attack until the territory has been conquered, or you don't have enough armies to continue attacking. N.B. There is no way to stop the attack once you have initiated it! %% % Move This action has an identical interface to an attack. Select the source country by clicking on it. Then click on the destination country. A pop-up dialog will appear asking you how many armies to move. If you are satisfied with the amount (by default all but one), simply hit or click on OK. If you are not, move the mouse to the edit widget, and edit the number. When you are finished hit or click on OK. %% % Sending Messages Click on a player in the Message Destination list-box, or on "All Players" to broadcast the message. Type in your message in the long message entry widget above the box that displays messages from the server, and then hit . Your message will be sent immediately. You could use the feature to send covert messages, or establish secret alliances! You could just use it to insult other players, of course. %% %Future Enhancements Note: These are old comments from Elan. At least the simple computer player has been implemented already, for many other features there are currently no plans. Look in the file TODO for features/bugfixes in the works. Look in the file ChangeLog for features implemented/bugs fixed. There are the enhancements I want to make for version 1.0 (in no real order): o Computer Players. Simple player. o New statistics and logging dialogs. o New registration dialogs (grabs focus, better color selection). o Change the scheme of all big dialogs to use message passing only. o A graphical toolbar with tooltips. o Save/Load. o Join Game/Leave Game. o Restart game (calls for voting protocall). o Change "Repeat Attack" to "Repeat Action" o Add game options (distributing countries, missions). o Dynamic (and optionally persistant) player color editing. There are my longer term goals (version 2.0?), in no particular order: o Increase the aesthetic value of the game (3D map, new NeXTStep-like widgets?). o Genetic Programming computer player. o Drag 'n Drop for armies from dice window like MAC-Risk? o Nicer color selection (color cube (square))? o Port to Windows 95! o Menu bar instead of the widgets at the bottom of the screen? o Make the whole thing better abstracted in terms of OS and GUI. o Undo feature. o GUI for server, to pick game options, show statistics? %% xfrisk-1.2/INSTALL0100644000175000017500000000356507041650546012750 0ustar johnojohno $Id: INSTALL,v 1.6 2000/01/20 18:18:14 morphy Exp $ 0. YOU NEED AN ANSI C COMPILER! A C++ compiler may also work (try it!) XFrisk will eventually be rewritten in C++ anyway :) POSIX compliance would probably help. 1. Edit the Makefile to suit your system and taste. Imake is no longer used. GNU autoconf might be used in the future. NOTE: XFrisk is forgiving. If it can't find its data files, it looks in the current directory. So if you're just trying XFrisk out, you can just type `make' to get fully working binaries without any need for root privilege or installing anything. 2. Compile. Type `make'. If that bombs, try `gmake'. If that bombs, edit the Makefile and take out the line that says "include depend.mk", do `make types.h', and then try again. More make options: -make friskserver to compile only server -make ai to compile ai's -make uninstall will try to uninstall the installed file. this will of course only work if you don't change PREFIX in Makefile Then install with `make install'. 3. Try it out by running `friskserver' and then `xfrisk .' You can run the former in the background if you wish. For , put in the name of the machine on which the server is running. For example, if both are running on the same machine, then type: > friskserver & > xfrisk 127.0.0.1 Or if the last command fails, try: > xfrisk localhost Or you can just run the `risk' script, which does this for you. It uses localhost. If 127.0.0.1 works for you, then edit the script and change it. If both localhost and 127.0.0.1 (loopback device) fail for you, try the actual name of your machine (you can do this through > xfrisk `hostname` which you can also put in the script). 4. Enjoy it! xfrisk-1.2/Makefile0100644000175000017500000001545007042650043013344 0ustar johnojohno# # XFrisk - The classic board game for X # Copyright (C) 1993-1999 Elan Feingold (elan@aetherworks.com) # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # # $Id: Makefile,v 1.22 2000/01/23 19:01:55 tony Exp $ # # $Log: Makefile,v $ # Revision 1.22 2000/01/23 19:01:55 tony # default to Xaw3d, with comment # # Revision 1.21 2000/01/20 18:03:20 morphy # Cleanup, comments to aid the non-initiated and reordering for clarity # # Revision 1.20 2000/01/18 19:55:06 morphy # Minor correction to Drop All Armies prevention # # Revision 1.19 2000/01/18 18:56:04 morphy # Added note and option: -DNARROWPROTO fixes Xaw scrollbars # # Revision 1.18 2000/01/17 21:11:34 tony # fix on dropping armies during fortification, made configurable from here # ################## # Language options # Define only either one, not both LANGUAGE=ENGLISH #LANGUAGE=FRENCH ################## # Gameplay options # Dropping more than 1 army while fortifying: # Use this one to disallow dropping all... DROPALL= # ... or this one to allow dropping all at once #DROPALL=-DDROPALL # The max number of armies to drop is set in game.c, DROP_ARMIES # which will be ignored it DROPALL is not set #################### # C compiler options # GNU gcc is recommended. CC=gcc # Use these with gcc CFLAGS=-g -Wall -W -fno-common -pedantic # If you don't have gcc, don't use -Wall -W -fno-common #CFLAGS=-g # Debugging options - these don't all work # Assertions catch "shouldn't happen" type errors and immediately terminate the game # if one is caught #CFLAGS+=-DASSERTIONS # # For debugging memory problems #CFLAGS+=-DMEM_DEBUG # # For logging #CFLAGS+=-DLOGGING # # Test games (quick start) #CFLAGS+=-DTEST_GAME ## Initial linker options LDFLAGS= ## Installation prefix # Adjust to taste. Stuff gets installed here. PREFIX=/usr/local #PREFIX=/usr/local/X11 ## X11 location and options # for X11R6 # Point this at your X tree. XDIR=/usr/X11R6 #XDIR=/usr/local/X11 #XDIR=/usr/openwin # try Xaw if you don't have Xaw3d #XAW=Xaw XAW=Xaw3d XLIBS=-L$(XDIR)/lib -l$(XAW) -lXext -lXmu -lXt -lSM -lICE -lX11 XINC=-I$(XDIR)/include CFLAGS+=$(XINC) # for X11R5 #XLIBS=-L$(XDIR)/lib -lXaw -lXext -lXmu -lXt -lX11 # System V (Solaris, Irix, etc.) will probably want -lsocket -lnsl. #LIBS=-lsocket -lnsl # on other systems leave LIBS blank for now LIBS= # On some systems -DNARROWPROTO is needed for working Xaw scrollbars # This includes FreeBSD 3.x and recent Linux CFLAGS+=-DNARROWPROTO # If the link fails because it can't find snprintf, uncomment this. #COMPAT_OBJS+=snprintf.o # If you get complaints about ranlib not being found, exchange these. RANLIB=ranlib #RANLIB=true # For HPUX #CFLAGS+=-Ae # For Suns with OpenWindows #CFLAGS+=-I/usr/openwin/include # On particularly lame systems (e.g., Solaris 2.5) you may need to # uncomment this. #XLIBS+=-Wl,-rpath,$(XDIR)/lib # For BSD/OS (BSD/OS's ranlib sometimes seems to munch files) #XLIBS+=-lipc #RANLIB=true # For BSD and other nonbroken systems INSTALL_DATA=install -c -m 644 INSTALL_BIN=install -c -m 755 # For systems without a BSD install #INSTALL_DATA=cp #INSTALL_BIN=cp ############################################################ # You shouldn't need to edit below here # ############################################################ LIBDIR=$(PREFIX)/lib/xfrisk BINDIR=$(PREFIX)/bin # Data files, stored in LIBDIR MAP=World.risk COUNTRY=Countries.risk HELP=Help.risk # Flags & programs DEFINES=-D$(LANGUAGE) -DMAPFILE=\"$(LIBDIR)/$(MAP)\" -DCOUNTRYFILE=\"$(LIBDIR)/$(COUNTRY)\" -DHELPFILE=\"$(LIBDIR)/$(HELP)\" $(DROP_ONE) CFLAGS+=$(DEFINES) # The targets and directives all: xfrisk friskserver aiDummy aiConway aiColson World.risk Countries.risk # The client program GAMEOBJS=client.o network.o gui.o callbacks.o utils.o dice.o cards.o \ game.o colormap.o help.o riskgame.o debug.o clientMain.o colorEdit.o \ registerPlayers.o addPlayer.o viewStats.o viewCards.o viewLog.o \ viewChat.o viewFeedback.o xfrisk: $(GAMEOBJS) $(COMPAT_OBJS) $(CC) $(LDFLAGS) $^ $(XINC) $(XLIBS) $(LIBS) -o $@ # The server program SERVEROBJS=server.o network.o deck.o riskgame.o debug.o clients.o serverMain.o # these could be compiled without X as soon as callbacks gets fixed :-) # right now compile will break if the X include files are not found friskserver: $(SERVEROBJS) $(COMPAT_OBJS) $(CC) $(LDFLAGS) $^ $(LIBS) -o $@ ai: aiDummy aiConway aiColson # The map building program buildmap: buildmap.o debug.o $(CC) $(LDFLAGS) $^ $(LIBS) -o $@ # The architecture analysis program findtypes: findtypes.o $(CC) $(LDFLAGS) $^ $(LIBS) -o $@ # A framework for a computer player aiDummy: aiDummy.o libfriskAI.a $(CC) $(LDFLAGS) $^ $(LIBS) -o $@ # A real computer player, by Andrew Conway aiConway: aiConway.o libfriskAI.a $(CC) $(LDFLAGS) $^ $(LIBS) -o $@ # A real computer player, by Jean-Claude Colson aiColson: aiColson.o libfriskAI.a $(CC) $(LDFLAGS) $^ $(LIBS) -o $@ # The computer player library libfriskAI.a: network.o aiDice.o game.o riskgame.o debug.o aiClientMain.o \ aiController.o aiStubs.o $(COMPAT_OBJS) $(AR) -cruv $@ $^ $(RANLIB) $@ install: all -(umask 022; mkdir -p -m755 $(LIBDIR) $(BINDIR) $(APPLOADDIR)) $(INSTALL_DATA) $(MAP) $(LIBDIR) $(INSTALL_DATA) $(COUNTRY) $(LIBDIR) $(INSTALL_DATA) $(HELP) $(LIBDIR) $(INSTALL_BIN) risk $(BINDIR) $(INSTALL_BIN) xfrisk $(BINDIR) $(INSTALL_BIN) friskserver $(BINDIR) $(INSTALL_BIN) aiDummy $(BINDIR) $(INSTALL_BIN) aiConway $(BINDIR) $(INSTALL_BIN) aiColson $(BINDIR) # Other targets Countries.risk World.risk: World.ppm buildmap ./buildmap World.ppm World.risk Countries.risk uninstall: rm -rf $(LIBDIR) rm -f $(BINDIR)/risk rm -f $(BINDIR)/xfrisk rm -f $(BINDIR)/friskserver rm -f $(BINDIR)/aiDummy rm -f $(BINDIR)/aiConway rm -f $(BINDIR)/aiColson types.h: findtypes ./findtypes version: touch version.h include depend.mk depend: types.h $(CC) $(CFLAGS) -MM *.c >depend.mk depend.mk: touch depend.mk $(MAKE) depend tidy: rm -f *.log *~ core clean: tidy rm -f *.o *.a findtypes types.h buildmap Countries.risk World.risk distclean: clean rm -f aiDummy aiConway aiColson xfrisk friskserver depend.mk core check: find . -type f \! -perm 444 \! -perm 555 -print xfrisk-1.2/README.NEW0100644000175000017500000000143207043121535013207 0ustar johnojohnov0.99c0 ======= o Shift-click (left mouse button) on a country during a game to edit the color of that player dynamically, on a per-client basis! o New registration dialogs, supporting new color editing, computer players, with improved UI friendliness. v0.99c0+bpk1 ============ o You can now add multiple armies at a time during fortification. This makes game setup a lot faster. (Use the right mouse button.) v0.99c0+argon1 ============== o Supports 16-bit and 15-bit truecolor displays. v1.00 ===== o Supports 16-bit truecolor displays, but not (apparently) 15-bit. v1.00+efnet10 ============= o All of the above, plus a *lot* of bug fixes. v1.1 ==== o Actually never really existed, was develop version in cvs v.1.2 ===== o Many fixes, see Changelog xfrisk-1.2/TODO0100644000175000017500000000673707000076347012407 0ustar johnojohnoBPK's todo: let enter hit the active window boxes fix that stupid chat scroll problem make some of that French English argon's todo: Fix truecolor color editing. Should be possible to click on a country to find its name somehow. Short Term Goals (v1.0) (in implementation order) ================================================= X 1. Fix all reported bugs 2. New dialogs/views XX o Statistics view o New card view XXX o New registration dialog (for computer players) o Logging view o Feedback view XX 3. Computer players. Simple player. 4. Voting (for restarting game and the like) 5. Graphical toolbar similar to Microsoft apps. Tooltips. o Add Save/Load (to architecture independant file format). o Change "Repeat Attack" to "Repeat Action" o Connect/disconnect to server o New Game o Send Message XXX 6. Dynamic and optionally persistant color editing 7. Most popular changes on TODO list XXX o Add the SO_NODELAY option o Game options (through server) o Better font handling (75 DPI/100 DPI) o Bitmaps for cards. o Mouse movement over a country displays name and continent. o Add assertions for RISK_Get*Of[Country|Player]!! o Man page! o Have a larger version (not 800x600) o Missions. Abstract concept of "Game Over" so this is easy. o Make font handling nice if it can't find first choice. Long Term Goals (v2.0) ====================== o Rewrite in C++ o Aesthetic value (write my own widgets, sort of NeXTish, using primitives that can be mapped to Win32/X). o GA or GP computer player o Drag'n Drop for armies like MAC Risk (from dice window) o Maintain bug level to near zero. o Port to Windows95 o Menu bar o Undo (Infinite, of course) o GUI for server o Make the game part more separate from GUI/Network, then implement a few other games over this: Scrabble (Rabble) and Monopoly. Try not to get sued. SERVER (for future): ==================== o Meta-server (which lets people download newest version automatically). o In case a player doesn't reconnect after disappearing, assign a computer player to continue the game. o Make it so that client allocation is handled the same way as player allocation. o Let newly joined clients take over for dead players, or perhaps also let already existing players take over (In general, this is allowing Player Migration). CLIENT (in future): =================== o Have better support for atomic message passing (transactions). For example, ATOMIC stream of messages, or just define some atomic operations that correspond to one or more primitives (i.e. ALLOC_PLAYER, PLACE_ARMIES, etc...) o Incorporate message ID into message itself. o Make some network operations more like transactions, for example MSG_MOVE, MSG_ATTACK, etc. -- perhaps composed of multiple dist. obj. primitive messages. o Have _NET_* return Frisk error codes (instead of "... failed"). o Have non-debugging malloc check for NULL pointers. o Add srandom() calls. o Improve message set to reduce bandwidth (a PlaceArmy action takes 4 messages currently, and there is overlap). o Icon for the game (tiny world map?) o Acknowlege the world gif?? o Clean code up and add function explanations!!! o Limit size of buttons in Popup dialog, center them. o Fix so that 1 bit X servers work. o NET_GetStatistics for stats on bytes tx/rx. o Use intro fonts for end of game message. o Update the MSG_TURNNOTIFY message to just take the player. o Choosing defense die? o Display values of the continents. xfrisk-1.2/World.gif0100644000175000017500000003064007000075543013460 0ustar johnojohnoGIF87a”¥ëÇ1 Ô`¹H€ºúñ$ÿàgZÑ;ÿÿÿtBÿA,ïbæ^ãß<϶Uÿ±qÛURáKâDÃÿßeÿÏ<8XÿÛ<ªf×899qÊXÿÿÇu$ètTO·iAª4݃Fÿ:êÛ$AÿKÿnOÿ¥hÃAóqJíÿÿ,ø®e ã,>,”þ@€pH,ȤrÉl:ŸÐ¨tJ­Z¯Ø¬vËíz¿à°xL.›Ïè´zÍn»ßð¸|N¯Ûïø¼~Ïïûÿ€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’p•–—˜™šš“žŸ ¡¢£v›¦§¨©—¤¬­®¯°±’ª´µ¶·›²º»¼½¾¿¸ÂÃÄ´ÀÇÈÉÊËxÅÎÏЙÌÓÔÕÖ×NÑÚÛÄØÞßàáS•B˜„Üèé·âìíîØªtêóôÎï÷øù²Âiõþÿöô HÐQ±3*4V°¡Ã‡}–YH±¢4ˆ3jd#‘ŒÅ7ŠIRK€rÃú\©°¤Ë—0@Sɲf½˜8sŠŒFÓ¦þÏt:ƒ ¨­çÏ£<‡*]*n›Q¤PS2Ju79Q³¦ªÊµk/ s´Š½èµ¬YR`å{¶­ÛNóî¬Íú¶®]ƒWåÎEz·¯ßBêJí=ú·°aÀ¶y¸±c?±.®ù¸²eÅRÃNfy¹³ç6ÏÔnþø¹´é‰3ãŒyºµk.ô8®þ÷ºvçU]Z¢žÖ¶oÇäÈf )†wïßÈÿžÚB<Œñ™'§˜N}zòë0m oþåy­`Wª‹/»ùÚ¯X,î=—òð©Ÿÿ4 ¾ýó×DòÝ iöíY²E|–ç&¨à‚ 2øÊ}æTÀ„VXa$zÿþ9ç]ÈUƒ$–è`+Fè’…,¶è¢…‚ä5e`¬æEˆ8*eâŽ<º’¢Š$½(är\64z¸ˆ86)P’øà÷5¤;Df©e ©aÑawK2ÙdŽ9Ei¦‚P©f}L¬y%jâ£åœC`ÀyÈèå—^°uã˜NÂtæ |¸iè›Fª(~÷Ð騋vÞ))žcLj€˜sÓv|æF˜€JÒ fî±è©ö%ê=ê*Œ–ÆÚE¬´^ês¬)ÉÙ¡Š:©Pšº*ªª˦@¯&;a¤µJšE³´jz+§ëéÚé½’ù+°=êa,±‰ž ‘²É2 ­³þTœ+kB&åZãµ`dâ¨Üš(ì·«¡¨Fä¾j®ºêp´´áZ-€º!¯ˆÕk/øF|,œ†>hd|(ý>úïÀ ‡¼î´SdÆBj, ŸHK E‚eH,ó¾m®I1oEÎÒ±£‹,4ÈÒÆå©ÉOi†Êã5Üò‚RœÆÌTW¬Í»áµwƒ›~¡ÉPL£!üú•ÀþúįÀñO¬Ån† ýþzSïÿéPðŸ²G@×i{DòÞ÷Ä>~H&2]Ø]ŸP•©ï}Ì`ûäW<;´ìs;²’Þ„À¿îë(¬R¨³ºP{U@`¸@¡5°?˜q CBu úPƒBà ÷äE¡[Å2¡ï&=:ñ‰}À §˜½(ȰN5Ìâ 7¤‡ÌD0óêáÇȾø QˆE4¢î—Ä%ºQfM„¢þŸ(E*Ú±ŠK¸¢„Ån‘‚|ÐaiÈHÈàñŒˆìà:× $DéjoŒdôæHI'᎘d]õø"ö1d4…ùÒà *¥¨¼\"W)¿20ò‘\~f)ÉZ*Ž•Ìeõ2ÉKM"“òä'†’u¼ÈL&2׆á˜R ©Lå!YIÍVrá•ØDlÉM¼éò›¬c/Çy`²ˆÃ<œJsS™Ê¤‚p´ðÌ{ÔÓ Ñ,ä4«ÉO"a~hTB6³¹Ín4UàLh߯ÉДӜËf:É€X´ûq<7:#r”åžSÈ'!ÍØÏ~!‘Žè+™þwÐnâR¡ß`C{ùPˆJt¢ÑZ§EÙIÊ5lô§ ˜QÚ¼Ò%Õ "ã>KZÒò“*ZêR˜ZUœ3¥i ZtâÔ†ÝéNÛùN õ3GUBR¸T¦ºÕ­BˆjýÚ˜ª¼Qõ/µêešU†Á¦7ý*ºÄJØP–Õ¬mCZ“±X&4–keë[';Ù¸ÊX²L$ïªÄ¼ê•Ž}Íê_ÍùÁR +aǺ"Ö¬¦yld}ØVÊÚ¥–½l©2«YÞrvžý, /Ú†“Bp€r—Ë\æ–¨]®jW[LNöµðTÃc±]',v¶@¼­x©™þ[ÝÆ’®uõíoŸ\áN¯Å5®¸ÝæÚWº^õcr›;]êVw|mÀ.lL¿€¼—süÆË`D–×¼lt^o º^&º—ŽXïL7ùµúÞ÷ÃC &@¼Ú!C®ðY—Ý)t/¾‚‡7„7øÆÖ„0©$¬YFá¯ÂUkï…ªáâ:¡cûý°’SÛ„%;Ù¹%ŽòE5u]'Ö+>ÌŒPãøËÖq„I'–™tCn†‹ìW*¸ÊÃO޳œç¬ÜþJY¬s°²ž …ÿÂÏUز„GÒ/38ÌbF"™›Gá3KLÈi¾›ûzÀ-ÑùÒ˜V²ïŒgþ8ìùÓ-þË–¹ötoím>†%9÷ç<ï¿Î„ß>'Ã'z|Õ+¿éÌ7áìŸý©·—öÓÇãíωý½oÿþ½N‚÷A“ÑÛôG~Õ”|ç'%é§~áÄ~í'uïþwt0R:§}ø§oÝ·¿÷e·ã'€oE€ØH‹v€¢ãY ¸€î‡:ðjp!8ƒS¦˜%±hnÈT ‚"8‚$H:K€‚²§‚h{kQ/˜}(ƒ`Gƒ5ø}àE—ƒ·ƒpe~>aAGD†1×€G(-¸uK˜kMè„OxQÈß@…rH…ø4pjEh¨…«Ôƒ]¨h_h,'(† H†eèKn†]·†lxgJð†À‡ s‰rHGx#%pY¨‡<˜nFЇ˜„˜?‚(†„ÈfFðBp€ˆ]·ˆ2…Žøk× ‰²H‡FpâþÇVQ ‰›˜jB¾è‹Gà‰±Š·4ŠaXŠ–fxˆª¨m:ÅŠˆ¯l±8‹²X‡ †‰d¤º(^–Õ‹¿Žâȇž8Ä'ÆH„ÈZM`ˆ©ØŒÙ¦ˆÐ؆B0G Öxe OIЊ7âãȅˆ&çÈ*鈂ë(Z„j8‹öxÕ’ø‘Pz¸xþh[D "9Y HŒ˜)8m숙iò‘Œ8‘A‡Y…] ‘y‹eä‘Y~0’BI’B™**Ù~B`„ é’×÷’K“2)eI“V&7é:¹“\ð“å7”þ`Ž%i’G‰I©”L¹aŠ00P•SɆUi•|Y©•[¹‘]é•[–~CP”ör”)y–2\+8EŒÀ–ŒIoÉ_qé„sI—¡ÆùyÉ•X°‘|¹‹ù—c)Œ­„…i˜c¸Km¶˜Œ¹šmù”)•‘YX“I™Ë„sˆ7I‹Z™yiœÙ™&”Ÿ š¡Ù‡£y€¥išT÷R‰Y@ÀšÐÙš#¶w°›E›•© ³X¹9‰[À›àžI; œÁ9œŸYœÆyœ®—œÊùK™5ÍI@ÏöyŸ¬i«h¼WØY›Ìp™Bз™ây úþ›æI^‰ž~©ž]ÈžŽçžï9<3ŸË¸ø¹¡Ê–nü¹{³i•Þ`C@ é› º¢™™‡ ÊAàè JŽ>(¡,G¡ï¹œ9ƒ¡0TŸú£Ñy©¢7¢i“úˆ¢Û9,Ú¤[é¢/ªH2ŠžZ€6Ún8š£ðŸ<Ꜥ`¦øIDêy؉¤)ª¤K jÓ¦Jà¤p:žQÊJ1:¥*˜ “~B ¥ÇH\Õ¦šb¨‚*ÏX¦TI›S¸¤jº¦G§Žª“§7§šS§v–Uj¥Ì—¥|z˜É¨¡ƒú©ƒ:†ÚqgZ¢Šº¨)Ú¨ºªP*©óÓ •j©—þz~W dšº©TWdž ª¼*¦[ЊÿiªIŠª‘ˆ«z¬­*©”«`9«ÊW«¿u«¸ Ÿ¦˜½z­` °­ÜÚ­Þú­ÞZ¨ýYª¨@¬ÅªªÇ§‘ꪯʬÃI£!­w%­¸Ú¥Š¹–غ¯ª­àú¯»­âZ¤”i—Ê®ºYëú¨Éª¬° ¯²ê¬LG¯µ§ÓJŠºª¯üº±Ðé¯û±á:°fz•D@X™ªë »°ŽÚ°sº¬Û¬xê Ðf±«Ž“f­»³«é± û³+²H²ÝZ²*ö(‹°IÀ²ìJŒ½â)¶;ÂDü½/ZÀ(ì Y£pÇÀ7ûÂ^š¼2 ª9\ÃëuU)L?ÜÅûÁã9¹EL·BÄ"<ƺë²;xÂI±óúxJùZ ÅQ,ÅS¨ZlÅ΋ÅË´ÅKáÅ€ü¸-zÆhü½`Æ…<ÂjìlÜÆ–Š©Ã[˜Dp”\É–|ÉÄ›”üÀv|ÇaZÅzü­\Í[ÈeÆbœÈ”{ÈþÉÊ|ÄìÈ¿‹Às¾pÄ—¼Ë¼\É™<Š›ÌÉ1ìɾÊÎK•y,½^á¶§ÜŻʰÜÊ© ©„Ít+ËRKËäkËd5ψ½ÎâÎYk¼´æÄªÆlº›–Ì~\ÍìÁC`Í$œÊóLϹ»ÈŒœÍÚ¼Í+¡B€=Ð Üj0ÎÐð˃HÇu¬±éüÉël¸þeÅoÏû Íøl¹÷¼ÑùŒÍý ¯Ü¼j£Ð}Ò`Žâ¢Ð,Ð嬔Ô ]Ì-¶²iÑvѳ[ÍÝÓŠ¾HÒvZµ+¥"(}Ô)]ÐUrÐ-ÝÔ½üÒ“wΑ0Ó]ÓŠ[XþzÜ:ýÅ>ÝÕE¬Ï'ÇB]©D-U¬fÒHÔtÅÔNÝÖ˜L¡Á¬–SMÕ@ Ê=]ÕnËÓ^ý×`lM0Ö±ZÖt3iØi}nÝØ– Õc(Õ“@×?j×ëŒ×8í|Ý×ÝÙºKÀ¯:Ø„]ØÌ6Š}ÚŠ=ÉŽÝØ¥é§€Û ”ݯ–ʘ=Á†±ÙœíÙºý´ä'ÖH<ÚC=Ò÷ƒÚÄ}ÚB°Úm Ùí:µðÜÐ=̱Ÿ³mÑcUÝ¢¼×¸ÛºíÕ>™xb Üx+ÜÝRÜæ½ØC€Ü-’q]kÎ Ýð߃0ÝcjÕWL5|ÛÛÍÝݽÑÜÞá-þÞ1KÞörÞŽÞêÍÒå¼Üî˜ñýàð=ßô¤Ømßì¬Ýûí¶ýÝÓKP%<€.àžÀpà&~Ôªàâ|‚ þþâ áNÝnáLÑ×Oá_LDlNÆX€nG â¾kØ¥râHŽâl­âOý|íuNã^3Þ±^ã:|ã>|:¾ÓH ÀGÐßaðI@äEU¦äj.ÐéÍäO«FåR.߆Påù‰åw­]þÃ\¾ã_^ÏØc°‹AmæSk䠳抎ÒKîæ¾ytsNçTnçyåxžÝC±ç|^`ž‚^©Wæ†~èØ”æ‹¾èÇþíèo ÅR0éÑÝÉô×™^ÊZÎéüëéŸèþÁY襱܌֩žê«ÎêΣXë1ÑvNëµ.¶\Œë^nмÞ¸ìÁ.Ò·\ìàÎæÎêO¾:J°]̨–ŽéXÎÔ^íWpí¼NÏL ö~ïö¾—gÄíÝάå[âáðãîèå®°î£ËîínÊïλæô^ïø^ñùžFêýîïsð?ðnÞœÿöÞR. Ô=ò*¿ò,ŸòD€­ oÕðÜå¥4ïÒìãÖ<¿ó<¿óB EÐóñ¤ý‰ïñmŽìímð% -õR¿òþ/ÿ©1Ÿç]±ç[Vò®Ñ]¯óBöb?öCŸñCnôO(ŸôJò ¾‚OPT“Þ S_÷vOõE­WŸÕgAóYðX_ÈH@ö„_ø¹û^ôh/£êIìl¯ôÈNÉð—s? wù˜¿H`Ÿ{Ï÷fá÷VÐ]ù|»E€Æƒoø¨_øˆ?Dü¾øŒDûâù›÷4çžùº¿ûCpçў埯ãWàgæ~mȧŸúÊ/ö«µgïúd½<²?ýù ýÐS€ûŸ°ûÜù½ï¡¿ßmúR@lÅoóçoË¿þÌ¿T!ýJ¬MF@ýôìäž¡Â6ÚŸûÝßþÿw/@0PˆEã™T.ç•N©Uë›Õn¹]oÉc/q†ZØlî¶jèuûŸ×ïùš§P+b°Ðð1Qq‘±1€c’²Òò3Ss“³3Óé"Tt”´Ô´ÔiaAm*Ãõ6ƒu–vvã7Ww—·×·÷‰Ix˜˜¨ö9YyY«Ìù¹‚9+î-N®ª/[{;ÏËñ<\œñÉÓü=Ýô´ÝÝT9V^Vº¾ö?_ÿWªØŸØ^@B3† 5kÕbãö"Ÿ.ã(V´xH’:9®{÷Ècóä4©e_J•)üs©ädL™3­´™Paþ- ¯Dôù³Î–‹C‰:*×iÒŽì> ùÉX4©:áõdeV•-_v¥PlØ‚6ŸÍâpmÚ³Sxniëh\nÞŠÖµ›Qi^½çž6%j-©SÅÊÔEkb}C¼º,ü2-²ÎÔ¨µ¬– / çÈõœm‹,vI/r²ujMLý^ân–¬Á„#<ŒXqî«ÿÕöý›f°ppùe+×6ëÌòÀç¹=µI)]ú´jíÛ1°ng%°—Ù% ¼Uwz\\Nù*¬||ùUÄpI~ÿ¾=6gèp‘^½³ˆž¸®¨ì¸;5"<-Æ#i¾zγJ½ Ù[B þ˜"Ü0B0ìÃDå’IC¦ÿ¦ó£?Ï$°"¼|1/ÿª¢A)èyâÁy8”fB*´p$v’È(B<Ò²"¡0‘IŸ`qaœ)C¹¢Fs|PÉdvAïÇ•²Ë2©B« $ÕLKlÎéž„Ò(*íTÊ»,`³qK.Í<æK0ÃÌÇ$2ÿsD”–@˜B›Õe]5Äc8=)ÒXA›”RŒ\¼Wu¸øî‰4<õ3U5Dõ‘T_NÒ0ØdYa•ÙüŠ”Z‰æ¬•[s½Öœ]Oáó×Á”=ãªQ‹]ïþXC¿=7‹fÕEn–Wa^¢½6:‚( LšlK–fš¶ª¯˜ÂbiâYíd¯z뺹Öbë¼þº'<øŠ‹.ûÞ‘ÐN;î*zŒ:½ª¾J<عIÎÚn­³¨<ïzöæÛï¿=|Eq¨ |bÿòµ?–bÐÔ]?þFòÉ1·üòÙ5ßœh'>ß}÷À‘‚÷zIÇõl¦_Ï‚í€Õ;žù3bO˜òÙë®BúÌ»ÈwÜuçûÞ«èÞûÁ‡±x~›G~uÜ–?ŸýâžW7úê­Bþék·?û¯·Ÿÿþý÷@xã›’éºÕ>ô‘K}3à¥ð>øÕ¯rP€à«ç„ü©lÿÓà=@"¨|ÀbàÓ˜ÀÜŒ…Çq «œ@A¾P~¼`¼2ÈAþσÜ- ˜Âêl ëóaûVÈÂøÁ‰H”aâP´>qƒ9Ô¡jb3ž!‚ëŠSà™WD&Œ`\â!E Bþ;Ê¥¢P¸*ÖþŒ‹ÿRÝ ãø:/®ª…aÔã eY™ÑaHã ù'Eî8á‰ßYaÅ:2C7LÝE¿=^r‚O@ѧpFB~2x‹L"©HQèM“¤—è¸J§QIÄä,!(…h^‚å.;hH½²”Á<¥vBè W.#’Ç,cyDZ>ÓvMä¤-iÈKkŽ|æ6?0L*òÊäQ+ʼn.f)ÐT§ô¨ -\þñšÖôeR´ÉMa檜ñÙb¨²˜ÏÈœ³UÎ\ç@i·$w¾3RºŒç.繑'ØS˜Þ¥?}³O.‹¢…h«ÚÑhjò–…“B ʆê þ¢Ü”hŒ2ú‹r j-ËFA$PTš!íÂgHZÒOž”/õLé=í$ÓŠ¾”„É3jLh꬛>u~d<(DÃÓžút@í0‡ZÊ•bj©‘"LÖ“4596…ª:Û™KêH(5Äjµº ¡vÕ«_åˆYÅ:Ö9*•¯‰B«rÖ ÕNÒ0@9ëUç Å5:ô®x%*ÛWrZ•=ë` [اV§ }DÛX4>6¨’…¨^u¥YËj…¬eum=8+"Ï~V±ôcP¨š¢‡‘Q®¦Íª7¹ªÚm²³­b´¨<À*7µe×moÚÖì)#(½fŒ›Òº¦ºþGÍYú«*éÚ–ºÍíu“áíʳ»ñ]-1Ë œñ–°¾Ñ=ogÓ‹Sëj·Çx/!*_G45ù-Ï}û©`Øí½ý…¦@°Þ *cÀt=ð†'‹'ës¼~0„Ù$ágR¸ÂÎß22|ÃârX¾ßÅ„ˆ9D*ׂÄiU«‰]ˆâ«øÂn1a\däRâÆ;úQ’i‘cóX>þ±Ag(¯d Y‘-rŒÁÊd%ã—%^®Œ“Ùµc(T Póšÿ[eÑÐË8Ôò–ã{d1£j1Î%ï@æüœ™OXó  ­æ6WqîßœéÜ]äòÏHe²ŸñcI@߭Йþ.4•Ý̲D+º—Ph4‡õ é`IúÆ”F§™ +eM¿Èì2‡L…Q¸Ô¦>õe'­ê€¦s­Qxõ° }hYc8¸¦µõ­¹ ^]++™wöu3ƒíjb_´3H†¯Àì:÷ÙèJ ¤§­&`³UÐ×V÷ Eª½€¼— ÞVí"Ã-2Ø’»Ü«^gº×ÝoCgûØö.wå×Ö[maÆw¾kzîúiÁßÿ7À÷f’¹²¢à¯ÂŽ]3œÚµ´¶ÄI®évÒâ>¥EƇZ/Ž».³¦yÈ? €’ß\ÝGyÊãy –w5#ÒBPô—×£ÒÁÒ™®Ì™ÓÜ~6ÇþùÔ‰}r·ž¤çÈø¹wëQt¯ýèJú2˜^vóéĮ́ÞöaÃ…‰3Ùn2¶Îõe|ýëaGúsÏ`v¿—Ý oú$Ó®v©»ñ™†{¬ÄÂKiÔÝžÌÀ{Þõ¾wü²Bð™×üæ]Wøf&ôŠ·:“ ÃÐz@>¢’ŸüÐ+oy Îbó±—½Ù ïùJ>ô¹Ÿx¬ÿóÓŸõÝúê[ÿåËsaöÉ—}ím_fÝ?÷œŽdL:ÔwøÅw}ƒ‘¯|ïk>qÍ/3ûÑ; 8Ã%H7…Ïh:òÚß§ð}ûg>nâgSùù?eéËE>N , þðNþæOá àþþöªFÿ’¤ÿúOç$Bp½­)ï·/最?pðlæ÷/¡o‚C,°*ä û pPžgðì–iI°ÍÏØ¤…H+,ðî²ï°iEð!0Ÿo»¡L\L,€PVõ†H>æcŒm0 M†ü–0ñx﷞ІƒUÏ­ð _Ï*dP gpcºÁôþO £3ÐëÔUÞp }F…up·îTòPo­©° ýPIÑqã Ñíüè`ÊÐ ™Í±!1%qý¥ ëPd8±GíAìDqHHþQ Mñ×âSñæz†ƒjƒ_e±Hh‘#ç-Q3Q ü/5È7€îۀхqGˆÑ—TŽ“qê¼`ÓzPÎ èÜoµ‘åã¯1qä¸±ß ÎäŠÄ}±É1òâÓq>ÖqÛñßs® °ñUJÔæm ö‘ÕÑ­UÜ1’ #Ž Éóq! ®!añ!!2"‰q"²"-R•dÑžñ Ì#õ$C2>FR"²%/#»ç7ìÎ%}&ƒQ&ƒ&ÙQ´ñ$s’êþ|€(ñ±ý>R(‡²6ŠÒ(Ò$•2÷ñsþ:tQ!£ åNâÑ‘*ÅÂ*¯òPR+·¿2ƒ ã)ÝO&ÊÒ,Ï’*ÒR-ÿ„-Û2%.IJ.[²#ój&ì/ѲáþR…"ý2 ¿…{~Ñâ£,3,1 F€3;Ó3?4=Ó •Ï1³2—ò\&,«<3iB 4g“6C¾ÏO1)O“ S3|~0#Ã5_3&Þð j9“s4—¯4o’7»]~s5Sï#¹ &‰ó$jÑ ’“;•ó6“OnbÇ (i7Ÿsý%”’:a² ¦;Â8e³;ç³6—“óÂSaº ˆÊÓ<¿Ñ`S94P­3þßÓ$Œ“>9=pö”e]–Åø³?Ų̀îR,´ÒP³à@4;áP>”DmÓAñ¯LPfQΞ‡B¯@)/4—-,7Ô.gD#ƒvÔ>q³Dt6µ 3wDEDÇBrøÓ J€I›´I)4eG3´FiáF?4GcG·ôDqsDL4>Š4M,ñL€† œTMKJ#0¬âO æÒ ®C³4,¶”K¿ÓGÔOÁÔ7ÈT>€fM•PÕ´Mù¯Ò°0YsètJíôNñ”Gõ<¿´O/uA!P#$? P?uPµüUQr=çÔQëRiBRóÔû,þSc•; cS7$?AWTT™0°:TNµ UuU©¢Uó”RÁVeUYKT j•C ÇSs5WwÕ-5 N_Ì0Q5U‡UK‹•K™sYÕO¥ÁYwz¤UZ©õ/­UQƒXƒUU¹õ$¼ÕX9O\ïÕOGB›eIÑWq2J•KÝÕCáU^Å‚^ñ´G±1YñÕagµʵHøÕ_ÓËËW«´` ö`Á"a%µK¡àaG–YÏ@b•Ĉ¢µbAU]•c©ÐT£ò †^±´ccâc‹u3I–gI´ N¶Kå VÖbSQÁ®3[­ fKõfq6géµa{VjƒT €ÖLX þˆ6][5ókEÍ@—¶N;´ikái¡6j§Vm‡t¶s ¬–/+Mk‰–kqŽÆÜs Ķ@€fɶlgálÑvmb!ÇYTvnѵnI.É®3oõ6 †óoi!p½5m s™/I—néÐË$wf! @w LÀtO×ʶruör1wm5× 9we7ïŒt§@oqôv¯u{uvuY×u‡W4 WDdwv—ÒðVis7r·t}Wzo6xv;‰×u3úyý•v{“Ïv÷ r÷/Ó Ò}Ñ@}9EzÛ÷tåµzA¶u±×aµ×Qº·sÝôÙ wE—èÄ× ÜWþ€¹5~­—~W{³“Wà €w|8€¸}‡µ€ ø€§6üÌtçö{a­ÞØù–¹€‚Oøwßó‚¹4ƒ58u:8q?XôN|G˜„¿–PX‡+x(W˜æ·…er`˜s¶kÏwK8‚9vt™—vŠß7$}ø‡ƒ˜g]‡ˆcØÃN‚oøJ›X‰Ï ŠÇ8ur…¯×Šöu²Xkx¥n¡Ë|•Ö‹A·‹µ€Œ£X&/ˆÓx\‡ó7ôZoŽ=ôy™öŽñ8wxŠ ¸ýøGÙ'+Öýí âXŽÃø]m¶ŽýÖ ÜÄt`‘Q¸‘«!YYÛg’½þ÷{P“ YXÙ„G™‚KÙ”O•/U•WYq#Ó 09“q …Y P†–OØ–où8sYLˆ—‹Öe]Ù‰mtšká˜I9©xRq™™»…žù_u2 €ùh=¹Q«y õš8›µy›E¶›ëó›ÁùSiWa6ÐyÖ™‡…Ñ-÷‘Ó8…蹞7+ŸôZi¡\ùÙwÍøŸå7 3xˆºP š·•H:…©1¢:ž9S6¯È¢Cµí~–5š*€–£¥Ø£?šu'šp먤״’g8$ƒuGZ:”ù¦A:—©¦ •qàŽ¥Z§gny¢ºU—Ù%)Tþ8Õ¨©‡’N‹Ä¡Ÿª£Z¦¥ÖŸ´ú º÷$«@«Í:©¥ù•ëÁjÙ—‘£à¡}:¬ÚŠ%i­÷š¯ùš{µØ? ¯ûú59ùO™ :Ú®ïZ~ú‘²÷zh›Ý;²ýú“'wœ‹ ê:±»ƒ[X¯/Û´ÿzv/«M[²;–œwº§“Y´¹™xK›µ#{²é n³3û,_› ⸡À¥e›±ÇZ›·/q)Ù²—»·ov¸5[ D{´é×¶¡›°›{ZW[»×š³1sº1yºUغ¹ï5»¿»µ)™½›ºË[ P¨›rÏ;½Åu½ß›­÷þ¹ù¼ã›¡©€¾ë;’!x­;¿Ãu¿üP›P½·ھå»À Á7|ÃÕ Á©w¶<••»Âœ»uõ¿K<½@Z¼ÅßhU´À œÃk¼ÃµàÃAü¸ESWIÅ1»ª¼µ·ÀÅ‹Üű¸3ÜÆ—\Á±àÆ;–Á±×Ç…ÜÄ¥€Ê«ü Œ\Ë_É7» ”œÉk< 8¼i£¼¶üÊÓ|»³`˵DávÆi<ÌŸÜ Ä\ÇÚ¶ÕvÊÕœÏá›ÍÛÜÍßÜ â\Îç|ÌɼÌ{x]©Ï=º«Ð·¼ié ÒçœÎ©ÀÆUWѳwϽѵ Ò]^ Ý ,þ½Ð™üÐ=ÑñÜÓ?ÔùüÏGÝȹµ¾QÕ5ÓW=Ó¡ÜÕgšÑcÝÑgÖ|UqÙS}Ó\Õ[¦y<_Ñ\Ø© ŠÔ³4Ù“]×›ý ýÎ?Ú›™Ä§½Ï«ÝÚ‹R³]Û·}Ù»=Ì=¢óœdƒÜe=ËÏÝsTÝÕÝÛ½ ¼Ýן=s¥½ÞUüÞñÝØtßù}×ÿà\à}Ü žÚ­áó8^ãÓ—œãž€¡:Ü#™à)ž¿ÍýâUà=5~ã;Þã;>à#þuKÞä¿›Ø/;Y¾å]žçí<äzä3•Þk¾Äoßs^ç¾ß{Þå!>g`uþƒÞ›•‰è ÞèÏ铞ᙞéá÷l¡ r¥ž6)ªê!œÈSžË_Së÷}é¹¾áWõé`æþ ¾>¹É¾ìß› Ð>ísíÙÞí»þçÅæÞðéžVìÛ6¬òÞæ÷žïU3ÿð¿çWu¬àð7ñŸ~ÄùÊñ—›Å#_í)?ÛÛÞòßÝN9Ÿõ[Ÿî=_ˆ+ôy{ôѾôM_ÛS_ðsÔõ{ÿðÿcƒÞµfÿ´» ò%ÿ,q¿òuÿòAÔ÷Ÿ?ó¯ÿxø‰ßÏŸôRù“þ㙿ù±úŸ_ú£:úû4¼¬ÿÑÏžïùqû×¾û½¿éÁ?ü}ü–îͺÐþȱý…±ý)€±h<"“Ê¢°é|B£Ò)µj½b³Ú-·‹]Ãâ1yì$¡›`À¨í~Ãão/½n¿ã©§=¿ïÿ þy©"&*."æ9>BFJn¡TZ^bfjnrj-†.M’–šžN–©®š9‰±ÉÅÊ¢ÒÖNâæê2ú2Ú Óu#o ‰27?CG{±RW›ÉbÃIosïzçvýŽ'r›Ÿ—&«¯w.7¿¢ËÏ£ZÛWÃfgÓó›‚ÿä#޹~Na§p¡%wðA(qâ•{UåÓ‹"G/?‚ãBp\Ç’ò¢d÷ "K"&_¼(ó•Æþ0oN©3œÈ‘¾pµ•r¨º•-YMmæL!5å(Uºsj >EÍ*‰(WcBÔ*öÓ‹NŸj{“*Û>V¯ªP+·N׺œ¾‚…7w/ž²÷΢÷cÛÂ'z¬øŠÝÆ™ŒæÕ»x²¿ö2vCy¢aªˆo À1éJx#¿­Zˆej€3k^ݯ³Î^Weo.íø4jɸ·f…öˆßüh¤Úø`Ýv›ôÎË|ppŒÄÓNG‡<äN|fWì¼+ïèÃÏ­Næ5lôò¶{ë¼û¹ãQ:1ºþXõ×®·Áß9ðé’…wR$ \÷)~½)˜•4þ¡9‚ÅTübáX ®ãàƒzÔ„a X‰Û`(ˆZ±ÈŠ‚ˆ d#F6#N'®qŽ,¶XÈ0þ([6âh^‘&ñØc{KB¤CBiÜ‘^%©d•5¹BŠmIŒ”nAAd˜¢]ÙN–Ñ)Q—_bÓæ0c ä„™r†–¦2k’ˆ'=]z‰–ŸsŽiç ¿éùŸû* p Öh0RJš]¢˜Ü¸hX•šó(˜œÚÒ"¨Ì]zI¦šú6*4²‡ª§ùª‘¥š†*X²® h ³àê½ÎZê©¶2ì0ºzÙª±°Â·¬j´Kl(ÎÚ‚¬“‘RɯÙR&l´Ò*þÁ--Ö®q–¸’4{îb‚»©º¤‹"ïBB½“]úm»GÜ o¼åö›‡½óu$û:Cp$ÿÊ«p9¼WS ã,>ã,>ÿnOÿnOÿnOÿnOÿnOÿnOÿnOÿnOÿnOÿnOÿnOÿnOÿnOÿnOÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿK³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ®e ®e ®e ®e ®e ®e ®e ®e ®e ®e ®e ®e ®e ®e ®e ®e ®e ®e ®e ®e ®e ®e íÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿnOÿnOÿnOÿnOÿnOÿnOÿnOÿnOÿnOã,>ã,>ã,>ã,>ã,>ã,>ã,>ÿnOÿnOÿnOÿnOÿnOÿnOÿnOÿnOÿnOÿnOÿnOÿnOÿnOÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿK³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ®e ®e ®e ®e ®e ®e ®e ®e ®e ®e ®e ®e ®e ®e ®e ®e ®e ®e ®e ®e ®e ®e ®e íÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ÿnOÿnOÿnOÿnOÿnOÿnOÿnOÿnOÿnOÿnOÿnOÿnOÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿK³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ®e ®e ®e ®e ®e ®e ®e ®e ®e ®e ®e ®e ®e ®e ®e ®e ®e ®e ®e ®e ®e ®e ®e íÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ÿnOÿnOÿnOÿnOÿnOÿnOÿnOÿnOÿnOÿnOÿnOÿnOÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿK³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ®e ®e ®e ®e ®e ®e ®e ®e ®e ®e ®e ®e ®e ®e ®e ®e ®e ®e ®e ®e ®e ®e íÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ÿnOÿnOÿnOÿnOÿnOÿnOÿnOÿnOÿnOÿnOÿnOÿnOÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿK³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ®e ®e ®e ®e ®e ®e ®e ®e ®e ®e ®e ®e ®e ®e ®e ®e ®e ®e ®e ®e ®e ®e ®e íÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ÿnOÿnOÿnOÿnOÿnOÿnOÿnOÿnOÿnOÿnOÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿK³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ®e ®e ®e ®e ®e ®e ®e ®e ®e ®e ®e ®e ®e ®e ®e ®e ®e ®e ®e ®e ®e ®e ®e íÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ÿnOÿnOÿnOÿnOÿnOÿnOÿnOÿnOÿnOã,>ÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿK³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ®e ®e ®e ®e ®e ®e ®e ®e ®e ®e ®e ®e ®e ®e ®e ®e ®e ®e ®e ®e ®e ®e ®e íÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ÿnOÿnOÿnOÿnOÿnOÿnOÿnOÿnOã,>ã,>ÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿK³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ®e ®e ®e ®e ®e ®e ®e ®e ®e ®e ®e ®e ®e ®e ®e ®e ®e ®e ®e ®e ®e ®e ®e íÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ÿnOÿnOÿnOã,>ã,>ÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿK³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ®e ®e ®e ®e ®e ®e ®e ®e ®e ®e ®e ®e ®e ®e ®e ®e ®e ®e ®e ®e ®e ®e ®e ®e íÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿK³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ®e ®e ®e ®e ®e ®e ®e ®e ®e ®e ®e ®e ®e ®e ®e ®e ®e ®e ®e ®e ®e ®e ®e íÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿK³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ®e ®e ®e ®e ®e ®e ®e ®e ®e ®e ®e ®e ®e ®e ®e ®e ®e ®e ®e ®e ®e ®e ®e íÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿK³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ®e ®e ®e ®e ®e ®e ®e ®e ®e ®e ®e ®e ®e ®e ®e ®e ®e ®e ®e ®e ®e ®e ®e íÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿK³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ®e ®e ®e ®e ®e ®e ®e ®e ®e ®e ®e ®e ®e ®e ®e ®e ®e ®e ®e ®e ®e ®e íÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿK³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ®e ®e ®e ®e ®e ®e ®e ®e ®e ®e ®e ®e ®e ®e ®e ®e ®e ®e ®e ®e ®e ®e íÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿK³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ®e ®e ®e ®e ®e ®e ®e ®e ®e ®e ®e ®e ®e ®e ®e ®e ®e ®e ®e ®e ®e íÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿK³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ®e ®e ®e ®e ®e ®e ®e ®e ®e ®e ®e ®e ®e ®e ®e ®e ®e ®e ®e íÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿK³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ®e ®e ®e ®e ®e ®e ®e ®e ®e ®e ®e ®e ®e ®e ®e ®e ®e ®e íÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿK³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ®e ®e ®e ®e ®e ®e ®e ®e ®e ®e ®e ®e ®e ®e ®e ®e ®e ®e ®e íÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿK³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ®e ®e ®e ®e ®e ®e ®e ®e ®e ®e ®e ®e ®e ®e ®e ®e ®e íÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿK³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ®e ®e ®e ®e ®e ®e ®e ®e ®e ®e ®e ®e ®e ®e ®e ®e íÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿK³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJÿÿÿ®e ®e ®e ®e ®e ®e ®e ®e ®e ®e ®e ®e ®e ®e íÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿK³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJÿÿÿ®e ®e ®e ®e ®e ®e ®e ®e ®e ®e ®e ®e ®e ®e íÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿK³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJÿÿÿ®e ®e ®e ®e ®e ®e ®e ®e ®e ®e ®e ®e íÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿK³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJÿÿÿ®e ®e ®e ®e ®e ®e ®e ®e ®e íÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿK³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJÿÿÿ®e ®e ®e ®e ®e ®e íÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿK³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJÿÿÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿK³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJÿÿÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿK³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJÿÿÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿK³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJÿÿÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿK³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJÿÿÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿK³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿKÿK³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ÿKÿKÿKÿKÿKÿKÿKÿKÿKÿK³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ÿKÿKÿKÿKÿKÿKÿKÿKÿKÿK³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ÿKÿKÿKÿKÿKÿK³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ÿKÿKÿKÿKÿKÿK³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ÿKÿK³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ÿK³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJ³qJíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>³qJ³qJ³qJ³qJ³qJ³qJ³qJíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>íÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿíÿÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ÿ,øÿ,øÿ,øÿ,øÿ,øÿ,øã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ÿ,øÿ,øÿ,øÿ,øÿ,øã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ÿ,øã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>ã,>xfrisk-1.2/XFrisk.ad0100644000175000017500000004755107011645631013432 0ustar johnojohno*font: fixed *borderColor: black *foreground: black *background: DeepSkyBlue3 *defaultDistance: 1 *Form.background: DeepSkyBlue3 *Form.foreground: black *Label*background: DeepSkyBlue4 *Label*foreground: Yellow *List*background: DeepSkyBlue3 *List*foreground: black *Text*background: DeepSkyBlue3 *Text*foreground: black *Viewport*background: DeepSkyBlue3 *Viewport*foreground: black *Command.background: DeepSkyBlue2 *Command.foreground: Black *Command.height: 22 *wMap.width: 800 *wMap.height: 404 *wMap.translations: #override\n\ Shift: mapShiftClick()\n\ : mapClick()\n\ : mapClick()\n\ : mapClick() *wPlayField.width: 795 *wPlayField.height: 70 *wPlayField.fromVert: wMap *wPlayField.defaultDistance: 2 *wControls.width: 795 *wControls.height: 200 *wControls.fromVert: wPlayField *wControls.background: DeepSkyBlue3 *wAttackLabel.label: Attack *wAttackLabel.width: 50 *wAttackList.defaultColumns: 1 *wAttackList.fromVert: wAttackLabel *wAttackList.height: 64 *wAttackList.width: 50 *wActionLabel.label: Action *wActionLabel.fromHoriz: wAttackLabel *wActionLabel.width: 110 *wActionList.defaultColumns: 1 *wActionList.fromVert: wActionLabel *wActionList.fromHoriz: wAttackList *wMsgDestLabel.fromHoriz: wActionLabel *wMsgDestLabel.label: Msg. Dest. *wMsgDestLabel.width: 100 *wMsgDestViewport.fromHoriz: wActionList *wMsgDestViewport.fromVert: wMsgDestLabel *wMsgDestViewport.width: 100 *wMsgDestViewport.height: 64 *wMsgDestViewport.forceBars: True *wMsgDestViewport.useRight: True *wMsgDestViewport.allowVert: True *wMsgDestList.defaultColumns: 1 *wSendMsgText.fromHoriz: wMsgDestLabel *wSendMsgText*background: Skyblue *wSendMsgText*foreground: black *wSendMsgText.autoFill: True *wSendMsgText.width: 527 *wSendMsgText.translations: #override\n\ Return: sendMessage()\n\ CtrlM: no-op()\n\ CtrlJ: no-op()\n\ Linefeed: no-op()\n\ Tab: no-op() *wMsgText.width: 527 *wMsgText.height: 64 *wMsgText.displayCaret: False *wMsgText.fromHoriz: wMsgDestViewport *wMsgText.fromVert: wSendMsgText *wCurrentPlayer.width: 25 *wCurrentPlayer.height: 21 *wCurrentPlayer.background: black *wCommentLabel.foreground: Black *wCommentLabel.justify: left *wCommentLabel.label: Welcome to Frisk! *wCommentLabel.font: *helvetica-m*-r-*12* *wCommentLabel.width: 498 *wCommentLabel.height: 21 *wCommentLabel.background: #aabbdd *wCommentLabel.fromHoriz: wCurrentPlayer *wAboutButton.fromVert: wCommentLabel *wAboutButton.label: About *wCancelAttackButton.fromVert: wCommentLabel *wCancelAttackButton.fromHoriz: wAboutButton *wCancelAttackButton.label: Cancel Action *wRepeatButton.fromVert: wCommentLabel *wRepeatButton.fromHoriz: wCancelAttackButton *wRepeatButton.label: Repeat Attack *wEndTurnButton.fromVert: wCommentLabel *wEndTurnButton.fromHoriz: wRepeatButton *wEndTurnButton.label: End Turn *wShowCardsButton.fromHoriz: wEndTurnButton *wShowCardsButton.fromVert: wCommentLabel *wShowCardsButton.label: Show Cards *wStatViewButton.fromHoriz: wShowCardsButton *wStatViewButton.fromVert: wCommentLabel *wStatViewButton.label: Stats View *wHelpButton.fromHoriz: wStatViewButton *wHelpButton.fromVert: wCommentLabel *wHelpButton.label: Help *wQuitButton.fromVert: wCommentLabel *wQuitButton.fromHoriz: wHelpButton *wQuitButton.label: Quit *wErrorLabel.foreground: Black *wErrorLabel.justify: left *wErrorLabel.label: *wErrorLabel.font: *helvetica-m*-r-*12* *wErrorLabel.width: 527 *wErrorLabel.height: 21 *wErrorLabel.background: #aabbdd *wErrorLabel.fromVert: wQuitButton *wDiceBox.width: 263 *wDiceBox.height: 72 *wDiceBox.background: #00aa00 *wDiceBox.fromHoriz: wCommentLabel *wCardViewport.width: 790 *wCardViewport.height: 206 *wCardViewport.forceBars: True *wCardViewport.useRight: True *wCardViewport.allowVert: True ! Card popup *wCardForm.width: 790 *wCardForm.height: 206 *wExchangeButton.fromVert: wCardViewport *wExchangeButton.label: Exchange Cards *wCancelCardsButton.fromVert: wCardViewport *wCancelCardsButton.fromHoriz: wExchangeButton *wCancelCardsButton.label: Cancel ! Armies popup *wArmiesForm.defaultDistance: 8 *wArmiesLabel.label: Number of Armies: *wArmiesLabel.width: 125 *wArmiesText*background: Skyblue *wArmiesText.fromHoriz: wArmiesLabel *wArmiesText.width: 30 *wArmiesText*translations: #override\ Return: popupArmies()\n\ CtrlM: no-op()\n\ CtrlJ: no-op()\n\ Linefeed: no-op()\n\ Tab: no-op() *wFinishArmiesButton.fromVert: wArmiesLabel *wFinishArmiesButton.label: Ok *wFinishArmiesButton.width: 80 *wCancelArmiesButton.fromVert: wArmiesText *wCancelArmiesButton.fromHoriz: wFinishArmiesButton *wCancelArmiesButton.label: Cancel *wCancelArmiesButton.width: 80 ! Help popup *Help.label: Frisk Help *wHelpForm.width: 600 *wHelpForm.height: 400 *wHelpTopicLabel.label: Help Topics *wHelpTopicLabel.width: 200 *wHelpLabel.label: *wHelpLabel.fromHoriz: wHelpTopicLabel *wHelpLabel.width: 500 *wHelpTopicList.defaultColumns: 1 *wHelpTopicList.forceColumns: True *wHelpTopicViewport.width: 200 *wHelpTopicViewport.height: 380 *wHelpTopicViewport.fromVert: wHelpTopicLabel *wHelpTopicViewport.forceBars: True *wHelpTopicViewport.useRight: True *wHelpTopicViewport.allowVert: True *wHelpTopicViewport*font: *helvetica-m*-r-*12* *wHelpText.width: 500 *wHelpText.height: 380 *wHelpText.fromVert: wHelpTopicLabel *wHelpText.fromHoriz: wHelpTopicViewport *wHelpText*font: *helvetica-m*-r-*12* *wHelpOkButton.fromVert: wHelpTopicViewport *wHelpOkButton.label: Close Help Window ! Dialog popup !!*wDialogLabel.width: 300 *wDialogLabel*font: *helvetica-b*-o-*14* *wDialogLabel.background: DeepSkyBlue3 *wDialogLabel.borderColor: DeepSkyBlue3 *wDialogLabel.borderWidth: 0 *wDialogLabel.justify: Left *wDialogForm.defaultDistance: 8 *wDialogButton1.fromVert: wDialogLabel *wDialogButton1.font: *helvetica-m*-r-*12* *wDialogButton2.fromVert: wDialogLabel *wDialogButton2.font: *helvetica-m*-r-*12* *wDialogButton3.fromVert: wDialogLabel *wDialogButton3.font: *helvetica-m*-r-*12* !!!!!!!!!!!!!!!!!!!!!!!!!!!!! ! Color Editing popup !!!!!!!!!!!!!!!!!!!!!!!!!!!!! *wColorEditForm.width: 310 *wColorEditForm.height: 400 *wColorEditForm.defaultDistance: 5 *wColorEditLabel.width: 221 *wColorEditLabel.label: Select a color *wRedScrollbar.topShadowPixel: #ff0000 *wRedScrollbar.bottomShadowPixel: #990000 *wRedScrollbar.background: #dd0000 *wRedScrollbar.width: 20 *wRedScrollbar.height: 140 *wRedScrollbar.foreground: Black *wRedScrollbar.fromVert: wColorEditLabel *wRedScrollbar.translations: #override\n\ : StartScroll(Continuous) MoveThumb() NotifyThumb() \n\ : MoveThumb() NotifyThumb() \n\ : StartScroll(Continuous) MoveThumb() NotifyThumb() \n\ : MoveThumb() NotifyThumb() \n\ : StartScroll(Continuous) MoveThumb() NotifyThumb()\n\ : MoveThumb() NotifyThumb() *wRedScrollbar.scrollVCursor: hand1 *wRedScrollbar.scrollRCursor: hand1 *wGreenScrollbar.topShadowPixel: #00ff00 *wGreenScrollbar.bottomShadowPixel: #009900 *wGreenScrollbar.background: #00dd00 *wGreenScrollbar.width: 20 *wGreenScrollbar.height: 140 *wGreenScrollbar.foreground: Black *wGreenScrollbar.fromHoriz: wRedScrollbar *wGreenScrollbar.fromVert: wColorEditLabel *wGreenScrollbar.translations: #override\n\ : StartScroll(Continuous) MoveThumb() NotifyThumb() \n\ : MoveThumb() NotifyThumb() \n\ : StartScroll(Continuous) MoveThumb() NotifyThumb() \n\ : MoveThumb() NotifyThumb() \n\ : StartScroll(Continuous) MoveThumb() NotifyThumb()\n\ : MoveThumb() NotifyThumb() *wGreenScrollbar.scrollVCursor: hand1 *wGreenScrollbar.scrollRCursor: hand1 *wBlueScrollbar.topShadowPixel: #0000ff *wBlueScrollbar.bottomShadowPixel: #000099 *wBlueScrollbar.background: #0000dd *wBlueScrollbar.width: 20 *wBlueScrollbar.height: 140 *wBlueScrollbar.foreground: Black *wBlueScrollbar.fromHoriz: wGreenScrollbar *wBlueScrollbar.fromVert: wColorEditLabel *wBlueScrollbar.translations: #override\n\ : StartScroll(Continuous) MoveThumb() NotifyThumb() \n\ : MoveThumb() NotifyThumb() \n\ : StartScroll(Continuous) MoveThumb() NotifyThumb() \n\ : MoveThumb() NotifyThumb() \n\ : StartScroll(Continuous) MoveThumb() NotifyThumb()\n\ : MoveThumb() NotifyThumb() *wBlueScrollbar.scrollVCursor: hand1 *wBlueScrollbar.scrollRCursor: hand1 *wSampleCountryForm.label: *wSampleCountryForm.width: 140 *wSampleCountryForm.height: 140 *wSampleCountryForm.fromVert: wColorEditLabel *wSampleCountryForm.fromHoriz: wBlueScrollbar *wSampleCountryForm.borderColor:black *wSampleCountryForm.internalHeight:0 *wSampleCountryForm.internalWidth:0 *wColorInputLabel.label: Color Name *wColorInputLabel.width: 107 *wColorInputLabel.fromVert: wRedScrollbar *wColorInputText.width: 107 *wColorInputText.fromHoriz: wColorInputLabel *wColorInputText.fromVert: wSampleCountryForm *wColorInputText*background: LightSkyBlue1 *wColorInputText*borderColor: Black *wColorInputText*translations: #override\ Return: updateColor()\n\ Escape: colorEditCancel()\n\ CtrlM: no-op()\n\ CtrlJ: no-op()\n\ Linefeed: no-op()\n\ Tab: no-op() *wColorDummy.width: 33 *wColorDummy.borderColor: DeepSkyBlue3 *wColorDummy.height: 22 *wColorDummy.fromVert: wColorInputLabel *wColorDummy.shadowWidth: 0 *wColorOK.fromVert: wColorInputLabel *wColorOK.fromHoriz: wColorDummy *wColorOK.width: 70 *wColorOK.label: Ok *wColorCancel.fromVert: wColorInputLabel *wColorCancel.fromHoriz: wColorOK *wColorCancel.width: 70 *wColorCancel.label: Cancel !!!!!!!!!!!!!!!!!!!!!!!!!!!!! ! Registration Dialog !!!!!!!!!!!!!!!!!!!!!!!!!!!!! *wRegisterForm.width: 300 *wRegisterForm.height: 350 *wRegisterForm*font: fixed *wRegisterForm.defaultDistance: 4 *wPlayerViewport.width: 300 *wPlayerViewport.height: 260 *wPlayerViewport.forceBars: True *wPlayerViewport.useRight: True *wPlayerViewport.allowVert: True *wPlayerViewport*background: DeepSkyBlue2 *wPlayerForm.translations: #override\n\ Shift: regMouseShiftClick()\n\ : regMouseClick() *wPlayerForm*wShowPlayerForm.width: 280 *wPlayerForm*wShowPlayerForm.height: 20 *wPlayerForm*wShowPlayerForm.borderColor: DeepSkyBlue2 *wPlayerForm*wShowPlayerForm.translations: #override\n\ Shift: regMouseShiftClick()\n\ : regMouseClick() ! Player Color *wShowPlayerForm*wShowPlayerColor.borderColor: DeepSkyBlue2 *wShowPlayerForm*wShowPlayerColor.borderWidth: 1 *wShowPlayerForm*wShowPlayerColor.internalHeight: 0 *wShowPlayerForm*wShowPlayerColor.internalWidth: 0 *wShowPlayerForm*wShowPlayerColor.label: *wShowPlayerForm*wShowPlayerColor.width: 18 *wShowPlayerForm*wShowPlayerColor.height: 18 *wShowPlayerForm*wShowPlayerColor.shadowWidth: 0 *wShowPlayerForm*wShowPlayerColor.translations: #override\n\ : regEditColor() ! Player Name *wShowPlayerForm*wShowPlayerName.borderColor: DeepSkyBlue2 *wShowPlayerForm*wShowPlayerName.label: *wShowPlayerForm*wShowPlayerName.width: 150 *wShowPlayerForm*wShowPlayerName.height: 18 *wShowPlayerForm*wShowPlayerName.resize: False *wShowPlayerForm*wShowPlayerName.justify: left *wShowPlayerForm*wShowPlayerName.shadowWidth: 0 ! Player Species *wShowPlayerForm*wShowPlayerSpecies.borderColor: DeepSkyBlue2 *wShowPlayerForm*wShowPlayerSpecies.label: *wShowPlayerForm*wShowPlayerSpecies.width: 95 *wShowPlayerForm*wShowPlayerSpecies.resize: False *wShowPlayerForm*wShowPlayerSpecies.height: 18 *wShowPlayerForm*wShowPlayerSpecies.justify: left *wShowPlayerForm*wShowPlayerSpecies.shadowWidth: 0 *wAddPlayerButton.width: 147 *wAddPlayerButton.label: Add Player *wAddPlayerButton.fromVert: wPlayerViewport *wDeletePlayerButton.width: 147 *wDeletePlayerButton.label: Delete Player *wDeletePlayerButton.fromHoriz: wAddPlayerButton *wDeletePlayerButton.fromVert: wPlayerViewport *wRegisterOKButton.width: 95 *wRegisterOKButton.label: Start Game *wRegisterOKButton.fromVert: wAddPlayerButton *wRegisterOKButton.fromHoriz: wAddPlayerButton !!!!!!!!!!!!!!!!!!!!!!! ! Add player dialog !!!!!!!!!!!!!!!!!!!!!!! *wAddPlayerForm.width: 600 *wAddPlayerForm.height: 300 *wAddPlayerForm.defaultDistance: 5 *wPlayerNameLabel.label: Name *wPlayerNameLabel.width: 100 *wPlayerNameLabel.justify: left *wPlayerNameText.width: 200 *wPlayerNameText.fromHoriz: wPlayerNameLabel *wPlayerNameText*background: LightSkyBlue1 *wPlayerNameText.borderColor: Black *wPlayerNameText.translations: #override\n\ Escape: playerCancel()\n\ Return: playerOk()\n\ CtrlM: no-op()\n\ CtrlJ: no-op()\n\ Linefeed: no-op()\n\ Tab: no-op() *wPlayerSpeciesLabel.label: Species *wPlayerSpeciesLabel.width: 100 *wPlayerSpeciesLabel.fromVert: wPlayerNameLabel *wPlayerSpeciesLabel.justify: left *wPlayerSpeciesViewport.width: 200 *wPlayerSpeciesViewport.height: 100 *wPlayerSpeciesViewport.fromHoriz: wPlayerSpeciesLabel *wPlayerSpeciesViewport.fromVert: wPlayerNameText *wPlayerSpeciesViewport.forceBars: True *wPlayerSpeciesViewport.useRight: True *wPlayerSpeciesViewport.allowVert: True *wPlayerSpeciesViewport*background: DeepSkyBlue2 *wPlayerSpeciesListBox.width: 200 *wPlayerSpeciesListBox*background: DeepSkyBlue2 *wPlayerDummy1.fromVert: wPlayerSpeciesLabel *wPlayerDummy1.width: 100 *wPlayerDummy1.height: 76 *wPlayerDummy1.label: *wPlayerDummy1.background: DeepSkyBlue3 *wPlayerDummy1.borderColor: DeepSkyBlue3 *wPlayerDummy1.shadowWidth: 0 *wPlayerDescLabel.label: Description *wPlayerDescLabel.justify: left *wPlayerDescLabel.width: 100 *wPlayerDescLabel.fromVert: wPlayerDummy1 *wPlayerDescText.width: 200 *wPlayerDescText.height: 30 *wPlayerDescText.fromVert: wPlayerSpeciesViewport *wPlayerDescText.fromHoriz: wPlayerDescLabel *wPlayerDescText.displayCaret: False *wPlayerDescText*background: DeepSkyBlue2 *wPlayerDescText.cursor: top_left_arrow *wPlayerDummy2.fromVert: wPlayerDescLabel *wPlayerDummy2.width: 100 *wPlayerDummy2.height: 6 *wPlayerDummy2.label: *wPlayerDummy2.background: DeepSkyBlue3 *wPlayerDummy2.borderColor: DeepSkyBlue3 *wPlayerDummy2.shadowWidth: 0 *wPlayerVersionLabel.label: Version *wPlayerVersionLabel.justify: left *wPlayerVersionLabel.width: 100 *wPlayerVersionLabel.fromVert: wPlayerDummy2 *wPlayerVersionText.width: 200 *wPlayerVersionText.fromVert: wPlayerDescText *wPlayerVersionText.fromHoriz: wPlayerVersionLabel *wPlayerVersionText.displayCaret: False *wPlayerVersionText*background: DeepSkyBlue2 *wPlayerVersionText.cursor: top_left_arrow *wPlayerAuthorLabel.label: Author *wPlayerAuthorLabel.justify: left *wPlayerAuthorLabel.width: 100 *wPlayerAuthorLabel.fromVert: wPlayerVersionLabel *wPlayerAuthorText.width: 200 *wPlayerAuthorText.fromHoriz: wPlayerAuthorLabel *wPlayerAuthorText.fromVert: wPlayerVersionText *wPlayerAuthorText.displayCaret: False *wPlayerAuthorText*background: DeepSkyBlue2 *wPlayerAuthorText.cursor: top_left_arrow *wPlayerColorLabel.label: Color *wPlayerColorLabel.width: 100 *wPlayerColorLabel.justify: left *wPlayerColorLabel.fromVert: wPlayerAuthorLabel *wPlayerColorDisplay.fromVert: wPlayerAuthorText *wPlayerColorDisplay.fromHoriz: wPlayerColorLabel *wPlayerColorDisplay.width: 18 *wPlayerColorDisplay.height: 18 *wPlayerColorDisplay.shadowWidth: 0 *wPlayerColorDisplay.label: *wPlayerColorDisplay.background: Black *wPlayerColorDisplay.cursor: hand1 *wPlayerColorDisplay*translations: #override \ : playerEditColor()\n\ : playerEditColor()\n\ : playerEditColor() *wPlayerDummy3.fromVert: wPlayerColorLabel *wPlayerDummy3.width: 300 *wPlayerDummy3.height: 12 *wPlayerDummy3.label: *wPlayerDummy3.background: DeepSkyBlue3 *wPlayerDummy3.borderColor: DeepSkyBlue3 *wPlayerDummy3.shadowWidth: 0 *wPlayerDummy4.fromVert: wPlayerDummy3 *wPlayerDummy4.width: 50 *wPlayerDummy4.height: 20 *wPlayerDummy4.label: *wPlayerDummy4.background: DeepSkyBlue3 *wPlayerDummy4.borderColor: DeepSkyBlue3 *wPlayerDummy4.shadowWidth: 0 *wPlayerOk.label: Ok *wPlayerOk.width: 100 *wPlayerOk.fromHoriz: wPlayerDummy4 *wPlayerOk.fromVert: wPlayerDummy3 *wPlayerCancel.label: Cancel *wPlayerCancel.width: 100 *wPlayerCancel.fromHoriz: wPlayerOk *wPlayerCancel.fromVert: wPlayerDummy3 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! !! Statistics view !! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! *wStatForm.width: 300 *wStatForm.height: 400 *wStatNumberForm.width: 300 *wStatNumberForm.height: 250 *wStatNumberForm.defaultDistance: 2 *wStatGraphForm.fromVert: wStatNumberForm *wStatGraphForm.defaultDistance: 2 *wStatGraphForm.resizable: False *wStatGraph.width: 300 *wStatGraph.height: 150 *wStatCloseButton.fromVert: wStatGraphForm *wStatCloseButton.width: 475 *wStatCloseButton.label: Close *wStatCloseButton.justify: center *wStatColorLabel.label: *wStatColorLabel.background: DeepSkyBlue3 *wStatColorLabel.borderColor: DeepSkyBlue3 *wStatColorLabel.width: 22 *wStatColorLabel.justify: center *wStatNameLabel.label: Name *wStatNameLabel.width: 80 *wStatNameLabel.justify: center *wStatNameLabel.fromHoriz: wStatColorLabel *wStatArmiesLabel.label: Armies *wStatArmiesLabel.width: 80 *wStatArmiesLabel.justify: center *wStatArmiesLabel.fromHoriz: wStatNameLabel *wStatCountriesLabel.label: Territories *wStatCountriesLabel.width: 80 *wStatCountriesLabel.justify: center *wStatCountriesLabel.fromHoriz: wStatArmiesLabel *wStatCardsLabel.label: Cards *wStatCardsLabel.width: 80 *wStatCardsLabel.justify: center *wStatCardsLabel.fromHoriz: wStatCountriesLabel *wStatWLDLabel.label: Win/Lose/Draw *wStatWLDLabel.width: 90 *wStatWLDLabel.justify: center *wStatWLDLabel.fromHoriz: wStatCardsLabel *wStatViewport.fromVert: wStatGraphLabel *wStatViewport.forceBars: True *wStatViewport.useRight: True *wStatViewport.allowVert: True *wStatViewport*background: DeepSkyBlue2 *wStatViewport.width: 471 *wStatViewport.height: 208 *wStatViewport.fromVert: wStatNameLabel *wStatPlayerForm*borderColor: DeepSkyBlue2 *wShowPlayerForm*defaultDistance: 2 *wStatNumberForm*wStatPlayerColor.borderColor: DeepSkyBlue2 *wStatNumberForm*wStatPlayerColor.width: 18 *wStatNumberForm*wStatPlayerColor.height: 18 *wStatNumberForm*wStatPlayerColor.label: *wStatNumberForm*wStatPlayerName.borderColor: DeepSkyBlue2 *wStatNumberForm*wStatPlayerName.height: 18 *wStatNumberForm*wStatPlayerName.width: 80 *wStatNumberForm*wStatPlayerName.label: *wStatNumberForm*wStatPlayerArmies.borderColor: DeepSkyBlue2 *wStatNumberForm*wStatPlayerArmies.height: 18 *wStatNumberForm*wStatPlayerArmies.width: 80 *wStatNumberForm*wStatPlayerArmies.label: *wStatNumberForm*wStatPlayerCountries.borderColor: DeepSkyBlue2 *wStatNumberForm*wStatPlayerCountries.height: 18 *wStatNumberForm*wStatPlayerCountries.width: 80 *wStatNumberForm*wStatPlayerCountries.label: *wStatNumberForm*wStatPlayerCards.borderColor: DeepSkyBlue2 *wStatNumberForm*wStatPlayerCards.height: 18 *wStatNumberForm*wStatPlayerCards.width: 80 *wStatNumberForm*wStatPlayerCards.label: *wStatNumberForm*wStatPlayerWLD.borderColor: DeepSkyBlue2 *wStatNumberForm*wStatPlayerWLD.height: 18 *wStatNumberForm*wStatPlayerWLD.width: 90 *wStatNumberForm*wStatPlayerWLD.label: *wStatGraphLabel.label: Territories vs. Time *wStatGraphLabel.width: 471 *wStatGraph.width: 471 *wStatGraph.height: 110 *wStatGraph.internalWidth: 0 *wStatGraph.internalHeight: 0 *wStatGraph.background: black *wStatGraph.fromVert: wStatGraphLabel xfrisk-1.2/addPlayer.c0100644000175000017500000005022607042645170013762 0ustar johnojohno/* * XFrisk - The classic board game for X * Copyright (C) 1993-1999 Elan Feingold (elan@aetherworks.com) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * $Id: addPlayer.c,v 1.12 2000/01/23 18:37:44 tony Exp $ * * $Log: addPlayer.c,v $ * Revision 1.12 2000/01/23 18:37:44 tony * removed a debug printf * * Revision 1.11 2000/01/15 17:34:12 morphy * Fixes to update color indicator to initial color and after editing color * * Revision 1.10 2000/01/10 22:47:39 tony * made colorstuff more private to colormap.c, only scrollbars get set wrong, rest seems to work ok now * * * \file "Add player" dialog */ #include #include #include #include #include #include #include #include #include #include #include #include "addPlayer.h" #include "colorEdit.h" #include "client.h" #include "utils.h" #include "types.h" #include "gui-vars.h" #include "riskgame.h" #include "callbacks.h" #include "debug.h" /* Private functions */ void PLAYER_EditColor(void); void PLAYER_SetSpecies(Int32 iSpecies); void PLAYER_SpeciesCreated(Int32 iSpecies); void PLAYER_SpeciesDestroyed(Int32 iSpecies); void PLAYER_RenderSpecies(void); void PLAYER_Ok(void); void PLAYER_Cancel(void); void PLAYER_SelectSpecies(Widget w, XtPointer pData, XtPointer call_data); Int32 PLAYER_SlotToSpecies(Int32 iSlot); Int32 PLAYER_SpeciesToSlot(Int32 iSpecies); /* Globals */ static Flag fPoppedUp = FALSE; static String *ppstrStrings = NULL; static Int32 *piSlotToSpecies = NULL; static Int32 iCurrentSpecies = SPECIES_HUMAN; static Int32 iNumSlots = 1; Int32 r, g, b; /* really static? at least keep global */ /* Action tables */ static XtActionsRec actionTable[] = { { "playerEditColor", (XtActionProc)PLAYER_EditColor }, { "playerOk", (XtActionProc)PLAYER_Ok }, { "playerCancel", (XtActionProc)PLAYER_Cancel }, { NULL, NULL } }; /* Widgets */ static Widget wAddPlayerShell; static Widget wPlayerNameText; static Widget wPlayerSpeciesListbox; static Widget wPlayerDescText; static Widget wPlayerVersionText; static Widget wPlayerAuthorText; static Widget wPlayerDummy1; static Widget wPlayerDummy2; static Widget wPlayerDummy3; static Widget wPlayerDummy4; static Widget wAddPlayerForm; static Widget wPlayerNameLabel; static Widget wPlayerSpeciesLabel; static Widget wPlayerSpeciesViewport; static Widget wPlayerAuthorLabel; static Widget wPlayerVersionLabel; static Widget wPlayerDescLabel; static Widget wPlayerColorLabel; static Widget wPlayerColorDisplay; static Widget wPlayerOk; static Widget wPlayerCancel; /** * Pick a color for this player \par store in map */ void PLAYER_InitColor() { r = rand() % 65536; g = rand() % 65536; b = rand() % 65536; while ((r+g+b) < 120000) { r = r + (rand() % 30000); g = g + (rand() % 30000); b = b + (rand() % 30000); } if (r>=65536) r = 65535; if (g>=65536) g = 65535; if (b>=65536) b = 65535; COLOR_StoreColor(COLOR_DieToColor(0), r, g, b); } /************************************************************************ * FUNCTION: PLAYER_BuildDialog * HISTORY: * 01.29.95 ESF Created. * PURPOSE: * NOTES: ************************************************************************/ void PLAYER_BuildDialog(void) { wAddPlayerShell = XtCreatePopupShell("wAddPlayerShell", transientShellWidgetClass, wToplevel, pVisualArgs, iVisualCount); /* The form */ wAddPlayerForm = XtCreateManagedWidget("wAddPlayerForm", formWidgetClass, wAddPlayerShell, NULL, 0); /* Player name */ wPlayerNameLabel = XtCreateManagedWidget("wPlayerNameLabel", labelWidgetClass, wAddPlayerForm, NULL, 0); wPlayerNameText = XtVaCreateManagedWidget("wPlayerNameText", asciiTextWidgetClass, wAddPlayerForm, XtNeditType, XawtextEdit, NULL); /* Player species */ wPlayerSpeciesLabel = XtCreateManagedWidget("wPlayerSpeciesLabel", labelWidgetClass, wAddPlayerForm, NULL, 0); wPlayerSpeciesViewport = XtCreateManagedWidget("wPlayerSpeciesViewport", viewportWidgetClass, wAddPlayerForm, NULL, 0); wPlayerSpeciesListbox = XtVaCreateManagedWidget("wPlayerSpeciesListbox", listWidgetClass, wPlayerSpeciesViewport, NULL); XtAddCallback(wPlayerSpeciesListbox, XtNcallback, PLAYER_SelectSpecies, NULL); /* Player description */ wPlayerDummy1 = XtCreateManagedWidget("wPlayerDummy1", labelWidgetClass, wAddPlayerForm, NULL, 0); wPlayerDescLabel = XtCreateManagedWidget("wPlayerDescLabel", labelWidgetClass, wAddPlayerForm, NULL, 0); wPlayerDescText = XtVaCreateManagedWidget("wPlayerDescText", asciiTextWidgetClass, wAddPlayerForm, XtNwrap, XawtextWrapWord, XtNautoFill, True, NULL); /* Player version */ wPlayerDummy2 = XtCreateManagedWidget("wPlayerDummy2", labelWidgetClass, wAddPlayerForm, NULL, 0); wPlayerVersionLabel = XtCreateManagedWidget("wPlayerVersionLabel", labelWidgetClass, wAddPlayerForm, NULL, 0); wPlayerVersionText = XtCreateManagedWidget("wPlayerVersionText", asciiTextWidgetClass, wAddPlayerForm, NULL, 0); /* Player author */ wPlayerAuthorLabel = XtCreateManagedWidget("wPlayerAuthorLabel", labelWidgetClass, wAddPlayerForm, NULL, 0); wPlayerAuthorText = XtCreateManagedWidget("wPlayerAuthorText", asciiTextWidgetClass, wAddPlayerForm, NULL, 0); /* Player color */ wPlayerColorLabel = XtCreateManagedWidget("wPlayerColorLabel", labelWidgetClass, wAddPlayerForm, NULL, 0); wPlayerColorDisplay = XtVaCreateManagedWidget("wPlayerColorDisplay", labelWidgetClass, wAddPlayerForm, XtNbackground, COLOR_QueryColor(COLOR_DieToColor(0)), NULL); /* Space */ wPlayerDummy3 = XtCreateManagedWidget("wPlayerDummy3", formWidgetClass, wAddPlayerForm, NULL, 0); /* OK and Cancel buttons */ wPlayerDummy4 = XtCreateManagedWidget("wPlayerDummy4", formWidgetClass, wAddPlayerForm, NULL, 0); wPlayerOk = XtCreateManagedWidget("wPlayerOk", commandWidgetClass, wAddPlayerForm, NULL, 0); XtAddCallback(wPlayerOk, XtNcallback, (XtCallbackProc)PLAYER_Ok, NULL); wPlayerCancel = XtCreateManagedWidget("wPlayerCancel", commandWidgetClass, wAddPlayerForm, NULL, 0); XtAddCallback(wPlayerCancel, XtNcallback, (XtCallbackProc)PLAYER_Cancel, NULL); /* Add Actions */ XtAppAddActions(appContext, actionTable, XtNumber(actionTable)); /* Init the string table and mapping function */ ppstrStrings = (String *)MEM_Alloc(sizeof(String)*2); ppstrStrings[0] = (String)MEM_Alloc(strlen( RISK_GetNameOfSpecies(SPECIES_HUMAN))+1); strcpy(ppstrStrings[0], RISK_GetNameOfSpecies(SPECIES_HUMAN)); ppstrStrings[1] = (String)NULL; piSlotToSpecies = (Int32 *)MEM_Alloc(sizeof(Int32)*1); piSlotToSpecies[0] = SPECIES_HUMAN; } /************************************************************************ * FUNCTION: PLAYER_PopupDialog * HISTORY: * 01.29.95 ESF Created. * 02.26.95 ESF Fixed to generate brighter random colors. * 04.30.95 ESF Fixed to generate even brighter random colors. * 05.06.95 ESF Fixed a bug whereas the wrong species was highlighted. * 15.01.00 MSH Fixed to update color indicator to initial color. * PURPOSE: * NOTES: called from "Register players" ************************************************************************/ void PLAYER_PopupDialog(void) { Int32 x, y; /* Center the new shell */ UTIL_CenterShell(wAddPlayerShell, wToplevel, &x, &y); XtVaSetValues(wAddPlayerShell, XtNallowShellResize, False, XtNx, x, XtNy, y, XtNborderWidth, 1, XtNtitle, "Add Player", NULL); /* TBD: Could make sure here that COLOR_DieToColor(0) had a * reasonable color for the new player, i.e. unique, nice... * for now pick a random color...but not too dim!! */ PLAYER_InitColor(); /* Update the color indicator */ XtVaSetValues(wPlayerColorDisplay, XtNbackground, COLOR_QueryColor(COLOR_DieToColor(0)), NULL); /* Do the species stuff */ PLAYER_RenderSpecies(); PLAYER_SetSpecies(iCurrentSpecies); XawListHighlight(wPlayerSpeciesListbox, PLAYER_SpeciesToSlot(iCurrentSpecies)); /* Pop the dialog up, set the keyboard focus */ XtPopup(wAddPlayerShell, XtGrabExclusive); fPoppedUp = TRUE; XtSetKeyboardFocus(wToplevel, wPlayerNameText); XtSetKeyboardFocus(wAddPlayerShell, wPlayerNameText); } /************************************************************************ * FUNCTION: PLAYER_Ok * HISTORY: * 01.29.94 ESF Created. * 01.31.94 ESF Delete the strings after registering. * 02.05.94 ESF Remove local registration from here. * 02.05.94 ESF Adding color validity checking. * 03.07.94 ESF Switched to varargs Xt calls. * 03.08.94 ESF Fixed lack of NULL termination in XtVa calls. * 05.04.94 ESF Fixed DistObj changes, added SetNumLivePlayers() * 05.07.94 ESF Fixed to not let too many players register. * 11.16.94 ESF Fixed to not send info to the server re. new player. * 01.15.95 ESF Fixed to not allocate memory for the empty strings. * PURPOSE: * NOTES: ************************************************************************/ void PLAYER_Ok(void) { CString strPlayerName; Int32 iNewPlayer; XColor xColor; char buf[256]; /* Get the name */ XtVaGetValues(wPlayerNameText, XtNstring, &strPlayerName, NULL); /* Don't bother doing anything if something's not filled out */ if (!strlen(strPlayerName)) return; /* See if there are too many players */ if ((iNewPlayer=CLNT_AllocPlayer(CBK_IncomingMessage)) == -1) { (void)UTIL_PopupDialog("Error", "Maximum number of players exceeded!", 1, "Ok", NULL, NULL); return; } /* Get the XColor from the color index */ COLOR_GetColor(COLOR_DieToColor(0), &xColor.red, &xColor.green, &xColor.blue); snprintf(buf, sizeof(buf), "#%02x%02x%02x", xColor.red/256, xColor.green/256, xColor.blue/256); /* Init. the player */ RISK_SetColorCStringOfPlayer(iNewPlayer, buf); RISK_SetSpeciesOfPlayer(iNewPlayer, iCurrentSpecies); RISK_SetNameOfPlayer(iNewPlayer, strPlayerName); /* If the client is human, then the client is this one, otherwise * it's the AI client that registered it. */ if (iCurrentSpecies == SPECIES_HUMAN) RISK_SetClientOfPlayer(iNewPlayer, CLNT_GetThisClientID()); else RISK_SetClientOfPlayer(iNewPlayer, RISK_GetClientOfSpecies(iCurrentSpecies)); /* This player is now finished. Note this */ RISK_SetAllocationStateOfPlayer(iNewPlayer, ALLOC_COMPLETE); /* Make sure the name's erased */ XtVaSetValues(wPlayerNameText, XtNstring, "", NULL); XtPopdown(wAddPlayerShell); fPoppedUp = FALSE; /* Reset keyboard focus */ XtSetKeyboardFocus(wToplevel, wToplevel); } /************************************************************************ * FUNCTION: PLAYER_Cancel * HISTORY: * 01.29.95 ESF Created. * 02.12.95 ESF Finished. * PURPOSE: * NOTES: ************************************************************************/ void PLAYER_Cancel(void) { CString strName; /* Make sure the player name widget * is empty, popup warning if not. */ XtVaGetValues(wPlayerNameText, XtNstring, &strName, NULL); if (strlen(strName)) if (UTIL_PopupDialog("Warning", "Discard current registration data?", 2, "Yes", "No", NULL) == QUERY_NO) return; XtPopdown(wAddPlayerShell); /* Reset keyboard focus */ XtSetKeyboardFocus(wToplevel, wToplevel); } /************************************************************************ * FUNCTION: PLAYER_EditColor * HISTORY: * 01.29.95 ESF Created. * 15.01.00 MSH Fixed to update color indicator widget after edit. * PURPOSE: * NOTES: ************************************************************************/ void PLAYER_EditColor(void) { /* Relinquish the keyboard focus */ XtUngrabKeyboard(wPlayerNameText, CurrentTime); /* Popup the color editing dialog */ COLEDIT_EditColor(COLOR_DieToColor(0), FALSE); /* Update the color indicator */ XtVaSetValues(wPlayerColorDisplay, XtNbackground, COLOR_QueryColor(COLOR_DieToColor(0)), NULL); /* Regain the keyboard focus */ while(XtGrabKeyboard(wPlayerNameText, True, GrabModeAsync, GrabModeAsync, CurrentTime) == GrabNotViewable) ; /* TwiddleThumbs() */ } /************************************************************************ * FUNCTION: PLAYER_SetSpecies * HISTORY: * 02.12.95 ESF Created. * PURPOSE: * NOTES: ************************************************************************/ void PLAYER_SetSpecies(Int32 iSpecies) { if ((RISK_GetNameOfSpecies(iSpecies)) == NULL) { printf("Warning: Illegal species (%d)\n", iSpecies); return; } XtVaSetValues(wPlayerDescText, XtNstring, RISK_GetDescriptionOfSpecies(iSpecies), NULL); XtVaSetValues(wPlayerAuthorText, XtNstring, RISK_GetAuthorOfSpecies(iSpecies), NULL); XtVaSetValues(wPlayerVersionText, XtNstring, RISK_GetVersionOfSpecies(iSpecies), NULL); } /************************************************************************ * FUNCTION: PLAYER_Callback * HISTORY: * 02.23.95 ESF Created. * PURPOSE: * NOTES: ************************************************************************/ void PLAYER_Callback(Int32 iMessType, void *pvMess) { /* * SpeciesCreated --> Add species to species list * SpeciesDestroyed --> Delete species from species list */ if (iMessType == MSG_OBJINTUPDATE && ((MsgObjIntUpdate *)pvMess)->iField == SPE_ALLOCATION && ((MsgObjIntUpdate *)pvMess)->iNewValue == ALLOC_COMPLETE) { /* SpeciesCreated */ PLAYER_SpeciesCreated(((MsgObjStrUpdate *)pvMess)->iIndex1); } else if (iMessType == MSG_OBJINTUPDATE && ((MsgObjIntUpdate *)pvMess)->iField == SPE_ALLOCATION && ((MsgObjIntUpdate *)pvMess)->iNewValue == ALLOC_NONE) { /* SpeciesDestroyed */ PLAYER_SpeciesDestroyed(((MsgObjIntUpdate *)pvMess)->iIndex1); } } #define PAD_LENGTH 34 /************************************************************************ * FUNCTION: PLAYER_RenderSpecies * HISTORY: * 02.23.95 ESF Created. * 03.03.95 ESF Finished. * 04.01.95 ESF Fixed a bug, needed parens around iNumSpecies+1. * PURPOSE: * NOTES: ************************************************************************/ void PLAYER_RenderSpecies(void) { /* This is just a first approximation of a future, perhaps much * faster or smarter version. This one does its job, though... */ XawListReturnStruct *pItem; Int32 i, j, k, iLastSelection, iLastSpecies; Int32 iNumSpecies = RISK_GetNumSpecies(); CString *ppstr = (CString *)MEM_Alloc(sizeof(CString)*(iNumSpecies+1)); Int32 *piMap = (Int32 *)MEM_Alloc(sizeof(Int32)*iNumSpecies); CString str; for (i=j=0; ilist_index; iLastSpecies = PLAYER_SlotToSpecies(iLastSelection); XtFree((void *)pItem); /* Display the list! */ XtVaSetValues(wPlayerSpeciesListbox, XtNlist, ppstr, XtNnumberStrings, iNumSpecies, NULL); /* If there were old strings, free all of the memory */ if (ppstrStrings) { for (i=0; i!=iNumSlots; i++) MEM_Free(ppstrStrings[i]); MEM_Free(ppstrStrings); } if (piSlotToSpecies) MEM_Free(piSlotToSpecies); /* Keep the new list of strings and the new mapping */ ppstrStrings = ppstr; piSlotToSpecies = piMap; iNumSlots = iNumSpecies; /* Select the last species if it's still around */ if ((iLastSpecies = PLAYER_SpeciesToSlot(iLastSpecies)) != -1) XawListHighlight(wPlayerSpeciesListbox, iLastSpecies); else XawListHighlight(wPlayerSpeciesListbox, MIN(iLastSelection, iNumSpecies-1)); } /************************************************************************ * FUNCTION: PLAYER_SpeciesDestroyed * HISTORY: * 02.23.95 ESF Created. * PURPOSE: * NOTES: ************************************************************************/ void PLAYER_SpeciesDestroyed(Int32 iSpecies) { UNUSED(iSpecies); if (fPoppedUp == TRUE) PLAYER_RenderSpecies(); } /************************************************************************ * FUNCTION: PLAYER_SpeciesCreated * HISTORY: * 02.23.95 ESF Created. * PURPOSE: * NOTES: ************************************************************************/ void PLAYER_SpeciesCreated(Int32 iSpecies) { UNUSED(iSpecies); if (fPoppedUp == TRUE) PLAYER_RenderSpecies(); } /************************************************************************ * FUNCTION: PLAYER_SelectSpecies * HISTORY: * 03.03.95 ESF Created. * PURPOSE: * NOTES: ************************************************************************/ void PLAYER_SelectSpecies(Widget w, XtPointer pData, XtPointer call_data) { const XawListReturnStruct *pItem = XawListShowCurrent(wPlayerSpeciesListbox); const Int32 iIndex = pItem->list_index; UNUSED(w); UNUSED(pData); UNUSED(call_data); /* Free up memory */ XtFree((void *)pItem); /* If it's off any of the species, then set the one that was set */ if (iIndex == -1) { PLAYER_SetSpecies(iCurrentSpecies); XawListHighlight(wPlayerSpeciesListbox, PLAYER_SpeciesToSlot(iCurrentSpecies)); return; } /* Find out what species it is */ iCurrentSpecies = PLAYER_SlotToSpecies(iIndex); /* Put in the description, author, etc. */ PLAYER_SetSpecies(iCurrentSpecies); } /************************************************************************ * FUNCTION: PLAYER_SlotToSpecies * HISTORY: * 03.03.95 ESF Created. * PURPOSE: * NOTES: ************************************************************************/ Int32 PLAYER_SlotToSpecies(Int32 iSlot) { D_Assert(iSlot>=-1, "Wierd slot!"); D_Assert(piSlotToSpecies, "No mapping!"); /* This means that the user has clicked off of any slot */ if (iSlot == -1) return iCurrentSpecies; return piSlotToSpecies[iSlot]; } /************************************************************************ * FUNCTION: PLAYER_SpeciesToSlot * HISTORY: * 03.03.95 ESF Created. * 05.13.95 ESF Fixed to not return error. * PURPOSE: * NOTES: ************************************************************************/ Int32 PLAYER_SpeciesToSlot(Int32 iSpecies) { Int32 i; for (i=0; ppstrStrings[i]!=NULL; i++) { if (piSlotToSpecies[i] == iSpecies) return i; } /* The species doesn't exist, return SPECIES_HUMAN */ iCurrentSpecies = SPECIES_HUMAN; return iCurrentSpecies; } xfrisk-1.2/addPlayer.h0100644000175000017500000000212107013357406013756 0ustar johnojohno/* * XFrisk - The classic board game for X * Copyright (C) 1993-1999 Elan Feingold (elan@aetherworks.com) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * $Id: addPlayer.h,v 1.3 1999/11/13 21:58:30 morphy Exp $ */ #ifndef _ADDPLAYER #define _ADDPLAYER #include "types.h" void PLAYER_PopupDialog(void); void PLAYER_BuildDialog(void); void PLAYER_Callback(Int32 iMessType, void *pvMess); #endif xfrisk-1.2/aiClient.h0100644000175000017500000000634607013357406013616 0ustar johnojohno/* * XFrisk - The classic board game for X * Copyright (C) 1993-1999 Elan Feingold (elan@aetherworks.com) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * $Id: aiClient.h,v 1.3 1999/11/13 21:58:30 morphy Exp $ */ #ifndef _AICLIENT #define _AICLIENT #include "types.h" /* Private stuff */ #define DefineSpecies(callback, name, author, version, desc) \ void *(*__AI_Callback)(void *, Int32, void *) = callback; \ CString __strName = name; \ CString __strAuthor = author; \ CString __strVersion = version; \ CString __strDesc = desc; /* Registering to observe the distributed object (for advanced clients * only -- actually this was only added because the client I was * porting over needed it, but it might be useful for others). * Preobservers get called before the object is changed, so that they * can see what changed. Postobservers get called after the object is * changed. */ void AI_RegisterPreObserver(void (*PreCallback)(Int32, void *)); void AI_RegisterPostObserver(void (*PostCallback)(Int32, void *)); /* Commands sent to the callback */ #define AI_INIT_ONCE 0 #define AI_INIT_GAME 1 #define AI_INIT_TURN 2 #define AI_FORTIFY 3 /* (Number of armies) */ #define AI_PLACE 4 #define AI_ATTACK 5 #define AI_MOVE 6 #define AI_EXCHANGE_CARDS 7 #define AI_SERVER_MESSAGE 8 /* (Text of the message) */ #define AI_MESSAGE 9 /* (Text of the message) */ #define AI_MOVE_MANUAL 10 /* (Number of armies) */ /* Actions computer players can perform -- PUBLIC INTERFACE */ Flag AI_Place(Int32 iCountry, Int32 iNumArmies); Flag AI_Attack(Int32 iSrcCountry, Int32 iDstCountry, Int32 iAttackMode, Int32 iDiceMode, Int32 iMoveMode); Flag AI_Move(Int32 iSrcCountry, Int32 iDstCountry, Int32 iNumArmies); Flag AI_ExchangeCards(Int32 *piCards); Flag AI_SendMessage(Int32 iMessDest, CString strMessage); Flag AI_EndTurn(void); /* Attack modes */ #define ATTACK_ONCE 0 #define ATTACK_DOORDIE 1 /* Dice modes */ #define DICE_MAXIMUM 0 #define DICE_ONE 1 #define DICE_TWO 2 #define DICE_THREE 3 /* What to do with armies after taking a country. If you wish to move * the maximum amount of armies into the country you might occupy with * the attack, pass ARMIES_MOVE_MAX. If you want the minimum number * of armies moved, pass ARMIES_MOVE_MIN. If you want finer control, * pass in ARMIES_MOVE_MANUAL, and your callback will be called with * the command AI_MOVE_MANUAL. */ #define ARMIES_MOVE_MAX 0 #define ARMIES_MOVE_MIN 1 #define ARMIES_MOVE_MANUAL 2 #endif xfrisk-1.2/aiClientMain.c0100644000175000017500000005252607020020265014403 0ustar johnojohno/* * XFrisk - The classic board game for X * Copyright (C) 1993-1999 Elan Feingold (elan@aetherworks.com) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * $Id: aiClientMain.c,v 1.8 1999/11/27 18:19:33 tony Exp $ */ #include #include #include #include #ifdef _AIX #include #endif #include #include #include #include #include #include #include #include #include "types.h" #include "utils.h" #include "client.h" #include "version.h" #include "network.h" #include "riskgame.h" #include "game.h" #include "debug.h" #include "aiClient.h" #include "aiController.h" /* Private functions */ void AI_Start(Int32 argc, CString *argv); void AI_RecoverFailure(CString strReason, Int32 iNumFailures); void AI_MainLoop(void); void AI_Replicate(Int32 iMessType, void *pvMess, Int32 iType, Int32 iSource); /* Dummies or stubs or fill-ins */ Int32 CLNT_GetCommLinkOfClient(Int32 iThisClient); /* EEEK!!! this same function(name) has been defined in callbacks.c * callbacks is included, what is going on? which one called? */ void CBK_IncomingMessage(Int32 iMessType, void *pvMess); void FatalError(CString strError, Int32 iExitValue); CString strClientName; Int32 iCommLink, iReply; Int32 iSpeciesID, iCurrentClient, iCurrentPlayer, iState; Flag fGameInitialized = FALSE; Flag fGameStarted = FALSE; extern CString __strName; extern CString __strAuthor; extern CString __strVersion; extern CString __strDesc; extern void *(*__AI_Callback)(void *, Int32, void *); void *pvContext[MAX_PLAYERS]; /* Move this to the Imakefile!! */ #ifdef __hpux #define FDSET int #else #define FDSET fd_set #endif /************************************************************************ * FUNCTION: main * HISTORY: * 02.20.95 ESF Created from clientMain.c`main * PURPOSE: * NOTES: ************************************************************************/ int main(int argc, char **argv) { Int32 i; /* Check args */ if (argc != 2) { printf("Usage: %s \n", argv[0]); exit(-1); } for (i=0; i!=MAX_PLAYERS; i++) pvContext[i] = (void *)NULL; /* Setup memory debugging library */ MEM_BootStrap("aiClient-memory.log"); /* Initialize everything */ RISK_InitObject(AI_Replicate, NULL, NULL, AI_RecoverFailure, NULL); AI_Start(argc, argv); /* Let the server know that we're ready to go as soon as it is... */ (void)RISK_SendMessage(CLNT_GetCommLinkOfClient(CLNT_GetThisClientID()), MSG_STARTGAME, NULL); iState = STATE_FORTIFY; /* And we're off */ AI_MainLoop(); return(0); } /************************************************************************ * FUNCTION: AI_Start * HISTORY: * 02.20.95 ESF Created from CLNT_Init. * PURPOSE: * NOTES: ************************************************************************/ void AI_Start(Int32 argc, CString *argv) { struct sockaddr_in server; struct hostent *hp; char strHostName[MAXHOSTNAMELEN + 1]; Int32 iMessageType, i; void *pvMessage; MsgRegisterClient msgRegisterClient; UNUSED(argc); /* * We want to ignore this signal, because we don't want a I/O * failure to terminate the program. */ signal(SIGPIPE, SIG_IGN); /* Create sockets */ if ((iCommLink = socket(AF_INET, SOCK_STREAM, 0)) < 0) #ifdef ENGLISH FatalError("Cannot create CommLink.", 1); #endif #ifdef FRENCH FatalError("CLIENT: Ne peut créer la liaison.", 1); #endif /* Connect socket using name specified by command line */ server.sin_family = AF_INET; if ((hp = gethostbyname(argv[1])) == 0) { char buf[256]; #ifdef ENGLISH snprintf(buf, sizeof(buf), "AI-CLIENT: The host `%s' is unknown.", argv[1]); #endif #ifdef FRENCH snprintf(buf, sizeof(buf), "IA-CLIENT: La machine `%s' est inconnue.", argv[1]); #endif FatalError(buf, 1); } memcpy(&server.sin_addr, hp->h_addr, hp->h_length); server.sin_port = htons(RISK_PORT); /* Send the server name information through the sockets so it can ID * the sending clients, and discover the pair of sockets that belong * to each client. The server sends back the client ID. */ gethostname(strHostName, sizeof(strHostName)); msgRegisterClient.strClientAddress = (CString)MEM_Alloc(strlen(strHostName)+32); snprintf(msgRegisterClient.strClientAddress, strlen(strHostName)+32, "%s[%lu]", strHostName, (unsigned long)getpid()); strClientName = msgRegisterClient.strClientAddress; msgRegisterClient.iClientType = CLIENT_AI; /* The Protocol: * * Connect to the server. Then do the following: * * Send MSG_HELLO. * Receive MSG_VERSION --> OK! * Other --> Protocol bogosity. * Send MSG_REGISTERCLIENT if version is correct. * Receive MSG_CLIENTIDENT --> OK! * MSG_CLIENTEXIT --> Server is full. * Other --> Protocol bogosity. * Send MSG_VERSION if version is incorrect. */ if (connect(iCommLink, (struct sockaddr *)&server, sizeof(server)) < 0) { #ifdef ENGLISH printf("AI-CLIENT: Cannot connect to a Frisk server on `%s'.\n" " One probably needs to be started by running\n" " `friskserver' on the machine.\n", argv[1]); #endif #ifdef FRENCH printf("IA-CLIENT: Impossible de se connecter au serveur Frisk sur `%s'.\n" " Quelqu'un doit commencer par lancer `friskserver' \n" " sur cette machine.\n", argv[1]); #endif FatalError(NULL, 0); } /* Send the greeting */ #ifdef ENGLISH printf("AI-CLIENT: Establishing CommLink to server.\n"); #endif #ifdef FRENCH fflush(stdout); printf("IA-CLIENT: Établissement d'une communication avec le serveur.\n"); #endif (void)RISK_SendMessage(iCommLink, MSG_HELLO, NULL); /* Get the version and check it. */ (void)RISK_ReceiveMessage(iCommLink, &iMessageType, &pvMessage); if (iMessageType != MSG_VERSION) { #ifdef ENGLISH printf("AI-CLIENT: Server is not following protocol (%d)! Exiting.\n", #endif #ifdef FRENCH printf("IA-CLIENT: Le serveur n'utilise pas le même protocol (%d)! Quit.\n", #endif iMessageType); FatalError(NULL, 0); } if (strcmp(((MsgVersion *)pvMessage)->strVersion, VERSION)) { #ifdef ENGLISH printf("AI-CLIENT: Version mismatch (server running %s)! Exiting.\n", #endif #ifdef FRENCH printf("IA-CLIENT: Mauvaise version (le server utilise %s)! Quit.\n", #endif ((MsgVersion *)pvMessage)->strVersion); FatalError(NULL, 0); } NET_DeleteMessage(iMessageType, pvMessage); /* Send back the registration message */ (void)RISK_SendMessage(iCommLink, MSG_REGISTERCLIENT, &msgRegisterClient); /* Get the species ID */ #ifdef ENGLISH printf("AI-CLIENT: Waiting for server to send species ID..."); #endif #ifdef FRENCH printf("IA-CLIENT: Attente du server pour obtenir l'ID de l'espèce..."); #endif (void)RISK_ReceiveMessage(iCommLink, &iMessageType, &pvMessage); if (iMessageType != MSG_SPECIESIDENT) { #ifdef ENGLISH printf("Server is not following protocol (%d)!", iMessageType); FatalError("Protocol error.", -1); #endif #ifdef FRENCH printf("IA-CLIENT: Le serveur n'utilise pas le même protocol (%d)!\n", iMessageType); FatalError("Erreur de protocol.", -1); #endif } else #ifdef ENGLISH printf("Done.\n"); #endif #ifdef FRENCH printf("Reçu.\n"); #endif iSpeciesID = ((MsgSpeciesIdent *)pvMessage)->iSpeciesID; NET_DeleteMessage(iMessageType, pvMessage); /* Wait for the response */ #ifdef ENGLISH printf("AI-CLIENT: Waiting for server to send client ID..."); #endif #ifdef FRENCH printf("IA-CLIENT: Attend que le serveur émette l'ID client..."); #endif (void)RISK_ReceiveMessage(iCommLink, &iMessageType, &pvMessage); if (iMessageType == MSG_EXIT) FatalError("Can't connect, server is full -- I'm impressed!", -1); else if (iMessageType == MSG_CLIENTIDENT) { #ifdef ENGLISH printf("Done.\n"); #endif #ifdef FRENCH printf("Reçu.\n"); #endif /* Set the ID of the client, and then set the sockets of the client */ iCurrentClient = ((MsgClientIdent *)pvMessage)->iClientID; } else { #ifdef ENGLISH printf("Server is not following protocol (%d)!", iMessageType); FatalError("Protocol error!", -1); #endif #ifdef FRENCH printf("IA-CLIENT: Le serveur n'utilise pas le même protocol (%d)!\n", iMessageType); FatalError("Erreur de protocol.", -1); #endif } /* Free up memory */ NET_DeleteMessage(MSG_CLIENTIDENT, pvMessage); /* Get the species ID */ i = iSpeciesID; #ifdef ENGLISH printf("AI-CLIENT: Me species #%d. You Jane.\n", i); #endif #ifdef FRENCH printf("IA-CLIENT: Mon espèce est %d.\n", i); #endif /* Init the species; afterwards, indicate the species is finished. */ RISK_SetNameOfSpecies(i, __strName); RISK_SetClientOfSpecies(i, CLNT_GetThisClientID()); RISK_SetAuthorOfSpecies(i, __strAuthor); RISK_SetVersionOfSpecies(i, __strVersion); RISK_SetDescriptionOfSpecies(i, __strDesc); RISK_SetAllocationStateOfSpecies(i, ALLOC_COMPLETE); /* Let the player do one-time initializations */ __AI_Callback(NULL, AI_INIT_ONCE, (void *)iSpeciesID); } /************************************************************************ * FUNCTION: CLNT_GetThisClientID * HISTORY: * 30.10.99 MSH Created. * PURPOSE: * Returns client ID of 'this' client * NOTES: See below ************************************************************************/ Int32 CLNT_GetThisClientID(void) { return iCurrentClient; } /************************************************************************ * FUNCTION: CLNT_GetCommLinkOfClient * HISTORY: * 02.20.95 ESF Created. * PURPOSE: * NOTES: DUMMY!! ************************************************************************/ Int32 CLNT_GetCommLinkOfClient(Int32 iThisClient) { UNUSED(iThisClient); return iCommLink; } /************************************************************************ * FUNCTION: AI_RecoverFailure * HISTORY: * 02.21.95 ESF Created. * PURPOSE: * NOTES: ************************************************************************/ void AI_RecoverFailure(CString strReason, Int32 iFailureCommlink) { #ifdef ENGLISH printf("AI-CLIENT: Fatal Error (%s) on CommLink %d. Not equipped to\n" "recover from failure yet. I'm exiting.\n", #endif #ifdef FRENCH printf("IA-CLIENT: Erreur fatale (%s) sur la ligne %d.\n" " Pas equippé pour récupérer cette erreur.\n" " Je quitte.\n", #endif strReason, iFailureCommlink); exit(-1); } /************************************************************************ * FUNCTION: FatalError * HISTORY: * 02.21.95 ESF Created. * PURPOSE: * NOTES: ************************************************************************/ void FatalError(CString strError, Int32 iExitValue) { if (strError) #ifdef ENGLISH printf("AI-CLIENT: Fatal error (%s)\n", strError); #endif #ifdef ENGLISH printf("IA-CLIENT: Erreur fatale (%s)\n", strError); #endif exit(iExitValue); } /************************************************************************ * FUNCTION: AI_MainLoop * HISTORY: * 02.21.95 ESF Created from CLNT_Init. * PURPOSE: * NOTES: ************************************************************************/ void AI_MainLoop(void) { void *pvMessage; Int32 iMessageType; fd_set fdSet, fdBackup; FD_ZERO(&fdBackup); FD_SET(CLNT_GetCommLinkOfClient(CLNT_GetThisClientID()), &fdBackup); /* Initialize everything */ AI_Init(); /* Loop forever */ for(;;) { fdSet = fdBackup; /* Wait for a message */ if (select(CLNT_GetCommLinkOfClient(CLNT_GetThisClientID())+1, (FDSET *)&fdSet, (FDSET *)0, (FDSET *)0, NULL) < 0) perror("Select"); /* Receive the message */ if (!RISK_ReceiveMessage(CLNT_GetCommLinkOfClient(CLNT_GetThisClientID()), &iMessageType, &pvMessage)) AI_RecoverFailure("Server failed.", -1); /* Process it */ CBK_IncomingMessage(iMessageType, pvMessage); } } /************************************************************************ * FUNCTION: CBK_IncomingMessage * HISTORY: * 04.30.95 ESF Created. * 25.08.95 JC Added MSG_EXIT. * 25.08.95 JC Modified MSG_ENDOFGAME, if computer is the winner and * if more than one player, then the computer decide to * continue. * 25.08.95 JC Start the game only after a fortification. * 28.08.95 JC Added MSG_ENDOFMISSION and MSG_VICTORY. * 30.08.95 JC Added MSG_FORCEEXCHANGECARDS. * 04.09.95 JC Added AI_SERVER_MESSAGE. * PURPOSE: * NOTES: ************************************************************************/ void CBK_IncomingMessage(Int32 iMessType, void *pvMessage) { switch(iMessType) { case MSG_TURNNOTIFY: { MsgTurnNotify *pvMess = (MsgTurnNotify *)pvMessage; /* Set the current player */ iCurrentPlayer = pvMess->iPlayer; if (!fGameInitialized) { fGameInitialized = TRUE; /* Let the player do initializations of game */ __AI_Callback(NULL, AI_INIT_GAME, (void *)iSpeciesID); } /* Check to see if it's this client. */ if (pvMess->iClient == CLNT_GetThisClientID()) { pvContext[iCurrentPlayer] = __AI_Callback(pvContext[iCurrentPlayer], AI_INIT_TURN, NULL); /* See if the fortification is done */ if (!fGameStarted && (iState == STATE_FORTIFY) && (RISK_GetNumArmiesOfPlayer(iCurrentPlayer) == 0)) fGameStarted = TRUE; if (fGameStarted) { if (RISK_GetNumCardsOfPlayer(iCurrentPlayer) >= 3) { pvContext[iCurrentPlayer] = __AI_Callback(pvContext[iCurrentPlayer], AI_EXCHANGE_CARDS, NULL); AI_CheckCards(); } /* Give the players the initial armies */ GAME_SetTurnArmiesOfPlayer(iCurrentPlayer); if (iState == STATE_REGISTER) return; iState = STATE_PLACE; do { /* Send the commands */ pvContext[iCurrentPlayer] = __AI_Callback(pvContext[iCurrentPlayer], AI_PLACE, NULL); if (iState == STATE_ATTACK) { AI_CheckPlacement(); pvContext[iCurrentPlayer] = __AI_Callback(pvContext[iCurrentPlayer], AI_ATTACK, NULL); } } while (iState == STATE_PLACE); if (iState == STATE_ATTACK) { iState = STATE_MOVE; pvContext[iCurrentPlayer] = __AI_Callback(pvContext[iCurrentPlayer], AI_MOVE, NULL); } } else if (iState == STATE_FORTIFY) { pvContext[iCurrentPlayer] = __AI_Callback(pvContext[iCurrentPlayer], AI_FORTIFY, (void *)1); AI_CheckFortification(); } if (iState != STATE_REGISTER) { /* End the turn */ AI_EndTurn(); } } } break; case MSG_MESSAGEPACKET: { MsgMessagePacket *msgMessagePacket = (MsgMessagePacket *)pvMessage; if (msgMessagePacket->iFrom >= FROM_SERVER) { Int32 iOldPlayer = iCurrentPlayer; if (msgMessagePacket->iTo >= 0) iCurrentPlayer = msgMessagePacket->iTo; else iCurrentPlayer = RISK_GetNthPlayerAtClient(CLNT_GetThisClientID(), 0); (void)__AI_Callback(NULL, AI_SERVER_MESSAGE, (void *)(msgMessagePacket->strMessage)); iCurrentPlayer = iOldPlayer; } else if ( (msgMessagePacket->iFrom >= 0) && (msgMessagePacket->iTo >= 0)) { Int32 iOldPlayer = iCurrentPlayer; iCurrentPlayer = msgMessagePacket->iTo; pvContext[iCurrentPlayer] = __AI_Callback(pvContext[iCurrentPlayer], AI_MESSAGE, (void *)msgMessagePacket); iCurrentPlayer = iOldPlayer; } } break; case MSG_FORCEEXCHANGECARDS: { MsgForceExchangeCards *msg = (MsgForceExchangeCards *)pvMessage; if (msg->iPlayer >= 0) { if (iState != STATE_ATTACK) return; iCurrentPlayer = msg->iPlayer; pvContext[iCurrentPlayer] = __AI_Callback(pvContext[iCurrentPlayer], AI_EXCHANGE_CARDS, NULL); AI_CheckCards(); if (iState != STATE_ATTACK) return; iState = STATE_PLACE; } } break; case MSG_ENDOFMISSION: { Int32 iWinner = ((MsgEndOfMission *)pvMessage)->iWinner; D_Assert(iWinner >= -1 && iWinner < MAX_PLAYERS, "Bogus Winner!"); if (RISK_GetClientOfPlayer(iWinner) == CLNT_GetThisClientID()) { if (RISK_GetNumLivePlayers() <= 1) { fGameStarted = FALSE; iState = STATE_REGISTER; (void)RISK_SendMessage(CLNT_GetCommLinkOfClient(CLNT_GetThisClientID()), MSG_ENDOFGAME, NULL); } } } break; case MSG_VICTORY: { Int32 iWinner = ((MsgVictory *)pvMessage)->iWinner; D_Assert(iWinner >= -1 && iWinner < MAX_PLAYERS, "Bogus Winner!"); if (RISK_GetClientOfPlayer(iWinner) == CLNT_GetThisClientID()) { fGameStarted = FALSE; iState = STATE_REGISTER; (void)RISK_SendMessage(CLNT_GetCommLinkOfClient(CLNT_GetThisClientID()), MSG_ENDOFGAME, NULL); } } break; case MSG_ENDOFGAME: { fGameStarted = FALSE; iState = STATE_FORTIFY; /* Let the server know that this client is ready to play */ (void)RISK_SendMessage(CLNT_GetCommLinkOfClient(CLNT_GetThisClientID()), MSG_STARTGAME, NULL); fGameInitialized = FALSE; AI_Init(); } case MSG_NOMESSAGE: break; case MSG_REPLYPACKET: iReply = ((MsgReplyPacket *)pvMessage)->iReply; break; case MSG_EXIT: UTIL_ExitProgram(0); break; default: ; /* Nothing... */ } } /************************************************************************ * FUNCTION: UTIL_GetArmyNumber * HISTORY: * 02.25.95 ESF Created. * 30.08.95 JC Computer can play like a human. * 31.08.95 JC if (ARMIES_MOVE_MIN == ARMIES_MOVE_MAX) -> * if (iMoveMode == ARMIES_MOVE_MIN). * PURPOSE: * NOTES: ************************************************************************/ Int32 UTIL_GetArmyNumber(Int32 iMin, Int32 iMax, Flag fLetCancel) { extern Int32 iMoveMode; UNUSED(fLetCancel); if (iMoveMode == ARMIES_MOVE_MAX) return iMax; if (iMoveMode == ARMIES_MOVE_MIN) return iMin; if (iMoveMode == ARMIES_MOVE_MANUAL) { Int32 iNumArmies = iMax-iMin; pvContext[iCurrentPlayer] = __AI_Callback(pvContext[iCurrentPlayer], AI_MOVE_MANUAL, (void *)&iNumArmies); return iNumArmies+iMin; } return (iMax-iMin)/2; } /************************************************************************ * FUNCTION: * HISTORY: * 02.25.95 ESF Created. * PURPOSE: * NOTES: ************************************************************************/ void AI_RegisterPreObserver(void (*PreCallback)(Int32, void *)) { UNUSED(PreCallback); /* A bit of a hack, for now... */ } /************************************************************************ * FUNCTION: * HISTORY: * 02.25.95 ESF Created. * PURPOSE: * NOTES: ************************************************************************/ void AI_RegisterPostObserver(void (*PostCallback)(Int32, void *)) { UNUSED(PostCallback); /* A bit of a hack, for now... */ } /************************************************************************ * FUNCTION: AI_Replicate * HISTORY: * 02.25.95 ESF Created. * PURPOSE: * NOTES: ************************************************************************/ void AI_Replicate(Int32 iMessType, void *pvMess, Int32 iType, Int32 iSource) { UNUSED(iSource); /* * Do the physical replication (the server will broadcast it), * but only if this callback is being called for an outgoing * message (i.e. a replication). Otherwise, a message just * came in. */ if (iType == MESS_OUTGOING) { (void)RISK_SendMessage(CLNT_GetCommLinkOfClient(CLNT_GetThisClientID()), iMessType, pvMess); } } xfrisk-1.2/aiColson.c0100644000175000017500000015670707011320551013624 0ustar johnojohno/*********************************************************************** * * 18-8-95 Created by Jean-Claude Colson. * * RISK game player. * $Id: aiColson.c,v 1.5 1999/11/07 15:57:29 tony Exp $ * ***********************************************************************/ #include #include #include "aiClient.h" #include "client.h" #include "debug.h" #include "types.h" #include "riskgame.h" #include "game.h" #include "utils.h" void *COLSON_Play(void *pData, Int32 iCommand, void *pArgs); #define AUTHOR "Jean-Claude COLSON" /* The species */ DefineSpecies( COLSON_Play, "Ordinateur", AUTHOR, "0.01", "Machine violente." ) /************************************************************************/ /* External data */ extern Int32 iCurrentPlayer; /************************************************************************/ static Int32 numTurn[MAX_PLAYERS]; static Int32 piContinent[MAX_PLAYERS]; static Int16 isEnemyPlayer[MAX_PLAYERS]; static Int16 levelEnemy=0; /************************************************************************ * FUNCTION: RISK_GetTotalArmiesOfPlayer * HISTORY: * 31.08.95 JC Created. * PURPOSE: * NOTES: ************************************************************************/ Int32 RISK_GetTotalArmiesOfPlayer(Int32 iPlayer) { Int32 i, nb; nb = 0; for (i=0; i= levelEnemy; } /************************************************************************ * FUNCTION: IsFriendPlayer * HISTORY: * 31.08.95 JC Created. * PURPOSE: * NOTES: ************************************************************************/ Flag IsFriendPlayer(Int32 iPlayer) { return isEnemyPlayer[iPlayer] < levelEnemy; } /************************************************************************ * FUNCTION: GetNumEnemy * HISTORY: * 01.09.95 JC Created. * PURPOSE: * NOTES: ************************************************************************/ Int32 GetNumEnemy(Int32 iPlayer) { Int32 i, nb, nbPlayers; UNUSED(iPlayer); nbPlayers = RISK_GetNumLivePlayers(); nb = 0; for (i=0; i= levelEnemy) nb++; if (levelEnemy == 1) nb--; return(nb); } /************************************************************************ * FUNCTION: IsStrongerPlayer * HISTORY: * 31.08.95 JC Created. * PURPOSE: * NOTES: ************************************************************************/ Flag IsStrongerPlayer(Int32 iPlayer) { Int32 i, nb, nbPlayers; nbPlayers = RISK_GetNumLivePlayers(); nb = RISK_GetTotalArmiesOfPlayer(iPlayer); nb = nb + nb/5; for (i=0; i nb) return FALSE; return TRUE; } /************************************************************************ * FUNCTION: IsSmallerPlayer * HISTORY: * 31.08.95 JC Created. * PURPOSE: * NOTES: ************************************************************************/ Flag IsSmallerPlayer(Int32 iPlayer) { Int32 i, nb, nbPlayers; nbPlayers = RISK_GetNumLivePlayers(); nb = 3 * RISK_GetTotalArmiesOfPlayer(iPlayer); for (i=0; i nb) return TRUE; return FALSE; } /************************************************************************ * FUNCTION: IsContinentOfPlayer * HISTORY: * 31.08.95 JC Created. * PURPOSE: * NOTES: ************************************************************************/ Flag IsContinentOfPlayer(Int32 iContinent, Int32 iPlayer) { Int32 i, nb; nb = 0; for (i=0; i 0) { if (min == 0) { if ( (piCount[i][cont] == RISK_GetNumCountriesOfContinent(cont)) && (RISK_GetValueOfContinent(cont)>bonus)) { for (j=0; j max) { for (j=0; j bonus)) { min = RISK_GetNumCountriesOfContinent(cont) - piCount[i][cont]; bonus = RISK_GetValueOfContinent(cont); maxContinent[i][cont] = TRUE; } else if (piCount[i][cont] >= RISK_GetNumCountriesOfContinent(cont)/2) { posContinent[i][j] = TRUE; } } } for (n=0; n<=MAX_PLAYERS; n++) { /* Search a continent with no conflict */ for (j=0; j piCount[j][cont])) continent = -1; } i++; } } cont++; } if (IsFriendPlayer(j) && (continent!=-1)) { for (cont=0; cont!=NUM_CONTINENTS; cont++) if (cont != continent) { maxContinent[j][cont] = FALSE; posContinent[j][cont] = FALSE; } for (i=0; i!=MAX_PLAYERS; i++) posContinent[i][continent] = FALSE; piContinent[j] = continent; } } } /* Search a continent with no computer conflict */ for (j=0; j piCount[j][cont])) continent = -1; } i++; } } cont++; } if (continent!=-1) { for (cont=0; cont!=NUM_CONTINENTS; cont++) if (cont != continent) { maxContinent[j][cont] = FALSE; posContinent[j][cont] = FALSE; } for (i=0; i!=MAX_PLAYERS; i++) posContinent[i][continent] = FALSE; piContinent[j] = continent; } } } /* Search a possible continent with no conflict */ for (j=0; j piCount[j][cont])) continent = -1; } i++; } } cont++; } if (continent!=-1) { for (cont=0; cont!=NUM_CONTINENTS; cont++) if (cont != continent) { maxContinent[j][cont] = FALSE; posContinent[j][cont] = FALSE; } for (i=0; i!=MAX_PLAYERS; i++) posContinent[i][continent] = FALSE; piContinent[j] = continent; } } } /* Search a possible continent with no computer conflict */ for (j=0; j piCount[j][cont])) continent = -1; } i++; } } cont++; } if (continent!=-1) { for (cont=0; cont!=NUM_CONTINENTS; cont++) if (cont != continent) { maxContinent[j][cont] = FALSE; posContinent[j][cont] = FALSE; } for (i=0; i!=MAX_PLAYERS; i++) posContinent[i][continent] = FALSE; piContinent[j] = continent; } } } } for (j=0; j0) { continent = cont; i = 0; while (i= levelEnemy) nb++; } return nb; } /************************************************************************ * FUNCTION: GetContinentToConquier * HISTORY: * 21.07.95 JC Created. * PURPOSE: * NOTES: ************************************************************************/ Int32 GetContinentToConquier(Int32 iPlayer, Int32 *attack) { Int32 piCount[NUM_CONTINENTS]; Int32 piOppo[NUM_CONTINENTS]; Int32 piAttac[NUM_CONTINENTS]; Int32 i, min, max, bonus, continent; /* Init. */ for (i=0; i!=NUM_CONTINENTS; i++) { piCount[i] = 0; piOppo[i] = 0; piAttac[i] = 0; } /* Count up how many countries the player has in each of the continents */ for (i=0; i!=NUM_COUNTRIES; i++) { if (RISK_GetOwnerOfCountry(i) == iPlayer) { piCount[RISK_GetContinentOfCountry(i)]++; piOppo[RISK_GetContinentOfCountry(i)] -= RISK_GetNumArmiesOfCountry (i); if (GAME_IsEnemyAdjacent(i)) piAttac[RISK_GetContinentOfCountry(i)]++; } else { if (IsEnemyPlayer(RISK_GetOwnerOfCountry(i))) piOppo[RISK_GetContinentOfCountry(i)] += RISK_GetNumArmiesOfCountry (i); else piOppo[RISK_GetContinentOfCountry(i)] += 2 * RISK_GetNumArmiesOfCountry (i); } } continent = -1; min = 10000; max = 0; bonus = 0; for (i=0; i!=NUM_CONTINENTS; i++) { if (IsContinentOfMission(iPlayer, i)) piOppo[i] -= piOppo[i]/3; if (piCount[i] < RISK_GetNumCountriesOfContinent(i)) if (piOppo[i] < min) { continent = i; min = piOppo[i]; max = piCount[i]; bonus = RISK_GetValueOfContinent(i); } } *attack = piAttac[continent]; return(continent); } /************************************************************************ * FUNCTION: NbEnenyAdjacent * HISTORY: * 28.08.95 JC Created. * PURPOSE: * NOTES: ************************************************************************/ Int32 NbEnenyAdjacent(Int32 iCountry) { Int32 i, iPlayer, max, nb, destCountry, iEnemy; Int32 NumEnemy[MAX_PLAYERS]; Flag fIsEnemy[MAX_PLAYERS]; Flag fIAmStrong; iPlayer = RISK_GetOwnerOfCountry(iCountry); fIAmStrong = IsStrongerPlayer(iPlayer); for (i=0; i max) max = nb; } } return max; } /************************************************************************ * FUNCTION: NbToEqualEnenyAdjacent * HISTORY: * 07.09.95 JC Created. * PURPOSE: * NOTES: ************************************************************************/ Int32 NbToEqualEnenyAdjacent(Int32 iCountry) { Int32 i, iPlayer, nb, nbe, nbi, destCountry, iEnemy; iPlayer = RISK_GetOwnerOfCountry(iCountry); nbe = 0; nb = 0; i = 0; while ((i < 6) && (RISK_GetAdjCountryOfCountry(iCountry, i) != -1)) { destCountry = RISK_GetAdjCountryOfCountry(iCountry, i); iEnemy = RISK_GetOwnerOfCountry(destCountry); if (iEnemy != iPlayer) { nbe -= RISK_GetNumArmiesOfCountry(destCountry); nb++; } i++; } nbi = RISK_GetNumArmiesOfCountry(iCountry); nbe = (nbe + nbi)/nb; if ((nbi - nbe)< 10) nbe = nbi - 10; return nbe; } /************************************************************************/ static Int32 Attack_SrcCountry = -1; static Int32 Attack_DestCountry = -1; /************************************************************************ * FUNCTION: ComputerAttack * HISTORY: * 09.08.95 JC Created. * PURPOSE: * NOTES: ************************************************************************/ Flag ComputerAttack(Int32 iPlayer, Int32 destCountry, Flag die, Int32 dif, Int32 iMove) { Int32 srcCountry, iCountry, i, nb, max; srcCountry = -1; max = RISK_GetNumArmiesOfCountry(destCountry) + dif; nb = 0; i = 0; while ((i < 6) && (RISK_GetAdjCountryOfCountry(destCountry, i) != -1)) { iCountry = RISK_GetAdjCountryOfCountry(destCountry, i); if (RISK_GetOwnerOfCountry(iCountry) == iPlayer) { if (RISK_GetNumArmiesOfCountry(iCountry) > max) { max = RISK_GetNumArmiesOfCountry(iCountry); srcCountry = iCountry; } nb = nb + RISK_GetNumArmiesOfCountry(iCountry); } i++; } if (srcCountry == -1) return FALSE; nb = nb - RISK_GetNumArmiesOfCountry(srcCountry); do { Attack_SrcCountry = srcCountry; Attack_DestCountry = destCountry; AI_Attack (srcCountry, destCountry, ATTACK_DOORDIE, DICE_MAXIMUM, iMove); } while ( (RISK_GetOwnerOfCountry(destCountry) != iPlayer) && (RISK_GetNumArmiesOfCountry(srcCountry) > 1) && (die || ( RISK_GetNumArmiesOfCountry(srcCountry) > RISK_GetNumArmiesOfCountry(destCountry)))); if (RISK_GetOwnerOfCountry(destCountry) == iPlayer) return (TRUE); nb = nb + RISK_GetNumArmiesOfCountry(srcCountry); if (!die && (nb <= (RISK_GetNumArmiesOfCountry(destCountry) + 20))) return FALSE; i = 0; while ((i < 6) && (RISK_GetAdjCountryOfCountry(destCountry, i) != -1)) { iCountry = RISK_GetAdjCountryOfCountry(destCountry, i); if ( (RISK_GetOwnerOfCountry(iCountry) == iPlayer) && (RISK_GetNumArmiesOfCountry(iCountry) > 1)) { do { Attack_SrcCountry = iCountry; Attack_DestCountry = destCountry; AI_Attack (iCountry, destCountry, ATTACK_DOORDIE, DICE_MAXIMUM, iMove); } while ( (RISK_GetOwnerOfCountry(destCountry) != iPlayer) && (RISK_GetNumArmiesOfCountry(iCountry) > 1) && (die || ( RISK_GetNumArmiesOfCountry(iCountry) > RISK_GetNumArmiesOfCountry(destCountry)))); if (RISK_GetOwnerOfCountry(destCountry) == iPlayer) return (TRUE); } i++; } return (FALSE); } /************************************************************************ * FUNCTION: Fortify * HISTORY: * 21.07.95 JC Created. * PURPOSE: * NOTES: ************************************************************************/ void Fortify(Int32 iPlayer) { Int32 iContinent, iCountry, nb; Flag boool; iContinent = GetContinentToFortify(iPlayer, &nb); boool = FALSE; iCountry = 0; if (nb > 0) { nb = rand() % nb; while (!boool && (iCountry < NUM_COUNTRIES)) { if ((RISK_GetOwnerOfCountry(iCountry) == iPlayer) && (RISK_GetContinentOfCountry(iCountry) == iContinent) && GAME_IsEnemyAdjacent(iCountry)) { if (nb <= 0) { AI_Place (iCountry, 1); boool = TRUE; } nb--; } if (!boool) iCountry++; } } iCountry = 0; while (!boool && (iCountry < NUM_COUNTRIES)) { if ( (RISK_GetOwnerOfCountry(iCountry) == iPlayer) && GAME_IsEnemyAdjacent(iCountry)) { AI_Place (iCountry, 1); boool = TRUE; } else iCountry++; } iCountry = 0; while (!boool && (iCountry < NUM_COUNTRIES)) { if (RISK_GetOwnerOfCountry(iCountry) == iPlayer) { AI_Place (iCountry, 1); boool = TRUE; } else iCountry++; } } /************************************************************************ * FUNCTION: Place * HISTORY: * 21.07.95 JC Created. * PURPOSE: * NOTES: ************************************************************************/ void Place(Int32 iPlayer) { Int32 iContinent, iCountry, iEnemy; Int32 destCountry, i, j, nb, min; Flag boool; iContinent = GetContinentToFortify(iPlayer, &nb); boool = FALSE; /* Try to destroy a enemy player */ iCountry = 0; while ( !boool && (iCountry < NUM_COUNTRIES)) { if ((RISK_GetOwnerOfCountry(iCountry) == iPlayer) && GAME_IsEnemyAdjacent(iCountry)) { i = 0; while (!boool && (i < 6) && (RISK_GetAdjCountryOfCountry(iCountry, i) != -1)) { destCountry = RISK_GetAdjCountryOfCountry(iCountry, i); iEnemy = RISK_GetOwnerOfCountry(destCountry); if ( (iEnemy != iPlayer) && IsEnemyPlayer(iEnemy) && (RISK_GetTotalArmiesOfPlayer(iEnemy) < ( RISK_GetNumArmiesOfPlayer(iPlayer) + RISK_GetNumArmiesOfCountry(iCountry) - 5))) { AI_Place (iCountry, RISK_GetNumArmiesOfPlayer(iPlayer)); boool = TRUE; } else i++; } } if (!boool) iCountry++; } /* Try to conquier an entire continent, attack enemy */ destCountry = 0; while ( !boool && (destCountry < NUM_COUNTRIES)) { iEnemy = RISK_GetOwnerOfCountry(destCountry); if ( (iEnemy != iPlayer) && IsEnemyPlayer(iEnemy) && (RISK_GetContinentOfCountry(destCountry) == iContinent)) { i = 0; while (!boool && (i < 6) && (RISK_GetAdjCountryOfCountry(destCountry, i) != -1)) { j = RISK_GetAdjCountryOfCountry(destCountry, i); if (RISK_GetOwnerOfCountry(j) == iPlayer) { iCountry = j; boool = TRUE; } i++; } if (boool) AI_Place (iCountry, RISK_GetNumArmiesOfPlayer(iPlayer)); } destCountry++; } /* Try to destroy a player */ iCountry = 0; while ( !boool && (iCountry < NUM_COUNTRIES)) { if ((RISK_GetOwnerOfCountry(iCountry) == iPlayer) && GAME_IsEnemyAdjacent(iCountry)) { i = 0; while (!boool && (i < 6) && (RISK_GetAdjCountryOfCountry(iCountry, i) != -1)) { destCountry = RISK_GetAdjCountryOfCountry(iCountry, i); iEnemy = RISK_GetOwnerOfCountry(destCountry); if ( (iEnemy != iPlayer) && (RISK_GetTotalArmiesOfPlayer(RISK_GetOwnerOfCountry(destCountry)) < ( RISK_GetNumArmiesOfPlayer(iPlayer) + RISK_GetNumArmiesOfCountry(iCountry) - 5))) { AI_Place (iCountry, RISK_GetNumArmiesOfPlayer(iPlayer)); boool = TRUE; } else i++; } } if (!boool) iCountry++; } /* Try to conquier an entire continent */ destCountry = 0; while ( !boool && (destCountry < NUM_COUNTRIES)) { iEnemy = RISK_GetOwnerOfCountry(destCountry); if ( (RISK_GetContinentOfCountry(destCountry) == iContinent) && (iEnemy != iPlayer)) { i = 0; while (!boool && (i < 6) && (RISK_GetAdjCountryOfCountry(destCountry, i) != -1)) { j = RISK_GetAdjCountryOfCountry(destCountry, i); if (RISK_GetOwnerOfCountry(j) == iPlayer) { iCountry = j; boool = TRUE; } i++; } if (boool) AI_Place (iCountry, RISK_GetNumArmiesOfPlayer(iPlayer)); } destCountry++; } /* Try to defend an entire continent */ if (!boool && (nb > 0)) { boool = TRUE; while (boool && (RISK_GetNumArmiesOfPlayer(iPlayer) > 0)) { iCountry = 0; min = 0; boool = FALSE; while (iCountry < NUM_COUNTRIES) { if ( (RISK_GetOwnerOfCountry(iCountry) == iPlayer) && (RISK_GetContinentOfCountry(iCountry) == iContinent) && GAME_IsEnemyAdjacent(iCountry)) { nb = NbToEqualEnenyAdjacent(iCountry); if (nb < min) { min = nb ; destCountry = iCountry; boool = TRUE; } } iCountry++; } if (boool) AI_Place (destCountry, 1); } boool = (RISK_GetNumArmiesOfPlayer(iPlayer) <= 0); } iContinent = GetContinentToConquier(iPlayer, &nb); /* Try to conquier an entire continent, attack enemy */ iCountry = 0; while ( !boool && (iCountry < NUM_COUNTRIES)) { if ((RISK_GetOwnerOfCountry(iCountry) == iPlayer) && (RISK_GetContinentOfCountry(iCountry) == iContinent) && GAME_IsEnemyAdjacent(iCountry)) { i = 0; while (!boool && (i < 6) && (RISK_GetAdjCountryOfCountry(iCountry, i) != -1)) { destCountry = RISK_GetAdjCountryOfCountry(iCountry, i); iEnemy = RISK_GetOwnerOfCountry(destCountry); if ( (iEnemy != iPlayer) && IsEnemyPlayer(iEnemy) && (RISK_GetContinentOfCountry(destCountry) == iContinent)) { AI_Place (iCountry, RISK_GetNumArmiesOfPlayer(iPlayer)); boool = TRUE; } else i++; } } if (!boool) iCountry++; } /* Try to conquier an entire continent */ iCountry = 0; while ( !boool && (iCountry < NUM_COUNTRIES)) { if ((RISK_GetOwnerOfCountry(iCountry) == iPlayer) && (RISK_GetContinentOfCountry(iCountry) == iContinent) && GAME_IsEnemyAdjacent(iCountry)) { i = 0; while (!boool && (i < 6) && (RISK_GetAdjCountryOfCountry(iCountry, i) != -1)) { destCountry = RISK_GetAdjCountryOfCountry(iCountry, i); iEnemy = RISK_GetOwnerOfCountry(destCountry); if ( (iEnemy != iPlayer) && (RISK_GetContinentOfCountry(destCountry) == iContinent)) { AI_Place (iCountry, RISK_GetNumArmiesOfPlayer(iPlayer)); boool = TRUE; } else i++; } } if (!boool) iCountry++; } /* Try to defend an entire continent */ if (!boool && (nb > 0)) { iCountry = 0; min = 1000; boool = FALSE; while (iCountry < NUM_COUNTRIES) { if ( (RISK_GetOwnerOfCountry(iCountry) == iPlayer) && (RISK_GetContinentOfCountry(iCountry) == iContinent) && GAME_IsEnemyAdjacent(iCountry)) { nb = NbToEqualEnenyAdjacent(iCountry); if (nb < min) { min = RISK_GetNumArmiesOfCountry(iCountry); destCountry = iCountry; boool = TRUE; } } iCountry++; } if (boool) AI_Place (destCountry, RISK_GetNumArmiesOfPlayer(iPlayer)); } /* Try to prepare an enemy attack, find a lowest defence */ if (!boool) { iCountry = 0; while (!boool && (iCountry < NUM_COUNTRIES)) { if ( (RISK_GetOwnerOfCountry(iCountry) == iPlayer) && GAME_IsEnemyAdjacent(iCountry)) { boool = FALSE; i = 0; while (!boool && (i < 6) && (RISK_GetAdjCountryOfCountry(iCountry, i) != -1)) { destCountry = RISK_GetAdjCountryOfCountry(iCountry, i); iEnemy = RISK_GetOwnerOfCountry(destCountry); if ( (RISK_GetContinentOfCountry(destCountry) == iContinent) && (iEnemy != iPlayer) && IsEnemyPlayer(iEnemy) && ( ( RISK_GetNumArmiesOfCountry(iCountry) > RISK_GetNumArmiesOfCountry(destCountry)+3) || (RISK_GetNumArmiesOfCountry(destCountry)==1))) boool = TRUE; if (!boool) i++; } if (boool) AI_Place (iCountry, RISK_GetNumArmiesOfPlayer(iPlayer)); } if (!boool) iCountry++; } } /* Try to prepare an enemy attack */ if (!boool) { iCountry = 0; while (!boool && (iCountry < NUM_COUNTRIES)) { if ( (RISK_GetOwnerOfCountry(iCountry) == iPlayer) && GAME_IsEnemyAdjacent(iCountry)) { boool = FALSE; i = 0; while (!boool && (i < 6) && (RISK_GetAdjCountryOfCountry(iCountry, i) != -1)) { destCountry = RISK_GetAdjCountryOfCountry(iCountry, i); iEnemy = RISK_GetOwnerOfCountry(destCountry); if ((iEnemy != iPlayer) && IsEnemyPlayer(iEnemy)) boool = TRUE; if (!boool) i++; } if (boool) AI_Place (iCountry, RISK_GetNumArmiesOfPlayer(iPlayer)); } if (!boool) iCountry++; } } /* Try to prepare an attack */ if (!boool) { iCountry = 0; while (!boool && (iCountry < NUM_COUNTRIES)) { if ( (RISK_GetOwnerOfCountry(iCountry) == iPlayer) && GAME_IsEnemyAdjacent(iCountry)) { AI_Place (iCountry, RISK_GetNumArmiesOfPlayer(iPlayer)); boool = TRUE; } else iCountry++; } } /* Try to place */ if (!boool) { iCountry = 0; while ( !boool && (iCountry < NUM_COUNTRIES)) { if (RISK_GetOwnerOfCountry(iCountry) == iPlayer) { AI_Place (iCountry, RISK_GetNumArmiesOfPlayer(iPlayer)); boool = TRUE; } else iCountry++; } } } /************************************************************************ * FUNCTION: AttacEnemy * HISTORY: * 01.09.95 JC Created from Attack. * PURPOSE: * NOTES: ************************************************************************/ void AttacEnemy(Int32 iPlayer) { Int32 iContinent, destCountry, iEnemy, nb; iContinent = GetContinentToFortify(iPlayer, &nb); /* Try to conquier an entire continent, attack player of other species */ destCountry = 0; while (destCountry < NUM_COUNTRIES) { iEnemy = RISK_GetOwnerOfCountry(destCountry); if ( (RISK_GetContinentOfCountry(destCountry) == iContinent) && (iEnemy != iPlayer) && IsEnemyPlayer(iEnemy)) { if (ComputerAttack (iPlayer, destCountry, TRUE, (RISK_GetNumArmiesOfCountry(destCountry) < 5)?1: ((nb > 4)?RISK_GetNumArmiesOfCountry(destCountry):3), ARMIES_MOVE_MANUAL)) { destCountry = 0; nb++; } else destCountry++; } else destCountry++; } /* Try to conquier an entire continent */ destCountry = 0; while (destCountry < NUM_COUNTRIES) { if ( (RISK_GetContinentOfCountry(destCountry) == iContinent) && (RISK_GetOwnerOfCountry(destCountry) != iPlayer)) { if (ComputerAttack (iPlayer, destCountry, TRUE, (RISK_GetNumArmiesOfCountry(destCountry) < 3)?1:50, ARMIES_MOVE_MANUAL)) { destCountry = 0; nb++; } else destCountry++; } else destCountry++; } if ( !IsContinentOfPlayer(iContinent, iPlayer) && (numTurn[iPlayer] <= 2) && (RISK_GetNumLivePlayers() > NUM_CONTINENTS/2)) return; iContinent = GetContinentToConquier(iPlayer, &nb); nb = 0; /* Try to destroy a human player */ destCountry = 0; while (destCountry < NUM_COUNTRIES) { if ( (RISK_GetOwnerOfCountry(destCountry) != iPlayer) && (RISK_GetSpeciesOfPlayer(RISK_GetOwnerOfCountry(destCountry)) == SPECIES_HUMAN) && (RISK_GetNumCountriesOfPlayer(RISK_GetOwnerOfCountry(destCountry)) == 1)) if (ComputerAttack (iPlayer, destCountry, TRUE, (nb > 2)?10:2, ARMIES_MOVE_MANUAL)) nb++; destCountry++; } /* Try to destroy a enemy player */ destCountry = 0; while (destCountry < NUM_COUNTRIES) { if ( IsEnemyPlayer(RISK_GetOwnerOfCountry(destCountry)) && (RISK_GetNumCountriesOfPlayer(RISK_GetOwnerOfCountry(destCountry)) == 1)) if (ComputerAttack (iPlayer, destCountry, TRUE, (nb > 2)?20:2, ARMIES_MOVE_MANUAL)) nb++; destCountry++; } /* Try to destroy a player */ destCountry = 0; while (destCountry < NUM_COUNTRIES) { if ( (RISK_GetOwnerOfCountry(destCountry) != iPlayer) && (RISK_GetNumCountriesOfPlayer(RISK_GetOwnerOfCountry(destCountry)) == 1)) if (ComputerAttack (iPlayer, destCountry, TRUE, (nb > 2)?20:2, ARMIES_MOVE_MANUAL)) nb++; destCountry++; } /* Try to conquier an entire continent, attack player of other species */ destCountry = 0; while (destCountry < NUM_COUNTRIES) { if ( (RISK_GetContinentOfCountry(destCountry) == iContinent) && (RISK_GetOwnerOfCountry(destCountry) != iPlayer) && IsEnemyPlayer(RISK_GetOwnerOfCountry(destCountry))) { if (ComputerAttack (iPlayer, destCountry, TRUE, (RISK_GetNumArmiesOfCountry(destCountry) < 5)?1: ((nb > 4)?RISK_GetNumArmiesOfCountry(destCountry):3), ARMIES_MOVE_MANUAL)) { destCountry = 0; nb++; } else destCountry++; } else destCountry++; } /* Try to conquier an entire continent */ destCountry = 0; while (destCountry < NUM_COUNTRIES) { if ( (RISK_GetContinentOfCountry(destCountry) == iContinent) && (RISK_GetOwnerOfCountry(destCountry) != iPlayer)) { if (ComputerAttack (iPlayer, destCountry, TRUE, (RISK_GetNumArmiesOfCountry(destCountry) < 3)?1:50, ARMIES_MOVE_MANUAL)) { destCountry = 0; nb++; } else destCountry++; } else destCountry++; } /* Try to attack a stronger human player for a card */ destCountry = 0; while (destCountry < NUM_COUNTRIES) { iEnemy = RISK_GetOwnerOfCountry(destCountry); if ( (iEnemy != iPlayer) && IsEnemyPlayer(iEnemy) && (RISK_GetSpeciesOfPlayer(iEnemy) == SPECIES_HUMAN) && IsStrongerPlayer(RISK_GetOwnerOfCountry(destCountry))) if (ComputerAttack (iPlayer, destCountry, FALSE, (RISK_GetNumArmiesOfCountry(destCountry) < 3)?1:((nb > 2)?10:2), ARMIES_MOVE_MANUAL)) nb++; destCountry++; } /* Try to attack an human player for a card */ destCountry = 0; while (destCountry < NUM_COUNTRIES) { iEnemy = RISK_GetOwnerOfCountry(destCountry); if ( (iEnemy != iPlayer) && IsEnemyPlayer(iEnemy) && (RISK_GetSpeciesOfPlayer(iEnemy) == SPECIES_HUMAN)) if (ComputerAttack (iPlayer, destCountry, FALSE, (RISK_GetNumArmiesOfCountry(destCountry) < 3)?1:((nb > 2)?10:2), ARMIES_MOVE_MANUAL)) nb++; destCountry++; } /* Try to attack enemy player for a card */ destCountry = 0; while (destCountry < NUM_COUNTRIES) { iEnemy = RISK_GetOwnerOfCountry(destCountry); if ( (iEnemy != iPlayer) && IsEnemyPlayer(iEnemy)) if (ComputerAttack (iPlayer, destCountry, FALSE, (RISK_GetNumArmiesOfCountry(destCountry) < 3)?1:((nb > 2)?10:2), ARMIES_MOVE_MANUAL)) nb++; destCountry++; } /* Try to attack for a card, attack a stronger player */ destCountry = 0; while ((nb < 1) && (destCountry < NUM_COUNTRIES)) { iEnemy = RISK_GetOwnerOfCountry(destCountry); if ( (iEnemy != iPlayer) && IsStrongerPlayer(iEnemy)) if (ComputerAttack (iPlayer, destCountry, FALSE, (RISK_GetNumArmiesOfCountry(destCountry) < 2)?1:100, ARMIES_MOVE_MANUAL)) nb++; destCountry++; } /* Try to attack for a card */ destCountry = 0; while ((nb < 1) && (destCountry < NUM_COUNTRIES)) { if (RISK_GetOwnerOfCountry(destCountry) != iPlayer) if (ComputerAttack (iPlayer, destCountry, FALSE, (RISK_GetNumArmiesOfCountry(destCountry) < 2)?1:100, ARMIES_MOVE_MIN)) nb++; destCountry++; } } /************************************************************************ * FUNCTION: Attack * HISTORY: * 21.07.95 JC Created. * PURPOSE: * NOTES: ************************************************************************/ void Attack(Int32 iPlayer) { Int32 enemyAlive; if (RISK_GetAttackModeOfPlayer (iPlayer) != ACTION_DOORDIE) RISK_SetAttackModeOfPlayer (iPlayer, ACTION_DOORDIE); if (RISK_GetDiceModeOfPlayer (iPlayer) != ATTACK_AUTO) RISK_SetDiceModeOfPlayer (iPlayer, ATTACK_AUTO); enemyAlive = GetNumEnemy(iPlayer); while ((enemyAlive == 0) && (levelEnemy >0)) { levelEnemy--; enemyAlive = GetNumEnemy(iPlayer); } AttacEnemy(iPlayer); } /************************************************************************ * FUNCTION: HowManyArmiesToMove * HISTORY: * 23.08.95 JC Created. * 30.08.95 JC Place the number of armies to move in nb. * PURPOSE: * NOTES: ************************************************************************/ void HowManyArmiesToMove(Int32 iPlayer, Int32 *nb) { UNUSED(iPlayer); if ((Attack_SrcCountry == -1) || (Attack_DestCountry == -1)) return; if (!GAME_IsEnemyAdjacent(Attack_SrcCountry)) *nb = 0; else if (!GAME_IsEnemyAdjacent(Attack_DestCountry)) *nb = *nb; else *nb = *nb/2; Attack_SrcCountry = -1; Attack_DestCountry = -1; } /************************************************************************ * FUNCTION: Move * HISTORY: * 21.07.95 JC Created. * PURPOSE: * NOTES: ************************************************************************/ void Move(Int32 iPlayer) { Int32 iCountry, destCountry, i, max; Flag boool; /* Try to move an unused max army in a frontier */ boool = FALSE; i = 0; max = 1; while (i < NUM_COUNTRIES) { if ( (RISK_GetOwnerOfCountry(i) == iPlayer) && (RISK_GetNumArmiesOfCountry(i) > max) && !GAME_IsEnemyAdjacent(i)) { max = RISK_GetNumArmiesOfCountry(i); iCountry = i; boool = TRUE; } i++; } if (boool) { destCountry = GAME_FindEnemyAdjacent(iCountry); if (destCountry >= 0) AI_Move (iCountry, destCountry, RISK_GetNumArmiesOfCountry(iCountry)-1); else boool = FALSE; } /* Try to move an unused army in a country witch have a frontier */ iCountry = 0; while (!boool && (iCountry < NUM_COUNTRIES)) { if ( (RISK_GetOwnerOfCountry(iCountry) == iPlayer) && (RISK_GetNumArmiesOfCountry(iCountry) > 2) && !GAME_IsEnemyAdjacent(iCountry)) { destCountry = GAME_FindEnemyAdjacent(iCountry); if (destCountry >= 0) { AI_Move (iCountry, destCountry, RISK_GetNumArmiesOfCountry(iCountry)-1); boool = TRUE; } } iCountry++; } iCountry = 0; while (!boool && (iCountry < NUM_COUNTRIES)) { if ( (RISK_GetOwnerOfCountry(iCountry) == iPlayer) && (RISK_GetNumArmiesOfCountry(iCountry) > 2) && !GAME_IsEnemyAdjacent(iCountry)) { i = 0; while (!boool && (i < 6) && (RISK_GetAdjCountryOfCountry(iCountry, i) != -1)) { destCountry = RISK_GetAdjCountryOfCountry(iCountry, i); if (RISK_GetNumArmiesOfCountry(destCountry) == 1) { AI_Move (iCountry, destCountry, RISK_GetNumArmiesOfCountry(iCountry)/2); boool = TRUE; } if (!boool) i++; } } iCountry++; } } /************************************************************************ * FUNCTION: ExchangeCards * HISTORY: * 18.08.95 JC Created. * PURPOSE: * NOTES: ************************************************************************/ void ExchangeCards(Int32 iPlayer) { Int32 i, j, nb, typ, piCards[4], nbCards[4], piCardValues[MAX_CARDS]; Flag fOptimal, fStronger, fSmaller; fStronger = IsStrongerPlayer(iPlayer); fSmaller = IsSmallerPlayer(iPlayer); nb = RISK_GetNumCardsOfPlayer(iPlayer); do { piCards[0]=piCards[1]=piCards[2]=piCards[3]=-1; nbCards[0]=nbCards[1]=nbCards[2]=nbCards[3]=0; fOptimal = FALSE; for (i=0; i0)&&(nbCards[1]>0)&&(nbCards[2]>0)) { AI_ExchangeCards(piCards); fOptimal = TRUE; } else if ((nbCards[3]>=2)&&((nbCards[0]>0)||(nbCards[1]>0)||(nbCards[2]>0))) { if (nbCards[2]>1) { piCards[1] = piCards[3]; j = 0; } else if (nbCards[1]>1) { piCards[0] = piCards[3]; j = 2; } else if (nbCards[0]>1) { piCards[2] = piCards[3]; j = 1; } else if (nbCards[2]>0) { piCards[1] = piCards[3]; j = 0; } else if (nbCards[1]>0) { piCards[0] = piCards[3]; j = 2; } else { piCards[2] = piCards[3]; j = 1; } i = 0; while (i= NUM_COUNTRIES) { piCards[j]=i; i = nb; } else i++; } AI_ExchangeCards(piCards); fOptimal = TRUE; } else if (!fStronger && (nbCards[0]>=3)) { j = 0; for (i=0; i=3)) { j = 0; for (i=0; i=3)) { j = 0; for (i=0; i= 5) { if ((nbCards[0]>0)&&(nbCards[1]>0)&&(nbCards[3]>0)) piCards[2] = piCards[3]; else if ((nbCards[0]>0)&&(nbCards[3]>0)&&(nbCards[2]>0)) piCards[1] = piCards[3]; else if ((nbCards[3]>0)&&(nbCards[1]>0)&&(nbCards[2]>0)) piCards[0] = piCards[3]; else if (nbCards[0]>=3) { j = 0; for (i=0; i=3) { j = 0; for (i=0; i=3) { j = 0; for (i=0; i= 3)) || (nb >= 5)); } /************************************************************************ * FUNCTION: COLSON_Play * HISTORY: * 21.07.95 JC Created. * PURPOSE: * NOTES: ************************************************************************/ void *COLSON_Play(void *pData, Int32 iCommand, void *pArgs) { switch(iCommand) { case AI_INIT_ONCE: { /* InitClient((Int32)pArgs); */ } break; case AI_INIT_GAME: { InitGame((Int32)pArgs); } break; case AI_INIT_TURN: { numTurn[iCurrentPlayer]++; } break; case AI_FORTIFY: { Fortify(iCurrentPlayer); } break; case AI_PLACE: { Place(iCurrentPlayer); } break; case AI_ATTACK: { Attack(iCurrentPlayer); } break; case AI_MOVE_MANUAL: { HowManyArmiesToMove(iCurrentPlayer, (Int32 *)pArgs); } break; case AI_MOVE: { Move(iCurrentPlayer); } break; case AI_EXCHANGE_CARDS: { ExchangeCards(iCurrentPlayer); } break; case AI_SERVER_MESSAGE: { } break; case AI_MESSAGE: { MsgMessagePacket *msgMessagePacket = (MsgMessagePacket *)pArgs; Char strScratch[256]; if (strstr(msgMessagePacket->strMessage, "pacte") != NULL) { snprintf(strScratch, sizeof(strScratch), "%s a tenté de faire un pacte avec moi.", RISK_GetNameOfPlayer(msgMessagePacket->iFrom)); AI_SendMessage(DST_ALLPLAYERS, strScratch); } else AI_SendMessage(msgMessagePacket->iFrom, "Je ne répond pas"); } break; } return pData; } xfrisk-1.2/aiController.c0100644000175000017500000003037607013357406014516 0ustar johnojohno/* * XFrisk - The classic board game for X * Copyright (C) 1993-1999 Elan Feingold (elan@aetherworks.com) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * $Id: aiController.c,v 1.4 1999/11/13 21:58:30 morphy Exp $ */ #include "aiController.h" #include "aiClient.h" #include "client.h" #include "riskgame.h" #include "game.h" #include "debug.h" /* Prototypes */ Int32 CLNT_GetCommLinkOfClient(Int32 iThisClient); /* Externs */ extern void *(*__AI_Callback)(void *, Int32, void *); extern void *pvContext[MAX_PLAYERS]; extern Int32 iState, iCurrentPlayer; extern Flag fGameStarted; /* Globals */ Flag fPlayerFortified; /************************************************************************ * FUNCTION: AI_Init * HISTORY: * 04.23.95 ESF Created. * PURPOSE: * NOTES: ************************************************************************/ void AI_Init(void) { fPlayerFortified=FALSE; fGameStarted = FALSE; fGetsCard=FALSE; } /************************************************************************ * FUNCTION: AI_CheckCards * HISTORY: * 03.31.95 ESF Created. * 28.08.95 JC If the computerized must exchange cards then do. (copy of ExchangeCards) * PURPOSE: * NOTES: ************************************************************************/ void AI_CheckCards(void) { Int32 i, j, nb, typ, piCards[4], nbCards[4], piCardValues[MAX_CARDS]; Flag fOptimal; if (RISK_GetNumCardsOfPlayer (iCurrentPlayer) <= 4) return; #ifdef ENGLISH printf("AI: Error -- Checking cards.\n"); #endif #ifdef FRENCH printf("IA: Erreur -- Vérification des cartes.\n"); #endif nb = RISK_GetNumCardsOfPlayer(iCurrentPlayer); do { piCards[0]=piCards[1]=piCards[2]=piCards[3]=-1; nbCards[0]=nbCards[1]=nbCards[2]=nbCards[3]=0; fOptimal = FALSE; for (i=0; i0)&&(nbCards[1]>0)&&(nbCards[2]>0)) { AI_ExchangeCards(piCards); fOptimal = TRUE; } else if (nb >= 5) { if ((nbCards[0]>0)&&(nbCards[1]>0)&&(nbCards[3]>0)) piCards[2] = piCards[3]; else if ((nbCards[0]>0)&&(nbCards[3]>0)&&(nbCards[2]>0)) piCards[1] = piCards[3]; else if ((nbCards[3]>0)&&(nbCards[1]>0)&&(nbCards[2]>0)) piCards[0] = piCards[3]; else if (nbCards[0]>=3) { j = 0; for (i=0; i=3) { j = 0; for (i=0; i=3) { j = 0; for (i=0; i= 3)) || (nb >= 5)); } /************************************************************************ * FUNCTION: AI_CheckFortification * HISTORY: * 03.31.95 ESF Created. * PURPOSE: * NOTES: ************************************************************************/ void AI_CheckFortification(void) { /* If the player hasn't fortified yet, do it */ if (!fPlayerFortified) { Int32 i; #ifdef ENGLISH printf("AI: Error -- Checking fortification.\n"); #endif #ifdef FRENCH printf("IA: Erreur -- Vérification de la fortification.\n"); #endif /* Place an army in the first country we find */ for (i=0; i!=NUM_COUNTRIES; i++) if (RISK_GetOwnerOfCountry(i) == iCurrentPlayer) { AI_Place(i, 1); return; } D_Assert(FALSE, "Player didn't own any countries??"); } } /************************************************************************ * FUNCTION: AI_CheckPlacement * HISTORY: * 03.31.95 ESF Created. * PURPOSE: * NOTES: ************************************************************************/ void AI_CheckPlacement(void) { if (RISK_GetNumArmiesOfPlayer(iCurrentPlayer) != 0) { Int32 i; #ifdef ENGLISH printf("AI: Error -- Checking placement.\n"); #endif #ifdef FRENCH printf("IA: Erreur -- Vérification du placement.\n"); #endif /* Dump the armies on the first country */ for (i=0; i!=NUM_COUNTRIES; i++) if (RISK_GetOwnerOfCountry(i) == iCurrentPlayer) { AI_Place(i, RISK_GetNumArmiesOfPlayer(iCurrentPlayer)); return; } D_Assert(FALSE, "Player didn't own any countries??"); } } /************************************************************************ * FUNCTION: AI_Place * HISTORY: * 03.31.95 ESF Created. * 21.08.95 JC AI_CheckCards if game is started. * 28.08.95 JC No AI_CheckCards. * PURPOSE: * NOTES: ************************************************************************/ Flag AI_Place(Int32 iCountry, Int32 iNumArmies) { if (GAME_ValidPlaceDst(iCountry) && iNumArmies <= RISK_GetNumArmiesOfPlayer(iCurrentPlayer) && ((iState == STATE_FORTIFY && iNumArmies == 1) || iState != STATE_FORTIFY)) { GAME_PlaceArmies(iCountry, iNumArmies); /* Player has fortified if in fortification stage */ fPlayerFortified = TRUE; return TRUE; } else { #ifdef ENGLISH printf("AI: Error -- illegal place (%d, %d)\n", iCountry, iNumArmies); #endif #ifdef FRENCH printf("IA: Erreur -- placement illégal (%d, %d)\n", iCountry, iNumArmies); #endif return FALSE; } } /************************************************************************/ Int32 iMoveMode; /************************************************************************ * FUNCTION: AI_Attack * HISTORY: * 03.31.95 ESF Created. * 23.08.95 JC Corrected a bug if iSrcCountry or iDstCountry are * totally invalid. * If ARMIES_MOVE_MANUAL, conserve NumArmiesOfPlayer. * 30.08.95 JC Do the move immediatly. * PURPOSE: * NOTES: ************************************************************************/ Flag AI_Attack(Int32 iSrcCountry, Int32 iDstCountry, Int32 iAttack, Int32 iDice, Int32 iMoveSelectMode) { Int32 iAttackMode, iDiceMode; char *srcName, *dstName; iMoveMode = iMoveSelectMode; /* Set the modes for the attack */ switch (iDice) { case DICE_ONE: iDiceMode = ATTACK_ONE; break; case DICE_TWO: iDiceMode = ATTACK_TWO; break; case DICE_THREE: iDiceMode = ATTACK_THREE; break; case DICE_MAXIMUM: iDiceMode = ATTACK_AUTO; break; default: #ifdef ENGLISH printf("AI: Error -- choosing dice mode for attack.\n"); #endif #ifdef FRENCH printf("IA: Erreur -- choix du mode des dés pour combattre.\n"); #endif return FALSE; } switch (iAttack) { case ATTACK_ONCE: iAttackMode = ACTION_ATTACK; break; case ATTACK_DOORDIE: iAttackMode = ACTION_DOORDIE; break; default: #ifdef ENGLISH printf("AI: Error -- choosing attack mode for attack.\n"); #endif #ifdef FRENCH printf("IA: Erreur -- choix du mode d'attaque pour combattre.\n"); #endif return FALSE; } RISK_SetAttackModeOfPlayer(iCurrentPlayer, iAttackMode); RISK_SetDiceModeOfPlayer(iCurrentPlayer, iDiceMode); /* BUG -- return true if victory? */ if (GAME_ValidAttackSrc(iSrcCountry, TRUE) && GAME_ValidAttackDst(iSrcCountry, iDstCountry, TRUE) && GAME_ValidAttackDice(iDiceMode, iSrcCountry)) { GAME_Attack(iSrcCountry, iDstCountry); return TRUE; } else { if ((iSrcCountry>=0) && (iSrcCountry=0) && (iDstCountry %s)\n", #endif #ifdef FRENCH printf("IA: Erreur -- illégall attaque (%s --> %s)\n", #endif srcName, dstName); return FALSE; } } /************************************************************************ * FUNCTION: AI_Move * HISTORY: * 03.31.95 ESF Created. * 23.08.95 JC Don't check Cards and placement * if state <> STATE_MOVE. * PURPOSE: * NOTES: ************************************************************************/ Flag AI_Move(Int32 iSrcCountry, Int32 iDstCountry, Int32 iNumArmies) { if (GAME_ValidMoveSrc(iSrcCountry) && GAME_ValidMoveDst(iSrcCountry, iDstCountry) && RISK_GetNumArmiesOfCountry(iSrcCountry) >= iNumArmies+1) { GAME_MoveArmies(iSrcCountry, iDstCountry, iNumArmies); return TRUE; } else { #ifdef ENGLISH printf("AI: Error -- illegal move (%s --> %s)\n", #endif #ifdef FRENCH printf("IA: Erreur -- mouvement illégal (%s --> %s)\n", #endif RISK_GetNameOfCountry(iSrcCountry), RISK_GetNameOfCountry(iDstCountry)); return FALSE; } } /************************************************************************ * FUNCTION: AI_ExchangeCards * HISTORY: * 03.31.95 ESF Created. * PURPOSE: * NOTES: ************************************************************************/ Flag AI_ExchangeCards(Int32 *piCards) { GAME_ExchangeCards(piCards); return TRUE; } /************************************************************************ * FUNCTION: AI_SendMessage * HISTORY: * 03.31.95 ESF Created. * PURPOSE: * NOTES: ************************************************************************/ Flag AI_SendMessage(Int32 iMessDest, CString strMessage) { MsgMessagePacket mess; mess.strMessage = strMessage; mess.iFrom = iCurrentPlayer; mess.iTo = iMessDest; (void)RISK_SendMessage(CLNT_GetCommLinkOfClient(CLNT_GetThisClientID()), MSG_MESSAGEPACKET, &mess); return TRUE; } /************************************************************************ * FUNCTION: AI_EndTurn * HISTORY: * 03.31.95 ESF Created. * 21.08.95 JC Added fGetsCard. * 23.08.95 JC Added test the mission. * PURPOSE: * NOTES: ************************************************************************/ Flag AI_EndTurn(void) { /* Get the player a card if he or she needs one */ if (fGetsCard) { MsgRequestCard msg; fGetsCard = FALSE; msg.iPlayer = iCurrentPlayer; (void)RISK_SendMessage(CLNT_GetCommLinkOfClient(CLNT_GetThisClientID()), MSG_REQUESTCARD, &msg); } if (fGameStarted) fCanExchange = TRUE; else fPlayerFortified = FALSE; /* Actually end the turn */ (void)RISK_SendMessage(CLNT_GetCommLinkOfClient(CLNT_GetThisClientID()), MSG_ENDTURN, NULL); return TRUE; } xfrisk-1.2/aiController.h0100644000175000017500000000251207000075544014506 0ustar johnojohno/***************************************************************************** * * * Copyright (c) 1993-1997 Elan Feingold (elan@jeeves.net) * * * * PERMISSION TO USE, COPY, MODIFY, AND TO DISTRIBUTE THIS SOFTWARE * * AND ITS DOCUMENTATION FOR ANY PURPOSE IS HEREBY GRANTED WITHOUT * * FEE, PROVIDED THAT THE ABOVE COPYRIGHT NOTICE APPEAR IN ALL * * COPIES AND MODIFIED COPIES AND THAT BOTH THAT COPYRIGHT NOTICE AND * * THIS PERMISSION NOTICE APPEAR IN SUPPORTING DOCUMENTATION. THERE * * IS NO REPRESENTATIONS ABOUT THE SUITABILITY OF THIS SOFTWARE FOR * * ANY PURPOSE. THIS SOFTWARE IS PROVIDED "AS IS" WITHOUT EXPRESS * * OR IMPLIED WARRANTY. * * * *****************************************************************************/ #ifndef _AICONTROLLER #define _AICONTROLLER #include "types.h" /* These routines check that the player is in a valid state */ void AI_Init(void); void AI_CheckCards(void); void AI_CheckFortification(void); void AI_CheckPlacement(void); #endif xfrisk-1.2/aiConway.c0100644000175000017500000006152107000076347013625 0ustar johnojohno/*********************************************************************** * * 14-6-90 Created by Andrew Conway. * 22-4-95 ESF commented, changed function names, removed campuses. * * Passive (defensive) RISK game player. * ***********************************************************************/ #include #include "aiClient.h" #include "aiConway.h" #include "debug.h" #include "types.h" #include "riskgame.h" #include "game.h" #include "utils.h" /* The species */ DefineSpecies( CONWAY_Play, "Conway's `Mean Player'", "Andrew Conway", "0.99", "His best player. It's vicious, and tends to attack you" "in whatever places you show interest." ) /* External data */ extern Int32 iCurrentPlayer; static int enemyarmies; static int playerarmies; static COUNTRY *mindest, *minroute; static int mindist; static COUNTRYLIST *pDesiredCountries=NULL, *pAllCountries=NULL; static Flag fCurrentPlayerIsWinning; static CONTINENT pContinents[NUM_CONTINENTS]; static PLAYER players[MAX_PLAYERS]; static PLAYERTYPE playerType = { "Mean", 0, 0, 1, 0, 0, 2, 5, 0, 1, 1, 0, 1, 1, 0, 0, 1, 5, 0 }; /************************************************************************ * FUNCTION: * HISTORY: * 04.23.95 ESF Created. * PURPOSE: * NOTES: ************************************************************************/ void *CONWAY_Play(void *pData, Int32 iCommand, void *pArgs) { UNUSED(pArgs); switch (iCommand) { /*********************/ case AI_INIT_ONCE: { /* Set up the world to appear as Conway wants it to */ printf("AI-CONWAY: Creating Conway-world...\n"); CONWAY_InitWorld(); /* Create a list of all the countries */ pAllCountries = CLIST_CreateEmpty(); make_wholelist(); } break; /*********************/ case AI_INIT_TURN: { /* Free old list */ if (pDesiredCountries) CLIST_Destroy (pDesiredCountries); fCurrentPlayerIsWinning = CONT_FindDesired (iCurrentPlayer); pDesiredCountries = CLIST_GetDesiredCountries (iCurrentPlayer); CLIST_CalculateUsefulness (iCurrentPlayer, pDesiredCountries); } break; /*********************/ case AI_FORTIFY: CONWAY_FortifyTerritories (iCurrentPlayer, 1, /* for now */ pDesiredCountries); break; /*********************/ case AI_PLACE: CONWAY_FortifyTerritories (iCurrentPlayer, RISK_GetNumArmiesOfPlayer(iCurrentPlayer), pDesiredCountries); break; /*********************/ case AI_ATTACK: { if (mindest) { if (passive_attack (mindest, minroute)) { /* RAMPAGE!!! */ find_destination (pDesiredCountries, iCurrentPlayer); while (mindest && (RISK_GetNumArmiesOfCountry(mindest->iIndex) > 2)) { if (passive_attack (mindest, minroute)) CLIST_RemoveCountry (pDesiredCountries, minroute); find_destination (pDesiredCountries, iCurrentPlayer); } CLIST_CalculateUsefulness (iCurrentPlayer, pDesiredCountries); } } copy_armies_movable (); } break; /*********************/ case AI_MOVE: CONWAY_MoveArmies (iCurrentPlayer); break; /*********************/ case AI_MESSAGE: break; } return pData; } #define NEARNESS_WEIGHT 10 #define BORDER_WEIGHT 10 #define NEXT_BORD_WEIGHT 2 typedef enum {Min, Max} Kind; typedef int (*EvalFunc)(COUNTRY *); int CLIST_Evaluate (COUNTRYLIST *from, EvalFunc foo); COUNTRYLIST *CLIST_Create (COUNTRY *country) { COUNTRYLIST *p; p = (COUNTRYLIST *) MEM_Alloc (sizeof (COUNTRYLIST)); p->country = country; p->next = NULL; return p; } COUNTRYLIST *CLIST_CreateEmpty (void) { return CLIST_Create (NULL); } void CLIST_AddCountry (COUNTRYLIST *cl, COUNTRY *country) { while (cl->next) cl = cl->next; cl->next = CLIST_Create (country); } void CLIST_RemoveCountry (COUNTRYLIST *cl, COUNTRY *c) { COUNTRYLIST *p; if (cl == NULL) return; for (p=cl, cl=cl->next; cl; p=cl, cl=cl->next) { if (cl->country == c) { p->next = cl->next; MEM_Free (cl); return; /* Used to not return! */ } } } void CLIST_Destroy (COUNTRYLIST *cl) { COUNTRYLIST *p; for (; cl; cl = p) { p = cl->next; MEM_Free (cl); } } static COUNTRY *savedcountry; int CNT_NextToSaved (COUNTRY *country) { return CNT_IsNextTo (savedcountry, country); } int CLIST_Evaluate (COUNTRYLIST *from, EvalFunc function) { int value = 0; for (from = from->next; from; from = from->next) value += ((*function) (from->country)); return value; } COUNTRYLIST *CLIST_Extract (COUNTRYLIST *from, int (*function)()) { COUNTRYLIST *cl; cl = CLIST_CreateEmpty (); for (from = from->next; from; from = from->next) if ((*function) (from->country)) { CLIST_AddCountry (cl, from->country); } return cl; } int CNT_IsOwned (COUNTRY *country) { int res; res = (iCurrentPlayer == RISK_GetOwnerOfCountry(country->iIndex)); return res; } COUNTRYLIST *CLIST_GetOwned (int player) { iCurrentPlayer = player; return CLIST_Extract (pAllCountries, CNT_IsOwned); } int CNT_IsNearlyOwned (COUNTRY *country) { return ((iCurrentPlayer == RISK_GetOwnerOfCountry(country->iIndex)) || CLIST_Evaluate (country->adjacentlist, (EvalFunc)CNT_IsOwned)); } int CNT_IsDesired (COUNTRY *country) { const int owner = RISK_GetOwnerOfCountry(country->iIndex); /* If we already own it --> No */ if (iCurrentPlayer == owner) return 0; /* If we are winning and we want to go for everything --> Yes */ if (fCurrentPlayerIsWinning && playerType.wantallwinning) return 1; /* If we already own the continent --> Yes */ if (country->continent->almost_owned) return 1; /* If we last owned it and we like getting back things --> Yes */ if (iCurrentPlayer == CONWAY_GetLastOwnerOfCountry(country) && playerType.wantback) return 1; /* If the continent's owned... */ if (country->continent->owner != -1) { /* ...and we own things around it --> Yes */ if (playerType.break1 && CLIST_Evaluate (country->adjacentlist, (EvalFunc)CNT_IsOwned)) return 1; /* ...and we almost own things around it --> Yes */ if (playerType.break2 && CLIST_Evaluate (country->adjacentlist, (EvalFunc)CNT_IsNearlyOwned)) return 1; } /* No */ return 0; } COUNTRYLIST *CLIST_GetDesiredCountries (int player) { iCurrentPlayer = player; return CLIST_Extract (pAllCountries, CNT_IsDesired); } int CNT_NumAttackers (COUNTRY *country) { if (RISK_GetOwnerOfCountry(country->iIndex) == iCurrentPlayer) return 0; else return RISK_GetNumArmiesOfCountry(country->iIndex) + 1; } static COUNTRY *pDefendedCountry; static int iExtremeDefense; static Kind kind; void CNT_Vulnerability (COUNTRY *pCountry) { int iBadDefense; /* If we don't own it, forget about it... */ if (RISK_GetOwnerOfCountry(pCountry->iIndex) != iCurrentPlayer) return; /* If we've already defended it as much as possible, forget it */ if (RISK_GetNumArmiesOfCountry(pCountry->iIndex) == 99) return; /* See how badly defended this country is. Give points for attackers * adjacent to it. Add points for usefulness of the country, and take * points away for armies that we have on the country. */ iBadDefense = CLIST_Evaluate (pCountry->adjacentlist, (EvalFunc)CNT_NumAttackers) - RISK_GetNumArmiesOfCountry(pCountry->iIndex) + pCountry->usefulness; if ((!pDefendedCountry) || (kind == Max && iBadDefense > iExtremeDefense) || (kind == Min && iBadDefense < iExtremeDefense)) { /* We've found a worse defended country */ iExtremeDefense = iBadDefense; pDefendedCountry = pCountry; } } COUNTRY *CNT_WorstDefended (COUNTRYLIST *have, int player) { iCurrentPlayer = player; pDefendedCountry = NULL; kind = Max; CLIST_Evaluate (have, (EvalFunc)CNT_Vulnerability); return pDefendedCountry; } COUNTRY *CNT_BestDefended (COUNTRYLIST *have, int player) { iCurrentPlayer = player; pDefendedCountry = NULL; kind = Min; CLIST_Evaluate (have, (EvalFunc)CNT_Vulnerability); return pDefendedCountry; } void CNT_SetZeroFlag (COUNTRY *country) { country->flag = 0; } static COUNTRY *pStartCountry, *pBestSrcCountry, *pSrcCountry; static COUNTRY *pBestDestinationCountry; static int saveddist, iBestDistance; static COUNTRYLIST *worklist; void CNT_AddToWorklist (COUNTRY *country) { COUNTRYLIST *p; p = worklist; while (p->next) { p = p->next; if (p->country == country) return; } p->next = CLIST_Create (country); } void CNT_AddIfConquerable (COUNTRY *country) { int dist; /* If we're at the start, return */ if (country == pStartCountry) return; /* If we're at the source, return */ if (country == pSrcCountry) return; /* If the country is owned by the current player */ if (RISK_GetOwnerOfCountry(country->iIndex) == iCurrentPlayer) { /* It's cheaper to get through, since it already has armies */ dist = saveddist - RISK_GetNumArmiesOfCountry(country->iIndex); /* If this is the best route we've found, use it */ if ((!pBestDestinationCountry) || (dist < iBestDistance)) { pBestSrcCountry = pSrcCountry; pBestDestinationCountry = country; iBestDistance = dist; } } else /* Enemy country to get through */ { /* Approximate cost to get through: 2+armies+meanness */ dist = saveddist + 2 + RISK_GetNumArmiesOfCountry(country->iIndex); /* dist += ptype[players[RISK_GetOwnerOfCountry(country->iIndex)].type]. adddist; */ /* If the cost is more than we could possible have -- forget it */ if ((pBestDestinationCountry) && (dist >= iBestDistance + 99)) return; /* If the cost is more then we have flagged, forget it */ if ((country->flag) && (country->flag <= dist)) return; /* Otherwise, add it to our worklist */ country->flag = dist; CNT_AddToWorklist (country); } } int CONT_AlmostOwned (CONTINENT *cont, int player) { int country, unowned = 0, iNumEnemyArmies = 0, ownarmies = 0; D_Assert(player == iCurrentPlayer, "Wrong player!"); for (country = 0; country < cont->numcountries; country++) { /* If we don't own a country in the continent */ if (player != RISK_GetOwnerOfCountry(cont->countries[country].iIndex)) { iNumEnemyArmies += RISK_GetNumArmiesOfCountry(cont-> countries[country]. iIndex); unowned++; } else ownarmies += RISK_GetNumArmiesOfCountry(cont->countries[country]. iIndex); } cont->almost_owned = (unowned <= playerType.almostowned); cont->almost_owned |= (iNumEnemyArmies + 4*unowned + playerType.excessarmies < ownarmies); enemyarmies += iNumEnemyArmies + 4*unowned; playerarmies += ownarmies; return (iNumEnemyArmies - ownarmies + 2*unowned); } int CONT_FindDesired (int player) /* check continents wanted */ { int cont; int numarmies, numarmies_sofar; CONTINENT *wantcont = NULL; enemyarmies = 0; playerarmies = 0; numarmies_sofar = 0; for (cont = 0; cont < NUM_CONTINENTS; cont++) { numarmies = CONT_AlmostOwned (CONT_GetContinent(cont), player); if (player == CONT_GetOwner(cont)) continue; if ((!wantcont) || (numarmies < numarmies_sofar)) { wantcont = CONT_GetContinent(cont); numarmies_sofar = numarmies; } } /* Agressive */ if ((wantcont) && playerType.wantbestcont) wantcont->almost_owned = 1; return (enemyarmies < 2 * playerarmies); } void find_nearest (COUNTRY *pCountry) { COUNTRYLIST *p; CLIST_Evaluate (pAllCountries, (EvalFunc)CNT_SetZeroFlag); pBestDestinationCountry = NULL; pStartCountry = pCountry; worklist = CLIST_Create (pCountry); pCountry->flag = RISK_GetNumArmiesOfCountry(pCountry->iIndex); while (worklist) { if(CNT_IsOwned(worklist->country)) { worklist = worklist->next; continue; } pSrcCountry = worklist->country; saveddist = pSrcCountry->flag; CLIST_Evaluate (pSrcCountry->adjacentlist, (EvalFunc)CNT_AddIfConquerable); p = worklist; worklist = worklist->next; MEM_Free (p); } } void copy_armies_movable (void) { int cont, country; CONTINENT *thiscont; COUNTRY *thiscountry; for (cont = 0; cont < NUM_CONTINENTS; cont++) { thiscont = CONT_GetContinent(cont); for (country = 0; country < thiscont->numcountries; country++) { thiscountry = thiscont->countries + country; thiscountry->movable = RISK_GetNumArmiesOfCountry(thiscountry->iIndex); thiscountry->pass_through = 0; } } } void CNT_IsNearest (COUNTRY *country) { find_nearest (country); if ((!mindest) || (iBestDistance < mindist)) { mindist = iBestDistance; mindest = pBestDestinationCountry; minroute = pBestSrcCountry; } } void find_destination (COUNTRYLIST *pDesiredCountries, int player) { iCurrentPlayer = player; if (players[player].lastattacked && playerType.concentratelastattack) { find_nearest (players[player].lastattacked); mindest = pBestDestinationCountry; minroute = pBestSrcCountry; mindist = iBestDistance * 2 / 3; } else mindest = NULL; CLIST_Evaluate (pDesiredCountries, (EvalFunc)CNT_IsNearest); } void CNT_DistributeArmiesEvenly (int player, int amount) { COUNTRYLIST *have; COUNTRY *country; /* Get the list of owned countries */ have = CLIST_GetOwned (player); /* While we have armies to place */ while (amount > 0) { /* Get the worst defended one */ country = CNT_WorstDefended (have, player); if (!country) return; /* Put an army on that country */ AI_Place(country->iIndex, 1); /* amount--; country->numarmies++; draw_country (country); */ } CLIST_Destroy (have); } void CONWAY_FortifyTerritories (int player, int amount, COUNTRYLIST *pDesiredCountries) { if ((!pDesiredCountries->next) && (!players[player].lastattacked)) { CNT_DistributeArmiesEvenly (player, amount); mindest = NULL; } else { find_destination (pDesiredCountries, player); if (mindest) { AI_Place(mindest->iIndex, amount); /* mindest->numarmies += amount; draw_country (mindest); */ } else CNT_DistributeArmiesEvenly (player, amount); } } int passive_attack (COUNTRY *from, COUNTRY *to) { Int32 iOldDestOwner = RISK_GetOwnerOfCountry(to->iIndex); /* Perform the attack */ if(AI_Attack(from->iIndex, to->iIndex, ATTACK_DOORDIE, DICE_MAXIMUM, ARMIES_MOVE_MAX) == FALSE) return 0; /* Book-keeping */ if (RISK_GetOwnerOfCountry(to->iIndex) != iOldDestOwner) { /* Who owned the country last? */ to->lastowner = iOldDestOwner; /* Last attacked (and taken) from */ players[iOldDestOwner].lastattacked = to; } if (to == players[RISK_GetOwnerOfCountry(from->iIndex)].lastattacked) { /* Got It! */ players[RISK_GetOwnerOfCountry(from->iIndex)].lastattacked = NULL; return 1; } else return 0; } void CNT_FortifyNeighbor (COUNTRY *country) { COUNTRY *pWorstDefendedCountry; if (RISK_GetOwnerOfCountry(country->iIndex) != iCurrentPlayer) return; while (country->movable) { pWorstDefendedCountry = CNT_WorstDefended (country->adjacentlist, iCurrentPlayer); /* If there is no worst defended, or it's the one we're looking * at, then forget it. */ if ((!pWorstDefendedCountry) || (pWorstDefendedCountry == country)) break; /* Move an army from the country to the worst defended country * of the ones it borders on. */ AI_Move(country->iIndex, pWorstDefendedCountry->iIndex, 1); country->movable--; /* country->numarmies--; pWorstDefendedCountry->numarmies++; draw_country (country); draw_country (pWorstDefendedCountry); */ if (!pWorstDefendedCountry->pass_through) { pWorstDefendedCountry->pass_through = 1; pWorstDefendedCountry->movable++; } } } void CNT_SetZeroNearness (COUNTRY *country) { country->nearness = 0; } void CNT_CalculateUsefulness (COUNTRY *country) { if (RISK_GetOwnerOfCountry(country->iIndex) != iCurrentPlayer) return; country->usefulness = ((country->continent->owner == iCurrentPlayer) ? country->criticalness : 0) + country->nearness; } void do_nearness (COUNTRY *country) { find_nearest (country); if (pBestDestinationCountry) pBestDestinationCountry->nearness += NEARNESS_WEIGHT; } void CLIST_CalculateUsefulness (int player, COUNTRYLIST *pDesiredCountries) { iCurrentPlayer = player; CLIST_Evaluate (pAllCountries, (EvalFunc)CNT_SetZeroNearness); CLIST_Evaluate (pDesiredCountries, (EvalFunc)do_nearness); CLIST_Evaluate (pAllCountries, (EvalFunc)CNT_CalculateUsefulness); } void CONWAY_MoveArmies (int iPlayer) { /* Find the worst defended country, use a neighbor to fortify it */ COUNTRYLIST *pNeighbors, *pAllMyCountries = CLIST_GetOwned(iPlayer); COUNTRY *pWorstDefended, *pBestDefended; int working = 10; while (working && pAllMyCountries->next) { pWorstDefended = CNT_WorstDefended(pAllMyCountries, iPlayer); pNeighbors = pWorstDefended->adjacentlist; pBestDefended = CNT_BestDefended(pNeighbors, iPlayer); if (pBestDefended && RISK_GetNumArmiesOfCountry(pBestDefended->iIndex) >= 2) { int iNumArmies = RISK_GetNumArmiesOfCountry(pBestDefended->iIndex)/2; working = 0; /* Do it */ AI_Move(pBestDefended->iIndex, pWorstDefended->iIndex, iNumArmies); } else { working--; if (pWorstDefended) CLIST_RemoveCountry(pAllMyCountries, pWorstDefended); } } } void distribute_passive_initial (int player, int amount) { COUNTRYLIST *pDesiredCountries; fCurrentPlayerIsWinning = CONT_FindDesired (player); pDesiredCountries = CLIST_GetDesiredCountries (player); CLIST_CalculateUsefulness (player, pDesiredCountries); CONWAY_FortifyTerritories (player, amount, pDesiredCountries); CLIST_Destroy (pDesiredCountries); } /* Related to AI */ void CNT_IsAdjacent (COUNTRY *country) { savedcountry = country; country->adjacentlist = CLIST_Extract (pAllCountries, CNT_NextToSaved); } void CNT_IsCritical (COUNTRY *country) { if (CNT_IsBorder (country)) country->criticalness = BORDER_WEIGHT; else country->criticalness = NEXT_BORD_WEIGHT * CLIST_Evaluate (country->adjacentlist, (EvalFunc)CNT_IsBorder); } int CNT_IsBorder (COUNTRY *country) { int contcount; int iCountry, contno; CONTINENT *cont, *thiscont; cont = country->continent; iCountry = country - cont->countries; contno = (int)(cont - pContinents); for (contcount = 0; contcount < NUM_CONTINENTS; contcount++) { thiscont = CONT_GetContinent(contcount); if (join_contains_country (thiscont->joins, thiscont->numjoins, contno, iCountry)) return 1; } return 0; } void make_wholelist (void) { int cont, country; CONTINENT *thiscont; COUNTRY *thiscountry; for (cont = 0; cont < NUM_CONTINENTS; cont++) { thiscont = &pContinents[cont]; for (country = 0; country < thiscont->numcountries; country++) { thiscountry = thiscont->countries + country; CLIST_AddCountry (pAllCountries, thiscountry); thiscountry->pass_through = 0; } } /* Calculate all of the adjacent countries */ CLIST_Evaluate (pAllCountries, (EvalFunc)CNT_IsAdjacent); /* Calculate the criticalness of the countries */ CLIST_Evaluate (pAllCountries, (EvalFunc)CNT_IsCritical); } int join_contains_country (JOIN *joins, int numjoins, int contno, int num) { while (numjoins--) { if (((joins->continentto == contno) && (joins->countryto == num)) || ((joins->continentfrom == contno) && (joins->countryfrom == num))) return 1; joins++; } return 0; } static int nextplayer; void reown (COUNTRY *country) { if (CONWAY_GetLastOwnerOfCountry(country) == iCurrentPlayer) country->lastowner = nextplayer = CONWAY_NextPlayer (nextplayer); } void redistribute_last (int player) { iCurrentPlayer = player; nextplayer = -1; CLIST_Evaluate (pAllCountries, (EvalFunc)reown); } CONTINENT *CONT_GetContinent(int iCont) { return &pContinents[iCont]; } int CONT_GetOwner(int iCont) { return pContinents[iCont].owner; } int CONWAY_NextPlayer(int iCurrentPlayer) { do { /* Go to the next player, wrap-around if we're at the end */ iCurrentPlayer = (iCurrentPlayer+1) % MAX_PLAYERS; } while (RISK_GetStateOfPlayer(iCurrentPlayer) == FALSE || RISK_GetAllocationStateOfPlayer(iCurrentPlayer) != ALLOC_COMPLETE); /* Return the player who's turn it is */ return iCurrentPlayer; } int CNT_IsNextTo(COUNTRY *countrya, COUNTRY *countryb) { int numa, numb, contnoa, contnob, i; CONTINENT *conta, *contb; JOIN *join; conta = countrya->continent; contb = countryb->continent; numa = countrya - conta->countries; numb = countryb - contb->countries; contnoa = conta - pContinents; contnob = contb - pContinents; if (conta == contb) return (countrya->is_connected[numb]); for (i=0; inumjoins; i++) { join = &conta->joins[i]; if ((join->continentto == contnob) && (join->countryfrom == numa) && (join->countryto == numb)) return 1; } for (i=0; inumjoins; i++) { join = &contb->joins[i]; if ((join->continentto == contnoa) && (join->countryfrom == numb) && (join->countryto == numa)) return 1; } return 0; } void CONWAY_InitWorld(void) { Int32 i, j, k; Int32 iCountry, iCountry2; Int32 iNumCountries, iNumJoins; Int32 pTempCountries[NUM_COUNTRIES]; JOIN pTempJoins[NUM_COUNTRIES]; /* For each continent, find number of countries */ for (i=0; i!=NUM_CONTINENTS; i++) { for (j=iNumCountries=0; j!=NUM_COUNTRIES; j++) if (RISK_GetContinentOfCountry(j) == i) pTempCountries[iNumCountries++] = j; /* Allocate the countries */ pContinents[i].numcountries = iNumCountries; pContinents[i].countries = (COUNTRY *)MEM_Alloc(sizeof(COUNTRY)* iNumCountries); printf("AI-CONWAY: `%s' has %d countries.\n", RISK_GetNameOfContinent(i), iNumCountries); /* Fill in the countries */ for (j=0; j!=iNumCountries; j++) { iCountry = pTempCountries[j]; printf(" o `%s'\n", RISK_GetNameOfCountry(iCountry)); pContinents[i].countries[j].continent = &pContinents[i]; pContinents[i].countries[j].iIndex = iCountry; pContinents[i].countries[j].movable = 0; pContinents[i].countries[j].lastowner = -1; pContinents[i].countries[j].usefulness = 0; } } /* Now calculate the number of joins */ for (i=0; i!=NUM_CONTINENTS; i++) { for (j=iNumJoins=0; j!=pContinents[i].numcountries; j++) { iCountry = pContinents[i].countries[j].iIndex; for (k=0; RISK_GetAdjCountryOfCountry(iCountry, k)!=-1 && k<6; k++) { iCountry2 = RISK_GetAdjCountryOfCountry(iCountry, k); if (RISK_GetContinentOfCountry(iCountry2) != i) { Int32 k, iCont1, iCont2; iCont1 = i; iCont2 = RISK_GetContinentOfCountry(iCountry2); /* Store countries as offset from ->countries */ for (k=0; k!=pContinents[iCont1].numcountries; k++) if (pContinents[iCont1].countries[k].iIndex == iCountry) { pTempJoins[iNumJoins].countryfrom = k; } for (k=0; k!=pContinents[iCont2].numcountries; k++) if (pContinents[iCont2].countries[k].iIndex == iCountry2) { pTempJoins[iNumJoins].countryto = k; } pTempJoins[iNumJoins].continentfrom = i; pTempJoins[iNumJoins].continentto = RISK_GetContinentOfCountry(iCountry2); iNumJoins++; } } } /* Allocate the joins */ pContinents[i].joins = (JOIN *)MEM_Alloc(sizeof(JOIN)*iNumJoins); pContinents[i].numjoins = iNumJoins; printf("AI-CONWAY: Continent `%s' has %d joins.\n", RISK_GetNameOfContinent(i), iNumJoins); for (j=0; j!=iNumJoins; j++) memcpy(&pContinents[i].joins[j], &pTempJoins[j], sizeof(JOIN)); } /* Calculate the `is_connected' data member */ for (i=0; i!=NUM_CONTINENTS; i++) { /* For each country in the continent */ for (j=0; j!=pContinents[i].numcountries; j++) { /* Allocate space for the array */ pContinents[i].countries[j].is_connected = (int *)MEM_Alloc(sizeof(Int32)*pContinents[i].numcountries); /* Now, for each of the countries in the continent, answer the * question: Is country j connect to it? */ for (k=0; k!=pContinents[i].numcountries; k++) if (GAME_CanAttack(pContinents[i].countries[j].iIndex, pContinents[i].countries[k].iIndex)) pContinents[i].countries[j].is_connected[k] = 1; else pContinents[i].countries[j].is_connected[k] = 0; } } } #if 0 int pass_through; ?? int flag; int movable; #endif xfrisk-1.2/aiConway.h0100644000175000017500000000636407000075544013634 0ustar johnojohno#ifndef _AICONWAYH #define _AICONWAYH #define CONWAY_GetLastOwnerOfCountry(c) (c->lastowner) typedef struct country { struct continent *continent; int lastowner; /**/ struct _COUNTRYLIST *adjacentlist; /**/ int movable; int pass_through; int *is_connected; int flag; int usefulness; int criticalness; int nearness; int iIndex; } COUNTRY; typedef struct _COUNTRYLIST { COUNTRY *country; struct _COUNTRYLIST *next; } COUNTRYLIST; typedef struct join { int continentfrom; int continentto; int countryfrom; int countryto; } JOIN; typedef struct continent { int owner; /* D */ int almost_owned; int numcountries; COUNTRY *countries; int numjoins; /**/ JOIN *joins; /**/ } CONTINENT; typedef struct player { COUNTRY *lastattacked; } PLAYER; typedef struct playertype { char *name; int def_strength; /* Defensive strength */ int att_strength; /* Attacking strength */ int dolastattacked; /* 1 if want to change lastattacked on a * fight. */ int human; int dead; int almostowned; /* Number of unowned sectors to want a * continent */ int excessarmies; /* Number of excess armies to want a * continent */ int wantbestcont; /* Want the continent you are strongest on */ int wantback; /* Want to get countries back */ int wantallwinning; /* Want to get all when winning */ int passive; int passivewantbackfrom; /* Will get a country from this person */ int smart; int smartwantbackfrom; /* Will get a country back from this person */ int break1; /* Break continent from 1 away */ int break2; /* Break continent from 2 away */ int adddist; /* add to distance score for attacking this * type */ int concentratelastattack; /* Concentrate on last attacked space */ } PLAYERTYPE; /* Functions */ COUNTRYLIST *CLIST_CreateEmpty (void); COUNTRYLIST *CLIST_GetDesiredCountries (int player); void CLIST_RemoveCountry (COUNTRYLIST *cl, COUNTRY *c); void CLIST_AddCountry (COUNTRYLIST *cl, COUNTRY *country); void CLIST_Destroy (COUNTRYLIST *cl); void CLIST_CalculateUsefulness (int player, COUNTRYLIST *pDesiredCountries); CONTINENT *CONT_GetContinent(int iCont); int CONT_FindDesired (int player); int CONT_GetOwner(int iCont); int CONT_AlmostOwned (CONTINENT *cont, int player); void CONWAY_MoveArmies (int iPlayer); int CONWAY_NextPlayer(int); void CONWAY_InitWorld(void); void *CONWAY_Play(void *pData, Int32 iCommand, void *pArgs); void CONWAY_FortifyTerritories (int player, int amount, COUNTRYLIST *pDesiredCountries); int passive_attack (COUNTRY *from, COUNTRY *to); void find_destination (COUNTRYLIST *pDesiredCountries, int player); void copy_armies_movable (void); int join_contains_country (JOIN *joins, int numjoins, int contno, int num); void make_wholelist (void); void CNT_CalculateUsefulness (COUNTRY *c); int CNT_IsBorder (COUNTRY *c); void CNT_DistributeArmiesEvenly (int player, int amount); void CNT_CalculateUsefulness (COUNTRY *c); void CNT_IsAdjacent(COUNTRY *c); int CNT_IsNextTo(COUNTRY *c0, COUNTRY *c1); #endif xfrisk-1.2/aiDice.c0100644000175000017500000000171407013357406013231 0ustar johnojohno/* * XFrisk - The classic board game for X * Copyright (C) 1993-1999 Elan Feingold (elan@aetherworks.com) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * $Id: aiDice.c,v 1.3 1999/11/13 21:58:30 morphy Exp $ */ #define DICE_AI #include "diceCommon.c" #undef DICE_AI xfrisk-1.2/aiDummy.c0100644000175000017500000000254507013357406013463 0ustar johnojohno/* * XFrisk - The classic board game for X * Copyright (C) 1993-1999 Elan Feingold (elan@aetherworks.com) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * $Id: aiDummy.c,v 1.4 1999/11/13 21:58:30 morphy Exp $ */ #include #include #include "aiClient.h" #include "utils.h" void *DUMMY_Play(void *pData, Int32 iCommand, void *pArgs); DefineSpecies( DUMMY_Play, "Terminator 1", "Elan Feingold", "0.01", "A pathetically stupid player." ) void *DUMMY_Play(void *pData, Int32 iCommand, void *pArgs) { UNUSED(pData); UNUSED(iCommand); UNUSED(pArgs); printf("WOWOWOWWOW!!! I made it....\n"); return NULL; } xfrisk-1.2/aiDummy.h0100644000175000017500000000162407013357406013465 0ustar johnojohno/* * XFrisk - The classic board game for X * Copyright (C) 1993-1999 Elan Feingold (elan@aetherworks.com) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * $Id: aiDummy.h,v 1.3 1999/11/13 21:58:30 morphy Exp $ */ xfrisk-1.2/aiStubs.c0100644000175000017500000000500207013357406013457 0ustar johnojohno/* * XFrisk - The classic board game for X * Copyright (C) 1993-1999 Elan Feingold (elan@aetherworks.com) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * $Id: aiStubs.c,v 1.4 1999/11/13 21:58:30 morphy Exp $ */ #include #include "riskgame.h" #include "game.h" #include "types.h" #include "utils.h" extern Int32 iCurrentPlayer; Int32 UTIL_PopupDialog(CString strTitle, CString strQuestion, Int32 iNumOptions, CString strOption1, CString strOption2, CString strOption3) { UNUSED(iNumOptions); UNUSED(strOption1); UNUSED(strOption2); UNUSED(strOption3); #ifdef ENGLISH printf("AI: [%s] `%s'\n", strTitle, strQuestion); #endif #ifdef FRENCH printf("IA: [%s] `%s'\n", strTitle, strQuestion); #endif return 0; } void UTIL_ServerEnterState(Int32 iNewState) { UNUSED(iNewState); } void UTIL_DisplayComment(CString strComment) { UNUSED(strComment); /* #ifdef ENGLISH printf("AI: `%s'\n", strComment); #endif #ifdef FRENCH printf("IA: `%s'\n", strComment); #endif */} void UTIL_DisplayError(CString strError) { UNUSED(strError); /* #ifdef ENGLISH printf("AI: `%s'\n", strError); #endif #ifdef FRENCH printf("IA: `%s'\n", strError); #endif */} void UTIL_DarkenCountry(Int32 iCountry) { UNUSED(iCountry); } void UTIL_LightCountry(Int32 iCountry) { UNUSED(iCountry); } void UTIL_DisplayActionCString(Int32 iState, Int32 iPlayer) { UNUSED(iState); UNUSED(iPlayer); } void UTIL_ExitProgram(Int32 iExitValue) { exit(iExitValue); } void REG_PopupDialog(void) {} void COLOR_SetWorldColors() {} Int32 COLOR_DieToColor(Int32 iDie) { UNUSED(iDie); return 0; } Int32 COLOR_PlayerToColor(Int32 iPlayer) { UNUSED(iPlayer); return 0; } void COLOR_CopyColor(Int32 iSrc, Int32 iDst) { UNUSED(iSrc); UNUSED(iDst); } void DICE_Refresh(void) {} void DICE_Hide(void) {} xfrisk-1.2/buildmap.c0100644000175000017500000003034707041646151013653 0ustar johnojohno/* * XFrisk - The classic board game for X * Copyright (C) 1993-1999 Elan Feingold (elan@aetherworks.com) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * $Id: buildmap.c,v 1.11 2000/01/20 17:56:57 morphy Exp $ * * $Log: buildmap.c,v $ * Revision 1.11 2000/01/20 17:56:57 morphy * Made this thing a bit less verbose, it's running too fast for the old * style progress indications to be of use anymore. * * Revision 1.10 2000/01/10 22:47:40 tony * made colorstuff more private to colormap.c, only scrollbars get set wrong, rest seems to work ok now * * Revision 1.9 2000/01/09 18:20:15 morphy * Backed out change done in rev 1.7: colourmap entries should not be terminated with newline * * ACHTUNG!! iNumColors used here is not the global one! */ #include #include #include #include #include "debug.h" #include "types.h" typedef struct _Color { Byte r, g, b; } Color; typedef struct _BoundingBox { Int32 l, r, t, b; } BoundingBox; struct Directory { Int32 iWidth, iHeight, iLength; Int32 lOffset; } pDirectory[256]; /* No matter where these are, the pseudocolor image always has these * colors at these entries. */ #define BLACK 255 #define WHITE 254 Color pColormap[256]; BoundingBox pBoundingBox[256]; /************************************************************************ * Purpose: Take an image in raw format (i.e. width height rgb rgb rgb) * with up to 256 unique colors and compress it in a run length encoded * fashion, saving the colormap at the beginning of the file. The new * format is as follows (plain numbers, raw form, and [] means nothing): * * [Width Height] * [number of consecutive pixels] [color] * [number of consecutive pixels] [color] * ..... * [# of colors] * [R G B] * [R G B] * ... * * Note that this is not entirely efficient as a run of dissimilar * pixels will double in length. However, for images that I am going * to be compressing this is not the case (maps). * * 2.14.94 ESF Sped up by reading in the file all at once. * * 2.14.94 ESF Added purpose. Generate a country file, that contains * all of the countries, with color 0 backdrop, to use as * the backing for the cards. * * 2.22.94 ESF Added a pseudocolor image so that the country compression * works correctly. * * 2.22.94 ESF Fixed country saving bug. * 3.07.94 ESF Started work on colormap extras (detecting black and white). * 5.04.94 ESF Fixed bugs related to colormap extras. * 6.25.94 ESF Fixed country file color bug. * 1.15.95 ESF Fixed memory leak. ************************************************************************/ void Exit(CString strError); int Compress(Byte *pbBuffer, Int32 iNumBytes, FILE *hOut); int main(int argc, char **argv) { Int32 iNumColors=0, iWidth, iHeight, iCWidth, iCHeight; Color colorCache; FILE *hIn, *hOut, *hOut2; Int32 x, y, i, iTotalPixels=0; Byte r, g, b, bRLE_Color, bRLE_Length; Byte fFound, fCacheValid; Byte *pbTrueColor, *pbPseudoColor, *pbCountry, *pbMisc, *pbTrue; Byte *pbPseudo; Char strBuf[80]; /* Init. and open all the needed files */ if (argc!=4) Exit("Usage is \"compress \""); if ((hIn=fopen(argv[1], "r"))==NULL) Exit("Cannot open input file"); if ((hOut=fopen(argv[2], "w"))==NULL) Exit("Cannot open output file"); if ((hOut2=fopen(argv[3], "w"))==NULL) Exit("Cannot open output file for countries"); /* Init cache */ fCacheValid = 0; /* Init RLE vars */ bRLE_Color = 0; bRLE_Length = 0; /* Init bounding boxes */ for (i=0; i!=256; i++) { pBoundingBox[i].l = pBoundingBox[i].t = 65535; pBoundingBox[i].b = pBoundingBox[i].r == -1; } /* Read the header and make sure that it's the right type of ppm image */ fgets(strBuf, sizeof(strBuf), hIn); if (strcmp(strBuf, "P6\n")) Exit("Not the right type of ppm (need 24 bit raw image)!"); /* Strip out comments */ do fgets(strBuf, sizeof(strBuf), hIn); while(strBuf[0]=='#'); /* Find out the dimensions of the image */ sscanf(strBuf, "%d %d", &iWidth, &iHeight); /* Get the number of colors */ fgets(strBuf, sizeof(strBuf), hIn); sscanf(strBuf, "%d", &iNumColors); /* Height and width info */ printf("Image is [%dx%d].\n", iWidth, iHeight); printf("Image reportedly has %d colors.\n", iNumColors); iNumColors=0; /* Save room for number of colors */ fprintf(hOut, "%4d %4d %3d\n", iWidth, iHeight, 0); /* Allocate memory for the images */ if ((pbTrue=pbTrueColor= (unsigned char *)MEM_Alloc(iHeight*iWidth*3))==NULL) Exit("Could not allocate memory for the TrueColor image"); if ((pbPseudo=pbPseudoColor= (unsigned char *)MEM_Alloc(iHeight*iWidth))==NULL) Exit("Could not allocate memory for the PseudoColor image"); /* Read in the image */ fread(pbTrueColor, 1, iHeight*iWidth*3, hIn); fprintf(stdout, "Compressing: "); fflush(stdout); /* Read in the file, allocating colormap entries as neccessary */ for (y=0; y!=iHeight; y++) { for (x=0; x!=iWidth; x++) { /* Read in a pixel */ r = *pbTrue++; g = *pbTrue++; b = *pbTrue++; /* If it is equal to the color cached, then simply output * the translation, otherwise look it up. */ if (fCacheValid && r==colorCache.r && g==colorCache.g && b==colorCache.b) { /* Color in cache, has RLE line reached its maximum length? */ if (++bRLE_Length==255) { fprintf(hOut, "%c%c", bRLE_Length, bRLE_Color); /* Create the pseudocolor image */ memset(pbPseudo, bRLE_Color, bRLE_Length); pbPseudo+=bRLE_Length; /* Book-keeping */ iTotalPixels+=bRLE_Length; bRLE_Length=0; } } else { /* Color changed, flush RLE line! */ if (fCacheValid) { fprintf(hOut, "%c%c", bRLE_Length, bRLE_Color); /* Create the pseudocolor image */ memset(pbPseudo, bRLE_Color, bRLE_Length); pbPseudo+=bRLE_Length; iTotalPixels+=bRLE_Length; } bRLE_Length=1; /* Search, checking for special colors first */ if (r==0 && g==0 && b==0) fFound=1, i=BLACK; else if (r==255 && g==255 && b==255) fFound=1, i=WHITE; else for (i=0, fFound=0; i!=iNumColors && !fFound; i++) if (r==pColormap[i].r && g==pColormap[i].g && b==pColormap[i].b) fFound=1, i--; /* The new color */ bRLE_Color = i; if (!fFound) { /* Add color to colormap */ pColormap[iNumColors].r = r; pColormap[iNumColors].g = g; pColormap[iNumColors].b = b; iNumColors++; } /* Put the color into the cache */ colorCache.r=r; colorCache.g=g; colorCache.b=b; fCacheValid = 1; } /* Do bounding box stuff */ if (pBoundingBox[bRLE_Color].t > y) pBoundingBox[bRLE_Color].t = y; else if (pBoundingBox[bRLE_Color].b < y) pBoundingBox[bRLE_Color].b = y; if (pBoundingBox[bRLE_Color].l > x) pBoundingBox[bRLE_Color].l = x; else if (pBoundingBox[bRLE_Color].r < x) pBoundingBox[bRLE_Color].r = x; } /* Stats... */ if (!(y % 5)) { fprintf(stdout, "."); fflush(stdout); } } printf(" done\n"); /* The last segment */ if (bRLE_Length) { fprintf(hOut, "%c%c", bRLE_Length, bRLE_Color); /* Create the pseudocolor image */ memset(pbPseudo, bRLE_Color, bRLE_Length); pbPseudo+=bRLE_Length; iTotalPixels+=bRLE_Length; } /* Known colormap entries, this is background/ocean (shouldn't be hardwired) */ pColormap[iNumColors].r = 0; pColormap[iNumColors].g = 0; pColormap[iNumColors].b = 115; iNumColors++; pColormap[iNumColors].r = 255; pColormap[iNumColors].g = 255; pColormap[iNumColors].b = 255; iNumColors++; /* Print out colormap information */ for (i=0; i!=iNumColors; i++) fprintf(hOut, "%c%c%c", pColormap[i].r, pColormap[i].g, pColormap[i].b); fseek(hOut, 10, SEEK_SET); fprintf(hOut, "%3d\n", iNumColors); /* The End */ fclose(hIn); fclose(hOut); printf("There are %d pixels, I compressed %d of them, %s\n", iWidth*iHeight, iTotalPixels, iWidth*iHeight==iTotalPixels ? "Excellent!" : "Ouch!"); printf("Working on countries file: "); /* Adjust iNumColors down by two, since black/white don't count */ iNumColors -= 2; /* Write a dummy header */ fprintf(hOut2, "%d\n", iNumColors); fwrite(pDirectory, iNumColors, sizeof(pDirectory[0]), hOut2); /* Get all of the countries, except for 0, which is supposed to be * the background. * tony: this might be it!! */ for (i=0; i < iNumColors; i++) { fprintf(stdout, ".", i); fflush(stdout); /* Allocate memory for the country structure */ iCWidth = pBoundingBox[i].r - pBoundingBox[i].l; iCHeight = pBoundingBox[i].b - pBoundingBox[i].t; if ((pbMisc=pbCountry= (unsigned char *)MEM_Alloc(iCWidth*iCHeight))==NULL) Exit("Could not allocate memory for country pixmap...\n"); /* Copy the portion over from the main map, and change all colors * s.t. color != i to 0. */ for (y=pBoundingBox[i].t; y=0) { fprintf(hOut, "%c%c", iRunLength, iLastPixel); iCompressedLength+=2; iTotalPixels+=iRunLength; } iRunLength=1; iLastPixel=iNewPixel; } } /* The last segment */ if (iRunLength) { fprintf(hOut, "%c%c", iRunLength, iLastPixel); iTotalPixels+=iRunLength; iCompressedLength+=2; } if (iTotalPixels != iNumBytes) printf("Error! Values don't match! (%d!=%d)\n", iTotalPixels, iNumBytes); return (iCompressedLength); } xfrisk-1.2/callbacks.c0100644000175000017500000013724307040707502013775 0ustar johnojohno/* * XFrisk - The classic board game for X * Copyright (C) 1993-1999 Elan Feingold (elan@aetherworks.com) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * $Id: callbacks.c,v 1.17 2000/01/17 21:53:06 tony Exp $ * * Used by client/AI * Notes: * should not use X, so ai can be compiled on X-less box * is included by riskgame.c, maybe fix there? * or this be the X part, and move out other messages? */ #include #include #include #include #include #include #include #include #include #include #include "language.h" #include "network.h" #include "gui-vars.h" #include "gui-func.h" #include "utils.h" #include "callbacks.h" #include "version.h" #include "riskgame.h" #include "client.h" #include "dice.h" #include "cards.h" #include "game.h" #include "colormap.h" #include "help.h" #include "colorEdit.h" #include "registerPlayers.h" #include "debug.h" #include "viewStats.h" /* Game globals -- move elsewhere? -- make part of riskgame object state! */ static Flag fPlayingRemotely=FALSE; static Flag fForceExchange=FALSE; static Int32 iCountryToFortify=-1; static Int32 piMsgDstPlayerID[MAX_PLAYERS+1]; static Flag fWaitMission = FALSE; static Flag fHaveSeenFirstPlayer; Int32 iIndexMD; Int32 iActionState=ACTION_PLACE; Int32 iReply; CString pstrMsgDstCString[MAX_PLAYERS+1]; Int32 iFirstPlayer; Int32 iState, iCurrentPlayer; Flag fGameStarted=FALSE; /************************************************************************ * FUNCTION: CBK_XIncomingMessage * HISTORY: * 03.17.94 ESF Created. * 06.24.94 ESF Fixed memory leak bug. * PURPOSE: * NOTES: ************************************************************************/ void CBK_XIncomingMessage(XtPointer pClientData, int *iSource, XtInputId *id) { Int32 iMessType; void *pvMess; UNUSED(pClientData); UNUSED(id); (void)RISK_ReceiveMessage(*iSource, &iMessType, &pvMess); CBK_IncomingMessage(iMessType, pvMess); NET_DeleteMessage(iMessType, pvMess); } /************************************************************************ * FUNCTION: CBK_IncomingMessage * HISTORY: * 01.26.94 ESF Created. * 01.27.94 ESF Coded MSG_MESSAGEPACKET case. * 01.29.94 ESF Changed MSG_MESSAGEPACKET to scroll correctly. * 02.05.94 ESF Added MSG_REGISTERPLAYER handling. * 03.02.94 ESF Added more army placing glue. * 03.04.94 ESF Factored out code, cleaned up. * 03.05.94 ESF Added color-coded player turn indicator call. * 03.06.94 ESF Fixed initialization of iCurrentPlayer bug. * 03.16.94 ESF Added continent bonuses. * 03.17.94 ESF Factored out X code so that this could be more general. * 03.17.94 ESF Fixed bug, player indicator broken for remote case. * 03.17.94 ESF Added fPlayingRemotely setting. * 03.18.94 ESF Completed MSG_UPDATEARMIES code. * 03.28.94 ESF Added code for MSG_ENDOFGAME and MSG_DEADPLAYER. * 03.29.94 ESF Added code for MSG_CARDPACKET. * 03.29.94 ESF Fixed bug in handling on MSG_UPDATEARMIES. * 03.29.94 ESF Added handling for MSG_REPLYPACKET. * 04.11.94 ESF Added handling for MSG_CARDPACKET. * 05.12.94 ESF Added handling for MSG_DELETEMSGDST. * 05.17.94 ESF Added handling for MSG_NETMESSAGE. * 05.19.94 ESF Added verbose message when exit occurs. * 08.28.94 ESF Added handling for MSG_POPUPREGISTERBOX. * 09.01.94 ESF Added handling for MSG_NETPOPUP. * 10.29.94 ESF Added handling for MSG_DICEROLL. * 10.29.94 ESF Added handling for MSG_MOVENOTIFY. * 10.29.94 ESF Added handling for MSG_ATTACKNOTIFY. * 10.29.94 ESF Added handling for MSG_PLACEROLL. * 01.15.95 ESF Removed handling for MSG_DELETEMSGDST. * 24.08.95 JC Added handling for MSG_MISSION. * 25.08.95 JC new game if MSG_ENDOFGAME and winner is -1. * 25.08.95 JC Start the game only after a fortification. * 28.08.95 JC Added handling for MSG_ENDOFMISSION, MSG_VICTORY. * Now MSG_ENDOFGAME => new game * PURPOSE: * NOTES: ************************************************************************/ void CBK_IncomingMessage(Int32 iMessType, void *pvMess) { switch(iMessType) { case MSG_NOMESSAGE: /* NoOp */ break; case MSG_NETMESSAGE: UTIL_DisplayComment(((MsgNetMessage *)(pvMess))->strMessage); break; case MSG_PLACENOTIFY: { /* Copy the message, since we are using it for a while */ MsgPlaceNotify *msgMess = (MsgPlaceNotify *)MEM_Alloc(sizeof(MsgPlaceNotify)); memcpy((void *)msgMess, (void *)pvMess, sizeof(MsgPlaceNotify)); /* Do the notification, and then add a timeout for erasing it */ UTIL_PlaceNotification((XtPointer)msgMess, NULL); XtAppAddTimeOut(appContext, NOTIFY_TIME, UTIL_PlaceNotification, msgMess); } break; case MSG_MOVENOTIFY: { /* Copy the message, since we are using it for a while */ MsgMoveNotify *msgMess = (MsgMoveNotify *)MEM_Alloc(sizeof(MsgMoveNotify)); memcpy((void *)msgMess, (void *)pvMess, sizeof(MsgMoveNotify)); /* Do the notification, and then add a timeout for erasing it */ UTIL_MoveNotification((XtPointer)msgMess, NULL); XtAppAddTimeOut(appContext, NOTIFY_TIME, UTIL_MoveNotification, msgMess); } break; case MSG_ATTACKNOTIFY: { /* Copy the message, since we are using it for a while */ MsgAttackNotify *msgMess = (MsgAttackNotify *)MEM_Alloc(sizeof(MsgAttackNotify)); memcpy((void *)msgMess, (void *)pvMess, sizeof(MsgAttackNotify)); /* Do the notification, and then add a timeout for erasing it */ UTIL_AttackNotification((XtPointer)msgMess, NULL); XtAppAddTimeOut(appContext, NOTIFY_TIME, UTIL_AttackNotification, msgMess); } break; case MSG_DICEROLL: { MsgDiceRoll *pmsgDiceRoll = (MsgDiceRoll *)pvMess; /* Set the dice colors to be the correct ones */ COLOR_CopyColor(COLOR_PlayerToColor(iCurrentPlayer), COLOR_DieToColor(0)); COLOR_CopyColor(COLOR_PlayerToColor(pmsgDiceRoll->iDefendingPlayer), COLOR_DieToColor(1)); /* Erase what was there, and then display the dice */ DICE_Hide(); DICE_DrawDice(pmsgDiceRoll->pAttackDice, pmsgDiceRoll->pDefendDice); } break; case MSG_NETPOPUP: { #ifdef ENGLISH (void)UTIL_PopupDialog("Message from Server", ((MsgNetPopup *)pvMess)->strMessage, 1, "Ok", NULL, NULL); #endif #ifdef FRENCH (void)UTIL_PopupDialog("Message du Serveur", ((MsgNetPopup *)pvMess)->strMessage, 1, "Oui", NULL, NULL); #endif } break; case MSG_POPUPREGISTERBOX: { /* Clear any text... */ UTIL_DisplayError(""); UTIL_DisplayComment(""); REG_PopupDialog(); } break; case MSG_FORCEEXCHANGECARDS: { if (iState != STATE_REGISTER) { if (((MsgForceExchangeCards *)pvMess)->iPlayer >= 0) { #ifdef ENGLISH UTIL_DisplayComment("You have too many cards" " and must exchange a set."); #endif #ifdef FRENCH UTIL_DisplayComment("Vous avez trop de cartes" " et devez échanger"); #endif fForceExchange = fCanExchange = TRUE; CBK_ShowCards((Widget)NULL, (XtPointer)NULL, (XtPointer)NULL); iState = STATE_PLACE; UTIL_ServerEnterState(iState); } } } break; case MSG_REPLYPACKET: iReply = ((MsgReplyPacket *)pvMess)->iReply; break; case MSG_ENDOFMISSION: { MsgEndOfMission *pmsgEndOfMission = (MsgEndOfMission *)pvMess; Int32 iWinner = pmsgEndOfMission->iWinner; D_Assert(iWinner >= 0 && iWinner < MAX_PLAYERS, "Bogus Winner!"); /* Print out a final message */ GAME_MissionAccomplied(iWinner, pmsgEndOfMission->iTyp, pmsgEndOfMission->iNum1, pmsgEndOfMission->iNum2); } break; case MSG_VICTORY: { Int32 iWinner = ((MsgVictory *)pvMess)->iWinner; D_Assert(iWinner >= 0 && iWinner < MAX_PLAYERS, "Bogus Winner!"); /* Print out a final message */ GAME_Victory(iWinner); } break; case MSG_ENDOFGAME: { /* Set the cursor so that the client doesn't have * the icon of the hourglass by any chance, because * it doesn't really make sense. */ UTIL_SetCursorShape(CURSOR_PLAY); /* Print out a final message */ fHaveSeenFirstPlayer = FALSE; GAME_GameOverMan(); } break; case MSG_MESSAGEPACKET: { MsgMessagePacket *pMess = (MsgMessagePacket *)pvMess; UTIL_DisplayMessage(pMess->iFrom, pMess->iTo, pMess->strMessage); } break; case MSG_TURNNOTIFY: { #ifdef ASSERTIONS Int32 i; #endif MsgTurnNotify *pTurn = (MsgTurnNotify *)pvMess; iCurrentPlayer = pTurn->iPlayer; if(!fHaveSeenFirstPlayer) { fHaveSeenFirstPlayer = TRUE; iFirstPlayer = iCurrentPlayer; } /* Set the color of the player color-coded indicator */ GUI_SetColorOfCurrentPlayer(COLOR_PlayerToColor(iCurrentPlayer)); if (pTurn->iClient == CLNT_GetThisClientID()) { fPlayingRemotely = FALSE; /* Set the cursor to indicate play */ UTIL_SetCursorShape(CURSOR_PLAY); /* See if everyone has finished fortifying their territories. * If they have not, then there is a serious problem. */ if (!fGameStarted && (iState == STATE_FORTIFY) && (RISK_GetNumArmiesOfPlayer(iCurrentPlayer) == 0)) { fGameStarted = TRUE; iCountryToFortify = -1; #ifdef ASSERTIONS /* Sanity check */ for (i=0; i!=RISK_GetNumLivePlayers(); i++) { Int32 iPlayer = RISK_GetNthLivePlayer(i); Int32 iFirstAttacker; Int32 j; D_Assert(RISK_GetNumArmiesOfPlayer(iPlayer)>=0, "Bogus number of armies."); D_Assert(RISK_GetNumArmiesOfPlayer(iPlayer) == 0, "This player has armies and shouldn't!"); /* I not entirely sure this correct. But it's at least a * little better than before. People who have already had * their first turn are allowed to have cards. --Pac */ for(j=0;j!=RISK_GetNumLivePlayers();++j) if(RISK_GetNthLivePlayer(j)==iFirstPlayer) break; D_Assert(j!=RISK_GetNumLivePlayers(), "first player isn't alive?"); /* negative % positive = negative, unfortunately */ iFirstAttacker=j-NUM_COUNTRIES%RISK_GetNumLivePlayers(); while(iFirstAttacker<0) iFirstAttacker+=RISK_GetNumLivePlayers(); iFirstAttacker=RISK_GetNthLivePlayer(iFirstAttacker); D_Assert(iPlayer < iCurrentPlayer || iPlayer >= iFirstAttacker || RISK_GetNumCardsOfPlayer(iPlayer) == 0, "This player has cards and shouldn't!"); } #endif } if (fGameStarted) { /* Force the player to exchange if he or she possesses * 5 cards or more. */ if (RISK_GetNumCardsOfPlayer(iCurrentPlayer) >= 5) { #ifdef ENGLISH UTIL_DisplayComment("You have more than five cards" " and must exchange a set."); #endif #ifdef FRENCH UTIL_DisplayComment("Vous avez plus de cinq cartes" " et devez échanger"); #endif fForceExchange = TRUE; CBK_ShowCards((Widget)NULL, (XtPointer)NULL, (XtPointer)NULL); } /* Go into placing state, give the player as many armies as * he or she deserves by dividing the total number of * countries owned divided by 3, for a minimum of three * armies. */ iState = STATE_PLACE; UTIL_ServerEnterState(iState); /* All of the armies should have been used up */ D_Assert(RISK_GetNumArmiesOfPlayer(iCurrentPlayer) == 0, "Number of armies should be 0!"); GAME_SetTurnArmiesOfPlayer(iCurrentPlayer); } else if (iState == STATE_FORTIFY) { UTIL_ServerEnterState(iState); if (iCountryToFortify != -1) { GAME_PlaceClick(iCountryToFortify, PLACE_ONE); iCountryToFortify = -1; UTIL_DisplayError(""); } } UTIL_DisplayActionCString(iState, iCurrentPlayer); } else { char buf[256]; fPlayingRemotely = TRUE; /* Set the cursor to indicate waiting */ UTIL_SetCursorShape(CURSOR_WAIT); #ifdef ENGLISH snprintf(buf, sizeof(buf), "%s is playing remotely...", #endif #ifdef FRENCH snprintf(buf, sizeof(buf), "%s joue à distance...", #endif RISK_GetNameOfPlayer(iCurrentPlayer)); UTIL_DisplayComment(buf); } } break; case MSG_EXIT: /* Popup telling what happened */ #ifdef ENGLISH (void)UTIL_PopupDialog("Exit Notification", "Terminating game! Goodbye...", 1, "Ok", NULL, NULL); #endif #ifdef FRENCH (void)UTIL_PopupDialog("Notification d'abandon", "Jeu terminé! Au revoir...", 1, "Ok", NULL, NULL); #endif close(CLNT_GetCommLinkOfClient(CLNT_GetThisClientID())); CLNT_SetCommLinkOfClient(CLNT_GetThisClientID(), -1); UTIL_ExitProgram(0); break; case MSG_MISSION: { Int32 iPlayer; if (!fWaitMission) { if (UTIL_PlayerIsLocal(iCurrentPlayer)) iPlayer = iCurrentPlayer; else if (UTIL_NumPlayersAtClient(CLNT_GetThisClientID()) == 1) iPlayer = RISK_GetNthPlayerAtClient(CLNT_GetThisClientID(), 0); else iPlayer = -1; if (iPlayer != -1) { GAME_ShowMission(iPlayer); #ifdef ENGLISH (void)UTIL_PopupDialog("Mission Notification", "The mission is visible in the " "message zone", 1, "Ok", NULL, NULL); #endif #ifdef FRENCH (void)UTIL_PopupDialog("Notification de mission", "La mission est visible dans la " "zone de message", 1, "Oui", NULL, NULL); #endif } else /* Popup telling what happened */ #ifdef ENGLISH (void)UTIL_PopupDialog("Mission Notification", "To view your mission, click on\n" " mission's button", 1, "Ok", NULL, NULL); #endif #ifdef FRENCH (void)UTIL_PopupDialog("Notification de mission", "Pour voir la mission, il faut \n" "utiliser le bouton mission", 1, "Oui", NULL, NULL); #endif } } break; default: { char buf[256]; #ifdef ENGLISH snprintf(buf, sizeof(buf), "CALLBACKS: Unhandled message (%d)", iMessType); (void)UTIL_PopupDialog("Fatal Error", buf, 1, "Ok", NULL, NULL); #endif #ifdef FRENCH snprintf(buf, sizeof(buf), "CALLBACKS: message non géré(%d)", iMessType); (void)UTIL_PopupDialog("Erreur fatale", buf, 1, "Ok", NULL, NULL); #endif RISK_SendMessage(CLNT_GetCommLinkOfClient(CLNT_GetThisClientID()), MSG_DEREGISTERCLIENT, NULL); UTIL_ExitProgram(-1); } } } /************************************************************************ * FUNCTION: CBK_RefreshMap * HISTORY: * 01.27.94 ESF Created. * 01.28.94 ESF Changed to work with pixmap. * PURPOSE: * NOTES: ************************************************************************/ void CBK_RefreshMap(Widget w, XtPointer pData, XtPointer pCalldata) { XExposeEvent *pExpose = (XExposeEvent *)pCalldata; UNUSED(w); UNUSED(pData); XCopyArea(hDisplay, pixMapImage, hWindow, hGC, pExpose->x, pExpose->y, pExpose->width, pExpose->height, pExpose->x, pExpose->y); } #define DOUBLE_CLICK_TIME 300 /************************************************************************ * FUNCTION: CBK_MapClick * HISTORY: * 01.27.94 ESF Created * 02.03.94 ESF Don't allocate colors in order, use mapping. * 03.03.94 ESF Added some game glue. * 03.07.94 ESF Made a lean, mean, fighting function. Look in game.c. * 03.17.94 ESF Fixed remote case. * 05.10.94 ESF Fixed to do nothing unless game has started. * 10.02.94 ESF Added PLACE_ALL option. * 06.09.95 JC Remember on click in fortify mode. * 12.29.96 BPK Added multiple armies placement in fortification * 01.17.00 ThH Now GAME_PlaceClick decides about number placed during fortify * PURPOSE: * NOTES: Handle click on map ************************************************************************/ void CBK_MapClick(Widget w, XEvent *pEvent, String *str, Cardinal *card) { Int32 x, y, iCountry; char buf[256]; UNUSED(w); UNUSED(str); UNUSED(card); if (iState == STATE_REGISTER) return; /* Find out the coordinates and time of the mouse click */ x = pEvent->xbutton.x; y = pEvent->xbutton.y; /* Find out what country was clicked on */ iCountry = COLOR_ColorToCountry(XGetPixel(pMapImage, x, y)); if (fPlayingRemotely) { if ( (UTIL_NumPlayersAtClient(CLNT_GetThisClientID()) == 1) && (iState == STATE_FORTIFY) && (iCountry < NUM_COUNTRIES)) { if (iCountryToFortify == -1) { iCountryToFortify = iCountry; snprintf(buf, sizeof(buf), "%s %s", RISK_GetNameOfCountry(iCountryToFortify), TXT_BE_FORTIFIED); UTIL_DisplayError(buf); return; } } #ifdef ENGLISH snprintf(buf, sizeof(buf), "Click as you may, it's %s's turn...", #endif #ifdef FRENCH snprintf(buf, sizeof(buf), "Jouez avec le bouton, mais c'est le tour de %s...", #endif RISK_GetNameOfPlayer(iCurrentPlayer)); UTIL_DisplayError(buf); return; } /* Erase previous errors */ UTIL_DisplayError(""); switch (iState) { case STATE_FORTIFY: /* * Changed so we can place multiple armies during fortification * -- BPK * -- TdH GAME_PlaceClick takes care of it now * instead fall through */ case STATE_PLACE: if (pEvent->xbutton.button == Button1) GAME_PlaceClick(iCountry, PLACE_ONE); else if (pEvent->xbutton.button == Button2) GAME_PlaceClick(iCountry, PLACE_ALL); else if (pEvent->xbutton.button == Button3) GAME_PlaceClick(iCountry, PLACE_MULTIPLE); break; case STATE_ATTACK: GAME_AttackClick(iCountry); break; case STATE_MOVE: GAME_MoveClick(iCountry); break; default: D_Assert(FALSE, "Shouldn't be here!"); } } /************************************************************************ * FUNCTION: CBK_Quit * HISTORY: * 01.29.94 ESF Created * 04.02.94 ESF Added confirmation. * 08.28.94 ESF Fixed to implement cleaner exit. * 15.01.00 MSH Fixed to include Cancel button in English dialog * PURPOSE: * NOTES: ************************************************************************/ void CBK_Quit(Widget w, XtPointer pData, XtPointer call_data) { Int32 rep; UNUSED(w); UNUSED(pData); UNUSED(call_data); #ifdef ENGLISH rep = UTIL_PopupDialog("Quit", "Quit Frisk or new game?", 3, "Quit", "New", "Cancel"); #endif #ifdef FRENCH rep = UTIL_PopupDialog("Quit", "Quitter Frisk ou nouvelle partie?", 3, "Quitter", "Nouvelle", "Annuler"); #endif switch (rep) { case QUERY_YES: { UTIL_ExitProgram(0); } case QUERY_NO: { iState = STATE_REGISTER; (void)RISK_SendMessage(CLNT_GetCommLinkOfClient(CLNT_GetThisClientID()), MSG_ENDOFGAME, NULL); } } } /************************************************************************ * FUNCTION: CBK_ShowCards * HISTORY: * 02.19.94 ESF Created. * 03.17.94 ESF Erase the error display. * 05.04.94 ESF Fixed so that only the owner can see his or her cards. * 05.10.94 ESF Fixed to do nothing unless game has started. * 05.12.94 ESF Fixed to display correct cards. * PURPOSE: * NOTES: ************************************************************************/ void CBK_ShowCards(Widget w, XtPointer pData, XtPointer call_data) { Int32 i, iPlayer; UNUSED(w); UNUSED(pData); UNUSED(call_data); #ifdef CARD_DEBUG static Int32 j; #endif if (iState == STATE_REGISTER) return; UTIL_DisplayError(""); /* If the player clicking is the current player, show cards, otherwise, * if there's more than one player at the client, issue an error, unless * there's only one, in which case show his or her cards. */ if (UTIL_PlayerIsLocal(iCurrentPlayer)) iPlayer = iCurrentPlayer; else if (UTIL_NumPlayersAtClient(CLNT_GetThisClientID()) == 1) iPlayer = RISK_GetNthPlayerAtClient(CLNT_GetThisClientID(), 0); else { iPlayer = -1; #ifdef ENGLISH (void)UTIL_PopupDialog("Error", "Wait until your turn!", 1, "Ok", "Cancel", NULL); #endif #ifdef FRENCH (void)UTIL_PopupDialog("Erreur", "Il faut attendre son tour!", 1, "Ok", "Annule", NULL); #endif } /* If it's valid, display cards */ if (iPlayer >= 0) { XtPopup(wCardShell, XtGrabExclusive); #ifdef CARD_DEBUG for (i=0; i!=MAX_CARDS; i++) { CARD_RenderCard(j, i); j = (++j) % NUM_CARDS; } #else for (i=0; i!=RISK_GetNumCardsOfPlayer(iPlayer); i++) CARDS_RenderCard(RISK_GetCardOfPlayer(iPlayer, i), i); #endif } } /************************************************************************ * FUNCTION: CBK_CancelCards * HISTORY: * 02.19.94 ESF Created. * 03.17.94 ESF Added clearing of selections and unmappings. * 04.01.94 ESF Fixed clearing of error when player cancels. * 04.11.94 ESF Added not popping down the shell when !fForceExchange. * PURPOSE: * NOTES: ************************************************************************/ void CBK_CancelCards(Widget w, XtPointer pData, XtPointer call_data) { Int32 i; UNUSED(w); UNUSED(pData); UNUSED(call_data); if (fForceExchange == TRUE) #ifdef ENGLISH (void)UTIL_PopupDialog("Error", "You must exchange cards!", 1, "Ok", NULL, NULL); #endif #ifdef FRENCH (void)UTIL_PopupDialog("Erreur", "Il faut échanger des cartes!", 1, "Ok", NULL, NULL); #endif else { UTIL_DisplayError(""); XtPopdown(wCardShell); /* Unmap the cards and clear the selections */ for (i=0; i!=MAX_CARDS; i++) { XtUnmanageChild(wCardToggle[i]); XtVaSetValues(wCardToggle[i], XtNstate, False, NULL); } } } /************************************************************************ * FUNCTION: CBK_ShowMission * HISTORY: * 16.08.95 JC Created. * PURPOSE: * NOTES: ************************************************************************/ void CBK_ShowMission(Widget w, XtPointer pData, XtPointer call_data) { Int32 iPlayer; UNUSED(w); UNUSED(pData); UNUSED(call_data); if (iState == STATE_REGISTER) return; UTIL_DisplayError(""); /* If the player clicking is the current player, show cards, otherwise, * if there's more than one player at the client, issue an error, unless * there's only one, in which case show his or her cards. */ if (UTIL_PlayerIsLocal(iCurrentPlayer)) iPlayer = iCurrentPlayer; else if (UTIL_NumPlayersAtClient(CLNT_GetThisClientID()) == 1) iPlayer = RISK_GetNthPlayerAtClient(CLNT_GetThisClientID(), 0); else { iPlayer = -1; #ifdef ENGLISH (void)UTIL_PopupDialog("Error", "Wait until your turn!", 1, "Ok", NULL, NULL); #endif #ifdef FRENCH (void)UTIL_PopupDialog("Erreur", "Il faut attendre son tour!", 1, "Ok", NULL, NULL); #endif } /* If it's valid, display mission */ if (iPlayer >= 0) { if (RISK_GetMissionTypeOfPlayer(iPlayer) == NO_MISSION) { #ifdef ENGLISH if(UTIL_PopupDialog("Mission", "Play with a mission?", 2, "Ok", "Cancel", NULL) == QUERY_NO) #endif #ifdef FRENCH if(UTIL_PopupDialog("Mission", "Jouer avec une mission?", 2, "Oui", "Annule", NULL) == QUERY_NO) #endif return; fWaitMission = TRUE; (void)RISK_SendSyncMessage(CLNT_GetCommLinkOfClient(CLNT_GetThisClientID()), MSG_MISSION, NULL, MSG_MISSION, CBK_IncomingMessage); fWaitMission = FALSE; } GAME_ShowMission(iPlayer); } } /************************************************************************ * FUNCTION: CBK_Attack * HISTORY: * 03.03.94 ESF Stubbed. * 03.05.94 ESF Coded. * 05.07.94 ESF Modified to work with Distributed RiskGame Object. * 05.10.94 ESF Fixed to do nothing unless game has started. * 05.19.94 ESF Fixed bug, not refering to DiceMode. * 10.15.94 ESF Added flexibility. * 01.17.95 ESF Free pItem. * PURPOSE: * NOTES: ************************************************************************/ void CBK_Attack(Widget w, XtPointer pData, XtPointer call_data) { XawListReturnStruct *pItem; UNUSED(w); UNUSED(pData); UNUSED(call_data); if (iState == STATE_REGISTER) return; /* Don't do anything if current player is not local and there is not * one player at this client. */ if (UTIL_PlayerIsLocal(iCurrentPlayer) == FALSE) return; /* I know this is silly, but hey... (We should get the data from pData?) */ pItem = XawListShowCurrent(wAttackList); RISK_SetDiceModeOfPlayer(iCurrentPlayer, pItem->list_index); /* Free up memory */ XtFree((void *)pItem); } /************************************************************************ * FUNCTION: CBK_Action * HISTORY: * 03.03.94 ESF Stubbed. * 03.05.94 ESF Coded. * 03.29.94 ESF Added player attack mode history. * 05.07.94 ESF Modified to work with Distributed RiskGame Object. * 05.10.94 ESF Fixed to do nothing unless game has started. * 11.19.94 ESF Added a few UTIL_DisplayError("")'s, where needed. * 01.17.95 ESF Free pItem. * PURPOSE: * NOTES: ************************************************************************/ void CBK_Action(Widget w, XtPointer pData, XtPointer call_data) { XawListReturnStruct *pItem; UNUSED(w); UNUSED(pData); UNUSED(call_data); if (iState == STATE_REGISTER) return; /* Don't do anything if current player is not local */ if (!UTIL_PlayerIsLocal(iCurrentPlayer)) return; /* I know this is silly, but hey... (We should get the data from pData?) */ pItem = XawListShowCurrent(wActionList); switch (pItem->list_index) { /*****************/ case ACTION_PLACE: /*****************/ if (iState == STATE_PLACE || iState == STATE_FORTIFY) { UTIL_DisplayError(""); iActionState = pItem->list_index; } else /* Invalid */ { #ifdef ENGLISH UTIL_DisplayError("You've already placed your armies."); #endif #ifdef FRENCH UTIL_DisplayError("Toutes vos armées sont déjà placée."); #endif XawListHighlight(wActionList, ACTION_ATTACK); } break; /*******************/ case ACTION_ATTACK: case ACTION_DOORDIE: /*******************/ if (iState == STATE_ATTACK) { UTIL_DisplayError(""); iActionState = pItem->list_index; /* Keep track of the type of attack selected */ RISK_SetAttackModeOfPlayer(iCurrentPlayer, pItem->list_index); } else if (iState == STATE_PLACE || iState == STATE_FORTIFY) { #ifdef ENGLISH UTIL_DisplayError("You must finish placing your armies."); #endif #ifdef FRENCH UTIL_DisplayError("Il faut finir de placer vos armées."); #endif XawListHighlight(wActionList, ACTION_PLACE); } else if (iState == STATE_MOVE) /* Must not have moved yet */ { /* Keep track of the type of attack selected */ RISK_SetAttackModeOfPlayer(iCurrentPlayer, pItem->list_index); iState = STATE_ATTACK; UTIL_DisplayError(""); UTIL_ServerEnterState(iState); UTIL_DisplayActionCString(iState, iCurrentPlayer); } break; /****************/ case ACTION_MOVE: /****************/ if (iState == STATE_MOVE) { UTIL_DisplayError(""); iActionState = pItem->list_index; } else if (iState == STATE_FORTIFY || iState == STATE_PLACE) { #ifdef ENGLISH UTIL_DisplayError("You must finish placing your armies."); #endif #ifdef FRENCH UTIL_DisplayError("Il faut finir de placer vos armées."); #endif XawListHighlight(wActionList, ACTION_PLACE); } else /* STATE_ATTACK */ { iState = STATE_MOVE; UTIL_DisplayError(""); UTIL_ServerEnterState(iState); UTIL_DisplayActionCString(iState, iCurrentPlayer); } break; default: D_Assert(FALSE, "Shouldn't be here -- bogus state!"); } /* Free up memory */ XtFree((void *)pItem); } /************************************************************************ * FUNCTION: CBK_MsgDest * HISTORY: * 03.03.94 ESF Stubbed. * 05.07.94 ESF Created and modified to work with Distributed Object. * 05.19.94 ESF Fixed a bug, wasn't refering to MsgDestList. * 01.17.95 ESF Free pItem. * PURPOSE: * NOTES: ************************************************************************/ void CBK_MsgDest(Widget w, XtPointer pData, XtPointer call_data) { XawListReturnStruct *pItem; Int32 iPlayer; UNUSED(w); UNUSED(pData); UNUSED(call_data); if (UTIL_PlayerIsLocal(iCurrentPlayer)) iPlayer = iCurrentPlayer; else if (UTIL_NumPlayersAtClient(CLNT_GetThisClientID()) == 1) iPlayer = RISK_GetNthPlayerAtClient(CLNT_GetThisClientID(), 0); else iPlayer = -1; if (iPlayer == -1) return; /* I know this is silly, but hey... (We should get the data from pData?) */ pItem = XawListShowCurrent(wMsgDestList); RISK_SetMsgDstModeOfPlayer(iPlayer, pItem->list_index); /* Free up memory */ XtFree((void *)pItem); } /************************************************************************ * FUNCTION: CBK_SendMessage * HISTORY: * 05.03.94 ESF Created. * 05.04.94 ESF Enhanced. * 10.02.94 ESF Moved here and fixed a few (serious) bugs. * 01.09.95 ESF Changed to name sender if current player on client. * 01.17.95 ESF Free pItem. * 29.08.95 JC strFrom -> iFrom, iTo now contain the iPlayer. * PURPOSE: * NOTES: ************************************************************************/ void CBK_SendMessage(void) { CString strMess; XawListReturnStruct *pItem; MsgMessagePacket mess; /* Get the message and destination from widgets */ XtVaGetValues(wSendMsgText, XtNstring, &strMess, NULL); pItem = XawListShowCurrent(wMsgDestList); /* Who's sending the message? */ if (UTIL_NumPlayersAtClient(CLNT_GetThisClientID()) == 1) mess.iFrom = RISK_GetNthPlayerAtClient(CLNT_GetThisClientID(), 0); else if (RISK_GetClientOfPlayer(iCurrentPlayer) == CLNT_GetThisClientID()) mess.iFrom = iCurrentPlayer; else mess.iFrom = FROM_UNKNOW; /* Who do we send the message to? */ if (pItem->list_index == -1 || pItem->list_index == 0) mess.iTo = DST_ALLPLAYERS; else { mess.iTo = piMsgDstPlayerID[pItem->list_index]; D_Assert(mess.iTo!=-1, "Bogus player!"); } mess.strMessage = strMess; /* Display the message locally if necessary */ if (mess.iTo != DST_ALLPLAYERS && RISK_GetClientOfPlayer(mess.iTo) != CLNT_GetThisClientID()) { UTIL_DisplayMessage(mess.iFrom, mess.iTo, mess.strMessage); } /* Send the message */ (void)RISK_SendMessage(CLNT_GetCommLinkOfClient(CLNT_GetThisClientID()), MSG_MESSAGEPACKET, &mess); /* Erase the old message */ XtVaSetValues(wSendMsgText, XtNstring, "", NULL); /* Free up memory */ XtFree((void *)pItem); } /************************************************************************ * FUNCTION: CBK_CancelAttack * HISTORY: * 03.03.94 ESF Stubbed. * 03.04.94 ESF Coded. * 05.10.94 ESF Fixed to do nothing unless game has started. * PURPOSE: * NOTES: ************************************************************************/ void CBK_CancelAttack(Widget w, XtPointer pData, XtPointer call_data) { UNUSED(w); UNUSED(pData); UNUSED(call_data); if (iState == STATE_REGISTER) return; if (fPlayingRemotely) { #ifdef ENGLISH UTIL_DisplayError("Nice try, but it isn't your turn..."); #endif #ifdef FRENCH UTIL_DisplayError("Bien essayé, mais ce n'est pas votre tour..."); #endif return; } UTIL_DisplayError(""); if (iState == STATE_ATTACK) { if (GAME_AttackFrom() >=0) UTIL_DarkenCountry(GAME_AttackFrom()); GAME_SetAttackSrc(-1); } else if (iState == STATE_MOVE) { if (iMoveSrc >=0) UTIL_DarkenCountry(iMoveSrc); iMoveSrc = -1; } UTIL_DisplayActionCString(iState, iCurrentPlayer); } /************************************************************************ * FUNCTION: CBK_Repeat * HISTORY: * 03.03.94 ESF Stubbed. * 03.06.94 ESF Coded. * 03.07.94 ESF Fixed state bug. * 03.08.94 ESF Added DOORDIE recognition. * 03.16.94 ESF Fixed bug in DOORDIE. * 04.02.94 ESF Added server notification caching for do-or-die. * 05.10.94 ESF Fixed to do nothing unless game has started. * 05.19.94 ESF Added verbose message across network. * PURPOSE: * NOTES: ************************************************************************/ void CBK_Repeat(Widget w, XtPointer pData, XtPointer call_data) { MsgNetMessage mess; char buf[256]; UNUSED(w); UNUSED(pData); UNUSED(call_data); if (iState == STATE_REGISTER) return; if (fPlayingRemotely) { #ifdef ENGLISH snprintf(buf, sizeof(buf), "I'm afraid that's up to %s to decide...", #endif #ifdef FRENCH snprintf(buf, sizeof(buf), "Je suis effrayé par ce que vous décidez pour %s...", #endif RISK_GetNameOfPlayer(iCurrentPlayer)); UTIL_DisplayError(buf); return; } if (iState != STATE_ATTACK) #ifdef ENGLISH UTIL_DisplayError("You can't do any attacking at the moment."); #endif #ifdef FRENCH UTIL_DisplayError("Il n'y a rien à faire pour l'instant."); #endif else if (iActionState == ACTION_ATTACK || iActionState == ACTION_DOORDIE) { if (iLastAttackSrc == -1 || iLastAttackDst == -1) { #ifdef ENGLISH UTIL_DisplayError("You can't repeat an uncomplete attack."); #endif #ifdef FRENCH UTIL_DisplayError("Impossible de répéter une attaque incomplète."); #endif return; } /* send a verbose message */ #ifdef ENGLISH snprintf(buf, sizeof(buf), "%s is attacking from %s to %s", RISK_GetNameOfPlayer(iCurrentPlayer), RISK_GetNameOfCountry(iLastAttackSrc), RISK_GetNameOfCountry(iLastAttackDst)); #endif #ifdef FRENCH snprintf(buf, sizeof(buf), "%s attaque %s depuis %s", RISK_GetNameOfPlayer(iCurrentPlayer), RISK_GetNameOfCountry(iLastAttackDst), RISK_GetNameOfCountry(iLastAttackSrc)); #endif mess.strMessage = buf; (void)RISK_SendMessage(CLNT_GetCommLinkOfClient(CLNT_GetThisClientID()), MSG_NETMESSAGE, &mess); /* Repeat the attack */ GAME_Attack(iLastAttackSrc, iLastAttackDst); } } /************************************************************************ * FUNCTION: CBK_Help * HISTORY: * 04.01.94 ESF Coded. * PURPOSE: * NOTES: ************************************************************************/ void CBK_Help(Widget w, XtPointer pData, XtPointer call_data) { Int32 x, y; UNUSED(w); UNUSED(pData); UNUSED(call_data); /* Center popup */ UTIL_CenterShell(wHelpShell, wToplevel, &x, &y); XtVaSetValues(wHelpShell, XtNallowShellResize, False, XtNx, x, XtNy, y, XtNborderWidth, 1, #ifdef ENGLISH XtNtitle, "Frisk Help", #endif #ifdef FRENCH XtNtitle, "Aide de frisk", #endif NULL); XtPopup(wHelpShell, XtGrabNone); } /************************************************************************ * FUNCTION: CBK_HelpSelectTopic * HISTORY: * 04.01.94 ESF Coded. * 01.17.95 ESF Free pItem. * PURPOSE: * NOTES: ************************************************************************/ void CBK_HelpSelectTopic(Widget w, XtPointer pData, XtPointer call_data) { XawListReturnStruct *pItem; UNUSED(w); UNUSED(pData); UNUSED(call_data); /* I know this is sill, but hey... (We should get the data from pData) */ pItem = XawListShowCurrent(wHelpTopicList); HELP_IndexPopupHelp(pItem->list_index); /* Free up memory */ XtFree((void *)pItem); } /************************************************************************ * FUNCTION: CBK_HelpOk * HISTORY: * 04.01.94 ESF Coded. * PURPOSE: * NOTES: ************************************************************************/ void CBK_HelpOk(Widget w, XtPointer pData, XtPointer call_data) { UNUSED(w); UNUSED(pData); UNUSED(call_data); XtPopdown(wHelpShell); } /************************************************************************ * FUNCTION: CBK_ExchangeCards * HISTORY: * 03.03.94 ESF Stubbed. * 03.29.94 ESF Coded. * 05.03.94 ESF Fixed for when the player has many cards. * 02.21.95 ESF Fixed a bug -- only current player may exchange. * PURPOSE: * NOTES: ************************************************************************/ void CBK_ExchangeCards(Widget w, XtPointer pData, XtPointer call_data) { Int32 i, iNumCardsSelected; Flag iCardState; Int32 piCards[3], piCardValues[3], piCardTypes[3]; UNUSED(w); UNUSED(pData); UNUSED(call_data); /* If it's not the current player, then don't let the exchange * take place. This fixes a nasty bug reported by many. */ if (RISK_GetClientOfPlayer(iCurrentPlayer) != CLNT_GetThisClientID()) UTIL_DisplayError(TXT_ONLY_CURRENT); /* Get the cards that have been pressed, check for validity */ for (i=iNumCardsSelected=0; i!=MAX_CARDS; i++) { XtVaGetValues(wCardToggle[i], XtNstate, &iCardState, NULL); if (iCardState == True) { if (iNumCardsSelected<3) piCards[iNumCardsSelected] = i; iNumCardsSelected++; } } /* Clear the selections of the cards */ for (i=0; i!=MAX_CARDS; i++) XtVaSetValues(wCardToggle[i], XtNstate, False, NULL); /* Valid number of cards selected */ if (fCanExchange == FALSE) { #ifdef ENGLISH UTIL_DisplayError("You can only exchange cards at the beginning of " "your turn."); #endif #ifdef FRENCH UTIL_DisplayError("Les cartes ne sont échangeables qu'au début de " "votre tour."); #endif return; } else if (iNumCardsSelected!=3) { #ifdef ENGLISH UTIL_DisplayError("You must select three cards to exchange."); #endif #ifdef FRENCH UTIL_DisplayError("Il faut sélectionner trois cartes pour pouvoir " "échanger."); #endif return; } /* Substitute the indices for the card values */ for (i=0; i!=3; i++) { piCardValues[i] = RISK_GetCardOfPlayer(iCurrentPlayer, piCards[i]); /* Set the type of the card */ if (piCardValues[i]iField) { case CNT_OWNER: { /* Recolor the country */ if (pMess->iNewValue >= 0) COLOR_ColorCountry(pMess->iIndex1, pMess->iNewValue); } break; case CNT_NUMARMIES: { /* Redraw the number of armies on the country. Since the * country may be lit up because of the notification, we * take pains not to mess with it. Check to see if it was * lit up, and if so, leave it that way. */ UTIL_PrintArmies(pMess->iIndex1, pMess->iNewValue, CLNT_GetLightCountOfCountry(pMess->iIndex1)>0 ? WhitePixel(hDisplay, 0) : BlackPixel(hDisplay, 0)); } break; case PLR_ALLOCATION: { /* If a player was killed then remove it from the MsgDst list */ if (pMess->iNewValue == ALLOC_NONE) { Int32 iDeadPlayer = pMess->iIndex1; Int32 i, iIndex; Flag fDone = FALSE; /* Search for the entry to delete it */ for (i=1; i!=iIndexMD && !fDone; i++) if (piMsgDstPlayerID[i] == iDeadPlayer) fDone = TRUE; D_Assert(fDone, "Something's wierd!"); /* Cause we want to recover somewhat if not debugging */ if (!fDone) break; /* We found the entry. Delete it and move the others down */ iIndex = (i-1); MEM_Free(pstrMsgDstCString[iIndex]); piMsgDstPlayerID[iIndex] = -1; iIndexMD--; for (i=iIndex; iiNewValue == ALLOC_COMPLETE) { /* A new player, add this to the list, update listbox */ char buf[256]; pstrMsgDstCString[iIndexMD] = (CString)MEM_Alloc(strlen( RISK_GetNameOfPlayer(pMess->iIndex1))+1); piMsgDstPlayerID[iIndexMD] = pMess->iIndex1; strcpy(pstrMsgDstCString[iIndexMD], RISK_GetNameOfPlayer(pMess->iIndex1)); UTIL_RefreshMsgDest(++iIndexMD); /* Also create a message that tells of the new player */ #ifdef ENGLISH snprintf(buf, sizeof(buf), "%s (%s) has joined.", #endif #ifdef FRENCH snprintf(buf, sizeof(buf), "%s (%s) est arrivé.", #endif RISK_GetNameOfPlayer(pMess->iIndex1), RISK_GetNameOfSpecies( RISK_GetSpeciesOfPlayer(pMess->iIndex1))); UTIL_DisplayMessage(FROM_SERVER, DST_OTHER, buf); } } break; default: /* A message that we don't care about */ ; } break; } case MSG_OBJSTRUPDATE: { MsgObjStrUpdate *pMess = (MsgObjStrUpdate *)pvMess; switch (pMess->iField) { case PLR_COLORSTRING: { /* Allocate the color */ COLOR_StoreNamedColor(pMess->strNewValue, pMess->iIndex1); } break; default: /* A message that we don't care about */ ; } } break; default: /* Nothing... */ ; } } xfrisk-1.2/callbacks.h0100644000175000017500000000555307013357406014004 0ustar johnojohno/* * XFrisk - The classic board game for X * Copyright (C) 1993-1999 Elan Feingold (elan@aetherworks.com) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * $Id: callbacks.h,v 1.5 1999/11/13 21:58:30 morphy Exp $ */ #ifndef _CALLBACKS #define _CALLBACKS #include #include #include #include "types.h" void CBK_XIncomingMessage(XtPointer pClientData, int *iSource, XtInputId *id); void CBK_IncomingMessage(Int32 iMessType, void *pvMessage); void CBK_RefreshMap(Widget w, XtPointer pData, XtPointer call_data); void CBK_RefreshDice(Widget w, XtPointer pData, XtPointer call_data); void CBK_MapClick(Widget w, XEvent *pEvent, String *str, Cardinal *card); void CBK_Quit(Widget w, XtPointer pData, XtPointer call_data); void CBK_ShowCards(Widget w, XtPointer pData, XtPointer call_data); void CBK_CancelCards(Widget w, XtPointer pData, XtPointer call_data); void CBK_ShowMission(Widget w, XtPointer pData, XtPointer call_data); void CBK_Attack(Widget w, XtPointer pData, XtPointer call_data); void CBK_Action(Widget w, XtPointer pData, XtPointer call_data); void CBK_MsgDest(Widget w, XtPointer pData, XtPointer call_data); void CBK_SendMessage(void); void CBK_CancelAttack(Widget w, XtPointer pData, XtPointer call_data); void CBK_About(Widget w, XtPointer pData, XtPointer call_data); void CBK_Repeat(Widget w, XtPointer pData, XtPointer call_data); void CBK_Help(Widget w, XtPointer pData, XtPointer call_data); void CBK_ExchangeCards(Widget w, XtPointer pData, XtPointer call_data); void CBK_EndTurn(Widget w, XtPointer pData, XtPointer call_data); void CBK_ArmiesShell(Widget w, XtPointer pData, XtPointer call_data); void CBK_HelpOk(Widget w, XtPointer pData, XtPointer call_data); void CBK_HelpSelectTopic(Widget w, XtPointer pData, XtPointer call_data); void CBK_Replicate(Int32 iMessType, void *pvMess, Int32 iType, Int32 iSrc); void CBK_Callback(Int32 iMessType, void *pvMess); extern Int32 iActionState, iCurrentPlayer; extern Int32 iState; extern Flag fGameStarted; extern Int32 iReply; extern Int32 iFirstPlayer; /* The first fortifier */ /* Relating to the message destination listbox */ extern CString pstrMsgDstCString[]; #endif xfrisk-1.2/cards.c0100644000175000017500000005374007037154271013156 0ustar johnojohno/** * XFrisk - The classic board game for X * Copyright (C) 1993-1999 Elan Feingold (elan@aetherworks.com) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * $Id: cards.c,v 1.20 2000/01/12 19:40:41 morphy Exp $ * * $Log: cards.c,v $ * Revision 1.20 2000/01/12 19:40:41 morphy * Comment changes, removed note about Argentina card color (not current anymore) * * Revision 1.19 2000/01/10 22:47:40 tony * made colorstuff more private to colormap.c, only scrollbars get set wrong, rest seems to work ok now * * Revision 1.18 2000/01/09 16:07:46 tony * wrong doxygen tags * * Revision 1.17 2000/01/08 18:38:03 tony * oops, even dumped core * * Revision 1.16 2000/01/08 17:28:03 tony * comment added * * Revision 1.15 2000/01/08 01:45:34 tony * color greenland card fixed! ? * * Revision 1.13 2000/01/04 21:41:53 tony * removed redundant stuff for jokers * * Revision 1.12 2000/01/04 21:11:06 tony * a bit more structure by using Cards[] * * Revision 1.11 1999/12/25 21:58:02 morphy * Fixed typo in doxygen file comment * * Revision 1.10 1999/12/19 22:51:09 tony * cl0d fixed greenland card * */ /** \file * Graphical part of cards handling for client */ #include #include #include #include #include #include #include #include "network.h" #include "gui-vars.h" #include "riskgame.h" #include "client.h" #include "types.h" #include "utils.h" #include "cards.h" #include "colormap.h" #include "callbacks.h" #include "debug.h" #define PICTURE_FRACTION 0.6 /* Private function */ static void _CARDS_ComputeScaleVector(Int32 *piVector, Int32 x0, Int32 y0, Int32 x1, Int32 y1); /* Private data */ /** A structure to hold the directory information */ static struct Directory { Int32 iWidth, iHeight, iLength; Int32 lOffset; } pDirectory[NUM_COUNTRIES]; /** Cards */ static struct { Pixmap pixmap; Int32 color; } Cards[NUM_CARDS]; /** Font structure for card texts */ static XFontStruct *pCardFont; /** * Initialize the set of cards, called once on start * * \b History: * \arg 27.10.99 TdH Moved out of CARDS_RenderCard */ void CARDS_Init() { int i; /* Load the font */ if ((pCardFont=XLoadQueryFont(hDisplay, "*helvetica-b*-r-*12*")) == NULL) { (void)UTIL_PopupDialog("Warning", "Could not open card font (using fixed)\n", 1, "Ok", NULL, NULL); /* Assume 'fixed' is always there -- not good. */ pCardFont = XLoadQueryFont(hDisplay, "fixed"); } /* Init the pixmap cache */ for (i=0; i!=NUM_CARDS; i++) { Cards[i].pixmap = 0L; Cards[i].color = -1; } } /** * Set color of card, create bitmap if not yet there * \b History: * \arg 05.01.00 TdH Created * * \b Notes: * Took out of CARDS_RenderCard */ void CARDS_SetColor(Int32 iCard, Int32 iColor) { XImage *pimageCountry; Int32 iPictureWidth, iPictureHeight, iPictureOffset; Int32 iFontHeight, iFontWidth; Int32 blackpixel,whitepixel; Int32 x, y, c; char buf[256]; Cards[iCard].color = iColor;/* new color */ whitepixel = WhitePixel(hDisplay, 0); blackpixel = BlackPixel(hDisplay, 0); /* Makes life easier */ iPictureWidth = CARD_WIDTH; iPictureHeight = (double)CARD_HEIGHT * PICTURE_FRACTION; iPictureOffset = CARD_HEIGHT - iPictureHeight; /* Check to see if pixmap is in cache. If not, build it */ if (Cards[iCard].pixmap == 0L) { Cards[iCard].pixmap = XCreatePixmap(hDisplay, pixMapImage, CARD_WIDTH, CARD_HEIGHT, COLOR_GetDepth()); /* Fill the card up with white and black */ XSetForeground(hDisplay, hGC, blackpixel); XFillRectangle(hDisplay, Cards[iCard].pixmap, hGC, 0, 0, CARD_WIDTH, CARD_HEIGHT); XSetForeground(hDisplay, hGC, WhitePixel(hDisplay, 0)); XFillRectangle(hDisplay, Cards[iCard].pixmap, hGC, 0, 0, CARD_WIDTH, iPictureOffset); } pimageCountry = CARDS_GetCountryImage(iCard, -1, -1); /* Compress the card image, being careful about the pointer */ pimageCountry = CARDS_ScaleImage(pimageCountry, (Int32)(4.0/5.0 * (float)iPictureWidth), (Int32)(4.0/5.0 * (float)iPictureHeight)); /* Dump image, centered, on lower 2/3 of card */ if (COLOR_IsTrueColor()) { for (y = 0; y < pimageCountry->height; y++) { for (x = 0; x < pimageCountry->width; x++) { c = XGetPixel(pimageCountry, x, y); if (c != blackpixel) { c = iColor; } XSetForeground(hDisplay, hGC, c); XDrawPoint(hDisplay, Cards[iCard].pixmap, hGC, (iPictureWidth - pimageCountry->width)/2 + x, iPictureOffset + (iPictureHeight - pimageCountry->height)/2 + y); } } } else XPutImage(hDisplay, Cards[iCard].pixmap, hGC, pimageCountry, 0, 0, (iPictureWidth - pimageCountry->width)/2, iPictureOffset + (iPictureHeight - pimageCountry->height)/2, pimageCountry->width, pimageCountry->height); /* Write the name of the country on the card */ iFontHeight = (pCardFont->max_bounds.ascent + pFont->max_bounds.descent); iFontWidth = XTextWidth(pCardFont, RISK_GetNameOfCountry(iCard), strlen(RISK_GetNameOfCountry(iCard))); /* Set the font */ XSetFont(hDisplay, hGC, pCardFont->fid); XSetForeground(hDisplay, hGC, whitepixel); XDrawString(hDisplay, Cards[iCard].pixmap, hGC, (iPictureWidth - iFontWidth)/2, iPictureOffset+iFontHeight, RISK_GetNameOfCountry(iCard), strlen(RISK_GetNameOfCountry(iCard))); /* Lose all of the used memory */ XDestroyImage(pimageCountry); /* Now put the appropriate bitmap there */ #ifdef ENGLISH snprintf(buf, sizeof(buf), "%s", (iCard%3==0) ? "Cavalry" : (iCard%3==1) ? "Infantry" : "Artillery"); #endif #ifdef FRENCH snprintf(buf, sizeof(buf), "%s", (iCard%3==0) ? "Cavalerie" : (iCard%3==1) ? "Infanterie" : "Artillerie"); #endif iFontWidth = XTextWidth(pCardFont, buf, strlen(buf)); XSetForeground(hDisplay, hGC, blackpixel); XDrawString(hDisplay, Cards[iCard].pixmap, hGC, (CARD_WIDTH - iFontWidth)/2, iFontHeight, buf, strlen(buf)); } /** * Create pixmap for joker * * \b History: * \arg 05.01.00 TdH Created * * \b Notes: * Took out of CARDS_RenderCard */ void CARDS_GetJoker(Int32 iCard) { char buf[256]; if (Cards[iCard].pixmap == 0L){ Int32 iFontHeight, iFontWidth; /* Makes life easier */ Cards[iCard].pixmap = XCreatePixmap(hDisplay, pixMapImage, CARD_WIDTH, CARD_HEIGHT, COLOR_GetDepth()); /* Jokers are all white */ XSetForeground(hDisplay, hGC, WhitePixel(hDisplay, 0)); XFillRectangle(hDisplay, Cards[iCard].pixmap, hGC, 0, 0, CARD_WIDTH, CARD_HEIGHT); /* Set the font */ XSetFont(hDisplay, hGC, pCardFont->fid); /* It's a joker, put all of the bitmaps there ??*/ snprintf(buf, sizeof(buf), "%s", "Joker"); iFontWidth = XTextWidth(pCardFont, buf, strlen(buf)); iFontHeight = (pCardFont->max_bounds.ascent + pCardFont->max_bounds.descent); XSetForeground(hDisplay, hGC, BlackPixel(hDisplay, 0)); XDrawString(hDisplay, Cards[iCard].pixmap, hGC, (CARD_WIDTH - iFontWidth)/2, iFontHeight, buf, strlen(buf)); } } /** * Draw cards * * \b History: * \arg 02.21.94 ESF Created. * \arg 02.22.94 ESF Fixed positioning bug, made prettier. * \arg 03.02.94 ESF Added the printing of the country name. * \arg 03.29.94 ESF Fixed the setup for printing the jokers. * \arg 04.02.94 ESF Fixed name centering, wasn't XSetFont'ing. * \arg 05.06.94 ESF Made it more beautiful, took out hacks. * \arg 06.25.94 ESF Optimized card decompression. * \arg 09.02.94 ESF Fixed off-by-two bug. * \arg 23.08.95 JC Use COLOR_Depth. * \arg 27.10.99 TdH Took out CARDS_Init to get rid of static and check */ void CARDS_RenderCard(Int32 iCard, Int32 iPosition) { Int32 c; /* Range check */ if (iCard<0 || iCard>=NUM_CARDS || iPosition>=MAX_CARDS || iPosition<0) { (void)UTIL_PopupDialog("Warning!", "Bogus request to CARDS_RenderCard()!\n", 1, "Ok", NULL, NULL); return; } /* Find out which country/image goes with the card */ if (iCard < NUM_COUNTRIES) { /* Check to see if the color of the card/country has changed * if card has no pixmap, color will be -1, which is no existing color */ c = COLOR_QueryColor(COLOR_CountryToColor(iCard)); if(Cards[iCard].color != c) CARDS_SetColor(iCard,c); } else {/* it's a joker */ if (Cards[iCard].pixmap == 0L) CARDS_GetJoker(iCard); } /* Now it's built, put it in the card's bitmap resource, manage the card */ XtVaSetValues(wCardToggle[iPosition],XtNbitmap, Cards[iCard].pixmap, NULL); XtManageChild(wCardToggle[iPosition]); } /** * Using Bresenham's algorithm, squish the image passed in to * a box [x, y]. Return the compressed image. Preserve aspect * ratio of the image, so find out the MAX of the compression in * the x and y directions. * \b History: * \arg ??.??.93 ESF Created for the XDissolver. * \arg 02.22.94 ESF Made pretty, changed to work with 8 bit images. * \arg 11.29.94 ESF Completely rewrote to use true Bresenham algorithm. * \arg 01.15.95 ESF Fixed off by one error causing memory access errors. */ XImage *CARDS_ScaleImage(XImage *pimageInput, Int32 iMaxWidth, Int32 iMaxHeight) { XImage *pimageCompressed; Byte *pbData; Int32 iOutputWidth, iOutputHeight; /* Believe it or not, scaling a 2D image is like drawing two lines, * using Bresenham's algorithm. This algorithm is probably analogous * to the methods used in games such as Wolfenstein 3D, since one can * use a similar algorithm for rotating bitmaps in 3D. * * The key here is that the first "line" that we use to scale is the * hypotenuse of a triangle. The base of the triangle is the width of * the input image, and the other side (vertical) is the width of the * output image. * * The second "line" is similar, except that the dimensions of the sides * are the heights of the input image and output image. * * We proceed to "draw" (i.e. perform the Bresenham algorithm for) the * two lines, in the structure of a nested loop -- for each pixel of * the outer line, draw the entire inner line). * * The line is going to be in the first quadrant, since the dimensions * of the images are positive. Thus, the pixels of the line will either * be drawn "to the right of", "above", or "above and to the right of" * the anterior pixel (in other words, as we draw the line, the next * pixel will either go to the right, up, or diagonally up and to the * right. * * Remember, the base of the triangle represents the dimension of the * _input_ image. As we draw the line, if the pixel that we draw is * _heigher_ than the last one, we copy a pixel from the source image * to the destination image. The pixel that we copy is the one that * falls directly _below_ the pixel we are drawing, and we copy it to * the location directly to the _right_ of the current pixel. * * You should be able to imagine in this fashion scaling a single * scan-line of an image. The source line was the base of the * triangle, and the verticle side of the triangle was the * destination scan-line. Thus, in order to scale a 2D image, we * simply perform two line drawings, one inside the other, as * mentioned above. * * As for an informal proof of this method, (not like I was ever * any good at _formal_ proofs), I show that the method works for * a scan-line at the border conditions, and then, using smoke, magic, * and poor man's induction, I handwave my way into 2 dimensions. * * The easiest scaling to prove is the 1:1 ratio. This will result in * a completely diagonal line. Since we copy a pixel across whenever * we go up at all, we will copy across a pixel every time we move, * since we are moving diagonally all the way. Thus the scan-lines * will be identical. * */ Int32 *pHorizontalLine, *pVerticalLine; Int32 iCompression; Int32 iWidthCompression, iHeightCompression; Int32 x, y; /* Calculate the dimensions of the output image, preserving aspect ratio. * I want to avoid using any floating point, so use a primitive fixed * point representation here, simply multiply the numbers by 1024 and then * divide the final result by the same factor. This has two consequences: * * a) The accuracy is limited to approximately 3 digits. * b) The range on the input parameters of the calculation is * limited to 2^32 >> 10 = 2^22. I don't think there are * countries larger than this in width or height :) */ /* Watch out for negative numbers! */ D_Assert(pimageInput->width >= 0 && pimageInput->height >=0, "Negative image?"); /*** Scale (encoding) ***/ pimageInput->width <<= 10; pimageInput->height <<= 10; iWidthCompression = MAX(pimageInput->width / iMaxWidth, 1<<10); iHeightCompression = MAX(pimageInput->height / iMaxHeight, 1<<10); /* To preserve the aspect ratio, choose the larger of * the compression ratios, and use it in both directions. */ iCompression = MAX(iWidthCompression, iHeightCompression); /* Find out the size of the output image */ iOutputWidth = (pimageInput->width)/iCompression; iOutputHeight = (pimageInput->height)/iCompression; /*** Scale (decoding) ***/ pimageInput->width >>= 10; pimageInput->height >>= 10; /* After we have done this, do a sanity check on the result */ D_Assert(iOutputWidth <= iMaxWidth && iOutputHeight <= iMaxHeight, "Scaling algorithm meltdown!"); /* Allocate memory for the lines */ pHorizontalLine = (Int32 *)MEM_Alloc(sizeof(Int32)*iOutputWidth); pVerticalLine = (Int32 *)MEM_Alloc(sizeof(Int32)*iOutputHeight); /* We want to draw lines that represent the hypotenuse of triangles * that have heights of pimageInput->[height | width] pixels and * widths of iOutput[Width | Height] pixels. Thus, since out lines * start at (0, 0), we _must_ subtract 1 from the widths and heights * in order to draw a line or the correct dimensions. */ /* First "draw" the line representing the "width" compression */ _CARDS_ComputeScaleVector(pHorizontalLine, 0, 0, pimageInput->width-1, iOutputWidth-1); /* Now "draw" the line representing the "height" compression */ _CARDS_ComputeScaleVector(pVerticalLine, 0, 0, pimageInput->height-1, iOutputHeight-1); /* This will hold the compressed input data as we're compressing it */ pbData = (Byte *)XtMalloc(sizeof(Byte)*iOutputWidth*iOutputHeight); pimageCompressed = XCreateImage(hDisplay, pVisual, 8, ZPixmap, 0, (char *)pbData, iOutputWidth, iOutputHeight, 8, iOutputWidth); /* Loop through the scale vectors and compress the image (UNROLL?) */ for (y=0; y!=iOutputHeight; y++) for (x=0; x!=iOutputWidth; x++) { /* CSE hand optimization */ const Int32 xx = pHorizontalLine[x], yy = pVerticalLine[y]; /* Sanity check */ D_Assert(xx>=0 && xxwidth, "Bogus horiz. r-pixel."); D_Assert(yy>=0 && yyheight, "Bogus vert. r-pixel."); D_Assert(x>=0 && xwidth, "Bogus horiz. w-pixel."); D_Assert(y>=0 && yheight, "Bogus vert. w-pixel."); /* Copy a pixel */ XPutPixel(pimageCompressed, x, y, XGetPixel(pimageInput, xx, yy)); } /* Destroy the old image */ XDestroyImage(pimageInput); /* Free memory */ MEM_Free(pHorizontalLine); MEM_Free(pVerticalLine); /* Return the compressed image */ return(pimageCompressed); } /** * "Draws" a line from (x0, y0) to (x1, y1), including both endpoints, * which is stored in a vector of function values in which (V[y], y) * form the point pairs. Caller is reponsible for allocation and * deallocation of vector. * * \b History: * \arg 12.30.94 ESF Created. * \arg 01.15.95 ESF Added check that line is in first quadrant. * * \par Notes: * Taken from _Computer Graphics_, by Folen and van Dam et. al., * slightly hand optimized, at the cost of clarity -- sorry. * Remember that the vector must have (y1-y0)+1 elements allocated. * Also, this algorithm only draws lines in the first quadrant. */ static void _CARDS_ComputeScaleVector(Int32 *piVector, Int32 x0, Int32 y0, Int32 x1, Int32 y1) { Int32 dx, dy, incrE, incrNE, d, x, y; /* Ensure that the line is in the first quadrant */ if (x0>x1 || y0>y1) { #ifdef ENGLISH printf("Error: (_CARDS_ScaleVector) Line not in first quadrant."); #endif #ifdef ENGLISH printf("Erreur: (_CARDS_ScaleVector) La ligne n'est pas dans le premier quadrant."); #endif UTIL_ExitProgram(-1); } /* Initialize variables, prime the algorithm */ dx = x1 - x0; dy = y1 - y0; d = 2*dy - dx; incrE = 2*dy; incrNE = 2*(dy-dx); x = x0; y = y0; /* Map one value (like drawing a pixel) */ piVector[y] = x; while (x < x1) { if (d <= 0) x++, d+=incrE; else x++, y++, d+=incrNE; /* Map one value (like drawing a pixel) */ piVector[y] = x; } } /** * \b History: * \arg 01.22.95 ESF Created. * \arg 06.05.97 DAH Make hFile a local; remember to close it. * \arg 06.06.97 DAH Actually, it needs to be static. * \arg 19.12.99 TdH Cl0d suggested this fix, greenland card now shows */ XImage *CARDS_GetCountryImage(Int32 iCountry, Int32 iFgColor, Int32 iBgColor) { static Flag fDirectoryRead = FALSE; Int32 iCardColor, iCardBackground, i; Int32 iNumCountries; Byte bLength, bColor; Byte *pbImage, *pTemp, *pTemp2; Byte *pbBogus, *pbCompressed; XImage *pimageCountry; static FILE *hFile; char buf[256]; const Int32 iCard = iCountry; if (!fDirectoryRead) { fDirectoryRead = TRUE; /* Open the file */ if ((hFile=UTIL_OpenFile(COUNTRYFILE, "r"))==NULL) { #ifdef ENGLISH snprintf(buf, sizeof(buf), "CARDS: Cannot open %s!\n", COUNTRYFILE); (void)UTIL_PopupDialog("Fatal Error", buf, #endif #ifdef FRENCH snprintf(buf, sizeof(buf), "CARDS: Ne peut ouvrir %s!\n", COUNTRYFILE); (void)UTIL_PopupDialog("Erreur fatale", buf, #endif 1, "Ok", NULL, NULL); UTIL_ExitProgram(-1); } /* Read the directory */ fscanf(hFile, "%d%c", &iNumCountries, (char *)&pbBogus); if (iNumCountries != NUM_COUNTRIES) /* One is for ocean */ { #ifdef ENGLISH (void)UTIL_PopupDialog("Fatal Error", "CARDS: Wrong number of countries!", #endif #ifdef FRENCH (void)UTIL_PopupDialog("Erreur fatale", "CARDS: Nombre de pays invalide!", #endif 1, "Ok", NULL, NULL); UTIL_ExitProgram(-1); } fread(pDirectory, iNumCountries, sizeof(pDirectory[0]), hFile); /* Hack for now */ iNumCountries = NUM_COUNTRIES; } /* Allocate the memory for the card */ pbImage = (Byte *)XtMalloc(pDirectory[iCard].iWidth * pDirectory[iCard].iHeight); pbCompressed = (Byte *)MEM_Alloc(pDirectory[iCard].iLength); /* Go seek the card */ fseek(hFile, pDirectory[iCard].lOffset, SEEK_SET); /* Read it in from the data file */ fread(pbCompressed, pDirectory[iCard].iLength, 1, hFile); /* Get the colors of the card. This is an optimization, * since we should get the color from the compressed card * bitmap. However, we know what color the card should * be because of our nice organization of the card -> * country mapping. If the caller has passed in specific values * for these, use them instead of the defaults. */ /* do NOT ask me why +1 must be used, but it seems to work */ iCardColor = (iFgColor == -1) ? COLOR_CountryToColor(iCard + 1) : iFgColor; iCardBackground = (iFgColor == -1) ? BlackPixel(hDisplay, 0) : iBgColor; /* Uncompress the data */ for (i=0,pTemp2=pbCompressed,pTemp=pbImage; i #define CARD_WIDTH 138 #define CARD_HEIGHT 190 /* Card types */ #define CARD_CANON 0 #define CARD_FOOTMAN 1 #define CARD_HORSEMAN 2 #define CARD_JOKER 3 /* Initialize */ void CARDS_Init(); /* The main function */ void CARDS_RenderCard(Int32 iCard, Int32 iPositions); /* Worker functions */ XImage *CARDS_ScaleImage(XImage *pimageInput, Int32 iMaxWidth, Int32 iMaxHeight); XImage *CARDS_GetCountryImage(Int32 iCountry, Int32 iFgColor, Int32 iBgColor); /* This is the mapping from (card #) :==> (country, type) where country * is the country to portray on the card, and type is defined in risk.h, * as CARD_[FOOTMAN|HORSEMAN|CANNON|JOKER]: * * The first 42 cards are: Card i is of country i and of type (i mod 3). * The next 2 cards are jokers. */ #endif xfrisk-1.2/client.c0100644000175000017500000002270707042657705013345 0ustar johnojohno/* * XFrisk - The classic board game for X * Copyright (C) 1993-1999 Elan Feingold (elan@aetherworks.com) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * $Id: client.c,v 1.14 2000/01/23 20:08:37 tony Exp $ * * $Log: client.c,v $ * Revision 1.14 2000/01/23 20:08:37 tony * doxygen fixes * * Revision 1.13 2000/01/07 21:37:07 tony * a line after $Id: client.c,v 1.14 2000/01/23 20:08:37 tony Exp $ * * Revision 1.12 2000/01/04 21:41:53 tony * removed redundant stuff for jokers * */ /** \file * Client functions and data, mainly about communication */ #include #include #include #include #include #include #include #include #include #include #include #include "utils.h" #include "network.h" #include "client.h" #include "callbacks.h" #include "riskgame.h" #include "gui-func.h" #include "types.h" #include "dice.h" #include "debug.h" #include "registerPlayers.h" #include "viewStats.h" #include "addPlayer.h" #include "language.h" /* Private data */ /** \struct _Client * To store client info */ typedef struct _Client { Int32 iCommLink;/**< just this commlink now */ } Client; static Client pClients[MAX_CLIENTS];/**< to keep track of others? */ /* Used for the UTIL_*Notify routines */ static Flag piCountryLightCount[NUM_COUNTRIES]; static CString strClientName; extern Int32 iReply; static Int32 iCurrentClient; /* Do something with these... */ void FatalError(CString strError, Int32 iRetVal); /** * Sets up communication stuff * * \b History: * \tag 01.23.94 ESF Created. * \tag 02.22.94 ESF Cleaned up a bit, removing warnings. * \tag 08.10.94 ESF Cleanup up to make more OS independant. * \tag 01.17.95 ESF Fixed memory leak. */ void CLNT_Init(int argc, char **argv) { struct sockaddr_in server; struct hostent *hp; char strHostName[MAXHOSTNAMELEN + 1]; Int32 iCommLink, i; Int32 iMessageType; void *pvMessage; MsgRegisterClient msgRegisterClient; char buf[256]; int len; UNUSED(argc); /* Seed the random number generator */ srand(time(NULL)); /* Init the client structures */ for (i=0; i!=NUM_COUNTRIES; i++) CLNT_SetLightCountOfCountry(i, 0); for (i=0; i!=MAX_CLIENTS; i++) CLNT_SetCommLinkOfClient(i, -1); /* We want to ignore this signal, because we don't want a I/O * failure to terminate the program. */ signal(SIGPIPE, SIG_IGN); /* Create Commlink */ if ((iCommLink = socket(AF_INET, SOCK_STREAM, 0)) < 0) FatalError(ERR_COMMLINK, 1); /* Connect socket using name specified by command line */ server.sin_family = AF_INET; if ((hp = gethostbyname(argv[1])) == 0) { snprintf(buf, sizeof(buf), ERR_UNKNOWN_HOST, argv[1]); FatalError(buf, 1); } memcpy(&server.sin_addr, hp->h_addr, hp->h_length); server.sin_port = htons(RISK_PORT); /* Send the server name information through the sockets so it can ID * the sending clients, and discover the pair of sockets that belong * to each client. The server sends back the client ID. */ gethostname(strHostName, sizeof(strHostName)); len = strlen(strHostName)+32;; msgRegisterClient.strClientAddress = (CString)MEM_Alloc(len); snprintf(msgRegisterClient.strClientAddress, len, "%s[%lu]", strHostName, (unsigned long)getpid()); strClientName = msgRegisterClient.strClientAddress; /* Connect to the server. Connect the socket, send * MSG_REGISTER and then wait for a MSG_CLIENTIDENT * message to be send back. */ if (connect(iCommLink, (struct sockaddr *)&server, sizeof(server)) < 0) { printf(ERR_COULD_NOT_CONNECT, argv[1]); FatalError(NULL, 0); } /* Set the options on the CommLink */ NET_SetCommLinkOptions(iCommLink); (void)RISK_SendMessage(iCommLink, MSG_OLDREGISTERCLIENT, &msgRegisterClient); printf(MSG_CONNECTED); printf(MSG_WAITING_SRV_ID); fflush(stdout); (void)RISK_ReceiveMessage(iCommLink, &iMessageType, &pvMessage); printf(MSG_DONE); if (iMessageType == MSG_EXIT) FatalError(ERR_SERVER_FULL, -1); else if (iMessageType == MSG_CLIENTIDENT) { /* Set the ID of the client, and then set the sockets of the client */ iCurrentClient = ((MsgClientIdent *)pvMessage)->iClientID; CLNT_SetCommLinkOfClient(CLNT_GetThisClientID(), iCommLink); } else FatalError(ERR_PROTOCOL_MISMATCH, -1); /* Free up memory */ NET_DeleteMessage(MSG_CLIENTIDENT, pvMessage); } /************************************************************************ * FUNCTION: CLNT_PreViewVector * HISTORY: * 02.19.95 ESF Created. * 02.23.95 ESF Added PLAYER_callback. * PURPOSE: * All incoming and outgoing messages notify this function once and * only once, for the purpose of notifying the views' controllers, * BEFORE(!!!) they have taken effect on the local dist. object. * NOTES: ************************************************************************/ void CLNT_PreViewVector(Int32 iMessType, void *pvMess) { /* Ideally here I could spawn a thread per callback... */ STAT_Callback(iMessType, pvMess); } /************************************************************************ * FUNCTION: CLNT_PostViewVector * HISTORY: * 03.30.95 ESF Created. * PURPOSE: * All incoming and outgoing messages notify this function once and * only once, for the purpose of notifying the views' controllers, * AFTER(!!!) they have taken effect on the local dist. object. * NOTES: ************************************************************************/ void CLNT_PostViewVector(Int32 iMessType, void *pvMess) { /* Ideally here I could spawn a thread per callback... */ PLAYER_Callback(iMessType, pvMess); REG_Callback(iMessType, pvMess); CBK_Callback(iMessType, pvMess); } /************************************************************************ * FUNCTION: CLNT_RecoverFailure * HISTORY: * 08.28.94 ESF Created. * 09.28.94 ESF Fixed to popup a message before exiting. * PURPOSE: * NOTES: ************************************************************************/ void CLNT_RecoverFailure(CString strReason, Int32 iCommLink) { UNUSED(iCommLink); printf(ERR_SERVER_FAILED, strReason); printf(ERR_NONRECOVERABLE); (void)UTIL_PopupDialog(ERR_OBJECT_FAILURE, ERR_SRV_NONRECOVERABLE, 1, "Ok", NULL, NULL); exit(0); } /************************************************************************ * FUNCTION: CLNT_AllocPlayer * HISTORY: * 05.12.94 ESF Created. * 05.15.94 ESF Fixed race condition, go to server for player. * PURPOSE: * NOTES: ************************************************************************/ Int32 CLNT_AllocPlayer(void (*pfMsgHandler)(Int32, void *)) { (void)RISK_SendSyncMessage(CLNT_GetCommLinkOfClient(CLNT_GetThisClientID()), MSG_ALLOCPLAYER, NULL, MSG_REPLYPACKET, pfMsgHandler); return(iReply); } /************************************************************************ * FUNCTION: CLNT_FreePlayer * HISTORY: * 05.12.94 ESF Created. * 05.15.94 ESF Fixed race condition, go to server. * 07.16.94 ESF Added assert. * PURPOSE: * NOTES: ************************************************************************/ void CLNT_FreePlayer(Int32 i) { MsgFreePlayer mess; /* Tell the server that this player ID is free */ mess.iPlayer = i; (void)RISK_SendMessage(CLNT_GetCommLinkOfClient(CLNT_GetThisClientID()), MSG_FREEPLAYER, &mess); } /***************************************/ void CLNT_SetCommLinkOfClient(Int32 iNumClient, Int32 iCommLink) { D_Assert(iNumClient>=0 && iNumClient=0 && iNumClient= 0 && iCountry < NUM_COUNTRIES, "Country out of range"); return piCountryLightCount[iCountry]; } /***************************************/ void CLNT_SetLightCountOfCountry(Int32 iCountry, Int32 iLightCount) { D_Assert(iCountry >= 0 && iCountry < NUM_COUNTRIES, "Country out of range"); D_Assert(iLightCount>=0, "Bogus LightCount"); piCountryLightCount[iCountry] = iLightCount; } /********************************************/ void FatalError(CString strError, Int32 iRetVal) { if (strError) printf("%s\n", strError); exit(iRetVal); } xfrisk-1.2/client.h0100644000175000017500000000311207013367560013332 0ustar johnojohno/* * XFrisk - The classic board game for X * Copyright (C) 1993-1999 Elan Feingold (elan@aetherworks.com) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * $Id: client.h,v 1.6 1999/11/13 23:08:32 tony Exp $ */ #ifndef _CLIENT_H #define _CLIENT_H #include "types.h" void CLNT_Init(int argc, CString *argv); void CLNT_Connect(void); Int32 CLNT_AllocPlayer(void (*pfMsgHandler)(Int32, void *)); void CLNT_FreePlayer(Int32 i); void CLNT_RecoverFailure(CString strReason, Int32 iCommLink); void CLNT_PreViewVector(Int32 iMessType, void *pMess); void CLNT_PostViewVector(Int32 iMessType, void *pMess); /* Methods */ Int32 CLNT_GetCommLinkOfClient(Int32 iNumClient); void CLNT_SetCommLinkOfClient(Int32 iNumClient, Int32 iCommLink); Int32 CLNT_GetLightCountOfCountry(Int32 iCountry); void CLNT_SetLightCountOfCountry(Int32 iCountry, Int32 iCount); Int32 CLNT_GetThisClientID(void); #endif xfrisk-1.2/clientMain.c0100644000175000017500000000577407034750714014152 0ustar johnojohno/* * XFrisk - The classic board game for X * Copyright (C) 1993-1999 Elan Feingold (elan@aetherworks.com) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * $Id: clientMain.c,v 1.11 2000/01/05 23:20:44 tony Exp $ * * $Log: clientMain.c,v $ * Revision 1.11 2000/01/05 23:20:44 tony * change CARD_ to CARDS_ * * Revision 1.10 1999/12/26 15:39:33 tony * oops, that was borked * * Revision 1.9 1999/12/26 15:09:24 tony * merged two versions, conflicts in doxygen * * Revision 1.8 1999/12/26 01:35:28 morphy * Doxygen comments, CVS Log tag, corrected comment usage before main() - removed warning about comment start tag inside comment * */ /** \file * The client's main() * */ #include "cards.h" #include "callbacks.h" #include "client.h" #include "colormap.h" #include "network.h" #include "riskgame.h" #include "dice.h" #include "help.h" #include "gui-func.h" #include "debug.h" /** * Client main function. * * \b History: * \arg 01.23.94 ESF Created. * \arg 02.22.94 ESF Cleaned up a bit, removing warnings. * \arg 08.10.94 ESF Cleanup up to make more OS independant. * \arg 08.16.94 ESF Moved to its own file, cleaned up. * \arg 10.30.94 ESF Fixed a bug, have to init dist. obj. first! * \arg 12.30.94 ESF Added more robust startup checks. */ int main(int argc, char **argv) { FILE *hLogFile=NULL; /* Check args */ if (argc < 2) { printf("Usage: %s []\n", argv[0]); exit(-1); } /* Setup memory debugging library */ MEM_BootStrap("client-memory.log"); #ifdef LOGGING /* Open debugging log file */ if ((hLogFile = fopen("client.log", "w")) == NULL) { #ifdef ENGLISH printf("Could not open \"client.log\" for writing, exiting..."); #endif #ifdef FRENCH printf("Impossible d'ouvrir \"client.log\" en écriture, quit..."); #endif exit(-1); } #endif /* Initialize everything */ RISK_InitObject(CBK_Replicate, CLNT_PreViewVector, CLNT_PostViewVector, CLNT_RecoverFailure, hLogFile);/* callbacks */ CLNT_Init(argc, argv);/* communications */ GUI_Setup(argc, argv);/* */ COLOR_Init(); GUI_AddCallbacks(CLNT_GetCommLinkOfClient(CLNT_GetThisClientID())); DICE_Init(); HELP_Init(HELPFILE); CARDS_Init();/* The graphical part of cards */ /* And we're off... */ GUI_Start(); return 0; } /* EOF */ xfrisk-1.2/clients.c0100644000175000017500000002241307041646331013512 0ustar johnojohno/* * XFrisk - The classic board game for X * Copyright (C) 1993-1999 Elan Feingold (elan@aetherworks.com) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * $Id: clients.c,v 1.11 2000/01/20 17:58:49 morphy Exp $ * * $Log: clients.c,v $ * Revision 1.11 2000/01/20 17:58:49 morphy * Removed dead code (static decl. of previously removed function) * Added inclusion of string.h for memset() prototype * * Revision 1.10 2000/01/17 22:31:54 tony * removed "lost code" * * Revision 1.9 1999/12/26 01:48:17 morphy * Added missing doxygen file tag. * * Revision 1.8 1999/12/26 01:43:22 morphy * Converted _CLIENTS_GetNthClient() to static * * Revision 1.7 1999/12/26 01:01:29 morphy * Corrected layout of CVS Log tag in header. * * Revision 1.6 1999/12/26 00:58:45 morphy * Doxygen comments, minor layout changes. */ /** \file * Client list. */ #include #include #include "riskgame.h" #include "clients.h" #include "debug.h" #include "language.h" /* Private data types */ /** * Structure to track client failures */ typedef struct _Failure { CString strReason; Int32 iCount; } Failure; /** * Client data that doesn't get replicated to clients themselves. */ typedef struct _Client { Int32 iCommLink; CString strAddress; Int32 iState, iType, iSpecies; Flag fStarted; Failure failure; } Client; /* Private data structures */ static Client pClients[MAX_CLIENTS]; /**< Client list */ static Int32 iNumClients = 0; /**< Number of clients actually on list */ static Int32 iNumFailures = 0; /**< Total count of failures */ /** * Finish allocation of new client. * * \b History: * \arg 05.12.94 ESF Created. * \arg 08.08.94 ESF Moved here from server.c * \arg 08.21.94 ESF Fixed to work. */ Int32 CLIENTS_Alloc(void) { Int32 i; /* Since we wouldn't have accepted the connection if there weren't * a slot available, this call cannot fail. */ D_Assert(CLIENTS_GetNumClients() < MAX_CLIENTS, "Not good!"); CLIENTS_SetNumClients(CLIENTS_GetNumClients()+1); /* Find an available client */ for (i=0; i!=MAX_CLIENTS; i++) if (CLIENTS_GetAllocationState(i) == ALLOC_NONE) { CLIENTS_SetAllocationState(i, ALLOC_COMPLETE); CLIENTS_SetCommLink(i, -1); CLIENTS_SetStartState(i, FALSE); return (i); } D_Assert(FALSE, "Something wierd happened!"); /* For the compiler */ return (0); } /** * Return failure count of given client. */ Int32 CLIENTS_GetFailureCount(Int32 iClient) { return pClients[iClient].failure.iCount; } /** * Reset failure count of given client. */ void CLIENTS_ResetFailure(Int32 iNumClient) { pClients[iNumClient].failure.iCount = 0; pClients[iNumClient].failure.strReason = 0; } /** * Set printable address of client * * \bug (MSH 25.12.99) Obsolete since client addresses are not disclosed to others anymore! */ void CLIENTS_SetAddress(Int32 iNumClient, CString strAddress) { D_Assert(iNumClient>=0 && iNumClient=0 && iNumClient=0 && iNumClient=0 && iNumClient=0 && iNumClient 1 && iClientType != CLIENT_AI) { /* Let the new client know about old clients */ msgMess.strMessage = buf; msgMess.iFrom = FROM_SERVER; msgMess.iTo = DST_OTHER; /* Send info about everybody but the new client. */ for (n=0; n!=MAX_CLIENTS; n++) if (CLIENTS_GetAllocationState(n) == ALLOC_COMPLETE && CLIENTS_GetCommLinkOfClient(n) != iCommLink) { snprintf(buf, sizeof(buf),"%s %s.",CLIENT,IS_REGISTERED); /* Return value not wanted */ (void) RISK_SendMessage(iCommLink, MSG_MESSAGEPACKET, &msgMess); } } } /** * Return address of given client. */ CString CLIENTS_GetAddress(Int32 iNumClient) { D_Assert(iNumClient>=0 && iNumClient=0 && iNumClient=0 && iNumClient=0 && iNumClient=0 && iNumClient=0 && iCommLink < MAX_DESCRIPTORS, "Bogus CommLink!"); for (i=0; i!=MAX_CLIENTS; i++) if ((CLIENTS_GetAllocationState(i) == ALLOC_COMPLETE) && (CLIENTS_GetCommLinkOfClient(i) == iCommLink)) return (i); return (-1); } /** * Return failure reason string for given client. */ CString CLIENTS_GetFailureReason(Int32 iNumClient) { D_Assert( iNumClient >= 0 && iNumClient < MAX_CLIENTS,"wrong client"); return (pClients[iNumClient].failure.strReason); } /** * Return failure count for given client. */ Int32 CLIENTS_GetNumFailures(void) { return iNumFailures; } /** * Return number of clients that have finished registering players. * * \b History * \arg 04.06.95 ESF Created. */ Int32 CLIENTS_GetNumClientsStarted(void) { Int32 i, iCount; for (i=iCount=0; i!=MAX_CLIENTS; i++) if (CLIENTS_GetAllocationState(i) == ALLOC_COMPLETE && CLIENTS_GetStartState(i) == TRUE) iCount++; return iCount; } /** * Return start state of given client. * * \b History: * \arg 04.06.95 ESF Created. */ Int32 CLIENTS_GetStartState(Int32 iNumClient) { D_Assert(iNumClient>=0 && iNumClient=0 && iNumClient #include #include #include #include #include #include #include #include "colorEdit.h" #include "dice.h" #include "callbacks.h" #include "colormap.h" #include "client.h" #include "utils.h" #include "cards.h" #include "riskgame.h" #include "gui-vars.h" #include "debug.h" #include "riskgame.h" #include "viewStats.h" /* Local functions */ static void COLEDIT_Cancel(void); static void COLEDIT_ScrollbarMoved(void); static void COLEDIT_UpdateExampleImage(Int32 iColor); /* Action tables */ static XtActionsRec actionTable[] = { { "updateColor", (XtActionProc)COLEDIT_UpdateColorWithInput }, { "colorEditCancel", (XtActionProc)COLEDIT_Cancel }, { NULL, NULL } }; /* Widgets */ static Widget wColorEditShell; static Widget wColorEditForm; static Widget wColorEditLabel; static Widget wRedScrollbar, wBlueScrollbar, wGreenScrollbar; static Widget wSampleCountryForm; static Widget wColorInputLabel, wColorInputText; static Widget wColorOK, wColorCancel; /* Color editing related things */ #define COLOR_EDIT_OK 1 #define COLOR_EDIT_CANCEL 0 #define COLOR_EDIT_INPROGRESS -1 static Int32 iQueryResult = COLOR_EDIT_OK; static Pixmap pixSampleImage;/**< sample image */ static XImage *pScaledSample; Int32 iCountry;/**< index of country clicked on*/ Int32 iglobalColor;/**< index of color */ /** * \b History: * \arg 01.22.95 ESF Created. * \arg 01.24.95 ESF Changed to get coordinates manually. * \arg 01.25.95 ESF Added check that the country was not empty. * \arg 12.07.95 ESF Fixed a bug -- don't allow editing of ocean. */ void COLEDIT_MapShiftClick(void) { Int32 iColor; Int32 x, y, xRoot, yRoot; UInt32 uiButtons; Window winDummy1, winDummy2; if (!XQueryPointer(hDisplay, hWindow, &winDummy1, &winDummy2, &xRoot, &yRoot, &x, &y, &uiButtons)) { /* Pointer has somehow left window */ return; } /* Get the coordinates of the mouse */ iColor = XGetPixel(pMapImage, x, y); iCountry = COLOR_ColorToCountry(iColor); /* See if there is a player on the country * no idea why? */ if (iCountry<0 || iCountry>=NUM_COUNTRIES || RISK_GetOwnerOfCountry(iCountry) == -1 || RISK_GetNumArmiesOfCountry(iCountry) == 0) return; /* Edit this color */ COLEDIT_EditColor(iColor, TRUE);/* ok here */ } void COLEDIT_Ok(void) { iQueryResult = COLOR_EDIT_OK; } void COLEDIT_Cancel(void) { iQueryResult = COLOR_EDIT_CANCEL; } /** * Set scrollbars and text input box to given color * * \b History: * \arg 01.22.95 ESF Created. * \arg 18.08.95 JC Modified to call COLOR_GetColor. * \arg 18.01.00 MSH Reordered X..SetThumb parameters. */ void COLEDIT_InitDialogWithColor (Int32 iColorNum) { float f; UInt16 r, g, b; char buf[256]; COLOR_GetColor(iColorNum, &r, &g, &b); f = 1.0 - ((float)r)/65535.0; XawScrollbarSetThumb(wRedScrollbar, f, 0.05); f = 1.0 - ((float)g)/65535.0; XawScrollbarSetThumb(wGreenScrollbar, f, 0.05); f = 1.0 - ((float)b)/65535.0; XawScrollbarSetThumb(wBlueScrollbar, f, 0.05); /* Display the name of the color */ snprintf(buf, sizeof(buf), "#%02x%02x%02x", r/256, g/256, b/256); XtVaSetValues(wColorInputText, XtNstring, buf, XtNinsertPosition, strlen(buf), NULL); } /** * Build the X dialog structure. Called from gui.c * * \b History: * \arg 01.21.95 ESF Created. */ void COLEDIT_BuildDialog(void) { Widget wColorDummy; /* Add Actions */ XtAppAddActions(appContext, actionTable, XtNumber(actionTable)); wColorEditShell = XtCreatePopupShell("wColorEditShell", transientShellWidgetClass, wToplevel, pVisualArgs, iVisualCount); wColorEditForm = XtCreateManagedWidget("wColorEditForm", formWidgetClass, wColorEditShell, NULL, 0); /* The label for the dialog */ wColorEditLabel = XtCreateManagedWidget("wColorEditLabel", labelWidgetClass, wColorEditForm, NULL, 0); /* The three (RGB) scrollbars */ wRedScrollbar = XtCreateManagedWidget("wRedScrollbar", scrollbarWidgetClass, wColorEditForm, NULL, 0); XtAddCallback(wRedScrollbar, XtNjumpProc, (XtCallbackProc)COLEDIT_ScrollbarMoved, NULL); XawScrollbarSetThumb(wRedScrollbar, 0.0, 0.05); wGreenScrollbar = XtCreateManagedWidget("wGreenScrollbar", scrollbarWidgetClass, wColorEditForm, NULL, 0); XtAddCallback(wGreenScrollbar, XtNjumpProc, (XtCallbackProc)COLEDIT_ScrollbarMoved, NULL); XawScrollbarSetThumb(wGreenScrollbar, 0.0, 0.05); wBlueScrollbar = XtCreateManagedWidget("wBlueScrollbar", scrollbarWidgetClass, wColorEditForm, NULL, 0); XtAddCallback(wBlueScrollbar, XtNjumpProc, (XtCallbackProc)COLEDIT_ScrollbarMoved, NULL); XawScrollbarSetThumb(wBlueScrollbar, 0.0, 0.05); /* A sample country in the chosen color */ wSampleCountryForm = XtCreateManagedWidget("wSampleCountryForm", labelWidgetClass, wColorEditForm, NULL, 0); /* Input text label */ wColorInputLabel = XtCreateManagedWidget("wColorInputLabel", labelWidgetClass, wColorEditForm, NULL, 0); /* The actual widget for inputting text */ wColorInputText = XtVaCreateManagedWidget("wColorInputText", asciiTextWidgetClass, wColorEditForm, XtNeditType, XawtextEdit, NULL); /* This is used to align the OK/Cancel buttons */ wColorDummy = XtCreateManagedWidget("wColorDummy", formWidgetClass, wColorEditForm, NULL, 0); /* The buttons */ wColorOK = XtCreateManagedWidget("wColorOK", commandWidgetClass, wColorEditForm, NULL, 0); XtAddCallback(wColorOK, XtNcallback, (XtCallbackProc)COLEDIT_Ok, NULL); wColorCancel = XtCreateManagedWidget("wColorCancel", commandWidgetClass, wColorEditForm, NULL, 0); XtAddCallback(wColorCancel, XtNcallback, (XtCallbackProc)COLEDIT_Cancel, NULL); } /** Cleanup macro for the function COLEDIT_EditColor */ #define COLEDIT_CloseColorDialog() \ UTIL_DisplayError(""); \ XtSetKeyboardFocus(wToplevel, wToplevel); \ XtRemoveGrab(wColorEditShell); \ XtUnrealizeWidget(wColorEditShell); /** * Displays the dialog with given color. Called by player add and * registration routines. * * \b History: * \arg 01.22.95 ESF Created. * \arg 01.26.95 ESF Fixed last few bugs. * \arg 23.08.95 JC Use of COLOR_Depth. * \arg 12.07.95 ESF Made the editable color be the dice color. */ String COLEDIT_EditColor(Int32 iColorNum, Flag fStoreColor) { XEvent xEvent; Int32 x, y; CString strNewColor=NULL; D_Assert(iColorNum >= COLOR_CountryToColor(0) && iColorNum <= COLOR_DieToColor(3), "Asked to edit bogus color!"); /* Center the new shell */ UTIL_CenterShell(wColorEditShell, wToplevel, &x, &y); XtVaSetValues(wColorEditShell, XtNallowShellResize, False, XtNx, x, XtNy, y, XtNborderWidth, 1, #ifdef ENGLISH XtNtitle, "Edit Color", #endif #ifdef FRENCH XtNtitle, "Edition des couleurs", #endif NULL); /* Initialize the scrollbars to represent the right color */ COLEDIT_InitDialogWithColor(iColorNum); /* TdH looks wrong */ iCountry = COLOR_ColorToCountry(iColorNum); /* If the country requested was not a valid country, then * pick a random country for the caller. */ if (iCountry >= NUM_COUNTRIES || iCountry < 0) iCountry = rand() % NUM_COUNTRIES; /* Hide the dice */ DICE_Hide(); /* Put the country on the sample */ pScaledSample = CARDS_GetCountryImage(iCountry, iColorNum, COLOR_CountryToColor(NUM_COUNTRIES)); /* Scale it to the sample country form */ pScaledSample = CARDS_ScaleImage(pScaledSample, 100, 100); /* Set the initial color of the sample country * TdH: to check! */ COLOR_CopyColor(iColorNum, iColorNum); /* Dump it on the sample country location */ pixSampleImage = XCreatePixmap(hDisplay, pixMapImage, 140, 140, COLOR_GetDepth()); XSetForeground(hDisplay, hGC, COLOR_QueryColor(COLOR_CountryToColor(NUM_COUNTRIES))); XFillRectangle(hDisplay, pixSampleImage, hGC, 0, 0, 140, 140); XtVaSetValues(wSampleCountryForm, XtNbackground, COLOR_QueryColor(COLOR_CountryToColor(NUM_COUNTRIES)), NULL); COLEDIT_UpdateExampleImage(iColorNum); /* Popup the color editing dialog */ XtMapWidget(wColorEditShell); XtAddGrab(wColorEditShell, True, True); XtSetKeyboardFocus(wToplevel, wColorEditShell); XtSetKeyboardFocus(wColorEditShell, wColorInputText); /* Look until user presses one of the buttons */ iQueryResult = COLOR_EDIT_INPROGRESS;/* TdH: why this read?? */ while (iQueryResult == COLOR_EDIT_INPROGRESS) { /* pass events */ XNextEvent(hDisplay, &xEvent); XtDispatchEvent(&xEvent); } if (iQueryResult == COLOR_EDIT_OK) { Int32 i; /* Just in case the player typed a color name in and then hit "Ok" * update the color in the country in the last second that the dialog * is up, so that when we copy the color out of there it will be the * color that the player typed in. */ COLEDIT_UpdateColorWithInput(); /* Get the color from the text widget. If the player moved the * scrollbars, then the color will have been written in here. * If the player typed something in, it will be in here. */ XtVaGetValues(wColorInputText, XtNstring, &strNewColor, NULL); /* Are we trying to store the color? */ if (fStoreColor) { /* Sanity check */ if (iCountry < 0 || iCountry >= NUM_COUNTRIES || RISK_GetOwnerOfCountry(iCountry) == -1 || RISK_GetNumArmiesOfCountry(iCountry) <= 0) { (void)UTIL_PopupDialog("Error", "Cannot set new value for color!", 1, "Ok", NULL, NULL); } else { Int32 iOwner = RISK_GetOwnerOfCountry(iCountry); Flag isTrueColor = COLOR_IsTrueColor(); /* And also the actual color for the player */ COLOR_StoreNamedColor(strNewColor, iOwner); /* Set all the countries that the player owns to be new color */ for (i=0; i!=NUM_COUNTRIES; i++) if (RISK_GetOwnerOfCountry(i) == iOwner) { COLOR_CopyColor(COLOR_DieToColor(0), COLOR_CountryToColor(i)); if (isTrueColor) { COLOR_ColorCountry(i, iOwner); UTIL_DarkenCountry(i); } } if (isTrueColor) STAT_RenderSlot(STAT_PlayerToSlot(iOwner), iOwner); /* If the player whose color changed is the current * player, then recolor the current player indicator. * Also, the dice really need to change color too * (thanks, Kirsten, for reminding me about this -- who * says English majors can't program?) For now punt on * the dice. */ if (RISK_GetOwnerOfCountry(iCountry) == iCurrentPlayer) COLOR_CopyColor(COLOR_DieToColor(0), COLOR_DieToColor(2)); } } } XDestroyImage(pScaledSample); COLEDIT_CloseColorDialog(); return strNewColor; } /** * Updates color value and text box based on scrollbar movement. * Called during X event handling from the scrollbar widget. * * \b History: * \arg 01.22.95 ESF Created. */ void COLEDIT_ScrollbarMoved(void) { float r, g, b; XColor xColor; char buf[256]; XtVaGetValues(wRedScrollbar, XtNtopOfThumb, &r, NULL); XtVaGetValues(wGreenScrollbar, XtNtopOfThumb, &g, NULL); XtVaGetValues(wBlueScrollbar, XtNtopOfThumb, &b, NULL); /* Setup the new color */ xColor.red = (Int32)((1.0-r)*65535.0); xColor.green = (Int32)((1.0-g)*65535.0); xColor.blue = (Int32)((1.0-b)*65535.0); /* Color the sample country with the new color */ COLOR_StoreColor(COLOR_DieToColor(0), xColor.red, xColor.green, xColor.blue); COLEDIT_UpdateExampleImage(COLOR_DieToColor(0)); XFlush(hDisplay); /* Display the name of the color */ snprintf(buf, sizeof(buf), "#%02x%02x%02x", xColor.red/256, xColor.green/256, xColor.blue/256); XtVaSetValues(wColorInputText, XtNstring, buf, XtNinsertPosition, strlen(buf), NULL); } /** * Parse value from input box, update scrollbars and example * country image to reflect change. Uses XParseColor to * handle named colors listed in rgb.txt * * \b History: * \arg 01.23.95 ESF Created. */ void COLEDIT_UpdateColorWithInput(void) { CString strColor; float r, g, b; XColor xColor1, xColor2; char buf[256]; /* Get the color from the text widget */ XtVaGetValues(wColorInputText, XtNstring, &strColor, NULL); /* Also get the color from the scrollbars. */ XtVaGetValues(wRedScrollbar, XtNtopOfThumb, &r, NULL); XtVaGetValues(wGreenScrollbar, XtNtopOfThumb, &g, NULL); XtVaGetValues(wBlueScrollbar, XtNtopOfThumb, &b, NULL); snprintf(buf, sizeof(buf), "#%02x%02x%02x", (Int32)((1.0-r)*65535.0)/256, (Int32)((1.0-g)*65535.0)/256, (Int32)((1.0-b)*65535.0)/256); /* Adjust for the screen */ xColor1.flags = DoRed | DoGreen | DoBlue; (void)XParseColor(hDisplay, cmapColormap, buf, &xColor1); /* Is it a valid color? */ if (XParseColor(hDisplay, cmapColormap, strColor, &xColor2)) { /* If they match, then take this to mean the same as the "Ok" button. */ if (xColor1.red == xColor2.red && xColor1.green == xColor2.green && xColor1.blue == xColor2.blue) { COLEDIT_Ok(); } else { COLOR_StoreColor(COLOR_DieToColor(0), xColor2.red, xColor2.green, xColor2.blue); COLEDIT_InitDialogWithColor(COLOR_DieToColor(0)); COLEDIT_UpdateExampleImage(COLOR_DieToColor(0)); } } else #ifdef ENGLISH (void)UTIL_PopupDialog("Error", "That color does not exist!", 1, "Ok", NULL, NULL); #endif #ifdef FRENCH (void)UTIL_PopupDialog("Erreur", "Cette couleur n'existe pas!", 1, "Ok", NULL, NULL); #endif } /** * Draw example country image with given color. * * \b History: * \tag 09.01.00 MSH Created. */ static void COLEDIT_UpdateExampleImage(Int32 iColor) { Int32 x, y; if (COLOR_IsTrueColor()) { XSetForeground(hDisplay, hGC, COLOR_QueryColor(iColor)); for (y = 0; y < pScaledSample->height; y++) for (x = 0; x < pScaledSample->width; x++) { if (XGetPixel(pScaledSample, x, y) == NUM_COUNTRIES) continue; XDrawPoint(hDisplay, pixSampleImage, hGC, (140-pScaledSample->width)/2 + x, (140-pScaledSample->height)/2 + y); } } else { XPutImage(hDisplay, pixSampleImage, hGC, pScaledSample, 0, 0, (140-pScaledSample->width)/2, (140-pScaledSample->height)/2, 140, 140); } XtVaSetValues(wSampleCountryForm, XtNbitmap, pixSampleImage, NULL); } /* EOF */ xfrisk-1.2/colorEdit.h0100644000175000017500000000251207036460614014002 0ustar johnojohno/* * XFrisk - The classic board game for X * Copyright (C) 1993-1999 Elan Feingold (elan@aetherworks.com) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * $Id: colorEdit.h,v 1.4 2000/01/10 22:47:40 tony Exp $ */ #ifndef _COLOREDIT #define _COLOREDIT #include #include #include #include "types.h" void COLEDIT_UpdateColorWithInput(void);/* red info from inputbox */ void COLEDIT_MapShiftClick(void); /* edit color country selected from map */ void COLEDIT_BuildDialog(void); /* called once from gui */ String COLEDIT_EditColor(Int32 iColor, Flag fStoreColor);/* call the dialog */ #endif xfrisk-1.2/colormap.c0100644000175000017500000005652007040161377013674 0ustar johnojohno/* * XFrisk - The classic board game for X * Copyright (C) 1993-1999 Elan Feingold (elan@aetherworks.com) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * $Id: colormap.c,v 1.18 2000/01/15 21:13:35 morphy Exp $ * * $Log: colormap.c,v $ * Revision 1.18 2000/01/15 21:13:35 morphy * Removed superfluous debug code * * Revision 1.17 2000/01/15 11:33:28 morphy * Comments in doxygen format, minor clarity fixes in code * * Revision 1.16 2000/01/10 22:47:40 tony * made colorstuff more private to colormap.c, only scrollbars get set wrong, rest seems to work ok now * * Revision 1.15 2000/01/09 20:05:02 morphy * Corrections to color map loading - previously struct padding possibility was ignored * * Revision 1.14 2000/01/09 19:59:58 morphy * Corrected bit operation brainfart * * Revision 1.13 2000/01/09 20:29:44 tony * removed some more comments * * Revision 1.12 2000/01/09 19:24:36 morphy * Editorial changes, removed dead code an superfluous temporary variables * * Revision 1.11 2000/01/08 18:49:04 tony * oops * * Revision 1.10 2000/01/04 21:41:53 tony * removed redundant stuff for jokers * * Revision 1.9 2000/01/02 15:59:36 tony * truecolor mapiing fixed, rgbToNum was the one * * Revision 1.8 1999/12/26 23:13:24 tony * some comments about colormaps, QueryColor(). * some cleaning up in COLOR_GetColormap() */ /** \file * Color mapping for XFrisk GUI * * \b See: http://www.hp.com/xwindow/sharedInfo/Whitepapers/Visuals/visuals.html#WHAT_VISUAL * * \b From: http://www.motifzone.com/resources/man/XAllocStandardColormap.html * * The colormap member is the colormap created by the * XCreateColormap function. The red_max, green_max, and * blue_max members give the maximum red, green, and blue * values, respectively. Each color coefficient ranges from * zero to its max, inclusive. For example, a common colormap * allocation is 3/3/2 (3 planes for red, 3 planes for green, * and 2 planes for blue). This colormap would have red_max = * 7, green_max = 7, and blue_max = 3. An alternate allocation * that uses only 216 colors is red_max = 5, green_max = 5, and * blue_max = 5. * * The red_mult, green_mult, and blue_mult members give the * scale factors used to compose a full pixel value. (See the * discussion of the base_pixel members for further informa- * tion.) For a 3/3/2 allocation, red_mult might be 32, * green_mult might be 4, and blue_mult might be 1. For a 6- * colors-each allocation, red_mult might be 36, green_mult * might be 6, and blue_mult might be 1. * * The base_pixel member gives the base pixel value used to * compose a full pixel value. Usually, the base_pixel is * obtained from a call to the XAllocColorPlanes function. * Given integer red, green, and blue coefficients in their * appropriate ranges, one then can compute a corresponding * pixel value by using the following expression: * * (r * red_mult + g * green_mult + b * blue_mult + base_pixel) & 0xFFFFFFFF * */ #include #include #include #include #include "colormap.h" #include "client.h" #include "utils.h" #include "riskgame.h" #include "gui-vars.h" #include "debug.h" /* Private data */ /** * Fallback resource filename for use in discovering visual properties * \bug Should use a globally defined filename macro */ static CString strResources[] = { #ifdef ENGLISH #include "english.res" #endif #ifdef FRENCH #include "french.res" #endif NULL }; /** Color index to country index mapping table */ static Int32 piColorToCountry[MAX_COLORS]; /** Main color map */ static Color pWorldColors[MAX_COLORS]; /** Flag to indicate if display is true color */ static Flag trueColor = FALSE; /** Colormap used in truecolor */ unsigned long colormap[MAX_COLORS]; /** * Country index to color index mapping * 42 countries, 1 ocean, 1 lines, 3 dice, x players... * They must be long because that's how XAllocColorCells fills it */ unsigned long plCountryToColor[MAX_COLORS]; Colormap cmapColormap = 0; Int32 iNumColors; Int32 COLOR_Depth; /* Local variables for conversion between rgb and screen values. */ static int redShift, greenShift, blueShift; static int redMove, greenMove, blueMove; static Int32 redMask, greenMask, blueMask; /** * Returns number of used colors */ Int32 COLOR_GetNumColors(void) { return iNumColors; } /** * Sets number of used colors */ void COLOR_SetNumColors(Int32 iNum) { iNumColors = iNum; } /** * Returns color depth */ Int32 COLOR_GetDepth(void) { return COLOR_Depth; } /** * Finds and stores RGB shift and move values * * \b History: * \arg 31.01.98 JRXR Created. * */ void COLOR_InitRGB(XVisualInfo *Info) { Int32 r,g,b; int i; if (Info->class == TrueColor) { r = redMask = Info->red_mask; g = greenMask = Info->green_mask; b = blueMask = Info->blue_mask; for ( i=0 ; !(r & 1) ; r=r>>1,i++ ) ; redShift=i; for ( i=16 ; r ; r=r>>1,i-- ) ; redMove=i; for ( i=0 ; !(g & 1) ; g=g>>1,i++ ) ; greenShift=i; for ( i=16 ; g ; g=g>>1,i-- ) ; greenMove=i; for ( i=0 ; !(b & 1) ; b=b>>1,i++ ) ; blueShift=i; for ( i=16 ; b ; b=b>>1,i-- ) ; blueMove=i; } else if (Info->class == PseudoColor) { redMove = greenMove = blueMove = 8; redMask = 0x0000ff; greenMask = 0x00ff00; blueMask = 0xff0000; redShift = 0; greenShift = 8; blueShift = 16; } } /** * Separates RGB components from 32bit representation to separate 16bit variables * * \param Num 32bit composite RGB representation * \param Red Pointer to 16bit variable for red component * \param Green Pointer to 16bit variable for green component * \param Blue Pointer to 16bit variable for blue component * * \b History: * \arg 31.01.98 JRXR Created. * \arg 13.01.00 MSH Commented. */ void COLOR_numTorgb( Int32 Num, UInt16 *Red, UInt16 *Green, UInt16 *Blue ) { /* Mask out component and shift it to correct position */ *Red = ((Num & redMask) >> redShift) << redMove; *Green = ((Num & greenMask) >> greenShift) << greenMove; *Blue = ((Num & blueMask) >> blueShift) << blueMove; } /** * Combines given RGB component values to 32bit composite representation. * * \param Red 16bit red component * \param Green 16bit green component * \param Blue 16bit blue component * * \b History: * \arg 31.01.98 JRXR Created. * \arg 13.01.00 MSH Commented. */ Int32 COLOR_rgbToNum(Int32 Red, Int32 Green, Int32 Blue) { Int32 r,g,b; /* Separate significant bits from color components */ r = Red >> redMove; g = Green >> greenMove; b = Blue >> blueMove; /* Sum up the components */ return (r<height; y++) { for (x = 0; x < pMapImage->width; x++) { /* this returns *index* of color from the original worldmap */ c = XGetPixel(pMapImage, x, y); /* needed for compatibility with pseudocolor. * it's one on one in truecolor * country that belongs to this pixelvalue */ i = COLOR_ColorToCountry(c); c = COLOR_QueryColor(i); XSetForeground(hDisplay, hGC, c); XDrawPoint(hDisplay, pixMapImage, hGC, x, y); } } XCopyArea(hDisplay, pixMapImage, hWindow, hGC, 0, 0, pMapImage->width, pMapImage->height, 0, 0); } else { for (i=0; i < iNumColors; i++) { xColor.flags = DoRed | DoGreen | DoBlue; xColor.pixel = COLOR_CountryToColor(i); xColor.red = pWorldColors[i].r << 8; xColor.green = pWorldColors[i].g << 8; xColor.blue = pWorldColors[i].b << 8; D_Assert(xColor.pixel<=MAX_COLORS, "Pixel out of range."); XStoreColor(hDisplay, cmapColormap, &xColor); } } XFlush(hDisplay); } /** * Maps die index to color index. * * \bug Should map to real color value instead of just index. * * \b History: * \arg 03.04.94 ESF Created. * \arg 03.05.94 ESF Fixed bug, wrong offset. * \arg 08.28.94 ESF Fixed bug, wrong argument. * \arg 13.01.00 MSH Commented. */ Int32 COLOR_DieToColor(Int32 iDie) { D_Assert(iDie>=0 && iDie=0 && iCountry=0 && iPlayer=0 && iCountry=0 && iPlayerheight ; i++) { if(y+i<0) continue; for (j = 0; j < 300 && x+j < pMapImage->width ; j++) { if(x+j<0) continue; if (XGetPixel(pMapImage, x+j, y+i) == c) XDrawPoint(hDisplay, pixMapImage, hGC, x+j, y+i); } } XCopyArea(hDisplay, pixMapImage, hWindow, hGC, x, y, 300, 150, x, y); } } /** * Maps color index to country index. * * \b History: * \arg 02.05.94 ESF Created. * \arg 05.05.94 ESF Fixed for new colormap scheme. */ Int32 COLOR_ColorToCountry(Int32 iColor) { D_Assert(iColor>=0 && iColor=COLOR_CountryToColor(0) && iSrc<=COLOR_DieToColor(3), "Source color out of range."); D_Assert(iDst>=COLOR_CountryToColor(0) && iDst<=COLOR_DieToColor(3), "Dest. color out of range."); if(trueColor) { colormap[iDst] = colormap[iSrc]; } else { xColor.flags = DoRed | DoGreen | DoBlue; xColor.pixel = iSrc; XQueryColor(hDisplay, cmapColormap, &xColor); xColor.pixel = iDst; XStoreColor(hDisplay, cmapColormap, &xColor); } XFlush(hDisplay); } /** * Set color of given player to given color string. * * \b History: * \arg 05.03.94 ESF Created. * \arg 04.06.95 ESF Fixed bug, store closest displayable color. * \arg 17.08.95 JC true colors. */ void COLOR_StoreNamedColor(CString strPlayerColor, Int32 iPlayer) { XColor xColor, xColorClosest; D_Assert(iPlayer>=0 && iPlayer #include #include #include "types.h" #include "debug.h" /* Debug output */ FILE *hDebugFile; #endif #ifdef MEM_DEBUG #define ptrFakeToReal(a) (void *)(&((Pointer *)a)[0] - 1) #define ptrRealToFake(a) (void *)(&((Pointer *)a)[0] + 1) #define MAGIC_COOKIE1 0xab #define MAGIC_COOKIE2 0xcd #define MAGIC_COOKIE3 0xef #define MAGIC_COOKIE4 0x12 #define MEM_FILL 0xCC #define MAX_DATA 32 #define PAD_SIZE 8 /* In bytes, on each side of block. */ #ifndef TRUE #define TRUE 1 #endif #ifndef FALSE #define FALSE 0 #endif /* Data structure for hashing */ #define HASH_TABLE_SIZE 101 Flag fBootStrapped = FALSE; /* Data type for storing line/file info for non stack trace debugging */ typedef struct _Trace { UInt32 uiLine; Char szFile[MAX_DATA]; } Trace; /* A cell object for a singly linked list for the chain in chained hashing */ typedef struct _CELL { Pointer uiKey; /* pointer to memory */ size_t size; /* amount of memory */ Trace trcTrace; /* trace data */ struct _CELL *next; } Cell; /* Declare the hash table */ struct { UInt32 uiEntries; UInt32 uiTotalMem; UInt32 uiRealMem; Cell *ppChain[HASH_TABLE_SIZE]; } HashTable; /* Here is the magic cookie */ unsigned char MagicCookie[] = { MAGIC_COOKIE1, MAGIC_COOKIE2, MAGIC_COOKIE3, MAGIC_COOKIE4 }; #endif #ifdef ASSERTIONS /************************************************************************ * FUNCTION: _D_AssertFailed * HISTORY: * ??.??.93 ESF Created. * 05.19.94 ESF Cleaned up. * 10.03.94 ESF Added check for hFile. * 06.05.97 DAH hFile -> hDebugFile * PURPOSE: * Private function called when an assertion fails. * NOTES: ************************************************************************/ void _D_AssertFailed(CString strFile, UInt32 iLine, CString strAssert, CString strError) { Char szTemp[128]; Char *pNull = 0; MEM_BootStrap("debug.log"); snprintf(szTemp, sizeof(szTemp), "Assertion Failed (%s) @ (%s, %d) :: %s\n", strAssert, strFile, iLine, strError); if (hDebugFile) fprintf(hDebugFile, szTemp); printf("%s", szTemp); /* Dereference a NULL pointer to cause seg fault. */ *pNull = 0; /* Just in case that didn't work. */ exit(-1); } #endif #ifdef MEM_DEBUG /************************************************************************ * FUNCTION: D_BootStrap * HISTORY: * ??.??.93 ESF Created. * 05.19.94 ESF Cleaned up. * 10.03.94 ESF Added check for hFile. * 06.05.97 DAH hFile -> hDebugFile * PURPOSE: * NOTES: ************************************************************************/ void D_BootStrap(CString strFileName) { /* Setup the hash table, and the debug log file */ D_MemInitHashTable(); hDebugFile = fopen(strFileName, "w"); D_Assert(hDebugFile, "Could not open debugging file!"); fBootStrapped = TRUE; } /************************************************************************ * FUNCTION: D_MemAlloc * HISTORY: * ??.??.93 ESF Created. * 05.19.94 ESF Cleaned up. * PURPOSE: * NOTES: * Allocate 8 bytes more than is called for and use this to check * for overflows. Init it to MAGIC_COOKIE, then it got overwritten. * Allocate 8 bytes so that we can put one after the memory region * returned, and one before, and 8 instead of 1 because some * architectures (namely the PA-RISC) barf if we don't. Also fill * the memory with the value MEM_FILL. ************************************************************************/ void *D_MemAlloc(size_t size, UInt32 uiLine, CString strFile) { void *pvTemp; Byte *pbTemp; Char szTemp[256]; size_t s; MEM_BootStrap("debug.log"); /* Are we allocating a > 0 size block? */ D_AssertWhere(size>0, "Trying to allocate 0 or less bytes of memory!", uiLine, strFile); /* Allocate the block */ pvTemp = (void *)malloc(size + PAD_SIZE*2); pbTemp = (Byte *)pvTemp; /* Did it work? */ snprintf(szTemp, sizeof(szTemp), "Out of memory (%d bytes requested).", (Pointer)size); D_AssertWhere(pbTemp != NULL, szTemp, uiLine, strFile); /* Fill the memory with MEM_FILL */ memset(pvTemp, MEM_FILL, size+PAD_SIZE*2); /* Init the safety Fields */ for(s=0; s!=4; s++) pbTemp[s] = pbTemp[size+PAD_SIZE*2-s-1] = MagicCookie[s]; /* Output debug info */ snprintf(szTemp, sizeof(szTemp), "MEM_Alloc(): Created at (%s, %d) ==> %d bytes, at " "0x%08x\n", strFile, uiLine, size, (Pointer)ptrRealToFake(pbTemp)); D_PrintStr(szTemp); /* Put the new pointer into the hash table and return it */ D_MemHashNewEntry((Pointer)pbTemp, size, uiLine, strFile); return(ptrRealToFake(pbTemp)); } /************************************************************************ * FUNCTION: D_MemFree * HISTORY: * ??.??.93 ESF Created. * 05.19.94 ESF Cleaned up. * PURPOSE: * Frees memory. * NOTES: ************************************************************************/ void D_MemFree(FakePtr vPtr, UInt32 uiLine, CString strFile) { size_t size; MEM_BootStrap("debug.log"); /* Note that we're freeing a chunk */ D_PrintStrLong("MEM_Free(): Freeing chunk [0x%08x] in (", (Pointer)vPtr); D_PrintStr(strFile); D_PrintStrLong(", %d)\n", uiLine); /* If the pointer is valid, check it for corruptness */ D_AssertWhere(D_MemKeyInTable((Pointer)ptrFakeToReal(vPtr)), "Attempting to free bogus pointer!", uiLine, strFile); D_MemCheckPointer(vPtr, uiLine, strFile, 0); /* Update the memory usage info */ size = D_MemGetBlockSize(vPtr); HashTable.uiTotalMem -= size; HashTable.uiRealMem -= size - PAD_SIZE*2; /* Fill it with the value we use for new memory */ /* Some platform was touchy about this line (!?!?!?) */ /* memset(ptrFakeToReal(vPtr), MEM_FILL, size); */ /* Take it out of the hash table */ D_MemDeleteEntry((Pointer)ptrFakeToReal(vPtr)); /* Actually free it */ free(ptrFakeToReal(vPtr)); } /************************************************************************ * FUNCTION: D_MemShrink * HISTORY: * ??.??.93 ESF Created. * 05.19.94 ESF Cleaned up. * PURPOSE: * Realloc with the additional condition that we must be shrinking * the size of the region allocated. * NOTES: ************************************************************************/ void *D_MemShrink(FakePtr fakePtr, size_t sizeNew) { Byte *pbPtr; size_t size; MEM_BootStrap("debug.log"); /* Make sure we're shrinking memory */ size = D_MemGetBlockSize(fakePtr); D_Assert(size>sizeNew, "Not Shrinking Memory!"); /* Do the reallocation */ pbPtr = (Byte *)MEM_Alloc(sizeNew); memcpy(pbPtr, ptrFakeToReal(fakePtr), size); MEM_Free(fakePtr); return (FakePtr)pbPtr; } /************************************************************************ * FUNCTION: D_MemGrow * HISTORY: * ??.??.93 ESF Created. * 05.19.94 ESF Cleaned up. * PURPOSE: * Realloc with the additional condition that we must be enlarging * the size of the region allocated. * NOTES: ************************************************************************/ void *D_MemGrow(FakePtr fakePtr, size_t sizeNew) { Byte *pbPtr; size_t size; MEM_BootStrap("debug.log"); /* Make sure we're enlarging the size */ size = D_MemGetBlockSize(fakePtr); D_Assert(sizetrcTrace.uiLine = uiLine; StringCopy(pCell->trcTrace.szFile, strFile, MAX_DATA); /* Update the memory usage */ HashTable.uiEntries ++; HashTable.uiTotalMem += size; HashTable.uiRealMem += size + PAD_SIZE*2; /* set up a new cell with the key in it */ pCell->uiKey = uiKey; pCell->next = HashTable.ppChain[uiIndex]; pCell->size = size; /* link the new cell onto the old chain */ HashTable.ppChain[uiIndex] = pCell; } /************************************************************************ * FUNCTION: D_MemDeleteEntry * HISTORY: * ??.??.93 ESF Created. * 05.19.94 ESF Cleaned up. * PURPOSE: * This function cannot fail! Deletes a memory table entry * from the hash table. * NOTES: ************************************************************************/ void D_MemDeleteEntry(Pointer uiKey) { UInt32 uiIndex; /* slot in hash table that the key is hashed to */ Cell *pBob, *pJoe; /* just your average pointers */ uiIndex = D_MemHashFunc(uiKey); /* Searching the chain to find the key, if present */ for(pJoe=pBob=HashTable.ppChain[uiIndex]; pBob && pBob->uiKey!=uiKey; pJoe=pBob, pBob=pBob->next) /* TwiddleThumbs() */; /* Are we in trouble? */ D_Assert(pBob && pBob->uiKey == uiKey, "Element not in hash table (?!)"); if(pBob==pJoe) { HashTable.ppChain[uiIndex] = pBob->next; free(pJoe); } else { pJoe->next = pJoe->next->next; free(pBob); } } /************************************************************************ * FUNCTION: D_MemInitHashTable * HISTORY: * ??.??.93 ESF Created. * 05.19.94 ESF Cleaned up. * PURPOSE: * Initializes the hash table by setting the keys equal to zero and the * chain pointers to NULL. * NOTES: ************************************************************************/ void D_MemInitHashTable(void) { UInt32 i; /* Go through, set the chain pointer to NULL */ for(i=0; i!=HASH_TABLE_SIZE; i++) HashTable.ppChain[i] = NULL; /* Reset other parameters */ HashTable.uiEntries = 0; HashTable.uiTotalMem = HashTable.uiRealMem = (UInt32)0; } /************************************************************************ * FUNCTION: D_MemGetBlockSize * HISTORY: * ??.??.93 ESF Created. * 05.19.94 ESF Cleaned up. * PURPOSE: * If entry in table, return size. If not, assert and exit. * Should always be in table when we call. * NOTES: ************************************************************************/ size_t D_MemGetBlockSize(FakePtr fakePtr) { UInt32 uiIndex; /* slot in the hash table that the key is hashed to */ Cell *pBob; /* just your average pointer */ Pointer uiTemp = (Pointer)ptrFakeToReal(fakePtr); uiIndex = D_MemHashFunc(uiTemp); /* searching the chain to find the key, if present */ for(pBob=HashTable.ppChain[uiIndex]; pBob && pBob->uiKey!=uiTemp; pBob=pBob->next) /* TwiddleThumbs() */ ; if(!(pBob && pBob->uiKey == uiTemp)) return (size_t)0; return (size_t)pBob->size; } /************************************************************************ * FUNCTION: D_MemKeyInTable * HISTORY: * ??.??.93 ESF Created. * 05.19.94 ESF Cleaned up. * PURPOSE: * Searches in a hash table for a key and returns TRUE is the key * is present and FALSE otherwise. * NOTES: ************************************************************************/ Flag D_MemKeyInTable(Pointer uiKey) { UInt32 uiIndex; /* slot in the hash table that the key is hashed to */ Cell *pBob; /* just your average pointer */ uiIndex = D_MemHashFunc(uiKey); /* searching the chain to find the key, if present */ for(pBob=HashTable.ppChain[uiIndex]; pBob; pBob=pBob->next) if(pBob->uiKey==uiKey) return(TRUE); return(FALSE); } /************************************************************************ * FUNCTION: D_MemCheckPointer * HISTORY: * ??.??.93 ESF Created. * 05.19.94 ESF * PURPOSE: * Checks a pointer for data overrun. NOTE!!!!! This is a fake type * pointer that is checked, not areal pointer, since it assumes that * the region of memory directly after and before one dword is valid! * NOTES: ************************************************************************/ void D_MemCheckPointer(FakePtr fakePtr, UInt32 uiLine, CString strFile, Flag fDisp) { Byte *bPtr = (Byte *)ptrFakeToReal(fakePtr); size_t size, s; MEM_BootStrap("debug.log"); /* Be verbose about it if so desired */ if(fDisp) { D_PrintStrLong("MEM_CheckPointer(): Chunk [0x%08x] in (", (Pointer)fakePtr); D_PrintStr(strFile); D_PrintStrInt32(", %d) ", uiLine); } /* Is it even in the hash table? */ D_AssertWhere((size=D_MemGetBlockSize(fakePtr)), "Bogus pointer!", uiLine, strFile);; if(fDisp) D_PrintStrLong(" [%d bytes]\n", (size_t)size); /* Check for the magic cookie */ for(s=0; s!=4; s++) { if(bPtr[s] != MagicCookie[s]) { /* Print the cookie */ D_PrintStr("Lower Cookie: ["); for(s=0; s!=4; s++) D_PrintStrLong("0x%02x|", bPtr[s]); D_PrintStr("]\n"); D_AssertWhere(FALSE, "Corrupt Memory (Underflow)!", uiLine, strFile); } if(bPtr[size+PAD_SIZE*2-s-1] != MagicCookie[s]) { /* Print the cookie */ D_PrintStr("Upper Cookie: ["); for(s=0; s!=4; s++) D_PrintStrLong("0x%02x|", (Pointer)bPtr[size+PAD_SIZE*2-s-1]); D_PrintStr("]\n"); D_AssertWhere(FALSE, "Corrupt Memory (Overflow)!", uiLine, strFile); } } } /************************************************************************ * FUNCTION: D_MemCheckAllPointers * HISTORY: * ??.??.93 ESF Created. * 05.19.94 ESF Cleaned up. * PURPOSE: * NOTES: ************************************************************************/ void D_MemCheckAllPointers(UInt32 uiLine, CString strFile) { UInt32 i; Cell *pCell; MEM_BootStrap("debug.log"); /* Dump some verbose information */ D_PrintStr("MEM_CheckAllPointers(): Performing memory check in ("); D_PrintStr(strFile); D_PrintStrLong(", %d)...\n", uiLine); D_PrintStrInt32(" Total Memory allocated by client: %d\n", HashTable.uiTotalMem); /* Run through the whole hash pointer, dumping and checking the pointers */ for(i=0; i!=HASH_TABLE_SIZE; i++) for(pCell=HashTable.ppChain[i]; pCell; pCell=pCell->next) { D_PrintStr(" "); D_MemCheckPointer(ptrRealToFake(pCell->uiKey), pCell->trcTrace.uiLine, pCell->trcTrace.szFile, 1); } } /************************************************************************ * FUNCTION: D_MemDumpPointers * HISTORY: * ??.??.93 ESF Created. * 05.19.94 ESF Cleaned up. * PURPOSE: * NOTES: ************************************************************************/ void D_MemDumpPointers(void) { UInt32 i, uiCount; Cell *pCell; MEM_BootStrap("debug.log"); D_PrintStr("MEM_DumpPointers(): Dumping all pointers...\n"); /* Run through the whole hash table */ for(i=uiCount=0; i!=HASH_TABLE_SIZE; i++) { D_PrintStrInt32("%d: ", i); for(pCell=HashTable.ppChain[i]; pCell; pCell=pCell->next, uiCount++) D_PrintStrLong("0x%08x, ", (Pointer)pCell->uiKey); D_PrintStr("\n"); } D_PrintStrInt32("***** Total Chunks in Hash Table: %d\n", uiCount); } /************************************************************************ * FUNCTION: StringCopy * HISTORY: * ??.??.93 ESF Created. * 05.19.94 ESF Cleaned up. * PURPOSE: * NOTES: ************************************************************************/ CString StringCopy(CString strDst, CString strSrc, UInt16 usNum) { strncpy(strDst, strSrc, usNum-1); strDst[usNum-1] = '\0'; return(strDst); } /************************************************************************ * FUNCTION: D_TheEnd * HISTORY: * ??.??.93 ESF Created. * 05.19.94 ESF Cleaned up. * PURPOSE: * NOTES: ************************************************************************/ void D_TheEnd(void) { UInt32 i; Cell *p, *q, *pCell; /* Mind your P's and Q's... */ /* Check for memory leaks */ D_PrintStr("************ Memory Leaks ***********\n"); D_PrintStrInt32(" Total Memory allocated by client: %d\n", HashTable.uiTotalMem); /* Run through the whole hash pointer, freeing all of the pointers */ for(i=0; i!=HASH_TABLE_SIZE; i++) for(pCell=HashTable.ppChain[i]; pCell; pCell=pCell->next) { D_PrintStr(" "); D_MemCheckPointer(ptrRealToFake(pCell->uiKey), pCell->trcTrace.uiLine, pCell->trcTrace.szFile, 1); /* EThreads was touchy about this line (!?!?) */ /* MEM_Free(ptrRealToFake(pCell->uiKey)); */ } for (i=0; i!=HASH_TABLE_SIZE; i++) for (p=HashTable.ppChain[i]; p; p=q) { q = p->next; free(p); } } /************************************************************************ * FUNCTION: D_MemHashFunc * HISTORY: * ??.??.93 ESF Created. * 05.19.94 ESF Cleaned up. * PURPOSE: * NOTES: ************************************************************************/ UInt32 D_MemHashFunc(Pointer x) { return (UInt32)(x % (Pointer)HASH_TABLE_SIZE); } #else #define NOT_EMPTY #endif xfrisk-1.2/debug.h0100644000175000017500000001073307013357407013150 0ustar johnojohno/* * XFrisk - The classic board game for X * Copyright (C) 1993-1999 Elan Feingold (elan@aetherworks.com) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * $Id: debug.h,v 1.4 1999/11/13 21:58:31 morphy Exp $ */ #ifndef _DEBUG #define _DEBUG /* Turn assertions on if MEM_DEBUG is on */ #ifdef MEM_DEBUG #ifndef ASSERTIONS #define ASSERTIONS #endif #endif #include #include #include #include #include "types.h" /* This is the public header file and should be used by programmers * in their files. Any functions not declared in here, as well as * any data structures in debug.c are OFF LIMITS! Functions should * be accesed by their MEM_ equivalents to ensure that they disappear * when DEBUG is not defined. */ extern Flag fBootStrapped; extern FILE *hDebugFile; typedef void *FakePtr; #ifdef ASSERTIONS #define D_Assert(expr, szError) (expr) ? (void)0 : \ (void)_D_AssertFailed(__FILE__, __LINE__, #expr, szError) #define D_AssertWhere(expr, szError, iLine, szFile) (expr) ? (void)0 : \ (void)_D_AssertFailed(szFile, iLine, #expr, szError) #define D_PrintStr(str) { fprintf(hDebugFile, str); fflush(hDebugFile); } #define D_PrintStrInt32(str, iInt32) { fprintf(hDebugFile, str, iInt32); \ fflush(hDebugFile); } #define D_PrintStrLong(str, lLong) { fprintf(hDebugFile, str, lLong); \ fflush(hDebugFile); } #else #define D_PrintStr(szString) ; #define D_PrintStrInt(szString, i) ; #define D_PrintStrLong(szString, l) ; #define D_Assert(expr, str) ; #define D_AssertWhere(expr, s, i, e) ; #endif #ifdef MEM_DEBUG #define MEM_BootStrap(str) if(fBootStrapped==FALSE) D_BootStrap(str) #define MEM_Alloc(uSize) D_MemAlloc(uSize, __LINE__, __FILE__) #define MEM_Free(vPtr) { D_MemFree((void *)vPtr, __LINE__, __FILE__); vPtr=NULL; } #define MEM_CheckPointer(vPtr) D_MemCheckPointer(vPtr, __LINE__, __FILE__, 1) #define MEM_Shrink(vPtr, iNewSize) D_MemShrink(vPtr, iNewSize) #define MEM_Grow(vPtr, iNewSize) D_MemGrow(vPtr, iNewSize) #define MEM_DumpUsage() D_MemDumpUsage() #define MEM_CheckAllPointers() D_MemCheckAllPointers(__LINE__, __FILE__) #define MEM_DumpPointers() D_MemDumpPointers() #define MEM_TheEnd() D_TheEnd() #else #define MEM_Alloc(uSize) malloc(uSize) #define MEM_Free(vPtr) free((void *)vPtr) #define MEM_CheckPointer(vPtr) ; #define MEM_CheckAllPointers() ; #define MEM_Shrink(vPtr, iNewSize) realloc(vPtr, iNewSize) #define MEM_Grow(vPtr, iNewSize) realloc(vPtr, iNewSize) #define MEM_DumpUsage() ; #define MEM_BootStrap(str) ; #define MEM_TheEnd() ; #endif /* Random assertion helpers */ void _D_AssertFailed(CString strFile, UInt32 uiLine, CString strAssertion, CString strError); /* prototypes for debugging memory functions */ void *D_MemAlloc(size_t uSize, UInt32 uiLine, CString strFile); void D_MemFree(FakePtr fakePtr, UInt32 uiLine, CString strFile); void *D_MemShrink(void *vPtr, size_t sizeNew); void *D_MemGrow(void *vPtr, size_t sizeNew); void D_MemCheck(void); void D_MemDumpUsage(void); /* Pointer Checker stuff */ void D_MemCheckPointer(FakePtr fakePtr, UInt32 uiLine, CString strFile, Flag fDisp); void D_MemCheckAllPointers(UInt32 uiLine, CString strFile); void D_MemDumpPointers(void); size_t D_MemGetBlockSize(FakePtr fakePtr); /* Prototypes for hashing functions used */ void D_MemHashNewEntry(Pointer uiKey, size_t sizeBlock, UInt32 uiLine, CString strFile); void D_MemInitHashTable(void); Flag D_MemKeyInTable(Pointer uiKey); UInt32 D_MemHashFunc(Pointer uiNumber); void D_MemDeleteEntry(Pointer uiKey); /* Misc prototypes */ void D_BootStrap(CString str); void D_TheEnd(void); char *StringCopy(CString str1, CString str2, UInt16 usLength); #endif xfrisk-1.2/deck.c0100644000175000017500000001215407031214161012747 0ustar johnojohno/* * XFrisk - The classic board game for X * Copyright (C) 1993-1999 Elan Feingold (elan@aetherworks.com) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * $Id: deck.c,v 1.11 1999/12/25 19:18:09 morphy Exp $ * $Log: deck.c,v $ * Revision 1.11 1999/12/25 19:18:09 morphy * Corrected comment errors * * Revision 1.10 1999/12/19 22:48:27 tony * cl0d feexed the greenland card! * * Revision 1.9 1999/12/19 19:25:43 tony * added $Log: deck.c,v $ * added Revision 1.11 1999/12/25 19:18:09 morphy * added Corrected comment errors * added * added Revision 1.10 1999/12/19 22:48:27 tony * added cl0d feexed the greenland card! * added * */ /** \file * Card deck handling routines for the server */ #include #include #include #include #include "deck.h" #include "debug.h" /** \struct _Deck * Structure for card deck data. * * \b Note: This is now opaque - it can only be manipulated within \link deck.c deck.c \endlink */ struct _Deck { Int32 iCardsLeft; /**< Number of cards still in the deck */ Int32 iCardsReturned; /**< Number of cards returned to the deck */ Int32 iTotalCards; /**< Total number of cards in deck */ Int32 *piCards; /**< Pointer to list of cards still in the deck */ Int32 *piCardsReturned; /**< Pointer to list of cards returned to the deck */ }; /** * Create a card deck. * * \b History: * \arg 02.04.94 ESF Created. * \arg 03.16.94 ESF Added code for returned card handling. */ Deck *DECK_Create(Int32 iNumCards) { Deck *pDeck = (Deck *)MEM_Alloc(sizeof(Deck)); Int32 i; /* Seed the random number generator */ srand(time(NULL)); /* Init the structure */ pDeck->iCardsLeft = pDeck->iTotalCards = iNumCards; pDeck->iCardsReturned = 0; pDeck->piCards = (Int32 *)MEM_Alloc(sizeof(Int32)*iNumCards); pDeck->piCardsReturned = (Int32 *)MEM_Alloc(sizeof(Int32)*iNumCards); /* Init all of the cards */ for(i=0; i!=iNumCards; i++) pDeck->piCards[i] = i; return(pDeck); } /** * Draw a random card from the deck. * * \b History: * \arg 02.04.94 ESF Created. * \arg 03.16.94 ESF Added code for returned card handling. * \arg 05.15.94 ESF Changed to return -1 when deck is empty. */ Int32 DECK_GetCard(Deck *pDeck) { Int32 iCardIndex, iCard; /* If there are no cards left, take all of the cards from the * returned pile and put them into the deck. */ if (!pDeck->iCardsLeft) { /* Are there cards to return to the deck? */ if (!pDeck->iCardsReturned) return(-1); /* Copy all of the returned cards to the deck */ memcpy((char *)pDeck->piCards, (char *)pDeck->piCardsReturned, sizeof(Int32)*pDeck->iCardsReturned); pDeck->iCardsLeft = pDeck->iCardsReturned; pDeck->iCardsReturned = 0; #ifdef MEM_DEBUG { Int32 i; printf("New deck:\n"); for (i=0; i!=pDeck->iCardsLeft; i++) printf("%d.", pDeck->piCards[i]); printf("\n"); } #endif } /* Pick a card out of the remaining ones */ iCardIndex = rand() % pDeck->iCardsLeft; /* Switch the last card with this one. */ iCard = pDeck->piCards[iCardIndex]; pDeck->piCards[iCardIndex] = pDeck->piCards[--pDeck->iCardsLeft]; return(iCard); } /** * Add (return) a card to the deck. * \param pDeck Pointer to the deck * \param iCard Number of card to add * * \b History: * \arg 02.04.94 ESF Created. * \arg 03.16.94 ESF Fixed so that it would act like a real deck. * \arg 03.29.94 ESF Fixed a dumb bug in full deck detection. * \arg 25.08.95 JC Check total of cards. * \arg 15.11.99 Tdh Changed '>' into '>=' * \arg 17.12.99 MSH Removed superfluous UTIL_ExitProgram() call */ void DECK_PutCard(Deck *pDeck, Int32 iCard) { /* If returned card pile fills up, this is bad */ D_Assert(pDeck,"no deck passed"); if ((pDeck->iCardsLeft + pDeck->iCardsReturned) >= pDeck->iTotalCards) { #ifdef ENGLISH printf("Fatal Error! DECK: Can't add to full deck!\n"); #endif #ifdef FRENCH printf("Erreur fatale! Trop de cartes dans le jeu!\n"); #endif return; } /* Add the card to the retured cards pile */ pDeck->piCardsReturned[pDeck->iCardsReturned++] = iCard; } /** * Destroy the deck. * * \b History: * \arg 02.04.94 ESF Created. * \arg 03.16.94 ESF Added code for returned card handling. */ void DECK_Destroy(Deck *pDeck) { MEM_Free(pDeck->piCards); MEM_Free(pDeck->piCardsReturned); MEM_Free(pDeck); } xfrisk-1.2/deck.h0100644000175000017500000000222207013357407012762 0ustar johnojohno/* * XFrisk - The classic board game for X * Copyright (C) 1993-1999 Elan Feingold (elan@aetherworks.com) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * $Id: deck.h,v 1.4 1999/11/13 21:58:31 morphy Exp $ */ #ifndef _DECK #define _DECK #include "types.h" struct _Deck; typedef struct _Deck Deck; Deck *DECK_Create(Int32 iNumCards); Int32 DECK_GetCard(Deck *pDeck); void DECK_PutCard(Deck *pDeck, Int32 iCard); void DECK_Destroy(Deck *pDeck); #endif xfrisk-1.2/dice.bmp0100644000175000017500000001113007000075544013300 0ustar johnojohno#define five_width 28 #define five_height 28 static unsigned char five_bits[] = { 0xff, 0xff, 0xff, 0x0f, 0x01, 0x00, 0x00, 0x08, 0x01, 0x00, 0x00, 0x08, 0xf1, 0x00, 0xf0, 0x08, 0xe9, 0x01, 0xe8, 0x09, 0xe9, 0x01, 0xe8, 0x09, 0xc9, 0x01, 0xc8, 0x09, 0x19, 0x01, 0x18, 0x09, 0xf1, 0x00, 0xf0, 0x08, 0x01, 0x00, 0x00, 0x08, 0x01, 0x00, 0x00, 0x08, 0x01, 0xf0, 0x00, 0x08, 0x01, 0xe8, 0x01, 0x08, 0x01, 0xe8, 0x01, 0x08, 0x01, 0xc8, 0x01, 0x08, 0x01, 0x18, 0x01, 0x08, 0x01, 0xf0, 0x00, 0x08, 0x01, 0x00, 0x00, 0x08, 0x01, 0x00, 0x00, 0x08, 0xf1, 0x00, 0xf0, 0x08, 0xe9, 0x01, 0xe8, 0x09, 0xe9, 0x01, 0xe8, 0x09, 0xc9, 0x01, 0xc8, 0x09, 0x19, 0x01, 0x18, 0x09, 0xf1, 0x00, 0xf0, 0x08, 0x01, 0x00, 0x00, 0x08, 0x01, 0x00, 0x00, 0x08, 0xff, 0xff, 0xff, 0x0f}; #define four_width 28 #define four_height 28 static unsigned char four_bits[] = { 0xff, 0xff, 0xff, 0x0f, 0x01, 0x00, 0x00, 0x08, 0x01, 0x00, 0x00, 0x08, 0xf1, 0x00, 0xf0, 0x08, 0xe9, 0x01, 0xe8, 0x09, 0xe9, 0x01, 0xe8, 0x09, 0xc9, 0x01, 0xc8, 0x09, 0x19, 0x01, 0x18, 0x09, 0xf1, 0x00, 0xf0, 0x08, 0x01, 0x00, 0x00, 0x08, 0x01, 0x00, 0x00, 0x08, 0x01, 0x00, 0x00, 0x08, 0x01, 0x00, 0x00, 0x08, 0x01, 0x00, 0x00, 0x08, 0x01, 0x00, 0x00, 0x08, 0x01, 0x00, 0x00, 0x08, 0x01, 0x00, 0x00, 0x08, 0x01, 0x00, 0x00, 0x08, 0x01, 0x00, 0x00, 0x08, 0xf1, 0x00, 0xf0, 0x08, 0xe9, 0x01, 0xe8, 0x09, 0xe9, 0x01, 0xe8, 0x09, 0xc9, 0x01, 0xc8, 0x09, 0x19, 0x01, 0x18, 0x09, 0xf1, 0x00, 0xf0, 0x08, 0x01, 0x00, 0x00, 0x08, 0x01, 0x00, 0x00, 0x08, 0xff, 0xff, 0xff, 0x0f}; #define one_width 28 #define one_height 28 static unsigned char one_bits[] = { 0xff, 0xff, 0xff, 0x0f, 0x01, 0x00, 0x00, 0x08, 0x01, 0x00, 0x00, 0x08, 0x01, 0x00, 0x00, 0x08, 0x01, 0x00, 0x00, 0x08, 0x01, 0x00, 0x00, 0x08, 0x01, 0x00, 0x00, 0x08, 0x01, 0x00, 0x00, 0x08, 0x01, 0x00, 0x00, 0x08, 0x01, 0x00, 0x00, 0x08, 0x01, 0x00, 0x00, 0x08, 0x01, 0xf0, 0x00, 0x08, 0x01, 0xe8, 0x01, 0x08, 0x01, 0xe8, 0x01, 0x08, 0x01, 0xc8, 0x01, 0x08, 0x01, 0x18, 0x01, 0x08, 0x01, 0xf0, 0x00, 0x08, 0x01, 0x00, 0x00, 0x08, 0x01, 0x00, 0x00, 0x08, 0x01, 0x00, 0x00, 0x08, 0x01, 0x00, 0x00, 0x08, 0x01, 0x00, 0x00, 0x08, 0x01, 0x00, 0x00, 0x08, 0x01, 0x00, 0x00, 0x08, 0x01, 0x00, 0x00, 0x08, 0x01, 0x00, 0x00, 0x08, 0x01, 0x00, 0x00, 0x08, 0xff, 0xff, 0xff, 0x0f}; #define six_width 28 #define six_height 28 static unsigned char six_bits[] = { 0xff, 0xff, 0xff, 0x0f, 0x01, 0x00, 0x00, 0x08, 0x01, 0x00, 0x00, 0x08, 0xf1, 0x00, 0xf0, 0x08, 0xe9, 0x01, 0xe8, 0x09, 0xe9, 0x01, 0xe8, 0x09, 0xc9, 0x01, 0xc8, 0x09, 0x19, 0x01, 0x18, 0x09, 0xf1, 0x00, 0xf0, 0x08, 0x01, 0x00, 0x00, 0x08, 0x01, 0x00, 0x00, 0x08, 0xf1, 0x00, 0xf0, 0x08, 0xe9, 0x01, 0xe8, 0x09, 0xe9, 0x01, 0xe8, 0x09, 0xc9, 0x01, 0xc8, 0x09, 0x19, 0x01, 0x18, 0x09, 0xf1, 0x00, 0xf0, 0x08, 0x01, 0x00, 0x00, 0x08, 0x01, 0x00, 0x00, 0x08, 0xf1, 0x00, 0xf0, 0x08, 0xe9, 0x01, 0xe8, 0x09, 0xe9, 0x01, 0xe8, 0x09, 0xc9, 0x01, 0xc8, 0x09, 0x19, 0x01, 0x18, 0x09, 0xf1, 0x00, 0xf0, 0x08, 0x01, 0x00, 0x00, 0x08, 0x01, 0x00, 0x00, 0x08, 0xff, 0xff, 0xff, 0x0f, }; #define three_width 28 #define three_height 28 static unsigned char three_bits[] = { 0xff, 0xff, 0xff, 0x0f, 0x01, 0x00, 0x00, 0x08, 0x01, 0x00, 0x00, 0x08, 0xf1, 0x00, 0x00, 0x08, 0xe9, 0x01, 0x00, 0x08, 0xe9, 0x01, 0x00, 0x08, 0xc9, 0x01, 0x00, 0x08, 0x19, 0x01, 0x00, 0x08, 0xf1, 0x00, 0x00, 0x08, 0x01, 0x00, 0x00, 0x08, 0x01, 0x00, 0x00, 0x08, 0x01, 0xf0, 0x00, 0x08, 0x01, 0xe8, 0x01, 0x08, 0x01, 0xe8, 0x01, 0x08, 0x01, 0xc8, 0x01, 0x08, 0x01, 0x18, 0x01, 0x08, 0x01, 0xf0, 0x00, 0x08, 0x01, 0x00, 0x00, 0x08, 0x01, 0x00, 0x00, 0x08, 0x01, 0x00, 0xf0, 0x08, 0x01, 0x00, 0xe8, 0x09, 0x01, 0x00, 0xe8, 0x09, 0x01, 0x00, 0xc8, 0x09, 0x01, 0x00, 0x18, 0x09, 0x01, 0x00, 0xf0, 0x08, 0x01, 0x00, 0x00, 0x08, 0x01, 0x00, 0x00, 0x08, 0xff, 0xff, 0xff, 0x0f}; #define two_width 28 #define two_height 28 static unsigned char two_bits[] = { 0xff, 0xff, 0xff, 0x0f, 0x01, 0x00, 0x00, 0x08, 0x01, 0x00, 0x00, 0x08, 0xf1, 0x00, 0x00, 0x08, 0xe9, 0x01, 0x00, 0x08, 0xe9, 0x01, 0x00, 0x08, 0xc9, 0x01, 0x00, 0x08, 0x19, 0x01, 0x00, 0x08, 0xf1, 0x00, 0x00, 0x08, 0x01, 0x00, 0x00, 0x08, 0x01, 0x00, 0x00, 0x08, 0x01, 0x00, 0x00, 0x08, 0x01, 0x00, 0x00, 0x08, 0x01, 0x00, 0x00, 0x08, 0x01, 0x00, 0x00, 0x08, 0x01, 0x00, 0x00, 0x08, 0x01, 0x00, 0x00, 0x08, 0x01, 0x00, 0x00, 0x08, 0x01, 0x00, 0x00, 0x08, 0x01, 0x00, 0xf0, 0x08, 0x01, 0x00, 0xe8, 0x09, 0x01, 0x00, 0xe8, 0x09, 0x01, 0x00, 0xc8, 0x09, 0x01, 0x00, 0x18, 0x09, 0x01, 0x00, 0xf0, 0x08, 0x01, 0x00, 0x00, 0x08, 0x01, 0x00, 0x00, 0x08, 0xff, 0xff, 0xff, 0x0f}; xfrisk-1.2/dice.c0100644000175000017500000000172207013357407012757 0ustar johnojohno/* * XFrisk - The classic board game for X * Copyright (C) 1993-1999 Elan Feingold (elan@aetherworks.com) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * $Id: dice.c,v 1.3 1999/11/13 21:58:31 morphy Exp $ */ #define DICE_NORMAL #include "diceCommon.c" #undef DICE_NORMAL xfrisk-1.2/dice.h0100644000175000017500000000230507013357407012762 0ustar johnojohno/* * XFrisk - The classic board game for X * Copyright (C) 1993-1999 Elan Feingold (elan@aetherworks.com) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * $Id: dice.h,v 1.4 1999/11/13 21:58:31 morphy Exp $ */ #ifndef _DICE #define _DICE #include "types.h" #ifndef DICE_AI void DICE_Init(void); void DICE_DrawDice(Int32 *pAttackDice, Int32 *pDefendDice); #endif void DICE_Refresh(void); void DICE_Hide(void); Int32 DICE_Attack(Int32 iAttack, Int32 iDefend, Int32 iAttacker, Int32 iDefender); #endif xfrisk-1.2/diceAI.c0100644000175000017500000000171407013357407013172 0ustar johnojohno/* * XFrisk - The classic board game for X * Copyright (C) 1993-1999 Elan Feingold (elan@aetherworks.com) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * $Id: diceAI.c,v 1.3 1999/11/13 21:58:31 morphy Exp $ */ #define DICE_AI #include "diceCommon.c" #undef DICE_AI xfrisk-1.2/diceCommon.c0100644000175000017500000002202107036460614014123 0ustar johnojohno/* * XFrisk - The classic board game for X * Copyright (C) 1993-1999 Elan Feingold (elan@aetherworks.com) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * $Id: diceCommon.c,v 1.9 2000/01/10 22:47:40 tony Exp $ */ #ifndef DICE_AI #include #include #include #include #include #endif #include "dice.h" #include "riskgame.h" #include "debug.h" #include "types.h" #include "client.h" #include "utils.h" #ifndef DICE_AI #include "gui-vars.h" #include "colormap.h" #include "dice.bmp" #endif #ifndef DICE_AI static Pixmap pixAttackDice[6]; static Pixmap pixDefendDice[6]; static Window hDiceWindow; static Int32 iWidth, iHeight; static Int32 iHorizontalOffset, iVerticalOffset; static Int32 iBoxWidth, iBoxHeight; static Int32 iBackgroundColor; #endif static Int32 piAttackDice[3] = {-1, -1, -1}; static Int32 piDefendDice[3] = {-1, -1, -1}; #define DICE_Swap(a, b, temp) { temp=a; a=b; b=temp; } #define DICE_SPACING 6 #ifndef DICE_AI /************************************************************************ * FUNCTION: DICE_Creat * HISTORY: * 17.08.95 JC Created (copy of DICE_Init). * 23.08.95 JC Use of COLOR_Depth. * PURPOSE: * NOTES: ************************************************************************/ void DICE_Creat(Flag eff, Int32 iAttack, Int32 iDefend) { static Int32 attackColor = -1; static Int32 defendColor = -1; static struct { Byte *pbBits; } pDice[] = { { one_bits }, { two_bits }, { three_bits }, { four_bits }, { five_bits }, { six_bits }, }; Int32 i; Dimension dimBoxWidth, dimBoxHeight; hDiceWindow = XtWindow(wDiceBox); /* Find the width and height of the bitmaps, assuming THEY ARE EQUAL */ iWidth = one_height; iHeight = one_width; /* Get data from the die box widget */ XtVaGetValues(wDiceBox, XtNwidth, &dimBoxWidth, XtNheight, &dimBoxHeight, XtNbackground, &iBackgroundColor, NULL); iBoxWidth = dimBoxWidth; iBoxHeight = dimBoxHeight; iHorizontalOffset = ((Int32)dimBoxWidth-3*iWidth-2*DICE_SPACING)/2; iVerticalOffset = ((Int32)dimBoxHeight-2*iWidth-DICE_SPACING)/2; iAttack = COLOR_QueryColor(iAttack); if (iAttack != attackColor) { attackColor = iAttack; /* Create the attack dice */ for (i=0; i!=6; i++) { if (eff) XFreePixmap (hDisplay, pixAttackDice[i]); pixAttackDice[i] = XCreatePixmapFromBitmapData(hDisplay, hDiceWindow, (char *)pDice[i].pbBits, iWidth, iHeight, BlackPixel(hDisplay, 0), attackColor, COLOR_GetDepth()); } } iDefend = COLOR_QueryColor(iDefend); if (iDefend != defendColor) { defendColor = iDefend; /* Create the defend dice */ for (i=0; i!=6; i++) { if (eff) XFreePixmap (hDisplay, pixDefendDice[i]); pixDefendDice[i] = XCreatePixmapFromBitmapData(hDisplay, hDiceWindow, (char *)pDice[i].pbBits, iWidth, iHeight, BlackPixel(hDisplay, 0), defendColor, COLOR_GetDepth()); } } } /************************************************************************ * FUNCTION: DICE_Init * HISTORY: * 02.07.94 ESF Created. * 02.10.94 ESF Started work on coloring dice. * 03.03.94 ESF Changed to calculate offset numbers. * 03.05.94 ESF Changed to use varargs calls. * PURPOSE: * NOTES: ************************************************************************/ void DICE_Init(void) { DICE_Creat(FALSE, COLOR_DieToColor(0), COLOR_DieToColor(1)); } #endif /************************************************************************ * FUNCTION: DICE_Attack * HISTORY: * 02.07.94 ESF Created. * 03.03.94 ESF Changed to center the dice correctly. * 03.03.94 ESF Adding sorting of the dice and misc. checks. * 03.07.94 ESF Fixed iArmiesWon calculation. * 04.11.94 ESF Added refresh storage, factored out refresh code. * 10.30.94 ESF Added sending message to server, attacker/defender. * PURPOSE: * NOTES: ************************************************************************/ Int32 DICE_Attack(Int32 iAttack, Int32 iDefend, Int32 iAttacker, Int32 iDefender) { Int32 i, j, iTemp; Int32 iArmiesWon=0; MsgDiceRoll msgDiceRoll; UNUSED(iAttacker); if (iAttack>3 || iAttack<0 || iDefend>2 || iDefend<0) { /* (void)UTIL_PopupDialog("Fatal Error", "DICE: Attack has bogus params...\n", 1, "Ok", NULL, NULL); */ (void)RISK_SendMessage(CLNT_GetCommLinkOfClient(CLNT_GetThisClientID()), MSG_EXIT, NULL); UTIL_ExitProgram(-1); } /* Erase previous rolls */ DICE_Hide(); /* Init dice */ for (i=0; i!=3; i++) piAttackDice[i] = piDefendDice[i] = -1; /* Get the attack rolls (ranging 0..5 !!*/ for (i=0; i!=iAttack; i++) piAttackDice[i] = (int) (6.0 * (rand()/(RAND_MAX+1.0))); /* Get the defense rolls */ for (i=0; i!=iDefend; i++) piDefendDice[i] = (int) (6.0 * (rand()/(RAND_MAX+1.0))); /* Sort the dice rolls using bubble sort (at most needs two passes) */ for (i=0; i!=2; i++) for (j=0; j!=2-i; j++) { if (piAttackDice[j] < piAttackDice[j+1]) DICE_Swap(piAttackDice[j], piAttackDice[j+1], iTemp); if (piDefendDice[j] < piDefendDice[j+1]) DICE_Swap(piDefendDice[j], piDefendDice[j+1], iTemp); } /* Send a message to the server about the dice roll */ for (i=0; i!=3; i++) { msgDiceRoll.pAttackDice[i] = piAttackDice[i]; msgDiceRoll.pDefendDice[i] = piDefendDice[i]; } msgDiceRoll.iDefendingPlayer = iDefender; (void)RISK_SendMessage(CLNT_GetCommLinkOfClient(CLNT_GetThisClientID()), MSG_DICEROLL, &msgDiceRoll); /* Show the dice */ DICE_Refresh(); /* Find out the outcome of the battle */ for (i=0; i!=MIN(iDefend, iAttack); i++) if (piAttackDice[i] > piDefendDice[i]) iArmiesWon++; return iArmiesWon; /* For defender, iArmiesWon = iDefend-iArmiesWon */ } #ifndef DICE_AI /************************************************************************ * FUNCTION: DICE_Hide * HISTORY: * 02.07.94 ESF Stubbed. * 03.06.94 ESF Coded. * 04.11.94 ESF Added invalidation of the dice. * PURPOSE: * NOTES: ************************************************************************/ void DICE_Hide(void) { Int32 i; /* Delete the contents of the box */ XSetForeground(hDisplay, hGC, iBackgroundColor); XFillRectangle(hDisplay, hDiceWindow, hGC, 0, 0, iBoxWidth, iBoxHeight); /* Invalidate the saved dice */ for (i=0; i!=3; i++) piAttackDice[i] = piDefendDice[i] = -1; } /************************************************************************ * FUNCTION: DICE_Refresh * HISTORY: * 04.11.94 ESF Created. * PURPOSE: * NOTES: ************************************************************************/ void DICE_Refresh(void) { DICE_DrawDice(piAttackDice, piDefendDice); } /************************************************************************ * FUNCTION: * HISTORY: * 10.30.94 ESF Moved here and added parameter validation. * PURPOSE: * NOTES: ************************************************************************/ void DICE_DrawDice(Int32 *pAttackDice, Int32 *pDefendDice) { Int32 i; for (i=0; i!=3; i++) { /* Save these so that a refresh can see them */ piAttackDice[i] = pAttackDice[i]; piDefendDice[i] = pDefendDice[i]; /* Parameter validation */ D_Assert(pAttackDice[i]==-1 || (pAttackDice[i]>=0 && pAttackDice[i]<=5), "Dice number is out of range."); D_Assert(pDefendDice[i]==-1 || (pDefendDice[i]>=0 && pDefendDice[i]<=5), "Dice number is out of range."); } DICE_Creat(TRUE, COLOR_DieToColor(0), COLOR_DieToColor(1)); /* Show the dice */ for (i=0; i!=3; i++) { if (piAttackDice[i] != -1) XCopyArea(hDisplay, pixAttackDice[pAttackDice[i]], hDiceWindow, hGC, 0, 0, iWidth, iHeight, iHorizontalOffset + i*(iWidth+DICE_SPACING), iVerticalOffset); if (piDefendDice[i] != -1) XCopyArea(hDisplay, pixDefendDice[pDefendDice[i]], hDiceWindow, hGC, 0, 0, iWidth, iHeight, iHorizontalOffset + i*(iWidth+DICE_SPACING), iVerticalOffset + (iHeight+DICE_SPACING)); } } #endif xfrisk-1.2/doxygen.conf0100644000175000017500000000134707016076745014244 0ustar johnojohno# # Doxygen configuration file for XFrisk source documentation # # Usage: run 'doxygen doxygen.conf' in the XFrisk source directory # Output: HTML documentation in docs/html/ (start at index.html) # # See http://www.stack.nl/~dimitri/doxygen/ for more information # on the Doxygen tool # # $id$ # # Generic options PROJECT_NAME = XFrisk OUTPUT_DIRECTORY = docs WARNINGS = YES # Inclusion options EXTRACT_ALL = YES HIDE_UNDOC_MEMBERS = NO BRIEF_MEMBER_DESC = YES # Input options INPUT = . FILE_PATTERNS = *.h *.c RECURSIVE = NO # Output formats GENERATE_HTML = YES GENERATE_LATEX = NO # Preprocessing options ENABLE_PREPROCESSING = YES MACRO_EXPANSION = NO SEARCH_INCLUDES = YES INCLUDE_PATH = /usr/include /usr/X11R6/include xfrisk-1.2/english.res0100644000175000017500000005164107000075544014053 0ustar johnojohno"*font: fixed", "*borderColor: black", "*foreground: black", "*background: DeepSkyBlue3", "*defaultDistance: 1", "*Label.background: DeepSkyBlue4", "*Label.foreground: Yellow", "*Form.background: DeepSkyBlue3", "*Form.foreground: black", "*List*background: DeepSkyBlue3", "*List*foreground: black", "*Text*background: DeepSkyBlue3", "*Text*foreground: black", "*Viewport*background: DeepSkyBlue3", "*Viewport*foreground: black", "*Command.background: DeepSkyBlue2", "*Command.foreground: Black", "*Command.height: 22", "*wMap.width: 800", "*wMap.height: 404", "*wMap.translations: #override\\n\ Shift: mapShiftClick()\\n\ : mapClick()\\n\ : mapClick()\\n\ : mapClick()", "*wPlayField.width: 795", "*wPlayField.height: 70", "*wPlayField.fromVert: wMap", "*wPlayField.defaultDistance: 2", "*wControls.width: 795", "*wControls.height: 200", "*wControls.fromVert: wPlayField", "*wControls.background: DeepSkyBlue3", "*wAttackLabel.label: Attack", "*wAttackLabel.width: 50", "*wAttackList.defaultColumns: 1", "*wAttackList.fromVert: wAttackLabel", "*wAttackList.height: 64", "*wAttackList.width: 50", "*wActionLabel.label: Action", "*wActionLabel.fromHoriz: wAttackLabel", "*wActionLabel.width: 110", "*wActionList.defaultColumns: 1", "*wActionList.fromVert: wActionLabel", "*wActionList.fromHoriz: wAttackList", "*wMsgDestLabel.fromHoriz: wActionLabel", "*wMsgDestLabel.label: Msg. Dest.", "*wMsgDestLabel.width: 100", "*wMsgDestViewport.fromHoriz: wActionList", "*wMsgDestViewport.fromVert: wMsgDestLabel", "*wMsgDestViewport.width: 100", "*wMsgDestViewport.height: 64", "*wMsgDestViewport.forceBars: True", "*wMsgDestViewport.useRight: True", "*wMsgDestViewport.allowVert: True", "*wMsgDestList.defaultColumns: 1", "*wSendMsgText.fromHoriz: wMsgDestLabel", "*wSendMsgText*background: Skyblue", "*wSendMsgText*foreground: black", "*wSendMsgText.width: 527", "*wSendMsgText.translations: #override\\n\ Return: sendMessage()\\n\ CtrlM: no-op()\\n\ CtrlJ: no-op()\\n\ Linefeed: no-op()\\n\ Tab: no-op()", "*wMsgText.width: 527", "*wMsgText.height: 64", "*wMsgText.displayCaret: False", "*wMsgText.fromHoriz: wMsgDestViewport", "*wMsgText.fromVert: wSendMsgText", "*wCurrentPlayer.width: 25", "*wCurrentPlayer.height: 21", "*wCurrentPlayer.background: black", "*wCommentLabel.foreground: Black", "*wCommentLabel.justify: left", "*wCommentLabel.label: Welcome to Frisk!", "*wCommentLabel.font: *helvetica-m*-r-*12*", "*wCommentLabel.width: 498", "*wCommentLabel.height: 21", "*wCommentLabel.background: #aabbdd", "*wCommentLabel.fromHoriz: wCurrentPlayer", "*wAboutButton.fromVert: wCommentLabel", "*wAboutButton.label: About", "*wCancelAttackButton.fromVert: wCommentLabel", "*wCancelAttackButton.fromHoriz: wAboutButton", "*wCancelAttackButton.label: Cancel Action", "*wRepeatButton.fromVert: wCommentLabel", "*wRepeatButton.fromHoriz: wCancelAttackButton", "*wRepeatButton.label: Repeat Attack", "*wEndTurnButton.fromVert: wCommentLabel", "*wEndTurnButton.fromHoriz: wRepeatButton", "*wEndTurnButton.label: End Turn", "*wShowCardsButton.fromHoriz: wEndTurnButton", "*wShowCardsButton.fromVert: wCommentLabel", "*wShowCardsButton.label: Show Cards", "*wShowMissionButton.fromHoriz: wShowCardsButton", "*wShowMissionButton.fromVert: wCommentLabel", "*wShowMissionButton.label: Mission", "*wStatViewButton.fromHoriz: wShowMissionButton", "*wStatViewButton.fromVert: wCommentLabel", "*wStatViewButton.label: Stats View", "*wHelpButton.fromHoriz: wStatViewButton", "*wHelpButton.fromVert: wCommentLabel", "*wHelpButton.label: Help", "*wQuitButton.fromVert: wCommentLabel", "*wQuitButton.fromHoriz: wHelpButton", "*wQuitButton.label: Quit", "*wErrorLabel.foreground: Black", "*wErrorLabel.justify: left", "*wErrorLabel.label: ", "*wErrorLabel.font: *helvetica-m*-r-*12*", "*wErrorLabel.width: 527", "*wErrorLabel.height: 21", "*wErrorLabel.background: #aabbdd", "*wErrorLabel.fromVert: wQuitButton", "*wDiceBox.width: 263", "*wDiceBox.height: 72", "*wDiceBox.background: #00aa00", "*wDiceBox.fromHoriz: wCommentLabel", "*wCardViewport.width: 790", "*wCardViewport.height: 206", "*wCardViewport.forceBars: True", "*wCardViewport.useRight: True", "*wCardViewport.allowVert: True", "*wCardForm.width: 790", "*wCardForm.height: 206", "*wExchangeButton.fromVert: wCardViewport", "*wExchangeButton.label: Exchange Cards", "*wCancelCardsButton.fromVert: wCardViewport", "*wCancelCardsButton.fromHoriz: wExchangeButton", "*wCancelCardsButton.label: Cancel", "*wArmiesForm.defaultDistance: 8", "*wArmiesLabel.label: Number of Armies:", "*wArmiesLabel.width: 125", "*wArmiesText*background: Skyblue", "*wArmiesText.fromHoriz: wArmiesLabel", "*wArmiesText.width: 30", "*wArmiesText*translations: #override\ Return: popupArmies()\\n\ CtrlM: no-op()\\n\ CtrlJ: no-op()\\n\ Linefeed: no-op()\\n\ Tab: no-op()", "*wFinishArmiesButton.fromVert: wArmiesLabel", "*wFinishArmiesButton.label: Ok", "*wFinishArmiesButton.width: 80", "*wCancelArmiesButton.fromVert: wArmiesText", "*wCancelArmiesButton.fromHoriz: wFinishArmiesButton", "*wCancelArmiesButton.label: Cancel", "*wCancelArmiesButton.width: 80", "*Help.label: Frisk Help", "*wHelpForm.width: 600", "*wHelpForm.height: 400", "*wHelpTopicLabel.label: Help Topics", "*wHelpTopicLabel.width: 200", "*wHelpLabel.label: ", "*wHelpLabel.fromHoriz: wHelpTopicLabel", "*wHelpLabel.width: 500", "*wHelpTopicList.defaultColumns: 1", "*wHelpTopicList.forceColumns: True", "*wHelpTopicViewport.width: 200", "*wHelpTopicViewport.height: 380", "*wHelpTopicViewport.fromVert: wHelpTopicLabel", "*wHelpTopicViewport.forceBars: True", "*wHelpTopicViewport.useRight: True", "*wHelpTopicViewport.allowVert: True", "*wHelpTopicViewport*font: *helvetica-m*-r-*12*", "*wHelpText.width: 500", "*wHelpText.height: 380", "*wHelpText.fromVert: wHelpTopicLabel", "*wHelpText.fromHoriz: wHelpTopicViewport", "*wHelpText*font: *helvetica-m*-r-*12*", "*wHelpOkButton.fromVert: wHelpTopicViewport", "*wHelpOkButton.label: Close Help Window", "*wDialogLabel*font: *helvetica-b*-o-*14*", "*wDialogLabel.background: DeepSkyBlue3", "*wDialogLabel.borderColor: DeepSkyBlue3", "*wDialogLabel.borderWidth: 0", "*wDialogLabel.justify: Left", "*wDialogForm.defaultDistance: 8", "*wDialogButton1.fromVert: wDialogLabel", "*wDialogButton1.font: *helvetica-m*-r-*12*", "*wDialogButton2.fromVert: wDialogLabel", "*wDialogButton2.font: *helvetica-m*-r-*12*", "*wDialogButton3.fromVert: wDialogLabel", "*wDialogButton3.font: *helvetica-m*-r-*12*", "*wColorEditForm.width: 310", "*wColorEditForm.height: 400", "*wColorEditForm.defaultDistance: 5", "*wColorEditLabel.width: 221", "*wColorEditLabel.label: Select a color", "*wRedScrollbar.topShadowPixel: #ff0000", "*wRedScrollbar.bottomShadowPixel: #990000", "*wRedScrollbar.background: #dd0000", "*wRedScrollbar.width: 20", "*wRedScrollbar.height: 140", "*wRedScrollbar.foreground: Black", "*wRedScrollbar.fromVert: wColorEditLabel", "*wRedScrollbar.translations: #override\\n\ : StartScroll(Continuous) MoveThumb() NotifyThumb() \\n\ : MoveThumb() NotifyThumb() \\n\ : StartScroll(Continuous) MoveThumb() NotifyThumb() \\n\ : MoveThumb() NotifyThumb() \\n\ : StartScroll(Continuous) MoveThumb() NotifyThumb()\\n\ : MoveThumb() NotifyThumb()", "*wRedScrollbar.scrollVCursor: hand1", "*wRedScrollbar.scrollRCursor: hand1", "*wGreenScrollbar.topShadowPixel: #00ff00", "*wGreenScrollbar.bottomShadowPixel: #009900", "*wGreenScrollbar.background: #00dd00", "*wGreenScrollbar.width: 20", "*wGreenScrollbar.height: 140", "*wGreenScrollbar.foreground: Black", "*wGreenScrollbar.fromHoriz: wRedScrollbar", "*wGreenScrollbar.fromVert: wColorEditLabel", "*wGreenScrollbar.translations: #override\\n\ : StartScroll(Continuous) MoveThumb() NotifyThumb() \\n\ : MoveThumb() NotifyThumb() \\n\ : StartScroll(Continuous) MoveThumb() NotifyThumb() \\n\ : MoveThumb() NotifyThumb() \\n\ : StartScroll(Continuous) MoveThumb() NotifyThumb()\\n\ : MoveThumb() NotifyThumb()", "*wGreenScrollbar.scrollVCursor: hand1", "*wGreenScrollbar.scrollRCursor: hand1", "*wBlueScrollbar.topShadowPixel: #0000ff", "*wBlueScrollbar.bottomShadowPixel: #000099", "*wBlueScrollbar.background: #0000dd", "*wBlueScrollbar.width: 20", "*wBlueScrollbar.height: 140", "*wBlueScrollbar.foreground: Black", "*wBlueScrollbar.fromHoriz: wGreenScrollbar", "*wBlueScrollbar.fromVert: wColorEditLabel", "*wBlueScrollbar.translations: #override\\n\ : StartScroll(Continuous) MoveThumb() NotifyThumb() \\n\ : MoveThumb() NotifyThumb() \\n\ : StartScroll(Continuous) MoveThumb() NotifyThumb() \\n\ : MoveThumb() NotifyThumb() \\n\ : StartScroll(Continuous) MoveThumb() NotifyThumb()\\n\ : MoveThumb() NotifyThumb()", "*wBlueScrollbar.scrollVCursor: hand1", "*wBlueScrollbar.scrollRCursor: hand1", "*wSampleCountryForm.label: ", "*wSampleCountryForm.width: 140", "*wSampleCountryForm.height: 140", "*wSampleCountryForm.fromVert: wColorEditLabel", "*wSampleCountryForm.fromHoriz: wBlueScrollbar", "*wSampleCountryForm.borderColor:black", "*wSampleCountryForm.internalHeight:0", "*wSampleCountryForm.internalWidth:0", "*wColorInputLabel.label: Color Name", "*wColorInputLabel.width: 107", "*wColorInputLabel.fromVert: wRedScrollbar", "*wColorInputText.width: 107", "*wColorInputText.fromHoriz: wColorInputLabel", "*wColorInputText.fromVert: wSampleCountryForm", "*wColorInputText*background: LightSkyBlue1", "*wColorInputText*borderColor: Black", "*wColorInputText*translations: #override\ Return: updateColor()\\n\ Escape: colorEditCancel()\\n\ CtrlM: no-op()\\n\ CtrlJ: no-op()\\n\ Linefeed: no-op()\\n\ Tab: no-op()", "*wColorDummy.width: 33", "*wColorDummy.borderColor: DeepSkyBlue3", "*wColorDummy.height: 22", "*wColorDummy.fromVert: wColorInputLabel", "*wColorDummy.shadowWidth: 0", "*wColorOK.fromVert: wColorInputLabel", "*wColorOK.fromHoriz: wColorDummy", "*wColorOK.width: 70", "*wColorOK.label: Ok", "*wColorCancel.fromVert: wColorInputLabel", "*wColorCancel.fromHoriz: wColorOK", "*wColorCancel.width: 70", "*wColorCancel.label: Cancel", "*wRegisterForm.width: 300", "*wRegisterForm.height: 350", "*wRegisterForm*font: fixed", "*wRegisterForm.defaultDistance: 4", "*wPlayerViewport.width: 300", "*wPlayerViewport.height: 260", "*wPlayerViewport.forceBars: True", "*wPlayerViewport.useRight: True", "*wPlayerViewport.allowVert: True", "*wPlayerViewport*background: DeepSkyBlue2", "*wPlayerForm.translations: #override\\n\ Shift: regMouseShiftClick()\\n\ : regMouseClick()", "*wPlayerForm*wShowPlayerForm.width: 280", "*wPlayerForm*wShowPlayerForm.height: 20", "*wPlayerForm*wShowPlayerForm.borderColor: DeepSkyBlue2", "*wPlayerForm*wShowPlayerForm.translations: #override\\n\ Shift: regMouseShiftClick()\\n\ : regMouseClick()", "*wShowPlayerForm*wShowPlayerColor.borderColor: DeepSkyBlue2", "*wShowPlayerForm*wShowPlayerColor.borderWidth: 1", "*wShowPlayerForm*wShowPlayerColor.internalHeight: 0", "*wShowPlayerForm*wShowPlayerColor.internalWidth: 0", "*wShowPlayerForm*wShowPlayerColor.label: ", "*wShowPlayerForm*wShowPlayerColor.width: 18", "*wShowPlayerForm*wShowPlayerColor.height: 18", "*wShowPlayerForm*wShowPlayerColor.shadowWidth: 0", "*wShowPlayerForm*wShowPlayerColor.translations: #override\\n\ : regEditColor()", "*wShowPlayerForm*wShowPlayerName.borderColor: DeepSkyBlue2", "*wShowPlayerForm*wShowPlayerName.label: ", "*wShowPlayerForm*wShowPlayerName.width: 150", "*wShowPlayerForm*wShowPlayerName.height: 18", "*wShowPlayerForm*wShowPlayerName.resize: False", "*wShowPlayerForm*wShowPlayerName.justify: left", "*wShowPlayerForm*wShowPlayerName.shadowWidth: 0", "*wShowPlayerForm*wShowPlayerSpecies.borderColor: DeepSkyBlue2", "*wShowPlayerForm*wShowPlayerSpecies.label: ", "*wShowPlayerForm*wShowPlayerSpecies.width: 95", "*wShowPlayerForm*wShowPlayerSpecies.resize: False", "*wShowPlayerForm*wShowPlayerSpecies.height: 18", "*wShowPlayerForm*wShowPlayerSpecies.justify: left", "*wShowPlayerForm*wShowPlayerSpecies.shadowWidth: 0", "*wAddPlayerButton.width: 147", "*wAddPlayerButton.label: Add Player", "*wAddPlayerButton.fromVert: wPlayerViewport", "*wDeletePlayerButton.width: 147", "*wDeletePlayerButton.label: Delete Player", "*wDeletePlayerButton.fromHoriz: wAddPlayerButton", "*wDeletePlayerButton.fromVert: wPlayerViewport", "*wRegisterOKButton.width: 147", "*wRegisterOKButton.label: Start Game", "*wRegisterOKButton.fromVert: wAddPlayerButton", "*wRegisterNOButton.width: 147", "*wRegisterNOButton.label: Quit Game", "*wRegisterNOButton.fromVert: wAddPlayerButton", "*wRegisterNOButton.fromHoriz: wRegisterOKButton", "*wAddPlayerForm.width: 600", "*wAddPlayerForm.height: 300", "*wAddPlayerForm.defaultDistance: 5", "*wPlayerNameLabel.label: Name", "*wPlayerNameLabel.width: 100", "*wPlayerNameLabel.justify: left", "*wPlayerNameText.width: 200", "*wPlayerNameText.fromHoriz: wPlayerNameLabel", "*wPlayerNameText*background: LightSkyBlue1", "*wPlayerNameText.borderColor: Black", "*wPlayerNameText.translations: #override\\n\ Escape: playerCancel()\\n\ Return: playerOk()\\n\ CtrlM: no-op()\\n\ CtrlJ: no-op()\\n\ Linefeed: no-op()\\n\ Tab: no-op()", "*wPlayerSpeciesLabel.label: Species", "*wPlayerSpeciesLabel.width: 100", "*wPlayerSpeciesLabel.fromVert: wPlayerNameLabel", "*wPlayerSpeciesLabel.justify: left", "*wPlayerSpeciesViewport.width: 200", "*wPlayerSpeciesViewport.height: 100", "*wPlayerSpeciesViewport.fromHoriz: wPlayerSpeciesLabel", "*wPlayerSpeciesViewport.fromVert: wPlayerNameText", "*wPlayerSpeciesViewport.forceBars: True", "*wPlayerSpeciesViewport.useRight: True", "*wPlayerSpeciesViewport.allowVert: True", "*wPlayerSpeciesViewport*background: DeepSkyBlue2", "*wPlayerSpeciesListBox.width: 200", "*wPlayerSpeciesListBox*background: DeepSkyBlue2", "*wPlayerDummy1.fromVert: wPlayerSpeciesLabel", "*wPlayerDummy1.width: 100", "*wPlayerDummy1.height: 76", "*wPlayerDummy1.label: ", "*wPlayerDummy1.background: DeepSkyBlue3", "*wPlayerDummy1.borderColor: DeepSkyBlue3", "*wPlayerDummy1.shadowWidth: 0", "*wPlayerDescLabel.label: Description", "*wPlayerDescLabel.justify: left", "*wPlayerDescLabel.width: 100", "*wPlayerDescLabel.fromVert: wPlayerDummy1", "*wPlayerDescText.width: 200", "*wPlayerDescText.height: 30", "*wPlayerDescText.fromVert: wPlayerSpeciesViewport", "*wPlayerDescText.fromHoriz: wPlayerDescLabel", "*wPlayerDescText.displayCaret: False", "*wPlayerDescText*background: DeepSkyBlue2", "*wPlayerDescText.cursor: top_left_arrow", "*wPlayerDummy2.fromVert: wPlayerDescLabel", "*wPlayerDummy2.width: 100", "*wPlayerDummy2.height: 6", "*wPlayerDummy2.label: ", "*wPlayerDummy2.background: DeepSkyBlue3", "*wPlayerDummy2.borderColor: DeepSkyBlue3", "*wPlayerDummy2.shadowWidth: 0", "*wPlayerVersionLabel.label: Version", "*wPlayerVersionLabel.justify: left", "*wPlayerVersionLabel.width: 100", "*wPlayerVersionLabel.fromVert: wPlayerDummy2", "*wPlayerVersionText.width: 200", "*wPlayerVersionText.fromVert: wPlayerDescText", "*wPlayerVersionText.fromHoriz: wPlayerVersionLabel", "*wPlayerVersionText.displayCaret: False", "*wPlayerVersionText*background: DeepSkyBlue2", "*wPlayerVersionText.cursor: top_left_arrow", "*wPlayerAuthorLabel.label: Author", "*wPlayerAuthorLabel.justify: left", "*wPlayerAuthorLabel.width: 100", "*wPlayerAuthorLabel.fromVert: wPlayerVersionLabel", "*wPlayerAuthorText.width: 200", "*wPlayerAuthorText.fromHoriz: wPlayerAuthorLabel", "*wPlayerAuthorText.fromVert: wPlayerVersionText", "*wPlayerAuthorText.displayCaret: False", "*wPlayerAuthorText*background: DeepSkyBlue2", "*wPlayerAuthorText.cursor: top_left_arrow", "*wPlayerColorLabel.label: Color", "*wPlayerColorLabel.width: 100", "*wPlayerColorLabel.justify: left", "*wPlayerColorLabel.fromVert: wPlayerAuthorLabel", "*wPlayerColorDisplay.fromVert: wPlayerAuthorText", "*wPlayerColorDisplay.fromHoriz: wPlayerColorLabel", "*wPlayerColorDisplay.width: 18", "*wPlayerColorDisplay.height: 18", "*wPlayerColorDisplay.shadowWidth: 0", "*wPlayerColorDisplay.label:", "*wPlayerColorDisplay.background: Black", "*wPlayerColorDisplay.cursor: hand1", "*wPlayerColorDisplay*translations: #override \ : playerEditColor()\\n\ : playerEditColor()\\n\ : playerEditColor()", "*wPlayerDummy3.fromVert: wPlayerColorLabel", "*wPlayerDummy3.width: 300", "*wPlayerDummy3.height: 12", "*wPlayerDummy3.label: ", "*wPlayerDummy3.background: DeepSkyBlue3", "*wPlayerDummy3.borderColor: DeepSkyBlue3", "*wPlayerDummy3.shadowWidth: 0", "*wPlayerDummy4.fromVert: wPlayerDummy3", "*wPlayerDummy4.width: 50", "*wPlayerDummy4.height: 20", "*wPlayerDummy4.label: ", "*wPlayerDummy4.background: DeepSkyBlue3", "*wPlayerDummy4.borderColor: DeepSkyBlue3", "*wPlayerDummy4.shadowWidth: 0", "*wPlayerOk.label: Ok", "*wPlayerOk.width: 100", "*wPlayerOk.fromHoriz: wPlayerDummy4", "*wPlayerOk.fromVert: wPlayerDummy3", "*wPlayerCancel.label: Cancel", "*wPlayerCancel.width: 100", "*wPlayerCancel.fromHoriz: wPlayerOk", "*wPlayerCancel.fromVert: wPlayerDummy3", "*wStatForm.width: 300", "*wStatForm.height: 400", "*wStatNumberForm.width: 300", "*wStatNumberForm.height: 250", "*wStatNumberForm.defaultDistance: 2", "*wStatGraphForm.fromVert: wStatNumberForm", "*wStatGraphForm.defaultDistance: 2", "*wStatGraphForm.resizable: False", "*wStatGraph.width: 300", "*wStatGraph.height: 150", "*wStatCloseButton.fromVert: wStatGraphForm", "*wStatCloseButton.width: 475", "*wStatCloseButton.label: Close", "*wStatCloseButton.justify: center", "*wStatColorLabel.label: ", "*wStatColorLabel.background: DeepSkyBlue3", "*wStatColorLabel.borderColor: DeepSkyBlue3", "*wStatColorLabel.width: 22", "*wStatColorLabel.justify: center", "*wStatNameLabel.label: Name", "*wStatNameLabel.width: 80", "*wStatNameLabel.justify: center", "*wStatNameLabel.fromHoriz: wStatColorLabel", "*wStatArmiesLabel.label: Armies", "*wStatArmiesLabel.width: 80", "*wStatArmiesLabel.justify: center", "*wStatArmiesLabel.fromHoriz: wStatNameLabel", "*wStatCountriesLabel.label: Territories", "*wStatCountriesLabel.width: 80", "*wStatCountriesLabel.justify: center", "*wStatCountriesLabel.fromHoriz: wStatArmiesLabel", "*wStatCardsLabel.label: Cards", "*wStatCardsLabel.width: 80", "*wStatCardsLabel.justify: center", "*wStatCardsLabel.fromHoriz: wStatCountriesLabel", "*wStatWLDLabel.label: Win/Lose/Draw", "*wStatWLDLabel.width: 90", "*wStatWLDLabel.justify: center", "*wStatWLDLabel.fromHoriz: wStatCardsLabel", "*wStatViewport.fromVert: wStatGraphLabel", "*wStatViewport.forceBars: True", "*wStatViewport.useRight: True", "*wStatViewport.allowVert: True", "*wStatViewport*background: DeepSkyBlue2", "*wStatViewport.width: 471", "*wStatViewport.height: 208", "*wStatViewport.fromVert: wStatNameLabel", "*wStatPlayerForm*borderColor: DeepSkyBlue2", "*wShowPlayerForm*defaultDistance: 2", "*wStatNumberForm*wStatPlayerColor.borderColor: DeepSkyBlue2", "*wStatNumberForm*wStatPlayerColor.width: 18", "*wStatNumberForm*wStatPlayerColor.height: 18", "*wStatNumberForm*wStatPlayerColor.label: ", "*wStatNumberForm*wStatPlayerName.borderColor: DeepSkyBlue2", "*wStatNumberForm*wStatPlayerName.height: 18", "*wStatNumberForm*wStatPlayerName.width: 80", "*wStatNumberForm*wStatPlayerName.label: ", "*wStatNumberForm*wStatPlayerArmies.borderColor: DeepSkyBlue2", "*wStatNumberForm*wStatPlayerArmies.height: 18", "*wStatNumberForm*wStatPlayerArmies.width: 80", "*wStatNumberForm*wStatPlayerArmies.label: ", "*wStatNumberForm*wStatPlayerCountries.borderColor: DeepSkyBlue2", "*wStatNumberForm*wStatPlayerCountries.height: 18", "*wStatNumberForm*wStatPlayerCountries.width: 80", "*wStatNumberForm*wStatPlayerCountries.label: ", "*wStatNumberForm*wStatPlayerCards.borderColor: DeepSkyBlue2", "*wStatNumberForm*wStatPlayerCards.height: 18", "*wStatNumberForm*wStatPlayerCards.width: 80", "*wStatNumberForm*wStatPlayerCards.label: ", "*wStatNumberForm*wStatPlayerWLD.borderColor: DeepSkyBlue2", "*wStatNumberForm*wStatPlayerWLD.height: 18", "*wStatNumberForm*wStatPlayerWLD.width: 90", "*wStatNumberForm*wStatPlayerWLD.label: ", "*wStatGraphLabel.label: Territories vs. Time", "*wStatGraphLabel.width: 471", "*wStatGraph.width: 471", "*wStatGraph.height: 110", "*wStatGraph.internalWidth: 0", "*wStatGraph.internalHeight: 0", "*wStatGraph.background: black", "*wStatGraph.fromVert: wStatGraphLabel", xfrisk-1.2/findtypes.c0100644000175000017500000000777007013357407014071 0ustar johnojohno/* * XFrisk - The classic board game for X * Copyright (C) 1993-1999 Elan Feingold (elan@aetherworks.com) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * $Id: findtypes.c,v 1.4 1999/11/13 21:58:31 morphy Exp $ */ #include #include int main(void) { FILE *file = fopen("types.h", "w"); char *intType; char *byteType; char *shortType; char *pointerType; if (!file) { printf("Could not open types.h for writing...\n"); exit(-1); } printf("Analyzing architecture, to determine types..."); /* Find the types we need, which are: * * 32 bit [signed|unsigned] integer -- [U]Int32 * A type the size of a pointer -- Pointer * 8 bit type [signed|unsigned] -- [Char|Byte] * 16 bit integer [[signed|unsigned] -- [U]Short * * In addition, derive some utility types: * * Pointer to a char (NULL terminated) -- CString * Boolean value, how about a byte -- Bool */ fprintf(file, "#ifndef _TYPES\n"); fprintf(file, "#define _TYPES\n\n"); /*************************************/ fprintf(file, "/* 32 bit integer */\n"); /* Find the types */ if (sizeof(int) == 4) intType = "int"; else if (sizeof(long int) == 4) intType = "long int"; else if (sizeof(short int) == 4) intType = "short int"; else { printf("Cannot find a 32 bit integer type on this machine.\n"); exit(-1); } fprintf(file, "typedef %s Int32;\n", intType); fprintf(file, "typedef unsigned %s UInt32;\n\n", intType); /*************************************/ fprintf(file, "/* Pointer type */\n"); /* Find the types */ if (sizeof(void *) == sizeof (int)) pointerType = "int"; else if (sizeof(void *) == sizeof(long int)) pointerType = "long int"; else if (sizeof(void *) == sizeof(short int)) pointerType = "short int"; else { printf("Cannot find integer the size of a pointer on this machine.\n"); exit(-1); } fprintf(file, "typedef %s Pointer;\n\n", pointerType); /*************************************/ fprintf(file, "/* 16 bit integer */\n"); /* Find the types */ if (sizeof(int) == 2) shortType = "int"; else if (sizeof(long int) == 2) shortType = "long int"; else if (sizeof(short int) == 2) shortType = "short int"; else { printf("Cannot find a 16 bit integer type on this machine.\n"); exit(-1); } fprintf(file, "typedef %s Int16;\n", shortType); fprintf(file, "typedef unsigned %s UInt16;\n\n", shortType); /*************************************/ fprintf(file, "/* 8 bit integer */\n"); /* Find the types */ if (sizeof(int) == 1) byteType = "int"; else if (sizeof(long int) == 1) byteType = "long int"; else if (sizeof(short int) == 1) byteType = "short int"; else if (sizeof(char) == 1) byteType = "char"; else { printf("Cannot find an 8 bit integer type on this machine.\n"); exit(-1); } fprintf(file, "typedef %s Char;\n", byteType); fprintf(file, "typedef unsigned %s Byte;\n\n", byteType); /*******************************************/ fprintf(file, "/* Supplimentary types */\n"); fprintf(file, "typedef %s *CString;\n", byteType); fprintf(file, "typedef unsigned %s Flag;\n\n", byteType); fprintf(file, "#endif\n"); fclose(file); printf("done.\n"); exit(0); } xfrisk-1.2/french.res0100644000175000017500000005241707000075544013671 0ustar johnojohno"*font: fixed", "*borderColor: black", "*foreground: black", "*background: DeepSkyBlue3", "*defaultDistance: 1", "*Label.background: DeepSkyBlue4", "*Label.foreground: Yellow", "*Form.background: DeepSkyBlue3", "*Form.foreground: black", "*List*background: DeepSkyBlue3", "*List*foreground: black", "*Text*background: DeepSkyBlue3", "*Text*foreground: black", "*Viewport*background: DeepSkyBlue3", "*Viewport*foreground: black", "*Command.background: DeepSkyBlue2", "*Command.foreground: Black", "*Command.height: 22", "*wMap.width: 797", "*wMap.height: 404", "*wMap.translations: #override\\n\ Shift: mapShiftClick()\\n\ : mapClick()\\n\ : mapClick()\\n\ : mapClick()", "*wPlayField.width: 795", "*wPlayField.height: 70", "*wPlayField.fromVert: wMap", "*wPlayField.defaultDistance: 2", "*wControls.width: 795", "*wControls.height: 200", "*wControls.fromVert: wPlayField", "*wControls.background: DeepSkyBlue3", "*wAttackLabel.label: Attaquer", "*wAttackLabel.width: 50", "*wAttackList.defaultColumns: 1", "*wAttackList.fromVert: wAttackLabel", "*wAttackList.height: 64", "*wAttackList.width: 50", "*wActionLabel.label: Action", "*wActionLabel.fromHoriz: wAttackLabel", "*wActionLabel.width: 92", "*wActionList.defaultColumns: 1", "*wActionList.fromVert: wActionLabel", "*wActionList.fromHoriz: wAttackList", "*wMsgDestLabel.fromHoriz: wActionLabel", "*wMsgDestLabel.label: Msg. Dest.", "*wMsgDestLabel.width: 93", "*wMsgDestViewport.fromHoriz: wActionList", "*wMsgDestViewport.fromVert: wMsgDestLabel", "*wMsgDestViewport.width: 123", "*wMsgDestViewport.height: 64", "*wMsgDestViewport.forceBars: True", "*wMsgDestViewport.useRight: True", "*wMsgDestViewport.allowVert: True", "*wMsgDestList.defaultColumns: 1", "*wSendMsgText.fromHoriz: wMsgDestLabel", "*wSendMsgText*background: Skyblue", "*wSendMsgText*foreground: black", "*wSendMsgText.width: 549", "*wSendMsgText.translations: #override\\n\ Return: sendMessage()\\n\ CtrlM: no-op()\\n\ CtrlJ: no-op()\\n\ Linefeed: no-op()\\n\ Tab: no-op()", "*wMsgText.width: 549", "*wMsgText.height: 64", "*wMsgText.displayCaret: False", "*wMsgText.fromHoriz: wMsgDestViewport", "*wMsgText.fromVert: wSendMsgText", "*wCurrentPlayer.width: 25", "*wCurrentPlayer.height: 21", "*wCurrentPlayer.background: black", "*wCommentLabel.foreground: Black", "*wCommentLabel.justify: left", "*wCommentLabel.label: Bienvenu à Frisk!", "*wCommentLabel.font: *helvetica-m*-r-*12*", "*wCommentLabel.width: 555", "*wCommentLabel.height: 21", "*wCommentLabel.background: #aabbdd", "*wCommentLabel.fromHoriz: wCurrentPlayer", "*wAboutButton.fromVert: wCommentLabel", "*wAboutButton.label: À propos de", "*wCancelAttackButton.fromVert: wCommentLabel", "*wCancelAttackButton.fromHoriz:wAboutButton", "*wCancelAttackButton.label: Annuler Action", "*wRepeatButton.fromVert: wCommentLabel", "*wRepeatButton.fromHoriz: wCancelAttackButton", "*wRepeatButton.label: Répéter attaque", "*wEndTurnButton.fromVert: wCommentLabel", "*wEndTurnButton.fromHoriz: wRepeatButton", "*wEndTurnButton.label: Fin du tour", "*wShowCardsButton.fromHoriz: wEndTurnButton", "*wShowCardsButton.fromVert: wCommentLabel", "*wShowCardsButton.label: Cartes", "*wShowMissionButton.fromHoriz: wShowCardsButton", "*wShowMissionButton.fromVert: wCommentLabel", "*wShowMissionButton.label: Mission", "*wStatViewButton.fromHoriz: wShowMissionButton", "*wStatViewButton.fromVert: wCommentLabel", "*wStatViewButton.label: Stats", "*wHelpButton.fromHoriz: wStatViewButton", "*wHelpButton.fromVert: wCommentLabel", "*wHelpButton.label: Aide", "*wQuitButton.fromVert: wCommentLabel", "*wQuitButton.fromHoriz: wHelpButton", "*wQuitButton.label: Quitter", "*wErrorLabel.foreground: Black", "*wErrorLabel.justify: left", "*wErrorLabel.label: ", "*wErrorLabel.font: *helvetica-m*-r-*12*", "*wErrorLabel.width: 584", "*wErrorLabel.height: 21", "*wErrorLabel.background: #aabbdd", "*wErrorLabel.fromVert: wQuitButton", "*wDiceBox.width: 203", "*wDiceBox.height: 72", "*wDiceBox.background: #00aa00", "*wDiceBox.fromHoriz: wCommentLabel", "*wCardViewport.width: 790", "*wCardViewport.height: 206", "*wCardViewport.forceBars: True", "*wCardViewport.useRight: True", "*wCardViewport.allowVert: True", "*wCardForm.width: 790", "*wCardForm.height: 206", "*wExchangeButton.fromVert: wCardViewport", "*wExchangeButton.label: Exchange Cards", "*wCancelCardsButton.fromVert: wCardViewport", "*wCancelCardsButton.fromHoriz: wExchangeButton", "*wCancelCardsButton.label: Annuler", "*wArmiesForm.defaultDistance: 8", "*wArmiesLabel.label: Nombre d'armées:", "*wArmiesLabel.width: 125", "*wArmiesText*background: Skyblue", "*wArmiesText.fromHoriz: wArmiesLabel", "*wArmiesText.width: 30", "*wArmiesText*translations: #override\ Return: popupArmies()\\n\ CtrlM: no-op()\\n\ CtrlJ: no-op()\\n\ Linefeed: no-op()\\n\ Tab: no-op()", "*wFinishArmiesButton.fromVert: wArmiesLabel", "*wFinishArmiesButton.label: Ok", "*wFinishArmiesButton.width: 80", "*wCancelArmiesButton.fromVert: wArmiesText", "*wCancelArmiesButton.fromHoriz:wFinishArmiesButton", "*wCancelArmiesButton.label: Cancel", "*wCancelArmiesButton.width: 80", "*Help.label: Frisk Help", "*wHelpForm.width: 600", "*wHelpForm.height: 400", "*wHelpTopicLabel.label: Thème de l'aide", "*wHelpTopicLabel.width: 200", "*wHelpLabel.label: ", "*wHelpLabel.fromHoriz: wHelpTopicLabel", "*wHelpLabel.width: 500", "*wHelpTopicList.defaultColumns: 1", "*wHelpTopicList.forceColumns: True", "*wHelpTopicViewport.width: 200", "*wHelpTopicViewport.height: 380", "*wHelpTopicViewport.fromVert: wHelpTopicLabel", "*wHelpTopicViewport.forceBars: True", "*wHelpTopicViewport.useRight: True", "*wHelpTopicViewport.allowVert: True", "*wHelpTopicViewport*font: *helvetica-m*-r-*12*", "*wHelpText.width: 500", "*wHelpText.height: 380", "*wHelpText.fromVert: wHelpTopicLabel", "*wHelpText.fromHoriz: wHelpTopicViewport", "*wHelpText*font: *helvetica-m*-r-*12*", "*wHelpOkButton.fromVert: wHelpTopicViewport", "*wHelpOkButton.label: Fermer aide", "*wDialogLabel*font: *helvetica-b*-o-*14*", "*wDialogLabel.background: DeepSkyBlue3", "*wDialogLabel.borderColor: DeepSkyBlue3", "*wDialogLabel.borderWidth: 0", "*wDialogLabel.justify: Left", "*wDialogForm.defaultDistance: 8", "*wDialogButton1.fromVert: wDialogLabel", "*wDialogButton1.font: *helvetica-m*-r-*12*", "*wDialogButton2.fromVert: wDialogLabel", "*wDialogButton2.font: *helvetica-m*-r-*12*", "*wDialogButton3.fromVert: wDialogLabel", "*wDialogButton3.font: *helvetica-m*-r-*12*", "*wColorEditForm.width: 310", "*wColorEditForm.height: 400", "*wColorEditForm.defaultDistance: 5", "*wColorEditLabel.width: 221", "*wColorEditLabel.label: Selectionner une couleur", "*wRedScrollbar.topShadowPixel: #ff0000", "*wRedScrollbar.bottomShadowPixel: #990000", "*wRedScrollbar.background: #dd0000", "*wRedScrollbar.width: 20", "*wRedScrollbar.height: 140", "*wRedScrollbar.foreground: Black", "*wRedScrollbar.fromVert: wColorEditLabel", "*wRedScrollbar.translations: #override\\n\ : StartScroll(Continuous) MoveThumb() NotifyThumb() \\n\ : MoveThumb() NotifyThumb() \\n\ : StartScroll(Continuous) MoveThumb() NotifyThumb() \\n\ : MoveThumb() NotifyThumb() \\n\ : StartScroll(Continuous) MoveThumb() NotifyThumb()\\n\ : MoveThumb() NotifyThumb()", "*wRedScrollbar.scrollVCursor: hand1", "*wRedScrollbar.scrollRCursor: hand1", "*wGreenScrollbar.topShadowPixel: #00ff00", "*wGreenScrollbar.bottomShadowPixel: #009900", "*wGreenScrollbar.background: #00dd00", "*wGreenScrollbar.width: 20", "*wGreenScrollbar.height: 140", "*wGreenScrollbar.foreground: Black", "*wGreenScrollbar.fromHoriz: wRedScrollbar", "*wGreenScrollbar.fromVert: wColorEditLabel", "*wGreenScrollbar.translations: #override\\n\ : StartScroll(Continuous) MoveThumb() NotifyThumb() \\n\ : MoveThumb() NotifyThumb() \\n\ : StartScroll(Continuous) MoveThumb() NotifyThumb() \\n\ : MoveThumb() NotifyThumb() \\n\ : StartScroll(Continuous) MoveThumb() NotifyThumb()\\n\ : MoveThumb() NotifyThumb()", "*wGreenScrollbar.scrollVCursor: hand1", "*wGreenScrollbar.scrollRCursor: hand1", "*wBlueScrollbar.topShadowPixel: #0000ff", "*wBlueScrollbar.bottomShadowPixel: #000099", "*wBlueScrollbar.background: #0000dd", "*wBlueScrollbar.width: 20", "*wBlueScrollbar.height: 140", "*wBlueScrollbar.foreground: Black", "*wBlueScrollbar.fromHoriz: wGreenScrollbar", "*wBlueScrollbar.fromVert: wColorEditLabel", "*wBlueScrollbar.translations: #override\\n\ : StartScroll(Continuous) MoveThumb() NotifyThumb() \\n\ : MoveThumb() NotifyThumb() \\n\ : StartScroll(Continuous) MoveThumb() NotifyThumb() \\n\ : MoveThumb() NotifyThumb() \\n\ : StartScroll(Continuous) MoveThumb() NotifyThumb()\\n\ : MoveThumb() NotifyThumb()", "*wBlueScrollbar.scrollVCursor: hand1", "*wBlueScrollbar.scrollRCursor: hand1", "*wSampleCountryForm.label: ", "*wSampleCountryForm.width: 140", "*wSampleCountryForm.height: 140", "*wSampleCountryForm.fromVert: wColorEditLabel", "*wSampleCountryForm.fromHoriz: wBlueScrollbar", "*wSampleCountryForm.borderColor: black", "*wSampleCountryForm.internalHeight: 0", "*wSampleCountryForm.internalWidth: 0", "*wColorInputLabel.label: Nom couleur", "*wColorInputLabel.width: 107", "*wColorInputLabel.fromVert: wRedScrollbar", "*wColorInputText.width: 107", "*wColorInputText.fromHoriz: wColorInputLabel", "*wColorInputText.fromVert: wSampleCountryForm", "*wColorInputText*background: LightSkyBlue1", "*wColorInputText*borderColor: Black", "*wColorInputText*translations: #override\ Return: updateColor()\\n\ Escape: colorEditCancel()\\n\ CtrlM: no-op()\\n\ CtrlJ: no-op()\\n\ Linefeed: no-op()\\n\ Tab: no-op()", "*wColorDummy.width: 33", "*wColorDummy.borderColor: DeepSkyBlue3", "*wColorDummy.height: 22", "*wColorDummy.fromVert: wColorInputLabel", "*wColorDummy.shadowWidth: 0", "*wColorOK.fromVert: wColorInputLabel", "*wColorOK.fromHoriz: wColorDummy", "*wColorOK.width: 70", "*wColorOK.label: Confirmer", "*wColorCancel.fromVert: wColorInputLabel", "*wColorCancel.fromHoriz: wColorOK", "*wColorCancel.width: 70", "*wColorCancel.label: Annuler", "*wRegisterForm.width: 300", "*wRegisterForm.height: 350", "*wRegisterForm*font: fixed", "*wRegisterForm.defaultDistance: 4", "*wPlayerViewport.width: 300", "*wPlayerViewport.height: 260", "*wPlayerViewport.forceBars: True", "*wPlayerViewport.useRight: True", "*wPlayerViewport.allowVert: True", "*wPlayerViewport*background: DeepSkyBlue2", "*wPlayerForm.translations: #override\\n\ Shift: regMouseShiftClick()\\n\ : regMouseClick()", "*wPlayerForm*wShowPlayerForm.width: 280", "*wPlayerForm*wShowPlayerForm.height: 20", "*wPlayerForm*wShowPlayerForm.borderColor: DeepSkyBlue2", "*wPlayerForm*wShowPlayerForm.translations: #override\\n\ Shift: regMouseShiftClick()\\n\ : regMouseClick()", "*wShowPlayerForm*wShowPlayerColor.borderColor: DeepSkyBlue2", "*wShowPlayerForm*wShowPlayerColor.borderWidth: 1", "*wShowPlayerForm*wShowPlayerColor.internalHeight: 0", "*wShowPlayerForm*wShowPlayerColor.internalWidth: 0", "*wShowPlayerForm*wShowPlayerColor.label: ", "*wShowPlayerForm*wShowPlayerColor.width: 18", "*wShowPlayerForm*wShowPlayerColor.height: 18", "*wShowPlayerForm*wShowPlayerColor.shadowWidth: 0", "*wShowPlayerForm*wShowPlayerColor.translations: #override\\n\ : regEditColor()", "*wShowPlayerForm*wShowPlayerName.borderColor: DeepSkyBlue2", "*wShowPlayerForm*wShowPlayerName.label: ", "*wShowPlayerForm*wShowPlayerName.width: 150", "*wShowPlayerForm*wShowPlayerName.height: 18", "*wShowPlayerForm*wShowPlayerName.resize: False", "*wShowPlayerForm*wShowPlayerName.justify: left", "*wShowPlayerForm*wShowPlayerName.shadowWidth: 0", "*wShowPlayerForm*wShowPlayerSpecies.borderColor: DeepSkyBlue2", "*wShowPlayerForm*wShowPlayerSpecies.label: ", "*wShowPlayerForm*wShowPlayerSpecies.width: 95", "*wShowPlayerForm*wShowPlayerSpecies.resize: False", "*wShowPlayerForm*wShowPlayerSpecies.height: 18", "*wShowPlayerForm*wShowPlayerSpecies.justify: left", "*wShowPlayerForm*wShowPlayerSpecies.shadowWidth: 0", "*wAddPlayerButton.width: 147", "*wAddPlayerButton.label: Ajouter un joueur", "*wAddPlayerButton.fromVert: wPlayerViewport", "*wDeletePlayerButton.width: 147", "*wDeletePlayerButton.label: Détruire un joueur", "*wDeletePlayerButton.fromHoriz: wAddPlayerButton", "*wDeletePlayerButton.fromVert: wPlayerViewport", "*wRegisterOKButton.width: 147", "*wRegisterOKButton.label: Commencer jeu", "*wRegisterOKButton.fromVert: wAddPlayerButton", "*wRegisterNOButton.width: 147", "*wRegisterNOButton.label: Quitter frisk", "*wRegisterNOButton.fromVert: wAddPlayerButton", "*wRegisterNOButton.fromHoriz: wRegisterOKButton", "*wAddPlayerForm.width: 600", "*wAddPlayerForm.height: 300", "*wAddPlayerForm.defaultDistance: 5", "*wPlayerNameLabel.label: Nom", "*wPlayerNameLabel.width: 100", "*wPlayerNameLabel.justify: left", "*wPlayerNameText.width: 200", "*wPlayerNameText.fromHoriz: wPlayerNameLabel", "*wPlayerNameText*background: LightSkyBlue1", "*wPlayerNameText.borderColor: Black", "*wPlayerNameText.translations: #override\\n\ Escape: playerCancel()\\n\ Return: playerOk()\\n\ CtrlM: no-op()\\n\ CtrlJ: no-op()\\n\ Linefeed: no-op()\\n\ Tab: no-op()", "*wPlayerSpeciesLabel.label: Espèce", "*wPlayerSpeciesLabel.width: 100", "*wPlayerSpeciesLabel.fromVert: wPlayerNameLabel", "*wPlayerSpeciesLabel.justify: left", "*wPlayerSpeciesViewport.width: 200", "*wPlayerSpeciesViewport.height: 100", "*wPlayerSpeciesViewport.fromHoriz: wPlayerSpeciesLabel", "*wPlayerSpeciesViewport.fromVert: wPlayerNameText", "*wPlayerSpeciesViewport.forceBars: True", "*wPlayerSpeciesViewport.useRight: True", "*wPlayerSpeciesViewport.allowVert: True", "*wPlayerSpeciesViewport*background: DeepSkyBlue2", "*wPlayerSpeciesListBox.width: 200", "*wPlayerSpeciesListBox*background: DeepSkyBlue2", "*wPlayerDummy1.fromVert: wPlayerSpeciesLabel", "*wPlayerDummy1.width: 100", "*wPlayerDummy1.height: 76", "*wPlayerDummy1.label: ", "*wPlayerDummy1.background: DeepSkyBlue3", "*wPlayerDummy1.borderColor: DeepSkyBlue3", "*wPlayerDummy1.shadowWidth: 0", "*wPlayerDescLabel.label: Description", "*wPlayerDescLabel.justify: left", "*wPlayerDescLabel.width: 100", "*wPlayerDescLabel.fromVert: wPlayerDummy1", "*wPlayerDescText.width: 200", "*wPlayerDescText.height: 30", "*wPlayerDescText.fromVert: wPlayerSpeciesViewport", "*wPlayerDescText.fromHoriz: wPlayerDescLabel", "*wPlayerDescText.displayCaret: False", "*wPlayerDescText*background: DeepSkyBlue2", "*wPlayerDescText.cursor: top_left_arrow", "*wPlayerDummy2.fromVert: wPlayerDescLabel", "*wPlayerDummy2.width: 100", "*wPlayerDummy2.height: 6", "*wPlayerDummy2.label: ", "*wPlayerDummy2.background: DeepSkyBlue3", "*wPlayerDummy2.borderColor: DeepSkyBlue3", "*wPlayerDummy2.shadowWidth: 0", "*wPlayerVersionLabel.label: Version", "*wPlayerVersionLabel.justify: left", "*wPlayerVersionLabel.width: 100", "*wPlayerVersionLabel.fromVert: wPlayerDummy2", "*wPlayerVersionText.width: 200", "*wPlayerVersionText.fromVert: wPlayerDescText", "*wPlayerVersionText.fromHoriz: wPlayerVersionLabel", "*wPlayerVersionText.displayCaret: False", "*wPlayerVersionText*background: DeepSkyBlue2", "*wPlayerVersionText.cursor: top_left_arrow", "*wPlayerAuthorLabel.label: Auteur", "*wPlayerAuthorLabel.justify: left", "*wPlayerAuthorLabel.width: 100", "*wPlayerAuthorLabel.fromVert: wPlayerVersionLabel", "*wPlayerAuthorText.width: 200", "*wPlayerAuthorText.fromHoriz: wPlayerAuthorLabel", "*wPlayerAuthorText.fromVert: wPlayerVersionText", "*wPlayerAuthorText.displayCaret: False", "*wPlayerAuthorText*background: DeepSkyBlue2", "*wPlayerAuthorText.cursor: top_left_arrow", "*wPlayerColorLabel.label: Couleur", "*wPlayerColorLabel.width: 100", "*wPlayerColorLabel.justify: left", "*wPlayerColorLabel.fromVert: wPlayerAuthorLabel", "*wPlayerColorDisplay.fromVert: wPlayerAuthorText", "*wPlayerColorDisplay.fromHoriz: wPlayerColorLabel", "*wPlayerColorDisplay.width: 18", "*wPlayerColorDisplay.height: 18", "*wPlayerColorDisplay.shadowWidth: 0", "*wPlayerColorDisplay.label: ", "*wPlayerColorDisplay.background: Black", "*wPlayerColorDisplay.cursor: hand1", "*wPlayerColorDisplay*translations: #override \ : playerEditColor()\\n\ : playerEditColor()\\n\ : playerEditColor()", "*wPlayerDummy3.fromVert: wPlayerColorLabel", "*wPlayerDummy3.width: 300", "*wPlayerDummy3.height: 12", "*wPlayerDummy3.label: ", "*wPlayerDummy3.background: DeepSkyBlue3", "*wPlayerDummy3.borderColor: DeepSkyBlue3", "*wPlayerDummy3.shadowWidth: 0", "*wPlayerDummy4.fromVert: wPlayerDummy3", "*wPlayerDummy4.width: 50", "*wPlayerDummy4.height: 20", "*wPlayerDummy4.label: ", "*wPlayerDummy4.background: DeepSkyBlue3", "*wPlayerDummy4.borderColor: DeepSkyBlue3", "*wPlayerDummy4.shadowWidth: 0", "*wPlayerOk.label: Confirme", "*wPlayerOk.width: 100", "*wPlayerOk.fromHoriz: wPlayerDummy4", "*wPlayerOk.fromVert: wPlayerDummy3", "*wPlayerCancel.label: Annuler", "*wPlayerCancel.width: 100", "*wPlayerCancel.fromHoriz: wPlayerOk", "*wPlayerCancel.fromVert: wPlayerDummy3", "*wStatForm.width: 300", "*wStatForm.height: 400", "*wStatNumberForm.width: 300", "*wStatNumberForm.height: 250", "*wStatNumberForm.defaultDistance: 2", "*wStatGraphForm.fromVert: wStatNumberForm", "*wStatGraphForm.defaultDistance: 2", "*wStatGraphForm.resizable: False", "*wStatGraph.width: 300", "*wStatGraph.height: 150", "*wStatCloseButton.fromVert: wStatGraphForm", "*wStatCloseButton.width: 475", "*wStatCloseButton.label: Fermer", "*wStatCloseButton.justify: center", "*wStatColorLabel.label: ", "*wStatColorLabel.background: DeepSkyBlue3", "*wStatColorLabel.borderColor: DeepSkyBlue3", "*wStatColorLabel.width: 22", "*wStatColorLabel.justify: center", "*wStatNameLabel.label: Nom", "*wStatNameLabel.width: 80", "*wStatNameLabel.justify: center", "*wStatNameLabel.fromHoriz: wStatColorLabel", "*wStatArmiesLabel.label: Armées", "*wStatArmiesLabel.width: 80", "*wStatArmiesLabel.justify: center", "*wStatArmiesLabel.fromHoriz: wStatNameLabel", "*wStatCountriesLabel.label: Territoires", "*wStatCountriesLabel.width: 80", "*wStatCountriesLabel.justify: center", "*wStatCountriesLabel.fromHoriz: wStatArmiesLabel", "*wStatCardsLabel.label: Cartes", "*wStatCardsLabel.width: 80", "*wStatCardsLabel.justify: center", "*wStatCardsLabel.fromHoriz: wStatCountriesLabel", "*wStatWLDLabel.label: Vict/Pert/Nb", "*wStatWLDLabel.width: 90", "*wStatWLDLabel.justify: center", "*wStatWLDLabel.fromHoriz: wStatCardsLabel", "*wStatViewport.fromVert: wStatGraphLabel", "*wStatViewport.forceBars: True", "*wStatViewport.useRight: True", "*wStatViewport.allowVert: True", "*wStatViewport*background: DeepSkyBlue2", "*wStatViewport.width: 471", "*wStatViewport.height: 208", "*wStatViewport.fromVert: wStatNameLabel", "*wStatPlayerForm*borderColor: DeepSkyBlue2", "*wShowPlayerForm*defaultDistance: 2", "*wStatNumberForm*wStatPlayerColor.borderColor: DeepSkyBlue2", "*wStatNumberForm*wStatPlayerColor.width: 18", "*wStatNumberForm*wStatPlayerColor.height: 18", "*wStatNumberForm*wStatPlayerColor.label: ", "*wStatNumberForm*wStatPlayerName.borderColor: DeepSkyBlue2", "*wStatNumberForm*wStatPlayerName.height: 18", "*wStatNumberForm*wStatPlayerName.width: 80", "*wStatNumberForm*wStatPlayerName.label: ", "*wStatNumberForm*wStatPlayerArmies.borderColor: DeepSkyBlue2", "*wStatNumberForm*wStatPlayerArmies.height: 18", "*wStatNumberForm*wStatPlayerArmies.width: 80", "*wStatNumberForm*wStatPlayerArmies.label: ", "*wStatNumberForm*wStatPlayerCountries.borderColor: DeepSkyBlue2", "*wStatNumberForm*wStatPlayerCountries.height: 18", "*wStatNumberForm*wStatPlayerCountries.width: 80", "*wStatNumberForm*wStatPlayerCountries.label: ", "*wStatNumberForm*wStatPlayerCards.borderColor: DeepSkyBlue2", "*wStatNumberForm*wStatPlayerCards.height: 18", "*wStatNumberForm*wStatPlayerCards.width: 80", "*wStatNumberForm*wStatPlayerCards.label: ", "*wStatNumberForm*wStatPlayerWLD.borderColor: DeepSkyBlue2", "*wStatNumberForm*wStatPlayerWLD.height: 18", "*wStatNumberForm*wStatPlayerWLD.width: 90", "*wStatNumberForm*wStatPlayerWLD.label: ", "*wStatGraphLabel.label: Évolution des territoires", "*wStatGraphLabel.width: 471", "*wStatGraph.width: 471", "*wStatGraph.height: 110", "*wStatGraph.internalWidth: 0", "*wStatGraph.internalHeight: 0", "*wStatGraph.background: black", "*wStatGraph.fromVert: wStatGraphLabel", xfrisk-1.2/game.c0100644000175000017500000014350207041143776012772 0ustar johnojohno/* * XFrisk - The classic board game for X * Copyright (C) 1993-1999 Elan Feingold (elan@aetherworks.com) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * $Id: game.c,v 1.13 2000/01/18 20:07:26 morphy Exp $ * * $Log: game.c,v $ * Revision 1.13 2000/01/18 20:07:26 morphy * Made middle button (drop all armies) obey DROP_ARMIES limitation * * Revision 1.12 2000/01/18 19:56:43 morphy * Prevention of dropping all armies works now * * Revision 1.11 2000/01/18 09:25:47 tony * oops, little braino in "dropping armies" code * * Revision 1.10 2000/01/17 21:09:03 tony * small fix on dropping armies during fortification, optional number * */ #include #include #include #include "registerPlayers.h" #include "callbacks.h" #include "utils.h" #include "dice.h" #include "game.h" #include "debug.h" #include "riskgame.h" #include "types.h" #include "colormap.h" #include "client.h" /* Globals */ static MsgNetMessage mess; static Int32 iAttackDst=-1; static Int32 iMoveDst=-1; /*iAttackSrc is used by callbacks.c */ static Int32 iAttackSrc=-1; Int32 iLastAttackSrc=-1, iLastAttackDst=-1; Int32 iMoveSrc=-1; Flag fGetsCard=FALSE; Flag fCanExchange=TRUE; /* max number of armies to allow when not using DROP_ALL */ #define DROP_ARMIES 3 /************************************************************************ * FUNCTION: GAME_AttackFrom * HISTORY: 291099 Tdh * PURPOSE: Return value of iAttackSrc * NOTES: to make iAttackSrc private to game.c */ Int32 GAME_AttackFrom() { return iAttackSrc; } /************************************************************************ * FUNCTION: GAME_SetAttackSrc * HISTORY: 291099 Tdh * PURPOSE: Set value of iAttackSrc * NOTES: to make iAttackSrc private to game.c */ void GAME_SetAttackSrc(Int32 src) { iAttackSrc = src; } /************************************************************************ * FUNCTION: GAME_CanAttack * HISTORY: * 03.04.94 ESF Created. * PURPOSE: Check if this attack is possible * NOTES: ************************************************************************/ Flag GAME_CanAttack(Int32 AttackSrc, Int32 iAttackDst) { Int32 i; for (i=0; i!=6 && RISK_GetAdjCountryOfCountry(AttackSrc, i)!=-1; i++) if (RISK_GetAdjCountryOfCountry(AttackSrc, i) == iAttackDst) return TRUE; return FALSE; } /************************************************************************ * FUNCTION: GAME_SetTurnArmiesOfPlayer * HISTORY: * 04.23.95 ESF Created. * PURPOSE: * NOTES: ************************************************************************/ void GAME_SetTurnArmiesOfPlayer(Int32 iCurrentPlayer) { Int32 iNumArmies=0; /* Add the continent bonus */ iNumArmies += GAME_GetContinentBonus(iCurrentPlayer); /* Add the standard "at-least-three-and-at-most-one-per-three-countries" */ iNumArmies += MAX(RISK_GetNumCountriesOfPlayer(iCurrentPlayer)/3, 3); RISK_SetNumArmiesOfPlayer(iCurrentPlayer, iNumArmies); } /************************************************************************ * FUNCTION: GAME_MoveArmies * HISTORY: * 03.04.94 ESF Created. * 03.18.94 ESF Added server update. * 05.19.94 ESF Added verbose message across network. * PURPOSE: * NOTES: ************************************************************************/ void GAME_MoveArmies(Int32 iSrcCountry, Int32 iDstCountry, Int32 iNumArmies) { MsgMoveNotify msgMoveNotify; char buf[256]; /* Notify the server */ msgMoveNotify.iSrcCountry = iSrcCountry; msgMoveNotify.iDstCountry = iDstCountry; (void)RISK_SendMessage(CLNT_GetCommLinkOfClient(CLNT_GetThisClientID()), MSG_MOVENOTIFY, &msgMoveNotify); /* send a verbose message */ #ifdef ENGLISH snprintf(buf, sizeof(buf), "%s moved %d armies from %s to %s", #endif #ifdef FRENCH snprintf(buf, sizeof(buf), "%s déplace %d armée(s) de %s à %s", #endif RISK_GetNameOfPlayer(iCurrentPlayer), iNumArmies, RISK_GetNameOfCountry(iSrcCountry), RISK_GetNameOfCountry(iDstCountry)); mess.strMessage = buf; (void)RISK_SendMessage(CLNT_GetCommLinkOfClient(CLNT_GetThisClientID()), MSG_NETMESSAGE, &mess); /* Update date structures */ RISK_SetNumArmiesOfCountry(iDstCountry, RISK_GetNumArmiesOfCountry(iDstCountry) + iNumArmies); RISK_SetNumArmiesOfCountry(iSrcCountry, RISK_GetNumArmiesOfCountry(iSrcCountry) - iNumArmies); } /************************************************************************ * FUNCTION: GAME_PlaceArmies * HISTORY: * 03.04.94 ESF Stubbed. * 05.19.94 ESF Coded and added verbose message across network. * 10.02.94 ESF Added support for PLACE_ALL. * 04.30.95 ESF Moved the dialog code from to PlaceClick. * PURPOSE: * NOTES: ************************************************************************/ void GAME_PlaceArmies(Int32 iCountry, Int32 iArmies) { MsgPlaceNotify msgPlaceNotify; char buf[256]; /* Send a message to the server about this */ msgPlaceNotify.iCountry = iCountry; (void)RISK_SendMessage(CLNT_GetCommLinkOfClient(CLNT_GetThisClientID()), MSG_PLACENOTIFY, &msgPlaceNotify); /* Send a verbose message */ #ifdef ENGLISH snprintf(buf, sizeof(buf), "%s placing %d %s on %s", #endif #ifdef FRENCH snprintf(buf, sizeof(buf), "%s place %d %s en %s", #endif RISK_GetNameOfPlayer(iCurrentPlayer), iArmies, iArmies == 1 ? "army" : "armies", RISK_GetNameOfCountry(iCountry)); mess.strMessage = buf; (void)RISK_SendMessage(CLNT_GetCommLinkOfClient(CLNT_GetThisClientID()), MSG_NETMESSAGE, &mess); /* Once we've placed, can't exchange cards anymore */ fCanExchange = FALSE; /* Update the data structures */ RISK_SetNumArmiesOfPlayer(iCurrentPlayer, RISK_GetNumArmiesOfPlayer(iCurrentPlayer) - iArmies); RISK_SetNumArmiesOfCountry(iCountry, RISK_GetNumArmiesOfCountry(iCountry)+iArmies); /* If we're out of armies, jump into attack mode */ if (!RISK_GetNumArmiesOfPlayer(iCurrentPlayer) && iState == STATE_PLACE) { iState = STATE_ATTACK; UTIL_ServerEnterState(iState); UTIL_DisplayActionCString(iState, iCurrentPlayer); } UTIL_DisplayActionCString(iState, iCurrentPlayer); } /************************************************************************ * FUNCTION: GAME_Attack * HISTORY: * 04.23.95 ESF Created. * PURPOSE: * NOTES: ************************************************************************/ void GAME_Attack(Int32 iSrcCountry, Int32 iDstCountry) { Int32 iActionState = RISK_GetAttackModeOfPlayer(iCurrentPlayer); Int32 iDice = RISK_GetDiceModeOfPlayer(iCurrentPlayer); /* Keep these so as to be able to repeat attack */ iLastAttackSrc = iSrcCountry; iLastAttackDst = iDstCountry; if (iActionState == ACTION_ATTACK) { if (GAME_ValidAttackSrc(iSrcCountry, TRUE) && GAME_ValidAttackDst(iSrcCountry, iDstCountry, TRUE) && GAME_ValidAttackDice(iDice, iSrcCountry)) { GAME_DoAttack(iSrcCountry, iDstCountry, TRUE); UTIL_DisplayActionCString(iState, iCurrentPlayer); } } else if (iActionState == ACTION_DOORDIE) { Flag fNotify = TRUE; while (GAME_ValidAttackSrc(iSrcCountry, FALSE) && GAME_ValidAttackDst(iSrcCountry, iDstCountry, FALSE) && GAME_ValidAttackDice(iDice, iSrcCountry)) { GAME_DoAttack(iSrcCountry, iDstCountry, fNotify); /* Only True the first time around */ fNotify = FALSE; } } } /************************************************************************ * FUNCTION: GAME_DoAttack * HISTORY: * 03.04.94 ESF Created. * 03.06.94 ESF Added missing pieces. * 03.07.94 ESF Fixed owner update bug & army subtraction bug. * 03.18.94 ESF Added server notification. * 03.28.94 ESF Added message when country is taken. * 03.29.94 ESF Added more informative moving message. * 04.02.94 ESF Fixed bug, darken country if wrong number of die. * 04.02.94 ESF Only notify server if fCacheNotify == FALSE. * 05.04.94 ESF Fixed bug, changed location of call to GAME_PlayerDied(). * 05.04.94 ESF Fixed bug, when end of game occurs. * 05.19.94 ESF Added verbose notification when player takes country. * 05.19.94 ESF Moved calculation of dice correctness to ValidDice. * 11.06.94 ESF Cached results, so that Do-or-die runs quicker. * 11.06.94 ESF Added attack notification. * 01.17.95 ESF Changed fCacheNotify to fNotify. * 07.09.95 JC Fixed a bug with ENDOFMISSION and FORCEEXCHANGECARDS. * PURPOSE: * NOTES: ************************************************************************/ void GAME_DoAttack(Int32 iSrcCountry, Int32 iDstCountry, Flag fNotify) { MsgAttackNotify msgAttackNotify; Int32 iAttackDie, iDefendDie, iArmiesWon, iArmiesMove; Int32 iSrc, iDst, iPlayerAttackDie; char buf[256]; /* Cached values */ static Int32 iCachedSrcCountry=-1; static Int32 iCachedDstCountry=-1; iPlayerAttackDie = RISK_GetDiceModeOfPlayer(iCurrentPlayer); /* If the dice have been selected automatically, calculate them */ if (iPlayerAttackDie != ATTACK_AUTO) iAttackDie = iPlayerAttackDie+1; else iAttackDie = MIN(RISK_GetNumArmiesOfCountry(iSrcCountry)-1, 3); iDefendDie = MIN(RISK_GetNumArmiesOfCountry(iDstCountry), 2); /* Set the color of the dice if the attack has changed */ if (iCachedSrcCountry != iSrcCountry) COLOR_CopyColor(COLOR_PlayerToColor(RISK_GetOwnerOfCountry(iSrcCountry)), COLOR_DieToColor(0)); if (iCachedDstCountry != iDstCountry) COLOR_CopyColor(COLOR_PlayerToColor(RISK_GetOwnerOfCountry(iDstCountry)), COLOR_DieToColor(1)); /* Get the number of armies that the attacker won */ iArmiesWon = DICE_Attack(iAttackDie, iDefendDie, RISK_GetOwnerOfCountry(iSrcCountry), RISK_GetOwnerOfCountry(iDstCountry)); RISK_SetNumArmiesOfCountry(iDstCountry, RISK_GetNumArmiesOfCountry(iDstCountry) - iArmiesWon); RISK_SetNumArmiesOfCountry(iSrcCountry, RISK_GetNumArmiesOfCountry(iSrcCountry) - (MIN(iDefendDie, iAttackDie) - iArmiesWon)); /* Country was taken */ if (!RISK_GetNumArmiesOfCountry(iDstCountry)) { /* The attacking player gets a card */ fGetsCard = TRUE; /* Send a verbose message */ #ifdef ENGLISH snprintf(buf, sizeof(buf), "%s captured %s from %s", #endif #ifdef FRENCH snprintf(buf, sizeof(buf), "%s capture %s à partir de %s", #endif RISK_GetNameOfPlayer(iCurrentPlayer), RISK_GetNameOfCountry(iDstCountry), RISK_GetNameOfCountry(iSrcCountry)); mess.strMessage = buf; (void)RISK_SendMessage(CLNT_GetCommLinkOfClient(CLNT_GetThisClientID()), MSG_NETMESSAGE, &mess); /* Display informative message telling of victory */ #ifdef ENGLISH snprintf(buf, sizeof(buf), "%s moving armies from %s to %s.", RISK_GetNameOfPlayer(iCurrentPlayer), RISK_GetNameOfCountry(iSrcCountry), RISK_GetNameOfCountry(iDstCountry)); #endif #ifdef FRENCH snprintf(buf, sizeof(buf), "%s conquière %s à partir de %s.", RISK_GetNameOfPlayer(iCurrentPlayer), RISK_GetNameOfCountry(iDstCountry), RISK_GetNameOfCountry(iSrcCountry)); #endif UTIL_DisplayComment(buf); /* Update data structures */ iSrc = RISK_GetOwnerOfCountry(iSrcCountry); RISK_SetNumCountriesOfPlayer(iSrc, RISK_GetNumCountriesOfPlayer(iSrc)+1); iDst = RISK_GetOwnerOfCountry(iDstCountry); RISK_SetNumCountriesOfPlayer(iDst, RISK_GetNumCountriesOfPlayer(iDst)-1); /* New owner */ RISK_SetOwnerOfCountry(iDstCountry, RISK_GetOwnerOfCountry(iSrcCountry)); /* See if this victory signalled a _MSG_ENDOFMISSION condition */ if (GAME_IsMissionAccomplied(iCurrentPlayer, iDst)) { MsgEndOfMission msg; msg.iWinner = iCurrentPlayer; msg.iTyp = RISK_GetMissionTypeOfPlayer(iCurrentPlayer); msg.iNum1 = RISK_GetMissionContinent1OfPlayer(iCurrentPlayer); msg.iNum2 = RISK_GetMissionContinent2OfPlayer(iCurrentPlayer); RISK_SetMissionTypeOfPlayer(iCurrentPlayer, NO_MISSION); (void)RISK_SendSyncMessage(CLNT_GetCommLinkOfClient(CLNT_GetThisClientID()), MSG_ENDOFMISSION, &msg, MSG_ENDOFMISSION, CBK_IncomingMessage); /* If the winner stop the game ... */ if (iState == STATE_REGISTER) return; } /* Move the desired number of armies if it isn't end of game */ if (RISK_GetNumCountriesOfPlayer(iDst) != 0 || RISK_GetNumLivePlayers() != 2) { iArmiesMove = UTIL_GetArmyNumber(iAttackDie, RISK_GetNumArmiesOfCountry(iSrcCountry)-1, FALSE); RISK_SetNumArmiesOfCountry(iSrcCountry, RISK_GetNumArmiesOfCountry(iSrcCountry) - iArmiesMove); RISK_SetNumArmiesOfCountry(iDstCountry, RISK_GetNumArmiesOfCountry(iDstCountry) + iArmiesMove); } /* See if this victory signalled a _DEADPLAYER or _ENDOFGAME condition */ if (RISK_GetNumCountriesOfPlayer(iDst) == 0) GAME_PlayerDied(iDst); } else { /* If a new attack and not do-or-die, notify the server */ if (!(iCachedSrcCountry == iSrcCountry && iCachedDstCountry == iDstCountry)) { /* Send a verbose message */ #ifdef ENGLISH snprintf(buf, sizeof(buf), "%s is attacking from %s to %s", RISK_GetNameOfPlayer(iCurrentPlayer), RISK_GetNameOfCountry(iSrcCountry), RISK_GetNameOfCountry(iDstCountry)); #endif #ifdef FRENCH snprintf(buf, sizeof(buf), "%s attaque %s à partir de %s", RISK_GetNameOfPlayer(iCurrentPlayer), RISK_GetNameOfCountry(iDstCountry), RISK_GetNameOfCountry(iSrcCountry)); #endif mess.strMessage = buf; (void)RISK_SendMessage(CLNT_GetCommLinkOfClient(CLNT_GetThisClientID()), MSG_NETMESSAGE, &mess); UTIL_DisplayComment(buf); } } /* If we are told to notify, then notify */ if (fNotify == TRUE) { msgAttackNotify.iSrcCountry = iSrcCountry; msgAttackNotify.iDstCountry = iDstCountry; (void)RISK_SendMessage(CLNT_GetCommLinkOfClient(CLNT_GetThisClientID()), MSG_ATTACKNOTIFY, &msgAttackNotify); } /* Update cached values */ iCachedSrcCountry = iSrcCountry; iCachedDstCountry = iDstCountry; } /************************************************************************ * FUNCTION: GAME_IsEnemyAdjacent * HISTORY: * 03.05.94 ESF Created. * PURPOSE: * NOTES: ************************************************************************/ Flag GAME_IsEnemyAdjacent(Int32 iCountry) { Int32 i, iPlayer; iPlayer = RISK_GetOwnerOfCountry(iCountry); for (i=0; i!=6 && RISK_GetAdjCountryOfCountry(iCountry, i)!=-1; i++) if (RISK_GetOwnerOfCountry(RISK_GetAdjCountryOfCountry(iCountry, i)) != iPlayer) return TRUE; return FALSE; } /************************************************************************ * FUNCTION: GAME_IsFrontierAdjacent * HISTORY: * 03.08.95 JC Created. * PURPOSE: * NOTES: ************************************************************************/ Flag GAME_IsFrontierAdjacent(Int32 srcCountry, Int32 destCountry) { Int32 iPlayer, iContinent, iCountry, i; iPlayer = RISK_GetOwnerOfCountry(srcCountry); iContinent = RISK_GetContinentOfCountry(srcCountry); if (RISK_GetContinentOfCountry(destCountry) != iContinent) return GAME_IsEnemyAdjacent(destCountry); for (i=0; i!=6 && RISK_GetAdjCountryOfCountry(destCountry, i)!=-1; i++) { iCountry = RISK_GetAdjCountryOfCountry(destCountry, i); if (RISK_GetContinentOfCountry(iCountry) != iContinent) return TRUE; } return FALSE; } /************************************************************************ * FUNCTION: FindEnemyAdjacent * HISTORY: * 11.08.95 JC Created. * PURPOSE: * NOTES: ************************************************************************/ Int32 FindEnemyAdjacent(Int32 iCountry, Int32 distance) { Int32 i, min, res, iPlayer, dest; iPlayer = RISK_GetOwnerOfCountry(iCountry); min = 100000; for (i=0; i!=6 && RISK_GetAdjCountryOfCountry(iCountry, i)!=-1; i++) { dest = RISK_GetAdjCountryOfCountry(iCountry, i); if (RISK_GetOwnerOfCountry(dest) == iPlayer) { if (distance <= 3) { res = FindEnemyAdjacent(dest, distance + 1); if (res < min) min = res; } } else min = 0; } return (min + 1); } /************************************************************************ * FUNCTION: GAME_FindEnemyAdjacent * HISTORY: * 11.08.95 JC Created. * PURPOSE: * NOTES: ************************************************************************/ Int32 GAME_FindEnemyAdjacent(Int32 iCountry) { Int32 i, min, res, iPlayer, dest, destCountry; iPlayer = RISK_GetOwnerOfCountry(iCountry); destCountry = -1; min = 100000; for (i=0; i!=6 && RISK_GetAdjCountryOfCountry(iCountry, i)!=-1; i++) { dest = RISK_GetAdjCountryOfCountry(iCountry, i); if (RISK_GetOwnerOfCountry(dest) == iPlayer) { res = FindEnemyAdjacent(dest, 0); if (res < min) { min = res; destCountry = dest; } } else min = 0; } return (destCountry); } /************************************************************************ * FUNCTION: GAME_AttackClick * HISTORY: * 03.06.94 ESF Created. * 04.02.94 ESF Added notification of server after Do-or-Die. * 05.19.94 ESF Added verbose message across network. * 05.19.94 ESF Fixed for fixed attack dice do-or-die. * 07.14.94 ESF Fixed bug, bot checking attack dice on dest country. * 10.15.94 ESF Added printing of "Attacking from foo to bar" locally. * PURPOSE: * NOTES: ************************************************************************/ void GAME_AttackClick(Int32 iCountry) { char buf[256]; if (iAttackSrc < 0) { if (GAME_ValidAttackSrc(iCountry, TRUE) && GAME_ValidAttackDice(RISK_GetDiceModeOfPlayer(iCurrentPlayer), iCountry)) { iAttackSrc = iCountry; #ifdef ENGLISH snprintf(buf, sizeof(buf), "%s is attacking from %s to" " ", #endif #ifdef FRENCH snprintf(buf, sizeof(buf), "%s attaque à partir de %s ", #endif RISK_GetNameOfPlayer(iCurrentPlayer), RISK_GetNameOfCountry(iAttackSrc)); UTIL_DisplayComment(buf); UTIL_LightCountry(iAttackSrc); } } else if (GAME_ValidAttackDst(iAttackSrc, iCountry, TRUE) && GAME_ValidAttackDice(RISK_GetDiceModeOfPlayer(iCurrentPlayer), iAttackSrc)) { iAttackDst = iCountry; GAME_Attack(iAttackSrc, iAttackDst); iAttackSrc = iAttackDst = -1; UTIL_DisplayActionCString(iState, iCurrentPlayer); } } /************************************************************************ * FUNCTION: GAME_ValidAttackDice * HISTORY: * 05.19.94 ESF Created. * PURPOSE: * NOTES: ************************************************************************/ Flag GAME_ValidAttackDice(Int32 iAttackDice, Int32 iCountry) { char buf[256]; /* If the dice have been selected manually, check them */ if (iAttackDice != ATTACK_AUTO) { if (RISK_GetNumArmiesOfCountry(iCountry) <= iAttackDice+1) { #ifdef ENGLISH snprintf(buf, sizeof(buf), "You can't attack with %d dice, dummy.", #endif #ifdef FRENCH snprintf(buf, sizeof(buf), "Attaque impossible avec %d dé(s).", #endif iAttackDice+1); UTIL_DarkenCountry(iCountry); UTIL_DisplayError(buf); return FALSE; } } return TRUE; } /************************************************************************ * FUNCTION: GAME_ValidAttackSrc * HISTORY: * 03.06.94 ESF Created. * 03.07.94 ESF Added verbose option * PURPOSE: * NOTES: ************************************************************************/ Flag GAME_ValidAttackSrc(Int32 iAttackSrc, Flag fVerbose) { char buf[256]; if (iAttackSrc < 0) { if (fVerbose) #ifdef ENGLISH UTIL_DisplayError("Where the hell are you trying to attack from?"); #endif #ifdef FRENCH UTIL_DisplayError("D'où voulez-vous attaquer?"); #endif } else if (iAttackSrc >= NUM_COUNTRIES) { if (fVerbose) #ifdef ENGLISH UTIL_DisplayError("You can't attack from the ocean!"); #endif #ifdef FRENCH UTIL_DisplayError("Attaque impossible à partir de l'océan!"); #endif } else if (RISK_GetOwnerOfCountry(iAttackSrc) != iCurrentPlayer) { if (fVerbose) { #ifdef ENGLISH snprintf(buf, sizeof(buf), "You can't attack from %s -- you don't own it.", #endif #ifdef FRENCH snprintf(buf, sizeof(buf), "Attaque impossible à partir de %s.", #endif RISK_GetNameOfCountry(iAttackSrc)); UTIL_DisplayError(buf); } } else if (!GAME_IsEnemyAdjacent(iAttackSrc)) { if (fVerbose) { #ifdef ENGLISH snprintf(buf, sizeof(buf), "There are no enemy territories you can attack from %s.", #endif #ifdef FRENCH snprintf(buf, sizeof(buf), "Pas de territoire à attaquer à partir de %s.", #endif RISK_GetNameOfCountry(iAttackSrc)); UTIL_DisplayError(buf); } } else if (RISK_GetNumArmiesOfCountry(iAttackSrc) == 1) { if (fVerbose) #ifdef ENGLISH UTIL_DisplayError("You can't attack with 1 army."); #endif #ifdef FRENCH UTIL_DisplayError("Attaque impossible avec une seule armée."); #endif } else return TRUE; return FALSE; } /************************************************************************ * FUNCTION: GAME_ValidAttackDst * HISTORY: * 03.06.94 ESF Created. * 03.07.94 ESF Added verbose option * PURPOSE: * NOTES: ************************************************************************/ Flag GAME_ValidAttackDst(Int32 iAttackSrc, Int32 iAttackDst, Flag fVerbose) { char buf[256]; if (iAttackDst < 0) { if (fVerbose) #ifdef ENGLISH UTIL_DisplayError("Where the hell are you trying to attack from?"); #endif #ifdef FRENCH UTIL_DisplayError("Où voulez-vous attaquer?"); #endif } else if (iAttackDst >= NUM_COUNTRIES) { if (fVerbose) #ifdef ENGLISH UTIL_DisplayError("You can't attack the ocean!"); #endif #ifdef FRENCH UTIL_DisplayError("Impossible d'attaquer l'océan!"); #endif } else { if (!GAME_CanAttack(iAttackSrc, iAttackDst)) { if (fVerbose) { #ifdef ENGLISH snprintf(buf, sizeof(buf), "You can't attack %s from %s!", #endif #ifdef FRENCH snprintf(buf, sizeof(buf), "Attaque impossible de %s à partir de %s!", #endif RISK_GetNameOfCountry(iAttackDst), RISK_GetNameOfCountry(iAttackSrc)); UTIL_DisplayError(buf); } } else if (RISK_GetOwnerOfCountry(iAttackDst) == iCurrentPlayer) { if (fVerbose) { #ifdef ENGLISH snprintf(buf, sizeof(buf), "You can't attack %s -- you own it.", #endif #ifdef FRENCH snprintf(buf, sizeof(buf), "Attaque impossible de son propre territoire (%s).", #endif RISK_GetNameOfCountry(iAttackDst)); UTIL_DisplayError(buf); } } else return TRUE; } return FALSE; } /************************************************************************ * FUNCTION: GAME_PlaceClick * HISTORY: * 03.07.94 ESF Created. * 03.16.94 ESF Added support for placing multiple armies. * 05.19.94 ESF Factored out code to GAME_PlaceArmies. * 04.30.95 ESF Brought the dialog code from PlaceArmies here. * PURPOSE: * NOTES: ************************************************************************/ void GAME_PlaceClick(Int32 iCountry, Int32 iPlaceType) { Int32 maxN; /* Is the country picked the player's? */ if (GAME_ValidPlaceDst(iCountry)) { Int32 iArmies; maxN = RISK_GetNumArmiesOfPlayer(iCurrentPlayer); #ifndef DROPALL if ( iState == STATE_FORTIFY ) maxN = (maxN > DROP_ARMIES) ? DROP_ARMIES : maxN; #endif /* Depending on the type of placement, popup a dialog or not */ if (iPlaceType == PLACE_MULTIPLE) { iArmies = UTIL_GetArmyNumber(1, maxN, TRUE); if (!iArmies) return; } else if (iPlaceType == PLACE_ALL) iArmies = maxN; else iArmies = 1; GAME_PlaceArmies(iCountry, iArmies); /* If we're fortifying, we're done. */ if (iState == STATE_FORTIFY) GAME_EndTurn(); } } /************************************************************************ * FUNCTION: GAME_ValidPlaceDst * HISTORY: * 03.07.94 ESF Created. * PURPOSE: * NOTES: ************************************************************************/ Flag GAME_ValidPlaceDst(Int32 iPlaceDst) { if (iPlaceDst < 0) #ifdef ENGLISH UTIL_DisplayError("What the hell country is that!"); #endif #ifdef FRENCH UTIL_DisplayError("What the hell country is that!"); #endif else if (iPlaceDst >= NUM_COUNTRIES) #ifdef ENGLISH UTIL_DisplayError("Ahhh...That's the ocean, buddy..."); #endif #ifdef FRENCH UTIL_DisplayError("Ahhh...C'est l'océan, plouf..."); #endif else if (RISK_GetOwnerOfCountry(iPlaceDst) != iCurrentPlayer) #ifdef ENGLISH UTIL_DisplayError("You cannot place armies on opponent's territories."); #endif #ifdef FRENCH UTIL_DisplayError("Donner des armées à un autre joueur?"); #endif else return TRUE; return FALSE; } /************************************************************************ * FUNCTION: GAME_MoveClick * HISTORY: * 03.07.94 ESF Created. * 03.29.94 ESF Added a message when iMoveDst is verified. * 03.29.94 ESF Fixed lack of UTIL_DisplayComment() bug. * 01.09.95 JC End turn only if iState asn't moved to STATE_REGISTER. * PURPOSE: * NOTES: ************************************************************************/ void GAME_MoveClick(Int32 iCountry) { Int32 iNumArmies; char buf[256]; if (iMoveSrc < 0) { if (GAME_ValidMoveSrc(iCountry)) { iMoveSrc = iCountry; #ifdef ENGLISH snprintf(buf, sizeof(buf), "%s moving armies from %s to" " ", #endif #ifdef FRENCH snprintf(buf, sizeof(buf), "%s déplace des armées de %s en" " ", #endif RISK_GetNameOfPlayer(iCurrentPlayer), RISK_GetNameOfCountry(iMoveSrc)); UTIL_DisplayComment(buf); UTIL_LightCountry(iMoveSrc); } } else if (GAME_ValidMoveDst(iMoveSrc, iCountry)) { iMoveDst = iCountry; #ifdef ENGLISH snprintf(buf, sizeof(buf), "%s moving armies from %s to %s.", #endif #ifdef FRENCH snprintf(buf, sizeof(buf), "%s déplace des armées de %s en %s.", #endif RISK_GetNameOfPlayer(iCurrentPlayer), RISK_GetNameOfCountry(iMoveSrc), RISK_GetNameOfCountry(iMoveDst)); UTIL_DisplayComment(buf); iNumArmies = UTIL_GetArmyNumber(1, RISK_GetNumArmiesOfCountry(iMoveSrc)-1, TRUE); if (iNumArmies>0) { GAME_MoveArmies(iMoveSrc, iMoveDst, iNumArmies); if (iState != STATE_REGISTER) /* Turn over, man! */ GAME_EndTurn(); } else { UTIL_DarkenCountry(iMoveSrc); iMoveSrc = iMoveDst = -1; } } } /************************************************************************ * FUNCTION: GAME_ValidMoveSrc * HISTORY: * 03.07.94 ESF Created. * 03.29.94 ESF fixed a small bug, inserted "else". * PURPOSE: * NOTES: ************************************************************************/ Flag GAME_ValidMoveSrc(Int32 iMoveSrc) { if (iMoveSrc < 0) #ifdef ENGLISH UTIL_DisplayError("Where the hell are you trying to move from?"); #endif #ifdef FRENCH UTIL_DisplayError("Where the hell are you trying to move from?"); #endif else if (iMoveSrc >= NUM_COUNTRIES) #ifdef ENGLISH UTIL_DisplayError("You can't move armies from the ocean."); #endif #ifdef FRENCH UTIL_DisplayError("Impossible de déplacer des armées à partir de l'océan."); #endif else if (RISK_GetOwnerOfCountry(iMoveSrc) != iCurrentPlayer) #ifdef ENGLISH UTIL_DisplayError("You cannot move armies from an opponent's" " territories."); #endif #ifdef FRENCH UTIL_DisplayError("Impossible de prendre les armées d'un autre joueur."); #endif else if (RISK_GetNumArmiesOfCountry(iMoveSrc) == 1) #ifdef ENGLISH UTIL_DisplayError("You cannot move from territories that" " have one army to begin with."); #endif #ifdef FRENCH UTIL_DisplayError("Impossible de déplacer la seule armée d'un territoire."); #endif else return TRUE; return FALSE; } /************************************************************************ * FUNCTION: GAME_ValidMoveDst * HISTORY: * 03.07.94 ESF Created. * PURPOSE: * NOTES: used to get iMoveDst passed, which is a global static in game.c ************************************************************************/ Flag GAME_ValidMoveDst(Int32 iMoveSrc, Int32 iMoveDst) { char buf[256]; if (iMoveDst < 0) #ifdef ENGLISH UTIL_DisplayError("Where the hell are you trying to move from?"); #endif #ifdef FRENCH UTIL_DisplayError("Where the hell are you trying to move from?"); #endif else if (iMoveDst >= NUM_COUNTRIES) #ifdef ENGLISH UTIL_DisplayError("You can't move armies into the ocean -- they'd drown."); #endif #ifdef FRENCH UTIL_DisplayError("Impossible de placer des armées dans l'océan."); #endif else if (RISK_GetOwnerOfCountry(iMoveDst) != iCurrentPlayer) #ifdef ENGLISH UTIL_DisplayError("You cannot move armies to an opponent's" " territories."); #endif #ifdef FRENCH UTIL_DisplayError("Impossible de placer des armées sur un territoire ennemi."); #endif else if (!GAME_CanAttack(iMoveSrc, iMoveDst)) { #ifdef ENGLISH snprintf(buf, sizeof(buf), "Armies can't get to %s from %s", #endif #ifdef FRENCH snprintf(buf, sizeof(buf), "Déplacement impossible de %s en %s", #endif RISK_GetNameOfCountry(iMoveDst), RISK_GetNameOfCountry(iMoveSrc)); UTIL_DisplayError(buf); } else return TRUE; return FALSE; } /************************************************************************ * FUNCTION: GAME_GetContinentBonus * HISTORY: * 03.16.94 ESF Created. * 01.09.95 ESF Changed an if..else to an assertion. * PURPOSE: * NOTES: ************************************************************************/ Int32 GAME_GetContinentBonus(Int32 iPlayer) { Int32 piCount[NUM_CONTINENTS]; Int32 i, iArmies=0; /* Init. */ for (i=0; i!=NUM_CONTINENTS; i++) piCount[i] = 0; /* Count up how many countries the player has in each of the continents */ for (i=0; i!=NUM_COUNTRIES; i++) if (RISK_GetOwnerOfCountry(i) == iPlayer) { /* Sanity check */ D_Assert(RISK_GetContinentOfCountry(i) >= 0 && RISK_GetContinentOfCountry(i) < NUM_CONTINENTS, "Country has messed up number of armies."); piCount[RISK_GetContinentOfCountry(i)]++; } /* If the player has the total number of countries, give him or her bonus */ for (i=0; i!=NUM_CONTINENTS; i++) if (RISK_GetNumCountriesOfContinent(i) == piCount[i]) iArmies += RISK_GetValueOfContinent(i); return(iArmies); } /************************************************************************ * FUNCTION: GAME_PlayerDied * HISTORY: * 03.28.94 ESF Created. * 03.29.94 ESF Fixed off-by-one bug in end of game detection. * 04.11.94 ESF Added iKillerPlayer parameter. * 05.04.94 ESF Fixed bugs and exhanced. * 05.12.94 ESF Fixed bug, reset dead player's cards to 0. * 09.31.94 ESF Changed because of new ENDOFGAME contents. * 10.02.94 ESF Changed to set number of live players == 0. * 10.30.94 ESF Fixed bug, shouldn't be setting iNumLivePlayers to 0. * 01.09.95 ESF Changed to be more verbose. * 30.08.95 JC Talk the server: "force exchange of cards?". * PURPOSE: * NOTES: ************************************************************************/ void GAME_PlayerDied(Int32 iDeadPlayer) { MsgMessagePacket msg; char buf[256]; /* Notify everybody */ #ifdef ENGLISH snprintf(buf, sizeof(buf), "%s was destroyed by %s (who gained %d card%s).", #endif #ifdef FRENCH snprintf(buf, sizeof(buf), "%s est détruit par %s (qui gagne %d carte%s).", #endif RISK_GetNameOfPlayer(iDeadPlayer), RISK_GetNameOfPlayer(iCurrentPlayer), RISK_GetNumCardsOfPlayer(iDeadPlayer), (RISK_GetNumCardsOfPlayer(iDeadPlayer)>1)?"s":""); msg.strMessage = buf; msg.iFrom = FROM_SERVER; msg.iTo = DST_ALLPLAYERS; (void)RISK_SendMessage(CLNT_GetCommLinkOfClient(CLNT_GetThisClientID()), MSG_MESSAGEPACKET, &msg); /* Kill the player */ RISK_SetStateOfPlayer(iDeadPlayer, PLAYER_DEAD); /* Is there only one player left? If so, end of game... */ if (RISK_GetNumLivePlayers() == 1) { MsgVictory msgVictory; msgVictory.iWinner = iCurrentPlayer; (void)RISK_SendMessage(CLNT_GetCommLinkOfClient(CLNT_GetThisClientID()), MSG_VICTORY, &msgVictory); } else { MsgForceExchangeCards msg; Int32 i, n, m; /* Give the killer player all of the cards */ n = RISK_GetNumCardsOfPlayer(iCurrentPlayer); m = RISK_GetNumCardsOfPlayer(iDeadPlayer); /* Let the player know how many cards he or she got. */ if (m>0) { #ifdef ENGLISH snprintf(buf, sizeof(buf), "%s got %d card%s from %s.", #endif #ifdef FRENCH snprintf(buf, sizeof(buf), "%s prend %d carte%s de %s.", #endif RISK_GetNameOfPlayer(iCurrentPlayer), m, m==1?"":"s", RISK_GetNameOfPlayer(iDeadPlayer)); mess.strMessage = buf; (void)RISK_SendMessage(CLNT_GetCommLinkOfClient(CLNT_GetThisClientID()), MSG_NETMESSAGE, &mess); } for (i=0; i!=m; i++) RISK_SetCardOfPlayer(iCurrentPlayer, n+i, RISK_GetCardOfPlayer(iDeadPlayer, i)); RISK_SetNumCardsOfPlayer(iCurrentPlayer, n+m); RISK_SetNumCardsOfPlayer(iDeadPlayer, 0); if (m>0) { /* Force the player to exchange if he or she possesses * too many cards. */ msg.iPlayer = iCurrentPlayer; (void)RISK_SendMessage(CLNT_GetCommLinkOfClient(CLNT_GetThisClientID()), MSG_FORCEEXCHANGECARDS, &msg); } } } /************************************************************************ * FUNCTION: GAME_MissionToStr * HISTORY: * 29.08.95 JC Created (copy of GAME_ShowMission). * PURPOSE: Put in strScratch a description of the mission * NOTES: ************************************************************************/ void GAME_MissionToStr(Int32 iPlayer, Int16 iTyp, Int32 iNum1, Int32 iNum2, Flag fVict, char *buf, size_t bufsize) { UNUSED(iPlayer); #ifdef FRENCH switch (iTyp) { case NO_MISSION: snprintf(buf, bufsize, "Plus de mission -> Conquerir le monde"); break; case CONQUIER_WORLD: if (fVict) snprintf(buf, bufsize, "Mission accomplie: le monde est conquit"); else snprintf(buf, bufsize, "Mission: Conquerir le monde"); break; case CONQUIER_Nb_COUNTRY: if (fVict) snprintf(buf, bufsize, "Mission accomplie: %d territoires conquis", iNum1); else snprintf(buf, bufsize, "Mission: Conquerir %d territoires", iNum1); break; case CONQUIER_TWO_CONTINENTS: if (fVict) snprintf(buf, bufsize, "Mission accomplie: Conquerir %s et %s", RISK_GetNameOfContinent(iNum1), RISK_GetNameOfContinent(iNum2)); else snprintf(buf, bufsize, "Mission: Conquerir %s et %s", RISK_GetNameOfContinent(iNum1), RISK_GetNameOfContinent(iNum2)); break; case KILL_A_PLAYER: if (fVict || iNum2) snprintf(buf, bufsize, "Mission accomplie: %s est mort", RISK_GetNameOfPlayer(iNum1)); else if (RISK_GetNumCountriesOfPlayer(iNum1) <= 0) snprintf(buf, bufsize, "Mission impossible: Tuer %s qui est déjà mort", RISK_GetNameOfPlayer(iNum1)); else snprintf(buf, bufsize, "Mission: Tuer %s", RISK_GetNameOfPlayer(iNum1)); break; } #endif #ifdef ENGLISH switch (iTyp) { case NO_MISSION: snprintf(buf, bufsize, "Additional mission -> Conquer the world"); break; case CONQUIER_WORLD: if (fVict) snprintf(buf, bufsize, "Mission accomplished: the world is conquered"); else snprintf(buf, bufsize, "Mission: Conquer the world"); break; case CONQUIER_Nb_COUNTRY: if (fVict) snprintf(buf, bufsize, "Mission accomplished: %d countries conquered", iNum1); else snprintf(buf, bufsize, "Mission: Conquer %d countries", iNum1); break; case CONQUIER_TWO_CONTINENTS: if (fVict) snprintf(buf, bufsize, "Mission accomplished: Conquer %s and %s", RISK_GetNameOfContinent(iNum1), RISK_GetNameOfContinent(iNum2)); else snprintf(buf, bufsize, "Mission: Conquer %s and %s", RISK_GetNameOfContinent(iNum1), RISK_GetNameOfContinent(iNum2)); break; case KILL_A_PLAYER: if (fVict || iNum2) snprintf(buf, bufsize, "Mission accomplished: %s is dead", RISK_GetNameOfPlayer(iNum1)); else if (RISK_GetNumCountriesOfPlayer(iNum1) <= 0) snprintf(buf, bufsize, "Mission impossible: kill %s who's already dead", RISK_GetNameOfPlayer(iNum1)); else snprintf(buf, bufsize, "Mission: Kill %s", RISK_GetNameOfPlayer(iNum1)); break; } #endif } /************************************************************************ * FUNCTION: GAME_MissionAccomplied * HISTORY: * 25.08.95 JC Created from different pieces. * PURPOSE: * NOTES: ************************************************************************/ void GAME_MissionAccomplied(Int32 iWinner, Int16 iTyp, Int32 iNum1, Int32 iNum2) { Char str[256]; Int32 iChoice; char buf[256]; GAME_MissionToStr(iWinner, iTyp, iNum1, iNum2, TRUE, buf, sizeof(buf)); if (RISK_GetClientOfPlayer(iWinner) != CLNT_GetThisClientID()) { /* Player that has won is non-local */ #ifdef ENGLISH snprintf(str, sizeof(str), "%s has accomplied his mission!\n%s\n", RISK_GetNameOfPlayer(iCurrentPlayer), buf); (void)UTIL_PopupDialog("End of Mission", str, 2, "Cool!", "So What?", NULL); #endif #ifdef FRENCH snprintf(str, sizeof(str), "%s a terminé sa mission!\n%s\n", RISK_GetNameOfPlayer(iCurrentPlayer), buf); (void)UTIL_PopupDialog("Mission terminée", str, 2, "Cool!", "Et alors?", NULL); #endif return; } /* Winning player is local, congratulate him or her */ #ifdef ENGLISH (void)UTIL_PopupDialog(RISK_GetNameOfPlayer(iCurrentPlayer), "You WON!!!", 2, "Cool!", "So What?", NULL); #endif #ifdef FRENCH (void)UTIL_PopupDialog(RISK_GetNameOfPlayer(iCurrentPlayer), "Victoire!!!", 2, "Cool!", "Et alors?", NULL); #endif /* See if the player wants to continue or play again */ #ifdef ENGLISH if (RISK_GetNumLivePlayers () > 1) iChoice = UTIL_PopupDialog("Game over", "Play again?", 3, "Yes", "No", "Continue"); else iChoice = UTIL_PopupDialog("Game over", "Play again?", 2, "Yes", "No", NULL); #endif #ifdef FRENCH if (RISK_GetNumLivePlayers () > 1) iChoice = UTIL_PopupDialog("Partie terminée", "Jouer une autre partie?", 3, "Oui", "Non", "Continuer"); else iChoice = UTIL_PopupDialog("Partie terminée", "Jouer une autre partie?", 2, "Oui", "Non", NULL); #endif if (iChoice == QUERY_NO) { /* Leave the game */ UTIL_ExitProgram(0); } if (iChoice == QUERY_CANCEL) return; iState = STATE_REGISTER; (void)RISK_SendMessage(CLNT_GetCommLinkOfClient(CLNT_GetThisClientID()), MSG_ENDOFGAME, NULL); } /************************************************************************ * FUNCTION: GAME_Victory * HISTORY: * 28.08.95 JC Created from different pieces. * PURPOSE: * NOTES: ************************************************************************/ void GAME_Victory(Int32 iWinner) { Int32 iChoice; char buf[256]; if (RISK_GetClientOfPlayer(iWinner) != CLNT_GetThisClientID()) { /* Player that has won is non-local */ #ifdef ENGLISH snprintf(buf, sizeof(buf), "%s has won!", RISK_GetNameOfPlayer(iCurrentPlayer)); (void)UTIL_PopupDialog("End of Game", buf, 2, "Cool!", "So What?", NULL); #endif #ifdef FRENCH snprintf(buf, sizeof(buf), "%s a gagné!", RISK_GetNameOfPlayer(iCurrentPlayer)); (void)UTIL_PopupDialog("Fin du jeu", buf, 2, "Cool!", "Et alors?", NULL); #endif return; } /* Winning player is local, congratulate him or her */ #ifdef ENGLISH (void)UTIL_PopupDialog(RISK_GetNameOfPlayer(iCurrentPlayer), "You WON!!!", 2, "Cool!", "So What?", NULL); #endif #ifdef FRENCH (void)UTIL_PopupDialog(RISK_GetNameOfPlayer(iCurrentPlayer), "Victoire!!!", 2, "Cool!", "Et alors?", NULL); #endif /* See if the player wants to continue or play again */ #ifdef ENGLISH iChoice = UTIL_PopupDialog("Game over", "Play again?", 2, "Yes", "No", NULL); #endif #ifdef FRENCH iChoice = UTIL_PopupDialog("Partie terminée", "Jouer une autre partie?", 2, "Oui", "Non", NULL); #endif if (iChoice == QUERY_NO) { /* Leave the game */ UTIL_ExitProgram(0); } iState = STATE_REGISTER; (void)RISK_SendMessage(CLNT_GetCommLinkOfClient(CLNT_GetThisClientID()), MSG_ENDOFGAME, NULL); } /************************************************************************ * FUNCTION: GAME_GameOverMan * HISTORY: * 03.28.94 ESF Created. * 05.10.94 ESF Completed. * 05.12.94 ESF Added more functionality. * 01.05.95 DFE Fixed "Free Card" bug -- gave 1st person free card. * 02.13.95 ESF Updated to reflect new registration interface. * PURPOSE: * NOTES: ************************************************************************/ void GAME_GameOverMan(void) { /* There will be another game */ fGameStarted = FALSE; /* Since EndTurn isn't called, need to reset this so that first player * doesn't get a free card next game. */ fGetsCard = FALSE; /* The state will be one of registering */ if (iState != STATE_REGISTER) { iState = STATE_REGISTER; UTIL_ServerEnterState(iState); } UTIL_DisplayError(""); UTIL_DisplayComment(""); /* Set the colors to be of the initial setup */ COLOR_SetWorldColors(); /* Erase the dice roll */ DICE_Hide(); /* Get the new players */ REG_PopupDialog(); } /************************************************************************ * FUNCTION: GAME_ExchangeCards * HISTORY: * 03.29.94 ESF Created. * 04.23.95 ESF Fixed (terrible) card take-away bug. * 05.13.95 ESF Fixed (horrible) country bonus bug -- thanks Alan! * 22.08.95 JC Fixed a bug with computerized player * (piCards not ordered). * PURPOSE: * NOTES: ************************************************************************/ void GAME_ExchangeCards(Int32 *piCards) { Int32 i, j, k, piOldCards[3]; MsgExchangeCards msgCards; MsgNetMessage msgNetMessage; char buf[256]; /* only 3 cards because we're handling selected cards */ /* Save a copy and transform array indices into card indices */ for (i=0; i!=3; i++) { piOldCards[i] = piCards[i]; piCards[i] = RISK_GetCardOfPlayer(iCurrentPlayer, piCards[i]); } /* Send the cards to the server -- this will generate an _REPLYPACKET */ for (i=0; i!=3; i++) msgCards.piCards[i] = piCards[i]; (void)RISK_SendSyncMessage(CLNT_GetCommLinkOfClient(CLNT_GetThisClientID()), MSG_EXCHANGECARDS, &msgCards, MSG_REPLYPACKET, CBK_IncomingMessage); /* Update the date structures (bonus + countries on cards) */ RISK_SetNumArmiesOfPlayer(iCurrentPlayer, RISK_GetNumArmiesOfPlayer(iCurrentPlayer)+iReply); /* See if any of the cards match countries that the player has */ for (i=0; i!=3; i++) if (piCards[i] < NUM_COUNTRIES && /* Not a joker! */ RISK_GetOwnerOfCountry(piCards[i]) == iCurrentPlayer) RISK_SetNumArmiesOfCountry(piCards[i], RISK_GetNumArmiesOfCountry(piCards[i])+2); /* Take the cards away from the player */ for (i=0; i!=3; i++) { for (j=piOldCards[i]; jpiOldCards[i]) piOldCards[k] = piOldCards[k]-1; } RISK_SetNumCardsOfPlayer(iCurrentPlayer, RISK_GetNumCardsOfPlayer(iCurrentPlayer)-3); /* Display a message */ #ifdef ENGLISH snprintf(buf, sizeof(buf), "%s got %d armies from exchanging cards.", #endif #ifdef FRENCH snprintf(buf, sizeof(buf), "%s gagne %d armées en échangeant des cartes.", #endif RISK_GetNameOfPlayer(iCurrentPlayer), iReply); UTIL_DisplayError(buf); msgNetMessage.strMessage = buf; (void)RISK_SendMessage(CLNT_GetCommLinkOfClient(CLNT_GetThisClientID()), MSG_NETMESSAGE, &msgNetMessage); } /************************************************************************ * FUNCTION: GAME_EndTurn * HISTORY: * 03.17.94 ESF Created. * 03.28.94 ESF Added card code, do we need Sync on the call? * 03.28.94 ESF Moved iAttack/iDefend stuff here. * 03.29.94 ESF Added iMove stuff. * 04.11.94 ESF Added clear dice call. * 04.11.94 ESF Move message call to end. * 02.20.95 ESF Moved to game.c from utils.c * PURPOSE: * NOTES: ************************************************************************/ void GAME_EndTurn(void) { /* Get the player a card if he or she needs one */ if (fGetsCard) { MsgRequestCard msg; fGetsCard = FALSE; msg.iPlayer = iCurrentPlayer; (void)RISK_SendMessage(CLNT_GetCommLinkOfClient(CLNT_GetThisClientID()), MSG_REQUESTCARD, &msg); } /* Darken the country if the player was attacking or moving */ if (iAttackSrc >= 0) UTIL_DarkenCountry(iAttackSrc); if (iMoveSrc >= 0) UTIL_DarkenCountry(iMoveSrc); /* Clear the dice box */ DICE_Hide(); /* Init. variables for next turn */ fCanExchange = TRUE; iAttackSrc = iAttackDst = iLastAttackSrc = iLastAttackDst = -1; iMoveSrc = iMoveDst = -1; /* Notify the server of the end-of-turn condition and wait for a response */ (void)RISK_SendSyncMessage(CLNT_GetCommLinkOfClient(CLNT_GetThisClientID()), MSG_ENDTURN, NULL, MSG_TURNNOTIFY, CBK_IncomingMessage); } /************************************************************************ * FUNCTION: GAME_IsMissionAccomplied * HISTORY: * 16.08.95 JC Created. * 23.08.95 JC added iKilledPlayer. * PURPOSE: * NOTES: ************************************************************************/ Flag GAME_IsMissionAccomplied(Int32 iPlayer, Int32 iKilledPlayer) { Int32 piCount [NUM_CONTINENTS]; Int32 i, cont, n1, n2; switch (RISK_GetMissionTypeOfPlayer(iPlayer)) { case CONQUIER_WORLD: if (RISK_GetNumCountriesOfPlayer(iPlayer) >= NUM_COUNTRIES) return TRUE; break; case CONQUIER_Nb_COUNTRY: n1 = RISK_GetMissionNumberOfPlayer(iPlayer); if (RISK_GetNumCountriesOfPlayer(iPlayer) >= n1) return TRUE; break; case CONQUIER_TWO_CONTINENTS: for (cont=0; cont */ Flag GAME_CanAttack(Int32 AttackSrc, Int32 iCountry); extern Int32 iLastAttackSrc, iLastAttackDst; extern Int32 iMoveSrc; extern Flag fGetsCard, fCanExchange; #endif xfrisk-1.2/gui-func.h0100644000175000017500000000221407013357407013572 0ustar johnojohno/* * XFrisk - The classic board game for X * Copyright (C) 1993-1999 Elan Feingold (elan@aetherworks.com) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * $Id: gui-func.h,v 1.4 1999/11/13 21:58:31 morphy Exp $ */ #ifndef _GUI #define _GUI #include "types.h" void GUI_Setup(Int32 argc, CString *argv); void GUI_Start(void); void GUI_AddCallbacks(Int32 iReadSock); void GUI_LoadMap(CString strMapFile); void GUI_SetColorOfCurrentPlayer(Int32 iColor); #endif xfrisk-1.2/gui-vars.h0100644000175000017500000000475407013357407013625 0ustar johnojohno/* * XFrisk - The classic board game for X * Copyright (C) 1993-1999 Elan Feingold (elan@aetherworks.com) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * $Id: gui-vars.h,v 1.4 1999/11/13 21:58:31 morphy Exp $ */ #ifndef _GUI_VARS #define _GUI_VARS #include #include #include "riskgame.h" #include "colormap.h" extern Widget wToplevel, wForm; extern Widget wControls; extern Widget wAttackLabel, wAttackList; extern Widget wActionLabel, wActionList; extern Widget wMsgDestLabel, wMsgDestList, wMsgDestViewport; extern Widget wSendMsgText; extern Widget wMsgText; extern Widget wPlayField; extern Widget wCommentLabel, wQuitButton, wRepeatButton, wCancelAttackButton; extern Widget wHelpButton, wShowCardsButton; extern Widget wEndTurnButton, wDiceBox; extern Widget wErrorLabel; /* Move to cardView.c */ extern Widget wCardShell, wCardForm, wCardTableBox; extern Widget wCardViewport, wCardToggle[MAX_CARDS]; extern Widget wExchangeButton, wCancelCardsButton; /* Move somewhere... */ extern Widget wArmiesShell, wArmiesForm, wArmiesLabel, wArmiesText; extern Widget wFinishArmiesButton, wCancelArmiesButton; /* Move to helpView.c */ extern Widget wHelpShell, wHelpForm, wHelpTopicViewport, wHelpTopicList; extern Widget wHelpTopicLabel, wHelpText, wHelpOkButton; extern Widget wHelpLabel; /* Move to dialog.c */ extern Widget wDialogShell, wDialogLabel, wDialogButton[3], wDialogForm; extern Widget wAboutButton; extern XImage *pMapImage; extern Pixmap pixMapImage; extern Display *hDisplay; extern Window hWindow; extern int iScreen; extern GC hGC, hGC_XOR; extern XFontStruct *pFont; extern XtAppContext appContext; extern Visual *pVisual; extern Int32 iVisualCount; extern Arg pVisualArgs[3]; #endif xfrisk-1.2/gui.c0100644000175000017500000005536407036460614012652 0ustar johnojohno/* * XFrisk - The classic board game for X * Copyright (C) 1993-1999 Elan Feingold (elan@aetherworks.com) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * $Id: gui.c,v 1.12 2000/01/10 22:47:40 tony Exp $ * * $Log: gui.c,v $ * Revision 1.12 2000/01/10 22:47:40 tony * made colorstuff more private to colormap.c, only scrollbars get set wrong, rest seems to work ok now * * Revision 1.11 2000/01/09 20:05:02 morphy * Corrections to color map loading - previously struct padding possibility was ignored * * Revision 1.10 2000/01/09 19:17:43 morphy * Added Log tag in comment header * */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "gui-vars.h" #include "gui-func.h" #include "callbacks.h" #include "dice.h" #include "cards.h" #include "colormap.h" #include "utils.h" #include "debug.h" #include "types.h" #include "version.h" #include "colorEdit.h" #include "registerPlayers.h" #include "addPlayer.h" #include "viewCards.h" #include "viewStats.h" #include "viewFeedback.h" #include "viewLog.h" #include "viewStats.h" #include "viewChat.h" /* Main window widgets */ static Widget wMap; static Widget wCurrentPlayer; Widget wToplevel; Widget wDiceBox, wMsgDestList, wErrorLabel; Widget wActionList, wAttackList; Widget wSendMsgText; Widget wMsgText, wCommentLabel; /* Main stuff */ XtAppContext appContext; /* The view cards popup shell */ Widget wCardShell; Widget wCardToggle[MAX_CARDS]; /* The "place armies" popup shell */ Widget wArmiesShell, wArmiesText, wCancelArmiesButton; /* The "help" popup shell */ Widget wHelpShell; Widget wHelpTopicList, wHelpLabel, wHelpText; /* The "generic popup" dialog */ Widget wDialogLabel, wDialogButton[3]; Widget wDialogShell; /* Action tables */ static XtActionsRec actionTable[] = { { "popupArmies", (XtActionProc)UTIL_QueryYes }, { "mapClick", (XtActionProc)CBK_MapClick }, { "mapShiftClick", (XtActionProc)COLEDIT_MapShiftClick }, { "sendMessage", (XtActionProc)CBK_SendMessage }, { NULL, NULL } }; #ifdef ENGLISH static char *pstrAttackDice[] = { "1 die", "2 dice", "3 dice", "Auto", }; #endif #ifdef FRENCH static char *pstrAttackDice[] = { "1 dé", "2 dés", "3 dés", "Auto", }; #endif #ifdef ENGLISH static char *pstrActions[] = { "Place", "Attack", "Do or die", "move", }; #endif #ifdef FRENCH static char *pstrActions[] = { "Placer", "Attaquer", "À mort", "Déplacer", }; #endif /* Private functions */ static Int32 GUI_GetNumColorsInMap(CString strMapFile); Display *hDisplay; Window hWindow; GC hGC, hGC_XOR; Int32 iScreen; XFontStruct *pFont; Pixmap pixMapImage; XImage *pMapImage; Visual *pVisual; /* These are used to set up the visual in all shell widgets */ Int32 iVisualCount; Arg pVisualArgs[3]; /************************************************************************ * FUNCTION: GUI_Setup * HISTORY: * 01.25.94 ESF Created. * 02.19.94 ESF Added Card UI stuff. * 03.03.94 ESF Added callbacks for the remaining buttons. * 03.03.94 ESF Changed so `Number of Armies?' starts unmanaged. * 03.04.94 ESF Added another comment widget for error messages. * 03.06.94 ESF Added an army placement shell. * 03.14.94 ESF Changed shells to be transient. * 04.01.94 ESF Added help popup. * 04.02.94 ESF Added generic dialog with three possible answers. * 05.19.94 ESF Added TrueColor display patches. * 09.14.94 ESF Fixed so that it works with more TrueColor visuals. * 01.24.95 ESF Changed so that actions are added in one place. * 01.24.95 ESF Changed so that accelerators are done in res. file. * 01.25.95 ESF Added dummy widget for centering buttons in dialog. * 19.12.99 TdH Moved call to GUI_LoadMap(MAPFILE) here * PURPOSE: * NOTES: ************************************************************************/ void GUI_Setup(Int32 argc, CString *argv) { Int32 iCount, i, iVisualCount; Arg pArgs[10], pVisualArgs[3]; char buf[256]; Widget wForm, wControls; Widget wStatViewButton, wAboutButton; Widget wAttackLabel; Widget wActionLabel; Widget wMsgDestLabel, wMsgDestViewport; Widget wPlayField; Widget wQuitButton, wRepeatButton, wCancelAttackButton; Widget wHelpButton, wShowCardsButton, wShowMissionButton; Widget wEndTurnButton; /* The view cards popup shell */ Widget wCardForm, wCardTableBox; Widget wCardViewport; Widget wExchangeButton, wCancelCardsButton; /* The "place armies" popup shell */ Widget wArmiesForm, wArmiesLabel; Widget wFinishArmiesButton; /* The "help" popup shell */ Widget wHelpForm, wHelpTopicViewport; Widget wHelpTopicLabel, wHelpOkButton; /* The "generic popup" dialog */ Widget wDialogForm; /* Setup a colormap for the application */ COLOR_GetColormap(pVisualArgs, &iVisualCount, GUI_GetNumColorsInMap(MAPFILE) + MAX_PLAYERS + NUM_OTHERCOLORS, argc, argv); /* Create the application's main window */ wToplevel = XtAppCreateShell(NULL, "XFrisk", applicationShellWidgetClass, hDisplay, pVisualArgs, iVisualCount); /* Make sure to set the arguments from the command line */ XtVaSetValues(wToplevel, XtNargc, argc, XtNargv, argv, NULL); /* Add the action table */ XtAppAddActions(appContext, actionTable, XtNumber(actionTable)); /* The main window UI stuff */ wForm = XtCreateManagedWidget("wForm", formWidgetClass, wToplevel, NULL, 0); wMap = XtCreateManagedWidget("wMap", formWidgetClass, wForm, NULL, 0); wPlayField = XtCreateManagedWidget("wPlayField", formWidgetClass, wForm, NULL, 0); wControls = XtCreateManagedWidget("wControls", formWidgetClass, wForm, NULL, 0); /* Holds the number of attack dice to use (1, 2, or 3) */ wAttackLabel = XtCreateManagedWidget("wAttackLabel", labelWidgetClass, wControls, NULL, 0); iCount=0; XtSetArg(pArgs[iCount], XtNlist, pstrAttackDice); iCount++; XtSetArg(pArgs[iCount], XtNnumberStrings, 4); iCount++; wAttackList = XtCreateManagedWidget("wAttackList", listWidgetClass, wControls, pArgs, iCount); XtAddCallback(wAttackList, XtNcallback, CBK_Attack, NULL); /* Holds the action to perform (Place Armies, Attack, Free Move) */ wActionLabel = XtCreateManagedWidget("wActionLabel", labelWidgetClass, wControls, NULL, 0); iCount=0; XtSetArg(pArgs[iCount], XtNlist, pstrActions); iCount++; XtSetArg(pArgs[iCount], XtNnumberStrings, 4); iCount++; wActionList = XtCreateManagedWidget("wActionList", listWidgetClass, wControls, pArgs, iCount); XtAddCallback(wActionList, XtNcallback, CBK_Action, NULL); /* Holds the destination of a message (All, [players...]) */ wMsgDestLabel = XtCreateManagedWidget("wMsgDestLabel", labelWidgetClass, wControls, NULL, 0); wMsgDestViewport = XtCreateManagedWidget("wMsgDestViewport", viewportWidgetClass, wControls, NULL, 0); #ifdef ENGLISH pstrMsgDstCString[0] = "All Players"; #endif #ifdef FRENCH pstrMsgDstCString[0] = "Tous les joueurs"; #endif wMsgDestList = XtVaCreateManagedWidget("wMsgDestList", listWidgetClass, wMsgDestViewport, XtNlist, pstrMsgDstCString, XtNnumberStrings, 1, NULL); XtAddCallback(wMsgDestList, XtNcallback, CBK_MsgDest, NULL); /* Holds the message to send */ wSendMsgText = XtVaCreateManagedWidget("wSendMsgText", asciiTextWidgetClass, wControls, XtNeditType, XawtextEdit, XtNwrap, XawtextWrapNever, NULL); /* Holds all of the messages */ wMsgText = XtVaCreateManagedWidget("wMsgText", asciiTextWidgetClass, wControls, XtNstring, "", XtNscrollVertical, XawtextScrollAlways, XtNwrap, XawtextWrapWord, XtNautoFill, True, NULL); /* Turns the color of the player who's turn it is */ wCurrentPlayer = XtCreateManagedWidget("wCurrentPlayer", formWidgetClass, wPlayField, NULL, 0); /* Running commentary on the game, one liners, rules */ wCommentLabel = XtCreateManagedWidget("wCommentLabel", labelWidgetClass, wPlayField, NULL, 0); /* Tells about the game version */ wAboutButton = XtCreateManagedWidget("wAboutButton", commandWidgetClass, wPlayField, NULL, 0); XtAddCallback(wAboutButton, XtNcallback, CBK_About, NULL); /* Cancel an attack */ wCancelAttackButton = XtCreateManagedWidget("wCancelAttackButton", commandWidgetClass, wPlayField, NULL, 0); XtAddCallback(wCancelAttackButton, XtNcallback, CBK_CancelAttack, NULL); /* Repeat a single attack */ wRepeatButton = XtCreateManagedWidget("wRepeatButton", commandWidgetClass, wPlayField, NULL, 0); XtAddCallback(wRepeatButton, XtNcallback, CBK_Repeat, NULL); /* End a turn */ wEndTurnButton = XtCreateManagedWidget("wEndTurnButton", commandWidgetClass, wPlayField, NULL, 0); XtAddCallback(wEndTurnButton, XtNcallback, CBK_EndTurn, NULL); /* Show the cards */ wShowCardsButton = XtCreateManagedWidget("wShowCardsButton", commandWidgetClass, wPlayField, NULL, 0); XtAddCallback(wShowCardsButton, XtNcallback, CBK_ShowCards, NULL); /* Show the mission */ wShowMissionButton = XtCreateManagedWidget("wShowMissionButton", commandWidgetClass, wPlayField, NULL, 0); XtAddCallback(wShowMissionButton, XtNcallback, CBK_ShowMission, NULL); /* Statistics View */ wStatViewButton = XtCreateManagedWidget("wStatViewButton", commandWidgetClass, wPlayField, NULL, 0); XtAddCallback(wStatViewButton, XtNcallback, (XtCallbackProc)STAT_PopupDialog, NULL); /* Help */ wHelpButton = XtCreateManagedWidget("wHelpButton", commandWidgetClass, wPlayField, NULL, 0); XtAddCallback(wHelpButton, XtNcallback, CBK_Help, NULL); /* The Quit button */ wQuitButton = XtCreateManagedWidget("wQuitButton", commandWidgetClass, wPlayField, NULL, 0); XtAddCallback(wQuitButton, XtNcallback, CBK_Quit, NULL); /* Error messages */ wErrorLabel = XtCreateManagedWidget("wErrorLabel", labelWidgetClass, wPlayField, NULL, 0); /* Holds the rolled dice bitmaps */ wDiceBox = XtCreateManagedWidget("wDiceBox", formWidgetClass, wPlayField, NULL, 0); /* Finished */ XtRealizeWidget(wToplevel); /* Build the card popup shell */ wCardShell = XtCreatePopupShell("Cards", transientShellWidgetClass, wToplevel, pVisualArgs, iVisualCount); wCardForm = XtCreateManagedWidget("wCardForm", formWidgetClass, wCardShell, NULL, 0); wCardViewport = XtCreateManagedWidget("wCardViewport", viewportWidgetClass, wCardForm, NULL, 0); wCardTableBox = XtCreateManagedWidget("wCardTableBox", boxWidgetClass, wCardViewport, NULL, 0); for (i=0; i!=MAX_CARDS; i++) { snprintf(buf, sizeof(buf), "wCardToggle%d", i); wCardToggle[i] = XtVaCreateWidget(buf, toggleWidgetClass, wCardTableBox, XtNwidth, CARD_WIDTH, XtNheight, CARD_HEIGHT, XtNborderWidth, 0, XtNhighlightThickness, 0, XtNlabel, "", NULL); } wExchangeButton = XtCreateManagedWidget("wExchangeButton", commandWidgetClass, wCardForm, NULL, 0); XtAddCallback(wExchangeButton, XtNcallback, CBK_ExchangeCards, NULL); wCancelCardsButton = XtCreateManagedWidget("wCancelCardsButton", commandWidgetClass, wCardForm, NULL, 0); XtAddCallback(wCancelCardsButton, XtNcallback, CBK_CancelCards, NULL); /* Build the army placement shell */ wArmiesShell = XtCreatePopupShell("Armies", transientShellWidgetClass, wToplevel, pVisualArgs, iVisualCount); wArmiesForm = XtCreateManagedWidget("wArmiesForm", formWidgetClass, wArmiesShell, NULL, 0); wArmiesLabel = XtCreateManagedWidget("wArmiesLabel", labelWidgetClass, wArmiesForm, NULL, 0); wArmiesText = XtVaCreateManagedWidget("wArmiesText", asciiTextWidgetClass, wArmiesForm, XtNeditType, XawtextEdit, NULL); wFinishArmiesButton = XtCreateManagedWidget("wFinishArmiesButton", commandWidgetClass, wArmiesForm, NULL, 0); XtAddCallback(wFinishArmiesButton, XtNcallback, (XtCallbackProc)UTIL_QueryYes, NULL); wCancelArmiesButton = XtCreateManagedWidget("wCancelArmiesButton", commandWidgetClass, wArmiesForm, NULL, 0); XtAddCallback(wCancelArmiesButton, XtNcallback, (XtCallbackProc)UTIL_QueryNo, NULL); /* Build the help shell */ wHelpShell = XtCreatePopupShell("Help", transientShellWidgetClass, wToplevel, pVisualArgs, iVisualCount); wHelpForm = XtCreateManagedWidget("wHelpForm", formWidgetClass, wHelpShell, NULL, 0); wHelpTopicLabel = XtCreateManagedWidget("wHelpTopicLabel", labelWidgetClass, wHelpForm, NULL, 0); wHelpLabel = XtCreateManagedWidget("wHelpLabel", labelWidgetClass, wHelpForm, NULL, 0); wHelpTopicViewport = XtCreateManagedWidget("wHelpTopicViewport", viewportWidgetClass, wHelpForm, NULL, 0); wHelpTopicList = XtCreateManagedWidget("wHelpTopicList", listWidgetClass, wHelpTopicViewport, NULL, 0); XtAddCallback(wHelpTopicList, XtNcallback, CBK_HelpSelectTopic, NULL); wHelpText = XtVaCreateManagedWidget("wHelpText", asciiTextWidgetClass, wHelpForm, XtNwrap, XawtextWrapWord, XtNdisplayCaret, False, XtNscrollVertical, XawtextScrollAlways, NULL); wHelpOkButton = XtCreateManagedWidget("wHelpOkButton", commandWidgetClass, wHelpForm, NULL, 0); XtAddCallback(wHelpOkButton, XtNcallback, CBK_HelpOk, NULL); /* Build the generic dialog shells */ wDialogShell = XtCreatePopupShell("Dialog", transientShellWidgetClass, wToplevel, pVisualArgs, iVisualCount); wDialogForm = XtCreateManagedWidget("wDialogForm", formWidgetClass, wDialogShell, NULL, 0); wDialogLabel = XtCreateManagedWidget("wDialogLabel", labelWidgetClass, wDialogForm, NULL, 0); wDialogButton[0] = XtCreateManagedWidget("wDialogButton1", commandWidgetClass, wDialogForm, NULL, 0); XtAddCallback(wDialogButton[0], XtNcallback, (XtCallbackProc)UTIL_QueryYes, NULL); wDialogButton[1] = XtCreateManagedWidget("wDialogButton2", commandWidgetClass, wDialogForm, NULL, 0); XtAddCallback(wDialogButton[1], XtNcallback, (XtCallbackProc)UTIL_QueryNo, NULL); wDialogButton[2] = XtCreateManagedWidget("wDialogButton3", commandWidgetClass, wDialogForm, NULL, 0); XtAddCallback(wDialogButton[2], XtNcallback, (XtCallbackProc)UTIL_QueryCancel, NULL); /* Get a couple globals for the future */ hDisplay = XtDisplay(wMap); hWindow = XtWindow(wMap); iScreen = DefaultScreen(hDisplay); hGC = XCreateGC(hDisplay, hWindow, 0, NULL); hGC_XOR = XCreateGC(hDisplay, hWindow, 0, NULL); /* Set the XOR GC appropriately */ XSetFunction(hDisplay, hGC_XOR, GXinvert); XSetLineAttributes(hDisplay, hGC_XOR, 2, LineSolid, CapButt, JoinMiter); /* Get the font */ if ((pFont=XLoadQueryFont(hDisplay, "fixed")) == NULL) { #ifdef ENGLISH (void)UTIL_PopupDialog("Fatal Error", "GUI: Couldn't get font 'fixed'!\n", 1, #endif #ifdef FRENCH (void)UTIL_PopupDialog("Erreur fatale", "GUI: Impossible de charger la fonte'fixed'!\n", 1, #endif "Ok", NULL, NULL); UTIL_ExitProgram(-1); } /* Build the object-like MVC View dialogs */ COLEDIT_BuildDialog(); REG_BuildDialog(); PLAYER_BuildDialog(); CARD_BuildDialog(); CHAT_BuildDialog(); STAT_BuildDialog(); LOG_BuildDialog(); FDBK_BuildDialog(); /* Print a welcome message */ #ifdef ENGLISH snprintf(buf, sizeof(buf), "Welcome to Frisk %s!", VERSION); #endif #ifdef FRENCH snprintf(buf, sizeof(buf), "Bienvenu à Frisk %s!", VERSION); #endif UTIL_DisplayComment(buf); GUI_LoadMap(MAPFILE); } /************************************************************************ * FUNCTION: GUI_Start * HISTORY: * 01.25.94 ESF Created. * 01.29.94 ESF Added Registration popup. * 03.16.94 ESF Centering and automatic placement of wRegisterShell. * 04.01.94 ESF Fixed bug, XtNy had an x by it. * 01.29.95 ESF Cleaned up, almost nothing left. * PURPOSE: * NOTES: ************************************************************************/ void GUI_Start(void) { XtAppMainLoop(appContext); } /************************************************************************ * FUNCTION: GUI_AddCallbacks * HISTORY: * 01.25.94 ESF Created * 04.11.94 ESF Added event handler for dice region. * 01.24.95 ESF Added event handler for keyboard. * PURPOSE: * NOTES: ************************************************************************/ void GUI_AddCallbacks(Int32 iReadSock) { /* Add the input to receive messages from */ (void)XtAppAddInput (appContext, iReadSock, (XtPointer)XtInputReadMask, CBK_XIncomingMessage, NULL); /* Add event handlers */ XtAddEventHandler(wMap, ExposureMask, False, (XtEventHandler)CBK_RefreshMap, NULL); XtAddEventHandler(wMap, ExposureMask, False, (XtEventHandler)CBK_RefreshDice, NULL); } /************************************************************************ * FUNCTION: GUI_LoadMap * HISTORY: * 01.26.94 ESF Created. * 01.27.94 ESF Added palette code. * 01.28.94 ESF Changed to allocate pixmap as well as image. * 02.03.94 ESF Don't allocate colors in order, use mapping. * 02.23.94 ESF Started adding 24 bit server support. * 04.01.94 ESF Fixed free on bogus pointer. * 05.12.94 ESF Moved world colors to colormap.c. * 05.19.94 ESF Added TrueColor display patches. * 09.09.94 ESF Fixed small bug in initializing player turn indicator. * PURPOSE: * NOTES: TdH: i think here need to do some adjusment for colormap ************************************************************************/ void GUI_LoadMap(CString strMapFile) { Int32 iHeight, iWidth ,iNumPixels; FILE *hMap; Int32 iPixels; Byte bColor, bLength, *pMapData, *pDataStream, *pBuffer, *pTemp; Int32 lCurrent, lEnd, iNC; char buf[256]; /* Open file and get dimensions */ if ((hMap=UTIL_OpenFile(strMapFile, "r"))==NULL) { #ifdef ENGLISH snprintf(buf, sizeof(buf), "GUI: Could not load %s.", strMapFile); (void)UTIL_PopupDialog("Fatal Error", buf, 1, "Ok", NULL, NULL); #endif #ifdef FRENCH snprintf(buf, sizeof(buf), "GUI: Ne peut charger %s.", strMapFile); (void)UTIL_PopupDialog("Erreur fatale", buf, 1, "Ok", NULL, NULL); #endif UTIL_ExitProgram(-1); } fscanf(hMap, "%d%d%d\n", &iWidth, &iHeight, &iNC); COLOR_SetNumColors(iNC); /* Allocate memory for the map data */ pMapData = (unsigned char *)MEM_Alloc(iWidth*iHeight); /* Allocate memory for the buffer; first find out size of file */ lCurrent = ftell(hMap); fseek(hMap, 0, SEEK_END); lEnd = ftell(hMap); fseek(hMap, lCurrent, SEEK_SET); pTemp = pBuffer = (unsigned char *)MEM_Alloc(lEnd-lCurrent); /* Read in the rest of the file */ fread(pBuffer, 1, lEnd-lCurrent, hMap); iNumPixels = iWidth*iHeight; for (iPixels=0,pDataStream=pMapData; iPixels < iNumPixels; iPixels+=bLength) { /* Get a color segment */ bLength = *pBuffer++; bColor = *pBuffer++; /* Adjust for black/white */ if (bColor == BLACK) bColor = COLOR_GetNumColors()-2; else if (bColor == WHITE) bColor = COLOR_GetNumColors()-1; /* Put it in the map image */ memset(pDataStream, COLOR_CountryToColor(bColor), bLength); pDataStream += bLength; } /* Create an image to hold the map */ pMapImage = XCreateImage(hDisplay, pVisual, 8, ZPixmap, 0, (char *)pMapData, iWidth, iHeight, 8, iWidth); /* Create a pixmap to hold the image server-side */ pixMapImage = XCreatePixmap(hDisplay, RootWindowOfScreen(XtScreen(wMap)), iWidth, iHeight, DefaultDepth(hDisplay, DefaultScreen(hDisplay))); /* Save the world colormap */ COLOR_SetWorldColormap(pBuffer); COLOR_SetWorldColors(); /* Finally write map image to pixmap and window */ if (!COLOR_IsTrueColor()) XPutImage(hDisplay, pixMapImage, hGC, pMapImage, 0, 0, 0, 0, iWidth, iHeight); XCopyArea(hDisplay, pixMapImage, hWindow, hGC, 0, 0, iWidth, iHeight, 0, 0); /* After colormap is established we want to do this (move it elsewhere!) */ XtVaSetValues(wCurrentPlayer, XtNbackground, COLOR_QueryColor(COLOR_DieToColor(2)), NULL); /* Free up memory we were using */ MEM_Free(pTemp); } /************************************************************************ * FUNCTION: GUI_GetNumColorsInMap * HISTORY: * 09.14.94 ESF Created. * 10.02.94 ESF Fixed to not call UTIL_PopupDialog. * PURPOSE: * NOTES: Called once? ************************************************************************/ static Int32 GUI_GetNumColorsInMap(CString strMapFile) { FILE *hMap; Int32 iWidth, iHeight, iNumColors; /* Open file and get dimensions */ if ((hMap=UTIL_OpenFile(strMapFile, "r"))==NULL) { printf("CLIENT: Fatal error, could not load %s.\n", strMapFile); UTIL_ExitProgram(-1); } /* Read the header and close the file */ fscanf(hMap, "%d%d%d\n", &iWidth, &iHeight, &iNumColors); fclose(hMap); return iNumColors; } /************************************************************************ * FUNCTION: GUI_SetColorOfCurrentPlayer * HISTORY: * 17.08.94 JC Created. * PURPOSE: * NOTES: ************************************************************************/ void GUI_SetColorOfCurrentPlayer(Int32 iColor) { Int32 c, d; c = COLOR_QueryColor(iColor); XtVaGetValues(wCurrentPlayer, XtNbackground, &d, NULL); if (d != c) XtVaSetValues(wCurrentPlayer, XtNbackground, c, NULL); } xfrisk-1.2/help.c0100644000175000017500000001335107013357407013004 0ustar johnojohno/* * XFrisk - The classic board game for X * Copyright (C) 1993-1999 Elan Feingold (elan@aetherworks.com) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * $Id: help.c,v 1.4 1999/11/13 21:58:31 morphy Exp $ */ #include #include #include #include #include #include #include #include #include "riskgame.h" #include "network.h" #include "types.h" #include "help.h" #include "client.h" #include "gui-vars.h" #include "callbacks.h" #include "utils.h" #include "debug.h" static CString *pstrIndexCStrings; static CString *pstrHelpCStrings; static Int32 iNumHelpTopics=0; /* The first is the default number of topics, and the latter is the * number of new topics to allocate if we run out room. */ #define HELP_TOPICS 32 #define HELP_MORETOPICS 8 /************************************************************************ * FUNCTION: HELP_Init * HISTORY: * 04.01.94 ESF Created * 04.02.94 ESF Added allocation of more memory if needed. * PURPOSE: * NOTES: ************************************************************************/ void HELP_Init(CString strHelpFile) { FILE *hHelpFile; struct stat statBuf; char *pHelpText; Int32 i, j, iTopicsMemory = HELP_TOPICS; char buf[256]; /* Allocate the default amount of room for the help topics */ pstrIndexCStrings = (CString *)MEM_Alloc(sizeof(CString)*iTopicsMemory); pstrHelpCStrings = (CString *)MEM_Alloc(sizeof(CString)*iTopicsMemory); /* Open the file, and find out its size to allocate memory for it */ if ((hHelpFile=UTIL_OpenFile(HELPFILE, "r"))==NULL) { #ifdef ENGLISH snprintf(buf, sizeof(buf), "HELP: cannot open %s!", HELPFILE); UTIL_PopupDialog("Fatal Error", buf, 1, "Ok", NULL, NULL); #endif #ifdef FRENCH snprintf(buf, sizeof(buf), "HELP: impossible d'ouvrir %s!", HELPFILE); UTIL_PopupDialog("Erreur fatale", buf, 1, "Ok", NULL, NULL); #endif UTIL_ExitProgram(-1); } if (fstat(fileno(hHelpFile), &statBuf)!=0) { #ifdef ENGLISH UTIL_PopupDialog("Fatal Error", "HELP: Couldn't get size of file", #endif #ifdef FRENCH UTIL_PopupDialog("Erreur fatale", "HELP: Impossible d'obtenir la " "taille du fichier", #endif 1, "Ok", NULL, NULL); UTIL_ExitProgram(-1); } /* Read in the file after allocating room for it */ pHelpText = strHelpFile = (CString)MEM_Alloc(statBuf.st_size); fread(strHelpFile, statBuf.st_size, 1, hHelpFile); /* Search through the file for topics, filling out the tables of topic * pointers as we go, and allocating more memory as needed. When we * find an end of topic, stick a '\0' in, and erase '\n' since the * text widget will do the word wrapping for us. This can be sped up! */ for (i=0; i!=statBuf.st_size; i++) { if (pHelpText[i] == '\n' && (pHelpText[i+1] == '\n' || pHelpText[i+1] == '\t')) i++; /* Stick in a blank as long as the last character wasn't a space */ else if (pHelpText[i] == '\n' && i>0 && pHelpText[i-1] != ' ') pHelpText[i] = ' '; else if (pHelpText[i] == '%' && pHelpText[i+1] == '%') { /* We've found the end of a topic */ pHelpText[i] = '\0'; i+=2; } else if (pHelpText[i] == '%') { /* We've found the beginning of a topic */ pstrIndexCStrings[iNumHelpTopics] = &pHelpText[i+1]; /* Find the beginning of the topic */ for (j=i; pHelpText[j]!='\n'; j++) ; /* TwiddleThumbs() */ pHelpText[j] = '\0'; pstrHelpCStrings[iNumHelpTopics++] = &pHelpText[j+1]; /* Allocate more memory? */ if (iNumHelpTopics > iTopicsMemory) { iTopicsMemory += HELP_MORETOPICS; pstrHelpCStrings = (CString *)realloc(pstrHelpCStrings, sizeof(CString)* iTopicsMemory); pstrIndexCStrings = (CString *)realloc(pstrIndexCStrings, sizeof(CString)* iTopicsMemory); } } } /* Put the index strings in the list widget */ XtVaSetValues(wHelpTopicList, XtNlist, pstrIndexCStrings, XtNnumberStrings, iNumHelpTopics, NULL); } /************************************************************************ * FUNCTION: * HISTORY: * 04.01.94 ESF Created * PURPOSE: * NOTES: ************************************************************************/ void HELP_IndexPopupHelp(Int32 iTopic) { if (iTopic<0 || iTopic>=iNumHelpTopics) { UTIL_PopupDialog("Warning", "HELP: Topic not available!", 1, "Ok", NULL, NULL); return; } XtVaSetValues(wHelpLabel, XtNlabel, pstrIndexCStrings[iTopic], NULL); XtVaSetValues(wHelpText, XtNstring, pstrHelpCStrings[iTopic], NULL); } /************************************************************************ * FUNCTION: * HISTORY: * 04.01.94 ESF Created * PURPOSE: * NOTES: ************************************************************************/ void HELP_CStringPopupHelp(CString strTopic) { UNUSED(strTopic); D_Assert(FALSE, "Not implemented!"); } xfrisk-1.2/help.h0100644000175000017500000000206507013357407013011 0ustar johnojohno/* * XFrisk - The classic board game for X * Copyright (C) 1993-1999 Elan Feingold (elan@aetherworks.com) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * $Id: help.h,v 1.3 1999/11/13 21:58:31 morphy Exp $ */ #ifndef _HELP #define _HELP void HELP_Init(CString strHelpFile); void HELP_IndexPopupHelp(Int32 iTopic); void HELP_CStringPopupHelp(CString strTopic); #endif xfrisk-1.2/language.h0100644000175000017500000002341007040702715013635 0ustar johnojohno/* * XFrisk - The classic board game for X * Copyright (C) 1993-1999 Elan Feingold (elan@aetherworks.com) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * $Id: language.h,v 1.13 2000/01/17 21:12:45 tony Exp $ */ #ifndef _LANGUAGE_H #define _LANGUAGE_H #ifdef FRENCH #define HUMAN "Humain" #define UNKNOWN "Un inconnu" #define PINK_CREATURE "Créature rose et chevelue avec tendences auto-destructives." //countries #define NORTH_AMERICA "Amérique du nord" #define SOUTH_AMERICA "Amérique du sud" #define AFRICA "Afrique" #define AUSTRALIA "Australie" #define EUROPE "Europe" #define GREENLAND "Groenland" #define ICELAND "Islande" #define SIBERIA "Sibérie" #define URAL "Oural" #define ALASKA "Alaska" #define NORTHWEST "Territoires du nord-ouest" #define IRKUTSK "Irkutsk" #define SCANDINAVIA "Scandinavie" #define UKRAINE "Ukraine" #define KAMCHATKA "Kamchatka" #define QUEBEC "Québec" #define ONTARIO "Ontario" #define ALBERTA "Alberta" #define YAKUTSK "Yakutsk" #define GREAT_BRITAIN "Grande Bretagne" #define AFGHANISTAN "Afghanistan" #define NORTHERN_EUROPE "Europe du nord" #define WEST_STATES "Ouest des États-unis " #define EAST_STATES "Est des États-unis " #define WEST_EUROPE "Europe de l'ouest" #define SOUTH_EUROPE "Europe du sud" #define MONGOLIA "Mongolie" #define CHINA "Chine" #define JAPAN "Japon" #define MIDDLE_EAST "Moyen-Orient" #define CENTRAL_AMERICA "Amérique central" #define NORTH_AFRICA "Afrique du nord" #define EGYPT "Egypte" #define INDIA "Inde" #define SIAM "Siam" #define EAST_AFRICA "Afrique de l'est" #define INDONESIA "Indonésie" #define VENEZUELA "Vénézuéla" #define BRASIL "Brésil" #define PERU "Pérou" #define CONGO "Congo" #define NEW_GUINEA "Nouvelle Guinée" #define SOUTH_AFRICA "Afrique du sud" #define WESTERN_AUSTRALIA "Australie occidentale" #define EASTERN_AUSTRALIA "Est de l'australie" #define MADAGASCAR "Madagascar" #define ARGENTINA "Argentine" //messages #define CLIENT_MISMATCH "Mauvaise version de client" #define NEW_CLIENT "Un nouveau client" #define HAS_REGISTERED "est enregistré." #define NO_ROOM "Plus de place pour un nouveau client!" #define ERROR_PROTOCOL "Erreur de protocol" #define IGNORE_CLIENT "Ignore ce client." #define SERVER_CONNECT_FAILED "Une connexion échoue, le client est perdu..." #define GAME_OVER "Le jeu est terminé: un joueur vivant (ou un client complet) quitte le jeu." #define SERVER_STARTING "Démarage de Frisk" #define FINISHED_REGISTRY "a fini d'enregistrer ses joueurs." #define HAS_DEREGISTERED "%s a quitté." #define SERVERNAME "Serveur" #define CLIENT_DEAD "est considéré comme mort (il a émis un mauvais message.)\n" #define CLIENT "Le client" #define SERVER_STARTING "SERVEUR: Démarage de Frisk" #define ERR_PORT_IN_USE "SERVEUR: Le port de Frisk est utilisé. Le serveur est\n déjà lancé, ou un serveur est salement planté,\n dans ce cas il faut attendre quelques minutes pour\n que le port soit à nouveau disponible. Je quitte.\n" #define CLIENT "Le client" #define IS_REGISTERED "est enregistré." #define NEW_AI "Un nouveau client AI" #define HELLO_NEW "Bonjour nouveau client, vous êtes" #define BEING_UPDATED "va être mis à jour." #define BEGINNING "Les clients ont fini de s'enregistrer, le jeu commence." #define ERR_COMMLINK "CLIENT: Ne peut créer la liaison." #define ERR_UNKNOWN_HOST "CLIENT: La machine `%s' est inconnue." #define ERR_COULD_NOT_CONNECT "CLIENT: Impossible de se connecter au serveur Frisk sur `%s'.\n"\ " Quelqu'un doit commencer par lancer `friskserver' \n"\ " sur cette machine.\n" #define MSG_CONNECTED "CLIENT: Connecté au serveur.\n" #define MSG_WAITING_SRV_ID "CLIENT: Attend que le serveur émette l'ID client..." #define MSG_DONE "Reçu.\n" #define ERR_SERVER_FULL "CLIENT: Ne peut participer, le serveur est complet! Je suis impressionné..." #define ERR_PROTOCOL_MISMATCH "CLIENT: Le serveur n'utilise pas le même protocole!" #define ERR_SERVER_FAILED "CLIENT: Le server a échoué (%s)\n" #define ERR_NONRECOVERABLE "CLIENT: Impossible de réparer cela, une future version le fera.\n" #define ERR_OBJECT_FAILURE "Échec" #define ERR_SRV_NONRECOVERABLE "Le server a échoué, impossible de réparer." #define INVALID_MESSAGE "Le serveur a reçu un message invalide de ma part." #define ERR_COMMFAILED "SERVEUR: CommLink operation échoue, recupère.\n" #define TXT_HANDLED_FAILURE "SERVEUR: Récupération correcte de la perte d'un client.\n" #define TXT_SEND_FAILED "Échec à l'émission d'un message." #define TXT_RECEIVE_FAILED "Échec à la réception d'un message." #define TXT_CANT_OPEN "CARDS: Ne peut ouvrir" #define TXT_CARDS_NUMCOUNTRIES "CARDS: Nombre de pays invalide!" #define TXT_FATAL_ERROR "Erreur fatale" #define TXT_ONLY_CURRENT "Seul le joueur courant peut échanger des cartes!" #define TXT_BE_FORTIFIED "va être fortifié" #else /* ENGLISH is default language*/ #define HUMAN "Human" #define UNKNOWN "Unknown" #define PINK_CREATURE "Hairless pink creature with self-destructive tendencies." /*countries*/ #define NORTH_AMERICA "North America" #define SOUTH_AMERICA "South America" #define AFRICA "Africa" #define AUSTRALIA "Australia" #define ASIA "Asia" #define EUROPE "Europe" #define GREENLAND "Greenland" #define ICELAND "Iceland" #define SIBERIA "Siberia" #define URAL "Ural" #define ALASKA "Alaska" #define NORTH_WEST "Northwest Territories" #define IRKUTSK "Irkutsk" #define SCANDINAVIA "Scandinavia" #define UKRAINE "Ukraine" #define KAMCHATKA "Kamchatka" #define QUEBEC "Quebec" #define ONTARIO "Ontario" #define ALBERTA "Alberta" #define YAKUTSK "Yakutsk" #define GREAT_BRITAIN "Great Britain" #define AFGHANISTAN "Afghanistan" #define NORTHERN_EUROPE "Northern Europe" #define WEST_STATES "Western United States" #define EAST_STATES "Eastern United States" #define WEST_EUROPE "Western Europe" #define SOUTH_EUROPE "Southern Europe" #define MONGOLIA "Mongolia" #define CHINA "China" #define JAPAN "Japan" #define MIDDLE_EAST "Middle East" #define CENTRAL_AMERICA "Central America" #define NORTH_AFRICA "Northern Africa" #define EGYPT "Egypt" #define INDIA "India" #define SIAM "Siam" #define EAST_AFRICA "Eastern Africa" #define INDONESIA "Indonesia" #define VENEZUELA "Venezuela" #define BRASIL "Brazil" #define PERU "Peru" #define CONGO "Congo" #define NEW_GUINEA "New Guinea" #define SOUTH_AFRICA "South Africa" #define WESTERN_AUSTRALIA "Western Australia" #define EASTERN_AUSTRALIA "Eastern Australia" #define MADAGASCAR "Madagascar" #define ARGENTINA "Argentina" /*messages*/ #define HELLO_NEW "Hello new client, you are" #define BEGINNING "Clients have finished registering, beginning game." #define SERVERNAME "Server" #define BEING_UPDATED "is being updated." #define NEW_CLIENT "A new client" #define NEW_AI "A new AI client" #define CLIENT "The client" #define IS_REGISTERED "is registered" #define CLIENT_MISMATCH "Client version mismatch" #define ERROR_PROTOCOL "Error in protocol" #define IGNORE_CLIENT "Ignoring wanna-be client." #define SERVER_STARTING "Starting Frisk" #define HAS_DEREGISTERED "has deregistered." #define HAS_REGISTERED "has registered" #define NO_ROOM "Unable to allocate room for new client!" #define GAME_OVER "The game is over: a live player (or an entire client) left the game" #define FINISHED_REGISTRY "has finished registering players." /*lame, but the next two belong together :-)*/ #define CLIENT_DEAD "considered dead (it sent a bogus message.)\n" #define ERR_PORT_IN_USE " is already in use. Perhaps a\n server is already running, or else a server crashed\n badly, in which case you will probably have to wait\n a few minutes till the port clears. I'm exiting.\n" #define SERVER_CONNECT_FAILED "Connect to client failed, it's lost." #define ERR_COMMLINK "CLIENT: Cannot create CommLink." #define ERR_UNKNOWN_HOST "CLIENT: The host `%s' is unknown." #define ERR_COULD_NOT_CONNECT "CLIENT: Cannot connect to a Frisk server on `%s'.\n"\ " One probably needs to be started by running\n"\ " `friskserver' on the machine.\n" #define MSG_CONNECTED "CLIENT: Connected to server.\n" #define MSG_WAITING_SRV_ID "CLIENT: Waiting for server to send client ID..." #define MSG_DONE "Done.\n" #define ERR_SERVER_FULL "CLIENT: Can't join, server is full! I'm impressed..." #define ERR_PROTOCOL_MISMATCH "CLIENT: Server is not following protocol!" #define ERR_SERVER_FAILED "CLIENT: The server has failed (%s)\n" #define ERR_NONRECOVERABLE "CLIENT: Cannot recover from this, future version will.\n" #define ERR_OBJECT_FAILURE "Object Failure" #define ERR_SRV_NONRECOVERABLE "The server has failed, cannot recover." #define INVALID_MESSAGE "The server received an invalid message from me." #define ERR_COMMFAILED "SERVER: CommLink operation failed, recovering.\n" #define TXT_HANDLED_FAILURE "SERVER: Successfully handled client failure.\n" #define TXT_SEND_FAILED "SendMessage failed." #define TXT_RECEIVE_FAILED "ReceiveMessage failed." #define TXT_CANT_OPEN "CARDS: Cannot open" #define TXT_CARDS_NUMCOUNTRIES "CARDS: Wrong number of countries!" #define TXT_FATAL_ERROR "Fatal Error" #define TXT_ONLY_CURRENT "Only the current player may exchange cards!" #define TXT_BE_FORTIFIED "will be fortified" #endif #endif xfrisk-1.2/network.c0100644000175000017500000010726507031427341013550 0ustar johnojohno/* * XFrisk - The classic board game for X * Copyright (C) 1993-1999 Elan Feingold (elan@aetherworks.com) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * $Id: network.c,v 1.6 1999/12/26 15:06:09 morphy Exp $ * * $Log: network.c,v $ * Revision 1.6 1999/12/26 15:06:09 morphy * Doxygen comments * Added static qualifier to local functions * Miscellaneous editorial changes * */ /** * Messaging interface to/from the network. */ #include #include #include #include #include #include #include #include #include "riskgame.h" #include "types.h" #include "network.h" #include "debug.h" /* Useful macro */ #define ReturnIfError(foo) if ((foo) <= 0) return (-1); /* Local prototypes */ static Int32 _NET_SendString(Int32 iSocket, CString strCString); static Int32 _NET_SendLong(Int32 iSocket, Int32 iLong); static Int32 _NET_RecvString(Int32 iSocket, CString *pstrCString); static Int32 _NET_SocketRead(Int32 iSocket, void *ptr, Int32 iNumBytes); static Int32 _NET_SocketWrite(Int32 iSocket, void *ptr, Int32 iNumBytes); static Int32 _NET_RecvLong(Int32 iSocket, Int32 *piLong); /* Private to this routine */ static char strLogging[1024]; /** * Send a message to the given socket, field by field. * * \bug void pointer * \bug massive switch - case construct * * \b History: * \arg 01.24.94 ESF Created * \arg 01.28.94 ESF Added strFrom in MSG_MESSAGEPACKET. * \arg 03.04.94 ESF Changed MSG_UPDATE mesage. * \arg 03.05.94 ESF Added MSG_ENTERSTATE for fault tolerance. * \arg 03.28.94 ESF Added MSG_DEADPLAYER & MSG_ENDOFGAME. * \arg 03.28.94 ESF Changed MSG_REQUESTCARDS to ...CARD. * \arg 03.29.94 ESF Changed MSG_UPDATECARDS to MSG_EXCHANGECARDS. * \arg 03.29.94 ESF Changed uiReply to be an Int32. * \arg 04.11.94 ESF Added a player parameter to MSG_CARDPACKET. * \arg 04.11.94 ESF Added a killer paramter to MSG_DEADPLAYER. * \arg 05.03.94 ESF Added MSG_OBJ*UPDATE msgs. * \arg 05.03.94 ESF Removed MSG_REGISTERPLAYER and MSG_UPDATEARMIES. * \arg 05.05.94 ESF Added MSG_OBJ* msgs. * \arg 05.12.94 ESF Removed MSG_OBJ* msgs and added GAME messages. * \arg 05.12.94 ESF Added MSG_DEREGISTERCLIENT. * \arg 05.12.94 ESF Added MSG_DELETEMSGDST. * \arg 05.13.94 ESF Added MSG_STARTREGISTRATION. * \arg 05.15.94 ESF Added MSG_[FREE|ALLOC]PLAYER * \arg 05.15.94 ESF Removed MSG_DEADPLAYER. * \arg 05.17.94 ESF Added MSG_NETMESSAGE. * \arg 07.27.94 ESF Removed MSG_STARTREGISTRATION. * \arg 07.31.94 ESF Added MSG_NETPOPUP. * \arg 08.03.94 ESF Fixed to return error message. * \arg 08.28.94 ESF Added MSG_POPUPREGISTERBOX. * \arg 09.31.94 ESF Changed MSG_ENDOFGAME to take a string parameter. * \arg 10.29.94 ESF Added MSG_DICEROLL. * \arg 10.30.94 ESF Added MSG_PLACENOTIFY. * \arg 10.30.94 ESF Added MSG_ATTACKNOTIFY. * \arg 10.30.94 ESF Added MSG_MOVENOTIFY. * \arg 01.17.95 ESF Removed MSG_DELETEMSGDST. * \arg 02.21.95 ESF Added MSG_HELLO, MSG_VERSION. * \arg 02.21.95 ESF Modified MSG_REGISTERCLIENT to include type of client. * \arg 02.23.95 ESF Added MSG_OLDREGISTERCLIENT for backwards compatibility. * \arg 02.23.95 ESF Added MSG_SPECIESIDENT. * \arg 24.08.95 JC Added MSG_MISSION. * \arg 28.08.95 JC Added MSG_ENDOFMISSION and MSG_VICTORY. * \arg 30.08.95 JC Added MSG_FORCEEXCHANGECARDS. */ Int32 NET_SendMessage(Int32 iSocket, Int32 iMessType, void *pvMessage) { Int32 i; /* Send the message ID */ ReturnIfError(_NET_SendLong(iSocket, (Int32)iMessType)); switch(iMessType) { case MSG_OLDREGISTERCLIENT: { MsgOldRegisterClient *pmsgMess = (MsgOldRegisterClient *)pvMessage; ReturnIfError(_NET_SendString(iSocket, pmsgMess->strClientAddress)); } break; case MSG_REGISTERCLIENT: { MsgRegisterClient *pmsgMess = (MsgRegisterClient *)pvMessage; ReturnIfError(_NET_SendString(iSocket, pmsgMess->strClientAddress)); ReturnIfError(_NET_SendLong(iSocket, pmsgMess->iClientType)); } break; case MSG_EXCHANGECARDS: { MsgExchangeCards *pmsgMess = (MsgExchangeCards *)pvMessage; for(i=0; i!=3; i++) ReturnIfError(_NET_SendLong(iSocket, (Int32)pmsgMess->piCards[i])); } break; case MSG_CARDPACKET: { MsgCardPacket *pmsgMess = (MsgCardPacket *)pvMessage; ReturnIfError(_NET_SendLong(iSocket, (Int32)pmsgMess->iPlayer)); ReturnIfError(_NET_SendLong(iSocket, (Int32)pmsgMess->cdCard)); } break; case MSG_REPLYPACKET: { MsgReplyPacket *pmsgMess = (MsgReplyPacket *)pvMessage; ReturnIfError(_NET_SendLong(iSocket, (Int32)pmsgMess->iReply)); } break; case MSG_SENDMESSAGE: { MsgSendMessage *pmsgMess = (MsgSendMessage *)pvMessage; ReturnIfError(_NET_SendString(iSocket, pmsgMess->strMessage)); ReturnIfError(_NET_SendString(iSocket, pmsgMess->strDestination)); } break; case MSG_MESSAGEPACKET: { MsgMessagePacket *pmsgMess = (MsgMessagePacket *)pvMessage; ReturnIfError(_NET_SendString(iSocket, pmsgMess->strMessage)); ReturnIfError(_NET_SendLong(iSocket, pmsgMess->iFrom)); ReturnIfError(_NET_SendLong(iSocket, pmsgMess->iTo)); } break; case MSG_TURNNOTIFY: { MsgTurnNotify *pmsgMess = (MsgTurnNotify *)pvMessage; ReturnIfError(_NET_SendLong(iSocket, pmsgMess->iPlayer)); ReturnIfError(_NET_SendLong(iSocket, pmsgMess->iClient)); } break; case MSG_CLIENTIDENT: { MsgClientIdent *pmsgMess = (MsgClientIdent *)pvMessage; ReturnIfError(_NET_SendLong(iSocket, pmsgMess->iClientID)); } break; case MSG_REQUESTCARD: { MsgRequestCard *pmsgMess = (MsgRequestCard *)pvMessage; ReturnIfError(_NET_SendLong(iSocket, pmsgMess->iPlayer)); } break; case MSG_ENTERSTATE: { MsgEnterState *pmsgMess = (MsgEnterState *)pvMessage; ReturnIfError(_NET_SendLong(iSocket, pmsgMess->iState)); } break; case MSG_OBJSTRUPDATE: { MsgObjStrUpdate *pmsgMess = (MsgObjStrUpdate *)pvMessage; ReturnIfError(_NET_SendLong(iSocket, pmsgMess->iField)); ReturnIfError(_NET_SendLong(iSocket, pmsgMess->iIndex1)); ReturnIfError(_NET_SendLong(iSocket, pmsgMess->iIndex2)); ReturnIfError(_NET_SendString(iSocket, pmsgMess->strNewValue)); } break; case MSG_OBJINTUPDATE: { MsgObjIntUpdate *pmsgMess = (MsgObjIntUpdate *)pvMessage; ReturnIfError(_NET_SendLong(iSocket, pmsgMess->iField)); ReturnIfError(_NET_SendLong(iSocket, pmsgMess->iIndex1)); ReturnIfError(_NET_SendLong(iSocket, pmsgMess->iIndex2)); ReturnIfError(_NET_SendLong(iSocket, pmsgMess->iNewValue)); } break; case MSG_FREEPLAYER: { MsgFreePlayer *pmsgMess = (MsgFreePlayer *)pvMessage; ReturnIfError(_NET_SendLong(iSocket, pmsgMess->iPlayer)); } break; /* These happen to be identical, so we can lump them. */ case MSG_NETMESSAGE: case MSG_NETPOPUP: { MsgNetMessage *pmsgMess = (MsgNetMessage *)pvMessage; ReturnIfError(_NET_SendString(iSocket, pmsgMess->strMessage)); } break; case MSG_ENDOFMISSION: { MsgEndOfMission *pmsgMess = (MsgEndOfMission *)pvMessage; ReturnIfError(_NET_SendLong(iSocket, pmsgMess->iWinner)); ReturnIfError(_NET_SendLong(iSocket, pmsgMess->iTyp)); ReturnIfError(_NET_SendLong(iSocket, pmsgMess->iNum1)); ReturnIfError(_NET_SendLong(iSocket, pmsgMess->iNum2)); } break; case MSG_VICTORY: { MsgVictory *pmsgMess = (MsgVictory *)pvMessage; ReturnIfError(_NET_SendLong(iSocket, pmsgMess->iWinner)); } break; case MSG_DICEROLL: { MsgDiceRoll *pmsgMess = (MsgDiceRoll *)pvMessage; for (i=0; i!=3; i++) ReturnIfError(_NET_SendLong(iSocket, pmsgMess->pAttackDice[i])); for (i=0; i!=3; i++) ReturnIfError(_NET_SendLong(iSocket, pmsgMess->pDefendDice[i])); ReturnIfError(_NET_SendLong(iSocket, pmsgMess->iDefendingPlayer)); } break; case MSG_PLACENOTIFY: { MsgPlaceNotify *pmsgMess = (MsgPlaceNotify *)pvMessage; ReturnIfError(_NET_SendLong(iSocket, pmsgMess->iCountry)); } break; case MSG_ATTACKNOTIFY: { MsgAttackNotify *pmsgMess = (MsgAttackNotify *)pvMessage; ReturnIfError(_NET_SendLong(iSocket, pmsgMess->iSrcCountry)); ReturnIfError(_NET_SendLong(iSocket, pmsgMess->iDstCountry)); } break; case MSG_MOVENOTIFY: { MsgMoveNotify *pmsgMess = (MsgMoveNotify *)pvMessage; ReturnIfError(_NET_SendLong(iSocket, pmsgMess->iSrcCountry)); ReturnIfError(_NET_SendLong(iSocket, pmsgMess->iDstCountry)); } break; case MSG_VERSION: { MsgVersion *pmsgMess = (MsgVersion *)pvMessage; ReturnIfError(_NET_SendString(iSocket, pmsgMess->strVersion)); } break; case MSG_SPECIESIDENT: { MsgSpeciesIdent *pmsgMess = (MsgSpeciesIdent *)pvMessage; ReturnIfError(_NET_SendLong(iSocket, pmsgMess->iSpeciesID)); } break; case MSG_FORCEEXCHANGECARDS: { MsgForceExchangeCards *pmsgMess = (MsgForceExchangeCards *)pvMessage; ReturnIfError(_NET_SendLong(iSocket, pmsgMess->iPlayer)); } case MSG_EXIT: case MSG_STARTGAME: case MSG_ENDTURN: case MSG_DEREGISTERCLIENT: case MSG_ALLOCPLAYER: case MSG_POPUPREGISTERBOX: case MSG_HELLO: case MSG_MISSION: case MSG_ENDOFGAME: /* No parameters */ break; default: printf("NETWORK: Illegal message!\n"); } return (1); } /** * Receive one message from the network, field by field. * * \bug pointer to void pointer * \bug massive switch - case construct * * \b History: * \arg 01.24.94 ESF Created. * \arg 01.27.94 ESF Fixed bug in MSG_MESSAGEPACKET case. * \arg 01.28.94 ESF Added strFrom in MSG_MESSAGEPACKET. * \arg 03.04.94 ESF Changed _UPDATE mesage. * \arg 03.05.94 ESF Added _ENTERSTATE for fault tolerance. * \arg 03.28.94 ESF Added MSG_DEADPLAYER & MSG_ENDOFGAME. * \arg 03.28.94 ESF Changed MSG_REQUESTCARDS to ...CARD. * \arg 03.29.94 ESF Changed MSG_UPDATECARDS to MSG_EXCHANGECARDS. * \arg 03.29.94 ESF Changed uiReply to be an Int32. * \arg 04.11.94 ESF Added a player parameter to MSG_CARDPACKET. * \arg 04.11.94 ESF Added a killer paramter to MSG_DEADPLAYER. * \arg 05.03.94 ESF Added MSG_OBJ*UPDATE msgs. * \arg 05.03.94 ESF Removed MSG_REGISTERPLAYER and MSG_UPDATEARMIES. * \arg 05.05.94 ESF Added MSG_OBJ* msgs. * \arg 05.12.94 ESF Removed MSG_OBJ* msgs and added GAME messages. * \arg 05.12.94 ESF Added MSG_DEREGISTERCLIENT. * \arg 05.12.94 ESF Added MSG_DELETEMSGDST. * \arg 05.13.94 ESF Added MSG_STARTREGISTRATION. * \arg 05.15.94 ESF Added MSG_[FREE|ALLOC]PLAYER * \arg 05.15.94 ESF Removed MSG_DEADPLAYER. * \arg 05.17.94 ESF Added MSG_NETMESSAGE. * \arg 07.27.94 ESF Removed MSG_STARTREGISTRATION. * \arg 07.31.94 ESF Added MSG_NETPOPUP. * \arg 08.03.94 ESF Fixed to return error message. * \arg 08.28.94 ESF Added MSG_POPUPREGISTERBOX. * \arg 09.31.94 ESF Changed MSG_ENDOFGAME to take a string parameter. * \arg 10.29.94 ESF Added MSG_DICEROLL. * \arg 10.30.94 ESF Added MSG_PLACENOTIFY. * \arg 10.30.94 ESF Added MSG_ATTACKNOTIFY. * \arg 10.30.94 ESF Added MSG_MOVENOTIFY. * \arg 01.17.95 ESF Removed MSG_DELETEMSGDST. * \arg 02.21.95 ESF Added MSG_HELLO, MSG_VERSION. * \arg 02.21.95 ESF Modified MSG_REGISTERCLIENT to include type of client. * \arg 02.23.95 ESF Added MSG_OLDREGISTERCLIENT. * \arg 02.23.95 ESF Added MSG_SPECIESIDENT. * \arg 24.08.95 JC Added MSG_MISSION. * \arg 28.08.95 JC Added MSG_ENDOFMISSION and MSG_VICTORY. * \arg 30.08.95 JC Added MSG_FORCEEXCHANGECARDS. */ Int32 NET_RecvMessage(Int32 iSocket, Int32 *piMessType, void **ppvMessage) { Int32 i; /* Get the message ID */ ReturnIfError(_NET_RecvLong(iSocket, (Int32 *)piMessType)); switch(*piMessType) { case MSG_OLDREGISTERCLIENT: { MsgOldRegisterClient *pmsgMess = (MsgOldRegisterClient *)MEM_Alloc(sizeof(MsgOldRegisterClient)); ReturnIfError(_NET_RecvString(iSocket, &pmsgMess->strClientAddress)); *ppvMessage = (void *)pmsgMess; } break; case MSG_REGISTERCLIENT: { MsgRegisterClient *pmsgMess = (MsgRegisterClient *)MEM_Alloc(sizeof(MsgRegisterClient)); ReturnIfError(_NET_RecvString(iSocket, &pmsgMess->strClientAddress)); ReturnIfError(_NET_RecvLong(iSocket, &pmsgMess->iClientType)); *ppvMessage = (void *)pmsgMess; } break; case MSG_EXCHANGECARDS: { MsgExchangeCards *pmsgMess = (MsgExchangeCards *)MEM_Alloc(sizeof(MsgExchangeCards)); for(i=0; i!=3; i++) ReturnIfError(_NET_RecvLong(iSocket, (Int32 *)&pmsgMess->piCards[i])); *ppvMessage = (void *)pmsgMess; } break; case MSG_CARDPACKET: { MsgCardPacket *pmsgMess = (MsgCardPacket *)MEM_Alloc(sizeof(MsgCardPacket)); ReturnIfError(_NET_RecvLong(iSocket, (Int32 *)&pmsgMess->iPlayer)); ReturnIfError(_NET_RecvLong(iSocket, (Int32 *)&pmsgMess->cdCard)); *ppvMessage = (void *)pmsgMess; } break; case MSG_REPLYPACKET: { MsgReplyPacket *pmsgMess = (MsgReplyPacket *)MEM_Alloc(sizeof(MsgReplyPacket)); ReturnIfError(_NET_RecvLong(iSocket, (Int32 *)&pmsgMess->iReply)); *ppvMessage = (void *)pmsgMess; } break; case MSG_SENDMESSAGE: { MsgSendMessage *pmsgMess = (MsgSendMessage *)MEM_Alloc(sizeof(MsgSendMessage)); ReturnIfError(_NET_RecvString(iSocket, &pmsgMess->strMessage)); ReturnIfError(_NET_RecvString(iSocket, &pmsgMess->strDestination)); *ppvMessage = (void *)pmsgMess; } break; case MSG_MESSAGEPACKET: { MsgMessagePacket *pmsgMess = (MsgMessagePacket *)MEM_Alloc(sizeof(MsgMessagePacket)); ReturnIfError(_NET_RecvString(iSocket, &pmsgMess->strMessage)); ReturnIfError(_NET_RecvLong(iSocket, &pmsgMess->iFrom)); ReturnIfError(_NET_RecvLong(iSocket, &pmsgMess->iTo)); *ppvMessage = (void *)pmsgMess; } break; case MSG_TURNNOTIFY: { MsgTurnNotify *pmsgMess = (MsgTurnNotify *)MEM_Alloc(sizeof(MsgTurnNotify)); ReturnIfError(_NET_RecvLong(iSocket, &pmsgMess->iPlayer)); ReturnIfError(_NET_RecvLong(iSocket, &pmsgMess->iClient)); *ppvMessage = (void *)pmsgMess; } break; case MSG_CLIENTIDENT: { MsgClientIdent *pmsgMess = (MsgClientIdent *)MEM_Alloc(sizeof(MsgClientIdent)); ReturnIfError(_NET_RecvLong(iSocket, &pmsgMess->iClientID)); *ppvMessage = (void *)pmsgMess; } break; case MSG_REQUESTCARD: { MsgRequestCard *pmsgMess = (MsgRequestCard *)MEM_Alloc(sizeof(MsgRequestCard)); ReturnIfError(_NET_RecvLong(iSocket, &pmsgMess->iPlayer)); *ppvMessage = (void *)pmsgMess; } break; case MSG_ENTERSTATE: { MsgEnterState *pmsgMess = (MsgEnterState *)MEM_Alloc(sizeof(MsgEnterState)); ReturnIfError(_NET_RecvLong(iSocket, &pmsgMess->iState)); *ppvMessage = (void *)pmsgMess; } break; case MSG_OBJSTRUPDATE: { MsgObjStrUpdate *pmsgMess = (MsgObjStrUpdate *)MEM_Alloc(sizeof(MsgObjStrUpdate)); ReturnIfError(_NET_RecvLong(iSocket, &pmsgMess->iField)); ReturnIfError(_NET_RecvLong(iSocket, &pmsgMess->iIndex1)); ReturnIfError(_NET_RecvLong(iSocket, &pmsgMess->iIndex2)); ReturnIfError(_NET_RecvString(iSocket, &pmsgMess->strNewValue)); *ppvMessage = (void *)pmsgMess; } break; case MSG_OBJINTUPDATE: { MsgObjIntUpdate *pmsgMess = (MsgObjIntUpdate *)MEM_Alloc(sizeof(MsgObjIntUpdate)); ReturnIfError(_NET_RecvLong(iSocket, &pmsgMess->iField)); ReturnIfError(_NET_RecvLong(iSocket, &pmsgMess->iIndex1)); ReturnIfError(_NET_RecvLong(iSocket, &pmsgMess->iIndex2)); ReturnIfError(_NET_RecvLong(iSocket, &pmsgMess->iNewValue)); *ppvMessage = (void *)pmsgMess; } break; case MSG_FREEPLAYER: { MsgFreePlayer *pmsgMess = (MsgFreePlayer *)MEM_Alloc(sizeof(MsgFreePlayer)); ReturnIfError(_NET_RecvLong(iSocket, &pmsgMess->iPlayer)); *ppvMessage = (void *)pmsgMess; } break; /* These happen to be identical, so we can lump them. */ case MSG_NETMESSAGE: case MSG_NETPOPUP: { MsgNetMessage *pmsgMess = (MsgNetMessage *)MEM_Alloc(sizeof(MsgNetMessage)); ReturnIfError(_NET_RecvString(iSocket, &pmsgMess->strMessage)); *ppvMessage = (void *)pmsgMess; } break; case MSG_ENDOFMISSION: { MsgEndOfMission *pmsgMess = (MsgEndOfMission *)MEM_Alloc(sizeof(MsgEndOfMission)); ReturnIfError(_NET_RecvLong(iSocket, &pmsgMess->iWinner)); ReturnIfError(_NET_RecvLong(iSocket, &pmsgMess->iTyp)); ReturnIfError(_NET_RecvLong(iSocket, &pmsgMess->iNum1)); ReturnIfError(_NET_RecvLong(iSocket, &pmsgMess->iNum2)); *ppvMessage = (void *)pmsgMess; } break; case MSG_VICTORY: { MsgVictory *pmsgMess = (MsgVictory *)MEM_Alloc(sizeof(MsgVictory)); ReturnIfError(_NET_RecvLong(iSocket, &pmsgMess->iWinner)); *ppvMessage = (void *)pmsgMess; } break; case MSG_DICEROLL: { MsgDiceRoll *pmsgMess = (MsgDiceRoll *)MEM_Alloc(sizeof(MsgDiceRoll)); for (i=0; i!=3; i++) ReturnIfError(_NET_RecvLong(iSocket, &pmsgMess->pAttackDice[i])); for (i=0; i!=3; i++) ReturnIfError(_NET_RecvLong(iSocket, &pmsgMess->pDefendDice[i])); ReturnIfError(_NET_RecvLong(iSocket, &pmsgMess->iDefendingPlayer)); *ppvMessage = (void *)pmsgMess; } break; case MSG_PLACENOTIFY: { MsgPlaceNotify *pmsgMess = (MsgPlaceNotify *)MEM_Alloc(sizeof(MsgPlaceNotify)); ReturnIfError(_NET_RecvLong(iSocket, &pmsgMess->iCountry)); *ppvMessage = (void *)pmsgMess; } break; case MSG_ATTACKNOTIFY: { MsgAttackNotify *pmsgMess = (MsgAttackNotify *)MEM_Alloc(sizeof(MsgAttackNotify)); ReturnIfError(_NET_RecvLong(iSocket, &pmsgMess->iSrcCountry)); ReturnIfError(_NET_RecvLong(iSocket, &pmsgMess->iDstCountry)); *ppvMessage = (void *)pmsgMess; } break; case MSG_MOVENOTIFY: { MsgMoveNotify *pmsgMess = (MsgMoveNotify *)MEM_Alloc(sizeof(MsgMoveNotify)); ReturnIfError(_NET_RecvLong(iSocket, &pmsgMess->iSrcCountry)); ReturnIfError(_NET_RecvLong(iSocket, &pmsgMess->iDstCountry)); *ppvMessage = (void *)pmsgMess; } break; case MSG_VERSION: { MsgVersion *pmsgMess = (MsgVersion *)MEM_Alloc(sizeof(MsgVersion)); ReturnIfError(_NET_RecvString(iSocket, &pmsgMess->strVersion)); *ppvMessage = (void *)pmsgMess; } break; case MSG_SPECIESIDENT: { MsgSpeciesIdent *pmsgMess = (MsgSpeciesIdent *)MEM_Alloc(sizeof(MsgSpeciesIdent)); ReturnIfError(_NET_RecvLong(iSocket, &pmsgMess->iSpeciesID)); *ppvMessage = (void *)pmsgMess; } break; case MSG_FORCEEXCHANGECARDS: { MsgForceExchangeCards *pmsgMess = (MsgForceExchangeCards *)MEM_Alloc(sizeof(MsgForceExchangeCards)); ReturnIfError(_NET_RecvLong(iSocket, &pmsgMess->iPlayer)); *ppvMessage = (void *)pmsgMess; } break; case MSG_EXIT: case MSG_STARTGAME: case MSG_ENDTURN: case MSG_DEREGISTERCLIENT: case MSG_ALLOCPLAYER: case MSG_POPUPREGISTERBOX: case MSG_HELLO: case MSG_MISSION: case MSG_ENDOFGAME: *ppvMessage = NULL; break; default: printf("NETWORK: Illegal message!\n"); } return (1); } /************************************************************************ * FUNCTION: _NET_SendString * HISTORY: * 01.24.94 ESF Created. * 08.03.94 ESF Fixed to return error message. * 03.22.95 ESF Added handling for NULL strings. * PURPOSE: * NOTES: ************************************************************************/ static Int32 _NET_SendString(Int32 iSocket, CString strCString) { Int32 iLength; /* Send the length and then the string itself */ if (strCString == NULL) iLength = 0; else iLength = strlen(strCString)+1; ReturnIfError(_NET_SendLong(iSocket, (Int32)iLength)); return (_NET_SocketWrite(iSocket, (Char *)strCString, (Int32)iLength)); } /** * Send a long integer to the given socket. * * \b History: * 01.24.94 ESF Created * 08.03.94 ESF Fixed to return error message. */ static Int32 _NET_SendLong(Int32 iSocket, Int32 iLong) { Int32 iData = htonl(iLong); return (_NET_SocketWrite(iSocket, &iData, sizeof(Int32))); } /** * Receive a string from the given socket. First reads the length * (32bit value), then the string data. * * \bug Assumes that a nul terminating byte is in the data stream * * \b History: * \arg 01.24.94 ESF Created * \arg 08.03.94 ESF Fixed to return error message. * \arg 01.01.94 ESF Added check for correct number of bytes read. * \arg 03.22.95 ESF Added handling for NULL strings. */ static Int32 _NET_RecvString(Int32 iSocket, CString *pstrCString) { Int32 iLength; CString strTemp; Int32 iRet; /* Receive the length and then the byte stream */ ReturnIfError(_NET_RecvLong(iSocket, &iLength)); if (iLength) { strTemp = (CString)MEM_Alloc(iLength); iRet = _NET_SocketRead(iSocket, strTemp, iLength); /* Return an error if less than the string was read! */ if (iRet<0 || iRet!=iLength) iRet = -1; } else { iRet = -1; strTemp = NULL; } *pstrCString = strTemp; return iRet; } /** * Reads a 32bit value from the given socket. * * \b History: * \arg 01.24.94 ESF Created * \arg 08.03.94 ESF Fixed to return error message. * \arg 01.01.94 ESF Added check for correct number of bytes read. */ static Int32 _NET_RecvLong(Int32 iSocket, Int32 *piLong) { Int32 iRet = _NET_SocketRead(iSocket, piLong, sizeof(Int32)); /* Adjust for the network munging */ *piLong = ntohl(*piLong); /* Return an error if read returns an error or if the wrong number * of bytes come across -- there should be sizeof(Int32) bytes! */ if (iRet<0 || iRet!=sizeof(Int32)) iRet = -1; return iRet; } /** * Reads the given number of bytes from the given socket. * * \b History: * \arg 01.01.95 ESF Created. * \arg 01.21.95 ESF Fixed non-ANSIness. */ static Int32 _NET_SocketRead(Int32 iSocket, void *ptr, Int32 iNumBytes) { Int32 iBytesLeft, iRet; /* We may have to do multiple read() calls here */ iBytesLeft = iNumBytes; while (iBytesLeft > 0) { iRet = read(iSocket, ptr, iBytesLeft); /* If an error occured, return */ if (iRet < 0) return iRet; else if (iRet == 0) break; /* EOF */ iBytesLeft -= iRet; ptr = (Byte *)ptr + iRet; } /* Return the number of bytes read */ return (iNumBytes - iBytesLeft); } /** * Write the given number of bytes to the given socket. * * \b History: * \arg 01.24.94 ESF Created * \arg 08.03.94 ESF Fixed to return error message. * \arg 01.01.94 ESF Added check for correct number of bytes read. * \arg 01.21.95 ESF Fixed non-ANSIness. */ static Int32 _NET_SocketWrite(Int32 iSocket, void *ptr, Int32 iNumBytes) { Int32 iBytesLeft, iRet; /* We may have to do multiple read() calls here */ iBytesLeft = iNumBytes; while (iBytesLeft > 0) { iRet = write(iSocket, ptr, iBytesLeft); /* If an error occured, return */ if (iRet < 0) return iRet; iBytesLeft -= iRet; ptr = (Byte *)ptr + iRet; } /* Return the number of bytes read */ return (iNumBytes - iBytesLeft); } /** * Free the memory allocated for the given message. * * \b History: * \arg 06.24.94 ESF Created * \arg 07.31.94 ESF Added MSG_NETPOPUP. * \arg 09.31.94 ESF Changed MSG_ENDOFGAME to take a string parameter. * \arg 10.29.94 ESF Added MSG_DICEROLL. * \arg 10.30.94 ESF Added MSG_PLACENOTIFY. * \arg 10.30.94 ESF Added MSG_ATTACKNOTIFY. * \arg 10.30.94 ESF Added MSG_MOVENOTIFY. * \arg 01.17.95 ESF Removed MSG_DELETEMSGDST. * \arg 02.21.95 ESF Added MSG_HELLO, MSG_VERSION. * \arg 02.21.95 ESF Modified MSG_REGISTERCLIENT to include type of client. * \arg 02.23.95 ESF Added MSG_OLDREGISTERCLIENT. * \arg 02.23.95 ESF Added MSG_SPECIESIDENT. * \arg 24.08.95 JC Added MSG_MISSION. * \arg 30.08.95 JC Added MSG_FORCEEXCHANGECARDS. */ void NET_DeleteMessage(Int32 iMessType, void *pvMessage) { switch(iMessType) { case MSG_NOMESSAGE: break; case MSG_OLDREGISTERCLIENT: { MsgOldRegisterClient *pmsgMess = (MsgOldRegisterClient *)pvMessage; MEM_Free(pmsgMess->strClientAddress); MEM_Free(pmsgMess); } break; case MSG_REGISTERCLIENT: { MsgRegisterClient *pmsgMess = (MsgRegisterClient *)pvMessage; MEM_Free(pmsgMess->strClientAddress); MEM_Free(pmsgMess); } break; case MSG_EXCHANGECARDS: MEM_Free(pvMessage); break; case MSG_CARDPACKET: MEM_Free(pvMessage); break; case MSG_REPLYPACKET: MEM_Free(pvMessage); break; case MSG_SENDMESSAGE: { MsgSendMessage *pmsgMess = (MsgSendMessage *)pvMessage; MEM_Free(pmsgMess->strMessage); MEM_Free(pmsgMess->strDestination); MEM_Free(pvMessage); } break; case MSG_MESSAGEPACKET: { MsgMessagePacket *pmsgMess = (MsgMessagePacket *)pvMessage; MEM_Free(pmsgMess->strMessage); MEM_Free(pvMessage); } break; case MSG_TURNNOTIFY: MEM_Free(pvMessage); break; case MSG_CLIENTIDENT: MEM_Free(pvMessage); break; case MSG_REQUESTCARD: MEM_Free(pvMessage); break; case MSG_ENTERSTATE: MEM_Free(pvMessage); break; case MSG_OBJSTRUPDATE: { MsgObjStrUpdate *pmsgMess = (MsgObjStrUpdate*)pvMessage; if (pmsgMess->strNewValue) MEM_Free(pmsgMess->strNewValue); MEM_Free(pvMessage); } break; case MSG_OBJINTUPDATE: MEM_Free(pvMessage); break; case MSG_FREEPLAYER: MEM_Free(pvMessage); break; /* These happen to be identical, so we can lump them. */ case MSG_NETMESSAGE: case MSG_NETPOPUP: { MsgNetMessage *pmsgMess = (MsgNetMessage *)pvMessage; MEM_Free(pmsgMess->strMessage); MEM_Free(pvMessage); } break; case MSG_ENDOFMISSION: MEM_Free(pvMessage); break; case MSG_VICTORY: MEM_Free(pvMessage); break; case MSG_DICEROLL: MEM_Free(pvMessage); break; case MSG_PLACENOTIFY: MEM_Free(pvMessage); break; case MSG_ATTACKNOTIFY: MEM_Free(pvMessage); break; case MSG_MOVENOTIFY: MEM_Free(pvMessage); break; case MSG_VERSION: { MsgVersion *pmsgMess = (MsgVersion *)pvMessage; MEM_Free(pmsgMess->strVersion); MEM_Free(pvMessage); } break; case MSG_SPECIESIDENT: MEM_Free(pvMessage); break; case MSG_FORCEEXCHANGECARDS: MEM_Free(pvMessage); break; case MSG_EXIT: case MSG_STARTGAME: case MSG_ENDTURN: case MSG_DEREGISTERCLIENT: case MSG_ALLOCPLAYER: case MSG_POPUPREGISTERBOX: case MSG_HELLO: case MSG_MISSION: case MSG_ENDOFGAME: /* No parameters */ D_Assert(pvMessage == NULL, "Hum...this shouldn't happen."); break; default: D_Assert(FALSE, "Add case for a new message in NET_DeleteMessage!"); } } /** * Set socket options for better performance. * * \b History: * \arg 01.22.95 ESF Created. * \arg 02.27.95 ESF Added SO_REUSEADDR. * \arg 17.08.95 JC iOption -> &iOption. */ void NET_SetCommLinkOptions(Int32 iSocket) { #ifdef TCP_NODELAY { Int32 iOption = 1; if (setsockopt(iSocket, IPPROTO_TCP, TCP_NODELAY, (char *)&iOption, sizeof(iOption)) != 0) printf("NETWORK: Warning -- couldn't set TCP_NODELAY on CommLink!\n"); } #endif #ifdef SO_REUSEADDR { Int32 iOption = 1; if (setsockopt(iSocket, SOL_SOCKET, SO_REUSEADDR, (char *)&iOption, sizeof(iOption)) != 0) printf("NETWORK: Warning -- couldn't set SO_REUSEADDR on CommLink!\n"); } #endif } /** * Convert the given message to a human readable string for debugging. * * \b History: * \arg 03.19.95 ESF Created. * \arg 24.08.95 JC Added MSG_MISSION. * \arg 30.08.95 JC Added MSG_FORCEEXCHANGECARDS. */ CString NET_MessageToString(Int32 iMessType, void *pvMessage) { switch (iMessType) { case MSG_NOMESSAGE: snprintf(strLogging, sizeof(strLogging), "MsgNoMessage()"); break; case MSG_OLDREGISTERCLIENT: snprintf(strLogging, sizeof(strLogging), "MsgOldRegisterClient(strClientAddress=\"%s\")", ((MsgOldRegisterClient *)pvMessage)->strClientAddress); break; case MSG_REGISTERCLIENT: snprintf(strLogging, sizeof(strLogging), "MsgRegisterClient(strClientAddress=\"%s\"," " iClientType=%s)", ((MsgRegisterClient *)pvMessage)->strClientAddress, ((MsgRegisterClient *)pvMessage)->iClientType == CLIENT_NORMAL ? "CLIENT_NORMAL" : ((MsgRegisterClient *)pvMessage)->iClientType == CLIENT_AI ? "CLIENT_AI" : ((MsgRegisterClient *)pvMessage)->iClientType == CLIENT_STRICTOBSERVER ? "CLIENT_STRICTOBSERVER" : "*Unknown*"); break; case MSG_EXCHANGECARDS: snprintf(strLogging, sizeof(strLogging), "MsgExchangeCards(piCards={%d, %d, %d})", ((MsgExchangeCards *)pvMessage)->piCards[0], ((MsgExchangeCards *)pvMessage)->piCards[1], ((MsgExchangeCards *)pvMessage)->piCards[2]); break; case MSG_CARDPACKET: snprintf(strLogging, sizeof(strLogging), "MsgCardPacket(iPlayer=%d, iCard=%d)", ((MsgCardPacket *)pvMessage)->iPlayer, ((MsgCardPacket *)pvMessage)->cdCard); break; case MSG_REPLYPACKET: snprintf(strLogging, sizeof(strLogging), "MsgReplyPacket(iReply=%d)", ((MsgReplyPacket *)pvMessage)->iReply); break; case MSG_SENDMESSAGE: snprintf(strLogging, sizeof(strLogging), "MsgSendMessage(strMessage=\"%s\", " "strDestination=\"%s\")", ((MsgSendMessage *)pvMessage)->strMessage, ((MsgSendMessage *)pvMessage)->strDestination); break; case MSG_MESSAGEPACKET: snprintf(strLogging, sizeof(strLogging), "MsgMessagePacket(strMessage=\"%s\", " "iFrom=\"%d\", iTo=%d)", ((MsgMessagePacket *)pvMessage)->strMessage, ((MsgMessagePacket *)pvMessage)->iFrom, ((MsgMessagePacket *)pvMessage)->iTo); break; case MSG_TURNNOTIFY: snprintf(strLogging, sizeof(strLogging), "MsgTurnNotify(iPlayer=%d, iClient=%d)", ((MsgTurnNotify *)pvMessage)->iPlayer, ((MsgTurnNotify *)pvMessage)->iClient); break; case MSG_CLIENTIDENT: snprintf(strLogging, sizeof(strLogging), "MsgClientIdent(iClientID=%d)", ((MsgClientIdent *)pvMessage)->iClientID); break; case MSG_REQUESTCARD: snprintf(strLogging, sizeof(strLogging), "MsgRequestCard(iPlayer=%d)", ((MsgRequestCard *)pvMessage)->iPlayer); break; case MSG_ENTERSTATE: snprintf(strLogging, sizeof(strLogging), "MsgEnterState(iState=%d)", ((MsgEnterState *)pvMessage)->iState); break; case MSG_OBJSTRUPDATE: snprintf(strLogging, sizeof(strLogging), "ObjStrUpdate(iField=%d, iIndex=[%d, %d], " "strNewValue=\"%s\")", ((MsgObjStrUpdate *)pvMessage)->iField, ((MsgObjStrUpdate *)pvMessage)->iIndex1, ((MsgObjStrUpdate *)pvMessage)->iIndex2, ((MsgObjStrUpdate *)pvMessage)->strNewValue); break; case MSG_OBJINTUPDATE: snprintf(strLogging, sizeof(strLogging), "ObjIntUpdate(iField=%d, iIndex=[%d, %d], " "iNewValue=%d)", ((MsgObjIntUpdate *)pvMessage)->iField, ((MsgObjIntUpdate *)pvMessage)->iIndex1, ((MsgObjIntUpdate *)pvMessage)->iIndex2, ((MsgObjIntUpdate *)pvMessage)->iNewValue); break; case MSG_FREEPLAYER: snprintf(strLogging, sizeof(strLogging), "MsgFreePlayer(iPlayer=%d)", ((MsgFreePlayer *)pvMessage)->iPlayer); break; case MSG_NETMESSAGE: snprintf(strLogging, sizeof(strLogging), "MsgNetMessage(strMessage=\"%s\")", ((MsgNetMessage *)pvMessage)->strMessage); break; case MSG_NETPOPUP: snprintf(strLogging, sizeof(strLogging), "MsgNetPopup(strMessage=\"%s\")", ((MsgNetPopup *)pvMessage)->strMessage); break; case MSG_ENDOFMISSION: snprintf(strLogging, sizeof(strLogging), "MsgEndOfMission(iWinner=%d, iTyp=%d, iNum1=%d, iNum2=%d)", ((MsgEndOfMission *)pvMessage)->iWinner, ((MsgEndOfMission *)pvMessage)->iTyp, ((MsgEndOfMission *)pvMessage)->iNum1, ((MsgEndOfMission *)pvMessage)->iNum2); break; case MSG_VICTORY: snprintf(strLogging, sizeof(strLogging), "MsgVictory(iWinner=%d)", ((MsgVictory *)pvMessage)->iWinner); break; case MSG_ENDOFGAME: snprintf(strLogging, sizeof(strLogging), "MsgEndOfGame()"); break; case MSG_DICEROLL: snprintf(strLogging, sizeof(strLogging), "MsgDiceRoll(iDefendingPlayer=%d, " "pAttackDice={%d, %d, %d}, pDefendDice={%d, %d, %d})", ((MsgDiceRoll *)pvMessage)->iDefendingPlayer, ((MsgDiceRoll *)pvMessage)->pAttackDice[0], ((MsgDiceRoll *)pvMessage)->pAttackDice[1], ((MsgDiceRoll *)pvMessage)->pAttackDice[2], ((MsgDiceRoll *)pvMessage)->pDefendDice[0], ((MsgDiceRoll *)pvMessage)->pDefendDice[1], ((MsgDiceRoll *)pvMessage)->pDefendDice[2]); break; case MSG_PLACENOTIFY: snprintf(strLogging, sizeof(strLogging), "MsgPlaceNotify(iCountry=%d)", ((MsgPlaceNotify *)pvMessage)->iCountry); break; case MSG_ATTACKNOTIFY: snprintf(strLogging, sizeof(strLogging), "MsgAttackNotify(iSrcCountry=%d, iDstCountry=%d)", ((MsgAttackNotify *)pvMessage)->iSrcCountry, ((MsgAttackNotify *)pvMessage)->iDstCountry); break; case MSG_MOVENOTIFY: snprintf(strLogging, sizeof(strLogging), "MsgMoveNotify(iSrcCountry=%d, iDstCountry=%d)", ((MsgMoveNotify *)pvMessage)->iSrcCountry, ((MsgMoveNotify *)pvMessage)->iDstCountry); break; case MSG_VERSION: snprintf(strLogging, sizeof(strLogging), "MsgVersion(strVersion=\"%s\")", ((MsgVersion *)pvMessage)->strVersion); break; case MSG_SPECIESIDENT: snprintf(strLogging, sizeof(strLogging), "MsgSpeciesIdent(iSpeciesID=%d)", ((MsgSpeciesIdent *)pvMessage)->iSpeciesID); break; case MSG_FORCEEXCHANGECARDS: snprintf(strLogging, sizeof(strLogging), "MsgForceExchangeCards(iPlayer=%d)", ((MsgForceExchangeCards *)pvMessage)->iPlayer); break; case MSG_EXIT: snprintf(strLogging, sizeof(strLogging), "MsgExit()"); break; case MSG_STARTGAME: snprintf(strLogging, sizeof(strLogging), "MsgStartGame()"); break; case MSG_ENDTURN: snprintf(strLogging, sizeof(strLogging), "MsgEndTurn()"); break; case MSG_DEREGISTERCLIENT: snprintf(strLogging, sizeof(strLogging), "MsgDeregisterClient()"); break; case MSG_ALLOCPLAYER: snprintf(strLogging, sizeof(strLogging), "MsgAllocPlayer()"); break; case MSG_POPUPREGISTERBOX: snprintf(strLogging, sizeof(strLogging), "MsgPopupRegisterBox()"); break; case MSG_HELLO: snprintf(strLogging, sizeof(strLogging), "MsgHello()"); break; case MSG_MISSION: snprintf(strLogging, sizeof(strLogging), "MsgMission()"); break; default: D_Assert(FALSE, "Add case to NET_StringToMessage!"); } return strLogging; } /* EOF */ xfrisk-1.2/network.h0100644000175000017500000001221207020020265013530 0ustar johnojohno/* * XFrisk - The classic board game for X * Copyright (C) 1993-1999 Elan Feingold (elan@aetherworks.com) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * $Id: network.h,v 1.4 1999/11/27 18:19:33 tony Exp $ */ #ifndef _NETWORK #define _NETWORK #include #include "types.h" /****************/ /* The Messages */ /****************/ #define MSG_NOMESSAGE 0xDead #define MSG_OLDREGISTERCLIENT 0x01 typedef struct _msgOldRegisterClient { CString strClientAddress; } MsgOldRegisterClient; #define MSG_REGISTERCLIENT 0x99 typedef struct _msgRegisterClient { CString strClientAddress; Int32 iClientType; /* Flags */ } MsgRegisterClient; /* Types of clients to connect */ #define CLIENT_NORMAL 0 #define CLIENT_AI 1 #define CLIENT_STRICTOBSERVER 2 /* TBD, for regression testing */ #define MSG_EXCHANGECARDS 0x03 typedef struct _msgExchangeCards { Int32 piCards[3]; } MsgExchangeCards; #define MSG_REQUESTCARD 0x04 typedef struct _msgRequestCard { Int32 iPlayer; } MsgRequestCard; #define MSG_CARDPACKET 0x05 typedef struct _msgCardPacket { Int32 iPlayer; Int32 cdCard; } MsgCardPacket; #define MSG_REPLYPACKET 0x06 typedef struct _msgReplyPacket { Int32 iReply; } MsgReplyPacket; #define MSG_SENDMESSAGE 0x07 typedef struct _msgSendMessage { CString strMessage; CString strDestination; } MsgSendMessage; #define MSG_MESSAGEPACKET 0x08 typedef struct _msgMessagePacket { CString strMessage; Int32 iFrom; Int32 iTo; } MsgMessagePacket; #define FROM_SERVER -1 #define FROM_UNKNOW -2 #define DST_ALLPLAYERS -1 #define DST_ALLBUTME -2 #define DST_OTHER -3 #define MSG_EXIT 0x09 #define MSG_STARTGAME 0x0A #define MSG_TURNNOTIFY 0x0B typedef struct _msgTurnNotify { Int32 iPlayer; Int32 iClient; } MsgTurnNotify; #define MSG_ENDTURN 0x0C #define MSG_CLIENTIDENT 0x0D typedef struct _msgClientIdent { Int32 iClientID; } MsgClientIdent; #define MSG_ENTERSTATE 0x0E typedef struct _msgEnterState { Int32 iState; } MsgEnterState; #define MSG_ENDOFGAME 0x10 #define MSG_OBJSTRUPDATE 0x11 typedef struct _msgObjStrUpdate { Int32 iField; Int32 iIndex1, iIndex2; CString strNewValue; } MsgObjStrUpdate; #define MSG_OBJINTUPDATE 0x12 typedef struct _msgObjIntUpdate { Int32 iField; Int32 iIndex1, iIndex2; Int32 iNewValue; } MsgObjIntUpdate; #define MSG_DEREGISTERCLIENT 0x16 #define MSG_ALLOCPLAYER 0x19 #define MSG_FREEPLAYER 0x20 typedef struct _msgFreePlayer { Int32 iPlayer; } MsgFreePlayer; #define MSG_NETMESSAGE 0x21 typedef struct _msgNetMessage { CString strMessage; } MsgNetMessage; #define MSG_NETPOPUP 0x22 typedef struct _msgNetPopup { CString strMessage; } MsgNetPopup; #define MSG_POPUPREGISTERBOX 0x23 #define MSG_DICEROLL 0x24 typedef struct _msgDiceRoll { Int32 iDefendingPlayer; Int32 pAttackDice[3]; Int32 pDefendDice[3]; } MsgDiceRoll; #define MSG_PLACENOTIFY 0x25 typedef struct _msgPlaceNotify { Int32 iCountry; } MsgPlaceNotify; #define MSG_ATTACKNOTIFY 0x26 typedef struct _msgAttackNotify { Int32 iSrcCountry; Int32 iDstCountry; } MsgAttackNotify; #define MSG_MOVENOTIFY 0x27 typedef struct _msgMoveNotify { Int32 iSrcCountry; Int32 iDstCountry; } MsgMoveNotify; #define MSG_POLLCLIENTS 0x28 typedef struct _msgPollClients { CString strPollQuestion; } MsgPollClients; #define MSG_HELLO 0x2a #define MSG_VERSION 0x2b typedef struct _msgVersion { CString strVersion; } MsgVersion; #define MSG_SPECIESIDENT 0x2c typedef struct _msgSpeciesIdent { Int32 iSpeciesID; } MsgSpeciesIdent; #define MSG_MISSION 0x2d #define MSG_ENDOFMISSION 0x2e typedef struct _msgEndOfMission { Int32 iWinner; Int32 iTyp; Int32 iNum1; Int32 iNum2; } MsgEndOfMission; #define MSG_VICTORY 0x2f typedef struct _msgVictory { Int32 iWinner; } MsgVictory; #define MSG_FORCEEXCHANGECARDS 0x30 typedef struct _msgForceExchangeCards { Int32 iPlayer; } MsgForceExchangeCards; Int32 NET_SendMessage(Int32 iSocket, Int32 iMessType, void *pvMessage); Int32 NET_RecvMessage(Int32 iSocket, Int32 *piMessType, void **pvMessage); void NET_DeleteMessage(Int32 iMessType, void *pvMessage); void NET_SetCommLinkOptions(Int32 iSocket); CString NET_MessageToString(Int32 iMessType, void *pvMessage); #endif xfrisk-1.2/registerPlayers.c0100644000175000017500000004672407036460615015253 0ustar johnojohno/* * XFrisk - The classic board game for X * Copyright (C) 1993-1999 Elan Feingold (elan@aetherworks.com) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * $Id: registerPlayers.c,v 1.8 2000/01/10 22:47:41 tony Exp $ * * */ /** \file "Player registration" dialog */ #include #include #include #include #include #include #include #include #include #include #include #include "registerPlayers.h" #include "addPlayer.h" #include "colorEdit.h" #include "gui-vars.h" #include "riskgame.h" #include "utils.h" #include "debug.h" #include "client.h" /* Private functions */ void REG_EditColor(Widget w, XEvent *pEvent, String *str, Cardinal *card); void REG_PerformSelect(Int32 iSlot, Flag fEraseOthers); void REG_RenderSlot(Int32 iSlot, Int32 iPlayer); Flag REG_IsSelected(Int32 iSlot); Int32 REG_PlayerToSlot(Int32 iPlayer); void REG_DeletePlayer(void); void REG_AddPlayer(void); void REG_PlayerCreated(Int32 iPlayer); void REG_PlayerDestroyed(Int32 iPlayer); void REG_Done(void); void REG_Quit(void); #define REG_SelectSlot(slot) \ XtVaSetValues(wShowPlayerForm[slot], XtNborderColor, iSelectColor, NULL) #define REG_UnselectSlot(slot) \ XtVaSetValues(wShowPlayerForm[slot], XtNborderColor, iUnselectColor, NULL) /* Action tables */ static XtActionsRec actionTable[] = { { "regMouseClick", REG_MouseClick }, { "regMouseShiftClick", REG_MouseShiftClick }, { "regEditColor", REG_EditColor }, { NULL, NULL } }; static Int32 piPositionToPlayer[MAX_PLAYERS]; static Int32 iSelectColor, iUnselectColor; static Cursor normalCursor, handCursor; static Widget wRegisterShell, wRegisterForm, wPlayerViewport, wPlayerForm; static Widget wShowPlayerColor[MAX_PLAYERS], wShowPlayerName[MAX_PLAYERS]; static Widget wShowPlayerSpecies[MAX_PLAYERS], wShowPlayerForm[MAX_PLAYERS]; static Widget wAddPlayerButton, wDeletePlayerButton; static Widget wRegisterOKButton, wRegisterNOButton; /************************************************************************ * FUNCTION: REG_BuildDialog * HISTORY: * 01.24.95 ESF Created. * 01.29.95 ESF Finished coding. * PURPOSE: * NOTES: ************************************************************************/ void REG_BuildDialog(void) { Int32 i; /* A cursor to use */ handCursor = XCreateFontCursor(hDisplay, XC_hand1); normalCursor = XCreateFontCursor(hDisplay, XC_left_ptr); iSelectColor = BlackPixel(hDisplay, 0); wRegisterShell = XtCreatePopupShell("wRegisterShell", transientShellWidgetClass, wToplevel, pVisualArgs, iVisualCount); wRegisterForm = XtCreateManagedWidget("wRegisterForm", formWidgetClass, wRegisterShell, NULL, 0); /* Where the players are displayed */ wPlayerViewport = XtCreateManagedWidget("wPlayerViewport", viewportWidgetClass, wRegisterForm, NULL, 0); wPlayerForm = XtCreateManagedWidget("wPlayerForm", boxWidgetClass, wPlayerViewport, NULL, 0); /* Each player */ for (i=0; i!=MAX_PLAYERS; i++) { wShowPlayerForm[i] = XtVaCreateManagedWidget("wShowPlayerForm", formWidgetClass, wPlayerForm, NULL); if (i) XtVaSetValues(wShowPlayerForm[i], XtNfromVert, wShowPlayerForm[i-1], NULL); wShowPlayerColor[i] = XtVaCreateManagedWidget("wShowPlayerColor", labelWidgetClass, wShowPlayerForm[i], NULL); wShowPlayerName[i] = XtVaCreateManagedWidget("wShowPlayerName", labelWidgetClass, wShowPlayerForm[i], XtNfromHoriz, wShowPlayerColor[i], NULL); wShowPlayerSpecies[i] = XtVaCreateManagedWidget("wShowPlayerSpecies", labelWidgetClass, wShowPlayerForm[i], XtNfromHoriz, wShowPlayerName[i], NULL); } /* The buttons */ wAddPlayerButton = XtCreateManagedWidget("wAddPlayerButton", commandWidgetClass, wRegisterForm, NULL, 0); XtAddCallback(wAddPlayerButton, XtNcallback, (XtCallbackProc)REG_AddPlayer, NULL); wDeletePlayerButton = XtCreateManagedWidget("wDeletePlayerButton", commandWidgetClass, wRegisterForm, NULL, 0); XtAddCallback(wDeletePlayerButton, XtNcallback, (XtCallbackProc)REG_DeletePlayer, NULL); /* The OK button */ wRegisterOKButton = XtCreateManagedWidget("wRegisterOKButton", commandWidgetClass, wRegisterForm, NULL, 0); XtAddCallback(wRegisterOKButton, XtNcallback, (XtCallbackProc)REG_Done, NULL); /* The NO button */ wRegisterNOButton = XtCreateManagedWidget("wRegisterNOButton", commandWidgetClass, wRegisterForm, NULL, 0); XtAddCallback(wRegisterNOButton, XtNcallback, (XtCallbackProc)REG_Quit, NULL); /* Add actions */ XtAppAddActions(appContext, actionTable, XtNumber(actionTable)); /* Reset the mapping */ for (i=0; i!=MAX_PLAYERS; i++) piPositionToPlayer[i] = -1; } /************************************************************************ * FUNCTION: REG_Done * HISTORY: * 01.29.94 ESF Created. * 05.19.94 ESF Added warning popup. * 01.29.95 ESF Moved to registerPlayer.c * 02.14.95 ESF Added unselection of slots. * PURPOSE: * NOTES: ************************************************************************/ void REG_Done(void) { extern Int32 iState; Int32 i, rep; /* If there aren't enough players (i.e. <2), then confirm that * the client wants to end the registration stage. */ if (RISK_GetNumPlayers()<2) { #ifdef ENGLISH rep = UTIL_PopupDialog("Warning", "Not enough players to begin game. " " Continue?", 3, "Yes", "No", "Quit"); #endif #ifdef FRENCH rep = UTIL_PopupDialog("Attention", "Pas assez de joueurs pour commencer. " " Continuer?", 3, "Oui", "Non", "Quitter"); #endif switch (rep) { case QUERY_NO: return; case QUERY_CANCEL: UTIL_ExitProgram(0); } } iState = STATE_FORTIFY; /* Let the server know that this client is ready to play */ (void)RISK_SendMessage(CLNT_GetCommLinkOfClient(CLNT_GetThisClientID()), MSG_STARTGAME, NULL); XtPopdown(wRegisterShell); /* Unselect all of the slots */ for (i=0; i!=MAX_PLAYERS; i++) REG_UnselectSlot(i); } /************************************************************************ * FUNCTION: REG_Quit * HISTORY: * 23.08.94 JC Created. * PURPOSE: * NOTES: ************************************************************************/ void REG_Quit(void) { UTIL_ExitProgram(0); } /************************************************************************ * FUNCTION: REG_DeletePlayer * HISTORY: * 02.13.95 ESF Created. * PURPOSE: * NOTES: ************************************************************************/ void REG_DeletePlayer(void) { Int32 i; MsgMessagePacket mess; /* Get all of the players that are selected and delete * them if the client is allowed to. */ for (i=0; i!=MAX_PLAYERS; i++) if (REG_IsSelected(i)) { /* To delete a player you have to be the client of the player, * or the player has to be an AI player (anyone can delete one). */ if (RISK_GetClientOfPlayer(piPositionToPlayer[i]) == CLNT_GetThisClientID() || RISK_GetSpeciesOfPlayer(piPositionToPlayer[i]) != SPECIES_HUMAN) { /* Send a message to the rest of the clients */ char buf[256]; #ifdef ENGLISH snprintf(buf, sizeof(buf), "%s (%s) has left the game.", RISK_GetNameOfPlayer(piPositionToPlayer[i]), "Human"); #endif #ifdef FRENCH snprintf(buf, sizeof(buf), "%s (%s) has left the game.", RISK_GetNameOfPlayer(piPositionToPlayer[i]), "Human"); #endif mess.strMessage = buf; mess.iTo = DST_ALLPLAYERS; mess.iFrom = FROM_SERVER; (void)RISK_SendMessage(CLNT_GetCommLinkOfClient(CLNT_GetThisClientID()), MSG_MESSAGEPACKET, &mess); /* Actually destroy the player */ CLNT_FreePlayer(piPositionToPlayer[i]); /* Unselect the slot */ REG_UnselectSlot(i); /* Because the other players will move down to occupy * the position of the deleted player, we must start * looking from the slot that we just deleted. */ i--; } else { char buf[256]; #ifdef ENGLISH snprintf(buf, sizeof(buf), "%s belongs to another client.", #endif #ifdef FRENCH snprintf(buf, sizeof(buf), "%s belongs to another client.", #endif RISK_GetNameOfPlayer(piPositionToPlayer[i])); UTIL_PopupDialog("Error", buf, 1, "Ok", NULL, NULL); } } } /** \b History: \tag 01.29.95 ESF Created. \b Notes: \par maybe init color from here? */ void REG_AddPlayer(void) { PLAYER_PopupDialog(); } /************************************************************************ * FUNCTION: REG_PopupDialog * HISTORY: * 01.29.95 ESF Created. * PURPOSE: * NOTES: ************************************************************************/ void REG_PopupDialog(void) { Int32 x, y, i, iPlayer; /* Center the new shell */ UTIL_CenterShell(wRegisterShell, wToplevel, &x, &y); XtVaSetValues(wRegisterShell, XtNallowShellResize, False, XtNx, x, XtNy, y, XtNborderWidth, 1, #ifdef ENGLISH XtNtitle, "Player Registration", #endif #ifdef FRENCH XtNtitle, "Enregistrement des joueurs", #endif NULL); /* Reset the mapping */ for (i=0; i!=MAX_PLAYERS; i++) piPositionToPlayer[i] = -1; /* Pop it up... */ XtPopup(wRegisterShell, XtGrabExclusive); /* Add existant players */ for (i=0; i=0 && iSlot=MAX_PLAYERS) return FALSE; XtVaGetValues(wShowPlayerForm[iSlot], XtNborderColor, &iBorderColor, NULL); return (iBorderColor == iSelectColor); } /************************************************************************ * FUNCTION: REG_PlayerToSlot * HISTORY: * 02.13.95 ESF Created. * PURPOSE: * NOTES: ************************************************************************/ Int32 REG_PlayerToSlot(Int32 iPlayer) { Int32 iSlot; /* Which slot is the player in? */ for (iSlot=0; iSlot!=MAX_PLAYERS; iSlot++) if (piPositionToPlayer[iSlot] == iPlayer) break; D_Assert(iSlot Add player * PlayerDestroyed --> Delete player */ if (iMessType == MSG_OBJINTUPDATE && ((MsgObjIntUpdate *)pvMess)->iField == PLR_ALLOCATION && ((MsgObjIntUpdate *)pvMess)->iNewValue == ALLOC_COMPLETE) { /* PlayerCreated */ REG_PlayerCreated(((MsgObjIntUpdate *)pvMess)->iIndex1); } else if (iMessType == MSG_OBJINTUPDATE && ((MsgObjIntUpdate *)pvMess)->iField == PLR_ALLOCATION && ((MsgObjIntUpdate *)pvMess)->iNewValue == ALLOC_NONE) { /* PlayerDestroyed */ REG_PlayerDestroyed(((MsgObjIntUpdate *)pvMess)->iIndex1); } } xfrisk-1.2/registerPlayers.h0100644000175000017500000000250007013357410015231 0ustar johnojohno/* * XFrisk - The classic board game for X * Copyright (C) 1993-1999 Elan Feingold (elan@aetherworks.com) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * $Id: registerPlayers.h,v 1.3 1999/11/13 21:58:32 morphy Exp $ */ #ifndef _REGISTER #define _REGISTER #include #include "types.h" void REG_BuildDialog(void); void REG_PopupDialog(void); void REG_Callback(Int32 iMessType, void *pvMess); /* These should be private, called from REG_Callback */ void REG_MouseClick(Widget w, XEvent *pEvent, CString *str, Cardinal *card); void REG_MouseShiftClick(Widget w, XEvent *pEvent, String *str, Cardinal *card); #endif xfrisk-1.2/risk0100755000175000017500000000033607000075544012600 0ustar johnojohno#!/bin/sh if ( test $# -eq 0 ) then friskserver & sleep 2 SERVEUR=localhost aiColson $SERVEUR & elif ( test $# -eq 1 ) then SERVEUR=$1 else echo "Usage $0 nom" SERVEUR="lrim" fi xfrisk $SERVEUR xfrisk-1.2/riskgame.c0100644000175000017500000015346107042660041013656 0ustar johnojohno/* * XFrisk - The classic board game for X * Copyright (C) 1993-1999 Elan Feingold (elan@aetherworks.com) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * $Id: riskgame.c,v 1.16 2000/01/23 20:10:09 tony Exp $ */ /** \file * "World" used by server as well as client */ /* * * $Log: riskgame.c,v $ * Revision 1.16 2000/01/23 20:10:09 tony * oops, needed another commit for doxygen :-) * * Revision 1.14 2000/01/09 16:06:23 tony * oops, wrong doxygen tags * * Revision 1.13 2000/01/04 21:41:53 tony * removed redundant stuff for jokers * * Revision 1.12 1999/12/14 19:10:50 tony * got rid of this annoying message: * RISK_GetNthPlayerAtClient got 0, numplayers returned 2. to fix!! * lets hope the assertion is just wrong * * Revision 1.11 1999/11/28 14:28:47 tony * nothing special * * Revision 1.10 1999/11/27 19:19:07 tony * oops :-) only 40 in MessageNames * * * */ #include #include #include #include "callbacks.h" #include "network.h" #include "utils.h" #include "riskgame.h" #include "debug.h" #include "language.h" /* Private variables */ static FILE *hLogFile = (FILE *)NULL; /* Private functions */ static Int32 _RISK_GetMsgType(Int32 iField); static Int32 _RISK_GetIntValue(Int32 iField, Int32 iIndex1, Int32 iIndex2); static CString _RISK_GetStrValue(Int32 iField, Int32 iIndex1, Int32 iIndex2); static void *_RISK_BuildMsg(Int32 iMessType, Int32 iField, Int32 iIndex1, Int32 iIndex2, CString strNewValue, Int32 iNewValue); static void _RISK_Replicate(Int32 iField, Int32 iIndex1, Int32 iIndex2, CString strNewValue, Int32 iNewValue); /****************************************/ typedef struct _ContinentObject { CString strName; Int32 iValue; Int32 iNumCountries; } ContinentObject; /****************************************/ typedef struct _CountryObject { CString strName; /* Name of the country */ Int32 iContinent; /* The continent it forms part of */ Int32 iNumArmies; /* Number of armies on the country */ Int32 iTextX, iTextY; /* Where to write the text */ Int32 piOwner; /* The player it belongs to */ Int32 piAdjCountries[6]; /* All attackable countries */ } CountryObject; /****************************************/ typedef struct _PlayerObject { Int32 iAllocationState; Int32 iAttackMode, iDiceMode, iMsgDstMode; Int32 iSpecies; Flag iState; Int32 iClient; CString strName, strColor; Int32 iCountriesOwned, iNumArmies, iNumCards; Int32 piCards[MAX_CARDS]; Int16 typOfMission; Int32 mission1, mission2; } PlayerObject; /****************************************/ typedef struct _SpeciesObject { Int32 iAllocationState; Int32 iClient; CString strName; CString strAuthor; CString strVersion; CString strDescription; struct _SpeciesObject *next; } SpeciesObject; #ifdef LOGGING static char * MessageNames[] = { "MSG_NOMESSAGE", "MSG_OLDREGISTERCLIENT", "unused 0x02", "MSG_EXCHANGECARDS", "MSG_REQUESTCARD", "MSG_CARDPACKET", "MSG_CARDPACKET", "MSG_SENDMESSAGE", "MSG_SENDMESSAGE", "MSG_EXIT", "MSG_STARTGAME", "MSG_TURNNOTIFY", "MSG_ENDTURN", "MSG_CLIENTIDENT", "MSG_ENTERSTATE", "unused 0x0F" "MSG_ENDOFGAME", "MSG_OBJSTRUPDATE", "MSG_OBJINTUPDATE", "PLR_MISSION", "unused 0x14", "unused 0x15", "MSG_DEREGISTERCLIENT", "unused 0x17", "unused 0x18", "MSG_ALLOCPLAYER" "unused 0x1a", "unused 0x1b", "unused 0x1c", "unused 0x1d", "unused 0x1e", "unused 0x1d", "MSG_FREEPLAYER" "MSG_NETMESSAGE" "MSG_NETPOPUP" "MSG_POPUPREGISTERBOX" "MSG_DICEROLL" "MSG_PLACENOTIFY" "MSG_ATTACKNOTIFY", "MSG_MOVENOTIFY", "MSG_POLLCLIENTS", "unused 0x29", "MSG_HELLO", "MSG_VERSION", "MSG_ENDOFMISSION", "MSG_VICTORY", "MSG_VICTORY" }; #endif /****************************************/ typedef struct _Game { void (*ReplicateCallback)(Int32, void *, Int32, Int32); void (*FailureCallback)(CString, Int32); void (*PreViewCallback)(Int32, void *); void (*PostViewCallback)(Int32, void *); /* The databases */ SpeciesObject pSpecies; ContinentObject pContinents[NUM_CONTINENTS]; PlayerObject pPlayers[MAX_PLAYERS]; CountryObject pCountries[NUM_COUNTRIES]; } Game; /* The object (eventually do this in a loop?) */ static Game RiskGame = { NULL, NULL, NULL, NULL, { ALLOC_COMPLETE, -1,HUMAN,UNKNOWN, "0.001", PINK_CREATURE, (SpeciesObject *)NULL }, { { NORTH_AMERICA, 5, 9 }, { SOUTH_AMERICA, 2, 4 }, { AFRICA, 3, 6 }, { AUSTRALIA, 2, 4 }, { ASIA, 7, 12 }, { EUROPE, 5, 7 }, }, { { ALLOC_NONE, 1, 3, 0, 0, PLAYER_ALIVE, -1, NULL, NULL, 0, 0, 0, {0,0,0,0,0,0,0,0,0,0}, NO_MISSION, -1, -1 }, { ALLOC_NONE, 1, 3, 0, 0, PLAYER_ALIVE, -1, NULL, NULL, 0, 0, 0, {0,0,0,0,0,0,0,0,0,0}, NO_MISSION, -1, -1 }, { ALLOC_NONE, 1, 3, 0, 0, PLAYER_ALIVE, -1, NULL, NULL, 0, 0, 0, {0,0,0,0,0,0,0,0,0,0}, NO_MISSION, -1, -1 }, { ALLOC_NONE, 1, 3, 0, 0, PLAYER_ALIVE, -1, NULL, NULL, 0, 0, 0, {0,0,0,0,0,0,0,0,0,0}, NO_MISSION, -1, -1 }, { ALLOC_NONE, 1, 3, 0, 0, PLAYER_ALIVE, -1, NULL, NULL, 0, 0, 0, {0,0,0,0,0,0,0,0,0,0}, NO_MISSION, -1, -1 }, { ALLOC_NONE, 1, 3, 0, 0, PLAYER_ALIVE, -1, NULL, NULL, 0, 0, 0, {0,0,0,0,0,0,0,0,0,0}, NO_MISSION, -1, -1 }, { ALLOC_NONE, 1, 3, 0, 0, PLAYER_ALIVE, -1, NULL, NULL, 0, 0, 0, {0,0,0,0,0,0,0,0,0,0}, NO_MISSION, -1, -1 }, { ALLOC_NONE, 1, 3, 0, 0, PLAYER_ALIVE, -1, NULL, NULL, 0, 0, 0, {0,0,0,0,0,0,0,0,0,0}, NO_MISSION, -1, -1 }, { ALLOC_NONE, 1, 3, 0, 0, PLAYER_ALIVE, -1, NULL, NULL, 0, 0, 0, {0,0,0,0,0,0,0,0,0,0}, NO_MISSION, -1, -1 }, { ALLOC_NONE, 1, 3, 0, 0, PLAYER_ALIVE, -1, NULL, NULL, 0, 0, 0, {0,0,0,0,0,0,0,0,0,0}, NO_MISSION, -1, -1 }, { ALLOC_NONE, 1, 3, 0, 0, PLAYER_ALIVE, -1, NULL, NULL, 0, 0, 0, {0,0,0,0,0,0,0,0,0,0}, NO_MISSION, -1, -1 }, { ALLOC_NONE, 1, 3, 0, 0, PLAYER_ALIVE, -1, NULL, NULL, 0, 0, 0, {0,0,0,0,0,0,0,0,0,0}, NO_MISSION, -1, -1 }, }, { { GREENLAND, CNT_NORTHAMERICA, 0, 264, 32, -1, /* 0 */ {1, 5, 10, 11, -1, -1} }, { ICELAND, CNT_EUROPE, 0, 342, 51, -1, {0, 7, 14, -1, -1, -1} }, { SIBERIA, CNT_ASIA, 0, 622, 91, -1, {3, 6, 13, 21, 22, -1} }, { URAL, CNT_ASIA, 0, 557, 106, -1, {2, 8, 15, 22, -1, -1} }, { ALASKA, CNT_NORTHAMERICA, 0, 13, 61, -1, {5, 9, 12, -1, -1, -1} }, { NORTH_WEST, CNT_NORTHAMERICA, 0, 61, 62, -1, /* 5 */ {0, 4, 11, 12, -1, -1} }, { IRKUTSK, CNT_ASIA, 0, 700, 71, -1, {2, 9, 13, -1, -1, -1} }, { SCANDINAVIA, CNT_EUROPE, 0, 387, 85, -1, {1, 8, 14, 16, -1, -1} }, { UKRAINE, CNT_EUROPE, 0, 450, 103, -1, {3, 7, 15, 16, 20, 24}}, { KAMCHATKA, CNT_ASIA, 0, 731, 121, -1, {4, 6, 13, 21, 23, -1} }, { QUEBEC, CNT_NORTHAMERICA, 0, 181, 95, -1, /* 10 */ {0, 11, 18, -1, -1, -1} }, { ONTARIO, CNT_NORTHAMERICA, 0, 116, 97, -1, {0, 5, 10, 12, 17, 18} }, { ALBERTA, CNT_NORTHAMERICA, 0, 55, 90, -1, {4, 5, 11, 17, -1, -1} }, { YAKUTSK, CNT_ASIA, 0, 690, 111, -1, {2, 6, 9, 21, -1, -1} }, { GREAT_BRITAIN, CNT_EUROPE, 0, 338, 110, -1, {1, 7, 16, 19, -1, -1} }, { AFGHANISTAN, CNT_ASIA, 0, 534, 141, -1, /* 15 */ {3, 8, 22, 24, 28, -1} }, { NORTHERN_EUROPE, CNT_EUROPE, 0, 386, 113, -1, {7, 8, 14, 19, 20, -1} }, { WEST_STATES, CNT_NORTHAMERICA, 0, 62, 126, -1, {11, 12, 18, 25, -1, -1} }, { EAST_STATES, CNT_NORTHAMERICA, 0, 126, 145, -1, {10, 11, 17, 25, -1, -1} }, { WEST_EUROPE, CNT_EUROPE, 0, 338, 148, -1, {14, 16, 20, 26, -1, -1} }, { SOUTH_EUROPE, CNT_EUROPE, 0, 416, 134, -1, /* 20 */ {8, 16, 19, 24, 26, 27} }, { MONGOLIA, CNT_ASIA, 0, 685, 139, -1, {2, 9, 13, 22, 23, -1} }, { CHINA, CNT_ASIA, 0, 632, 163, -1, {2, 3, 15, 21, 28, 29} }, { JAPAN, CNT_ASIA, 0, 735, 166, -1, {9, 21, -1, -1, -1, -1} }, { MIDDLE_EAST, CNT_ASIA, 0, 477, 193, -1, {8, 15, 20, 27, 28, 30} }, { CENTRAL_AMERICA, CNT_NORTHAMERICA, 0, 87, 165, -1, /* 25 */ {17, 18, 32, -1, -1, -1}}, { NORTH_AFRICA, CNT_AFRICA, 0, 339, 214, -1, {19, 20, 27, 30, 33, 35} }, { EGYPT, CNT_AFRICA, 0, 407, 194, -1, {20, 24, 26, 30, -1, -1} }, { INDIA, CNT_ASIA, 0, 572, 194, -1, {15, 22, 24, 29, -1, -1} }, { SIAM, CNT_ASIA, 0, 637, 207, -1, {22, 28, 31, -1, -1, -1} }, { EAST_AFRICA, CNT_AFRICA, 0, 437, 231, -1, /* 30 */ {24, 26, 27, 35, 37, 40} }, { INDONESIA, CNT_AUSTRALIA, 0, 672, 262, -1, {29, 36, 38, -1, -1, -1} }, { VENEZUELA, CNT_SOUTHAMERICA, 0, 188, 230, -1, {25, 33, 34, -1, -1, -1} }, { BRASIL, CNT_SOUTHAMERICA, 0, 233, 277, -1, {26, 32, 34, 41, -1, -1} }, { PERU, CNT_SOUTHAMERICA, 0, 194, 294, -1, {32, 33, 41, -1, -1, -1}}, { CONGO, CNT_AFRICA, 0, 410, 271, -1, /* 35 */ {26, 30, 37, -1, -1, -1} }, { NEW_GUINEA, CNT_AUSTRALIA, 0, 751, 276, -1, {31, 38, 39, -1, -1, -1} }, { SOUTH_AFRICA, CNT_AFRICA, 0, 416, 326, -1, {30, 35, 40, -1, -1, -1} }, { WESTERN_AUSTRALIA, CNT_AUSTRALIA, 0, 700, 335, -1, {31, 36, 39, -1, -1, -1} }, { EASTERN_AUSTRALIA, CNT_AUSTRALIA, 0, 756, 343, -1, {36, 38, -1, -1, -1, -1} }, { MADAGASCAR, CNT_AFRICA, 0, 479, 321, -1, /* 40 */ {30, 37, -1, -1, -1, -1} }, { ARGENTINA, CNT_SOUTHAMERICA, 0, 189, 352, -1, {33, 34, -1, -1, -1, -1} }, } }; /* Species related private function */ SpeciesObject *_RISK_GetSpecies(Int32 iHandle); /** * Init callbacks * * \b History: * \tag 07.17.94 ESF Created. * \tag 08.13.94 ESF Rewrote. * \b Notes: * \parThis function is called by both client and server. */ void RISK_InitObject(void (*ReplicateCallback)(Int32, void *, Int32, Int32), void (*PreViewCallback)(Int32, void *), void (*PostViewCallback)(Int32, void *), void (*FailureCallback)(CString, Int32), FILE *hDebug) { RiskGame.ReplicateCallback = ReplicateCallback; RiskGame.FailureCallback = FailureCallback; RiskGame.PreViewCallback = PreViewCallback; RiskGame.PostViewCallback = PostViewCallback; /* The message callback has to be set -- it handles replication. */ D_Assert(RiskGame.ReplicateCallback, "ReplicateCallback needs to be set!"); /* Save this */ hLogFile = hDebug; } /************************************************************************ * FUNCTION: _RISK_Replicate * HISTORY: * 05.03.94 ESF Created. * 06.24.94 ESF Fixed memory leak. * 07.16.94 ESF Added assert. * 08.16.94 ESF Changed so that both can get callback (Server/Client). * 08.18.94 ESF Changed so that callback handles actual replication. * PURPOSE: * NOTES: ************************************************************************/ void _RISK_Replicate(Int32 iField, Int32 iIndex1, Int32 iIndex2, CString strNewValue, Int32 iNewValue) { void *pvMess; Int32 iMessType; /* Get the message and the message type */ iMessType = _RISK_GetMsgType(iField); pvMess = _RISK_BuildMsg(iMessType, iField, iIndex1, iIndex2, strNewValue, iNewValue); D_Assert(pvMess, "Got back NULL message!"); /* Call the callback for messages (before changing dist. obj.) */ if (RiskGame.PreViewCallback) RiskGame.PreViewCallback(iMessType, pvMess); /* Actually set the value (sort of roundabout :) Everything * to set the message follows the same code path now, so * it may be a bit roundabout but at least it's consistant. */ RISK_ProcessMessage(iMessType, pvMess); /* Call the callback for messages (after changing dist. obj.) */ if (RiskGame.PostViewCallback) RiskGame.PostViewCallback(iMessType, pvMess); /* Call the message handler. If there wasn't one, then * we would have a problem, since it handles the actual replication. * This involves sending a message to the server, or broadcasting * a message out, depending on whether a client or server has * registered this callback. The last parameter doesn't matter in * this case, because it's an outgoing message (the last parameter * is the message source). */ RiskGame.ReplicateCallback(iMessType, pvMess, MESS_OUTGOING, -1); /* Delete the memory the message was taking */ MEM_Free(pvMess); } /************************************************************************ * FUNCTION: RISK_SelectiveReplicate * HISTORY: * 05.06.94 ESF Created. * 05.10.94 ESF Added needed check for existence of callback. * 07.16.94 ESF Fixed loop bug, added assertions. * 08.28.94 ESF Changed to take indices, instead of ranges. * 01.01.95 ESF Fixed to remove a memory leak. * PURPOSE: * Sends data to a client, for purposes of data synchronicity. * NOTES: ************************************************************************/ void RISK_SelectiveReplicate(Int32 iSocket, Int32 iField, Int32 iIndex1, Int32 iIndex2) { void *pvMess; Int32 iValue = 0, iMessType; CString strValue = NULL; /* Type of the message */ iMessType = _RISK_GetMsgType(iField); /* Get the value... */ if (iMessType == MSG_OBJINTUPDATE) iValue = _RISK_GetIntValue(iField, iIndex1, iIndex2); else strValue = _RISK_GetStrValue(iField, iIndex1, iIndex2); /* And build the message... */ pvMess = _RISK_BuildMsg(iMessType, iField, iIndex1, iIndex2, strValue, iValue); (void)RISK_SendMessage(iSocket, iMessType, pvMess); /* Delete the memory the message took up */ MEM_Free(pvMess); } /************************************************************************ * FUNCTION: RISK_ResetObj * HISTORY: * 05.02.94 ESF Created. * PURPOSE: * NOTES: ************************************************************************/ void RISK_ResetObj(void) { Int32 i, iPlayer; /* Init the needed fields of the players */ for (i=0; iiField; iIndex1 = pIntMess->iIndex1; iIndex2 = pIntMess->iIndex2; iValue = pIntMess->iNewValue; switch (iField) { case PLR_ATTACKMODE: RiskGame.pPlayers[iIndex1].iAttackMode = iValue; break; case PLR_DICEMODE: RiskGame.pPlayers[iIndex1].iDiceMode = iValue; break; case PLR_MSGDSTMODE: RiskGame.pPlayers[iIndex1].iMsgDstMode = iValue; break; case PLR_STATE: RiskGame.pPlayers[iIndex1].iState = iValue; break; case PLR_CLIENT: RiskGame.pPlayers[iIndex1].iClient = iValue; break; case PLR_NUMCOUNTRIES: RiskGame.pPlayers[iIndex1].iCountriesOwned = iValue; break; case PLR_NUMARMIES: RiskGame.pPlayers[iIndex1].iNumArmies = iValue; break; case PLR_NUMCARDS: RiskGame.pPlayers[iIndex1].iNumCards = iValue; break; case PLR_SPECIES: RiskGame.pPlayers[iIndex1].iSpecies = iValue; break; case PLR_ALLOCATION: RiskGame.pPlayers[iIndex1].iAllocationState = iValue; break; case PLR_CARD: /* TdH: one of the places where greenlandbug might be caught */ RiskGame.pPlayers[iIndex1].piCards[iIndex2] = iValue; break; case PLR_MISSION: RiskGame.pPlayers[iIndex1].typOfMission = iValue; break; case PLR_MISSION1: RiskGame.pPlayers[iIndex1].mission1 = iValue; break; case PLR_MISSION2: RiskGame.pPlayers[iIndex1].mission2 = iValue; break; case CNT_NUMARMIES: RiskGame.pCountries[iIndex1].iNumArmies = iValue; break; case CNT_OWNER: RiskGame.pCountries[iIndex1].piOwner = iValue; break; case SPE_CLIENT: { SpeciesObject *s = _RISK_GetSpecies(iIndex1); s->iClient = iValue; } break; case SPE_ALLOCATION: { SpeciesObject *s = _RISK_GetSpecies(iIndex1); s->iAllocationState = iValue; } break; default: D_Assert(FALSE, "Badly build MSG_OBJINTUPDATE!"); } } else { iField = pStrMess->iField; iIndex1 = pStrMess->iIndex1; iIndex2 = pStrMess->iIndex2; strValue = pStrMess->strNewValue; switch (iField) { case PLR_NAME: if (RiskGame.pPlayers[iIndex1].strName != NULL) MEM_Free(RiskGame.pPlayers[iIndex1].strName); if (strValue) { RiskGame.pPlayers[iIndex1].strName = (CString)MEM_Alloc(strlen(strValue)+1); strcpy(RiskGame.pPlayers[iIndex1].strName, strValue); } else RiskGame.pPlayers[iIndex1].strName = NULL; break; case PLR_COLORSTRING: if (RiskGame.pPlayers[iIndex1].strColor != NULL) MEM_Free(RiskGame.pPlayers[iIndex1].strColor); if (strValue) { RiskGame.pPlayers[iIndex1].strColor = (CString)MEM_Alloc(strlen(strValue)+1); strcpy(RiskGame.pPlayers[iIndex1].strColor, strValue); } else RiskGame.pPlayers[iIndex1].strColor = NULL; break; case SPE_NAME: { SpeciesObject *s = _RISK_GetSpecies(iIndex1); if (s->strName != NULL) MEM_Free(s->strName); if (strValue) { s->strName = (CString)MEM_Alloc(strlen(strValue)+1); strcpy(s->strName, strValue); } else s->strName = NULL; } break; case SPE_VERSION: { SpeciesObject *s = _RISK_GetSpecies(iIndex1); if (s->strVersion != NULL) MEM_Free(s->strVersion); if (strValue) { s->strVersion = (CString)MEM_Alloc(strlen(strValue)+1); strcpy(s->strVersion, strValue); } else s->strVersion = NULL; } break; case SPE_DESCRIPTION: { SpeciesObject *s = _RISK_GetSpecies(iIndex1); if (s->strDescription != NULL) MEM_Free(s->strDescription); if (strValue) { s->strDescription = (CString)MEM_Alloc(strlen(strValue)+1); strcpy(s->strDescription, strValue); } else s->strDescription = NULL; } break; case SPE_AUTHOR: { SpeciesObject *s = _RISK_GetSpecies(iIndex1); if (s->strAuthor != NULL) MEM_Free(s->strAuthor); if (strValue) { s->strAuthor = (CString)MEM_Alloc(strlen(strValue)+1); strcpy(s->strAuthor, strValue); } else s->strAuthor = strValue; } break; default: D_Assert(FALSE, "Badly build MSG_OBJSTRUPDATE!"); } } } /***************************************/ void RISK_SetAttackModeOfPlayer(Int32 iPlayer, Int32 iMode) { D_Assert(iPlayer>=0 && iPlayer=0 && iPlayer=0 && iPlayer=0 && iPlayer=0 && iPlayer=0 && iPlayer=0 && iPlayer=0 && iPlayer=0 && iPlayer=0 && iPlayer=0 && iPlayer=0 && iPlayer=0 && iPlayer=0 && iPlayer=0 && iPlayer=0 && iPlayer=0 && iPlayer=0 && iPlayer=0 && iPlayer=0 && iCountry=0 && iCountry=0 && iPlayer=0 && iPlayer=0 && iPlayer=0 && iPlayer=0 && iPlayer=0 && iPlayer=0 && iPlayer=0 && iPlayer=0 && iPlayer=0 && iPlayer=0 && iContinent=0 && iContinent=0 && iContinent=0 && iPlayer=0 && iPlayer=0 && iPlayer=0 && iPlayer=0 && iPlayer=0 && iPlayer=0 && iPlayer=0 && iPlayer=0 && iPlayer=0 && iCountry=0 && iCountry=0 && iCountry=0 && iCountry=0 && iCountrynext) if (pSpecies->iAllocationState == ALLOC_COMPLETE) iCount++; return iCount; } /***************************************/ Int32 RISK_GetTextXOfCountry(Int32 iCountry) { D_Assert(iCountry>=0 && iCountry=0 && iCountryiClient; } /***************************************/ CString RISK_GetNameOfSpecies(Int32 iHandle) { return _RISK_GetSpecies(iHandle)->strName; } /***************************************/ Int32 RISK_GetAllocationStateOfSpecies(Int32 iHandle) { return _RISK_GetSpecies(iHandle)->iAllocationState; } /***************************************/ CString RISK_GetAuthorOfSpecies(Int32 iHandle) { return _RISK_GetSpecies(iHandle)->strAuthor; } /***************************************/ CString RISK_GetDescriptionOfSpecies(Int32 iHandle) { return _RISK_GetSpecies(iHandle)->strDescription; } /***************************************/ CString RISK_GetVersionOfSpecies(Int32 iHandle) { return _RISK_GetSpecies(iHandle)->strVersion; } /***************************************/ Int32 _RISK_GetMsgType(Int32 iField) { switch (iField) { case PLR_ATTACKMODE: case PLR_DICEMODE: case PLR_MSGDSTMODE: case PLR_STATE: case PLR_SPECIES: case PLR_ALLOCATION: case PLR_CLIENT: case PLR_NUMCOUNTRIES: case PLR_NUMARMIES: case PLR_NUMCARDS: case PLR_CARD: case PLR_MISSION: case PLR_MISSION1: case PLR_MISSION2: case CNT_CONTINENT: case CNT_NUMARMIES: case CNT_OWNER: case CNT_ADJCOUNTRY: case CNT_TEXTX: case CNT_TEXTY: case CON_VALUE: case CON_NUMCOUNTRIES: case SPE_CLIENT: case SPE_ALLOCATION: return MSG_OBJINTUPDATE; break; case PLR_NAME: case PLR_COLORSTRING: case CNT_NAME: case CON_NAME: case SPE_NAME: case SPE_VERSION: case SPE_DESCRIPTION: case SPE_AUTHOR: return MSG_OBJSTRUPDATE; default: D_Assert(FALSE, "Shouldn't be here!"); } /* For the compiler */ return (0); } /***************************************/ void *_RISK_BuildMsg(Int32 iMessType, Int32 iField, Int32 iIndex1, Int32 iIndex2, CString strValue, Int32 iValue) { if (iMessType == MSG_OBJINTUPDATE) { MsgObjIntUpdate *pIntMess = (MsgObjIntUpdate *)MEM_Alloc(sizeof(MsgObjIntUpdate)); /* Build the new message */ pIntMess->iField = iField; pIntMess->iIndex1 = iIndex1; pIntMess->iIndex2 = iIndex2; pIntMess->iNewValue = iValue; /* Return it */ return pIntMess; } else if (iMessType == MSG_OBJSTRUPDATE) { MsgObjStrUpdate *pStrMess = (MsgObjStrUpdate *)MEM_Alloc(sizeof(MsgObjStrUpdate)); /* Build the new message */ pStrMess->iField = iField; pStrMess->iIndex1 = iIndex1; pStrMess->iIndex2 = iIndex2; pStrMess->strNewValue = strValue; /* Return it */ return pStrMess; } D_Assert(FALSE, "Shouldn't be here!!"); /* Make the stupid compiler happy */ return NULL; } /************************************************************************ * FUNCTION: RISK_ObjectFailure * HISTORY: * 08.03.94 ESF Created. * 08.12.94 ESF Made nicer, integrated with sister routine. * 08.17.94 ESF Added string parameter. * 08.26.94 ESF Deleted integer parameter :) * 08.28.94 ESF Added callback for eventual recovery. * 10.01.94 ESF Added assertion. * PURPOSE: * Eventually this will handle fault tolerance. * NOTES: ************************************************************************/ void RISK_ObjectFailure(CString strReason, Int32 iCommLink) { D_Assert(RiskGame.FailureCallback, "Need to register a failure callback!"); RiskGame.FailureCallback(strReason, iCommLink); } /************************************************************************ * FUNCTION: RISK_GetNthLivePlayer * HISTORY: * 05.15.94 ESF Created. * 07.25.94 ESF Fixed a bug with the for loop, off-by-one. * 08.08.94 ESF Moved here from server.c * 08.27.94 ESF Renamed. * PURPOSE: * NOTES: ************************************************************************/ Int32 RISK_GetNthLivePlayer(Int32 iIndex) { Int32 i, iCount; D_Assert(iIndex>=0 && iIndex=0 && iIndex=0 && iIndex=0 && iClient=0 && iClientnext, i++) ptrLast = ptr; D_Assert(i==iSpecies || istrName = NULL; ptr->strVersion = NULL; ptr->strAuthor = NULL; ptr->strDescription = NULL; ptr->iClient = -1; ptr->iAllocationState = ALLOC_NONE; ptr->next = NULL; /* Append it to the list */ D_Assert(ptrLast, "Something is messed up!"); ptrLast->next = ptr; } D_Assert(ptr, "Something went very wrong, I don't have a pointer??"); return ptr; } /************************************************************************ * FUNCTION: _RISK_GetIntValue * HISTORY: * 03.20.95 ESF Created. * PURPOSE: * NOTES: ************************************************************************/ Int32 _RISK_GetIntValue(Int32 iField, Int32 iIndex1, Int32 iIndex2) { switch(iField) { case PLR_ATTACKMODE: return RiskGame.pPlayers[iIndex1].iAttackMode; break; case PLR_DICEMODE: return RiskGame.pPlayers[iIndex1].iDiceMode; break; case PLR_MSGDSTMODE: return RiskGame.pPlayers[iIndex1].iMsgDstMode; break; case PLR_STATE: return RiskGame.pPlayers[iIndex1].iState; break; case PLR_CLIENT: return RiskGame.pPlayers[iIndex1].iClient; break; case PLR_SPECIES: return RiskGame.pPlayers[iIndex1].iSpecies; break; case PLR_ALLOCATION: return RiskGame.pPlayers[iIndex1].iAllocationState; break; case PLR_NUMCOUNTRIES: return RiskGame.pPlayers[iIndex1].iCountriesOwned; break; case PLR_NUMARMIES: return RiskGame.pPlayers[iIndex1].iNumArmies; break; case PLR_NUMCARDS: return RiskGame.pPlayers[iIndex1].iNumCards; break; case PLR_CARD: return RiskGame.pPlayers[iIndex1].piCards[iIndex2]; break; case PLR_MISSION: return RiskGame.pPlayers[iIndex1].typOfMission; break; case PLR_MISSION1: return RiskGame.pPlayers[iIndex1].mission1; break; case PLR_MISSION2: return RiskGame.pPlayers[iIndex1].mission2; break; case CNT_NUMARMIES: return RiskGame.pCountries[iIndex1].iNumArmies; break; case CNT_OWNER: return RiskGame.pCountries[iIndex1].piOwner; break; case SPE_CLIENT: { SpeciesObject *s = _RISK_GetSpecies(iIndex1); return s->iClient; } break; case SPE_ALLOCATION: { SpeciesObject *s = _RISK_GetSpecies(iIndex1); return s->iAllocationState; } break; default: D_Assert(FALSE, "Add case to _RISK_GetIntValue!"); } /* Make compiler happy */ return 0; } /************************************************************************ * FUNCTION: _RISK_GetStrValue * HISTORY: * 03.20.95 ESF Created. * PURPOSE: * NOTES: ************************************************************************/ CString _RISK_GetStrValue(Int32 iField, Int32 iIndex1, Int32 iIndex2) { UNUSED(iIndex2); switch(iField) { case PLR_NAME: return RiskGame.pPlayers[iIndex1].strName; break; case PLR_COLORSTRING: return RiskGame.pPlayers[iIndex1].strColor; break; case SPE_NAME: { SpeciesObject *s = _RISK_GetSpecies(iIndex1); return s->strName; } break; case SPE_VERSION: { SpeciesObject *s = _RISK_GetSpecies(iIndex1); return s->strVersion; } break; case SPE_DESCRIPTION: { SpeciesObject *s = _RISK_GetSpecies(iIndex1); return s->strDescription; } break; case SPE_AUTHOR: { SpeciesObject *s = _RISK_GetSpecies(iIndex1); return s->strAuthor; } break; default: D_Assert(FALSE, "Add case to _RISK_GetStrValue"); } /* Make the compiler happy */ return NULL; } xfrisk-1.2/riskgame.h0100644000175000017500000002632207031463720013661 0ustar johnojohno/* * XFrisk - The classic board game for X * Copyright (C) 1993-1999 Elan Feingold (elan@aetherworks.com) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * $Id: riskgame.h,v 1.7 1999/12/26 19:09:04 morphy Exp $ * * $Log: riskgame.h,v $ * Revision 1.7 1999/12/26 19:09:04 morphy * Doxygen comments * */ /** \file * Interface definitions for the RISK game distributed object. * * \bug Contains a LOT of hardcoded information */ #ifndef _RISK #define _RISK #include #include "network.h" #include "types.h" /* Fields of the RiskGame object. There MUST NOT be any gaps in the * numeric sequence (because of how the replication works. */ #define PLR_ATTACKMODE 0 /* Remembers the attack mode of the player */ #define PLR_MSGDSTMODE 1 /* Remembers the last message destination */ #define PLR_DICEMODE 2 /* Remembers the last die mode */ #define PLR_STATE 3 /* Either TRUE = Alive, FALSE = Dead */ #define PLR_CLIENT 4 /* The client of the player */ #define PLR_NUMCOUNTRIES 5 /* Number of territories the player owns */ #define PLR_NUMARMIES 6 /* Number of armies the player holds */ #define PLR_NUMCARDS 7 /* Number of cards the player holds */ #define PLR_NAME 8 /* Name of the player */ #define PLR_COLORSTRING 9 /* Name of the color of the player */ #define PLR_CARD 10 /* A card of the player */ #define PLR_SPECIES 11 /* What is the player */ #define PLR_ALLOCATION 12 /* State of allocation of player */ #define PLR_MISSION 13 /* Mission's type of player */ #define PLR_MISSION1 14 /* Mission's number1 of player */ #define PLR_MISSION2 15 /* Mission's number2 of player */ #define CNT_NAME 16 #define CNT_CONTINENT 17 #define CNT_NUMARMIES 18 #define CNT_OWNER 19 #define CNT_ADJCOUNTRY 20 #define CNT_TEXTX 21 #define CNT_TEXTY 22 #define CON_NAME 23 #define CON_VALUE 24 #define CON_NUMCOUNTRIES 25 #define SPE_NAME 26 #define SPE_VERSION 27 #define SPE_DESCRIPTION 28 #define SPE_AUTHOR 29 #define SPE_CLIENT 30 #define SPE_ALLOCATION 31 /* Port at which the clients can find the server */ #define RISK_PORT 5324 /* Amount of time (in ms) for graphical notification */ #define NOTIFY_TIME 750 /* Limits */ #define MAX_CLIENTS 32 #define MAX_CARDS 10 #define MAX_PLAYERS 12 #define MAX_COLORS 256 /* This may be a static value (i.e. OPEN_MAX), or a dynamic value, * as in OSF/1, accessed through sysconf(). I'm not sure that all * systems have these, so we'll just guess. I don't think this is * exceptionally evil, since if we run out of descriptors, the socket * or accept calls will fail. */ #define MAX_DESCRIPTORS 128 /* Numbers */ #define NUM_CONTINENTS 6 #define NUM_COUNTRIES 42 #define NUM_OTHERCOLORS 4 /* Dice*2, Player Turn, ColorEdit */ #define NUM_CARDS (NUM_COUNTRIES+2) #define NUM_FORTIFY_ARMIES 1 /* Continents */ #define CNT_NORTHAMERICA 0 #define CNT_SOUTHAMERICA 1 #define CNT_AFRICA 2 #define CNT_AUSTRALIA 3 #define CNT_ASIA 4 #define CNT_EUROPE 5 /* Missions */ #define NO_MISSION 0 #define CONQUIER_WORLD 1 #define CONQUIER_Nb_COUNTRY 2 #define CONQUIER_TWO_CONTINENTS 3 #define KILL_A_PLAYER 4 /* Macros */ #ifdef MAX #undef MAX #endif #define MAX(a, b) ((a)>(b)?(a):(b)) #ifdef MIN #undef MIN #endif #define MIN(a, b) ((a)>(b)?(b):(a)) #ifndef TRUE #define TRUE 1 #endif #ifndef FALSE #define FALSE 0 #endif /* States in risk state machine */ #define STATE_REGISTER 0 #define STATE_FORTIFY 1 #define STATE_PLACE 2 #define STATE_ATTACK 3 #define STATE_MOVE 4 /* Defines for widgets */ #define ATTACK_ONE 0 #define ATTACK_TWO 1 #define ATTACK_THREE 2 #define ATTACK_AUTO 3 #define ACTION_PLACE 0 #define ACTION_ATTACK 1 #define ACTION_DOORDIE 2 #define ACTION_MOVE 3 /* The only known species at the beginning */ #define SPECIES_HUMAN 0 /* A PERSISTANT object will maintain a copy of itself on secondary storage. * Every time the object updates a field, it also updates the field on disk. */ #define MODE_PERSISTANT 8 /* States in allocation for players and species */ #define ALLOC_NONE 0 #define ALLOC_INPROGRESS 1 #define ALLOC_COMPLETE 2 /* States for players */ #define PLAYER_DEAD 0 #define PLAYER_ALIVE 1 /* These functions support all of the functionality of the RiskGame structure, * in order for it to work as a fully distributed object. The functions * are split into two catagories, those that receive input from a remote * source (through a message), those that receive input from the local * client, which is sent back to the server to broadcast to all the other * clients, and those that return fields of the object to the local client. * This file serves the functionality of a C++ object -- I would use GCC but * its C++ side is not stable enough. Hold your breath, though :) */ /* Constructor */ void RISK_InitObject(void (*ReplicateCallback)(Int32, void *, Int32, Int32), void (*PreViewCallback)(Int32, void *), void (*PostViewCallback)(Int32, void *), void (*FailureCallback)(CString, Int32), FILE *hDebug); #define MESS_INCOMING 0 #define MESS_OUTGOING 1 /* For persistance */ void RISK_SaveObject(CString strFileName); void RISK_LoadObject(CString strFileName); /* Utilities */ Int32 RISK_GetNthLivePlayer(Int32 iIndex); Int32 RISK_GetNthPlayer(Int32 iIndex); Int32 RISK_GetNthPlayerAtClient(Int32 iClient, Int32 iIndex); Int32 RISK_GetNumPlayersOfClient(Int32 iClient); Int32 RISK_GetNumLivePlayersOfClient(Int32 iClient); void RISK_ObjectFailure(CString strReason, Int32 iCommLink); /* For the failure routine */ #define SERVER -1 /* Reliable communication */ Int32 RISK_SendMessage(Int32 iDest, Int32 iMessType, void *pvMessage); Int32 RISK_ReceiveMessage(Int32 iSource, Int32 *piMessType, void **ppvMessage); Int32 RISK_SendSyncMessage(Int32 iCommLink, Int32 iMessType, void *pvMessage, Int32 iReturnMessType, void (*CBK_MessageReceived)(Int32, void *)); /* Methods for the distributed object. */ void RISK_SelectiveReplicate(Int32 iClientToServerSocket, Int32 iField, Int32 iIndex1, Int32 iIndex2); void RISK_ResetObj(void); void RISK_ResetGame(void); void RISK_ProcessMessage(Int32 iMessType, void *pMessage); void RISK_SetSpeciesOfPlayer(Int32 iPlayer, Int32 iSpecies); void RISK_SetAttackModeOfPlayer(Int32 iPlayer, Int32 iMode); void RISK_SetDiceModeOfPlayer(Int32 iPlayer, Int32 iMode); void RISK_SetMsgDstModeOfPlayer(Int32 iPlayer, Int32 iMode); void RISK_SetStateOfPlayer(Int32 iPlayer, Int32 iState); void RISK_SetClientOfPlayer(Int32 iPlayer, Int32 iClient); void RISK_SetAllocationStateOfPlayer(Int32 iPlayer, Int32 iState); void RISK_SetNumCountriesOfPlayer(Int32 iCountry, Int32 iNumCountries); void RISK_SetNumArmiesOfPlayer(Int32 iCountry, Int32 iNumArmies); void RISK_SetNumCardsOfPlayer(Int32 iPlayer, Int32 iNumCards); void RISK_SetNameOfPlayer(Int32 iPlayer, CString strName); void RISK_SetColorCStringOfPlayer(Int32 iPlayer, CString strColor); void RISK_SetCardOfPlayer(Int32 iPlayer, Int32 iCard, Int32 iValue); void RISK_SetMissionTypeOfPlayer(Int32 iPlayer, Int16 typ); void RISK_SetMissionNumberOfPlayer(Int32 iPlayer, Int32 n); void RISK_SetMissionContinent1OfPlayer(Int32 iPlayer, Int32 n); void RISK_SetMissionContinent2OfPlayer(Int32 iPlayer, Int32 n); void RISK_SetMissionMissionPlayerToKillOfPlayer(Int32 iPlayer, Int32 n); void RISK_SetMissionPlayerIsKilledOfPlayer(Int32 iPlayer, Flag boool); void RISK_SetNameOfCountry(Int32 iCountry, CString strName); void RISK_SetContinentOfCountry(Int32 iCountry, Int32 iContinent); void RISK_SetOwnerOfCountry(Int32 iCountry, Int32 iOwner); void RISK_SetNumArmiesOfCountry(Int32 iCountry, Int32 iNumArmies); void RISK_SetAdjCountryOfCountry(Int32 iCountry, Int32 iIndex, Int32 OtherC); Int32 RISK_GetSpeciesOfPlayer(Int32 iPlayer); Int32 RISK_GetDiceModeOfPlayer(Int32 iPlayer); Int32 RISK_GetMsgDstModeOfPlayer(Int32 iPlayer); Int32 RISK_GetAttackModeOfPlayer(Int32 iPlayer); Int32 RISK_GetStateOfPlayer(Int32 iPlayer); Int32 RISK_GetClientOfPlayer(Int32 iPlayer); Int32 RISK_GetAllocationStateOfPlayer(Int32 iPlayer); Int32 RISK_GetNumCountriesOfPlayer(Int32 iPlayer); Int32 RISK_GetNumArmiesOfPlayer(Int32 iPlayer); Int32 RISK_GetNumCardsOfPlayer(Int32 iPlayer); CString RISK_GetNameOfPlayer(Int32 iPlayer); CString RISK_GetColorCStringOfPlayer(Int32 iPlayer); Int32 RISK_GetCardOfPlayer(Int32 iPlayer, Int32 iCard); Int16 RISK_GetMissionTypeOfPlayer(Int32 iPlayer); Int32 RISK_GetMissionNumberOfPlayer(Int32 iPlayer); Int32 RISK_GetMissionContinent1OfPlayer(Int32 iPlayer); Int32 RISK_GetMissionContinent2OfPlayer(Int32 iPlayer); Int32 RISK_GetMissionPlayerToKillOfPlayer(Int32 iPlayer); Flag RISK_GetMissionIsPlayerKilledOfPlayer(Int32 iPlayer); CString RISK_GetNameOfCountry(Int32 iCountry); Int32 RISK_GetContinentOfCountry(Int32 iCountry); Int32 RISK_GetNumArmiesOfCountry(Int32 iCountry); Int32 RISK_GetOwnerOfCountry(Int32 iCountry); Int32 RISK_GetAdjCountryOfCountry(Int32 iCountry, Int32 iIndex); Int32 RISK_GetTextXOfCountry(Int32 iCountry); Int32 RISK_GetTextYOfCountry(Int32 iCountry); Int32 RISK_GetValueOfContinent(Int32 iContinent); CString RISK_GetNameOfContinent(Int32 iContinent); Int32 RISK_GetNumCountriesOfContinent(Int32 iContinent); Int32 RISK_GetNumLivePlayers(void); Int32 RISK_GetNumPlayers(void); /* The first (should-be-a) composite object in Frisk */ CString RISK_GetNameOfSpecies(Int32 iHandle); Int32 RISK_GetClientOfSpecies(Int32 iHandle); CString RISK_GetAuthorOfSpecies(Int32 iHandle); CString RISK_GetDescriptionOfSpecies(Int32 iHandle); CString RISK_GetVersionOfSpecies(Int32 iHandle); Int32 RISK_GetAllocationStateOfSpecies(Int32 iHandle); Int32 RISK_GetNumSpecies(void); void RISK_SetNameOfSpecies(Int32 iHandle, CString strName); void RISK_SetClientOfSpecies(Int32 iHandle, Int32 iClient); void RISK_SetAuthorOfSpecies(Int32 iHandle, CString strAuthor); void RISK_SetVersionOfSpecies(Int32 iHandle, CString strVersion); void RISK_SetDescriptionOfSpecies(Int32 iHandle, CString strDescription); void RISK_SetAllocationStateOfSpecies(Int32 iHandle, Int32 iState); void RISK_SetNumSpecies(Int32 iNumSpecies); #endif xfrisk-1.2/server.c0100644000175000017500000015474407033753241013374 0ustar johnojohno/* * XFrisk - The classic board game for X * Copyright (C) 1993-1999 Elan Feingold (elan@aetherworks.com) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * $Id: server.c,v 1.24 2000/01/02 22:52:17 tony Exp $ * * $Log: server.c,v $ * Revision 1.24 2000/01/02 22:52:17 tony * and a typo * * Revision 1.23 2000/01/02 22:51:23 tony * oops :-) still told hostname to clients * * Revision 1.22 1999/12/25 23:19:01 morphy * Yet more comments. * * Revision 1.21 1999/12/25 23:12:20 morphy * More comments on functions * * Revision 1.20 1999/12/25 22:03:36 morphy * Doxygen comments, removed 3 commented out functions * * */ /** \file * Server main loop and associated functionality. */ #include #include #include #ifdef _AIX #include #endif #include #include #include #include #include #include #include #include #include #include "language.h" #include "types.h" #include "riskgame.h" #include "network.h" #include "server.h" #include "deck.h" #include "debug.h" #include "version.h" #include "clients.h" /* Move this to the Imakefile!! */ #ifdef __hpux #define FDSET int #else #define FDSET fd_set #endif /* This may be a static value (i.e. OPEN_MAX), or a dynamic value, * as in OSF/1, accessed through sysconf(). I'm not sure that all * systems have these, so we'll just guess. I don't think this is * exceptionally evil, since if we run out of descriptors, the socket * or accept calls will fail. */ #if 0 #define MAX_DESCRIPTORS 128 #endif static Int32 iServerCommLink; /**< Server socket */ static Int32 iState; /**< */ static fd_set fdSet; /**< Client socket states */ static fd_set fdBackup; /**< Client socket states backup */ static Deck *pPlayerDeck = NULL; /**< Deck of free player ids */ static Deck *pCardDeck; /**< Card deck */ static Int32 iReply; /**< ??? */ static Int32 iMaxFileDescUsed = -1; /**< ??? */ static Int32 iServerMode = SERVER_REGISTERING; /**< ??? */ static Flag fGameReset = TRUE; /**< ??? */ static Flag fRememberKilled = FALSE; /**< ??? */ static Int32 iTurn; /**< ??? */ static Int32 iFirstPlayer; /**< ??? */ /* Private functions */ void SRV_ResetGame(void); void SRV_ReplicateRegistrationData(Int32 iCommLinkDest); void SRV_ReplicateAllData(Int32 iCommLinkDest); void SRV_AttemptNewGame(void); void SRV_DistributeCountries(void); Flag SRV_DistributeMissions(void); void SRV_SetInitialArmiesOfPlayers(void); void SRV_SetInitialMissionOfPlayers(void); void SRV_NotifyClientsOfTurn(Int32 iTurn); void SRV_HandleRegistration(Int32 iCommLink); void SRV_HandleSignals(Int32 iParam); void UTIL_ExitProgram(Int32 iExitValue); Int32 SRV_IterateTurn(void); /* Server message handlers */ void SRV_HandleEXIT(Int32 iExitValue); void SRV_HandleALLOCPLAYER(Int32 iClient); void SRV_HandleFREEPLAYER(void *pvMessage); void SRV_HandleREPLYPACKET(void *pvMessage); void SRV_HandleMESSAGEPACKET(Int32 iClient, void *pvMessage); void SRV_HandleENTERSTATE(void *pvMessage); void SRV_HandleDEREGISTERCLIENT(Int32 iClient); /** * Server initialization (signal handling, creating server socket, ...) * * \b History: * \arg 01.23.94 ESF Created. * \arg 02.22.94 ESF Cleaned up a bit, removing warnings. * \arg 05.08.94 ESF Fixed MSG_MESSAGEPACKET handling. * \arg 05.10.94 ESF Fixed, not registering needed callback with DistObj. * \arg 05.12.94 ESF Added fd usage map. * \arg 05.19.94 ESF Fixed bug, passing &pvMessage instead of pvMessage. * \arg 08.16.94 ESF Cleaned up. * \arg 10.01.94 ESF Added initialization of failures. * \arg 11.11.99 TdH Added call to CLIENTS_Init */ void SRV_Init(void) { struct sockaddr_in server; /* Print an informative message */ printf("%s: %s %s\n",SERVERNAME,SERVER_STARTING ,VERSION); /* Catch signals so that we can clean up upon termination */ signal(SIGHUP, SRV_HandleSignals); signal(SIGINT, SRV_HandleSignals); signal(SIGQUIT, SRV_HandleSignals); signal(SIGILL, SRV_HandleSignals); signal(SIGTRAP, SRV_HandleSignals); signal(SIGFPE, SRV_HandleSignals); signal(SIGKILL, SRV_HandleSignals); signal(SIGBUS, SRV_HandleSignals); signal(SIGTERM, SRV_HandleSignals); /* We want to ignore this signal, because we don't want a I/O * failure to terminate the program. */ signal(SIGPIPE, SIG_IGN); /* Init. clients and players */ CLIENTS_Init(); /* Initialize the pool of free players */ pPlayerDeck = DECK_Create(MAX_PLAYERS); /* Create server socket */ if ((iServerCommLink = socket(AF_INET, SOCK_STREAM, 0)) < 0) { perror("Creating CommLink"); UTIL_ExitProgram(1); } /* Update the max */ iMaxFileDescUsed = MAX(iMaxFileDescUsed, iServerCommLink); /* Name sockets using wildcards */ server.sin_family = AF_INET; server.sin_addr.s_addr = INADDR_ANY; server.sin_port = htons(RISK_PORT); /* Bind the socket to the port */ if (bind(iServerCommLink, (struct sockaddr *)&server, sizeof(server))) { printf("%s: Frisk port %d %s\n",SERVERNAME,RISK_PORT,ERR_PORT_IN_USE); UTIL_ExitProgram(1); } /* Add the socket options to the socket */ NET_SetCommLinkOptions(iServerCommLink); } /** * Broadcasts the given textual message to all clients * * \b History: * \arg 01.26.94 ESF Created. * \arg 01.15.95 ESF Initialized .iTo field to avoid uninitialized memory. */ void SRV_BroadcastTextMessage(CString strMessage) { MsgMessagePacket msgMess; msgMess.strMessage = strMessage; msgMess.iFrom = FROM_SERVER; msgMess.iTo = DST_ALLPLAYERS; /* Send the message out to all clients */ SRV_BroadcastMessage(MSG_MESSAGEPACKET, &msgMess); } /** * Main server message handler. Branches to message specific handlers. * * \b History: * \arg x.10.99 TdH took this bit out of SRV_PlayGame * * \bug morphy got -1 cards :-) has to do with greenland being #0 * \bug (MSH 25.12.99) This function is humongous - perhaps a better way exists? */ int SRV_HandleMessage(Int32 iClient, Int32 iMessageType, void * pvMessage) { Int32 n; char buf[256]; /* Depending on the message type, dispatch it to one * of the handlers. They usually take just a message, * but depending on what they do they could take the * and/or the client index. */ D_Assert(iClient <= MAX_CLIENTS, "client > MAX_CLIENTS"); switch (iMessageType) { case MSG_NETMESSAGE: case MSG_DICEROLL: case MSG_PLACENOTIFY: case MSG_ATTACKNOTIFY: case MSG_MOVENOTIFY: SRV_CompleteBroadcast(iClient, iMessageType, pvMessage); break; case MSG_ENDOFMISSION: case MSG_VICTORY: SRV_BroadcastMessage(iMessageType, pvMessage); break; case MSG_MISSION: if (SRV_DistributeMissions()) SRV_BroadcastMessage(iMessageType, pvMessage); break; case MSG_ENDOFGAME: iServerMode = SERVER_REGISTERING; /* Let everyone else know */ SRV_BroadcastMessage(MSG_ENDOFGAME, NULL); SRV_ResetGame(); break; case MSG_ALLOCPLAYER: SRV_HandleALLOCPLAYER(iClient); break; case MSG_FREEPLAYER: SRV_HandleFREEPLAYER(pvMessage); break; case MSG_REPLYPACKET: SRV_HandleREPLYPACKET(pvMessage); break; case MSG_MESSAGEPACKET: SRV_HandleMESSAGEPACKET(iClient, pvMessage); break; /* Mark the client as started */ case MSG_STARTGAME: CLIENTS_SetStartState(iClient, TRUE); /* Informative message */ /* should tell which player, not easy*/ printf("%s: %s %s\n",SERVERNAME,CLIENTS_GetAddress(iClient),FINISHED_REGISTRY); snprintf(buf,sizeof(buf),"%s: %s %s", SERVERNAME,NEW_CLIENT,FINISHED_REGISTRY); SRV_BroadcastTextMessage(buf); if (iServerMode == SERVER_REGISTERING) { /* Reset the game, and possible start it */ SRV_ResetGame();/*will only reset if not already done...*/ /* The first AI-Client can't start the game */ if ( (CLIENTS_GetType(iClient) != CLIENT_AI) || (CLIENTS_GetNumClientsStarted() > 1)) SRV_AttemptNewGame(); } else { /* Some random client tried to start in the middle * of a game, probably an overeager AI client. */ SRV_BroadcastTextMessage("somebody tried to join after game was started"); printf("client %s tried to join after game started\n",CLIENTS_GetAddress(iClient)); } break; case MSG_DEREGISTERCLIENT: /* Do the actual deregistration */ SRV_HandleDEREGISTERCLIENT(iClient); /* Informative message */ sprintf(buf,"%s: %s %s\n",SERVERNAME,CLIENTS_GetAddress(iClient),HAS_DEREGISTERED); printf(buf); SRV_BroadcastTextMessage("A client has deregistered"); break; case MSG_ENDTURN: { Int32 iPlayer; /* Sanity check */ D_Assert(RISK_GetNumLivePlayers(), "Modulo by zero!"); if (iServerMode == SERVER_FORTIFYING) { Int32 i; Flag fFoundPlayer; /* If noone has any more armies, then move to * SERVER_PLAYING mode. Otherwise, go along * the list of players, looking for a player who * still has armies to place. */ for (i=0, fFoundPlayer=FALSE; i!=RISK_GetNumLivePlayers() && !fFoundPlayer; i++) { /* The next player who's turn it is */ iPlayer = SRV_IterateTurn(); /* Is there a player with armies left? */ if (RISK_GetNumArmiesOfPlayer(iPlayer) != 0) { SRV_NotifyClientsOfTurn(iPlayer); fFoundPlayer = TRUE; } } /* If we have not found a player with armies, * then there are no longer any players with any * armies to fortify with. Let the game begin!! * Theorem (proof left to reader): When some * players have more armies to to fortify with * than others (because they got less countries), * then the last player to fortify here will be * the last player in relation to the first player * who fortified. So if we move to the next * player, it will be the player who fortified * first, which is what we want. * * This theorem is false when you use bpk's * multiple-fortify hack. See my comment in * SRV_AttemptNewGame. --Pac. */ if (!fFoundPlayer) { iServerMode = SERVER_PLAYING; iPlayer = iTurn = iFirstPlayer; SRV_NotifyClientsOfTurn(iPlayer); } } else { /* iServerMode == SERVER_PLAYING */ /* Get the next player */ iPlayer = SRV_IterateTurn(); SRV_NotifyClientsOfTurn(iPlayer); } } break; case MSG_ENTERSTATE: SRV_HandleENTERSTATE(pvMessage); break; case MSG_EXCHANGECARDS: {/*went wrong for morphy, he got -1 cards */ MsgExchangeCards *pMess = (MsgExchangeCards *)pvMessage; MsgReplyPacket msgMess; Int32 iNumJokers; /* Put cards back on the deck and change them to type */ for (n=iNumJokers=0; n!=3; n++) { DECK_PutCard(pCardDeck, pMess->piCards[n]); if (pMess->piCards[n] < NUM_COUNTRIES) pMess->piCards[n] %= 3; else pMess->piCards[n] = -1, iNumJokers++; } /* Find out how many armies the player gets in * exchange for the cards and send them to him or * her, in an _UPDATEARMIES message. Right now * the only option is fixed return values for card * exchanges. */ /* Do we have one of each (possibly with jokers)? */ if ((pMess->piCards[0] != pMess->piCards[1] && pMess->piCards[1] != pMess->piCards[2] && pMess->piCards[0] != pMess->piCards[2]) || iNumJokers >= 2) { msgMess.iReply = 10; } else if (pMess->piCards[0]==0 || pMess->piCards[1]==0 || pMess->piCards[2]==0) { msgMess.iReply = 8; } else if (pMess->piCards[0]==1 || pMess->piCards[1]==1 || pMess->piCards[2]==1) { msgMess.iReply = 6; } else { msgMess.iReply = 4; } (void)RISK_SendMessage(CLIENTS_GetCommLinkOfClient(iClient), MSG_REPLYPACKET, &msgMess); } break; case MSG_REQUESTCARD: { MsgRequestCard *pMess = (MsgRequestCard *)pvMessage; RISK_SetCardOfPlayer(pMess->iPlayer, RISK_GetNumCardsOfPlayer (pMess->iPlayer), DECK_GetCard(pCardDeck)); RISK_SetNumCardsOfPlayer(pMess->iPlayer, RISK_GetNumCardsOfPlayer (pMess->iPlayer)+1); } break; case MSG_FORCEEXCHANGECARDS: { Int32 iPlayer ; iPlayer = ((MsgForceExchangeCards *)pvMessage)->iPlayer; if (RISK_GetNumCardsOfPlayer(iPlayer) < 5) ((MsgForceExchangeCards *)pvMessage)->iPlayer = -1; (void)RISK_SendMessage(CLIENTS_GetCommLinkOfClient(iClient), MSG_FORCEEXCHANGECARDS, pvMessage); } break; case MSG_EXIT: SRV_HandleEXIT(0); break; case MSG_NOMESSAGE: break; default: { MsgNetPopup msg; /* Assume that client is messed up. Consider it * a failure and kill the client. */ printf("%s: %s %s: %s",SERVERNAME,CLIENT,CLIENT_DEAD,INVALID_MESSAGE); msg.strMessage = buf; (void)RISK_SendMessage(CLIENTS_GetCommLinkOfClient(iClient), MSG_NETPOPUP, &msg); /* Log the failure */ SRV_LogFailure("Sent bogus message", CLIENTS_GetCommLinkOfClient(iClient)); } /* Free up the memory the message was taking */ NET_DeleteMessage(iMessageType, pvMessage); /* broken D_Assert(iClient != MAX_CLIENTS && fHandledMessage == TRUE, "Message received from unknown source!!"); */ } return(0); } /** * Server main loop - 'Play the game' * * \b History: * \arg 02.04.94 ESF Created. * \arg 02.05.94 ESF Fixed broadcast loop bug. * \arg 02.05.94 ESF Fixed message receive bug. * \arg 03.03.94 ESF Changed to send _UPDATE to all clients but sender. * \arg 03.28.94 ESF Added _DEADPLAYER & _ENDOFGAME. * \arg 03.29.94 ESF Added _REQUESTCARD. * \arg 04.01.94 ESF Fixed card exchange to work right with jokers. * \arg 04.11.94 ESF Fixed CARDPACKET to broadcast the card. * \arg 05.05.94 ESF Added MSG_OBJ* msgs. * \arg 05.06.94 ESF Factored out dealing cards code. * \arg 05.15.94 ESF Added MSG_[ALLOC|FREE]PLAYER. * \arg 05.15.94 ESF Added MSG_REPLYPACKET. * \arg 05.17.94 ESF Added MSG_NETMESSAGE. * \arg 06.24.94 ESF Fixed memory leak bug. * \arg 07.27.94 ESF Completely revamped, combined with CollectPlayers(). * \arg 09.31.94 ESF Fixed so that a new deck is created upon reset. * \arg 10.01.94 ESF Fixed MSG_ENDOFGAME to pass message and not NULL. * \arg 10.02.94 ESF Fixed so in case of bogus message, client is killed. * \arg 10.03.94 ESF Fixed bug, excessive processing of MSG_DEREGISTERCLIENT. * \arg 10.08.94 ESF Added SERVER_FORTIFYING mode to fix a bug. * \arg 10.29.94 ESF Added handling for MSG_DICEROLL. * \arg 10.30.94 ESF Fixed serious bug: SERVER[_REGISTERING -> _FORTIFYING]. * \arg 25.08.95 JC Don't call perror if errno is equal to 4. * \arg 28.08.95 JC Added handling for MSG_ENDOFMISSION and MSG_VICTORY. * \arg 30.08.95 JC Added handling for MSG_FORCEEXCHANGECARDS. * \arg 30.08.95 JC The first AI-Client can't start the game, but other * AI-Client can do this for computer's battles. * \arg 14.06.97 DAH Don't use errno "4", use EINTR */ void SRV_PlayGame(void) { Int32 iClient, iMessageType, iError; void *pvMessage; /* Create the card deck */ pCardDeck = DECK_Create(NUM_COUNTRIES + 2); /* Add the initial fd to keep an eye on -- the connect socket */ FD_ZERO(&fdBackup); FD_SET(iServerCommLink, &fdBackup); /* Start accepting connections */ listen(iServerCommLink, 5); /* Loop for the entirety of the game */ for(;;) { fdSet = fdBackup; /* If there have been any failures, then deal with them */ SRV_RecoverFailures(); /* Wait for a message to come in */ if (select(iMaxFileDescUsed+1, (FDSET *)&fdSet, (FDSET *)0, (FDSET *)0, NULL) < 0) /* errno = EINTR is caused by SRV_HandleSignals */ if (errno != EINTR) perror("Select"); /* Two things might have happened here. Either an existing client * sent a message to the server, or a new client sent a message to * the connect port, trying to join the game. If the former occurred * process it normally. If the latter occurred, let the client * connect, and add its fd to the fd map. If we are in the middle * of a game, send it a message saying this, and then perform a * RISK_SelectiveReplicate() so as to get the new client in the * same state as the others. Also send a message to the other * clients telling them what is happening. */ if (FD_ISSET(iServerCommLink, &fdSet)) { /* new client trying to connect */ Int32 iNewCommLink; /* Try to accept the new connection */ if ((iNewCommLink = accept(iServerCommLink, 0, 0)) < 0) { /* Couldn't do it, go back to top */ printf("%s %s\n",SERVERNAME,SERVER_CONNECT_FAILED); continue; } else {/* connection went fine */ /* Does Frisk have enough resources to hold this client? */ if (CLIENTS_GetNumClients() >= MAX_CLIENTS || iNewCommLink >= MAX_DESCRIPTORS) { (void)RISK_SendMessage(iNewCommLink, MSG_EXIT, NULL); close(iNewCommLink); continue; } } /* Assert: At this point, connection is complete and we have * enough resources to keep it around. Begin connection protocol. */ /* Set options on new CommLink */ NET_SetCommLinkOptions(iNewCommLink); SRV_HandleRegistration(iNewCommLink); } else {/* no FD_ISSET, there is a client trying to send a message */ for (iClient=0; iClient < MAX_CLIENTS ; iClient++) { if (CLIENTS_GetAllocationState(iClient) == ALLOC_COMPLETE && FD_ISSET(CLIENTS_GetCommLinkOfClient(iClient), &fdSet)) { if (!RISK_ReceiveMessage(CLIENTS_GetCommLinkOfClient(iClient), &iMessageType, &pvMessage)) continue; if ( (iError = SRV_HandleMessage(iClient,iMessageType,pvMessage)) != 0) { printf("error %d when handling messagetype %d from %s\n",iError,iMessageType,CLIENTS_GetAddress(iClient)); } break; } } } } } /** * Notify all clients of turn change * * \b History: * \arg 08.27.94 ESF Created. * \arg 30.08.95 JC Send a message if the player have too many cards. * \arg 25.12.99 MSH Functionality of previous entry seems to have vanished */ void SRV_NotifyClientsOfTurn(Int32 iPlayer) { MsgTurnNotify msgTurnNotify; /* Let all clients know whos turn it is */ msgTurnNotify.iPlayer = iPlayer; msgTurnNotify.iClient = RISK_GetClientOfPlayer(iPlayer); SRV_BroadcastMessage(MSG_TURNNOTIFY, &msgTurnNotify); } /** * Distribute countries among live players. * * \b History: * \arg 05.12.94 ESF Created. * \arg 07.25.94 ESF Changed to support TEST_GAMEs. * \arg 10.30.94 ESF Changed to support TEST_GAMEs better. * \arg 10.30.94 ESF Changed to refer to LivePlayer instead of Player. */ void SRV_DistributeCountries(void) { Deck *pCountryDeck = DECK_Create(NUM_COUNTRIES); Int32 iCountry, iPlayer, i; /* Dole out the countries */ for(i=0; i!=NUM_COUNTRIES; i++) { /* Pick a country, any country */ iCountry = DECK_GetCard(pCountryDeck); #ifdef TEST_GAME /* Give countries to the first player, leave one for the rest */ iPlayer = (i <= NUM_COUNTRIES-RISK_GetNumLivePlayers()) ? RISK_GetNthLivePlayer(0) : RISK_GetNthLivePlayer(i-(NUM_COUNTRIES-RISK_GetNumLivePlayers())); #else iPlayer = iTurn; #endif /* Update the game object */ RISK_SetOwnerOfCountry(iCountry, iPlayer); RISK_SetNumCountriesOfPlayer(iPlayer, RISK_GetNumCountriesOfPlayer(iPlayer)+1); RISK_SetNumArmiesOfCountry(iCountry, 1); RISK_SetNumArmiesOfPlayer(iPlayer, RISK_GetNumArmiesOfPlayer(iPlayer)-1); /* Iterate to next player */ (void)SRV_IterateTurn(); } #ifdef TEST_GAME /* Set the number of armies to be small, to let the game start soon. */ for (i=0; i!=RISK_GetNumLivePlayers(); i++) RISK_SetNumArmiesOfPlayer(RISK_GetNthLivePlayer(i), 2); #endif DECK_Destroy(pCountryDeck); } /** * Calculate number of armies given to each player at game start * * \b History: * \arg 08.27.94 ESF Created. * \arg 12.07.95 ESF Fixed initial number of armies to be by the rules. * * \bug Part of rules is hardcoded here */ void SRV_SetInitialArmiesOfPlayers(void) { Int32 i, iPlayer, iNumArmies; const Int32 iNumPlayers = RISK_GetNumPlayers(); D_Assert(iNumPlayers >= 2, "Not enough players!"); /* Calculate the number of armies. */ iNumArmies = MAX( 50 - iNumPlayers*5, /* According to the rules */ NUM_COUNTRIES/iNumPlayers+1 ); /* At least one per country */ /* Make sure it's enough */ D_Assert(iNumPlayers*iNumArmies >= NUM_COUNTRIES, "Not enough armies!"); /* Set the initial number of armies for all the players */ for (i=0; i 0, "Number of armies is negative!"); } } /** * Set initial mission of all players to "no mission" * * \b History: * \arg 24.08.95 JC Created. */ void SRV_SetInitialMissionOfPlayers(void) { Int32 i, iPlayer, nb; nb = RISK_GetNumPlayers(); /* Set the initial mission's type for all the players */ for (i=0; iiReply; } /** * Handles player resignation during game. * \bug Terminates the game - recovery procedures needed! * * \b History: * \arg 06.10.94 ESF Created. * \arg 10.15.94 ESF Fixed a bug, only Set LivePlayers if player is alive. * \arg 11.06.94 ESF Fixed a bug, return player's cards to server. */ void SRV_HandleFREEPLAYER(void *pvMessage) { Int32 iPlayer, i; char buf[256]; /* Put the player ID back onto pool of free players */ iPlayer = ((MsgFreePlayer *)(pvMessage))->iPlayer; DECK_PutCard(pPlayerDeck, iPlayer); /* If the player has cards at this point, take them away and put * them back onto the card deck. */ for (i=0; i!=RISK_GetNumCardsOfPlayer(iPlayer); i++) DECK_PutCard(pCardDeck, RISK_GetCardOfPlayer(iPlayer, i)); /* Details, details... */ RISK_SetAllocationStateOfPlayer(iPlayer, ALLOC_NONE); /* If there were no live players at the client then we can let it go * without ending the game. Otherwise, end the game if we're in the * PLAY or FORTIFICATION stages of the game. If the number of live * players went down to 0, then we must go back to registering mode. * Kind of moot, but safe... */ /* Was the player alive? */ if (RISK_GetStateOfPlayer(iPlayer) == PLAYER_ALIVE && (iServerMode == SERVER_PLAYING || iServerMode == SERVER_FORTIFYING)) { MsgNetPopup msgNetPopup; /* Informative message */ snprintf(buf, sizeof(buf),GAME_OVER); msgNetPopup.strMessage = buf; SRV_BroadcastMessage(MSG_NETPOPUP, &msgNetPopup); /* There was no winner, reset the game */ SRV_BroadcastMessage(MSG_ENDOFGAME, NULL); /* It was the end of the game, so reset things */ SRV_ResetGame(); } else if (RISK_GetNumLivePlayers() == 0) SRV_ResetGame(); } /** * Sends message from client to all clients, all but originator or * specified recipient. * * \b History: * 06.10.94 ESF Created. */ void SRV_HandleMESSAGEPACKET(Int32 iClient, void *pvMessage) { MsgMessagePacket *pMess = (MsgMessagePacket *)pvMessage; if (pMess->iTo == DST_ALLPLAYERS) SRV_BroadcastMessage(MSG_MESSAGEPACKET, pvMessage); else if (pMess->iTo == DST_ALLBUTME) SRV_CompleteBroadcast(iClient, MSG_MESSAGEPACKET, pvMessage); else (void)RISK_SendMessage(CLIENTS_GetCommLinkOfClient( RISK_GetClientOfPlayer(pMess->iTo)), MSG_MESSAGEPACKET, pvMessage); } /** * Saves distributed server object state received from client. * \bug (MSH 25.12.99) Will figure out a better way to do this. * * \b History: * \arg 06.10.94 ESF Created. */ void SRV_HandleENTERSTATE(void *pvMessage) { iState = ((MsgEnterState *)pvMessage)->iState; } /** * Helper macro for cleaning up aborted registration process. */ #define _SRV_CleanupRegistration() \ /* NET_DeleteMessage(iMessType, pvMess); */ \ FD_CLR(iCommLink, &fdBackup);\ close(iCommLink); /** * Handles registration of a new client. * \b Note: contains code for connection re-estabilishment (???) * * \b History: * \arg 06.10.94 ESF Created. * \arg 08.31.94 ESF Changed to use only one socket. * \arg 09.28.94 ESF Fixed to handle errant clients correctly (free 'em). * \arg 09.28.94 ESF Fixed the process of filling in the new clients. * \arg 09.31.94 ESF Added notification of current turn for new clients. * \arg 10.01.94 ESF Fixed to check for failure of ReceiveMessage. * \arg 10.15.94 ESF Fixed, was freeing client that I wasn't allocating. * \arg 10.30.94 ESF Added quotes to the "A new client..." message. * \arg 01.01.95 ESF Fixed a bug in notifying clients of current player. * \arg 01.15.95 ESF Initilized iTo field to avoid uninitialized memory. * \arg 01.15.95 ESF Fixed memory leak. * \arg 02.21.95 ESF Add support for computer players. * \arg 02.21.95 ESF Cleaned up, fixed minor bugs. * \arg 25.08.95 JC Add || (RISK_GetNumSpecies() > 1) because the * presence of AI-Client which have no player. */ void SRV_HandleRegistration(Int32 iCommLink) { Int32 iMessType; MsgClientIdent msgClientIdent; MsgVersion msgVersion; MsgMessagePacket msgMess; void *pvMess, *pvDeleteMe = NULL; Int32 iNewClient, iClientType = CLIENT_NORMAL; Int32 iClientSpecies = SPECIES_HUMAN; Flag fOldClient = FALSE; CString strClientAddress; char buf[256]; /* The Protocol: * * Receive MSG_HELLO --> OK! * Other --> Protocol bogosity. * Send MSG_VERSION. * Receive MSG_REGISTERCLIENT --> OK! * MSG_VERSION --> Version mismatch. * Other --> Protocol bogosity. * Send MSG_CLIENTIDENT if server is not full. * Send MSG_CLIENTEXIT if server is full. */ /* It should be a MSG_HELLO! */ if (!RISK_ReceiveMessage(iCommLink, &iMessType, &pvMess) || (iMessType != MSG_HELLO && iMessType != MSG_OLDREGISTERCLIENT)) { printf("%s: %s %d %s\n",SERVERNAME,ERROR_PROTOCOL,iMessType,IGNORE_CLIENT); _SRV_CleanupRegistration(); return; } /* See if it's an old client */ fOldClient = (iMessType == MSG_OLDREGISTERCLIENT); /* If it is an old client, then get its name */ if (fOldClient) { strClientAddress = ((MsgOldRegisterClient *)pvMess)->strClientAddress; /* Mark this message for future deletion */ pvDeleteMe = pvMess; } else NET_DeleteMessage(MSG_HELLO, pvMess); /* If we're talking to a new client, send the version information */ if (!fOldClient) { /* Send the version */ msgVersion.strVersion = VERSION; (void)RISK_SendMessage(iCommLink, MSG_VERSION, &msgVersion); /* It should be a MSG_REGISTERCLIENT or a MSG_VERSION! */ if (!RISK_ReceiveMessage(iCommLink, &iMessType, &pvMess) || iMessType != MSG_REGISTERCLIENT) { if (iMessType == MSG_VERSION) printf("%s: %s (%s)\n",SERVERNAME,CLIENT_MISMATCH,((MsgVersion *)pvMess)->strVersion); else printf("%s: %s (%d) %s\n",SERVERNAME,ERROR_PROTOCOL,iMessType,IGNORE_CLIENT); _SRV_CleanupRegistration(); return; } /* Now we know the name (and type) of the client */ strClientAddress = ((MsgRegisterClient *)pvMess)->strClientAddress; iClientType = ((MsgRegisterClient *)pvMess)->iClientType; } /* If the client is an "AI" client, then send it the * dynamic ID of its species, which we allocate on-the-fly. */ if (iClientType == CLIENT_AI) { MsgSpeciesIdent msg; iClientSpecies = msg.iSpeciesID = SRV_AllocSpecies(); (void)RISK_SendMessage(iCommLink, MSG_SPECIESIDENT, &msg); } /* Get the handle to a new client */ iNewClient = CLIENTS_Alloc(); /* Did the allocation fail? */ if (iNewClient == -1) { printf("%s: %s\n",SERVERNAME,NO_ROOM); (void)RISK_SendMessage(iCommLink, MSG_EXIT, NULL); _SRV_CleanupRegistration(); return; } /* Send its ID */ msgClientIdent.iClientID = iNewClient; (void)RISK_SendMessage(iCommLink, MSG_CLIENTIDENT, &msgClientIdent); printf("%s: %s \"%s\" %s\n",SERVERNAME,NEW_CLIENT,strClientAddress, HAS_REGISTERED); /* Set up its fields */ CLIENTS_SetCommLink(iNewClient, iCommLink); CLIENTS_SetAddress(iNewClient, strClientAddress); CLIENTS_SetType(iNewClient, iClientType); CLIENTS_SetSpecies(iNewClient, iClientSpecies); /* Remember to look for messages from it with select(), * and update the maximum file descriptor. */ FD_SET(iCommLink, &fdBackup); iMaxFileDescUsed = MAX(iMaxFileDescUsed, iCommLink); /* Let the new client know about old clients, if needed */ /* should be passed client...*/ CLIENTS_TellAboutOthers(iCommLink,iClientType); /* Let all other clients know about it */ snprintf(buf, sizeof(buf),"%s %s",iClientType == CLIENT_AI ? NEW_AI:NEW_CLIENT,HAS_REGISTERED); msgMess.strMessage = buf; msgMess.iFrom = FROM_SERVER; msgMess.iTo = DST_OTHER; SRV_CompleteBroadcast(iNewClient, MSG_MESSAGEPACKET, &msgMess); /* And tell the client that just joined about itself */ snprintf(buf, sizeof(buf),"%s \"%s\".",HELLO_NEW,CLIENTS_GetAddress(iNewClient)); RISK_SendMessage(CLIENTS_GetCommLinkOfClient(iNewClient), MSG_MESSAGEPACKET, &msgMess); /* Tell the new client to pop up its registration box, if we * are not in game playing mode. */ if (iServerMode == SERVER_REGISTERING && iClientType != CLIENT_AI) (void)RISK_SendMessage(iCommLink, MSG_POPUPREGISTERBOX, NULL); /* If there are any players, let the new client * know about them, so that it can set up the * colors and other things. */ if (RISK_GetNumPlayers() || (RISK_GetNumSpecies() > 1)) { /* Let the clients know the situation */ snprintf(buf, sizeof(buf),"%s %s",CLIENT,BEING_UPDATED); SRV_BroadcastTextMessage(buf); if (iServerMode == SERVER_REGISTERING) SRV_ReplicateRegistrationData(iCommLink); else if (iServerMode == SERVER_PLAYING || iServerMode == SERVER_FORTIFYING) { MsgTurnNotify msgTurnNotify; SRV_ReplicateAllData(iCommLink); /* Let the client know who's turn it is currently */ msgTurnNotify.iPlayer = iTurn; msgTurnNotify.iClient = RISK_GetClientOfPlayer(msgTurnNotify.iPlayer); (void)RISK_SendMessage(iCommLink, MSG_TURNNOTIFY, &msgTurnNotify); } } /* Don't need these anymore */ if (pvDeleteMe) NET_DeleteMessage(MSG_OLDREGISTERCLIENT, pvDeleteMe); else NET_DeleteMessage(MSG_REGISTERCLIENT, pvMess); } /** * Handles client deregistration. * * \b History: * \arg 06.10.94 ESF Created. * \arg 08.31.94 ESF Revamped, made more sophisticated. * \arg 09.30.94 ESF Fixed bug, freeing player before MSG_DELETEMSGDST. * \arg 09.31.94 ESF Fixed so that FreeClient is called last. * \arg 10.01.94 ESF Fixed so that it doesn't return too soon. * \arg 01.15.95 ESF Removed MSG_DELETEMSGDST stuff. * \arg 01.24.95 ESF Fixed bug, reset iServerMode if SRV_NumClients()==1. */ void SRV_HandleDEREGISTERCLIENT(Int32 iClient) { /* * This isn't used and the operation has no side effects... * const Int32 iNumPlayersOfClient = RISK_GetNumLivePlayersOfClient(iClient); */ D_Assert(iClient>=0 && iClient=0 :) * \arg 09.14.94 ESF Fixed to deal with iNumClientsStarted. * \arg 03.25.95 ESF Added species considerations. * \arg 24.08.95 JC Quit if no client and fRememberKilled == TRUE. * * \b Notes: * \arg tony: to move to clients.c, fdbackup is problem */ void SRV_FreeClient(Int32 iClient) { Int32 i, iNumPlayers; MsgFreePlayer msgFreePlayer; /* Get rid of the client. We do this first so that broadcasts * won't include this client. This would normally result in * a SIGPIPE, if the exiting client had already shut down its * sockets, but since we ignore SIGPIPE, it would result in * a failed broadcast, which is technically wrong. */ CLIENTS_SetAllocationState(iClient, ALLOC_NONE); CLIENTS_SetNumClients(CLIENTS_GetNumClients()-1); /* Note that the client won't be participating in the game */ CLIENTS_SetStartState(iClient, FALSE); /* Reset the fields, close the sockets */ close(CLIENTS_GetCommLinkOfClient(iClient)); /* Remove the socket from the fd_set */ FD_CLR(CLIENTS_GetCommLinkOfClient(iClient), &fdBackup); /* Free all of the players at the client that is being nixed. * The client would call CLNT_FreePlayer to do this, which * is an RPC type call that sends MSG_FREEPLAYER to the * server (that's me!) So what we do here is manufacture a * MSG_FREEPLAYER and call the handler for it. A bit roundabout, * perhaps, but nevertheless a consistant way of dealing with * freeing players. Could probably be improved. Notice that * we get the Nth player, and _not_ the Nth live player. * Note also, that freeing a player has the side effect of * changing the value of RISK_GetNumPlayers(). */ iNumPlayers = RISK_GetNumPlayers(); for (i=iNumPlayers-1; i>=0; i--) if (RISK_GetClientOfPlayer(RISK_GetNthPlayer(i)) == iClient) { msgFreePlayer.iPlayer = RISK_GetNthPlayer(i); SRV_HandleFREEPLAYER((void *)&msgFreePlayer); } /* Additionally, if the client is an AI client, then we have to * remove the species from the list of species. */ if (CLIENTS_GetType(iClient) == CLIENT_AI) SRV_FreeSpecies(CLIENTS_GetSpecies(iClient)); if (fRememberKilled && (CLIENTS_GetNumClientsStarted() <= 0)) SRV_HandleEXIT(-1); if (iServerMode == SERVER_REGISTERING) { /* Reset the game, and possible start it */ SRV_ResetGame(); SRV_AttemptNewGame(); } } /** * Log a client failure. * * \b History: * \arg 10.01.94 ESF Created. */ void SRV_LogFailure(CString strReason, Int32 iCommLink) { const Int32 iClient = CLIENTS_GetCommLinkToClient(iCommLink); D_Assert(iClient >= -1 && iClient < MAX_CLIENTS, "Bogus client..."); /* This stops any more bogus messages from coming in from the * dead client, which probably has nothing interesting to say * anyway... */ FD_CLR(iCommLink, &fdBackup); /* If this is -1, then it is not a known client */ if (iClient == -1) { /* This shouldn't happen much */ printf(ERR_COMMFAILED); close(iCommLink); } else { /* Log the failure, to be dealt with later. */ CLIENTS_SetFailure(iClient,strReason); } } /** * Tries to recover all client failures. * * \b History: * \arg 08.28.94 ESF Created. * \arg 08.31.94 ESF Revised to do something. * \arg 09.29.94 ESF Fixed to deregister client in case of failure. * \arg 09.30.94 ESF Fixed to call the right deregistration function. * \arg 09.31.94 ESF Added MSG_NETMESSAGE to be sent also. * \arg 10.01.94 ESF Changed to reflect new failure handling. */ void SRV_RecoverFailures(void) { Int32 iClient; Int32 count; char buf[256]; /* An optimization */ if (CLIENTS_GetNumFailures() == 0) return; /* Go through all of the failures and handle them */ for (iClient=0; iClient!=MAX_CLIENTS; iClient++) if (CLIENTS_GetFailureCount(iClient) > 0) { MsgNetPopup msgNetPopup; MsgMessagePacket msgMessagePacket; /* It is in the list of clients, so we need to destroy it. * Make as if we received a MSG_DEREGISTERCLIENT. */ SRV_HandleDEREGISTERCLIENT(iClient); /* Tell the clients what's happening (N.B. this broadcast call * has to be made AFTER the CLIENTS_Free call, otherwise, the * broadcast will try to send a message to the client that * just failed, and we will enter a recursive situation.) */ count = CLIENTS_GetFailureCount(iClient); /* Information */ #ifdef ENGLISH snprintf(buf, sizeof(buf), "\"%s\" has failed (%d failure%s).", #endif #ifdef FRENCH snprintf(buf, sizeof(buf), "%s a échoué (%d échec%s)", #endif CLIENTS_GetFailureReason(iClient), count, count >1 ? "s" : ""); printf("%s: %s\n",SERVERNAME, CLIENTS_GetFailureReason(iClient)); msgNetPopup.strMessage = buf; SRV_BroadcastMessage(MSG_NETPOPUP, &msgNetPopup); msgMessagePacket.strMessage = buf; msgMessagePacket.iFrom = FROM_SERVER; msgMessagePacket.iTo = DST_ALLPLAYERS; SRV_BroadcastMessage(MSG_MESSAGEPACKET, &msgMessagePacket); /* Pheww... Finished. */ printf(TXT_HANDLED_FAILURE); CLIENTS_ResetFailure(iClient); } /* Reset this */ CLIENTS_SetNumFailures(0); } /** * Determines the next player to receive the turn. * * \b History: * \arg 10.29.94 ESF Created. * \arg 11.27.94 ESF Fixed a really stupid and serious bug. */ Int32 SRV_IterateTurn(void) { /* It may be that the player who's turn it just was killed a few * players, and the number of live players has gone down. The way * players are organized is as if they were stacked on one top of * the next, with the 0th live player at the bottom. In other words, * if the 2nd live player gets killed, then the 3rd live player becomes * the 2nd live player, etc. This is done so that one can loop from the * [0th -- NumLivePlayer()th] live player. However, when calculating * turns, this may screw us up. If is the 2nd live player's turn, and * during this turn the 1st live player gets killed, then the next turn * belongs to the 2nd live player (who used to be the 3rd live player). * So to calculate the next turn, we iterate through the players, NOT * the live players. We simply search for the next live player. In * case this sounds obvious, it probably is, but the code use to read: * "iTurn = (iTurn+1) % RISK_GetNumLivePlayers()" which is obviously wrong. */ do { /* Go to the next player, wrap-around if we're at the end */ iTurn = (iTurn+1) % MAX_PLAYERS; } while (RISK_GetStateOfPlayer(iTurn) == FALSE || RISK_GetAllocationStateOfPlayer(iTurn) != ALLOC_COMPLETE); /* Return the player who's turn it is */ return iTurn; } /** * Starts the allocation of a new species. * * \b History: * \arg 02.23.95 ESF Created. */ Int32 SRV_AllocSpecies(void) { /* Simply loop through the species looking for an empty slot. * Since they are created on demand, if the list is full, when * we get to the end the Dist. Obj. will build us a new one. */ Int32 i; for (i=0; RISK_GetAllocationStateOfSpecies(i) != ALLOC_NONE; i++) ; /* TwiddleThumbs */ /* Mark the species as allocated. Otherwise, if the requesting ai Client * hasn't done anything with the new species, and another ai Client * is asking for one, the first ai Client doesn't set the name to be * something non-NULL, then the server will return the SAME species * number -- race condition! */ RISK_SetAllocationStateOfSpecies(i, ALLOC_INPROGRESS); return i; } /** * Frees a species. * * \b History: * \arg 02.32.95 ESF Created. */ void SRV_FreeSpecies(Int32 i) { /* Reset the allocation state of the species */ RISK_SetAllocationStateOfSpecies(i, ALLOC_NONE); } /** * Restarts the game. * * \b History: * \arg 04.04.95 ESF Created. */ void SRV_ResetGame(void) { /* Things we have to do when a game is restarted: * 1. Set the server state to be SERVER_REGISTERING * 2. Actually reset the dist. obj. * 3. Create a new deck of cards. */ iServerMode = SERVER_REGISTERING; /* Reset the game if it has not been already reset */ if (!fGameReset) { RISK_ResetGame(); fGameReset = TRUE; /* Get a new deck, destroy the old one. */ DECK_Destroy(pCardDeck); pCardDeck = DECK_Create(NUM_COUNTRIES + 2); } } /** * Sanity checks and attempting to start a new game. * * \b History: * \arg 04.11.95 ESF Created. * \arg 30.08.95 JC if (iServerMode == SERVER_REGISTERING && ... ? */ void SRV_AttemptNewGame(void) { Int32 n, iIndex; /* See if we can start a game */ if ( (iServerMode != SERVER_REGISTERING) || (CLIENTS_GetNumClientsStarted() != CLIENTS_GetNumClients()) || (RISK_GetNumPlayers() < 2)) return; D_Assert(RISK_GetNumLivePlayers()>=2, "Bogus number of players!"); printf("%s: %s\n",SERVERNAME,BEGINNING); /* We're going to need to reset it before playing again, so mark this. */ fGameReset = FALSE; iServerMode = SERVER_FORTIFYING; SRV_SetInitialArmiesOfPlayers(); SRV_SetInitialMissionOfPlayers(); /* pacman sez: * Must choose a player to be "first" before choosing initial territories, * otherwise things won't go right. Example: with 5 players, the order of * things must be as follows: * 1. Every player gets 25 armies * 2. We go around choosing territories. When that's all done, the first * two players have 9 each and the other three players have 8 each. * 3. Enter "fortify" mode - AND IT IS NOW THE 3RD PLAYER'S TURN. To pick a * random player at this point is Wrong(TM). * 4. When the fortify mode is done, we'll be back at the first player * again. He gets to attack first. * This order might get disrupted during the fortify stage, if the clients * are using bpk's multiple-place patch. We must remember who was first to * undo this disruption and enter 4 with iTurn being what it should be, * Which is what it would have been if the clients had fortified * one-at-a-time, which is iFirstPlayer. */ iIndex = rand() % RISK_GetNumLivePlayers(); iTurn = iFirstPlayer = RISK_GetNthLivePlayer(iIndex); /* Dole out the countries */ SRV_DistributeCountries(); SRV_NotifyClientsOfTurn(iTurn); /* Reset this for the next time */ for (n=0; n!=MAX_CLIENTS; n++) if (CLIENTS_GetAllocationState(n) == ALLOC_COMPLETE) CLIENTS_SetStartState(n, FALSE); } xfrisk-1.2/server.h0100644000175000017500000000410407031507115013354 0ustar johnojohno/* * XFrisk - The classic board game for X * Copyright (C) 1993-1999 Elan Feingold (elan@aetherworks.com) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * $Id: server.h,v 1.6 1999/12/26 21:53:17 morphy Exp $ * * $Log: server.h,v $ * Revision 1.6 1999/12/26 21:53:17 morphy * Comment fixes, logical grouping & commenting of function prototypes * * Revision 1.5 1999/12/25 20:15:10 morphy * Added file comment and log header * * */ /** \file * Interface definitions for server */ #ifndef _SERVER #define _SERVER #include "types.h" /* Server states */ #define SERVER_REGISTERING 0 #define SERVER_FORTIFYING 1 #define SERVER_PLAYING 2 /* Initialization, reset and game startup */ void SRV_Init(void); void SRV_Reset(void); void SRV_PlayGame(void); /* Message broadcast & data replication */ void SRV_BroadcastTextMessage(CString strMessage); void SRV_BroadcastMessage(Int32 iMessType, void *pvMessage); void SRV_CompleteBroadcast(Int32 iClientExclude, Int32 iMessType, void *pvMess); void SRV_Replicate(Int32 iMessType, void *pvMess, Int32 iType, Int32 iSrc); /* Species handling */ Int32 SRV_AllocSpecies(void); void SRV_FreeSpecies(Int32 i); /* Client failure handling & cleanup */ void SRV_LogFailure(CString strReason, Int32 iCommLink); void SRV_RecoverFailures(void); void SRV_FreeClient(Int32 iClient); #endif xfrisk-1.2/serverMain.c0100644000175000017500000000341507031506557014171 0ustar johnojohno/* * XFrisk - The classic board game for X * Copyright (C) 1993-1999 Elan Feingold (elan@aetherworks.com) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * $Id: serverMain.c,v 1.5 1999/12/26 21:49:35 morphy Exp $ * * $Log: serverMain.c,v $ * Revision 1.5 1999/12/26 21:49:35 morphy * Doxygen comments. * */ /** \file * Server startup. */ #include #include #include "server.h" #include "riskgame.h" #include "debug.h" /** * Server startup function. * * \b History: * \arg 08.16.94 ESF Created. */ int main(void) { FILE *hLogFile=NULL; /* Startup the memory debugging system */ MEM_BootStrap("server-memory.log"); #ifdef LOGGING /* Open debugging log file */ if ((hLogFile = fopen("server.log", "w")) == NULL) { printf("Could not open \"server.log\" for writing, exiting..."); exit(-1); } #endif /* Initialize the distributed object */ RISK_InitObject(SRV_Replicate, NULL, NULL, SRV_LogFailure, hLogFile); /* Initialize the server and start things going */ SRV_Init(); SRV_PlayGame(); return(0); } /* EOF */ xfrisk-1.2/snprintf.c0100644000175000017500000000237007013357410013710 0ustar johnojohno/* * XFrisk - The classic board game for X * Copyright (C) 1993-1999 Elan Feingold (elan@aetherworks.com) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * $Id: snprintf.c,v 1.3 1999/11/13 21:58:32 morphy Exp $ */ #include #include #include /* * This is a not very good, but hopefully adequate, substitute for * snprintf. */ int snprintf(char *buf, size_t len, const char *fmt, ...) { int xlen; va_list ap; va_start(ap, fmt); xlen = vsprintf(buf, fmt, ap); assert(xlen==strlen(buf)); assert(xlen #include #include #include #include #include #include #include #include #include #include #include #include "utils.h" #include "network.h" #include "riskgame.h" #include "gui-vars.h" #include "client.h" #include "colormap.h" #include "callbacks.h" #include "game.h" #include "dice.h" #include "debug.h" #define MAX_LINES 5 #define MAX_DIGITS 3 #define MAX_STRING "888" /* Globals */ static Int32 iQueryResult; static Cursor cursorWait=0, cursorPlay=0; /* Private functions */ void UTIL_SetCountryBrightness(Int32 iCountry, Boolean fLight); /************************************************************************ * FUNCTION: UTIL_PrintArmies * HISTORY: * 01.28.94 ESF Created. * 02.05.94 ESF Added number centering (finally!) * 03.30.94 ESF Changed EXTRA_Y to be smaller. * 04.02.94 ESF Fixed font problem, not XSetFont'ing. * 05.05.94 ESF Fixed so that 0 armies doesn't print anything. * PURPOSE: * NOTES: ************************************************************************/ void UTIL_PrintArmies(Int32 iCountry, Int32 iNumArmies, Int32 iColor) { Int32 x, y, iWidth, iHeight; Char strNumber[4]; /* Is number of armies right? */ if (iNumArmies>999) { #ifdef ENGLISH (void)UTIL_PopupDialog("Warning", "UTIL: Too many armies", 1, "Ok", NULL, NULL); #endif #ifdef FRENCH (void)UTIL_PopupDialog("Attention", "UTIL: Trop d'armées", 1, "Oui", NULL, NULL); #endif return; } /* Setup what we want to print (could be empty) */ if (iNumArmies>0) snprintf(strNumber, sizeof(strNumber), "%d", iNumArmies); else snprintf(strNumber, sizeof(strNumber), " "); /* Erase the old number, assume three digits */ x = RISK_GetTextXOfCountry(iCountry); y = RISK_GetTextYOfCountry(iCountry); iHeight = (pFont->max_bounds.ascent + pFont->max_bounds.descent); iWidth = XTextWidth(pFont, MAX_STRING, MAX_DIGITS); /* Draw erasing rectangle on screen and pixmap */ XSetForeground(hDisplay, hGC, COLOR_QueryColor(COLOR_CountryToColor(iCountry))); XFillRectangle(hDisplay, hWindow, hGC, x, y-iHeight, iWidth, iHeight+1); XFillRectangle(hDisplay, pixMapImage, hGC, x, y-iHeight, iWidth, iHeight+1); /* Center the number, based on the number of digits */ if (strlen(strNumber)==1) x += iWidth/3; else if (strlen(strNumber)==2) x += iWidth/4; /* Finally draw the text in color requested. */ XSetForeground(hDisplay, hGC, iColor); XSetFont(hDisplay, hGC, pFont->fid); if (iNumArmies>=0) { XDrawString(hDisplay, hWindow, hGC, x, y, strNumber, strlen(strNumber)); XDrawString(hDisplay, pixMapImage, hGC, x, y, strNumber, strlen(strNumber)); } /* Flush the queue of requests */ XFlush(hDisplay); } /************************************************************************ * FUNCTION: UTIL_DisplayMessage * HISTORY: * 02.04.94 ESF Created. * 01.15.95 ESF Fixed memory leak. * 04.30.95 ESF Got rid of newlines in incoming message. * 04.30.95 ESF Improved multiline message handling. * 29.08.95 JC Put the newline in the beginning of the message. * 29.08.95 JC strFrom -> iFrom, added iTo. * PURPOSE: * NOTES: ************************************************************************/ void UTIL_DisplayMessage(Int32 iFrom, Int32 iTo, CString strMessage) { static Flag fFirst = TRUE; Int32 i, iCount; CString strOldMessage, strNewMessage; const char *strFrom = NULL, *strNewLine = "", *strTo = ""; int has_a_to = 1; size_t len; #ifdef ENGLISH const char *strToHead = "To "; #endif #ifdef FRENCH const char *strToHead = "à "; #endif /* Get the old text */ XtVaGetValues(wMsgText, XtNstring, &strOldMessage, NULL); /* Remove any newlines from new message */ for (i=0, iCount=strlen(strMessage); i!=iCount; i++) if (strMessage[i]=='\n') strMessage[i]=' '; /* Build up the new message */ if (fFirst) fFirst = FALSE; else strNewLine = "\n"; switch (iFrom) { case FROM_SERVER: #ifdef ENGLISH strFrom = "Server"; #endif #ifdef FRENCH strFrom = "Serveur"; #endif break; case FROM_UNKNOW: #ifdef ENGLISH strFrom = "Unknown"; #endif #ifdef FRENCH strFrom = "Inconnu"; #endif break; default: D_Assert(iFrom >= -1 && iFrom < MAX_PLAYERS, "Bogus sender!"); strFrom = RISK_GetNameOfPlayer(iFrom); } switch (iTo) { case DST_ALLPLAYERS: #ifdef ENGLISH strTo = "Everybody"; #endif #ifdef FRENCH strTo = "tous"; #endif break; case DST_OTHER: has_a_to = 0; break; default: strTo = RISK_GetNameOfPlayer(iTo); } len = strlen(strOldMessage) + strlen(strNewLine) + strlen(strFrom) + 2 + 1 + strlen(strToHead) + strlen(strTo) + 4 + strlen(strMessage) + 1; strNewMessage = (CString)MEM_Alloc(len); snprintf(strNewMessage, len, "%s%s%s: %s%s%s%s%s%s", strOldMessage, strNewLine, strFrom, has_a_to ? "(" : "", has_a_to ? strToHead : "", has_a_to ? strTo : "", has_a_to ? ") \"" : "", strMessage, has_a_to ? "\"" : ""); /* Set the new message, go to the end */ XtVaSetValues(wMsgText, XtNstring, strNewMessage, NULL); XawTextSetInsertionPoint(wMsgText, strlen(strNewMessage)); MEM_Free(strNewMessage); } /************************************************************************ * FUNCTION: UTIL_DisplayComment * HISTORY: * 02.07.94 ESF Created. * PURPOSE: * NOTES: ************************************************************************/ void UTIL_DisplayComment(CString strComment) { Arg pArgs[1]; Int32 iCount; iCount = 0; XtSetArg(pArgs[iCount], XtNlabel, strComment); iCount++; XtSetValues(wCommentLabel, pArgs, iCount); } /************************************************************************ * FUNCTION: UTIL_SetPlayerTurnIndicator * HISTORY: * 03.03.94 ESF Created. * PURPOSE: * NOTES: ************************************************************************/ void UTIL_SetPlayerTurnIndicator(Int32 iPlayer) { UNUSED(iPlayer); D_Assert(FALSE, "Unimplemented!"); } /************************************************************************ * FUNCTION: UTIL_DisplayActionCString * HISTORY: * 03.03.94 ESF Created. * 03.29.94 ESF Added player attack mode history. * 03.30.94 ESF Fixed bug, not erasing iAttackSrc. * 04.02.94 ESF Added clearing of error. * 05.07.94 ESF Removed clearing of error. * PURPOSE: * NOTES: ************************************************************************/ void UTIL_DisplayActionCString(Int32 iState, Int32 iPlayer) { char buf[256]; switch (iState) { case STATE_REGISTER: #ifdef ENGLISH snprintf(buf, sizeof(buf), "Waiting for all clients to register..."); #endif #ifdef FRENCH snprintf(buf, sizeof(buf), "Attent que tous les clients aient fini de s'enregistrer..."); #endif break; case STATE_FORTIFY: #ifdef ENGLISH snprintf(buf, sizeof(buf), "%s to place an army (%d remaining)...", #endif #ifdef FRENCH snprintf(buf, sizeof(buf), "%s place une armée (reste %d)...", #endif RISK_GetNameOfPlayer(iPlayer), RISK_GetNumArmiesOfPlayer(iPlayer)); XawListHighlight(wActionList, iActionState = ACTION_PLACE); if (UTIL_PlayerIsLocal(iPlayer)) { XawListHighlight(wAttackList, RISK_GetDiceModeOfPlayer(iCurrentPlayer)); XawListHighlight(wMsgDestList, RISK_GetMsgDstModeOfPlayer(iCurrentPlayer)); } break; case STATE_PLACE: #ifdef ENGLISH snprintf(buf, sizeof(buf), "%s placing armies (%d remaining)...", #endif #ifdef FRENCH snprintf(buf, sizeof(buf), "%s place des armées (reste %d)...", #endif RISK_GetNameOfPlayer(iPlayer), RISK_GetNumArmiesOfPlayer(iPlayer)); XawListHighlight(wActionList, iActionState = ACTION_PLACE); if (UTIL_PlayerIsLocal(iPlayer)) { XawListHighlight(wAttackList, RISK_GetDiceModeOfPlayer(iCurrentPlayer)); XawListHighlight(wMsgDestList, RISK_GetMsgDstModeOfPlayer(iCurrentPlayer)); } break; case STATE_ATTACK: #ifdef ENGLISH snprintf(buf, sizeof(buf), "%s attacking...", #endif #ifdef FRENCH snprintf(buf, sizeof(buf), "%s attaque...", #endif RISK_GetNameOfPlayer(iPlayer)); iActionState = RISK_GetAttackModeOfPlayer(iCurrentPlayer); XawListHighlight(wActionList, RISK_GetAttackModeOfPlayer(iCurrentPlayer)); if (UTIL_PlayerIsLocal(iPlayer)) { XawListHighlight(wAttackList, RISK_GetDiceModeOfPlayer(iCurrentPlayer)); XawListHighlight(wMsgDestList, RISK_GetMsgDstModeOfPlayer(iCurrentPlayer)); } break; case STATE_MOVE: if (GAME_AttackFrom() >= 0) { UTIL_DarkenCountry(GAME_AttackFrom()); GAME_SetAttackSrc(-1); } #ifdef ENGLISH snprintf(buf, sizeof(buf), "%s executing a free move...", #endif #ifdef FRENCH snprintf(buf, sizeof(buf), "%s déplace...", #endif RISK_GetNameOfPlayer(iPlayer)); XawListHighlight(wActionList, iActionState = ACTION_MOVE); if (UTIL_PlayerIsLocal(iPlayer)) { XawListHighlight(wAttackList, RISK_GetDiceModeOfPlayer(iCurrentPlayer)); XawListHighlight(wMsgDestList, RISK_GetMsgDstModeOfPlayer(iCurrentPlayer)); } break; default: D_Assert(FALSE, "Shouldn't be here!"); } UTIL_DisplayComment(buf); } /************************************************************************ * FUNCTION: UTIL_DisplayError * HISTORY: * 03.04.94 ESF Created. * PURPOSE: * NOTES: ************************************************************************/ void UTIL_DisplayError(CString strError) { Arg pArgs[1]; Int32 iCount; iCount=0; XtSetArg(pArgs[iCount], XtNlabel, strError); iCount++; XtSetValues(wErrorLabel, pArgs, iCount); } /************************************************************************ * FUNCTION: UTIL_ServerEnterState * HISTORY: * 03.05.94 ESF Created. * 11.16.94 ESF Added to send messages to other clients. * PURPOSE: * NOTES: ************************************************************************/ void UTIL_ServerEnterState(Int32 iNewState) { MsgEnterState m; MsgNetMessage msgNetMessage; char buf[256]; switch (iNewState) { case STATE_REGISTER: break; case STATE_PLACE: #ifdef ENGLISH snprintf(buf, sizeof(buf), "%s is placing %s.", RISK_GetNameOfPlayer(iCurrentPlayer), (RISK_GetNumArmiesOfPlayer(iCurrentPlayer) > 1 ? "armies" : "an army")); #endif #ifdef FRENCH snprintf(buf, sizeof(buf), "%s place %s armée%s.", RISK_GetNameOfPlayer(iCurrentPlayer), (RISK_GetNumArmiesOfPlayer(iCurrentPlayer)>1)?"des":"une", (RISK_GetNumArmiesOfPlayer(iCurrentPlayer)>1)?"s":""); #endif break; case STATE_FORTIFY: #ifdef ENGLISH snprintf(buf, sizeof(buf), "%s is fortifying territories.", #endif #ifdef FRENCH snprintf(buf, sizeof(buf), "%s fortifie des territoires.", #endif RISK_GetNameOfPlayer(iCurrentPlayer)); break; case STATE_ATTACK: #ifdef ENGLISH snprintf(buf, sizeof(buf), "%s is attacking.", #endif #ifdef FRENCH snprintf(buf, sizeof(buf), "%s attaque.", #endif RISK_GetNameOfPlayer(iCurrentPlayer)); break; case STATE_MOVE: #ifdef ENGLISH snprintf(buf, sizeof(buf), "%s is moving armie(s).", #endif #ifdef FRENCH snprintf(buf, sizeof(buf), "%s déplace des armée(s).", #endif RISK_GetNameOfPlayer(iCurrentPlayer)); break; default: D_Assert(0, "Bogus state!"); } msgNetMessage.strMessage = buf; (void)RISK_SendMessage(CLNT_GetCommLinkOfClient(CLNT_GetThisClientID()), MSG_NETMESSAGE, &msgNetMessage); /* Change states and let the server know about it */ m.iState = iNewState; (void)RISK_SendMessage(CLNT_GetCommLinkOfClient(CLNT_GetThisClientID()), MSG_ENTERSTATE, &m); } /* Utility for the next function */ #define UTIL_CloseArmyDialog() \ UTIL_DisplayError(""); \ XtSetKeyboardFocus(wToplevel, wToplevel); \ XtRemoveGrab(wArmiesShell); \ XtUnrealizeWidget(wArmiesShell); /************************************************************************ * FUNCTION: UTIL_GetArmyNumber * HISTORY: * 03.16.94 ESF Created. * 03.28.94 ESF Fixed minor printing bug. * 04.01.94 ESF Fixed bug in centering shell, had XtNy with an x. * PURPOSE: * NOTES: ************************************************************************/ Int32 UTIL_GetArmyNumber(Int32 iMinArmies, Int32 iMaxArmies, Flag fLetCancel) { Int32 x, y, iNumArmies; XEvent xEvent; CString strBuffer; char buf[256]; /* Make sure that the range is valid */ D_Assert(iMinArmies<=iMaxArmies, "Invalid range for army values!"); UTIL_CenterShell(wArmiesShell, wToplevel, &x, &y); XtVaSetValues(wArmiesShell, XtNallowShellResize, False, XtNx, x, XtNy, y, XtNborderWidth, 1, XtNtitle, "Frisk", NULL); /* Set the default number of armies as the maximum */ snprintf(buf, sizeof(buf), "%d", iMaxArmies); XtVaSetValues(wArmiesText, XtNstring, buf, NULL); /* Don't display the cancel button if there is no chance of this */ XtVaSetValues(wCancelArmiesButton, XtNsensitive, fLetCancel ? True : False, NULL); /* Pop it up */ XtMapWidget(wArmiesShell); XtAddGrab(wArmiesShell, True, True); XtSetKeyboardFocus(wToplevel, wArmiesShell); XtSetKeyboardFocus(wArmiesShell, wArmiesText); keep_going: iQueryResult = QUERY_INPROGRESS; while (iQueryResult == QUERY_INPROGRESS) { /* pass events */ XNextEvent(hDisplay, &xEvent); XtDispatchEvent(&xEvent); } /* User must have selected one of the buttons */ if (!fLetCancel && iQueryResult == QUERY_NO) goto keep_going; else if (iQueryResult == QUERY_NO) { UTIL_CloseArmyDialog(); return(0); } /* Get number of armies */ XtVaGetValues(wArmiesText, XtNstring, &strBuffer, NULL); iNumArmies = atoi(strBuffer); if (iNumArmiesiMaxArmies) { if (iNumArmies < iMinArmies) #ifdef ENGLISH snprintf(buf, sizeof(buf), "You must move at least %d armie%s.", #endif #ifdef FRENCH snprintf(buf, sizeof(buf), "Il faut déplacer au moins %d armée%s.", #endif iMinArmies, (iMinArmies>1)?"s":""); else #ifdef ENGLISH snprintf(buf, sizeof(buf), "You can't move more than %d armie%s.", #endif #ifdef FRENCH snprintf(buf, sizeof(buf), "Impossible de déplacer plus de %d armée%s.", #endif iMaxArmies, (iMaxArmies>1)?"s":""); UTIL_DisplayError(buf); goto keep_going; } UTIL_CloseArmyDialog(); return(iNumArmies); } void UTIL_QueryYes(Widget w, XtPointer pData, XtPointer pCalldata) { UNUSED(w); UNUSED(pData); UNUSED(pCalldata); iQueryResult = QUERY_YES; } void UTIL_QueryNo(Widget w, XtPointer pData, XtPointer pCalldata) { UNUSED(w); UNUSED(pData); UNUSED(pCalldata); iQueryResult = QUERY_NO; } void UTIL_QueryCancel(Widget w, XtPointer pData, XtPointer pCalldata) { UNUSED(w); UNUSED(pData); UNUSED(pCalldata); iQueryResult = QUERY_CANCEL; } /************************************************************************ * FUNCTION: UTIL_CenterShell * HISTORY: * 03.16.94 ESF Created. * PURPOSE: * NOTES: ************************************************************************/ void UTIL_CenterShell(Widget wCenter, Widget wBase, Int32 *x, Int32 *y) { Dimension dimWidth, dimHeight, dimTopWidth, dimTopHeight; Window hDummyWindow; /* Make sure the two widgets are realized */ if (!XtIsRealized(wCenter)) XtRealizeWidget(wCenter); if (!XtIsRealized(wBase)) XtRealizeWidget(wBase); /* Get the dimensions of the shells and center the popup. */ XtVaGetValues(wCenter, XtNwidth, &dimWidth, XtNheight, &dimHeight, NULL); XtVaGetValues(wBase, XtNwidth, &dimTopWidth, XtNheight, &dimTopHeight, NULL); XTranslateCoordinates(hDisplay, XtWindow(wBase), XDefaultRootWindow(hDisplay), (Int32)(dimTopWidth-dimWidth)/2, (Int32)(dimTopHeight-dimHeight)/2, x, y, &hDummyWindow); } /************************************************************************ * FUNCTION: UTIL_LightCountry * HISTORY: * 03.28.94 ESF Created. * PURPOSE: * NOTES: ************************************************************************/ void UTIL_LightCountry(Int32 iCountry) { UTIL_PrintArmies(iCountry, RISK_GetNumArmiesOfCountry(iCountry), WhitePixel(hDisplay, 0)); } /************************************************************************ * FUNCTION: UTIL_DarkenCountry * HISTORY: * 03.28.94 ESF Created. * PURPOSE: * NOTES: ************************************************************************/ void UTIL_DarkenCountry(Int32 iCountry) { UTIL_PrintArmies(iCountry, RISK_GetNumArmiesOfCountry(iCountry), BlackPixel(hDisplay, 0)); } /************************************************************************ * FUNCTION: UTIL_PopupDialog * HISTORY: * 04.02.94 ESF Created. * 05.12.94 ESF Revamped. * 10.30.94 ESF Added sanity check for hDisplay. * 01.25.95 ESF Added code to center buttons. * 01.25.95 ESF Changed the default title to "Frisk". * 04.30.95 ESF Fixed a bug with resizing of the label. * PURPOSE: * NOTES: ************************************************************************/ Int32 UTIL_PopupDialog(CString strTitle, CString strLabel, Int32 iNumOptions, CString strOption1, CString strOption2, CString strOption3) { CString pstrOptions[3]; Int32 i, x, y, iWidth; XEvent xEvent; static XFontStruct *pLabelFont=NULL; /* If this got called before the display is set up */ if (!hDisplay) { printf("%s: %s\n", strTitle, strLabel); return 0; } /* Initialize these for later */ pstrOptions[0] = strOption1; pstrOptions[1] = strOption2; pstrOptions[2] = strOption3; /* Get the font if necessary */ if (pLabelFont==NULL) if ((pLabelFont=XLoadQueryFont(hDisplay, "*helvetica-b*-o-*14*"))==NULL) { printf("Can't find the font \"*helvetica-b*-o-*14*\"!!\n"); UTIL_ExitProgram(-1); } /* Sanity check */ if (iNumOptions>3 || iNumOptions<1) { (void)UTIL_PopupDialog("Warning", "UTIL: Wacked # of options", 1, "Ok", NULL, NULL); return(-1); } /* Make sure the dialog is realized */ if(!XtIsRealized(wDialogShell)) XtRealizeWidget(wDialogShell); /* Set the title */ XtVaSetValues(wDialogShell, XtNtitle, strTitle == NULL ? "Frisk" : strTitle, XtNallowShellResize, True, NULL); /* Make sure that the label is big enough to hold the string, and * if the length of the button strings are larger, make it bigger. * Let there be a minimum width of 200... There are a few magic * numbers here, excuse them :) */ iWidth = MAX(200, MAX(XTextWidth(pLabelFont, strLabel, strlen(strLabel))+50, XTextWidth(pLabelFont, strOption1, strOption1 ? strlen(strOption1) : 0)+ XTextWidth(pLabelFont, strOption2, strOption2 ? strlen(strOption2) : 0)+ XTextWidth(pLabelFont, strOption3, strOption3 ? strlen(strOption3) : 0)+ 140)); /* Set the button resources */ for (i=0; i!=3; i++) if (iNumOptions>i) { XtMapWidget(wDialogButton[i]); XtVaSetValues(wDialogButton[i], XtNlabel, pstrOptions[i]==NULL ? "Null": pstrOptions[i], XtNfromHoriz, i>0 ? wDialogButton[i-1] : NULL, NULL); } else { XtUnmapWidget(wDialogButton[i]); XtVaSetValues(wDialogButton[i], XtNfromHoriz, 0, NULL); } /* We need to unrealize it so that the changes will take place (?) */ XtUnrealizeWidget(wDialogShell); /* Center and resize the shell, and then actually pop the dialog up */ XtVaSetValues(wDialogShell, XtNwidth, iWidth, NULL); XtVaSetValues(wDialogLabel, XtNlabel, strLabel, XtNwidth, iWidth, NULL); UTIL_CenterShell(wDialogShell, wToplevel, &x, &y); XtVaSetValues(wDialogShell, XtNx, x, XtNy, y, XtNborderWidth, 1, NULL); XtPopup(wDialogShell, XtGrabExclusive); iQueryResult = QUERY_INPROGRESS; while (iQueryResult == QUERY_INPROGRESS) { /* pass events */ XNextEvent(hDisplay, &xEvent); XtDispatchEvent(&xEvent); } /* User must have selected one of the buttons */ XtPopdown(wDialogShell); return(iQueryResult); } /************************************************************************ * FUNCTION: UTIL_PlayerIsLocal * HISTORY: * 04.11.94 ESF Created. * PURPOSE: * NOTES: ************************************************************************/ Flag UTIL_PlayerIsLocal(Int32 iPlayer) { return (RISK_GetClientOfPlayer(iPlayer) == CLNT_GetThisClientID() ? TRUE : FALSE); } /************************************************************************ * FUNCTION: UTIL_NumPlayersAtClient * HISTORY: * 05.04.94 ESF Created. * 05.13.95 ESF Fixed bug, wasn't checking if player was allocated. * PURPOSE: * NOTES: ************************************************************************/ Int32 UTIL_NumPlayersAtClient(Int32 iClient) { Int32 i, iCount; /* It's an error to call this with an out of range number */ D_Assert(iClient>=0 && iClientiCountry, pId == NULL ? TRUE : FALSE); /* If it's the second time we are being called then there will * be a pId and we can free the memory taken by it. */ if (pId != NULL) MEM_Free(msg); } /************************************************************************ * FUNCTION: UTIL_AttackNotification * HISTORY: * 10.30.94 ESF Created. * 11.16.94 ESF Finished. * 01.15.95 ESF Fixed memory leak. * PURPOSE: * NOTES: ************************************************************************/ void UTIL_AttackNotification(XtPointer msgMess, XtIntervalId *pId) { MsgAttackNotify *msg = (MsgAttackNotify *)msgMess; UTIL_SetCountryBrightness(msg->iSrcCountry, pId == NULL ? TRUE : FALSE); UTIL_DrawNiceLine(msg->iSrcCountry, msg->iDstCountry); /* If it's the second time we are being called then there will * be a pId and we can free the memory taken by it. */ if (pId != NULL) MEM_Free(msg); } /************************************************************************ * FUNCTION: UTIL_MoveNotification * HISTORY: * 10.30.94 ESF Created. * 11.16.94 ESF Finished. * 01.15.95 ESF Fixed memory leak. * PURPOSE: * NOTES: ************************************************************************/ void UTIL_MoveNotification(XtPointer msgMess, XtIntervalId *pId) { MsgMoveNotify *msg = (MsgMoveNotify *)msgMess; UTIL_SetCountryBrightness(msg->iSrcCountry, pId == NULL ? TRUE : FALSE); UTIL_DrawNiceLine(msg->iSrcCountry, msg->iDstCountry); /* If it's the second time we are being called then there will * be a pId and we can free the memory taken by it. */ if (pId != NULL) MEM_Free(msg); } #define BORDER 2 /************************************************************************ * FUNCTION: UTIL_DrawNiceLine * HISTORY: * 11.06.94 ESF Created. * 11.16.94 ESF Finished. * PURPOSE: * NOTES: ************************************************************************/ void UTIL_DrawNiceLine(Int32 iSrcCountry, Int32 iDstCountry) { Int32 x1, y1, x2, y2, iHalfHeight, iHalfWidth; Int32 iWidth, iHeight, ixDist, iyDist; /* Get the two endpoints of the line */ x1 = RISK_GetTextXOfCountry(iSrcCountry)-BORDER; y1 = RISK_GetTextYOfCountry(iSrcCountry)+BORDER; x2 = RISK_GetTextXOfCountry(iDstCountry)-BORDER; y2 = RISK_GetTextYOfCountry(iDstCountry)+BORDER; /* Get the width and height of the box containing the text. */ iHeight = (pFont->max_bounds.ascent + pFont->max_bounds.descent)+2*BORDER; iWidth = XTextWidth(pFont, MAX_STRING, MAX_DIGITS)+2*BORDER; /* Depending on where the source and destination of the line is, * draw it coming and going from the middle of one of the sides, * of from the corners. Thus, the line can come and go from eight * different points, which should be enough to make it look good. */ ixDist = (x1-x2<0) ? (x2-x1) : (x1-x2); iyDist = (y1-y2<0) ? (y2-y1) : (y1-y2); /* The compiler should do this (CSE), but I'm distrustful by nature */ iHalfHeight = iHeight / 2; iHalfWidth = iWidth / 2; if (ixDist > iyDist) { /* Use the middles of the sides */ if (x2 > x1) x1+=iWidth, y1-=iHalfHeight, y2-=iHalfHeight; else x2+=iWidth, y1-=iHalfHeight, y2-=iHalfHeight; } else { /* Use the middles of the top and bottom */ if (y2 > y1) x1+=iHalfWidth, x2+=iHalfWidth, y2-=iHeight; else x1+=iHalfWidth, x2+=iHalfWidth, y1-=iHeight; } if (!COLOR_IsTrueColor()) XDrawLine(hDisplay, hWindow, hGC_XOR, x1, y1, x2, y2); XFlush(hDisplay); } /************************************************************************ * FUNCTION: UTIL_SetCountryBrightness * HISTORY: * 11.16.94 ESF Created. * PURPOSE: * NOTES: ************************************************************************/ void UTIL_SetCountryBrightness(Int32 iCountry, Boolean fLight) { Int32 iLightRefCount; iLightRefCount = CLNT_GetLightCountOfCountry(iCountry); /* Light up or darken country, using reference counting. */ if (fLight) { if (iLightRefCount == 0) UTIL_LightCountry(iCountry); CLNT_SetLightCountOfCountry(iCountry, iLightRefCount + 1); } else { if (iLightRefCount == 1) UTIL_DarkenCountry(iCountry); CLNT_SetLightCountOfCountry(iCountry, iLightRefCount - 1); } } /************************************************************************ * FUNCTION: UTIL_OpenFile * HISTORY: * 12.31.94 ESF Created. * PURPOSE: * NOTES: ************************************************************************/ FILE *UTIL_OpenFile(CString strName, CString strOptions) { FILE *hFile; CString strNewName = NULL; Int32 i; /* First just try to open the complete file that was passed */ if ((hFile = fopen(strName, strOptions)) != NULL) return hFile; /* Construct an alternate name that is the same file * but in the current directory. Try to open this. */ /* Alloc some memory, with room for '\0' and './' */ strNewName = (CString)MEM_Alloc(strlen(strName)+1+2); /* Find the last occurance of '/' in the filename */ for (i=strlen(strName)-1; i>=0 && strName[i]!='/'; i--) ; /* TwiddleThumbs() */ /* Create the start of the new pathname */ strcpy(strNewName, "./"); /* Move the pointer along to the last '/', but don't run off the end */ strName = strName + MIN(i+1, (Int32)strlen(strName)); strcat(strNewName, strName); /* Try to open this file */ hFile = fopen(strName, strOptions); /* Free the memory */ MEM_Free(strNewName); /* Return the handle */ return hFile; } xfrisk-1.2/utils.h0100644000175000017500000000576507034464441013233 0ustar johnojohno/* * XFrisk - The classic board game for X * Copyright (C) 1993-1999 Elan Feingold (elan@aetherworks.com) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * $Id: utils.h,v 1.5 2000/01/04 21:41:53 tony Exp $ */ #ifndef _UTILS #define _UTILS #include #include #include "types.h" #ifdef __GNUC__ #define UNUSED(x) ((void)x) #else #define UNUSED(x) #endif #define QUERY_YES 0 #define QUERY_NO 1 #define QUERY_CANCEL 2 #define QUERY_INPROGRESS -1 #define PRINT_BLANK -1 #define PLAYER_NONE -1 #define CURSOR_PLAY 0 #define CURSOR_WAIT 1 #ifdef ENGLISH #define SERVERNAME "Server" #endif #ifdef FRENCH #define SERVERNAME "Serveur" #endif #define OUT_OF_MEM 1 /* X11 Graphical */ void UTIL_PrintArmies(Int32 iCountry, Int32 iNumArmies, Int32 iColor); void UTIL_DisplayMessage(Int32 iFrom, Int32 iTo, CString strMessage); void UTIL_DisplayComment(CString strComment); void UTIL_DisplayError(CString strError); void UTIL_SetPlayerTurnIndicator(Int32 iPlayer); void UTIL_DisplayActionCString(Int32 iState, Int32 iPlayer); void UTIL_CenterShell(Widget wCenter, Widget wBase, Int32 *x, Int32 *y); Int32 UTIL_GetArmyNumber(Int32 iMinArmies, Int32 iMaxArmies, Flag fLetCancel); Int32 UTIL_PopupDialog(CString strTitle, CString strQuestion, Int32 iNumOptions, CString strOption1, CString strOption2, CString strOption3); void UTIL_QueryYes(Widget w, XtPointer pData, XtPointer pCalldata); void UTIL_QueryNo(Widget w, XtPointer pData, XtPointer pCalldata); void UTIL_QueryCancel(Widget w, XtPointer pData, XtPointer pCalldata); void UTIL_LightCountry(Int32 iCountry); void UTIL_DarkenCountry(Int32 iCountry); void UTIL_RefreshMsgDest(Int32 iNumCStrings); void UTIL_SetCursorShape(Int32 iShape); void UTIL_DrawNiceLine(Int32 iSrcCountry, Int32 iDstCountry); /* Notification */ void UTIL_PlaceNotification(XtPointer msgMess, XtIntervalId *pId); void UTIL_AttackNotification(XtPointer msgMess, XtIntervalId *pId); void UTIL_MoveNotification(XtPointer msgMess, XtIntervalId *pId); /* Non-X11 */ void UTIL_ServerEnterState(Int32 iNewState); Flag UTIL_PlayerIsLocal(Int32 iPlayer); Int32 UTIL_NumPlayersAtClient(Int32 iClient); void UTIL_ExitProgram(Int32 iExitValue); FILE *UTIL_OpenFile(CString strName, CString strOptions); #endif xfrisk-1.2/version.h0100644000175000017500000000174607043121563013546 0ustar johnojohno/* * XFrisk - The classic board game for X * Copyright (C) 1993-1999 Elan Feingold (elan@aetherworks.com) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * $Id: version.h,v 1.6 2000/01/24 19:09:39 tony Exp $ */ /** * \file Version of the game */ #ifndef VERSION #define VERSION "1.2" #endif xfrisk-1.2/viewCards.c0100644000175000017500000000411107013357410013767 0ustar johnojohno/* * XFrisk - The classic board game for X * Copyright (C) 1993-1999 Elan Feingold (elan@aetherworks.com) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * $Id: viewCards.c,v 1.4 1999/11/13 21:58:32 morphy Exp $ */ #include "viewCards.h" #include "types.h" #include "utils.h" /************************************************************************ * FUNCTION: * HISTORY: * 02.17.95 ESF Created. * PURPOSE: * NOTES: ************************************************************************/ void CARD_BuildDialog(void) { } /************************************************************************ * FUNCTION: * HISTORY: * 02.17.95 ESF Created. * PURPOSE: * NOTES: ************************************************************************/ void CARD_PopupDialog(void) { } /************************************************************************ * FUNCTION: * HISTORY: * 02.17.95 ESF Created. * PURPOSE: * NOTES: ************************************************************************/ void CARD_Close(void) { } /************************************************************************ * FUNCTION: * HISTORY: * 02.17.95 ESF Created. * PURPOSE: * NOTES: ************************************************************************/ void CARD_Callback(Int32 iMessType, void *pvMessage) { UNUSED(iMessType); UNUSED(pvMessage); } xfrisk-1.2/viewCards.h0100644000175000017500000000214107013357410013775 0ustar johnojohno/* * XFrisk - The classic board game for X * Copyright (C) 1993-1999 Elan Feingold (elan@aetherworks.com) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * $Id: viewCards.h,v 1.3 1999/11/13 21:58:32 morphy Exp $ */ #ifndef _CARDSVIEW #define _CARDSVIEW #include "types.h" void CARD_BuildDialog(void); void CARD_PopupDialog(void); void CARD_Close(void); void CARD_Callback(Int32 iMessType, void *pvMessage); #endif xfrisk-1.2/viewChat.c0100644000175000017500000000410707013357410013617 0ustar johnojohno/* * XFrisk - The classic board game for X * Copyright (C) 1993-1999 Elan Feingold (elan@aetherworks.com) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * $Id: viewChat.c,v 1.4 1999/11/13 21:58:32 morphy Exp $ */ #include "viewChat.h" #include "types.h" #include "utils.h" /************************************************************************ * FUNCTION: * HISTORY: * 02.17.95 ESF Created. * PURPOSE: * NOTES: ************************************************************************/ void CHAT_BuildDialog(void) { } /************************************************************************ * FUNCTION: * HISTORY: * 02.17.95 ESF Created. * PURPOSE: * NOTES: ************************************************************************/ void CHAT_PopupDialog(void) { } /************************************************************************ * FUNCTION: * HISTORY: * 02.17.95 ESF Created. * PURPOSE: * NOTES: ************************************************************************/ void CHAT_Close(void) { } /************************************************************************ * FUNCTION: * HISTORY: * 02.17.95 ESF Created. * PURPOSE: * NOTES: ************************************************************************/ void CHAT_Callback(Int32 iMessType, void *pvMessage) { UNUSED(iMessType); UNUSED(pvMessage); } xfrisk-1.2/viewChat.h0100644000175000017500000000213607013357411013625 0ustar johnojohno/* * XFrisk - The classic board game for X * Copyright (C) 1993-1999 Elan Feingold (elan@aetherworks.com) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * $Id: viewChat.h,v 1.3 1999/11/13 21:58:33 morphy Exp $ */ #ifndef _CHATVIEW #define _CHATVIEW #include "types.h" void CHAT_BuildDialog(void); void CHAT_PopupDialog(void); void CHAT_Close(void); void CHAT_Callback(Int32 iMessType, void *pvMessage); #endif xfrisk-1.2/viewFeedback.c0100644000175000017500000000411707013357411014426 0ustar johnojohno/* * XFrisk - The classic board game for X * Copyright (C) 1993-1999 Elan Feingold (elan@aetherworks.com) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * $Id: viewFeedback.c,v 1.4 1999/11/13 21:58:33 morphy Exp $ */ #include "viewFeedback.h" #include "types.h" #include "utils.h" /************************************************************************ * FUNCTION: * HISTORY: * 02.17.95 ESF Created. * PURPOSE: * NOTES: ************************************************************************/ void FDBK_BuildDialog(void) { } /************************************************************************ * FUNCTION: * HISTORY: * 02.17.95 ESF Created. * PURPOSE: * NOTES: ************************************************************************/ void FDBK_PopupDialog(void) { } /************************************************************************ * FUNCTION: * HISTORY: * 02.17.95 ESF Created. * PURPOSE: * NOTES: ************************************************************************/ void FDBK_Close(void) { } /************************************************************************ * FUNCTION: * HISTORY: * 02.17.95 ESF Created. * PURPOSE: * NOTES: ************************************************************************/ void FDBK_Callback(Int32 iMessType, void *pvMessage) { UNUSED(iMessType); UNUSED(pvMessage); } xfrisk-1.2/viewFeedback.h0100644000175000017500000000214207013357411014427 0ustar johnojohno/* * XFrisk - The classic board game for X * Copyright (C) 1993-1999 Elan Feingold (elan@aetherworks.com) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * $Id: viewFeedback.h,v 1.3 1999/11/13 21:58:33 morphy Exp $ */ #ifndef _FDBKVIEW #define _FDBKVIEW #include "types.h" void FDBK_BuildDialog(void); void FDBK_PopupDialog(void); void FDBK_Close(void); void FDBK_Callback(Int32 iMessType, void *pvMessage); #endif xfrisk-1.2/viewLog.c0100644000175000017500000000411007013357411013454 0ustar johnojohno/* * XFrisk - The classic board game for X * Copyright (C) 1993-1999 Elan Feingold (elan@aetherworks.com) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * $Id: viewLog.c,v 1.4 1999/11/13 21:58:33 morphy Exp $ */ #include "viewLog.h" #include "types.h" #include "utils.h" /************************************************************************ * FUNCTION: * HISTORY: * 02.17.95 ESF Created. * PURPOSE: * NOTES: ************************************************************************/ void LOG_BuildDialog(void) { } /************************************************************************ * FUNCTION: * HISTORY: * 02.17.95 ESF Created. * PURPOSE: * NOTES: ************************************************************************/ void LOG_PopupDialog(void) { } /************************************************************************ * FUNCTION: * HISTORY: * 02.17.95 ESF Created. * PURPOSE: * NOTES: ************************************************************************/ void LOG_Close(void) { } /************************************************************************ * FUNCTION: * HISTORY: * 02.17.95 ESF Created. * PURPOSE: * NOTES: ************************************************************************/ void LOG_Callback(Int32 iMessType, void *pvMessage) { UNUSED(iMessType); UNUSED(pvMessage); } xfrisk-1.2/viewLog.h0100644000175000017500000000212707013357411013467 0ustar johnojohno/* * XFrisk - The classic board game for X * Copyright (C) 1993-1999 Elan Feingold (elan@aetherworks.com) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * $Id: viewLog.h,v 1.3 1999/11/13 21:58:33 morphy Exp $ */ #ifndef _LOGVIEW #define _LOGVIEW #include "types.h" void LOG_BuildDialog(void); void LOG_PopupDialog(void); void LOG_Close(void); void LOG_Callback(Int32 iMessType, void *pvMessage); #endif xfrisk-1.2/viewStats.c0100644000175000017500000005432407040411046014040 0ustar johnojohno/* * XFrisk - The classic board game for X * Copyright (C) 1993-1999 Elan Feingold (elan@aetherworks.com) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * $Id: viewStats.c,v 1.12 2000/01/16 18:47:02 tony Exp $ */ #include #include #include #include #include #include #include #include #include #include "viewStats.h" #include "riskgame.h" #include "callbacks.h" #include "gui-vars.h" #include "utils.h" #include "types.h" #include "debug.h" /* Defines */ #define GRAPH_WIDTH 471 #define GRAPH_HEIGHT 150 /* dX for graph 3 ok-ish*/ #define GRAPH_STEP 3 /* Private globals */ static Widget wStatShell, wStatForm; static Widget wStatNumberForm, wStatGraphForm; static Widget wStatColorLabel, wStatNameLabel, wStatArmiesLabel; static Widget wStatCountriesLabel, wStatCardsLabel, wStatWLDLabel; static Widget wStatViewport, wStatPlayerForm; static Widget wPlayerStatForm[MAX_PLAYERS], wStatPlayerColor[MAX_PLAYERS]; static Widget wStatPlayerName[MAX_PLAYERS], wStatPlayerArmies[MAX_PLAYERS]; static Widget wStatPlayerCountries[MAX_PLAYERS], wStatPlayerCards[MAX_PLAYERS]; static Widget wStatPlayerWLD[MAX_PLAYERS], wStatGraphLabel, wStatGraph; static Widget wStatCloseButton; static Int32 piSlotToPlayer[MAX_PLAYERS]; static Int32 iBackgroundColor; static Int32 iXPos = 0, fFirstTime = TRUE; static Pixmap pixmap; static Flag fDialogIsUp = FALSE; static Int32 piPlayerWin[MAX_PLAYERS], piPlayerLose[MAX_PLAYERS]; static Int32 piPlayerDraw[MAX_PLAYERS]; static Int32 piTotalArmies[MAX_PLAYERS]; static Int32 piLastValue[MAX_PLAYERS]; /* Private functions */ Int32 STAT_SlotToPlayer(Int32 iSlot); void STAT_InitThings(void); void STAT_UpdateGraph(void); void STAT_UpdateArmies(Int32 iPlayer, Int32 iArmies); void STAT_UpdateCountries(Int32 iPlayer, Int32 iCountries); void STAT_UpdateCards(Int32 iPlayer, Int32 iCards); void STAT_UpdateWinLoseDraw(Int32 iPlayer); void STAT_PlayerCreated(Int32 iPlayer); void STAT_PlayerDestroyed(Int32 iPlayer); /************************************************************************ * FUNCTION: STAT_AddPlayerStats * HISTORY: * 12.25.95 TdH Created. * PURPOSE: Add info lines about players * NOTES: ************************************************************************/ void STAT_AddPlayerStats(void) { Int32 i; /* Each player */ for (i=0; i!=MAX_PLAYERS; i++) { wPlayerStatForm[i] = XtVaCreateManagedWidget("wShowPlayerForm", formWidgetClass, wStatPlayerForm, NULL); if (i) XtVaSetValues(wPlayerStatForm[i], XtNfromVert, wPlayerStatForm[i-1], NULL); wStatPlayerColor[i] = XtVaCreateManagedWidget("wStatPlayerColor", labelWidgetClass, wPlayerStatForm[i], XtNresize, False, NULL); wStatPlayerName[i] = XtVaCreateManagedWidget("wStatPlayerName", labelWidgetClass, wPlayerStatForm[i], XtNfromHoriz, wStatPlayerColor[i], XtNresize, False, NULL); wStatPlayerArmies[i] = XtVaCreateManagedWidget("wStatPlayerArmies", labelWidgetClass, wPlayerStatForm[i], XtNfromHoriz, wStatPlayerName[i], XtNresize, False, NULL); wStatPlayerCountries[i] = XtVaCreateManagedWidget("wStatPlayerCountries", labelWidgetClass, wPlayerStatForm[i], XtNfromHoriz, wStatPlayerArmies[i], XtNresize, False, NULL); wStatPlayerCards[i] = XtVaCreateManagedWidget("wStatPlayerCards", labelWidgetClass, wPlayerStatForm[i], XtNfromHoriz, wStatPlayerCountries[i], XtNresize, False, NULL); wStatPlayerWLD[i] = XtVaCreateManagedWidget("wStatPlayerWLD", labelWidgetClass, wPlayerStatForm[i], XtNfromHoriz, wStatPlayerCards[i], XtNresize, False, NULL); } } /************************************************************************ * FUNCTION: * HISTORY: * 02.17.95 ESF Created. * PURPOSE: * NOTES: ************************************************************************/ void STAT_BuildDialog(void) { Int32 i; wStatShell = XtCreatePopupShell("wStatShell", topLevelShellWidgetClass, wToplevel, pVisualArgs, iVisualCount); /* The forms */ wStatForm = XtCreateManagedWidget("wStatForm", formWidgetClass, wStatShell, NULL, 0); wStatNumberForm = XtCreateManagedWidget("wStatNumberForm", formWidgetClass, wStatForm, NULL, 0); wStatGraphForm = XtCreateManagedWidget("wStatGraphForm", formWidgetClass, wStatForm, NULL, 0); wStatCloseButton = XtCreateManagedWidget("wStatCloseButton", commandWidgetClass, wStatForm, NULL, 0); XtAddCallback(wStatCloseButton, XtNcallback, (XtCallbackProc)STAT_Close, NULL); /* The labels */ wStatColorLabel = XtCreateManagedWidget("wStatColorLabel", labelWidgetClass, wStatNumberForm, NULL, 0); wStatNameLabel = XtCreateManagedWidget("wStatNameLabel", labelWidgetClass, wStatNumberForm, NULL, 0); wStatArmiesLabel = XtCreateManagedWidget("wStatArmiesLabel", labelWidgetClass, wStatNumberForm, NULL, 0); wStatCountriesLabel = XtCreateManagedWidget("wStatCountriesLabel", labelWidgetClass, wStatNumberForm, NULL, 0); wStatCardsLabel = XtCreateManagedWidget("wStatCardsLabel", labelWidgetClass, wStatNumberForm, NULL, 0); wStatWLDLabel = XtCreateManagedWidget("wStatWLDLabel", labelWidgetClass, wStatNumberForm, NULL, 0); /* The statistics "spreadsheet" */ wStatViewport = XtCreateManagedWidget("wStatViewport", viewportWidgetClass, wStatNumberForm, NULL, 0); wStatPlayerForm = XtCreateManagedWidget("wStatPlayerForm", boxWidgetClass, wStatViewport, NULL, 0); STAT_AddPlayerStats();/* info about each player */ /* The statistics graph */ wStatGraphLabel = XtVaCreateManagedWidget("wStatGraphLabel", labelWidgetClass, wStatGraphForm, NULL); wStatGraph = XtVaCreateManagedWidget("wStatGraph", labelWidgetClass, wStatGraphForm, NULL); /* Create the graph pixmap */ pixmap = XCreatePixmap(hDisplay, RootWindowOfScreen(XtScreen(wStatGraph)), GRAPH_WIDTH, GRAPH_HEIGHT, DefaultDepth(hDisplay, DefaultScreen(hDisplay))); /* Set it to be the background pixmap of the widget */ XtVaSetValues(wStatGraph, XtNbitmap, pixmap, NULL); STAT_InitThings(); /* In addition, reset the mapping -- this happens but once * this is why it's not in STAT_InitThings()*/ for (i=0; i!=MAX_PLAYERS; i++) piSlotToPlayer[i] = -1; } /************************************************************************ * FUNCTION: * HISTORY: * 04.01.95 ESF Created. * PURPOSE: * NOTES: ************************************************************************/ void STAT_InitThings(void) { Int32 i; /* Init the data & slots */ for (i=0; i!=MAX_PLAYERS; i++) { piPlayerWin[i] = piPlayerLose[i] = piPlayerDraw[i] = 0; piTotalArmies[i] = 0; if (fDialogIsUp) { STAT_UpdateWinLoseDraw(i); STAT_UpdateArmies(i, piTotalArmies[i]); } } /* Fill the pixmap with the color background of the ocean. * Tdh: and ocean color is borked. easiest fix would be a global SEACOLOR */ /* XSetForeground(hDisplay, hGC, COLOR_QueryColor(COLOR_CountryToColor(NUM_COUNTRIES)));*/ XSetForeground(hDisplay, hGC, 0); XFillRectangle(hDisplay, pixmap, hGC, 0, 0, GRAPH_WIDTH, GRAPH_HEIGHT); /* If the dialog is up, then blit the new stuff to it */ if (fDialogIsUp) XCopyArea(hDisplay, pixmap, XtWindow(wStatGraph), hGC, 0, 0, GRAPH_WIDTH, GRAPH_HEIGHT, 0, 0); iXPos = 0; /* This will trigger the first points on the graph to be drawn */ fFirstTime = TRUE; } /************************************************************************ * FUNCTION: * HISTORY: * 02.17.95 ESF Created. * PURPOSE: * NOTES: ************************************************************************/ void STAT_PopupDialog(void) { Int32 x, y, i, iPlayer; if (fDialogIsUp) { fDialogIsUp = FALSE; XtPopdown(wStatShell); return; } /* Center the new shell */ UTIL_CenterShell(wStatShell, wToplevel, &x, &y); XtVaSetValues(wStatShell, XtNallowShellResize, False, XtNx, x, XtNy, y, XtNborderWidth, 1, #ifdef ENGLISH XtNtitle, "Game Statistics", #endif #ifdef FRENCH XtNtitle, "Statistiques de la partie", #endif NULL); /* It's going to be up in a second. */ fDialogIsUp = TRUE; for (i=0; i MSG_ENDOFMISSION or MSG_VICTORY. * PURPOSE: * NOTES: ************************************************************************/ void STAT_Callback(Int32 iMessType, void *pvMess) { /* * GameBegin --> Init. things * EndTurn --> Territories graph * DiceRoll --> Win/Lose/Draw * Object(iNumCountries) --> Update * Object(iNumCards) --> Update * Object(iNumArmies) --> Update * PlayerCreated --> Add player * PlayerDestroyed --> Delete player */ if (iMessType == MSG_STARTGAME) { /* Reset things that need resetting between games */ STAT_InitThings(); } else if (iMessType == MSG_DICEROLL) { /* Go through the dice roll and update the * win/lose/draw statistics for the players. */ MsgDiceRoll *pMess = (MsgDiceRoll *)pvMess; Int32 i, iOtherPlayer = pMess->iDefendingPlayer; for (i=0; i!=3; i++) if (pMess->pAttackDice[i] != -1 && pMess->pDefendDice[i] != -1) { if (pMess->pAttackDice[i] > pMess->pDefendDice[i]) { piPlayerWin[iCurrentPlayer]++; piPlayerLose[iOtherPlayer]++; } else if (pMess->pAttackDice[i] == pMess->pDefendDice[i]) { piPlayerDraw[iCurrentPlayer]++; piPlayerDraw[iOtherPlayer]++; } else if (pMess->pAttackDice[i] < pMess->pDefendDice[i]) { piPlayerLose[iCurrentPlayer]++; piPlayerWin[iOtherPlayer]++; } } /* Win/Lose/Draw */ if (fDialogIsUp) { STAT_UpdateWinLoseDraw(iCurrentPlayer); STAT_UpdateWinLoseDraw(iOtherPlayer); } } else if ((iMessType == MSG_ENDOFMISSION) || (iMessType == MSG_VICTORY)) { /* The last position of the board, since ENDTURN won't come along. */ STAT_UpdateGraph(); } else if (iMessType == MSG_TURNNOTIFY) { /* Draws the initial points on the graph */ if (fFirstTime) { fFirstTime = FALSE; STAT_UpdateGraph(); } } else if (iMessType == MSG_ENDTURN) { /* Territories graph, but only if not in fortifying mode... */ if (iState != STATE_FORTIFY) STAT_UpdateGraph(); } else if (iMessType == MSG_OBJINTUPDATE && ((MsgObjIntUpdate *)pvMess)->iField == PLR_ALLOCATION && ((MsgObjIntUpdate *)pvMess)->iNewValue == ALLOC_COMPLETE) { /* PlayerCreated */ STAT_PlayerCreated(((MsgObjIntUpdate *)pvMess)->iIndex1); } else if (iMessType == MSG_OBJINTUPDATE && ((MsgObjIntUpdate *)pvMess)->iField == PLR_ALLOCATION && ((MsgObjIntUpdate *)pvMess)->iNewValue == ALLOC_NONE) { /* PlayerDestroyed */ STAT_PlayerDestroyed(((MsgObjIntUpdate *)pvMess)->iIndex1); } else if (iMessType == MSG_OBJINTUPDATE && ((MsgObjIntUpdate *)pvMess)->iField == PLR_NUMCOUNTRIES) { Int32 iPlayer = ((MsgObjIntUpdate *)pvMess)->iIndex1; /* Object(iNumCountries) */ if (iPlayer>=0) STAT_UpdateCountries(iPlayer, ((MsgObjIntUpdate *)pvMess)->iNewValue); } else if (iMessType == MSG_OBJINTUPDATE && ((MsgObjIntUpdate *)pvMess)->iField == PLR_NUMCARDS) { Int32 iPlayer = ((MsgObjIntUpdate *)pvMess)->iIndex1; /* Object(iNumCountries) */ if (iPlayer>=0) STAT_UpdateCards(iPlayer, ((MsgObjIntUpdate *)pvMess)->iNewValue); } else if (iMessType == MSG_OBJINTUPDATE && ((MsgObjIntUpdate *)pvMess)->iField == CNT_NUMARMIES) { Int32 iCountry = ((MsgObjIntUpdate *)pvMess)->iIndex1; Int32 iPlayer = RISK_GetOwnerOfCountry(iCountry); Int32 iNewValue = ((MsgObjIntUpdate *)pvMess)->iNewValue; Int32 iOldValue = RISK_GetNumArmiesOfCountry(iCountry); if (iPlayer >=0) { /* Update the number of total armies the player has */ piTotalArmies[iPlayer] += (iNewValue - iOldValue); STAT_UpdateArmies(iPlayer, piTotalArmies[iPlayer]); } } } /************************************************************************ * FUNCTION: * HISTORY: * 02.19.95 ESF Created. * PURPOSE: * NOTES: ************************************************************************/ void STAT_UpdateGraph(void) { Int32 iYPos, i; /* Assertion: iXPos is the new X position. */ /* Check to see if we are end the right end of the graph */ if (iXPos == GRAPH_WIDTH) { /* Pick the two-thirds point */ Int32 iNewStartX = GRAPH_WIDTH/3 * 2; /* Scroll the graph over a third to the left */ XCopyArea(hDisplay, pixmap, pixmap, hGC, iNewStartX/2, 0, GRAPH_WIDTH-iNewStartX/2, GRAPH_HEIGHT, 0, 0); /* Clean up the right third now */ XSetForeground(hDisplay, hGC, COLOR_QueryColor(COLOR_CountryToColor(NUM_COUNTRIES))); XFillRectangle(hDisplay, pixmap, hGC, iNewStartX, 0, GRAPH_WIDTH-iNewStartX, GRAPH_HEIGHT); iXPos = iNewStartX; } /* Assertion: iXPos is the next X place to draw the next point */ /* Put the number of countries of each player on the graph */ for (i=0; i!=MAX_PLAYERS; i++) { /* Pick the color of player i */ XSetForeground(hDisplay, hGC, COLOR_QueryColor(COLOR_PlayerToColor(i))); /* Calculate the y point */ iYPos = GRAPH_HEIGHT - RISK_GetNumCountriesOfPlayer(i) * GRAPH_HEIGHT / NUM_COUNTRIES; if (iXPos == 0) { /* First point, just draw a point */ XDrawPoint(hDisplay, pixmap, hGC, iXPos, iYPos); } else { /* Draw a line from the last point to the current one */ XDrawLine(hDisplay, pixmap, hGC, iXPos-GRAPH_STEP, piLastValue[i], iXPos, iYPos); XDrawLine(hDisplay, pixmap, hGC, iXPos-GRAPH_STEP, piLastValue[i]+1, iXPos, iYPos+1); } /* Copy portion to screen so it shows <==> the window's up */ if (fDialogIsUp) XCopyArea(hDisplay, pixmap, XtWindow(wStatGraph), hGC, iXPos-GRAPH_STEP, 0, 2, GRAPH_HEIGHT, iXPos-GRAPH_STEP, 0); /* Update the last y-value for the player i */ piLastValue[i] = iYPos; } /* Go to the next X position */ iXPos+=GRAPH_STEP; } /************************************************************************ * FUNCTION: * HISTORY: * 02.19.95 ESF Created. * PURPOSE: * NOTES: ************************************************************************/ void STAT_UpdateArmies(Int32 iPlayer, Int32 iArmies) { Int32 iSlot = STAT_PlayerToSlot(iPlayer); char buf[256]; if (iSlot != -1) { snprintf(buf, sizeof(buf), "%d", iArmies); XtVaSetValues(wStatPlayerArmies[iSlot], XtNlabel, buf, NULL); } } /************************************************************************ * FUNCTION: * HISTORY: * 02.19.95 ESF Created. * PURPOSE: * NOTES: ************************************************************************/ void STAT_UpdateCountries(Int32 iPlayer, Int32 iCountries) { Int32 iSlot = STAT_PlayerToSlot(iPlayer); char buf[256]; if (iSlot != -1) { snprintf(buf, sizeof(buf), "%d", iCountries); XtVaSetValues(wStatPlayerCountries[iSlot], XtNlabel, buf, NULL); } } /************************************************************************ * FUNCTION: * HISTORY: * 02.19.95 ESF Created. * PURPOSE: * NOTES: ************************************************************************/ void STAT_UpdateCards(Int32 iPlayer, Int32 iCards) { Int32 iSlot = STAT_PlayerToSlot(iPlayer); char buf[256]; if (iSlot != -1) { snprintf(buf, sizeof(buf), "%d", iCards); XtVaSetValues(wStatPlayerCards[iSlot], XtNlabel, buf, NULL); } } /************************************************************************ * FUNCTION: * HISTORY: * 02.19.95 ESF Created. * PURPOSE: * NOTES: ************************************************************************/ void STAT_UpdateWinLoseDraw(Int32 iPlayer) { Int32 iSlot = STAT_PlayerToSlot(iPlayer); char buf[256]; if (iSlot != -1) { snprintf(buf, sizeof(buf), "%d/%d/%d", piPlayerWin[iPlayer], piPlayerLose[iPlayer], piPlayerDraw[iPlayer]); XtVaSetValues(wStatPlayerWLD[iSlot], XtNlabel, buf, NULL); } } /************************************************************************ * FUNCTION: * HISTORY: * 02.19.95 ESF Created. * PURPOSE: * NOTES: ************************************************************************/ void STAT_PlayerCreated(Int32 iPlayer) { Int32 iSlot; /* Search for open slot */ for (iSlot=0; iSlot < MAX_PLAYERS; iSlot++) if (piSlotToPlayer[iSlot] == -1) break; /* There MUST be a slot */ D_Assert(iSlot >= MAX_PLAYERS, "Whoa, dude! Bogus player somewhere?!"); /* Actually dump the data to the slot */ STAT_RenderSlot(iSlot, iPlayer); } /************************************************************************ * FUNCTION: * HISTORY: * 02.19.95 ESF Created. * PURPOSE: * NOTES: ************************************************************************/ void STAT_PlayerDestroyed(Int32 iPlayer) { Int32 iSlot, i; /* Which slot is the player in? */ iSlot = STAT_PlayerToSlot(iPlayer); D_Assert(iSlot != -1, "Player should be in table!"); /* Move all the other entries up */ for (i=iSlot; (i