commit ba30e92f1b9a96533b08f63509b446d1ea18b435 Author: creme Date: Tue Feb 11 13:52:34 2020 +0000 init source v1.3.0 diff --git a/COPYING b/COPYING new file mode 100644 index 0000000..5e48515 --- /dev/null +++ b/COPYING @@ -0,0 +1,334 @@ +GNU GENERAL PUBLIC LICENSE + +Version 2, June 1991 + +Copyright (C) 1989, 1991 Free Software Foundation, Inc. 675 +Mass Ave, Cambridge, MA 02139, 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. + +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. + +one line to give the program's name and an idea of what it does. +Copyright (C) 19yy name of author + +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., 675 Mass Ave, Cambridge, MA 02139, 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. + +signature of Ty Coon, 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. + diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..d68866c --- /dev/null +++ b/Makefile @@ -0,0 +1,44 @@ +# +# Makefile for Starlanes +# +CC=/usr/bin/gcc +#CCOPTS=-Wall +CCOPTS=-O2 +CURSESLIB=ncurses +INSTALLDIR=/usr/local + +all: starlanes + +clean: *.o starlanes + rm -f *.o starlanes + +ai.o: ai.c common.h + $(CC) -g $(CCOPTS) -c ai.c + +starlanes.o: starlanes.c ai.c common.h + $(CC) -g $(CCOPTS) -c starlanes.c + +starlanes: starlanes.o ai.o + $(CC) -g starlanes.o ai.o -o starlanes -l$(CURSESLIB) + +install: + cp starlanes $(INSTALLDIR)/bin + cp starlanes.6 $(INSTALLDIR)/man/man6/ + chown bin:bin $(INSTALLDIR)/bin/starlanes + chown root:root $(INSTALLDIR)/man/man6/starlanes.6 + chmod 755 $(INSTALLDIR)/bin/starlanes + chmod 444 $(INSTALLDIR)/man/man6/starlanes.6 + +# fakeinstall just echos the install commands: +fakeinstall: + @echo cp starlanes $(INSTALLDIR)/bin + @echo cp starlanes.6 $(INSTALLDIR)/man/man6 + @echo chown bin:bin $(INSTALLDIR)/bin/starlanes + @echo chown root:root $(INSTALLDIR)/man/man6/starlanes.6 + @echo chmod 755 $(INSTALLDIR)/bin/starlanes + @echo chmod 444 $(INSTALLDIR)/man/man6/starlanes.6 + + + + + diff --git a/README b/README new file mode 100644 index 0000000..bb56aa8 --- /dev/null +++ b/README @@ -0,0 +1,36 @@ +Type "make" to build the starlanes binaries, then sign on as root +an type "make fakeinstall" +which will, uh, pretend to install everything. If all the commands that +it's going to execute look correct, go ahead and type "make install" (as +root) to install the goods. + +I would like to claim that the reason there is no +configure file is because for a small program +a configure file would be overkill but the +truth is that I don't as yet know how to make +one. Hence the make file may need adjusting. +For instance sometimes the curses program is +called plain curses and sometimes ncurses +It also expects there to be a /man/man6/ directory +in which case you should + +Please, if you have any problems while installing +let me, David, know ("dejvid@zamir.net" and +"dejvid@barnsdle.demon.co.uk") even if you +solve them. + +Of course you can always just change to the directory where +you installed starlanes and type "./starlanes" + +David +"dejvid@zamir.net" and "dejvid@barnsdle.demon.co.uk" + +This is a port to C from a version of Starlanes for the Osborne 1. The +original source is from a First Osborne Group (FOG) disk that I probably +picked up in 1982. The author isn't identified. Based on comments in +a TRS-80 version I picked up off the web, it would appear that it was +first published in Creative Computing magazine. + +-Beej +beej@ecst.csuchico.edu + diff --git a/ai.c b/ai.c new file mode 100644 index 0000000..7022b4c --- /dev/null +++ b/ai.c @@ -0,0 +1,383 @@ +/* Artificial Inteligence -anything in relation to non human players */ + +/* +** 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., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include +#include +#include +#include "common.h" + + + +/* +int move; +char map[120]; */ + + +/* +**void generate_nme(nme) +**used in place of getting name from humans +*/ +#define up_obj(move) (((move)-MAPX < 0)?OFFMAP:map[(move)-MAPX]) +#define down_obj(move) (((move)+MAPX >= MAPX*MAPY)?OFFMAP:map[(move)+MAPX]) +#define left_obj(move) (((move)%MAPX)?map[(move)-1]:OFFMAP) +#define right_obj(move) (((move)%MAPX == MAPX-1)?OFFMAP:map[(move)+1]) + +void generate_nme(char *nme) +{ + static int nmeNmr=0; + + switch(nmeNmr) { + case 0: strcpy(nme, "Vorg");break; + case 1: strcpy(nme, "Zhara");break; + case 2: strcpy(nme, "Dushan");break; + case 3: strcpy(nme, "Peko Pekovich");break; + case 4: strcpy(nme, "Agram Anastija");break; + default: strcpy(nme, "Man with no name");break; + }; + nmeNmr++; +} + +enum compass { North,East ,West,South } ;//type; + +enum farcompass {NorthW , FNorth, NorthE, FEast ,SouthE ,FSouth, SouthW ,FWest};// type; + +enum investstatus { none,small ,signif,main };// type; + +/* getfarmove gets the charecter value of a location 2 steps away. +** It makes no distiction between an empty space and an off map +** location +*/ +char getfarmove(enum farcompass fcom, char *map, int loc) +{ + static int MAPX=Mx ; + static int MAPY=My; + char ch; + switch(fcom) { + case NorthW: if ((loc-1*MAPX )< 0) ch=SPACE; + else { + ch=left_obj(loc-1*MAPX); + } + break; + case FNorth: if ((loc-2*MAPX )< 0) ch=SPACE; else ch=map[loc-2*MAPX];break; + case NorthE: if ((loc-1*MAPX )< 0) ch=SPACE; + else { + ch=right_obj(loc-1*MAPX); + } + break; + case FEast: if ((loc%MAPX)!=((loc+2)%MAPX)) ch=map[loc+2]; + else ch=SPACE ; + break; + case SouthE: if ((loc+MAPX )> (MAPX*MAPY)) ch=SPACE; + else { + ch=right_obj(loc+1*MAPX); + } + case FSouth: if ((loc+2*MAPX) > (MAPX*MAPY)) ch=SPACE; else ch=map[loc-2*MAPX];break; +/*(((loc)+2*MAPX > MAPX*MAPY)?SPACE:map[(loc)+2*MAPX]);break;*/ + case SouthW: if ((loc+MAPX )> (MAPX*MAPY)) ch=SPACE; + else { + ch=left_obj(loc+1*MAPX); + } + case FWest: if ((loc%MAPX)!=((loc-2)%MAPX)) ch=map[loc-2]; + else ch=SPACE ; + break; +/*if ((loc%MAPX)!=(loc-2)%MAPX))) ch=map[(loc)-2];else ch=SPACE;break;*/ + default: ch= '?';break; + }; + return ch; +} + +enum compass revdir(enum compass dir) +{ + enum compass rev; + switch(dir) { + case North:rev=South; break; + case East:rev=West; break; + case West:rev=East; break; + case South:rev=North; break; + } +return rev; +} + +int onestep(enum compass dir, int loc) +{ + int newloc; + switch(dir) { + case North:if ((loc)-Mx < 0) newloc=-1; + else newloc=loc-Mx; + break; + case South:if ((loc)+Mx > Mx*My) newloc=-1; + else newloc=loc+Mx; + break; + case West: if ((loc)%Mx ==0)newloc=-1; + else newloc=loc-1; + break; + case East: if ((loc)%Mx ==Mx-1)newloc=-1; + else newloc=loc+1; + break; + } + return newloc; +} + + +/* +** placemove( move) +** place move is passed the location of the numbers +** that appear on the screen to humans and selects one of these +** locations for the computer players move +*/ + +char placemove(PLAYER *pla,int *move, COMPANY *co, int turn,char *map, int Difficulty) +{ + static int MAPX=Mx ,MAPY=My; + char mvch; long moveval[NUMMOVES]; int neighb[4];int nc, ncom; + enum compass dir; + enum investstatus curst[NUMCO]; + double coholdings[NUMCO]; double tothold[NUMCO];int curpl; + char locs[South]; + int seed,intchar ,mvop,curCo,curMax, + smallC,bigC; /*this is for the implications of each move */ + long bgain,sgain; /* gains in mergers */ + + mvch= '1'; + curMax=-1000; + if ((Difficulty>1 )||(rand()%100>50)) + for (curCo=0;curCo<=NUMCO;curCo++){ + tothold[curCo] =0; + /*finds the proportion of holdings relativ to other players*/ + for (curpl=0;curpl0) curst[curCo]=signif; + else curst[curCo]=none; + } + if ((Difficulty>1 )||(rand()%100>50)) + for (mvop=0;mvop<=4;mvop++){ + seed=0; + locs[North] = up_obj(move[mvop]); + locs[South] = down_obj(move[mvop]); + locs[West] = left_obj(move[mvop]); + locs[East] = right_obj(move[mvop]); + moveval[mvop]=NEWCOCOST; + ncom=0; + for(dir=North;dir<=South;dir++){ + if (locs[dir]== STAR) moveval[mvop]=moveval[mvop]+STARCOST ; + if (locs[dir]== BLACKHOLE) moveval[mvop]=moveval[mvop]+BLACKHOLECOST ; + if (locs[dir]== NEWCO) { + moveval[mvop]=moveval[mvop]+NEWCOCOST ; + } + if iscompany(locs[dir]) { + nc=locs[dir]-'A'; + if ((ncom==0)||(nc!=neighb[1])){ + ncom++; /* todo add for cases when 3 co ajacent*/ + neighb[ncom]= nc; + } + } + } + if (ncom==0) if (moveval[mvop]>100) moveval[mvop]*=FOUNDER_BONUS; else moveval[mvop]=0 ; + /*need to check here whether company eliminated by black hole */ + else if (ncom==1){ + /*if company next door and holding is minimal then value will be reversed*/ + moveval[mvop]=moveval[mvop]*( coholdings[neighb[1]]-0.25)*tothold[ncom]; + } + else if (ncom>1){ + /*calculate value of merger*/ + smallC=1; + bigC=1; + for (curCo=2;curCo<=ncom;curCo++){ + if (co[neighb[curCo]].priceco[neighb[bigC]].price) + bigC= curCo; + } + sgain=co[neighb[smallC]].price*tothold[neighb[smallC]]* + (coholdings[neighb[smallC]]-0.25)/2;/*bonus*/ + sgain+=co[bigC].price*tothold[neighb[smallC]]* + (coholdings[neighb[smallC]]-0.25); + bgain=(moveval[mvop]+co[neighb[smallC]].price)* + tothold[neighb[bigC]]*(coholdings[neighb[bigC]]-0.25); + moveval[mvop]=sgain+bgain; + + } + if (moveval[mvop]>curMax) { + intchar= mvop +(int)'1'; + mvch= (char) intchar; + curMax=moveval[mvop] ; + } + } + else mvch=1; + return mvch; +} + + +/* +** distantblackhole starts at the black hole, moves two away and then +** looks at the three ajacent points for companies. It then increases +** the risk factor for any companies found. It isn't +** always able to detect when the route between the black hole +** and company is blocked so sometimes sees a risk that isn't there. +*/ + +void distantblackhole(COMPANY *co,char *map,int loc) +{ + int step,cloc; + enum compass dir,end; + int neighb[4], ncom, new,isnew,curCo; + + for (dir=North;dir<=South;dir++){ + step =onestep(dir, loc); + if (step>-1) if (map[step]==SPACE){ + step =onestep(dir, step); + ncom=0; + if (step>-1) if (!(iscompany(map[step]))) for (end=North;end<=South;end++) + if (end!=revdir(dir)){ /*point ajacent bh checked elsewhere*/ + cloc= onestep(end, step); + if iscompany(map[cloc]) { + new=map[cloc]-'A'; + isnew=1; + curCo=0; + while ((curCo<=ncom) && (isnew==1)){ + if (curCo==ncom) /* no need to check if co already found if first */ + neighb[curCo]=new; + else if (neighb[curCo]==new) isnew=0; + curCo++; + } + if (isnew==1) { + ncom++; + neighb[curCo]=new; + } + } + } + curCo=1; + while (curCo<=ncom){ + co[neighb[curCo]].risk+= BLACKHOLECOST/2; + curCo++; + } + } + } +} + +/* +**ai_buy_sell not only choses the most promising investments but +**actually executes the sales +*/ + +void ai_buy_sell(PLAYER *pl, COMPANY *co, int turn,char *map, int Difficulty) +{ + int curloc,curCo,BuyCo,SecCo,amt ; + static int MAPX=Mx , MAPY=My; + int localpt, localris; + enum compass dir; + int neighb[4]; + int nc, ncom,smallC,bigC; + char locs[South]; + + for(curCo=0;curCo2 )||(rand()%100>50)) + if (locs[dir]== BLACKHOLE) + localris=localris+BLACKHOLECOST;/*loss from the point*/ + if (locs[dir]== NEWCO) localpt=localpt+NEWCOCOST ; + } + } + ncom=0; + for(dir=North;dir<=South;dir++){ /*Then add those values to the potetial of companies*/ + if (iscompany(locs[dir])) { /*that are in the vicinity */ + nc=locs[dir]-'A'; + if ((ncom==0)||(nc!=neighb[1])){ + ncom++; /* todo add for cases when 3 co ajacent*/ + neighb[ncom]= nc; + } + } + } + if (ncom==1 ){ + co[nc].potential=co[nc].potential+localpt; + co[nc].risk=co[nc].risk+localris; + } + else if (ncom>1){ + smallC=1; + bigC=1; + for (curCo=2;curCo<=ncom;curCo++){ + if (co[neighb[curCo]].priceco[neighb[bigC]].price) + bigC= curCo; + } + /* bonus ignored for now*/ + co[neighb[bigC]].potential=co[neighb[bigC]].potential+(co[neighb[smallC]].price); + co[neighb[smallC]].potential=co[neighb[smallC]].potential+co[neighb[bigC]].price/2; + } + } + + SecCo=BuyCo=-1 ; + for(curCo=0;curCo0) { + co[curCo].netpot=(co[curCo].potential+co[curCo].risk)/ + (co[curCo].price); + if ((co[curCo].netpot>0)){ + if (BuyCo==-1) BuyCo=curCo; + else { + if (co[curCo].netpot>co[BuyCo].netpot) { + SecCo=BuyCo; + BuyCo=curCo; + } + else { + if (SecCo==-1) SecCo=curCo; + else if (co[curCo].netpot>co[SecCo].netpot) + SecCo=curCo; + } + } + } + } + if ((Difficulty>2 )||((Difficulty>1 )&&(rand()%100>50)) ) + for(curCo=0;curCo-1){ /*now buy shares in the company with the best prospects*/ + if (co[BuyCo].risk<0) { /*don't put all your eggs into one basket*/ + amt= pl[turn].cash/(co[BuyCo].price*2); + pl[turn].cash += (-amt * co[BuyCo].price); + pl[turn].holdings[BuyCo] += amt; + if (SecCo>-1){ + amt= pl[turn].cash/co[SecCo].price; + pl[turn].cash += (-amt * co[SecCo].price); + pl[turn].holdings[SecCo] += amt; + } + } + else { + amt= pl[turn].cash/co[BuyCo].price; + pl[turn].cash += (-amt * co[BuyCo].price); + pl[turn].holdings[BuyCo] += amt; + } + } +} diff --git a/ai.o b/ai.o new file mode 100644 index 0000000..7420b73 Binary files /dev/null and b/ai.o differ diff --git a/changelog b/changelog new file mode 100644 index 0000000..75bcf08 --- /dev/null +++ b/changelog @@ -0,0 +1,13 @@ +Version 1.3.0 released 2004 by David Barnsdale +dejvid@barnsdle.demon.co.uk and dejvid@zamir.net + +AI implemented. All AI related stuff placed in "ai.c". + +Information screen giving holdings of all players added. + +Bug caused by player earning excess money removed. + + + +Version 1.2.2 released 1997 by Brian "Beej" Hall +"beej@ecst.csuchico.edu" diff --git a/common.h b/common.h new file mode 100644 index 0000000..e7b4ff9 --- /dev/null +++ b/common.h @@ -0,0 +1,69 @@ +/* +** 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., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#define OFFMAP '-' /* space character */ +#define SPACE '.' /* space character */ +#define NEWCO '+' /* new company character */ +#define STAR '*' /* star character */ +#define BLACKHOLE '@' /* black hole character */ + +#define NUMCO 5 /* number of companies (don't change) */ +#define INIT_CO_COST 100 /* initial company start cost */ +#define FOUNDER_BONUS 5 /* founder gets this much stock */ +#define NUMMOVES 5 /* number of moves options a player gets */ +#define MAXPLAYERS 4 /* total number of players a game can have */ +#define STARCOST 500 /* company's price increase near star */ +#define BLACKHOLECOST -500 /* price increase near black hole */ +#define NEWCOCOST 100 /* company's price increase near new co */ + + +#define Mx 12 /* x dimension of map */ +#define My 10 /* y dimension of map */ + +/* macros to look at surrounding spaces on the map: */ + + +#define iscompany(c) ((c)>='A'&&(c)<='Z') +#define ripe(c) ((c)==STAR||(c)==NEWCO) +#define co_near(move) (iscompany(up_obj(move))||iscompany(down_obj(move))||iscompany(left_obj(move))||iscompany(right_obj(move))) +#define s_or_bh(c) ((c)==SPACE||(c)==BLACKHOLE) + + + + + +/* player and company structures: */ + +typedef struct { + char name[100]; + int holdings[NUMCO]; + long int svalue; /* stock value -- not always accurate!! */ + long int cash; + int ishuman; +} PLAYER; + +typedef struct { + char name[100]; + int price; + int size; + int potential; + int risk; /* value related to chance of being swallowed by Black Hole */ + int netpot; /* potential - risk */ +} COMPANY; + + + + diff --git a/starlanes b/starlanes new file mode 100755 index 0000000..ad867a6 Binary files /dev/null and b/starlanes differ diff --git a/starlanes.6 b/starlanes.6 new file mode 100644 index 0000000..09f8e66 --- /dev/null +++ b/starlanes.6 @@ -0,0 +1,425 @@ +.TH STARLANES 6 "29 March 1996" "Starlanes V1.2.2" +.SH NAME +starlanes \- the game of starlanes +.SH SYNOPSIS +.BR "starlanes " [ -v | c | m ] +.SH DESCRIPTION +.B Starlanes +is a game of interstellar commerce for 1 to 4 players. Players take +two-phase turns: the first phase is movement, the second is trading. +.PP +The object of the game is to become as wealthy as possible by trading +and merging companies whilst out-smarting your friends and enemies. +.SH OPTIONS +.TP 5 +-v +Print version information +.TP 5 +-c +Force the game to play in color mode +.TP 5 +-m +Force the game to play in mono mode +.SH PLAYING STARLANES +.SS The Starlanes User Interface +.B Starlanes +is written using color ncurses, but will detect a black and white +screen and will modify its output accordingly. On Linux, setting +.B TERM=console +or +.B TERM=linux +either on a virtual console or in a +.B color_xterm +window works well. +.PP +After the initial player determination screen, you will be presented +with the main +.B Starlanes +screen. This screen is split into three individual windows: the +.BR "map window" , +the +.BR "company window" , +and the +.BR "general info window" . +.PP +The +.B map window +shows the terrain of the universe. The legend is: +.PP +.RS +.BR * " - Star" +.br +.BR @ " - Black hole" +.br +.BR + " - Infant company" +.br +.BR . " - Empty space" +.br +.BR A +- Company A (Altair Starways) +.RE +.PP +The companies are +.BR "Altair Starways" , +.BR "Beetlejuice Ltd." , +.BR "Capella Freight Co." , +.BR "Denebola Shippers" , +and +.BR "Eridani Expediters" . +On the map, the companies are represented by the first letter of their +name. +.PP +The +.B company window +shows information concerning the currently existing companies, +including the company name, its price per share, and the current +player's holdings. +.PP +The +.B general info window +will prompt the user for input if the player is waiting to move or +trade, but will also display special announcements as they come up. +During a player's turn, that player's name is displayed in the title +bar of the window, along with his cash holdings. +.PP +Also, mention should be made of two other windows: the +.B player standings window +and the +.B company detail window +(not to be confused with the +.BR "company info window" .) +.PP +The +.B player standings window +can be brought up during the player's move by pressing the +.RB ' s ' +key. This window shows all the player's names, stock holdings, cash, +and total worth, sorted by total worth. It also shows the number of +sectors that remain to be filled by companies before the game ends. +.PP +The +.B company detail window +is invoked with the +.RB ' c ' +key. It shows, for each active company, its name, price per share, +size, and total worth (all player's shares * price per share). The +company size and total worth are useful in determining the result of a +.B merger +(see below.) +.PP +If a screen redraw is necessary, pressing +.RB ' ^L ' +at almost any of the prompts will accomplish that. +.PP +Finally, if the players want to +.B quit +before the game before is over, press +.RB ' q ' +or +.RB ' ^C ' +and a quit verification window will pop up. If +.RB ' y ' +is pressed, the final game standings will be displayed, and the +program will end. +.SS Player Movement +During the first phase of a player's turn, the computer will prompt +for a move from a choice of 5. These moves are chosen randomly (for +the most part). Upon making your move, there are several things that +might happen. (NOTE: it is important to remember that two objects on +the map are adjacent +.I only +if they are orthogonally adjacent. Diagonals +.B don't +count!) +.PP +If you move into a sector that is completely surrounded by empty space +.RB ( . ), +that sector will then contain an infant company +.RB ( + ). +.PP +If you move next to an existing company +.RB ( A - E ), +that company will expand into that sector of the map. If the new +extension of the company touches an infant company +.RB ( + ), +that infant company will also be assimilated. +.PP +Given that you're not moving next to an existing company, if you move next +to a star +.RB ( * ) +or an infant company +.RB ( + ), +a new company will be formed. You, as company founder, will receive +.B 5 +shares in the company for free. For calculating how much a company +will be worth, see +.BR "Company Pricing" , +below. +.PP +If you happen to move next to a black hole +.RB ( @ ), +one of many things could happen, depending on the circumstances. See +.BR "Black Holes" , +below. +.SS Company Pricing +Determining a company's price per share is fairly simple. Generally +speaking, a company is worth +.B $100 +for every sector it occupies (as given on the +.B "company info window" +under ``Size''), plus +.BR $500 +for every sector it occupies which is adjacent to a star +.RB ( * ), +minus +.BR $500 +for every sector it occupies which is adjacent to a black hole +.RB ( @ ). +If a +company's price per share drops to 0 or less, the company vanishes +(see +.BR "Black Holes" , +below.) Also note that you will not be able to visually estimate a +company's price per share if that company has undergone a stock split +(see +.BR "Stock Splits" , +below.) +.SS Holding Bonus +Immediately after a player's move, he is awarded a cash bonus equal to +.B 5% +of the total worth of his complete holdings. This bonus is awarded +even if the game ends directly following the move (see +.BR "Game's End" , +below.) This is the cash that the player will then use during the +trading phase (see +.BR Trading , +below.) +.SS Trading +If any companies exist after a player moves on the map, that player +will be given the chance to buy and sell stock. This is where the +game is really played. One must determine which companies are going +to earn the highest profits in the next round and invest in those +companies more heavily than ones that only have a small chance of turning a +profit. (See +.BR Strategy , +below.) The current player's cash value is printed next to his name +in the +.B general info window +title. +.PP +Use the arrow keys to select a company you wish to trade stock in, +then press +.BR return . +You will be asked for an amount to trade. Enter the number of shares +you wish to purchase in this company. (Just press +.B return +again or enter +.RB `` 0 '' +if you don't really want to trade with this company.) +Choose a negative amount if you want to sell shares (at +.B 100% +of their value.) At this point, the user can also press the +.RB ' m ' +key to purchase the maximum number of shares possible, or press the +.RB ' n ' +key to sell all of his holdings in this company. +.PP +Once the player has completed trading, he can press +.B escape +to end his turn, thereby transferring control to the next player. +.SS Mergers +When a player chooses a sector of the map that would cause two or +more companies to touch, a +.B merger +occurs. +.PP +First, the companies sizes are checked +and the company with the larger size absorbs the smaller. +.PP +If the companies are the same size, the company with the highest total +worth absorbs the smaller. +(The user can view company size and company total worth on the +.BR "company detail window" , +see above.) +.PP +Finally, if both company sizes and total worths match, the companies +will merge at random. +.PP +If a three or four-way +.B merger +occurs, the merges will take place one at a time, in an order that is +somewhat clockwise. +.PP +After a +.BR merger , +each player will have half the number of shares of +held in the vanquished company added to the number of shares held in the +still-existing company. The value of the still-existing company's +price per share will increase by the vanquished company's +price per share. +.PP +Additionally, each player receives a cash bonus equal to +.PP +.RS +.RB "10 * " "stock price" " * " "holdings percentage" , +.RE +.PP +where +.B stock price +is the old price per share of the vanquished company and +.B holdings percentage +is the percentage of total stock once owned in the vanquished company. +For example, imagine that +.B Altair Starways +(worth +.B $500 +per share) is merged into +.BR "Denebola Shippers" . +Also, assume that the player owned +.B 50% +of the total shares in +.BR "Altair Starways" . +Using the formula, that player would receive a bonus of +.PP +.RS +.RB "10 * " $500 " * " 50% " = " $2,500 . +.RE +.PP +For more hints on how to deal with +.BR mergers , +see +.BR Strategy , +below. +.SS Stock Splits +When a company's price per share climbs above +.BR $3,000 , +a +.B stock split +occurs. All player holdings in that company are doubled, and the +price per share is halved. See +.BR Strategy , +below, for money making tips during and after stock splits. +.SS Black Holes +Since +.B black holes +drain +.B $500 +from any company that is in contact with them, it is possible that the +company's price per share will drop to 0 or less. If this happens, +the entire company is sucked out of space and all player holdings are +lost. +.PP +If a player attempts to place an infant company +.RB ( + ) +near a +.BR "black hole " ( @ ), +that infant company will be immediately sucked up, resulting again in +an empty sector. +.PP +Likewise, if a player attempts to start a new company that would +normally be worth $500 or less per share next to a +.BR "black hole" , +the sectors that the new company would have occupied all become empty +space +.RB ( . ). +.PP +For some ways to make +.B black holes +work to your advantage, see +.BR Strategy , +below. +.SS Game's End +The game ends when +.B 54% +of the map is filled with companies (about +.B 70 +sectors.) The player who made the final move receives his +.B 5% +holdings bonus (see +.BR "Holding Bonus" , +above) and the final standings window is displayed. The player with +the highest total worth is the winner. +.SS Strategy +In order to maximize your profits, you must wisely invent your cash. +For instance, if a company is near a black hole, it is likely that it +will lose $500 per share in the next few rounds. Likewise, if a +company is near a star, it might soon have a $500 gain. +.PP +Also, the +larger the company, the greater that chance that it will be added onto +(just because it takes up more room on the map.) If you own 300 +shares in a company, and its value goes up by $100 per share, that's a +$30,000 increase in your net worth. +.PP +Another thing to watch for is when companies are about to merge. +Remember that the number of shares you own in the smaller company will +be halved before being added to the bigger one when they merge. This +can be used to your advantage, especially if the smaller company is +worth significantly less than the larger. If the big company is worth +$2,000 per share, and the small is worth $200 per share, you can buy 10 +times as many shares in the smaller. When the companies merge, the +number of shares in the smaller company is halved, but it's still 5 +times the amount of stock you could've purchased in the larger company. +.PP +Don't forget that when two companies merge, the players receive a cash +bonus that depends on the percentage of stock they owned in the +smaller company (see +.BR Mergers , +above.) It is good to try to own a higher percentage than anyone +else. +.PP +A way to gain profit earning potential is to have a large number of +shares in a company when the stock splits two-for-one (see +.BR "Stock Splits" , +above.) Even though your initial net worth remains the same after a +stock split, you'll now increase your net worth by twice the value you +used to whenever the company's price per share rises. Also, if your +opponent has 100 shares and you have 150 before the split, that'll +change to 200 shares and 300 shares, effectively increasing your lead +in shares by 100%. +.PP +Black holes weren't present in the original game, but were added to +give players who have fallen behind a chance to shaft the leaders. If +your opponent owns 100 shares of Altair Starways and you only own 50, +you can extend the company against a black hole. Your opponent will +lose $50,000 from his net worth, but you'll only lose $25,000. +.PP +Finally, a reminder to invest as much money as you possible can each +round (unless it's too risky.) The reason for this is the 5% cash +bonus all players receive each round based on their holdings (see +.BR "Holdings Bonus" , +above.) Your cash earns you no interest. +.SH FILES +.I /usr/local/games/starlanes +.br +.I /usr/local/man/man6/starlanes.6 +.SH AUTHOR +This version of +.B Starlanes +was written and is Copyright (C) by Brian +.RB `` Beej '' +Hall 1995-1997. The author can be reached at +.BR beej@ecst.csuchico.edu . +.B Starlanes +comes with ABSOLUTELY NO WARRANTY. This is +free software, and you are welcome to redistribute it under certain +conditions; read the file +.I COPYING +for details. +.SH ACKNOWLEDGMENTS +I'd like to thank the unnamed authors of the original Starlanes for +creating such a thought provoking and fun to play text-based game. I +got my first copy on a First Osborne Group (FOG) disk in what must have +been 1982 or so, and used to spend endless hours playing against my +friends. For us, the game is just as fun as ever. To the original +authors, I salute you! +.SH BUGS +There are no computer controlled players. +.PP +Doesn't respond if ^Z is pressed to suspend the game. +.PP +If only one person is playing, he or she will frequently make enough +money to break the fixed-field-length windows and/or cause the +variable that holds player cash to overflow. Try to keep your +earnings under $2 billion until I convert these variables to long +doubles. :-) diff --git a/starlanes.c b/starlanes.c new file mode 100644 index 0000000..f8d51f3 --- /dev/null +++ b/starlanes.c @@ -0,0 +1,1570 @@ +/* +** starlanes v1.3.0 (29-Mar-1997) -- a space-age stock trading game +** +** Copyright (C) 1997 Brian "Beej" Hall +** with modifications by David Barnsdale 2004 +** +** 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., 675 Mass Ave, Cambridge, MA 02139, USA. +** +** For more information, contact "beej@ecst.csuchico.edu" +** or "dejvid@zamir.net" and "dejvid@barnsdle.demon.co.uk" +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include "common.h" + + + +/* color stuff: */ + +#define BLUE_ON_BLACK COLOR_PAIR(1) +#define RED_ON_BLACK COLOR_PAIR(2) +#define GREEN_ON_BLACK COLOR_PAIR(3) +#define YELLOW_ON_BLACK COLOR_PAIR(4) +#define MAGENTA_ON_BLACK COLOR_PAIR(5) +#define CYAN_ON_BLACK COLOR_PAIR(6) +#define WHITE_ON_BLACK COLOR_PAIR(7) +#define YELLOW_ON_BLUE COLOR_PAIR(8) +#define WHITE_ON_BLUE COLOR_PAIR(9) +#define BLACK_ON_YELLOW COLOR_PAIR(10) +#define BLACK_ON_WHITE COLOR_PAIR(11) +#define BLACK_ON_RED COLOR_PAIR(12) +#define BLACK_ON_BLUE COLOR_PAIR(13) +#define BLACK_ON_GREEN COLOR_PAIR(14) + +#define MAP_TITLE (color?(BLACK_ON_WHITE):(A_REVERSE)) +#define MAP_BORDER (color?(WHITE_ON_BLACK|A_BOLD):(A_BOLD)) +#define MAP_SPACE (color?(WHITE_ON_BLACK):(A_NORMAL)) +#define MAP_STAR (color?(YELLOW_ON_BLACK|A_BOLD):(A_BOLD)) +#define MAP_NEWCO (color?(CYAN_ON_BLACK):(A_NORMAL)) +#define MAP_BLACKHOLE (A_NORMAL) +#define CO_A (color?(BLUE_ON_BLACK|A_BOLD):(A_NORMAL)) +#define CO_B (color?(GREEN_ON_BLACK):(A_NORMAL)) +#define CO_C (color?(YELLOW_ON_BLACK):(A_NORMAL)) +#define CO_D (color?(RED_ON_BLACK):(A_NORMAL)) +#define CO_E (color?(MAGENTA_ON_BLACK):(A_NORMAL)) + +#define GENERAL_TITLE (color?(WHITE_ON_BLUE|A_BOLD):(A_REVERSE)) +#define GENERAL_TITLE_BLINK (color?(WHITE_ON_BLUE|A_BOLD|A_BLINK):(A_REVERSE|A_BLINK)) +#define GENERAL_BORDER (color?(BLUE_ON_BLACK):(A_NORMAL)) +#define GENERAL_TEXT (A_NORMAL) + +#define COINFO_TITLE (color?(BLACK_ON_GREEN):(A_REVERSE)) +#define COINFO_TEXT (A_BOLD) + +#define STAND_TITLE (color?(YELLOW_ON_BLUE|A_BOLD):(A_REVERSE)) +#define STAND_BORDER (color?(BLUE_ON_BLACK):(A_BOLD)) +#define STAND_HEADER (color?(WHITE_ON_BLUE):(A_REVERSE)) + +#define MORE_COINFO_TITLE (color?(YELLOW_ON_BLUE|A_BOLD):(A_REVERSE)) +#define MORE_COINFO_BORDER (color?(BLUE_ON_BLACK):(A_BOLD)) +#define MORE_COINFO_HEADER (color?(WHITE_ON_BLUE):(A_REVERSE)) + +#define QUIT_TITLE (color?(BLACK_ON_RED):(A_REVERSE)) +#define QUIT_BORDER (color?(RED_ON_BLACK):(A_BOLD)) +#define QUIT_TEXT (color?(YELLOW_ON_BLACK|A_BOLD):(A_NORMAL)) + +/* macros to look at surrounding spaces on the map: */ + +#define up_obj(move) (((move)-MAPX < 0)?SPACE:map[(move)-MAPX]) +#define down_obj(move) (((move)+MAPX >= MAPX*MAPY)?SPACE:map[(move)+MAPX]) +#define left_obj(move) (((move)%MAPX)?map[(move)-1]:SPACE) +#define right_obj(move) (((move)%MAPX == MAPX-1)?SPACE:map[(move)+1]) + + +/* misc stuff: */ + + +#define INIT_CO_COST 100 /* initial company start cost */ +#define INIT_CASH 6000 /* initial player cash */ +#define SPLIT_PRICE 3000 /* when stocks split 2-1 */ + + +/* #define NUMMOVES 5 number of different moves a player gets */ + +#define END_PERCENT 54 /* end when this much of the map is full */ +#define DEF_LINES 25 /* default number of lines on screen */ +#define DEF_COLUMNS 80 /* default number of columns on screen */ + +#define CR 13 /* various keys */ +#define LF 10 +#define BS 8 +#define DEL 127 +#define ESC 27 +#define CTRL_L 12 +#define CTRL_C 3 +#define CTRL_Z 26 + + + + + +/* function prototypes: */ + +extern void generate_nme(char *nme); +extern char placemove( PLAYER *pla,int *move, COMPANY *co, int turn,char *map, int Difficulty); +extern void ai_buy_sell(PLAYER *pla, COMPANY *com, int turn,char *map, int Difficulty); + +void initialize(void); +void color_setup(void); +void get_num_players(void); +void showmap(void); +void drawmap(int loc, char c); +int get_move(void); /*called by main */ +void show_coinfo(void); +void more_coinfo(void); +void do_move(int move); +void do_merge(int *c1, int *c2, int *o1, int *o2); +void holding_bonus(void); +void holding_bonus(void); +void buy_sell(void); +int check_endgame(void); +int count_used_sectors(void); +void calc_cost(int cnum, int move, int n, int s, int w, int e); +void new_co_announce(int newc); +void suck_announce(int conum, int grown); +void merge_announce(int c1, int c2); +void xaction_announce(int c1, int c2); +void split_announce(int conum); +int co_avail(void); +void clear_general(char *s,int blink); +void center(WINDOW *win, int width, int row, char *s); +int my_mvwgetstr(WINDOW *win, int y, int x, int max, int restricted, char *s); +void redraw(void); +void show_standings(char *title); +void show_company_holdings(char *title); +int order_compare(const void *v1, const void *v2); +void quit_yn(void); +void shutdown(void); +void usage(void); +/* ai functions + typedef char nme[100]; + void generate_nme( char *nme); +char placemove(); */ +/* global variables */ + +char *VERSION = "1.3.0"; +char *VERSION_DATE = "1-June-2004"; +char *ident = "$Id: starlanes.c 1.2.2 29-Mar-1997 beej@ecst.csuchico.edu $"; + + +/* These two varibles must be cordinated with ai.c */ +/* These probably could be constants but untill I'm +sure they stay as variables. */ +int MAPX = Mx; /* x dimension of map */ +int MAPY = My; /* y dimension of map */ + +int LINES; /* lines in screen */ +int COLUMNS; /* columns in screen */ +char *map; /* pointer to the map data */ +char *mapc; /* copy of map for ai */ +PLAYER *pl; /* pointer to array of players */ +COMPANY *co; /* pointer to array of companies */ +int numplayers,turn; /* number of players, whose turn it is */ +WINDOW *mapwin,*general,*coinfo; /* pointers to the windows */ +int color; /* true if we want color */ +int sologame; /* set to true if nmr of playes is 0*/ +int Difficulty; + +int main(int argc, char *argv[]) +{ + int done = 0,move, colorforce=0, monoforce=0; + switch(argc) + { + case 1: break; + case 2: if (argv[1][1] == 'v') { + fprintf(stderr,"Starlanes for ncurses v%s Copyright (C) by Brian \"Beej\" Hall %s\n",VERSION,VERSION_DATE); + fprintf(stderr,"\nStarlanes comes with ABSOLUTELY NO WARRANTY. This is free\n"); + fprintf(stderr,"software, and you are welcome to redistribute it under\n"); + fprintf(stderr,"certain conditions. See the file COPYING for details.\n"); + exit(1); + } + else if (argv[1][1] == 'c') + colorforce = 1; + else if (argv[1][1] == 'm') + monoforce = 1; + else + usage(); + break; + default:usage(); + } + + /* initscr */ + initscr(); + start_color(); + + if (colorforce) + color = 1; + else if (monoforce) + color = 0; + else + color = has_colors(); + + if (color) color_setup(); + + raw(); + + /* init map, stocks */ + srand(time(NULL)); + initialize(); + + /* num players */ + get_num_players(); + + clear(); + attron(color?(YELLOW_ON_BLUE|A_BOLD):A_REVERSE); + mvprintw(0,0," StarLanes "); + attroff(color?(YELLOW_ON_BLUE|A_BOLD):A_REVERSE); + attron(color?BLUE_ON_BLACK:A_NORMAL); + printw("====================================================================="); + attroff(color?BLUE_ON_BLACK:A_NORMAL); + wnoutrefresh(stdscr); + showmap(); + show_coinfo(); + + do { + move = get_move(); + do_move(move); + holding_bonus(); + if ((done = check_endgame()) != 1) { + if (pl[turn].ishuman==1) buy_sell(); + else { + *mapc=*map ; + ai_buy_sell(pl,co,turn,map,Difficulty); + } + turn = (++turn)%numplayers; + } + } while (!done); + + shutdown(); + + return 0; +} + +/* +** initialize() - sets up the map, players, and companies +*/ + +void initialize(void) +{ + int i,j; + char *lines, *columns; + + /* get the size of the screen: */ + + if ((lines=getenv("LINES"))==NULL || (columns=getenv("COLUMNS"))==NULL) { + LINES = DEF_LINES; + COLUMNS = DEF_COLUMNS; + } else { + LINES = atoi(lines); + COLUMNS = atoi(columns); + } + + /* allocate space for everything: */ + + if ((map=malloc(MAPX*MAPY)) == NULL) { + fprintf(stderr,"starlanes: error mallocing space for map\n"); + exit(1); + } + if ((mapc=malloc(MAPX*MAPY)) == NULL) { + fprintf(stderr,"starlanes: error mallocing space for copy of map\n"); + exit(1); + } + + if ((co=calloc(1,NUMCO * sizeof(COMPANY))) == NULL) { + fprintf(stderr,"starlanes: error mallocing space for companies\n"); + exit(1); + } + + if ((pl=calloc(1,MAXPLAYERS * sizeof(PLAYER))) == NULL) { + fprintf(stderr,"starlanes: error mallocing space for players\n"); + exit(1); + } + + /* set up the map: */ + + for(i=0;i MAXPLAYERS); + addch(c+'0'); + + numplayers = (int)c; + if (numplayers == 0){ + numplayers=4; + sologame=1; + sprintf(s,"Please enter level (1 easiest,3 hardest)"); + center(stdscr,COLUMNS ,11,s); + refresh(); + noecho();raw(); + do { + Difficulty = getch()-'0'; + } while (Difficulty < 1 || Difficulty > 3); + addch(Difficulty+'0'); + } + else sologame =0; + + srand(getpid()); /* reseed the dumb random number generator */ + turn = rand()%numplayers; + + nl(); + for(plnmr=0;plnmr0){ + pl[plnmr].ishuman=0 /* here computer will generate a name */; + generate_nme(pl[plnmr].name); + } + else { + sprintf(s,"Player %d, enter your name: ",plnmr+1); + center(stdscr,COLUMNS-8 ,12+sologame+plnmr,s); + refresh(); + my_mvwgetstr(stdscr,plnmr+12+sologame,49,20,0,pl[plnmr].name); + /*getstr(pl[plnmr].name);*/ + if (pl[plnmr].name[0] == '\0') plnmr--; + } + } + nonl(); +} + + +/* +** showmap() -- draws the map in the map window +*/ + +void showmap(void) +{ + int i,j,attrs; + + wattron(mapwin,MAP_BORDER); + box(mapwin,'|','-'); + wattroff(mapwin,MAP_BORDER); + + wattron(mapwin,MAP_TITLE); + center(mapwin,MAPX*3+2,0," Map "); + wattroff(mapwin,MAP_TITLE); + + for(i=0;iNUMMOVES); + echo(); + + for(i=0;i SPLIT_PRICE) + split_announce(newc_type-'A'); + else + show_coinfo(); + } + } +} + +/* +** do_merge() -- does all the nasty business behind a merge +*/ + +void do_merge(int *c1, int *c2, int *o1, int *o2) +{ + int t,i,cb,cs,doswap=0; + + cb = *c1 - 'A'; + cs = *c2 - 'A'; + + if (co[cs].size == co[cb].size) { /* if same size, check prices */ + int pb=0,ps=0; + for(i=0;i pb) /* if smaller co has higher worth, swap 'em */ + doswap = 1; + else if (ps == pb) /* if same price, choose rand */ + doswap = rand()%2; + } + + if (co[cs].size > co[cb].size || doswap) { /* cb = merger, cs = mergee */ + t = cs; + cs = cb; + cb = t; + } + + for(i=0;i SPLIT_PRICE) + split_announce(cb); +} + +/* +** calc_cost() -- adds value to a company based on surroundings and converts +** NEWCOs to the company +*/ + +void calc_cost(int cnum, int move, int n, int s, int w, int e) +{ + if (n == STAR) co[cnum].price += STARCOST; /* stars */ + if (s == STAR) co[cnum].price += STARCOST; + if (w == STAR) co[cnum].price += STARCOST; + if (e == STAR) co[cnum].price += STARCOST; + + if (n == BLACKHOLE) co[cnum].price += BLACKHOLECOST; /* black holes */ + if (s == BLACKHOLE) co[cnum].price += BLACKHOLECOST; + if (w == BLACKHOLE) co[cnum].price += BLACKHOLECOST; + if (e == BLACKHOLE) co[cnum].price += BLACKHOLECOST; + + if (n == NEWCO) { /* starter companies */ + map[move-MAPX] = cnum + 'A'; /*company represented by A is 0 and so on */ + drawmap(move-MAPX,cnum+'A'); + co[cnum].size++; + co[cnum].price += NEWCOCOST; + } + if (s == NEWCO) { + map[move+MAPX] = cnum + 'A'; + drawmap(move+MAPX,cnum+'A'); + co[cnum].size++; + co[cnum].price += NEWCOCOST; + } + if (w == NEWCO) { + map[move-1] = cnum + 'A'; + drawmap(move-1,cnum+'A'); + co[cnum].size++; + co[cnum].price += NEWCOCOST; + } + if (e == NEWCO) { + map[move+1] = cnum + 'A'; + drawmap(move+1,cnum+'A'); + co[cnum].size++; + co[cnum].price += NEWCOCOST; + } + wnoutrefresh(mapwin); +} + +/* +** new_co_announce() -- announce the coming of a new company +*/ + +void new_co_announce(int newc) +{ + char s[80]; + + clear_general(" Special Announcement! ",1); + wattron(general,A_BOLD); + center(general,COLUMNS-2,2,"A new shipping company has been formed!"); + sprintf(s,"Its name is %s",co[newc].name); + center(general,COLUMNS-2,4,s); + wattroff(general,A_BOLD); + center(general,COLUMNS-2,7,"Press any key to continue..."); + wnoutrefresh(general); + noecho();raw(); + doupdate(); + while (getch() == CTRL_L) redraw(); +} + +/* +** suck_announce() -- when a company gets drawn into a black hole (value < 0) +*/ + +void suck_announce(int conum, int grown) +{ + int i; + + if (conum >= 0) { + for(i=0;i= 0 && grown == 1) { /* already existed */ + center(general,COLUMNS-2,2,"The company named"); + center(general,COLUMNS-2,3,co[conum].name); + center(general,COLUMNS-2,4,"has been sucked into a black hole!"); + center(general,COLUMNS-2,6,"All players' holdings lost."); + show_coinfo(); /* show change */ + } else if (conum >= 0 && grown == 0) { /* was trying to start up */ + center(general,COLUMNS-2,2,"The company that would have been named"); + center(general,COLUMNS-2,3,co[conum].name); + center(general,COLUMNS-2,4,"has been sucked into a black hole!"); + } else { /* was only a starter company, not a real one yet */ + center(general,COLUMNS-2,2,"The new company site just placed"); + center(general,COLUMNS-2,3,"has been sucked into a black hole!"); + } + wattroff(general,A_BOLD); + center(general,COLUMNS-2,8,"Press any key to continue..."); + wnoutrefresh(general); + noecho();raw(); + doupdate(); + while (getch() == CTRL_L) redraw(); +} + +/* +** merge_announce() -- announce a merger +*/ + +void merge_announce(int c1, int c2) +{ + clear_general(" Special Announcement! ",1); + wattron(general,A_BOLD); + center(general,COLUMNS-2,2,co[c2].name); + wattroff(general,A_BOLD); + center(general,COLUMNS-2,3,"has just been merged into"); + wattron(general,A_BOLD); + center(general,COLUMNS-2,4,co[c1].name); + wattroff(general,A_BOLD); + center(general,COLUMNS-2,7,"Press any key to continue..."); + wnoutrefresh(general); + noecho();raw(); + doupdate(); + while (getch() == CTRL_L) redraw(); +} + +/* +** xaction_announce() -- announce transactions after a merger +*/ + +void xaction_announce(int c1, int c2) +{ + int i,totalshares=0,newshares,bonus,totalholdings,percentage; + + clear_general(" Stock Transactions ",0); + center(general,COLUMNS-2,2,co[c2].name); + wattron(general,color?YELLOW_ON_BLUE|A_BOLD:A_REVERSE); + mvwprintw(general,2,4,"=Player===============Old Stock===New Stock===Total Holdings===Bonus="); + wattroff(general,color?YELLOW_ON_BLUE|A_BOLD:A_REVERSE); + + for(i=0;i= min && amt <= max) { + pl[turn].cash += (-amt * co[cos[cursor]].price); + pl[turn].holdings[cos[cursor]] += amt; + } else { + mvwprintw(general,cursor+3,40,"Invalid amount! "); + wmove(general,cursor+3,55); + wnoutrefresh(general); + doupdate(); + sleep(1); + } + mvwprintw(general,cursor+3,40," "); + sprintf(s," %s (Cash: $%ld) ",pl[turn].name,pl[turn].cash); + + if (amt) show_coinfo(); + + pos1 = ((COLUMNS-2)-strlen(s))/2; + pos2 = pos1 + strlen(s); + wattron(general,GENERAL_TITLE); + center(general,COLUMNS-2,0,s); + wattroff(general,GENERAL_TITLE); + wattron(general,GENERAL_BORDER); + mvwaddstr(general,0,pos1-4,"////"); + mvwaddstr(general,0,pos2,"////"); + wattroff(general,GENERAL_BORDER); + wmove(general,cursor+3,strlen(co[cos[cursor]].name)+20); + wnoutrefresh(general); + + break; + + case ESC: done = 1; + } /* switch */ + + if (cursor != newcur) { /* move cursor */ + switch(cos[cursor]) { + case 0: attrs = CO_A;break; + case 1: attrs = CO_B;break; + case 2: attrs = CO_C;break; + case 3: attrs = CO_D;break; + case 4: attrs = CO_E;break; + } + + wattron(general,attrs); + mvwprintw(general,cursor+3,20,co[cos[cursor]].name); + wattroff(general,attrs); + + wattron(general,color?BLACK_ON_WHITE:A_REVERSE); + mvwprintw(general, newcur+3, 20, co[cos[newcur]].name); + wattroff(general,color?BLACK_ON_WHITE:A_REVERSE); + + wnoutrefresh(general); + cursor = newcur; + } + } while(!done); +} + + +/* +** check_endgame() -- returns true if the game is over +*/ + +int check_endgame(void) +{ + int sum=0,i,maptotal; + + for(i=0;i= END_PERCENT && maptotal <= MAPX*MAPY-4; +} + +/* +** count_used_sectors() -- counts the number of non-empty sectors +*/ + +int count_used_sectors(void) +{ + int maptotal, i; + + for(i=maptotal=0;i